From 9bf37cc9712506b2483650c82d3c41152337ef7e Mon Sep 17 00:00:00 2001 From: Dave Burke Date: Tue, 17 Apr 2012 09:51:45 -0700 Subject: Fraunhofer AAC codec. License boilerplate update to follow. Change-Id: I2810460c11a58b6d148d84673cc031f3685e79b5 --- Android.mk | 1 + libAACdec/Android.mk | 1 + libAACdec/include/aacdecoder_lib.h | 626 ++++++++ libAACdec/src/Android.mk | 39 + libAACdec/src/aac_ram.cpp | 81 + libAACdec/src/aac_ram.h | 58 + libAACdec/src/aac_rom.cpp | 1780 ++++++++++++++++++++++ libAACdec/src/aac_rom.h | 125 ++ libAACdec/src/aacdec_drc.cpp | 997 +++++++++++++ libAACdec/src/aacdec_drc.h | 105 ++ libAACdec/src/aacdec_drc_types.h | 104 ++ libAACdec/src/aacdec_hcr.cpp | 1529 +++++++++++++++++++ libAACdec/src/aacdec_hcr.h | 64 + libAACdec/src/aacdec_hcr_bit.cpp | 103 ++ libAACdec/src/aacdec_hcr_bit.h | 44 + libAACdec/src/aacdec_hcr_types.h | 304 ++++ libAACdec/src/aacdec_hcrs.cpp | 1344 +++++++++++++++++ libAACdec/src/aacdec_hcrs.h | 91 ++ libAACdec/src/aacdec_pns.cpp | 320 ++++ libAACdec/src/aacdec_pns.h | 58 + libAACdec/src/aacdec_tns.cpp | 350 +++++ libAACdec/src/aacdec_tns.h | 64 + libAACdec/src/aacdecoder.cpp | 1667 +++++++++++++++++++++ libAACdec/src/aacdecoder.h | 250 ++++ libAACdec/src/aacdecoder_lib.cpp | 925 ++++++++++++ libAACdec/src/arm/block_arm.cpp | 77 + libAACdec/src/block.cpp | 703 +++++++++ libAACdec/src/block.h | 260 ++++ libAACdec/src/channel.cpp | 389 +++++ libAACdec/src/channel.h | 86 ++ libAACdec/src/channelinfo.cpp | 214 +++ libAACdec/src/channelinfo.h | 388 +++++ libAACdec/src/conceal.cpp | 1763 ++++++++++++++++++++++ libAACdec/src/conceal.h | 86 ++ libAACdec/src/conceal_types.h | 116 ++ libAACdec/src/debug.h | 35 + libAACdec/src/ldfiltbank.cpp | 148 ++ libAACdec/src/ldfiltbank.h | 48 + libAACdec/src/overlapadd.h | 43 + libAACdec/src/pulsedata.cpp | 96 ++ libAACdec/src/pulsedata.h | 83 ++ libAACdec/src/rvlc.cpp | 1157 +++++++++++++++ libAACdec/src/rvlc.h | 76 + libAACdec/src/rvlc_info.h | 118 ++ libAACdec/src/rvlcbit.cpp | 73 + libAACdec/src/rvlcbit.h | 41 + libAACdec/src/rvlcconceal.cpp | 639 ++++++++ libAACdec/src/rvlcconceal.h | 54 + libAACdec/src/stereo.cpp | 235 +++ libAACdec/src/stereo.h | 72 + libAACenc/Android.mk | 1 + libAACenc/include/aacenc_lib.h | 1150 +++++++++++++++ libAACenc/src/Android.mk | 53 + libAACenc/src/aacEnc_ram.cpp | 132 ++ libAACenc/src/aacEnc_ram.h | 163 +++ libAACenc/src/aacEnc_rom.cpp | 1170 +++++++++++++++ libAACenc/src/aacEnc_rom.h | 141 ++ libAACenc/src/aacenc.cpp | 952 ++++++++++++ libAACenc/src/aacenc.h | 232 +++ libAACenc/src/aacenc_hcr.cpp | 31 + libAACenc/src/aacenc_hcr.h | 33 + libAACenc/src/aacenc_lib.cpp | 1696 +++++++++++++++++++++ libAACenc/src/aacenc_pns.cpp | 532 +++++++ libAACenc/src/aacenc_pns.h | 52 + libAACenc/src/aacenc_tns.cpp | 1286 ++++++++++++++++ libAACenc/src/aacenc_tns.h | 135 ++ libAACenc/src/adj_thr.cpp | 2262 ++++++++++++++++++++++++++++ libAACenc/src/adj_thr.h | 79 + libAACenc/src/adj_thr_data.h | 88 ++ libAACenc/src/band_nrg.cpp | 297 ++++ libAACenc/src/band_nrg.h | 86 ++ libAACenc/src/bandwidth.cpp | 316 ++++ libAACenc/src/bandwidth.h | 44 + libAACenc/src/bit_cnt.cpp | 1060 ++++++++++++++ libAACenc/src/bit_cnt.h | 124 ++ libAACenc/src/bitenc.cpp | 1431 ++++++++++++++++++ libAACenc/src/bitenc.h | 120 ++ libAACenc/src/block_switch.cpp | 500 +++++++ libAACenc/src/block_switch.h | 85 ++ libAACenc/src/channel_map.cpp | 499 +++++++ libAACenc/src/channel_map.h | 72 + libAACenc/src/chaosmeasure.cpp | 99 ++ libAACenc/src/chaosmeasure.h | 41 + libAACenc/src/dyn_bits.cpp | 743 ++++++++++ libAACenc/src/dyn_bits.h | 104 ++ libAACenc/src/grp_data.cpp | 206 +++ libAACenc/src/grp_data.h | 53 + libAACenc/src/intensity.cpp | 691 +++++++++ libAACenc/src/intensity.h | 61 + libAACenc/src/interface.h | 100 ++ libAACenc/src/line_pe.cpp | 145 ++ libAACenc/src/line_pe.h | 77 + libAACenc/src/metadata_compressor.cpp | 965 ++++++++++++ libAACenc/src/metadata_compressor.h | 190 +++ libAACenc/src/metadata_main.cpp | 809 ++++++++++ libAACenc/src/metadata_main.h | 161 ++ libAACenc/src/ms_stereo.cpp | 189 +++ libAACenc/src/ms_stereo.h | 44 + libAACenc/src/noisedet.cpp | 170 +++ libAACenc/src/noisedet.h | 47 + libAACenc/src/pns_func.h | 89 ++ libAACenc/src/pnsparam.cpp | 248 ++++ libAACenc/src/pnsparam.h | 78 + libAACenc/src/pre_echo_control.cpp | 108 ++ libAACenc/src/pre_echo_control.h | 51 + libAACenc/src/psy_configuration.cpp | 594 ++++++++ libAACenc/src/psy_configuration.h | 102 ++ libAACenc/src/psy_const.h | 99 ++ libAACenc/src/psy_data.h | 89 ++ libAACenc/src/psy_main.cpp | 1338 +++++++++++++++++ libAACenc/src/psy_main.h | 111 ++ libAACenc/src/qc_data.h | 214 +++ libAACenc/src/qc_main.cpp | 1551 ++++++++++++++++++++ libAACenc/src/qc_main.h | 108 ++ libAACenc/src/quantize.cpp | 323 ++++ libAACenc/src/quantize.h | 56 + libAACenc/src/sf_estim.cpp | 1243 ++++++++++++++++ libAACenc/src/sf_estim.h | 54 + libAACenc/src/spreading.cpp | 52 + libAACenc/src/spreading.h | 40 + libAACenc/src/tns_func.h | 81 + libAACenc/src/tns_param.cpp | 31 + libAACenc/src/tns_param.h | 33 + libAACenc/src/tonality.cpp | 147 ++ libAACenc/src/tonality.h | 46 + libAACenc/src/transform.cpp | 203 +++ libAACenc/src/transform.h | 60 + libFDK/Android.mk | 1 + libFDK/include/FDK_archdef.h | 184 +++ libFDK/include/FDK_bitbuffer.h | 104 ++ libFDK/include/FDK_bitstream.h | 556 +++++++ libFDK/include/FDK_core.h | 47 + libFDK/include/FDK_crc.h | 169 +++ libFDK/include/FDK_tools_rom.h | 205 +++ libFDK/include/FDK_trigFcts.h | 169 +++ libFDK/include/abs.h | 59 + libFDK/include/arm/clz_arm.h | 59 + libFDK/include/arm/cplx_mul.h | 153 ++ libFDK/include/arm/fixmadd_arm.h | 97 ++ libFDK/include/arm/fixmul_arm.h | 79 + libFDK/include/arm/scale.h | 90 ++ libFDK/include/arm/scramble.h | 98 ++ libFDK/include/autocorr2nd.h | 66 + libFDK/include/clz.h | 127 ++ libFDK/include/common_fix.h | 324 ++++ libFDK/include/cplx_mul.h | 207 +++ libFDK/include/dct.h | 85 ++ libFDK/include/fft.h | 191 +++ libFDK/include/fft_rad2.h | 72 + libFDK/include/fixmadd.h | 244 ++++ libFDK/include/fixminmax.h | 58 + libFDK/include/fixmul.h | 223 +++ libFDK/include/fixpoint_math.h | 397 +++++ libFDK/include/mdct.h | 181 +++ libFDK/include/mips/abs_mips.h | 44 + libFDK/include/mips/clz_mips.h | 55 + libFDK/include/mips/cplx_mul.h | 93 ++ libFDK/include/mips/fixmadd_mips.h | 32 + libFDK/include/mips/fixmul_mips.h | 53 + libFDK/include/mips/scale.h | 48 + libFDK/include/mips/scramble.h | 59 + libFDK/include/qmf.h | 188 +++ libFDK/include/scale.h | 180 +++ libFDK/include/scramble.h | 103 ++ libFDK/include/x86/abs_x86.h | 44 + libFDK/include/x86/fixmul_x86.h | 115 ++ libFDK/src/Android.mk | 30 + libFDK/src/FDK_bitbuffer.cpp | 427 ++++++ libFDK/src/FDK_core.cpp | 66 + libFDK/src/FDK_crc.cpp | 397 +++++ libFDK/src/FDK_tools_rom.cpp | 2358 ++++++++++++++++++++++++++++++ libFDK/src/FDK_trigFcts.cpp | 607 ++++++++ libFDK/src/arm/autocorr2nd.cpp | 33 + libFDK/src/arm/dct_arm.cpp | 395 +++++ libFDK/src/arm/fft_rad2_arm.cpp | 259 ++++ libFDK/src/arm/qmf_arm.cpp | 710 +++++++++ libFDK/src/arm/scale_arm.cpp | 110 ++ libFDK/src/autocorr2nd.cpp | 216 +++ libFDK/src/dct.cpp | 513 +++++++ libFDK/src/fft.cpp | 1395 ++++++++++++++++++ libFDK/src/fft_rad2.cpp | 450 ++++++ libFDK/src/fixpoint_math.cpp | 1164 +++++++++++++++ libFDK/src/mdct.cpp | 339 +++++ libFDK/src/mips/fft_rad2_mips.cpp | 72 + libFDK/src/mips/mips_fft_twiddles.cpp | 516 +++++++ libFDK/src/mips/scale.cpp | 57 + libFDK/src/qmf.cpp | 1125 ++++++++++++++ libFDK/src/scale.cpp | 399 +++++ libMpegTPDec/Android.mk | 1 + libMpegTPDec/include/mpegFileRead.h | 132 ++ libMpegTPDec/include/tp_data.h | 277 ++++ libMpegTPDec/include/tpdec_lib.h | 430 ++++++ libMpegTPDec/src/Android.mk | 21 + libMpegTPDec/src/mpegFileFormat.h | 52 + libMpegTPDec/src/tpdec_adif.cpp | 93 ++ libMpegTPDec/src/tpdec_adif.h | 61 + libMpegTPDec/src/tpdec_adts.cpp | 326 +++++ libMpegTPDec/src/tpdec_adts.h | 174 +++ libMpegTPDec/src/tpdec_asc.cpp | 867 +++++++++++ libMpegTPDec/src/tpdec_latm.cpp | 364 +++++ libMpegTPDec/src/tpdec_latm.h | 103 ++ libMpegTPDec/src/tpdec_lib.cpp | 1127 ++++++++++++++ libMpegTPDec/src/version | 8 + libMpegTPEnc/Android.mk | 1 + libMpegTPEnc/include/mpegFileWrite.h | 78 + libMpegTPEnc/include/tp_data.h | 277 ++++ libMpegTPEnc/include/tpenc_lib.h | 234 +++ libMpegTPEnc/src/Android.mk | 21 + libMpegTPEnc/src/tpenc_adif.cpp | 120 ++ libMpegTPEnc/src/tpenc_adif.h | 73 + libMpegTPEnc/src/tpenc_adts.cpp | 253 ++++ libMpegTPEnc/src/tpenc_adts.h | 156 ++ libMpegTPEnc/src/tpenc_asc.cpp | 503 +++++++ libMpegTPEnc/src/tpenc_asc.h | 80 + libMpegTPEnc/src/tpenc_latm.cpp | 820 +++++++++++ libMpegTPEnc/src/tpenc_latm.h | 204 +++ libMpegTPEnc/src/tpenc_lib.cpp | 569 +++++++ libMpegTPEnc/src/version | 8 + libPCMutils/Android.mk | 1 + libPCMutils/include/pcmutils_lib.h | 220 +++ libPCMutils/src/Android.mk | 16 + libPCMutils/src/pcmutils_lib.cpp | 1219 +++++++++++++++ libSBRdec/Android.mk | 1 + libSBRdec/include/sbrdecoder.h | 275 ++++ libSBRdec/src/Android.mk | 32 + libSBRdec/src/arm/env_calc_arm.cpp | 86 ++ libSBRdec/src/arm/lpp_tran_arm.cpp | 89 ++ libSBRdec/src/env_calc.cpp | 2171 +++++++++++++++++++++++++++ libSBRdec/src/env_calc.h | 107 ++ libSBRdec/src/env_dec.cpp | 794 ++++++++++ libSBRdec/src/env_dec.h | 43 + libSBRdec/src/env_extr.cpp | 1333 +++++++++++++++++ libSBRdec/src/env_extr.h | 261 ++++ libSBRdec/src/huff_dec.cpp | 62 + libSBRdec/src/huff_dec.h | 42 + libSBRdec/src/lpp_tran.cpp | 942 ++++++++++++ libSBRdec/src/lpp_tran.h | 184 +++ libSBRdec/src/psbitdec.cpp | 536 +++++++ libSBRdec/src/psbitdec.h | 46 + libSBRdec/src/psdec.cpp | 1356 +++++++++++++++++ libSBRdec/src/psdec.h | 294 ++++ libSBRdec/src/psdec_hybrid.cpp | 595 ++++++++ libSBRdec/src/psdec_hybrid.h | 109 ++ libSBRdec/src/sbr_crc.cpp | 125 ++ libSBRdec/src/sbr_crc.h | 65 + libSBRdec/src/sbr_deb.cpp | 32 + libSBRdec/src/sbr_deb.h | 36 + libSBRdec/src/sbr_dec.cpp | 985 +++++++++++++ libSBRdec/src/sbr_dec.h | 152 ++ libSBRdec/src/sbr_ram.cpp | 136 ++ libSBRdec/src/sbr_ram.h | 100 ++ libSBRdec/src/sbr_rom.cpp | 1354 +++++++++++++++++ libSBRdec/src/sbr_rom.h | 174 +++ libSBRdec/src/sbr_scale.h | 65 + libSBRdec/src/sbrdec_drc.cpp | 450 ++++++ libSBRdec/src/sbrdec_drc.h | 88 ++ libSBRdec/src/sbrdec_freq_sca.cpp | 749 ++++++++++ libSBRdec/src/sbrdec_freq_sca.h | 48 + libSBRdec/src/sbrdecoder.cpp | 1448 ++++++++++++++++++ libSBRdec/src/transcendent.h | 313 ++++ libSBRenc/Android.mk | 1 + libSBRenc/include/sbr_encoder.h | 322 ++++ libSBRenc/src/Android.mk | 36 + libSBRenc/src/bit_sbr.cpp | 1001 +++++++++++++ libSBRenc/src/bit_sbr.h | 203 +++ libSBRenc/src/cmondata.h | 52 + libSBRenc/src/code_env.cpp | 584 ++++++++ libSBRenc/src/code_env.h | 97 ++ libSBRenc/src/env_bit.cpp | 192 +++ libSBRenc/src/env_bit.h | 68 + libSBRenc/src/env_est.cpp | 1834 +++++++++++++++++++++++ libSBRenc/src/env_est.h | 167 +++ libSBRenc/src/fram_gen.cpp | 2015 +++++++++++++++++++++++++ libSBRenc/src/fram_gen.h | 249 ++++ libSBRenc/src/invf_est.cpp | 472 ++++++ libSBRenc/src/invf_est.h | 119 ++ libSBRenc/src/mh_det.cpp | 1381 +++++++++++++++++ libSBRenc/src/mh_det.h | 138 ++ libSBRenc/src/nf_est.cpp | 518 +++++++ libSBRenc/src/nf_est.h | 89 ++ libSBRenc/src/ps_bitenc.cpp | 635 ++++++++ libSBRenc/src/ps_bitenc.h | 115 ++ libSBRenc/src/ps_const.h | 65 + libSBRenc/src/ps_encode.cpp | 1068 ++++++++++++++ libSBRenc/src/ps_encode.h | 117 ++ libSBRenc/src/ps_main.cpp | 1079 ++++++++++++++ libSBRenc/src/ps_main.h | 160 ++ libSBRenc/src/psenc_hybrid.cpp | 836 +++++++++++ libSBRenc/src/psenc_hybrid.h | 182 +++ libSBRenc/src/resampler.cpp | 450 ++++++ libSBRenc/src/resampler.h | 109 ++ libSBRenc/src/sbr.h | 107 ++ libSBRenc/src/sbr_def.h | 228 +++ libSBRenc/src/sbr_encoder.cpp | 2109 ++++++++++++++++++++++++++ libSBRenc/src/sbr_misc.cpp | 214 +++ libSBRenc/src/sbr_misc.h | 48 + libSBRenc/src/sbr_ram.cpp | 220 +++ libSBRenc/src/sbr_ram.h | 171 +++ libSBRenc/src/sbr_rom.cpp | 681 +++++++++ libSBRenc/src/sbr_rom.h | 70 + libSBRenc/src/sbrenc_freq_sca.cpp | 613 ++++++++ libSBRenc/src/sbrenc_freq_sca.h | 71 + libSBRenc/src/ton_corr.cpp | 829 +++++++++++ libSBRenc/src/ton_corr.h | 154 ++ libSBRenc/src/tran_det.cpp | 645 ++++++++ libSBRenc/src/tran_det.h | 92 ++ libSYS/Android.mk | 1 + libSYS/include/FDK_audio.h | 544 +++++++ libSYS/include/audio.h | 44 + libSYS/include/cmdl_parser.h | 159 ++ libSYS/include/conv_string.h | 74 + libSYS/include/genericStds.h | 421 ++++++ libSYS/include/machine_type.h | 295 ++++ libSYS/include/wav_file.h | 150 ++ libSYS/src/Android.mk | 19 + libSYS/src/cmdl_parser.cpp | 522 +++++++ libSYS/src/conv_string.cpp | 117 ++ libSYS/src/genericStds.cpp | 429 ++++++ libSYS/src/linux/FDK_stackload_linux.cpp | 28 + libSYS/src/linux/audio_linux.cpp | 28 + libSYS/src/linux/coresup_linux.cpp | 28 + libSYS/src/linux/genericStds_linux.cpp | 232 +++ libSYS/src/linux/uart_linux.cpp | 28 + libSYS/src/mips/genericStds_mips.cpp | 230 +++ libSYS/src/wav_file.cpp | 492 +++++++ 325 files changed, 110807 insertions(+) create mode 100644 Android.mk create mode 100644 libAACdec/Android.mk create mode 100644 libAACdec/include/aacdecoder_lib.h create mode 100644 libAACdec/src/Android.mk create mode 100644 libAACdec/src/aac_ram.cpp create mode 100644 libAACdec/src/aac_ram.h create mode 100644 libAACdec/src/aac_rom.cpp create mode 100644 libAACdec/src/aac_rom.h create mode 100644 libAACdec/src/aacdec_drc.cpp create mode 100644 libAACdec/src/aacdec_drc.h create mode 100644 libAACdec/src/aacdec_drc_types.h create mode 100644 libAACdec/src/aacdec_hcr.cpp create mode 100644 libAACdec/src/aacdec_hcr.h create mode 100644 libAACdec/src/aacdec_hcr_bit.cpp create mode 100644 libAACdec/src/aacdec_hcr_bit.h create mode 100644 libAACdec/src/aacdec_hcr_types.h create mode 100644 libAACdec/src/aacdec_hcrs.cpp create mode 100644 libAACdec/src/aacdec_hcrs.h create mode 100644 libAACdec/src/aacdec_pns.cpp create mode 100644 libAACdec/src/aacdec_pns.h create mode 100644 libAACdec/src/aacdec_tns.cpp create mode 100644 libAACdec/src/aacdec_tns.h create mode 100644 libAACdec/src/aacdecoder.cpp create mode 100644 libAACdec/src/aacdecoder.h create mode 100644 libAACdec/src/aacdecoder_lib.cpp create mode 100644 libAACdec/src/arm/block_arm.cpp create mode 100644 libAACdec/src/block.cpp create mode 100644 libAACdec/src/block.h create mode 100644 libAACdec/src/channel.cpp create mode 100644 libAACdec/src/channel.h create mode 100644 libAACdec/src/channelinfo.cpp create mode 100644 libAACdec/src/channelinfo.h create mode 100644 libAACdec/src/conceal.cpp create mode 100644 libAACdec/src/conceal.h create mode 100644 libAACdec/src/conceal_types.h create mode 100644 libAACdec/src/debug.h create mode 100644 libAACdec/src/ldfiltbank.cpp create mode 100644 libAACdec/src/ldfiltbank.h create mode 100644 libAACdec/src/overlapadd.h create mode 100644 libAACdec/src/pulsedata.cpp create mode 100644 libAACdec/src/pulsedata.h create mode 100644 libAACdec/src/rvlc.cpp create mode 100644 libAACdec/src/rvlc.h create mode 100644 libAACdec/src/rvlc_info.h create mode 100644 libAACdec/src/rvlcbit.cpp create mode 100644 libAACdec/src/rvlcbit.h create mode 100644 libAACdec/src/rvlcconceal.cpp create mode 100644 libAACdec/src/rvlcconceal.h create mode 100644 libAACdec/src/stereo.cpp create mode 100644 libAACdec/src/stereo.h create mode 100644 libAACenc/Android.mk create mode 100644 libAACenc/include/aacenc_lib.h create mode 100644 libAACenc/src/Android.mk create mode 100644 libAACenc/src/aacEnc_ram.cpp create mode 100644 libAACenc/src/aacEnc_ram.h create mode 100644 libAACenc/src/aacEnc_rom.cpp create mode 100644 libAACenc/src/aacEnc_rom.h create mode 100644 libAACenc/src/aacenc.cpp create mode 100644 libAACenc/src/aacenc.h create mode 100644 libAACenc/src/aacenc_hcr.cpp create mode 100644 libAACenc/src/aacenc_hcr.h create mode 100644 libAACenc/src/aacenc_lib.cpp create mode 100644 libAACenc/src/aacenc_pns.cpp create mode 100644 libAACenc/src/aacenc_pns.h create mode 100644 libAACenc/src/aacenc_tns.cpp create mode 100644 libAACenc/src/aacenc_tns.h create mode 100644 libAACenc/src/adj_thr.cpp create mode 100644 libAACenc/src/adj_thr.h create mode 100644 libAACenc/src/adj_thr_data.h create mode 100644 libAACenc/src/band_nrg.cpp create mode 100644 libAACenc/src/band_nrg.h create mode 100644 libAACenc/src/bandwidth.cpp create mode 100644 libAACenc/src/bandwidth.h create mode 100644 libAACenc/src/bit_cnt.cpp create mode 100644 libAACenc/src/bit_cnt.h create mode 100644 libAACenc/src/bitenc.cpp create mode 100644 libAACenc/src/bitenc.h create mode 100644 libAACenc/src/block_switch.cpp create mode 100644 libAACenc/src/block_switch.h create mode 100644 libAACenc/src/channel_map.cpp create mode 100644 libAACenc/src/channel_map.h create mode 100644 libAACenc/src/chaosmeasure.cpp create mode 100644 libAACenc/src/chaosmeasure.h create mode 100644 libAACenc/src/dyn_bits.cpp create mode 100644 libAACenc/src/dyn_bits.h create mode 100644 libAACenc/src/grp_data.cpp create mode 100644 libAACenc/src/grp_data.h create mode 100644 libAACenc/src/intensity.cpp create mode 100644 libAACenc/src/intensity.h create mode 100644 libAACenc/src/interface.h create mode 100644 libAACenc/src/line_pe.cpp create mode 100644 libAACenc/src/line_pe.h create mode 100644 libAACenc/src/metadata_compressor.cpp create mode 100644 libAACenc/src/metadata_compressor.h create mode 100644 libAACenc/src/metadata_main.cpp create mode 100644 libAACenc/src/metadata_main.h create mode 100644 libAACenc/src/ms_stereo.cpp create mode 100644 libAACenc/src/ms_stereo.h create mode 100644 libAACenc/src/noisedet.cpp create mode 100644 libAACenc/src/noisedet.h create mode 100644 libAACenc/src/pns_func.h create mode 100644 libAACenc/src/pnsparam.cpp create mode 100644 libAACenc/src/pnsparam.h create mode 100644 libAACenc/src/pre_echo_control.cpp create mode 100644 libAACenc/src/pre_echo_control.h create mode 100644 libAACenc/src/psy_configuration.cpp create mode 100644 libAACenc/src/psy_configuration.h create mode 100644 libAACenc/src/psy_const.h create mode 100644 libAACenc/src/psy_data.h create mode 100644 libAACenc/src/psy_main.cpp create mode 100644 libAACenc/src/psy_main.h create mode 100644 libAACenc/src/qc_data.h create mode 100644 libAACenc/src/qc_main.cpp create mode 100644 libAACenc/src/qc_main.h create mode 100644 libAACenc/src/quantize.cpp create mode 100644 libAACenc/src/quantize.h create mode 100644 libAACenc/src/sf_estim.cpp create mode 100644 libAACenc/src/sf_estim.h create mode 100644 libAACenc/src/spreading.cpp create mode 100644 libAACenc/src/spreading.h create mode 100644 libAACenc/src/tns_func.h create mode 100644 libAACenc/src/tns_param.cpp create mode 100644 libAACenc/src/tns_param.h create mode 100644 libAACenc/src/tonality.cpp create mode 100644 libAACenc/src/tonality.h create mode 100644 libAACenc/src/transform.cpp create mode 100644 libAACenc/src/transform.h create mode 100644 libFDK/Android.mk create mode 100644 libFDK/include/FDK_archdef.h create mode 100644 libFDK/include/FDK_bitbuffer.h create mode 100644 libFDK/include/FDK_bitstream.h create mode 100644 libFDK/include/FDK_core.h create mode 100644 libFDK/include/FDK_crc.h create mode 100644 libFDK/include/FDK_tools_rom.h create mode 100644 libFDK/include/FDK_trigFcts.h create mode 100644 libFDK/include/abs.h create mode 100644 libFDK/include/arm/clz_arm.h create mode 100644 libFDK/include/arm/cplx_mul.h create mode 100644 libFDK/include/arm/fixmadd_arm.h create mode 100644 libFDK/include/arm/fixmul_arm.h create mode 100644 libFDK/include/arm/scale.h create mode 100644 libFDK/include/arm/scramble.h create mode 100644 libFDK/include/autocorr2nd.h create mode 100644 libFDK/include/clz.h create mode 100644 libFDK/include/common_fix.h create mode 100644 libFDK/include/cplx_mul.h create mode 100644 libFDK/include/dct.h create mode 100644 libFDK/include/fft.h create mode 100644 libFDK/include/fft_rad2.h create mode 100644 libFDK/include/fixmadd.h create mode 100644 libFDK/include/fixminmax.h create mode 100644 libFDK/include/fixmul.h create mode 100644 libFDK/include/fixpoint_math.h create mode 100644 libFDK/include/mdct.h create mode 100644 libFDK/include/mips/abs_mips.h create mode 100644 libFDK/include/mips/clz_mips.h create mode 100644 libFDK/include/mips/cplx_mul.h create mode 100644 libFDK/include/mips/fixmadd_mips.h create mode 100644 libFDK/include/mips/fixmul_mips.h create mode 100644 libFDK/include/mips/scale.h create mode 100644 libFDK/include/mips/scramble.h create mode 100644 libFDK/include/qmf.h create mode 100644 libFDK/include/scale.h create mode 100644 libFDK/include/scramble.h create mode 100644 libFDK/include/x86/abs_x86.h create mode 100644 libFDK/include/x86/fixmul_x86.h create mode 100644 libFDK/src/Android.mk create mode 100644 libFDK/src/FDK_bitbuffer.cpp create mode 100644 libFDK/src/FDK_core.cpp create mode 100644 libFDK/src/FDK_crc.cpp create mode 100644 libFDK/src/FDK_tools_rom.cpp create mode 100644 libFDK/src/FDK_trigFcts.cpp create mode 100644 libFDK/src/arm/autocorr2nd.cpp create mode 100644 libFDK/src/arm/dct_arm.cpp create mode 100644 libFDK/src/arm/fft_rad2_arm.cpp create mode 100644 libFDK/src/arm/qmf_arm.cpp create mode 100644 libFDK/src/arm/scale_arm.cpp create mode 100644 libFDK/src/autocorr2nd.cpp create mode 100644 libFDK/src/dct.cpp create mode 100644 libFDK/src/fft.cpp create mode 100644 libFDK/src/fft_rad2.cpp create mode 100644 libFDK/src/fixpoint_math.cpp create mode 100644 libFDK/src/mdct.cpp create mode 100644 libFDK/src/mips/fft_rad2_mips.cpp create mode 100644 libFDK/src/mips/mips_fft_twiddles.cpp create mode 100644 libFDK/src/mips/scale.cpp create mode 100644 libFDK/src/qmf.cpp create mode 100644 libFDK/src/scale.cpp create mode 100644 libMpegTPDec/Android.mk create mode 100644 libMpegTPDec/include/mpegFileRead.h create mode 100644 libMpegTPDec/include/tp_data.h create mode 100644 libMpegTPDec/include/tpdec_lib.h create mode 100644 libMpegTPDec/src/Android.mk create mode 100644 libMpegTPDec/src/mpegFileFormat.h create mode 100644 libMpegTPDec/src/tpdec_adif.cpp create mode 100644 libMpegTPDec/src/tpdec_adif.h create mode 100644 libMpegTPDec/src/tpdec_adts.cpp create mode 100644 libMpegTPDec/src/tpdec_adts.h create mode 100644 libMpegTPDec/src/tpdec_asc.cpp create mode 100644 libMpegTPDec/src/tpdec_latm.cpp create mode 100644 libMpegTPDec/src/tpdec_latm.h create mode 100644 libMpegTPDec/src/tpdec_lib.cpp create mode 100644 libMpegTPDec/src/version create mode 100644 libMpegTPEnc/Android.mk create mode 100644 libMpegTPEnc/include/mpegFileWrite.h create mode 100644 libMpegTPEnc/include/tp_data.h create mode 100644 libMpegTPEnc/include/tpenc_lib.h create mode 100644 libMpegTPEnc/src/Android.mk create mode 100644 libMpegTPEnc/src/tpenc_adif.cpp create mode 100644 libMpegTPEnc/src/tpenc_adif.h create mode 100644 libMpegTPEnc/src/tpenc_adts.cpp create mode 100644 libMpegTPEnc/src/tpenc_adts.h create mode 100644 libMpegTPEnc/src/tpenc_asc.cpp create mode 100644 libMpegTPEnc/src/tpenc_asc.h create mode 100644 libMpegTPEnc/src/tpenc_latm.cpp create mode 100644 libMpegTPEnc/src/tpenc_latm.h create mode 100644 libMpegTPEnc/src/tpenc_lib.cpp create mode 100644 libMpegTPEnc/src/version create mode 100644 libPCMutils/Android.mk create mode 100644 libPCMutils/include/pcmutils_lib.h create mode 100644 libPCMutils/src/Android.mk create mode 100644 libPCMutils/src/pcmutils_lib.cpp create mode 100644 libSBRdec/Android.mk create mode 100644 libSBRdec/include/sbrdecoder.h create mode 100644 libSBRdec/src/Android.mk create mode 100644 libSBRdec/src/arm/env_calc_arm.cpp create mode 100644 libSBRdec/src/arm/lpp_tran_arm.cpp create mode 100644 libSBRdec/src/env_calc.cpp create mode 100644 libSBRdec/src/env_calc.h create mode 100644 libSBRdec/src/env_dec.cpp create mode 100644 libSBRdec/src/env_dec.h create mode 100644 libSBRdec/src/env_extr.cpp create mode 100644 libSBRdec/src/env_extr.h create mode 100644 libSBRdec/src/huff_dec.cpp create mode 100644 libSBRdec/src/huff_dec.h create mode 100644 libSBRdec/src/lpp_tran.cpp create mode 100644 libSBRdec/src/lpp_tran.h create mode 100644 libSBRdec/src/psbitdec.cpp create mode 100644 libSBRdec/src/psbitdec.h create mode 100644 libSBRdec/src/psdec.cpp create mode 100644 libSBRdec/src/psdec.h create mode 100644 libSBRdec/src/psdec_hybrid.cpp create mode 100644 libSBRdec/src/psdec_hybrid.h create mode 100644 libSBRdec/src/sbr_crc.cpp create mode 100644 libSBRdec/src/sbr_crc.h create mode 100644 libSBRdec/src/sbr_deb.cpp create mode 100644 libSBRdec/src/sbr_deb.h create mode 100644 libSBRdec/src/sbr_dec.cpp create mode 100644 libSBRdec/src/sbr_dec.h create mode 100644 libSBRdec/src/sbr_ram.cpp create mode 100644 libSBRdec/src/sbr_ram.h create mode 100644 libSBRdec/src/sbr_rom.cpp create mode 100644 libSBRdec/src/sbr_rom.h create mode 100644 libSBRdec/src/sbr_scale.h create mode 100644 libSBRdec/src/sbrdec_drc.cpp create mode 100644 libSBRdec/src/sbrdec_drc.h create mode 100644 libSBRdec/src/sbrdec_freq_sca.cpp create mode 100644 libSBRdec/src/sbrdec_freq_sca.h create mode 100644 libSBRdec/src/sbrdecoder.cpp create mode 100644 libSBRdec/src/transcendent.h create mode 100644 libSBRenc/Android.mk create mode 100644 libSBRenc/include/sbr_encoder.h create mode 100644 libSBRenc/src/Android.mk create mode 100644 libSBRenc/src/bit_sbr.cpp create mode 100644 libSBRenc/src/bit_sbr.h create mode 100644 libSBRenc/src/cmondata.h create mode 100644 libSBRenc/src/code_env.cpp create mode 100644 libSBRenc/src/code_env.h create mode 100644 libSBRenc/src/env_bit.cpp create mode 100644 libSBRenc/src/env_bit.h create mode 100644 libSBRenc/src/env_est.cpp create mode 100644 libSBRenc/src/env_est.h create mode 100644 libSBRenc/src/fram_gen.cpp create mode 100644 libSBRenc/src/fram_gen.h create mode 100644 libSBRenc/src/invf_est.cpp create mode 100644 libSBRenc/src/invf_est.h create mode 100644 libSBRenc/src/mh_det.cpp create mode 100644 libSBRenc/src/mh_det.h create mode 100644 libSBRenc/src/nf_est.cpp create mode 100644 libSBRenc/src/nf_est.h create mode 100644 libSBRenc/src/ps_bitenc.cpp create mode 100644 libSBRenc/src/ps_bitenc.h create mode 100644 libSBRenc/src/ps_const.h create mode 100644 libSBRenc/src/ps_encode.cpp create mode 100644 libSBRenc/src/ps_encode.h create mode 100644 libSBRenc/src/ps_main.cpp create mode 100644 libSBRenc/src/ps_main.h create mode 100644 libSBRenc/src/psenc_hybrid.cpp create mode 100644 libSBRenc/src/psenc_hybrid.h create mode 100644 libSBRenc/src/resampler.cpp create mode 100644 libSBRenc/src/resampler.h create mode 100644 libSBRenc/src/sbr.h create mode 100644 libSBRenc/src/sbr_def.h create mode 100644 libSBRenc/src/sbr_encoder.cpp create mode 100644 libSBRenc/src/sbr_misc.cpp create mode 100644 libSBRenc/src/sbr_misc.h create mode 100644 libSBRenc/src/sbr_ram.cpp create mode 100644 libSBRenc/src/sbr_ram.h create mode 100644 libSBRenc/src/sbr_rom.cpp create mode 100644 libSBRenc/src/sbr_rom.h create mode 100644 libSBRenc/src/sbrenc_freq_sca.cpp create mode 100644 libSBRenc/src/sbrenc_freq_sca.h create mode 100644 libSBRenc/src/ton_corr.cpp create mode 100644 libSBRenc/src/ton_corr.h create mode 100644 libSBRenc/src/tran_det.cpp create mode 100644 libSBRenc/src/tran_det.h create mode 100644 libSYS/Android.mk create mode 100644 libSYS/include/FDK_audio.h create mode 100644 libSYS/include/audio.h create mode 100644 libSYS/include/cmdl_parser.h create mode 100644 libSYS/include/conv_string.h create mode 100644 libSYS/include/genericStds.h create mode 100644 libSYS/include/machine_type.h create mode 100644 libSYS/include/wav_file.h create mode 100644 libSYS/src/Android.mk create mode 100644 libSYS/src/cmdl_parser.cpp create mode 100644 libSYS/src/conv_string.cpp create mode 100644 libSYS/src/genericStds.cpp create mode 100644 libSYS/src/linux/FDK_stackload_linux.cpp create mode 100644 libSYS/src/linux/audio_linux.cpp create mode 100644 libSYS/src/linux/coresup_linux.cpp create mode 100644 libSYS/src/linux/genericStds_linux.cpp create mode 100644 libSYS/src/linux/uart_linux.cpp create mode 100644 libSYS/src/mips/genericStds_mips.cpp create mode 100644 libSYS/src/wav_file.cpp diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/libAACdec/Android.mk b/libAACdec/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/libAACdec/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/libAACdec/include/aacdecoder_lib.h b/libAACdec/include/aacdecoder_lib.h new file mode 100644 index 0000000..881601b --- /dev/null +++ b/libAACdec/include/aacdecoder_lib.h @@ -0,0 +1,626 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS 1999-2008 + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +/** + * \file aacdecoder_lib.h + * \brief FDK AAC decoder library interface header file. + * + +\page INTRO Introduction + +\section SCOPE Scope + +This document describes the high-level interface and usage of the ISO/MPEG-2/4 AAC Decoder +library developed by the Fraunhofer Institute for Integrated Circuits (IIS). +Depending on the library configuration, it implements decoding of AAC-LC (Low-Complexity), +HE-AAC (High-Efficiency AAC, v1 and v2), AAC-LD (Low-Delay) and AAC-ELD (Enhanced Low-Delay). + +All references to SBR (Spectral Band Replication) are only applicable to HE-AAC and AAC-ELD +versions of the library. All references to PS (Parametric Stereo) are only applicable to +HE-AAC v2 versions of the library. + +\section DecoderBasics Decoder Basics + +This document can only give a rough overview about the ISO/MPEG-2 and ISO/MPEG-4 AAC audio +coding standard. To understand all the terms in this document, you are encouraged to read +the following documents. + +- ISO/IEC 13818-7 (MPEG-2 AAC), which defines the syntax of MPEG-2 AAC audio bitstreams. +- ISO/IEC 14496-3 (MPEG-4 AAC, subpart 1 and 4), which defines the syntax of MPEG-4 AAC audio bitstreams. +- Lutzky, Schuller, Gayer, Krämer, Wabnik, "A guideline to audio codec delay", 116th AES Convention, May 8, 2004 + +MPEG Advanced Audio Coding is based on a time-to-frequency mapping of the signal. The signal +is partitioned into overlapping portions and transformed into frequency domain. The spectral +components are then quantized and coded.\n +An MPEG2 or MPEG4 AAC audio bitstream is composed of frames. Contrary to MPEG-1/2 Layer-3 (mp3), +the length of individual frames is not restricted to a fixed number of bytes, but can take on +any length between 1 and 768 bytes. + + +\page LIBUSE Library Usage + +\section InterfaceDescritpion API Description + +All API header files are located in the folder /include of the release package. They are described in +detail in this document. All header files are provided for usage in C/C++ programs. The AAC decoder library +API functions are located at aacdecoder_lib.h. + +In binary releases the decoder core resides in statically linkable libraries called for example libAACdec.a, +(Linux) or FDK_aacDec_lib (Microsoft Visual C++). + +\section Calling_Sequence Calling Sequence + +For decoding of ISO/MPEG-2/4 AAC or HE-AAC v2 bitstreams the following sequence is mandatory. Input read +and output write functions as well as the corresponding open and close functions are left out, since they +may be implemented differently according to the user's specific requirements. The example implementation in +main.cpp uses file-based input/output, and in such case call mpegFileRead_Open() to open an input file and +to allocate memory for the required structures, and the corresponding mpegFileRead_Close() to close opened +files and to de-allocate associated structures. mpegFileRead_Open() tries to detect the bitstream format and +in case of MPEG-4 file format or Raw Packets file format (a Fraunhofer IIS proprietary format) reads the Audio +Specific Config data (ASC). An unsuccessful attempt to recognize the bitstream format requires the user to +provide this information manually (see \ref CommandLineUsage). For any other bitstream formats that are +usually applicable in streaming applications, the decoder itself will try to synchronize and parse the given +bitstream fragment using the FDK transport library. Hence, for streaming applications (without file access) +this step is not necessary. + +-# Call aacDecoder_Open() to open and retrieve a handle to a new AAC decoder instance. +\dontinclude main.cpp +\skipline aacDecoder_Open +-# If out-of-band config data (Audio Specific Config (ASC) or Stream Mux Config (SMC)) is available, call +aacDecoder_ConfigRaw() to pass it to the decoder and before the decoding process starts. If this data is +not available in advance, the decoder will get it from the bitstream and configure itself while decoding +with aacDecoder_DecodeFrame(). +-# Begin decoding loop. +\skipline do { +-# Read data from bitstream file or stream into a client-supplied input buffer ("inBuffer" in main.cpp). +If it is very small like just 4, aacDecoder_DecodeFrame() will +repeatedly return ::AAC_DEC_NOT_ENOUGH_BITS until enough bits were fed by aacDecoder_Fill(). Only read data +when this buffer has completely been processed and is then empty. For file-based input execute +mpegFileRead_Read() or any other implementation with similar functionality. +-# Call aacDecoder_Fill() to fill the decoder's internal bitstream input buffer with the client-supplied +external bitstream input buffer. +\skipline aacDecoder_Fill +-# Call aacDecoder_DecodeFrame() which writes decoded PCM audio data to a client-supplied buffer. It is the +client's responsibility to allocate a buffer which is large enough to hold this output data. +\skipline aacDecoder_DecodeFrame +If the bitstream's configuration (number of channels, sample rate, frame size) is not known in advance, you may +call aacDecoder_GetStreamInfo() to retrieve a structure containing this information and then initialize an audio +output device. In the example main.cpp, if the number of channels or the sample rate has changed since program +start or since the previously decoded frame, the audio output device will be re-initialized. If WAVE file output +is chosen, a new WAVE file for each new configuration will be created. +\skipline aacDecoder_GetStreamInfo +-# Repeat steps 5 to 7 until no data to decode is available anymore, or if an error occured. +\skipline } while +-# Call aacDecoder_Close() to de-allocate all AAC decoder and transport layer structures. +\skipline aacDecoder_Close + +\section BufferSystem Buffer System + +There are three main buffers in an AAC decoder application. One external input buffer to hold bitstream +data from file I/O or elsewhere, one decoder-internal input buffer, and one to hold the decoded output +PCM sample data, whereas this output buffer may overlap with the external input buffer. + +The external input buffer is set in the example framework main.cpp and its size is defined by ::IN_BUF_SIZE. +You may freely choose different sizes here. To feed the data to the decoder-internal input buffer, use the +function aacDecoder_Fill(). This function returns important information about how many bytes in the +external input buffer have not yet been copied into the internal input buffer (variable bytesValid). +Once the external buffer has been fully copied, it can be re-filled again. +In case you want to re-fill it when there are still unprocessed bytes (bytesValid is unequal 0), you +would have to additionally perform a memcpy(), so that just means unnecessary computational overhead +and therefore we recommend to re-fill the buffer only when bytesValid is 0. + +\image latex dec_buffer.png "Lifecycle of the external input buffer" width=9cm + +The size of the decoder-internal input buffer is set in tpdec_lib.h (see define ::TRANSPORTDEC_INBUF_SIZE). +You may choose a smaller size under the following considerations: + +- each input channel requires 768 bytes +- the whole buffer must be of size 2^n + +So for example a stereo decoder: + +\f[ +TRANSPORTDEC\_INBUF\_SIZE = 2 * 768 = 1536 => 2048 +\f] + +tpdec_lib.h and TRANSPORTDEC_INBUF_SIZE are not part of the decoder's library interface. Therefore +only source-code clients may change this setting. If you received a library release, please ask us and +we can change this in order to meet your memory requirements. + +\page OutputFormat Decoder audio output + +\section OutputFormatObtaining Obtaining channel mapping information + +The decoded audio output format is indicated by a set of variables of the CStreamInfo structure. +While the members sampleRate, frameSize and numChannels might be quite self explaining, +pChannelType and pChannelIndices might require some more detailed explanation. + +These two arrays indicate what is each output channel supposed to be. Both array have +CStreamInfo::numChannels cells. Each cell of pChannelType indicates the channel type, described in +the enum ::AUDIO_CHANNEL_TYPE defined in FDK_audio.h. The cells of pChannelIndices indicate the sub index +among the channels starting with 0 among all channels of the same audio channel type. + +The indexing scheme is the same as for MPEG-2/4. Thus indices are counted upwards starting from the front +direction (thus a center channel if any, will always be index 0). Then the indices count up, starting always +with the left side, pairwise from front toward back. For detailed explanation, please refer to +ISO/IEC 13818-7:2005(E), chapter 8.5.3.2. + +In case a Program Config is included in the audio configuration, the channel mapping described within +it will be adopted. + +In case of MPEG-D Surround the channel mapping will follow the same criteria described in ISO/IEC 13818-7:2005(E), +but adding corresponding top channels to the channel types front, side and back, in order to avoid any +loss of information. + +\section OutputFormatChange Changing the audio output format + +The channel interleaving scheme and the actual channel order can be changed at runtime through the +parameters ::AAC_PCM_OUTPUT_INTERLEAVED and ::AAC_PCM_OUTPUT_CHANNEL_MAPPING. See the description of those +parameters and the decoder library function aacDecoder_SetParam() for more detail. + +\section OutputFormatExample Channel mapping examples + +The following examples illustrate the location of individual audio samples in the audio buffer that +is passed to aacDecoder_DecodeFrame() and the expected data in the CStreamInfo structure which can be obtained +by calling aacDecoder_GetStreamInfo(). + +\subsection ExamplesStereo Stereo + +In case of ::AAC_PCM_OUTPUT_INTERLEAVED set to 0 and ::AAC_PCM_OUTPUT_CHANNEL_MAPPING set to 1, +a AAC-LC bit stream which has channelConfiguration = 2 in its audio specific config would lead +to the following values in CStreamInfo: + +CStreamInfo::numChannels = 2 + +CStreamInfo::pChannelType = { ::ACT_FRONT, ::ACT_FRONT } + +CStreamInfo::pChannelIndices = { 0, 1 } + +Since ::AAC_PCM_OUTPUT_INTERLEAVED is set to 0, the audio channels will be located as contiguous blocks +in the output buffer as follows: + +\verbatim + ... + ... +\endverbatim + +Where N equals to CStreamInfo::frameSize . + +\subsection ExamplesSurround Surround 5.1 + +In case of ::AAC_PCM_OUTPUT_INTERLEAVED set to 1 and ::AAC_PCM_OUTPUT_CHANNEL_MAPPING set to 1, +a AAC-LC bit stream which has channelConfiguration = 6 in its audio specific config, would lead +to the following values in CStreamInfo: + +CStreamInfo::numChannels = 6 + +CStreamInfo::pChannelType = { ::ACT_FRONT, ::ACT_FRONT, ::ACT_FRONT, ::ACT_LFE, ::ACT_BACK, ::ACT_BACK } + +CStreamInfo::pChannelIndices = { 1, 2, 0, 0, 0, 1 } + +Since ::AAC_PCM_OUTPUT_CHANNEL_MAPPING is 1, WAV file channel ordering will be used. For a 5.1 channel +scheme, thus the channels would be: front left, front right, center, LFE, surround left, surround right. +Thus the third channel is the center channel, receiving the index 0. The other front channels are +front left, front right being placed as first and second channels with indices 1 and 2 correspondingly. +There is only one LFE, placed as the fourth channel and index 0. Finally both surround +channels get the type definition ACT_BACK, and the indices 0 and 1. + +Since ::AAC_PCM_OUTPUT_INTERLEAVED is set to 1, the audio channels will be placed in the output buffer +as follows: + +\verbatim + +
+ + + +
+ + +... + + +
+ +\endverbatim + +Where N equals to CStreamInfo::frameSize . + +\subsection ExamplesArib ARIB coding mode 2/1 + +In case of ::AAC_PCM_OUTPUT_INTERLEAVED set to 1 and ::AAC_PCM_OUTPUT_CHANNEL_MAPPING set to 1, +in case of a ARIB bit stream using coding mode 2/1 as described in ARIB STD-B32 Part 2 Version 2.1-E1, page 61, +would lead to the following values in CStreamInfo: + +CStreamInfo::numChannels = 3 + +CStreamInfo::pChannelType = { ::ACT_FRONT, ::ACT_FRONT,:: ACT_BACK } + +CStreamInfo::pChannelIndices = { 0, 1, 0 } + +The audio channels will be placed as follows in the audio output buffer: + +\verbatim + + + + +... + + + +Where N equals to CStreamInfo::frameSize . + +\endverbatim + +*/ + +#ifndef AACDECODER_LIB_H +#define AACDECODER_LIB_H + +#include "machine_type.h" +#include "FDK_audio.h" + +#include "genericStds.h" + +/** + * \brief AAC decoder error codes. + */ +typedef enum { + AAC_DEC_OK = 0x0000, /*!< No error occured. Output buffer is valid and error free. */ + AAC_DEC_OUT_OF_MEMORY = 0x0002, /*!< Heap returned NULL pointer. Output buffer is invalid. */ + AAC_DEC_UNKNOWN = 0x0005, /*!< Error condition is of unknown reason, or from a another module. Output buffer is invalid. */ + + /* Synchronization errors. Output buffer is invalid. */ + aac_dec_sync_error_start = 0x1000, + AAC_DEC_TRANSPORT_SYNC_ERROR = 0x1001, /*!< The transport decoder had syncronisation problems. Do not exit decoding. Just feed new + bitstream data. */ + AAC_DEC_NOT_ENOUGH_BITS = 0x1002, /*!< The input buffer ran out of bits. */ + aac_dec_sync_error_end = 0x1FFF, + + /* Initialization errors. Output buffer is invalid. */ + aac_dec_init_error_start = 0x2000, + AAC_DEC_INVALID_HANDLE = 0x2001, /*!< The handle passed to the function call was invalid (NULL). */ + AAC_DEC_UNSUPPORTED_AOT = 0x2002, /*!< The AOT found in the configuration is not supported. */ + AAC_DEC_UNSUPPORTED_FORMAT = 0x2003, /*!< The bitstream format is not supported. */ + AAC_DEC_UNSUPPORTED_ER_FORMAT = 0x2004, /*!< The error resilience tool format is not supported. */ + AAC_DEC_UNSUPPORTED_EPCONFIG = 0x2005, /*!< The error protection format is not supported. */ + AAC_DEC_UNSUPPORTED_MULTILAYER = 0x2006, /*!< More than one layer for AAC scalable is not supported. */ + AAC_DEC_UNSUPPORTED_CHANNELCONFIG = 0x2007, /*!< The channel configuration (either number or arrangement) is not supported. */ + AAC_DEC_UNSUPPORTED_SAMPLINGRATE = 0x2008, /*!< The sample rate specified in the configuration is not supported. */ + AAC_DEC_INVALID_SBR_CONFIG = 0x2009, /*!< The SBR configuration is not supported. */ + AAC_DEC_SET_PARAM_FAIL = 0x200A, /*!< The parameter could not be set. Either the value was out of range or the parameter does + not exist. */ + AAC_DEC_NEED_TO_RESTART = 0x200B, /*!< The decoder needs to be restarted, since the requiered configuration change cannot be + performed. */ + aac_dec_init_error_end = 0x2FFF, + + /* Decode errors. Output buffer is valid but concealed. */ + aac_dec_decode_error_start = 0x4000, + AAC_DEC_TRANSPORT_ERROR = 0x4001, /*!< The transport decoder encountered an unexpected error. */ + AAC_DEC_PARSE_ERROR = 0x4002, /*!< Error while parsing the bitstream. Most probably it is corrupted, or the system crashed. */ + AAC_DEC_UNSUPPORTED_EXTENSION_PAYLOAD = 0x4003, /*!< Error while parsing the extension payload of the bitstream. The extension payload type + found is not supported. */ + AAC_DEC_DECODE_FRAME_ERROR = 0x4004, /*!< The parsed bitstream value is out of range. Most probably the bitstream is corrupt, or + the system crashed. */ + AAC_DEC_CRC_ERROR = 0x4005, /*!< The embedded CRC did not match. */ + AAC_DEC_INVALID_CODE_BOOK = 0x4006, /*!< An invalid codebook was signalled. Most probably the bitstream is corrupt, or the system + crashed. */ + AAC_DEC_UNSUPPORTED_PREDICTION = 0x4007, /*!< Predictor found, but not supported in the AAC Low Complexity profile. Most probably the + bitstream is corrupt, or has a wrong format. */ + AAC_DEC_UNSUPPORTED_CCE = 0x4008, /*!< A CCE element was found which is not supported. Most probably the bitstream is corrupt, or + has a wrong format. */ + AAC_DEC_UNSUPPORTED_LFE = 0x4009, /*!< A LFE element was found which is not supported. Most probably the bitstream is corrupt, or + has a wrong format. */ + AAC_DEC_UNSUPPORTED_GAIN_CONTROL_DATA = 0x400A, /*!< Gain control data found but not supported. Most probably the bitstream is corrupt, or has + a wrong format. */ + AAC_DEC_UNSUPPORTED_SBA = 0x400B, /*!< SBA found, but currently not supported in the BSAC profile. */ + AAC_DEC_TNS_READ_ERROR = 0x400C, /*!< Error while reading TNS data. Most probably the bitstream is corrupt or the system + crashed. */ + AAC_DEC_RVLC_ERROR = 0x400D, /*!< Error while decoding error resillient data. */ + aac_dec_decode_error_end = 0x4FFF, + + /* Ancillary data errors. Output buffer is valid. */ + aac_dec_anc_data_error_start = 0x8000, + AAC_DEC_ANC_DATA_ERROR = 0x8001, /*!< Non severe error concerning the ancillary data handling. */ + AAC_DEC_TOO_SMALL_ANC_BUFFER = 0x8002, /*!< The registered ancillary data buffer is too small to receive the parsed data. */ + AAC_DEC_TOO_MANY_ANC_ELEMENTS = 0x8003, /*!< More than the allowed number of ancillary data elements should be written to buffer. */ + aac_dec_anc_data_error_end = 0x8FFF + + +} AAC_DECODER_ERROR; + + +/** Macro to identify initialization errors. */ +#define IS_INIT_ERROR(err) ( (((err)>=aac_dec_init_error_start) && ((err)<=aac_dec_init_error_end)) ? 1 : 0) +/** Macro to identify decode errors. */ +#define IS_DECODE_ERROR(err) ( (((err)>=aac_dec_decode_error_start) && ((err)<=aac_dec_decode_error_end)) ? 1 : 0) +/** Macro to identify if the audio output buffer contains valid samples after calling aacDecoder_DecodeFrame(). */ +#define IS_OUTPUT_VALID(err) ( ((err) == AAC_DEC_OK) || IS_DECODE_ERROR(err) ) + +/** + * \brief AAC decoder setting parameters + */ +typedef enum +{ + AAC_PCM_OUTPUT_INTERLEAVED = 0x0000, /*!< PCM output mode (1: interleaved (default); 0: not interleaved). */ + AAC_PCM_OUTPUT_CHANNELS = 0x0001, /*!< Number of PCM output channels (if different from encoded audio channels, downmixing or + upmixing is applied). \n + -1: Disable up-/downmixing. The decoder output contains the same number of channels as the + encoded bitstream. \n + 1: The decoder performs a mono matrix mix-down if the encoded audio channels are greater + than one. Thus it ouputs always exact one channel. \n + 2: The decoder performs a stereo matrix mix-down if the encoded audio channels are greater + than two. If the encoded audio channels are smaller than two the decoder duplicates the + output. Thus it ouputs always exact two channels. \n */ + AAC_PCM_DUAL_CHANNEL_OUTPUT_MODE = 0x0002, /*!< Defines how the decoder processes two channel signals: + 0: Leave both signals as they are (default). + 1: Create a dual mono output signal from channel 1. + 2: Create a dual mono output signal from channel 2. + 3: Create a dual mono output signal by mixing both channels (L' = R' = 0.5*Ch1 + 0.5*Ch2). */ + AAC_PCM_OUTPUT_CHANNEL_MAPPING = 0x0003, /*!< Output buffer channel ordering. 0: MPEG PCE style order, 1: WAV file channel order (default). */ + + AAC_CONCEAL_METHOD = 0x0100, /*!< Error concealment: Processing method. \n + 0: Spectral muting. \n + 1: Noise substitution (see ::CONCEAL_NOISE). \n + 2: Energy interpolation (adds additional signal delay of one frame, see ::CONCEAL_INTER). \n */ + + AAC_DRC_BOOST_FACTOR = 0x0200, /*!< Dynamic Range Control: Scaling factor for boosting gain values. + Defines how the boosting DRC factors (conveyed in the bitstream) will be applied to the + decoded signal. The valid values range from 0 (don't apply boost factors) to 127 (fully + apply all boosting factors). */ + AAC_DRC_ATTENUATION_FACTOR = 0x0201, /*!< Dynamic Range Control: Scaling factor for attenuating gain values. Same as + AAC_DRC_BOOST_FACTOR but for attenuating DRC factors. */ + AAC_DRC_REFERENCE_LEVEL = 0x0202, /*!< Dynamic Range Control: Target reference level. Defines the level below full-scale + (quantized in steps of 0.25dB) to which the output audio signal will be normalized to by + the DRC module. The valid values range from 0 (full-scale) to 127 (31.75 dB below + full-scale). The value smaller than 0 switches off normalization. */ + AAC_DRC_HEAVY_COMPRESSION = 0x0203, /*!< Dynamic Range Control: En-/Disable DVB specific heavy compression (aka RF mode). + If set to 1, the decoder will apply the compression values from the DVB specific ancillary + data field. At the same time the MPEG-4 Dynamic Range Control tool will be disabled. By + default heavy compression is disabled. */ + + AAC_QMF_LOWPOWER = 0x0300, /*!< Quadrature Mirror Filter (QMF) Bank processing mode. \n + -1: Use internal default. Implies MPEG Surround partially complex accordingly. \n + 0: Use complex QMF data mode. \n + 1: Use real (low power) QMF data mode. \n */ + + AAC_MPEGS_ENABLE = 0x0500, /*!< MPEG Surround: Allow/Disable decoding of MPS content. Available only for decoders with MPEG + Surround support. */ + + AAC_TPDEC_CLEAR_BUFFER = 0x0603 /*!< Clear internal bit stream buffer of transport layers. The decoder will start decoding + at new data passed after this event and any previous data is discarded. */ + +} AACDEC_PARAM; + +/** + * \brief This structure gives information about the currently decoded audio data. + * All fields are read-only. + */ +typedef struct +{ + /* These three members are the only really relevant ones for the user. */ + INT sampleRate; /*!< The samplerate in Hz of the fully decoded PCM audio signal (after SBR processing). */ + INT frameSize; /*!< The frame size of the decoded PCM audio signal. \n + 1024 or 960 for AAC-LC \n + 2048 or 1920 for HE-AAC (v2) \n + 512 or 480 for AAC-LD and AAC-ELD */ + INT numChannels; /*!< The number of output audio channels in the decoded and interleaved PCM audio signal. */ + AUDIO_CHANNEL_TYPE *pChannelType; /*!< Audio channel type of each output audio channel. */ + UCHAR *pChannelIndices; /*!< Audio channel index for each output audio channel. + See ISO/IEC 13818-7:2005(E), 8.5.3.2 Explicit channel mapping using a program_config_element() */ + /* Decoder internal members. */ + INT aacSampleRate; /*!< sampling rate in Hz without SBR (from configuration info). */ + INT profile; /*!< MPEG-2 profile (from file header) (-1: not applicable (e. g. MPEG-4)). */ + AUDIO_OBJECT_TYPE aot; /*!< Audio Object Type (from ASC): is set to the appropriate value for MPEG-2 bitstreams (e. g. 2 for AAC-LC). */ + INT channelConfig; /*!< Channel configuration (0: PCE defined, 1: mono, 2: stereo, ... */ + INT bitRate; /*!< Instantaneous bit rate. */ + INT aacSamplesPerFrame; /*!< Samples per frame for the AAC core (from ASC). \n + 1024 or 960 for AAC-LC \n + 512 or 480 for AAC-LD and AAC-ELD */ + + AUDIO_OBJECT_TYPE extAot; /*!< Extension Audio Object Type (from ASC) */ + INT extSamplingRate; /*!< Extension sampling rate in Hz (from ASC) */ + + UINT flags; /*!< Copy if internal flags. Only to be written by the decoder, and only to be read externally. */ + + SCHAR epConfig; /*!< epConfig level (from ASC): only level 0 supported, -1 means no ER (e. g. AOT=2, MPEG-2 AAC, etc.) */ + + /* Statistics */ + INT numLostAccessUnits; /*!< This integer will reflect the estimated amount of lost access units in case aacDecoder_DecodeFrame() + returns AAC_DEC_TRANSPORT_SYNC_ERROR. It will be < 0 if the estimation failed. */ + + UINT numTotalBytes; /*!< This is the number of total bytes that have passed through the decoder. */ + UINT numBadBytes; /*!< This is the number of total bytes that were considered with errors from numTotalBytes. */ + UINT numTotalAccessUnits; /*!< This is the number of total access units that have passed through the decoder. */ + UINT numBadAccessUnits; /*!< This is the number of total access units that were considered with errors from numTotalBytes. */ + +} CStreamInfo; + + +typedef struct AAC_DECODER_INSTANCE *HANDLE_AACDECODER; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * \brief Initialize ancillary data buffer. + * + * \param self AAC decoder handle. + * \param buffer Pointer to (external) ancillary data buffer. + * \param size Size of the buffer pointed to by buffer. + * \return Error code. + */ +LINKSPEC_H AAC_DECODER_ERROR +aacDecoder_AncDataInit ( HANDLE_AACDECODER self, + UCHAR *buffer, + int size ); + +/** + * \brief Get one ancillary data element. + * + * \param self AAC decoder handle. + * \param index Index of the ancillary data element to get. + * \param ptr Pointer to a buffer receiving a pointer to the requested ancillary data element. + * \param size Pointer to a buffer receiving the length of the requested ancillary data element. + * \return Error code. + */ +LINKSPEC_H AAC_DECODER_ERROR +aacDecoder_AncDataGet ( HANDLE_AACDECODER self, + int index, + UCHAR **ptr, + int *size ); + +/** + * \brief Set one single decoder parameter. + * + * \param self AAC decoder handle. + * \param param Parameter to be set. + * \param value Parameter value. + * \return Error code. + */ +LINKSPEC_H AAC_DECODER_ERROR +aacDecoder_SetParam ( const HANDLE_AACDECODER self, + const AACDEC_PARAM param, + const INT value ); + + +/** + * \brief Get free bytes inside decoder internal buffer + * \param self Handle of AAC decoder instance + * \param pFreeBytes Pointer to variable receving amount of free bytes inside decoder internal buffer + * \return Error code + */ +LINKSPEC_H AAC_DECODER_ERROR +aacDecoder_GetFreeBytes ( const HANDLE_AACDECODER self, + UINT *pFreeBytes); + +/** + * \brief Open an AAC decoder instance + * \param transportFmt The transport type to be used + * \return AAC decoder handle + */ +LINKSPEC_H HANDLE_AACDECODER +aacDecoder_Open ( TRANSPORT_TYPE transportFmt, UINT nrOfLayers ); + +/** + * \brief Explicitly configure the decoder by passing a raw AudioSpecificConfig (ASC) or a StreamMuxConfig (SMC), + * contained in a binary buffer. This is required for MPEG-4 and Raw Packets file format bitstreams + * as well as for LATM bitstreams with no in-band SMC. If the transport format is LATM with or without + * LOAS, configuration is assumed to be an SMC, for all other file formats an ASC. + * + * \param self AAC decoder handle. + * \param conf Pointer to an unsigned char buffer containing the binary configuration buffer (either ASC or SMC). + * \param length Length of the configuration buffer in bytes. + * \return Error code. + */ +LINKSPEC_H AAC_DECODER_ERROR +aacDecoder_ConfigRaw ( HANDLE_AACDECODER self, + UCHAR *conf[], + const UINT length[] ); + + +/** + * \brief Fill AAC decoder's internal input buffer with bitstream data from the external input buffer. + * The function only copies such data as long as the decoder-internal input buffer is not full. + * So it grabs whatever it can from pBuffer and returns information (bytesValid) so that at a + * subsequent call of %aacDecoder_Fill(), the right position in pBuffer can be determined to + * grab the next data. + * + * \param self AAC decoder handle. + * \param pBuffer Pointer to external input buffer. + * \param bufferSize Size of external input buffer. This argument is required because decoder-internally + * we need the information to calculate the offset to pBuffer, where the next + * available data is, which is then fed into the decoder-internal buffer (as much + * as possible). Our example framework implementation fills the buffer at pBuffer + * again, once it contains no available valid bytes anymore (meaning bytesValid equal 0). + * \param bytesValid Number of bitstream bytes in the external bitstream buffer that have not yet been + * copied into the decoder's internal bitstream buffer by calling this function. + * The value is updated according to the amount of newly copied bytes. + * \return Error code. + */ +LINKSPEC_H AAC_DECODER_ERROR +aacDecoder_Fill ( HANDLE_AACDECODER self, + UCHAR *pBuffer[], + const UINT bufferSize[], + UINT *bytesValid ); + +#define AACDEC_CONCEAL 1 /*!< Flag for aacDecoder_DecodeFrame(): do not consider new input data. Do concealment. */ +#define AACDEC_FLUSH 2 /*!< Flag for aacDecoder_DecodeFrame(): Do not consider new input data. Flush filterbanks (output delayed audio). */ +#define AACDEC_INTR 4 /*!< Flag for aacDecoder_DecodeFrame(): Signal an input bit stream data discontinuity. Resync any internals as necessary. */ +#define AACDEC_CLRHIST 8 /*!< Flag for aacDecoder_DecodeFrame(): Clear all signal delay lines and history buffers. + Caution: This can cause discontinuities in the output signal. */ + +/** + * \brief Decode one audio frame + * + * \param self AAC decoder handle. + * \param pTimeData Pointer to external output buffer where the decoded PCM samples will be stored into. + * \param flags Bit field with flags for the decoder: \n + * (flags & AACDEC_CONCEAL) == 1: Do concealment. \n + * (flags & AACDEC_FLUSH) == 2: Discard input data. Flush filter banks (output delayed audio). \n + * (flags & AACDEC_INTR) == 4: Input data is discontinuous. Resynchronize any internals as necessary. + * \return Error code. + */ +LINKSPEC_H AAC_DECODER_ERROR +aacDecoder_DecodeFrame ( HANDLE_AACDECODER self, + INT_PCM *pTimeData, + const INT timeDataSize, + const UINT flags ); + +/** + * \brief De-allocate all resources of an AAC decoder instance. + * + * \param self AAC decoder handle. + * \return void + */ +LINKSPEC_H void aacDecoder_Close ( HANDLE_AACDECODER self ); + +/** + * \brief Get CStreamInfo handle from decoder. + * + * \param self AAC decoder handle. + * \return Reference to requested CStreamInfo. + */ +LINKSPEC_H CStreamInfo* aacDecoder_GetStreamInfo( HANDLE_AACDECODER self ); + +/** + * \brief Get decoder library info. + * + * \param info Pointer to an allocated LIB_INFO structure. + * \return 0 on success + */ +LINKSPEC_H INT aacDecoder_GetLibInfo( LIB_INFO *info ); + + +#ifdef __cplusplus +} +#endif + +#endif /* AACDECODER_LIB_H */ diff --git a/libAACdec/src/Android.mk b/libAACdec/src/Android.mk new file mode 100644 index 0000000..ae53694 --- /dev/null +++ b/libAACdec/src/Android.mk @@ -0,0 +1,39 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + aacdec_drc.cpp \ + aacdec_hcr.cpp \ + aacdecoder.cpp \ + aacdec_pns.cpp \ + aac_ram.cpp \ + block.cpp \ + channelinfo.cpp \ + ldfiltbank.cpp \ + rvlcbit.cpp \ + rvlc.cpp \ + aacdec_hcr_bit.cpp \ + aacdec_hcrs.cpp \ + aacdecoder_lib.cpp \ + aacdec_tns.cpp \ + aac_rom.cpp \ + channel.cpp \ + conceal.cpp \ + pulsedata.cpp \ + rvlcconceal.cpp \ + stereo.cpp + +LOCAL_CFLAGS := -DANDROID + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../../libPCMutils/include \ + $(LOCAL_PATH)/../../libFDK/include \ + $(LOCAL_PATH)/../../libSYS/include \ + $(LOCAL_PATH)/../../libMpegTPDec/include \ + $(LOCAL_PATH)/../../libSBRdec/include + +LOCAL_MODULE:= libAACdec + +include $(BUILD_STATIC_LIBRARY) diff --git a/libAACdec/src/aac_ram.cpp b/libAACdec/src/aac_ram.cpp new file mode 100644 index 0000000..ce8aee6 --- /dev/null +++ b/libAACdec/src/aac_ram.cpp @@ -0,0 +1,81 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2002) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "aac_ram.h" +#include "aac_rom.h" + +#define WORKBUFFER1_TAG 0 +#define WORKBUFFER2_TAG 1 + +/*! The structure AAC_DECODER_INSTANCE is the top level structure holding all decoder configurations, + handles and structs. + */ +C_ALLOC_MEM(AacDecoder, AAC_DECODER_INSTANCE, 1) + +/*! + \name StaticAacData + + Static memory areas, must not be overwritten in other sections of the decoder +*/ +/* @{ */ + +/*! The structure CAacDecoderStaticChannelInfo contains the static sideinfo which is needed + for the decoding of one aac channel.
+ Dimension: #AacDecoderChannels */ +C_ALLOC_MEM2(AacDecoderStaticChannelInfo, CAacDecoderStaticChannelInfo, 1, (6)) + +/*! The structure CAacDecoderChannelInfo contains the dynamic sideinfo which is needed + for the decoding of one aac channel.
+ Dimension: #AacDecoderChannels */ +C_ALLOC_MEM2(AacDecoderChannelInfo, CAacDecoderChannelInfo, 1, (6)) + +/*! Overlap buffer */ +C_ALLOC_MEM2(OverlapBuffer, FIXP_DBL, OverlapBufferSize, (6)) + +C_ALLOC_MEM(DrcInfo, CDrcInfo, 1) + +/* @} */ + +/*! + \name DynamicAacData + + Dynamic memory areas, might be reused in other algorithm sections, + e.g. the sbr decoder +*/ +C_ALLOC_MEM_OVERLAY(WorkBufferCore2, FIXP_DBL, ((6)*1024), SECT_DATA_L2, WORKBUFFER2_TAG) + + +C_ALLOC_MEM_OVERLAY(WorkBufferCore1, CWorkBufferCore1, 1, SECT_DATA_L1, WORKBUFFER1_TAG) + +/* @{ */ + + +/* @} */ + + + diff --git a/libAACdec/src/aac_ram.h b/libAACdec/src/aac_ram.h new file mode 100644 index 0000000..7c129e2 --- /dev/null +++ b/libAACdec/src/aac_ram.h @@ -0,0 +1,58 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef AAC_RAM_H +#define AAC_RAM_H + +#include "common_fix.h" + +#include "aacdecoder.h" + +#include "channel.h" + +#include "aacdec_hcr_types.h" +#include "aacdec_hcr.h" + +/* End of formal fix.h */ + +#define MAX_SYNCHS 10 +#define SAMPL_FREQS 12 + +H_ALLOC_MEM(AacDecoder, AAC_DECODER_INSTANCE) + +H_ALLOC_MEM(DrcInfo, CDrcInfo) + +H_ALLOC_MEM(AacDecoderStaticChannelInfo, CAacDecoderStaticChannelInfo) +H_ALLOC_MEM(AacDecoderChannelInfo, CAacDecoderChannelInfo) +H_ALLOC_MEM(OverlapBuffer, FIXP_DBL) + +H_ALLOC_MEM_OVERLAY(WorkBufferCore1, CWorkBufferCore1) +H_ALLOC_MEM_OVERLAY(WorkBufferCore2, FIXP_DBL) + + +#endif /* #ifndef AAC_RAM_H */ diff --git a/libAACdec/src/aac_rom.cpp b/libAACdec/src/aac_rom.cpp new file mode 100644 index 0000000..c4246c0 --- /dev/null +++ b/libAACdec/src/aac_rom.cpp @@ -0,0 +1,1780 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: Definition of constant tables + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "aac_rom.h" + + +/* Prescale InverseQuantTable by 4 to save + redundant shifts in invers quantization + */ +#define SCL_TAB(a) (a>>4) +const FIXP_DBL InverseQuantTable [INV_QUANT_TABLESIZE + 1] = +{ + SCL_TAB(0x32CBFD40), SCL_TAB(0x330FC340), SCL_TAB(0x33539FC0), SCL_TAB(0x33979280), SCL_TAB(0x33DB9BC0), SCL_TAB(0x341FBB80), SCL_TAB(0x3463F180), SCL_TAB(0x34A83DC0), + SCL_TAB(0x34ECA000), SCL_TAB(0x35311880), SCL_TAB(0x3575A700), SCL_TAB(0x35BA4B80), SCL_TAB(0x35FF0600), SCL_TAB(0x3643D680), SCL_TAB(0x3688BCC0), SCL_TAB(0x36CDB880), + SCL_TAB(0x3712CA40), SCL_TAB(0x3757F1C0), SCL_TAB(0x379D2F00), SCL_TAB(0x37E28180), SCL_TAB(0x3827E9C0), SCL_TAB(0x386D6740), SCL_TAB(0x38B2FA40), SCL_TAB(0x38F8A2C0), + SCL_TAB(0x393E6080), SCL_TAB(0x39843380), SCL_TAB(0x39CA1BC0), SCL_TAB(0x3A101940), SCL_TAB(0x3A562BC0), SCL_TAB(0x3A9C5340), SCL_TAB(0x3AE28FC0), SCL_TAB(0x3B28E180), + SCL_TAB(0x3B6F4800), SCL_TAB(0x3BB5C340), SCL_TAB(0x3BFC5380), SCL_TAB(0x3C42F880), SCL_TAB(0x3C89B200), SCL_TAB(0x3CD08080), SCL_TAB(0x3D176340), SCL_TAB(0x3D5E5B00), + SCL_TAB(0x3DA56700), SCL_TAB(0x3DEC87C0), SCL_TAB(0x3E33BCC0), SCL_TAB(0x3E7B0640), SCL_TAB(0x3EC26400), SCL_TAB(0x3F09D640), SCL_TAB(0x3F515C80), SCL_TAB(0x3F98F740), + SCL_TAB(0x3FE0A600), SCL_TAB(0x40286900), SCL_TAB(0x40704000), SCL_TAB(0x40B82B00), SCL_TAB(0x41002A00), SCL_TAB(0x41483D00), SCL_TAB(0x41906400), SCL_TAB(0x41D89F00), + SCL_TAB(0x4220ED80), SCL_TAB(0x42695000), SCL_TAB(0x42B1C600), SCL_TAB(0x42FA5000), SCL_TAB(0x4342ED80), SCL_TAB(0x438B9E80), SCL_TAB(0x43D46380), SCL_TAB(0x441D3B80), + SCL_TAB(0x44662780), SCL_TAB(0x44AF2680), SCL_TAB(0x44F83900), SCL_TAB(0x45415F00), SCL_TAB(0x458A9880), SCL_TAB(0x45D3E500), SCL_TAB(0x461D4500), SCL_TAB(0x4666B800), + SCL_TAB(0x46B03E80), SCL_TAB(0x46F9D800), SCL_TAB(0x47438480), SCL_TAB(0x478D4400), SCL_TAB(0x47D71680), SCL_TAB(0x4820FC00), SCL_TAB(0x486AF500), SCL_TAB(0x48B50000), + SCL_TAB(0x48FF1E80), SCL_TAB(0x49494F80), SCL_TAB(0x49939380), SCL_TAB(0x49DDEA80), SCL_TAB(0x4A285400), SCL_TAB(0x4A72D000), SCL_TAB(0x4ABD5E80), SCL_TAB(0x4B080000), + SCL_TAB(0x4B52B400), SCL_TAB(0x4B9D7A80), SCL_TAB(0x4BE85380), SCL_TAB(0x4C333F00), SCL_TAB(0x4C7E3D00), SCL_TAB(0x4CC94D00), SCL_TAB(0x4D146F80), SCL_TAB(0x4D5FA500), + SCL_TAB(0x4DAAEC00), SCL_TAB(0x4DF64580), SCL_TAB(0x4E41B180), SCL_TAB(0x4E8D2F00), SCL_TAB(0x4ED8BF80), SCL_TAB(0x4F246180), SCL_TAB(0x4F701600), SCL_TAB(0x4FBBDC00), + SCL_TAB(0x5007B480), SCL_TAB(0x50539F00), SCL_TAB(0x509F9B80), SCL_TAB(0x50EBA980), SCL_TAB(0x5137C980), SCL_TAB(0x5183FB80), SCL_TAB(0x51D03F80), SCL_TAB(0x521C9500), + SCL_TAB(0x5268FC80), SCL_TAB(0x52B57580), SCL_TAB(0x53020000), SCL_TAB(0x534E9C80), SCL_TAB(0x539B4A80), SCL_TAB(0x53E80A80), SCL_TAB(0x5434DB80), SCL_TAB(0x5481BE80), + SCL_TAB(0x54CEB280), SCL_TAB(0x551BB880), SCL_TAB(0x5568CF80), SCL_TAB(0x55B5F800), SCL_TAB(0x56033200), SCL_TAB(0x56507D80), SCL_TAB(0x569DDA00), SCL_TAB(0x56EB4800), + SCL_TAB(0x5738C700), SCL_TAB(0x57865780), SCL_TAB(0x57D3F900), SCL_TAB(0x5821AC00), SCL_TAB(0x586F7000), SCL_TAB(0x58BD4500), SCL_TAB(0x590B2B00), SCL_TAB(0x59592200), + SCL_TAB(0x59A72A80), SCL_TAB(0x59F54380), SCL_TAB(0x5A436D80), SCL_TAB(0x5A91A900), SCL_TAB(0x5ADFF500), SCL_TAB(0x5B2E5180), SCL_TAB(0x5B7CBF80), SCL_TAB(0x5BCB3E00), + SCL_TAB(0x5C19CD00), SCL_TAB(0x5C686D80), SCL_TAB(0x5CB71E00), SCL_TAB(0x5D05DF80), SCL_TAB(0x5D54B200), SCL_TAB(0x5DA39500), SCL_TAB(0x5DF28880), SCL_TAB(0x5E418C80), + SCL_TAB(0x5E90A100), SCL_TAB(0x5EDFC680), SCL_TAB(0x5F2EFC00), SCL_TAB(0x5F7E4280), SCL_TAB(0x5FCD9900), SCL_TAB(0x601D0080), SCL_TAB(0x606C7800), SCL_TAB(0x60BC0000), + SCL_TAB(0x610B9800), SCL_TAB(0x615B4100), SCL_TAB(0x61AAF980), SCL_TAB(0x61FAC300), SCL_TAB(0x624A9C80), SCL_TAB(0x629A8600), SCL_TAB(0x62EA8000), SCL_TAB(0x633A8A00), + SCL_TAB(0x638AA480), SCL_TAB(0x63DACF00), SCL_TAB(0x642B0980), SCL_TAB(0x647B5400), SCL_TAB(0x64CBAE80), SCL_TAB(0x651C1900), SCL_TAB(0x656C9400), SCL_TAB(0x65BD1E80), + SCL_TAB(0x660DB900), SCL_TAB(0x665E6380), SCL_TAB(0x66AF1E00), SCL_TAB(0x66FFE880), SCL_TAB(0x6750C280), SCL_TAB(0x67A1AC80), SCL_TAB(0x67F2A600), SCL_TAB(0x6843B000), + SCL_TAB(0x6894C900), SCL_TAB(0x68E5F200), SCL_TAB(0x69372B00), SCL_TAB(0x69887380), SCL_TAB(0x69D9CB80), SCL_TAB(0x6A2B3300), SCL_TAB(0x6A7CAA80), SCL_TAB(0x6ACE3180), + SCL_TAB(0x6B1FC800), SCL_TAB(0x6B716E00), SCL_TAB(0x6BC32400), SCL_TAB(0x6C14E900), SCL_TAB(0x6C66BD80), SCL_TAB(0x6CB8A180), SCL_TAB(0x6D0A9500), SCL_TAB(0x6D5C9800), + SCL_TAB(0x6DAEAA00), SCL_TAB(0x6E00CB80), SCL_TAB(0x6E52FC80), SCL_TAB(0x6EA53D00), SCL_TAB(0x6EF78C80), SCL_TAB(0x6F49EB80), SCL_TAB(0x6F9C5980), SCL_TAB(0x6FEED700), + SCL_TAB(0x70416380), SCL_TAB(0x7093FF00), SCL_TAB(0x70E6AA00), SCL_TAB(0x71396400), SCL_TAB(0x718C2D00), SCL_TAB(0x71DF0580), SCL_TAB(0x7231ED00), SCL_TAB(0x7284E300), + SCL_TAB(0x72D7E880), SCL_TAB(0x732AFD00), SCL_TAB(0x737E2080), SCL_TAB(0x73D15300), SCL_TAB(0x74249480), SCL_TAB(0x7477E480), SCL_TAB(0x74CB4400), SCL_TAB(0x751EB200), + SCL_TAB(0x75722F00), SCL_TAB(0x75C5BB00), SCL_TAB(0x76195580), SCL_TAB(0x766CFF00), SCL_TAB(0x76C0B700), SCL_TAB(0x77147E00), SCL_TAB(0x77685400), SCL_TAB(0x77BC3880), + SCL_TAB(0x78102B80), SCL_TAB(0x78642D80), SCL_TAB(0x78B83E00), SCL_TAB(0x790C5D00), SCL_TAB(0x79608B00), SCL_TAB(0x79B4C780), SCL_TAB(0x7A091280), SCL_TAB(0x7A5D6C00), + SCL_TAB(0x7AB1D400), SCL_TAB(0x7B064A80), SCL_TAB(0x7B5ACF80), SCL_TAB(0x7BAF6380), SCL_TAB(0x7C040580), SCL_TAB(0x7C58B600), SCL_TAB(0x7CAD7500), SCL_TAB(0x7D024200), + SCL_TAB(0x7D571E00), SCL_TAB(0x7DAC0800), SCL_TAB(0x7E010080), SCL_TAB(0x7E560780), SCL_TAB(0x7EAB1C80), SCL_TAB(0x7F004000), SCL_TAB(0x7F557200), SCL_TAB(0x7FAAB200), + SCL_TAB(0x7FFFFFFF) +} ; + +/** + * \brief Table representing scale factor gains. Given a scale factor sf, and a value pSpec[i] the + * gain is given by: MantissaTable[sf % 4][msb] = 2^(sf % 4) / (1<> 2)) + * The corresponding exponents for the values in this tables are stored in ExponentTable[sf % 4][msb] below. + */ +const FIXP_DBL MantissaTable [4][14] = +{ + { + 0x40000000, 0x50A28C00, 0x6597FA80, 0x40000000, 0x50A28C00, 0x6597FA80, 0x40000000, 0x50A28C00, + 0x6597FA80, 0x40000000, 0x50A28C00, 0x6597FA80, 0x40000000, 0x50A28C00 + }, + { + 0x4C1BF800, 0x5FE44380, 0x78D0DF80, 0x4C1BF800, 0x5FE44380, 0x78D0DF80, 0x4C1BF800, 0x5FE44380, + 0x78D0DF80, 0x4C1BF800, 0x5FE44380, 0x78D0DF80, 0x4C1BF800, 0x5FE44380 + }, + { + 0x5A827980, 0x7208F800, 0x47D66B00, 0x5A827980, 0x7208F800, 0x47D66B00, 0x5A827980, 0x7208F800, + 0x47D66B00, 0x5A827980, 0x7208F800, 0x47D66B00, 0x5A827980, 0x7208F800 + }, + { + 0x6BA27E80, 0x43CE3E80, 0x556E0400, 0x6BA27E80, 0x43CE3E80, 0x556E0400, 0x6BA27E80, 0x43CE3E80, + 0x556E0400, 0x6BA27E80, 0x43CE3E80, 0x556E0400, 0x6BA27E80, 0x43CE3E80 + } +} ; + +const SCHAR ExponentTable [4][14] = +{ + { 1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17, 18 }, + { 1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17, 18 }, + { 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 16, 17, 18 }, + { 1, 3, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 17, 19 } +} ; + + + +/* 49 scfbands */ +static const SHORT sfb_48_1024[50] = { + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48, 56, 64, + 72, 80, 88, 96, 108, 120, 132, 144, 160, 176, 196, 216, 240, 264, + 292, 320, 352, 384, 416, 448, 480, 512, 544, 576, 608, 640, 672, 704, + 736, 768, 800, 832, 864, 896, 928, 1024 +}; +/* 14 scfbands */ +static const SHORT sfb_48_128[15] = +{ + 0, 4, 8, 12, 16, 20, 28, 36, 44, 56, 68, 80, 96, 112, + 128 +}; + +/* 51 scfbands */ +static const SHORT sfb_32_1024[52] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48, 56, 64, + 72, 80, 88, 96, 108, 120, 132, 144, 160, 176, 196, 216, 240, 264, + 292, 320, 352, 384, 416, 448, 480, 512, 544, 576, 608, 640, 672, 704, + 736, 768, 800, 832, 864, 896, 928, 960, 992,1024 +}; + +/* 47 scfbands */ +static const SHORT sfb_24_1024[48] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 52, 60, + 68, 76, 84, 92, 100, 108, 116, 124, 136, 148, 160, 172, 188, 204, + 220, 240, 260, 284, 308, 336, 364, 396, 432, 468, 508, 552, 600, 652, + 704, 768, 832, 896, 960,1024 +}; + +/* 15 scfbands */ +static const SHORT sfb_24_128[16] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 64, 76, 92, + 108, 128 +}; + +/* 43 scfbands */ +static const SHORT sfb_16_1024[44] = +{ + 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 100, 112, + 124, 136, 148, 160, 172, 184, 196, 212, 228, 244, 260, 280, 300, 320, + 344, 368, 396, 424, 456, 492, 532, 572, 616, 664, 716, 772, 832, 896, + 960,1024 +}; + +/* 15 scfbands */ +static const SHORT sfb_16_128[16] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 60, 72, 88, + 108, 128 +}; + +/* 40 scfbands */ +static const SHORT sfb_8_1024[41] = +{ + 0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120, 132, 144, 156, + 172, 188, 204, 220, 236, 252, 268, 288, 308, 328, 348, 372, 396, 420, + 448, 476, 508, 544, 580, 620, 664, 712, 764, 820, 880, 944,1024 +}; + +/* 15 scfbands */ +static const SHORT sfb_8_128[16] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 60, 72, 88, + 108, 128 +}; + + + +static const SHORT sfb_48_960[50] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, + 40, 48, 56, 64, 72, 80, 88, 96, 108, 120, + 132, 144, 160, 176, 196, 216, 240, 264, 292, 320, + 352, 384, 416, 448, 480, 512, 544, 576, 608, 640, + 672, 704, 736, 768, 800, 832, 864, 896, 928, 960 +}; /* 49 scfbands */ +static const SHORT sfb_48_120[15] = +{ + 0, 4, 8, 12, 16, 20, 28, 36, 44, 56, + 68, 80, 96, 112, 120 +}; /* 14 scfbands */ + +static const SHORT sfb_32_960[50] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, + 40, 48, 56, 64, 72, 80, 88, 96, 108, 120, + 132, 144, 160, 176, 196, 216, 240, 264, 292, 320, + 352, 384, 416, 448, 480, 512, 544, 576, 608, 640, + 672, 704, 736, 768, 800, 832, 864, 896, 928, 960 +}; /* 49 scfbands */ + +static const SHORT sfb_24_960[47] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, + 40, 44, 52, 60, 68, 76, 84, 92, 100, 108, + 116, 124, 136, 148, 160, 172, 188, 204, 220, 240, + 260, 284, 308, 336, 364, 396, 432, 468, 508, 552, + 600, 652, 704, 768, 832, 896, 960 +}; /* 46 scfbands */ + +static const SHORT sfb_24_120[16] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 36, 44, + 52, 64, 76, 92, 108, 120 +}; /* 15 scfbands */ + +static const SHORT sfb_16_960[43] = +{ + 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, + 80, 88, 100, 112, 124, 136, 148, 160, 172, 184, + 196, 212, 228, 244, 260, 280, 300, 320, 344, 368, + 396, 424, 456, 492, 532, 572, 616, 664, 716, 772, + 832, 896, 960 +}; /* 42 scfbands */ + +static const SHORT sfb_16_120[16] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 40, + 48, 60, 72, 88, 108, 120 +}; /* 15 scfbands */ + +static const SHORT sfb_8_960[41] = +{ + 0, 12, 24, 36, 48, 60, 72, 84, 96, 108, + 120, 132, 144, 156, 172, 188, 204, 220, 236, 252, + 268, 288, 308, 328, 348, 372, 396, 420, 448, 476, + 508, 544, 580, 620, 664, 712, 764, 820, 880, 944, + 960 +}; /* 40 scfbands */ + +static const SHORT sfb_8_120[16] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 36, 44, + 52, 60, 72, 88, 108, 120 +}; /* 15 scfbands */ + + + + +static const SHORT sfb_48_512[37] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, + 40, 44, 48, 52, 56, 60, 68, 76, 84, 92, + 100, 112, 124, 136, 148, 164, 184, 208, 236, 268, + 300, 332, 364, 396, 428, 460, 512 +}; /* 36 scfbands */ +static const SHORT sfb_32_512[38] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, + 40, 44, 48, 52, 56, 64, 72, 80, 88, 96, + 108, 120, 132, 144, 160, 176, 192, 212, 236, 260, + 288, 320, 352, 384, 416, 448, 480, 512 +}; /* 37 scfbands */ +static const SHORT sfb_24_512[32] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, + 40, 44, 52, 60, 68, 80, 92, 104, 120, 140, + 164, 192, 224, 256, 288, 320, 352, 384, 416, 448, + 480, 512 +}; /* 31 scfbands */ + +static const SHORT sfb_48_480[36] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, + 40, 44, 48, 52, 56, 64, 72, 80, 88, 96, + 108, 120, 132, 144, 156, 172, 188, 212, 240, 272, + 304, 336, 368, 400, 432, 480 +}; /* 35 scfbands */ +static const SHORT sfb_32_480[38] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, + 40, 44, 48, 52, 56, 60, 64, 72, 80, 88, + 96, 104, 112, 124, 136, 148, 164, 180, 200, 224, + 256, 288, 320, 352, 384, 416, 448, 480 +}; /* 37 scfbands */ +static const SHORT sfb_24_480[31] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, + 40, 44, 52, 60, 68, 80, 92, 104, 120, 140, + 164, 192, 224, 256, 288, 320, 352, 384, 416, 448, + 480 +}; /* 30 scfbands */ + +const SFB_INFO sfbOffsetTables[5][16] = +{ + { + { NULL, NULL, 0, 0 }, + { NULL, NULL, 0, 0 }, + { NULL, NULL, 0, 0 }, + { sfb_48_1024, sfb_48_128, 49, 14 }, + { sfb_48_1024, sfb_48_128, 49, 14 }, + { sfb_32_1024, sfb_48_128, 51, 14 }, + { sfb_24_1024, sfb_24_128, 47, 15 }, + { sfb_24_1024, sfb_24_128, 47, 15 }, + { sfb_16_1024, sfb_16_128, 43, 15 }, + { sfb_16_1024, sfb_16_128, 43, 15 }, + { sfb_16_1024, sfb_16_128, 43, 15 }, + { sfb_8_1024, sfb_8_128, 40, 15 }, + { sfb_8_1024, sfb_8_128, 40, 15 }, + }, { + { NULL, NULL, 0, 0 }, + { NULL, NULL, 0, 0 }, + { NULL, NULL, 0, 0 }, + { sfb_48_960, sfb_48_120, 49, 14 }, + { sfb_48_960, sfb_48_120, 49, 14 }, + { sfb_32_960, sfb_48_120, 49, 14 }, + { sfb_24_960, sfb_24_120, 46, 15 }, + { sfb_24_960, sfb_24_120, 46, 15 }, + { sfb_16_960, sfb_16_120, 42, 15 }, + { sfb_16_960, sfb_16_120, 42, 15 }, + { sfb_16_960, sfb_16_120, 42, 15 }, + { sfb_8_960, sfb_8_120, 40, 15 }, + { sfb_8_960, sfb_8_120, 40, 15 }, + }, { + { NULL, NULL, 0, 0 }, + }, { + { NULL, NULL, 0, 0 }, + { NULL, NULL, 0, 0 }, + { NULL, NULL, 0, 0 }, + { sfb_48_512, NULL, 36, 0 }, + { sfb_48_512, NULL, 36, 0}, + { sfb_32_512, NULL, 37, 0 }, + { sfb_24_512, NULL, 31, 0 }, + { sfb_24_512, NULL, 31, 0 }, + { sfb_24_512, NULL, 31, 0 }, + { sfb_24_512, NULL, 31, 0 }, + { sfb_24_512, NULL, 31, 0 }, + { sfb_24_512, NULL, 31, 0 }, + { sfb_24_512, NULL, 31, 0 }, + }, { + { NULL, NULL, 0, 0 }, + { NULL, NULL, 0, 0 }, + { NULL, NULL, 0, 0 }, + { sfb_48_480, NULL, 35, 0 }, + { sfb_48_480, NULL, 35, 0 }, + { sfb_32_480, NULL, 37, 0 }, + { sfb_24_480, NULL, 30, 0 }, + { sfb_24_480, NULL, 30, 0 }, + { sfb_24_480, NULL, 30, 0 }, + { sfb_24_480, NULL, 30, 0 }, + { sfb_24_480, NULL, 30, 0 }, + { sfb_24_480, NULL, 30, 0 }, + { sfb_24_480, NULL, 30, 0 }, + } +}; + + +/*# don't use 1 bit hufman tables */ +/* + MPEG-2 AAC 2 BITS parallel Hufman Tables + + Bit 0: = 1=ENDNODE, 0=INDEX + Bit 1: = CODEWORD LEN MOD 2 + Bit 2..9: = VALUE/REF Tables 1..10,SCL + Bit 2..11: = VALUE/REF Table 11 +*/ + const USHORT HuffmanCodeBook_1[51][4] = +{ + {0x0157,0x0157,0x0004,0x0018}, {0x0008,0x000c,0x0010,0x0014}, {0x015b,0x015b,0x0153,0x0153}, {0x0057,0x0057,0x0167,0x0167}, + {0x0257,0x0257,0x0117,0x0117}, {0x0197,0x0197,0x0147,0x0147}, {0x001c,0x0030,0x0044,0x0058}, {0x0020,0x0024,0x0028,0x002c}, + {0x014b,0x014b,0x0163,0x0163}, {0x0217,0x0217,0x0127,0x0127}, {0x0187,0x0187,0x0097,0x0097}, {0x016b,0x016b,0x0017,0x0017}, + {0x0034,0x0038,0x003c,0x0040}, {0x0143,0x0143,0x0107,0x0107}, {0x011b,0x011b,0x0067,0x0067}, {0x0193,0x0193,0x0297,0x0297}, + {0x019b,0x019b,0x0247,0x0247}, {0x0048,0x004c,0x0050,0x0054}, {0x01a7,0x01a7,0x0267,0x0267}, {0x0113,0x0113,0x025b,0x025b}, + {0x0053,0x0053,0x005b,0x005b}, {0x0253,0x0253,0x0047,0x0047}, {0x005c,0x0070,0x0084,0x0098}, {0x0060,0x0064,0x0068,0x006c}, + {0x012b,0x012b,0x0123,0x0123}, {0x018b,0x018b,0x00a7,0x00a7}, {0x0227,0x0227,0x0287,0x0287}, {0x0087,0x0087,0x010b,0x010b}, + {0x0074,0x0078,0x007c,0x0080}, {0x021b,0x021b,0x0027,0x0027}, {0x01a3,0x01a3,0x0093,0x0093}, {0x0183,0x0183,0x0207,0x0207}, + {0x024b,0x024b,0x004b,0x004b}, {0x0088,0x008c,0x0090,0x0094}, {0x0063,0x0063,0x0103,0x0103}, {0x0007,0x0007,0x02a7,0x02a7}, + {0x009b,0x009b,0x026b,0x026b}, {0x0263,0x0263,0x01ab,0x01ab}, {0x009c,0x00a0,0x00a4,0x00b8}, {0x0241,0x0011,0x0069,0x0019}, + {0x0211,0x0041,0x0291,0x0299}, {0x00a8,0x00ac,0x00b0,0x00b4}, {0x008b,0x008b,0x0223,0x0223}, {0x00a3,0x00a3,0x020b,0x020b}, + {0x02ab,0x02ab,0x0283,0x0283}, {0x002b,0x002b,0x0083,0x0083}, {0x00bc,0x00c0,0x00c4,0x00c8}, {0x0003,0x0003,0x022b,0x022b}, + {0x028b,0x028b,0x02a3,0x02a3}, {0x0023,0x0023,0x0203,0x0203}, {0x000b,0x000b,0x00ab,0x00ab} +}; + +const USHORT HuffmanCodeBook_2[39][4] = +{ + {0x0004,0x000c,0x0020,0x0034}, {0x0157,0x0157,0x0159,0x0008}, {0x0153,0x0153,0x0257,0x0257}, {0x0010,0x0014,0x0018,0x001c}, + {0x0117,0x0117,0x0057,0x0057}, {0x0147,0x0147,0x0197,0x0197}, {0x0167,0x0167,0x0185,0x0161}, {0x0125,0x0095,0x0065,0x0215}, + {0x0024,0x0028,0x002c,0x0030}, {0x0051,0x0149,0x0119,0x0141}, {0x0015,0x0199,0x0259,0x0245}, {0x0191,0x0265,0x0105,0x0251}, + {0x0045,0x0111,0x0169,0x01a5}, {0x0038,0x0044,0x0058,0x006c}, {0x0295,0x0059,0x003c,0x0040}, {0x0227,0x0227,0x021b,0x021b}, + {0x0123,0x0123,0x0087,0x0087}, {0x0048,0x004c,0x0050,0x0054}, {0x018b,0x018b,0x006b,0x006b}, {0x029b,0x029b,0x01a3,0x01a3}, + {0x0207,0x0207,0x01ab,0x01ab}, {0x0093,0x0093,0x0103,0x0103}, {0x005c,0x0060,0x0064,0x0068}, {0x0213,0x0213,0x010b,0x010b}, + {0x012b,0x012b,0x0249,0x0061}, {0x0181,0x0291,0x0241,0x0041}, {0x0005,0x0099,0x0019,0x0025}, {0x0070,0x0074,0x0078,0x0088}, + {0x02a5,0x0261,0x0011,0x00a5}, {0x0049,0x0285,0x0269,0x0089}, {0x0221,0x007c,0x0080,0x0084}, {0x020b,0x020b,0x0003,0x0003}, + {0x00a3,0x00a3,0x02a3,0x02a3}, {0x02ab,0x02ab,0x0083,0x0083}, {0x008c,0x0090,0x0094,0x0098}, {0x028b,0x028b,0x0023,0x0023}, + {0x0283,0x0283,0x002b,0x002b}, {0x000b,0x000b,0x0203,0x0203}, {0x022b,0x022b,0x00ab,0x00ab} +}; + +const USHORT HuffmanCodeBook_3[39][4] = +{ + {0x0003,0x0003,0x0004,0x0008}, {0x0005,0x0101,0x0011,0x0041}, {0x000c,0x0010,0x0014,0x0020}, {0x0017,0x0017,0x0143,0x0143}, + {0x0051,0x0111,0x0045,0x0151}, {0x0105,0x0055,0x0018,0x001c}, {0x0157,0x0157,0x0147,0x0147}, {0x0117,0x0117,0x0009,0x0201}, + {0x0024,0x002c,0x0040,0x0054}, {0x0241,0x0019,0x0065,0x0028}, {0x0183,0x0183,0x0193,0x0193}, {0x0030,0x0034,0x0038,0x003c}, + {0x0027,0x0027,0x0253,0x0253}, {0x005b,0x005b,0x0083,0x0083}, {0x0063,0x0063,0x0093,0x0093}, {0x0023,0x0023,0x0213,0x0213}, + {0x0044,0x0048,0x004c,0x0050}, {0x004b,0x004b,0x0167,0x0167}, {0x0163,0x0163,0x0097,0x0097}, {0x0197,0x0197,0x0125,0x0085}, + {0x0185,0x0121,0x0159,0x0255}, {0x0058,0x005c,0x0060,0x0070}, {0x0119,0x0245,0x0281,0x0291}, {0x0069,0x00a5,0x0205,0x0109}, + {0x01a1,0x0064,0x0068,0x006c}, {0x002b,0x002b,0x01a7,0x01a7}, {0x0217,0x0217,0x014b,0x014b}, {0x0297,0x0297,0x016b,0x016b}, + {0x0074,0x0078,0x007c,0x0080}, {0x00a3,0x00a3,0x0263,0x0263}, {0x0285,0x0129,0x0099,0x00a9}, {0x02a1,0x01a9,0x0199,0x0265}, + {0x02a5,0x0084,0x0088,0x008c}, {0x0223,0x0223,0x008b,0x008b}, {0x0227,0x0227,0x0189,0x0259}, {0x0219,0x0090,0x0094,0x0098}, + {0x02ab,0x02ab,0x026b,0x026b}, {0x029b,0x029b,0x024b,0x024b}, {0x020b,0x020b,0x0229,0x0289} +}; + +const USHORT HuffmanCodeBook_4[38][4] = +{ + {0x0004,0x0008,0x000c,0x0018}, {0x0155,0x0151,0x0115,0x0055}, {0x0145,0x0005,0x0015,0x0001}, {0x0141,0x0045,0x0010,0x0014}, + {0x0107,0x0107,0x0053,0x0053}, {0x0103,0x0103,0x0113,0x0113}, {0x001c,0x0020,0x0034,0x0048}, {0x0043,0x0043,0x0013,0x0013}, + {0x0024,0x0028,0x002c,0x0030}, {0x015b,0x015b,0x0197,0x0197}, {0x0167,0x0167,0x0257,0x0257}, {0x005b,0x005b,0x011b,0x011b}, + {0x0067,0x0067,0x014b,0x014b}, {0x0038,0x003c,0x0040,0x0044}, {0x0193,0x0193,0x0251,0x0095}, {0x0161,0x0245,0x0125,0x0215}, + {0x0185,0x0019,0x0049,0x0025}, {0x0109,0x0211,0x0061,0x0241}, {0x004c,0x0050,0x0058,0x006c}, {0x0091,0x0121,0x0205,0x0181}, + {0x0085,0x0009,0x0201,0x0054}, {0x0023,0x0023,0x0083,0x0083}, {0x005c,0x0060,0x0064,0x0068}, {0x01a7,0x01a7,0x016b,0x016b}, + {0x019b,0x019b,0x0297,0x0297}, {0x0267,0x0267,0x025b,0x025b}, {0x00a5,0x0069,0x0099,0x01a1}, {0x0070,0x0074,0x0078,0x0084}, + {0x0291,0x0129,0x0261,0x0189}, {0x0285,0x01a9,0x0225,0x0249}, {0x0219,0x02a5,0x007c,0x0080}, {0x029b,0x029b,0x026b,0x026b}, + {0x00a3,0x00a3,0x002b,0x002b}, {0x0088,0x008c,0x0090,0x0094}, {0x0283,0x0283,0x008b,0x008b}, {0x0223,0x0223,0x020b,0x020b}, + {0x02ab,0x02ab,0x02a3,0x02a3}, {0x00ab,0x00ab,0x0229,0x0289} +}; + +const USHORT HuffmanCodeBook_5[41][4] = +{ + {0x0113,0x0113,0x0004,0x0008}, {0x010d,0x0115,0x0151,0x00d1}, {0x000c,0x0010,0x0014,0x0028}, {0x00d7,0x00d7,0x014f,0x014f}, + {0x00cf,0x00cf,0x0157,0x0157}, {0x0018,0x001c,0x0020,0x0024}, {0x010b,0x010b,0x0193,0x0193}, {0x011b,0x011b,0x0093,0x0093}, + {0x00c9,0x0159,0x008d,0x0195}, {0x0149,0x00d9,0x018d,0x0095}, {0x002c,0x0030,0x0044,0x0058}, {0x0105,0x011d,0x0051,0x01d1}, + {0x0034,0x0038,0x003c,0x0040}, {0x00c7,0x00c7,0x01d7,0x01d7}, {0x015f,0x015f,0x004f,0x004f}, {0x0147,0x0147,0x00df,0x00df}, + {0x0057,0x0057,0x01cf,0x01cf}, {0x0048,0x004c,0x0050,0x0054}, {0x018b,0x018b,0x019b,0x019b}, {0x008b,0x008b,0x009b,0x009b}, + {0x0085,0x009d,0x01c9,0x0059}, {0x019d,0x01d9,0x0185,0x0049}, {0x005c,0x0060,0x0074,0x0088}, {0x0011,0x0101,0x0161,0x0121}, + {0x0064,0x0068,0x006c,0x0070}, {0x00c3,0x00c3,0x0213,0x0213}, {0x00e3,0x00e3,0x000f,0x000f}, {0x0217,0x0217,0x020f,0x020f}, + {0x0143,0x0143,0x0017,0x0017}, {0x0078,0x007c,0x0080,0x0084}, {0x005f,0x005f,0x0047,0x0047}, {0x01c7,0x01c7,0x020b,0x020b}, + {0x0083,0x0083,0x01a3,0x01a3}, {0x001b,0x001b,0x021b,0x021b}, {0x008c,0x0090,0x0094,0x0098}, {0x01df,0x01df,0x0183,0x0183}, + {0x0009,0x00a1,0x001d,0x0041}, {0x01c1,0x021d,0x0205,0x01e1}, {0x0061,0x0005,0x009c,0x00a0}, {0x0023,0x0023,0x0203,0x0203}, + {0x0223,0x0223,0x0003,0x0003} +}; + +const USHORT HuffmanCodeBook_6[40][4] = +{ + {0x0004,0x0008,0x000c,0x001c}, {0x0111,0x0115,0x00d1,0x0151}, {0x010d,0x0155,0x014d,0x00d5}, {0x00cd,0x0010,0x0014,0x0018}, + {0x00d9,0x0159,0x0149,0x00c9}, {0x0109,0x018d,0x0119,0x0095}, {0x0195,0x0091,0x008d,0x0191}, {0x0020,0x0024,0x0038,0x004c}, + {0x0099,0x0189,0x0089,0x0199}, {0x0028,0x002c,0x0030,0x0034}, {0x0147,0x0147,0x015f,0x015f}, {0x00df,0x00df,0x01cf,0x01cf}, + {0x00c7,0x00c7,0x01d7,0x01d7}, {0x0057,0x0057,0x004f,0x004f}, {0x003c,0x0040,0x0044,0x0048}, {0x011f,0x011f,0x0107,0x0107}, + {0x0053,0x0053,0x01d3,0x01d3}, {0x019f,0x019f,0x0085,0x01c9}, {0x01d9,0x009d,0x0059,0x0049}, {0x0050,0x005c,0x0070,0x0084}, + {0x0185,0x01dd,0x0054,0x0058}, {0x005f,0x005f,0x0047,0x0047}, {0x01c7,0x01c7,0x0017,0x0017}, {0x0060,0x0064,0x0068,0x006c}, + {0x000f,0x000f,0x0163,0x0163}, {0x0143,0x0143,0x00c3,0x00c3}, {0x0217,0x0217,0x00e3,0x00e3}, {0x020f,0x020f,0x0013,0x0013}, + {0x0074,0x0078,0x007c,0x0080}, {0x0183,0x0183,0x0083,0x0083}, {0x021b,0x021b,0x000b,0x000b}, {0x0103,0x0103,0x01a3,0x01a3}, + {0x00a3,0x00a3,0x020b,0x020b}, {0x0088,0x008c,0x0090,0x0094}, {0x0123,0x0123,0x001b,0x001b}, {0x0213,0x0213,0x0005,0x0205}, + {0x001d,0x0061,0x021d,0x01e1}, {0x01c1,0x0041,0x0098,0x009c}, {0x0223,0x0223,0x0203,0x0203}, {0x0003,0x0003,0x0023,0x0023} +}; + +const USHORT HuffmanCodeBook_7[31][4] = +{ + {0x0003,0x0003,0x0004,0x0008}, {0x0007,0x0007,0x0043,0x0043}, {0x0045,0x000c,0x0010,0x0024}, {0x0049,0x0085,0x0009,0x0081}, + {0x0014,0x0018,0x001c,0x0020}, {0x004f,0x004f,0x00c7,0x00c7}, {0x008b,0x008b,0x000f,0x000f}, {0x00c3,0x00c3,0x00c9,0x008d}, + {0x0105,0x0051,0x0145,0x0055}, {0x0028,0x002c,0x0040,0x0054}, {0x00cd,0x0109,0x0101,0x0011}, {0x0030,0x0034,0x0038,0x003c}, + {0x0093,0x0093,0x014b,0x014b}, {0x0097,0x0097,0x0143,0x0143}, {0x005b,0x005b,0x0017,0x0017}, {0x0187,0x0187,0x00d3,0x00d3}, + {0x0044,0x0048,0x004c,0x0050}, {0x014f,0x014f,0x010f,0x010f}, {0x00d7,0x00d7,0x018b,0x018b}, {0x009b,0x009b,0x01c7,0x01c7}, + {0x018d,0x0181,0x0019,0x0111}, {0x0058,0x005c,0x0060,0x0068}, {0x005d,0x0151,0x009d,0x0115}, {0x00d9,0x01c9,0x00dd,0x0119}, + {0x0155,0x0191,0x01cd,0x0064}, {0x001f,0x001f,0x01c3,0x01c3}, {0x006c,0x0070,0x0074,0x0078}, {0x015b,0x015b,0x0197,0x0197}, + {0x011f,0x011f,0x01d3,0x01d3}, {0x01d7,0x01d7,0x015f,0x015f}, {0x019d,0x0199,0x01d9,0x01dd} +}; + +const USHORT HuffmanCodeBook_8[31][4] = +{ + {0x0004,0x0008,0x0010,0x0024}, {0x0047,0x0047,0x0049,0x0005}, {0x0085,0x0041,0x0089,0x000c}, {0x0003,0x0003,0x000b,0x000b}, + {0x0014,0x0018,0x001c,0x0020}, {0x0083,0x0083,0x004f,0x004f}, {0x00c7,0x00c7,0x008f,0x008f}, {0x00cb,0x00cb,0x00cd,0x0051}, + {0x0105,0x0091,0x0109,0x000d}, {0x0028,0x002c,0x0040,0x0054}, {0x00c1,0x00d1,0x010d,0x0095}, {0x0030,0x0034,0x0038,0x003c}, + {0x0057,0x0057,0x014b,0x014b}, {0x0147,0x0147,0x00d7,0x00d7}, {0x014f,0x014f,0x0113,0x0113}, {0x0117,0x0117,0x0103,0x0103}, + {0x0044,0x0048,0x004c,0x0050}, {0x0153,0x0153,0x0013,0x0013}, {0x018b,0x018b,0x009b,0x009b}, {0x005b,0x005b,0x0187,0x0187}, + {0x018d,0x00d9,0x0155,0x0015}, {0x0058,0x005c,0x0060,0x0068}, {0x0119,0x0141,0x0191,0x005d}, {0x009d,0x01c9,0x0159,0x00dd}, + {0x01c5,0x0195,0x01cd,0x0064}, {0x019b,0x019b,0x011f,0x011f}, {0x006c,0x0070,0x0074,0x0078}, {0x001b,0x001b,0x01d3,0x01d3}, + {0x0183,0x0183,0x015f,0x015f}, {0x019f,0x019f,0x01db,0x01db}, {0x01d5,0x001d,0x01c1,0x01dd} +}; + +const USHORT HuffmanCodeBook_9[84][4] = +{ + {0x0003,0x0003,0x0004,0x0008}, {0x0007,0x0007,0x0043,0x0043}, {0x0045,0x000c,0x0010,0x002c}, {0x0049,0x0085,0x0009,0x0081}, + {0x0014,0x0018,0x001c,0x0020}, {0x004f,0x004f,0x008b,0x008b}, {0x00c7,0x00c7,0x000d,0x00c1}, {0x00c9,0x008d,0x0105,0x0051}, + {0x0109,0x0145,0x0024,0x0028}, {0x0093,0x0093,0x00cf,0x00cf}, {0x0103,0x0103,0x0013,0x0013}, {0x0030,0x0044,0x0058,0x00a4}, + {0x0034,0x0038,0x003c,0x0040}, {0x0057,0x0057,0x014b,0x014b}, {0x0187,0x0187,0x010f,0x010f}, {0x0097,0x0097,0x005b,0x005b}, + {0x00d3,0x00d3,0x0141,0x0189}, {0x0048,0x004c,0x0050,0x0054}, {0x0015,0x01c5,0x014d,0x0205}, {0x0061,0x0111,0x00d5,0x0099}, + {0x005d,0x0181,0x00a1,0x0209}, {0x018d,0x01c9,0x0151,0x0065}, {0x005c,0x0068,0x007c,0x0090}, {0x0245,0x009d,0x0060,0x0064}, + {0x001b,0x001b,0x0117,0x0117}, {0x00db,0x00db,0x00e3,0x00e3}, {0x006c,0x0070,0x0074,0x0078}, {0x01c3,0x01c3,0x00a7,0x00a7}, + {0x020f,0x020f,0x0193,0x0193}, {0x01cf,0x01cf,0x0203,0x0203}, {0x006b,0x006b,0x011b,0x011b}, {0x0080,0x0084,0x0088,0x008c}, + {0x024b,0x024b,0x0157,0x0157}, {0x0023,0x0023,0x001f,0x001f}, {0x00df,0x00df,0x00ab,0x00ab}, {0x00e7,0x00e7,0x0123,0x0123}, + {0x0094,0x0098,0x009c,0x00a0}, {0x0287,0x0287,0x011f,0x011f}, {0x015b,0x015b,0x0197,0x0197}, {0x0213,0x0213,0x01d3,0x01d3}, + {0x024f,0x024f,0x006f,0x006f}, {0x00a8,0x00bc,0x00d0,0x00f4}, {0x00ac,0x00b0,0x00b4,0x00b8}, {0x0217,0x0217,0x0027,0x0027}, + {0x0163,0x0163,0x00e9,0x0289}, {0x0241,0x00ad,0x0125,0x0199}, {0x0071,0x0251,0x01a1,0x02c5}, {0x00c0,0x00c4,0x00c8,0x00cc}, + {0x0165,0x0129,0x01d5,0x015d}, {0x02c9,0x0305,0x00b1,0x00ed}, {0x028d,0x0255,0x01d9,0x01e1}, {0x012d,0x0281,0x019d,0x00f1}, + {0x00d4,0x00d8,0x00dc,0x00e0}, {0x0029,0x0169,0x0291,0x0219}, {0x0309,0x01a5,0x01e5,0x02d1}, {0x002d,0x0259,0x02cd,0x0295}, + {0x00e4,0x00e8,0x00ec,0x00f0}, {0x0223,0x0223,0x021f,0x021f}, {0x0173,0x0173,0x030f,0x030f}, {0x016f,0x016f,0x01df,0x01df}, + {0x0133,0x0133,0x01af,0x01af}, {0x00f8,0x010c,0x0120,0x0134}, {0x00fc,0x0100,0x0104,0x0108}, {0x01ab,0x01ab,0x0313,0x0313}, + {0x025f,0x025f,0x02d7,0x02d7}, {0x02c3,0x02c3,0x01b3,0x01b3}, {0x029b,0x029b,0x0033,0x0033}, {0x0110,0x0114,0x0118,0x011c}, + {0x01eb,0x01eb,0x0317,0x0317}, {0x029f,0x029f,0x0227,0x0227}, {0x0303,0x0303,0x01ef,0x01ef}, {0x0263,0x0263,0x0267,0x0267}, + {0x0124,0x0128,0x012c,0x0130}, {0x022b,0x022b,0x02df,0x02df}, {0x01f3,0x01f3,0x02db,0x02db}, {0x02e3,0x02e3,0x022f,0x022f}, + {0x031f,0x031f,0x031b,0x031b}, {0x0138,0x013c,0x0140,0x0144}, {0x02a1,0x0269,0x0321,0x02a5}, {0x02e5,0x0325,0x02e9,0x0271}, + {0x02a9,0x026d,0x0231,0x02ad}, {0x02b1,0x02f1,0x0148,0x014c}, {0x032b,0x032b,0x02ef,0x02ef}, {0x032f,0x032f,0x0333,0x0333} +}; + +const USHORT HuffmanCodeBook_10[82][4] = +{ + {0x0004,0x000c,0x0020,0x004c}, {0x0045,0x0085,0x0049,0x0008}, {0x008b,0x008b,0x0007,0x0007}, {0x0010,0x0014,0x0018,0x001c}, + {0x0043,0x0043,0x00c7,0x00c7}, {0x008f,0x008f,0x004f,0x004f}, {0x00cb,0x00cb,0x00cf,0x00cf}, {0x0009,0x0081,0x0109,0x0091}, + {0x0024,0x0028,0x002c,0x0038}, {0x0105,0x0051,0x0001,0x00d1}, {0x010d,0x000d,0x00c1,0x0111}, {0x0149,0x0095,0x0030,0x0034}, + {0x0147,0x0147,0x0057,0x0057}, {0x00d7,0x00d7,0x014f,0x014f}, {0x003c,0x0040,0x0044,0x0048}, {0x0117,0x0117,0x0153,0x0153}, + {0x009b,0x009b,0x018b,0x018b}, {0x00db,0x00db,0x0013,0x0013}, {0x005b,0x005b,0x0103,0x0103}, {0x0050,0x0064,0x0078,0x00c0}, + {0x0054,0x0058,0x005c,0x0060}, {0x0187,0x0187,0x018f,0x018f}, {0x0157,0x0157,0x011b,0x011b}, {0x0193,0x0193,0x0159,0x009d}, + {0x01cd,0x01c9,0x0195,0x00a1}, {0x0068,0x006c,0x0070,0x0074}, {0x00dd,0x0015,0x005d,0x0141}, {0x0061,0x01c5,0x00e1,0x011d}, + {0x01d1,0x0209,0x0199,0x015d}, {0x0205,0x020d,0x0121,0x0211}, {0x007c,0x0084,0x0098,0x00ac}, {0x01d5,0x0161,0x0215,0x0080}, + {0x019f,0x019f,0x01db,0x01db}, {0x0088,0x008c,0x0090,0x0094}, {0x00a7,0x00a7,0x001b,0x001b}, {0x021b,0x021b,0x00e7,0x00e7}, + {0x024f,0x024f,0x0067,0x0067}, {0x024b,0x024b,0x0183,0x0183}, {0x009c,0x00a0,0x00a4,0x00a8}, {0x01a3,0x01a3,0x0127,0x0127}, + {0x0253,0x0253,0x00ab,0x00ab}, {0x0247,0x0247,0x01df,0x01df}, {0x01e3,0x01e3,0x0167,0x0167}, {0x00b0,0x00b4,0x00b8,0x00bc}, + {0x021f,0x021f,0x00eb,0x00eb}, {0x0257,0x0257,0x012b,0x012b}, {0x028b,0x028b,0x006b,0x006b}, {0x028f,0x028f,0x01a7,0x01a7}, + {0x00c4,0x00d8,0x00ec,0x0100}, {0x00c8,0x00cc,0x00d0,0x00d4}, {0x025b,0x025b,0x0023,0x0023}, {0x0293,0x0293,0x001f,0x001f}, + {0x00af,0x00af,0x025d,0x00ed}, {0x01a9,0x0285,0x006d,0x01e5}, {0x00dc,0x00e0,0x00e4,0x00e8}, {0x01c1,0x0221,0x0169,0x02cd}, + {0x0295,0x0261,0x016d,0x0201}, {0x012d,0x02c9,0x029d,0x0299}, {0x01e9,0x02d1,0x02c5,0x00b1}, {0x00f0,0x00f4,0x00f8,0x00fc}, + {0x0225,0x00f1,0x01ad,0x02d5}, {0x0131,0x01ed,0x0171,0x030d}, {0x02d9,0x0025,0x0229,0x0029}, {0x0071,0x0241,0x0311,0x0265}, + {0x0104,0x010c,0x0120,0x0134}, {0x01b1,0x0309,0x02a1,0x0108}, {0x02a7,0x02a7,0x0307,0x0307}, {0x0110,0x0114,0x0118,0x011c}, + {0x022f,0x022f,0x01f3,0x01f3}, {0x02df,0x02df,0x0317,0x0317}, {0x031b,0x031b,0x026b,0x026b}, {0x02e3,0x02e3,0x0233,0x0233}, + {0x0124,0x0128,0x012c,0x0130}, {0x0283,0x0283,0x031f,0x031f}, {0x002f,0x002f,0x02ab,0x02ab}, {0x026f,0x026f,0x02af,0x02af}, + {0x02c3,0x02c3,0x02ef,0x02ef}, {0x0138,0x013c,0x0140,0x0144}, {0x02e7,0x02e7,0x02eb,0x02eb}, {0x0033,0x0033,0x0323,0x0323}, + {0x0271,0x0329,0x0325,0x032d}, {0x02f1,0x0301,0x02b1,0x0331} +}; + +const USHORT HuffmanCodeBook_11[152][4] = +{ + {0x0004,0x0010,0x0038,0x008c}, {0x0001,0x0085,0x0008,0x000c}, {0x0843,0x0843,0x0007,0x0007}, {0x0083,0x0083,0x008b,0x008b}, + {0x0014,0x0018,0x001c,0x0024}, {0x0107,0x0107,0x010b,0x010b}, {0x0185,0x008d,0x010d,0x0009}, {0x0189,0x0101,0x018d,0x0020}, + {0x0093,0x0093,0x0207,0x0207}, {0x0028,0x002c,0x0030,0x0034}, {0x0113,0x0113,0x020b,0x020b}, {0x0193,0x0193,0x020f,0x020f}, + {0x000f,0x000f,0x0183,0x0183}, {0x0097,0x0097,0x0117,0x0117}, {0x003c,0x0050,0x0064,0x0078}, {0x0040,0x0044,0x0048,0x004c}, + {0x028b,0x028b,0x0213,0x0213}, {0x0287,0x0287,0x0197,0x0197}, {0x028f,0x028f,0x0217,0x0217}, {0x0291,0x0119,0x0309,0x0099}, + {0x0054,0x0058,0x005c,0x0060}, {0x0199,0x030d,0x0305,0x0811}, {0x080d,0x02c1,0x01c1,0x0241}, {0x0219,0x0341,0x0011,0x0311}, + {0x0201,0x0809,0x0295,0x0815}, {0x0068,0x006c,0x0070,0x0074}, {0x03c1,0x0141,0x0441,0x0389}, {0x011d,0x038d,0x0299,0x0315}, + {0x0819,0x0541,0x019d,0x009d}, {0x04c1,0x081d,0x0805,0x0385}, {0x007c,0x0080,0x0084,0x0088}, {0x0391,0x05c1,0x021d,0x0641}, + {0x0821,0x00c1,0x0319,0x0825}, {0x0409,0x0395,0x0829,0x06c1}, {0x01a1,0x0121,0x040d,0x0015}, {0x0090,0x00c8,0x011c,0x0170}, + {0x0094,0x0098,0x00a0,0x00b4}, {0x0741,0x082d,0x029d,0x0411}, {0x0399,0x031d,0x0281,0x009c}, {0x0223,0x0223,0x07c3,0x07c3}, + {0x00a4,0x00a8,0x00ac,0x00b0}, {0x0833,0x0833,0x0407,0x0407}, {0x00a3,0x00a3,0x083b,0x083b}, {0x0417,0x0417,0x0837,0x0837}, + {0x048f,0x048f,0x02a3,0x02a3}, {0x00b8,0x00bc,0x00c0,0x00c4}, {0x039f,0x039f,0x048b,0x048b}, {0x0323,0x0323,0x0127,0x0127}, + {0x01a7,0x01a7,0x083f,0x083f}, {0x0493,0x0493,0x041b,0x041b}, {0x00cc,0x00e0,0x00f4,0x0108}, {0x00d0,0x00d4,0x00d8,0x00dc}, + {0x001b,0x001b,0x0227,0x0227}, {0x0497,0x0497,0x03a3,0x03a3}, {0x041f,0x041f,0x0487,0x0487}, {0x01ab,0x01ab,0x0303,0x0303}, + {0x00e4,0x00e8,0x00ec,0x00f0}, {0x012b,0x012b,0x00a7,0x00a7}, {0x02a7,0x02a7,0x0513,0x0513}, {0x050b,0x050b,0x0327,0x0327}, + {0x050f,0x050f,0x049b,0x049b}, {0x00f8,0x00fc,0x0100,0x0104}, {0x022b,0x022b,0x0423,0x0423}, {0x02ab,0x02ab,0x03a7,0x03a7}, + {0x01af,0x01af,0x0507,0x0507}, {0x001f,0x001f,0x032b,0x032b}, {0x010c,0x0110,0x0114,0x0118}, {0x049f,0x049f,0x058f,0x058f}, + {0x0517,0x0517,0x00ab,0x00ab}, {0x0593,0x0593,0x012f,0x012f}, {0x0137,0x0137,0x051b,0x051b}, {0x0120,0x0134,0x0148,0x015c}, + {0x0124,0x0128,0x012c,0x0130}, {0x01b7,0x01b7,0x058b,0x058b}, {0x0043,0x0043,0x0597,0x0597}, {0x02af,0x02af,0x022d,0x0425}, + {0x051d,0x04a1,0x0801,0x0691}, {0x0138,0x013c,0x0140,0x0144}, {0x0381,0x068d,0x032d,0x00b5}, {0x0235,0x01b1,0x0689,0x02b5}, + {0x0521,0x0599,0x0429,0x03a9}, {0x0139,0x0231,0x0585,0x0611}, {0x014c,0x0150,0x0154,0x0158}, {0x00ad,0x060d,0x0685,0x0131}, + {0x059d,0x070d,0x0615,0x0695}, {0x0239,0x0711,0x03ad,0x01b9}, {0x02b1,0x0335,0x0331,0x0021}, {0x0160,0x0164,0x0168,0x016c}, + {0x042d,0x0609,0x04a5,0x02b9}, {0x0699,0x0529,0x013d,0x05a1}, {0x0525,0x0339,0x04a9,0x0715}, {0x04ad,0x00b9,0x0709,0x0619}, + {0x0174,0x0188,0x019c,0x01cc}, {0x0178,0x017c,0x0180,0x0184}, {0x0605,0x0435,0x0401,0x03b5}, {0x061d,0x03b1,0x069d,0x01bd}, + {0x00b1,0x0719,0x0789,0x02bd}, {0x023d,0x0705,0x05a5,0x0791}, {0x018c,0x0190,0x0194,0x0198}, {0x03b9,0x06a1,0x04b5,0x0621}, + {0x0795,0x078d,0x05a9,0x052d}, {0x0431,0x033d,0x03bd,0x0721}, {0x00bd,0x071d,0x0025,0x0481}, {0x01a0,0x01a4,0x01a8,0x01b8}, + {0x06a5,0x0625,0x04b1,0x0439}, {0x06a9,0x04b9,0x0531,0x0799}, {0x079d,0x01ac,0x01b0,0x01b4}, {0x0727,0x0727,0x043f,0x043f}, + {0x05af,0x05af,0x072f,0x072f}, {0x0787,0x0787,0x062b,0x062b}, {0x01bc,0x01c0,0x01c4,0x01c8}, {0x072b,0x072b,0x05b7,0x05b7}, + {0x0537,0x0537,0x06af,0x06af}, {0x062f,0x062f,0x07a3,0x07a3}, {0x05bb,0x05bb,0x0637,0x0637}, {0x01d0,0x01e4,0x01f8,0x020c}, + {0x01d4,0x01d8,0x01dc,0x01e0}, {0x06b3,0x06b3,0x04bf,0x04bf}, {0x053b,0x053b,0x002b,0x002b}, {0x05b3,0x05b3,0x07a7,0x07a7}, + {0x0503,0x0503,0x0633,0x0633}, {0x01e8,0x01ec,0x01f0,0x01f4}, {0x002f,0x002f,0x0733,0x0733}, {0x07ab,0x07ab,0x06b7,0x06b7}, + {0x0683,0x0683,0x063b,0x063b}, {0x053f,0x053f,0x05bf,0x05bf}, {0x01fc,0x0200,0x0204,0x0208}, {0x07af,0x07af,0x06bb,0x06bb}, + {0x0037,0x0037,0x0583,0x0583}, {0x0737,0x0737,0x063f,0x063f}, {0x06bf,0x06bf,0x07b3,0x07b3}, {0x0210,0x0214,0x0218,0x021c}, + {0x003b,0x003b,0x073b,0x073b}, {0x07b7,0x07b7,0x0033,0x0033}, {0x07bb,0x07bb,0x0701,0x0601}, {0x073d,0x003d,0x0781,0x07bd}, + {0x0118,0x0117,0x0100,0x0109}, {0x05a5,0x05a1,0x05b7,0x0513}, {0x08f9,0x08ff,0x0821,0x08ff}, {0x084f,0x08ff,0x08bc,0x08ff}, + {0x0815,0x08ff,0x0837,0x08ff}, {0x080d,0x08ff,0x085f,0x08ff}, {0x084a,0x08ff,0x087d,0x08ff}, {0x08ff,0x08ff,0x08a8,0x08ff}, + {0x0815,0x08ff,0x083f,0x08ff}, {0x0830,0x08ff,0x0894,0x08ff}, {0x08d4,0x08ff,0x0825,0x08ff}, {0x08ef,0x08ff,0x083f,0x08ff}, + {0x0809,0x08ff,0x08fc,0x08ff}, {0x0842,0x08ff,0x08b3,0x08ff}, {0x070d,0x07a9,0x060e,0x06e2}, {0x06c7,0x06d0,0x04b2,0x0407} +}; + + +const USHORT HuffmanCodeBook_SCL[65][4] = +{ + {0x00f3,0x00f3,0x0004,0x0008}, {0x00ef,0x00ef,0x00f5,0x00e9}, {0x00f9,0x000c,0x0010,0x0014}, {0x00e7,0x00e7,0x00ff,0x00ff}, + {0x00e1,0x0101,0x00dd,0x0105}, {0x0018,0x001c,0x0020,0x0028}, {0x010b,0x010b,0x00db,0x00db}, {0x010f,0x010f,0x00d5,0x0111}, + {0x00d1,0x0115,0x00cd,0x0024}, {0x011b,0x011b,0x00cb,0x00cb}, {0x002c,0x0030,0x0034,0x0040}, {0x00c7,0x00c7,0x011f,0x011f}, + {0x0121,0x00c1,0x0125,0x00bd}, {0x0129,0x00b9,0x0038,0x003c}, {0x0133,0x0133,0x012f,0x012f}, {0x0137,0x0137,0x013b,0x013b}, + {0x0044,0x0048,0x004c,0x0058}, {0x00b7,0x00b7,0x00af,0x00af}, {0x00b1,0x013d,0x00a9,0x00a5}, {0x0141,0x00a1,0x0050,0x0054}, + {0x0147,0x0147,0x009f,0x009f}, {0x014b,0x014b,0x009b,0x009b}, {0x005c,0x0060,0x0064,0x0070}, {0x014f,0x014f,0x0095,0x008d}, + {0x0155,0x0085,0x0091,0x0089}, {0x0151,0x0081,0x0068,0x006c}, {0x015f,0x015f,0x0167,0x0167}, {0x007b,0x007b,0x007f,0x007f}, + {0x0074,0x0078,0x0080,0x00b0}, {0x0159,0x0075,0x0069,0x006d}, {0x0071,0x0061,0x0161,0x007c}, {0x0067,0x0067,0x005b,0x005b}, + {0x0084,0x0088,0x008c,0x009c}, {0x005f,0x005f,0x0169,0x0055}, {0x004d,0x000d,0x0005,0x0009}, {0x0001,0x0090,0x0094,0x0098}, + {0x018b,0x018b,0x018f,0x018f}, {0x0193,0x0193,0x0197,0x0197}, {0x019b,0x019b,0x01d7,0x01d7}, {0x00a0,0x00a4,0x00a8,0x00ac}, + {0x0187,0x0187,0x016f,0x016f}, {0x0173,0x0173,0x0177,0x0177}, {0x017b,0x017b,0x017f,0x017f}, {0x0183,0x0183,0x01a3,0x01a3}, + {0x00b4,0x00c8,0x00dc,0x00f0}, {0x00b8,0x00bc,0x00c0,0x00c4}, {0x01bf,0x01bf,0x01c3,0x01c3}, {0x01c7,0x01c7,0x01cb,0x01cb}, + {0x01cf,0x01cf,0x01d3,0x01d3}, {0x01bb,0x01bb,0x01a7,0x01a7}, {0x00cc,0x00d0,0x00d4,0x00d8}, {0x01ab,0x01ab,0x01af,0x01af}, + {0x01b3,0x01b3,0x01b7,0x01b7}, {0x01db,0x01db,0x001b,0x001b}, {0x0023,0x0023,0x0027,0x0027}, {0x00e0,0x00e4,0x00e8,0x00ec}, + {0x002b,0x002b,0x0017,0x0017}, {0x019f,0x019f,0x01e3,0x01e3}, {0x01df,0x01df,0x0013,0x0013}, {0x001f,0x001f,0x003f,0x003f}, + {0x00f4,0x00f8,0x00fc,0x0100}, {0x0043,0x0043,0x004b,0x004b}, {0x0053,0x0053,0x0047,0x0047}, {0x002f,0x002f,0x0033,0x0033}, + {0x003b,0x003b,0x0037,0x0037} +}; + + + +/* .CodeBook = HuffmanCodeBook_x, .Dimension = 4, .numBits = 2, .Offset = 0 */ +const CodeBookDescription AACcodeBookDescriptionTable[13] = { + { NULL, 0, 0, 0 }, + { HuffmanCodeBook_1, 4, 2, 1 }, + { HuffmanCodeBook_2, 4, 2, 1 }, + { HuffmanCodeBook_3, 4, 2, 0 }, + { HuffmanCodeBook_4, 4, 2, 0 }, + { HuffmanCodeBook_5, 2, 4, 4 }, + { HuffmanCodeBook_6, 2, 4, 4 }, + { HuffmanCodeBook_7, 2, 4, 0 }, + { HuffmanCodeBook_8, 2, 4, 0 }, + { HuffmanCodeBook_9, 2, 4, 0 }, + { HuffmanCodeBook_10, 2, 4, 0 }, + { HuffmanCodeBook_11, 2, 5, 0 }, + { HuffmanCodeBook_SCL, 1, 8, 60 } +}; + +const CodeBookDescription AACcodeBookDescriptionSCL = { HuffmanCodeBook_SCL, 1, 8, 60 }; + + + +/* ********************************************************************************************* */ +/* Table: HuffTree41 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the decode tree for spectral data (Codebook 1). */ +/* bit 23 and 11 not used */ +/* bit 22 and 10 determine end value */ +/* bit 21-12 and 9-0 (offset to next node) or (index value * 4) */ +/* --------------------------------------------------------------------------------------------- */ +/* input: codeword */ +/* --------------------------------------------------------------------------------------------- */ +/* output: index * 4 */ +/* --------------------------------------------------------------------------------------------- */ +/* HuffTree */ +const UINT aHuffTree41[80] = {0x4a0001,0x026002,0x013003,0x021004,0x01c005,0x00b006,0x010007,0x019008, + 0x00900e,0x00a03a,0x400528,0x00c037,0x00d03b,0x454404,0x00f04c,0x448408, + 0x017011,0x01202e,0x42c40c,0x034014,0x01502c,0x016049,0x410470,0x01804e, + 0x414424,0x03201a,0x02001b,0x520418,0x02f01d,0x02a01e,0x01f04d,0x41c474, + 0x540420,0x022024,0x04a023,0x428510,0x025029,0x430508,0x02703c,0x028047, + 0x50c434,0x438478,0x04802b,0x46443c,0x02d03e,0x4404b0,0x44451c,0x03003f, + 0x03104b,0x52444c,0x033039,0x4f0450,0x035041,0x036046,0x4e8458,0x04f038, + 0x45c53c,0x4604e0,0x4f8468,0x46c4d4,0x04503d,0x4ac47c,0x518480,0x043040, + 0x4844dc,0x042044,0x4884a8,0x4bc48c,0x530490,0x4a4494,0x4984b8,0x49c4c4, + 0x5044b4,0x5004c0,0x4d04c8,0x4f44cc,0x4d8538,0x4ec4e4,0x52c4fc,0x514534}; + +/* ********************************************************************************************* */ +/* Table: HuffTree42 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the decode tree for spectral data (Codebook 2). */ +/* bit 23 and 11 not used */ +/* bit 22 and 10 determine end value */ +/* bit 21-12 and 9-0 (offset to next node) or (index value * 4) */ +/* --------------------------------------------------------------------------------------------- */ +/* input: codeword */ +/* --------------------------------------------------------------------------------------------- */ +/* output: index * 4 */ +/* --------------------------------------------------------------------------------------------- */ +const UINT aHuffTree42[80] = {0x026001,0x014002,0x009003,0x010004,0x01d005,0x00600d,0x007018,0x450008, + 0x4e0400,0x02e00a,0x03900b,0x03d00c,0x43c404,0x01b00e,0x00f04f,0x4d8408, + 0x023011,0x01203b,0x01a013,0x41440c,0x015020,0x016040,0x025017,0x500410, + 0x038019,0x540418,0x41c444,0x02d01c,0x420520,0x01e042,0x03701f,0x4244cc, + 0x02a021,0x02204c,0x478428,0x024031,0x42c4dc,0x4304e8,0x027033,0x4a0028, + 0x50c029,0x4344a4,0x02c02b,0x470438,0x4404c8,0x4f8448,0x04902f,0x04b030, + 0x44c484,0x524032,0x4ec454,0x03e034,0x035046,0x4c4036,0x488458,0x4d445c, + 0x460468,0x04e03a,0x51c464,0x03c04a,0x46c514,0x47453c,0x04503f,0x47c4ac, + 0x044041,0x510480,0x04304d,0x4e448c,0x490518,0x49449c,0x048047,0x4c0498, + 0x4b84a8,0x4b0508,0x4fc4b4,0x4bc504,0x5304d0,0x5344f0,0x4f452c,0x528538}; + +/* ********************************************************************************************* */ +/* Table: HuffTree43 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the decode tree for spectral data (Codebook 3). */ +/* bit 23 and 11 not used */ +/* bit 22 and 10 determine end value */ +/* bit 21-12 and 9-0 (offset to next node) or (index value * 4) */ +/* --------------------------------------------------------------------------------------------- */ +/* input: codeword */ +/* --------------------------------------------------------------------------------------------- */ +/* output: index * 4 */ +/* --------------------------------------------------------------------------------------------- */ +const UINT aHuffTree43[80] = {0x400001,0x002004,0x00300a,0x46c404,0x00b005,0x00600d,0x034007,0x037008, + 0x494009,0x4d8408,0x42440c,0x00c01b,0x490410,0x00e016,0x00f011,0x010014, + 0x4144fc,0x01201d,0x020013,0x508418,0x4c0015,0x41c440,0x022017,0x018026, + 0x019035,0x03801a,0x420444,0x01c01f,0x430428,0x02101e,0x44842c,0x478434, + 0x4b4438,0x45443c,0x02c023,0x039024,0x02503f,0x48844c,0x030027,0x02e028, + 0x032029,0x02a041,0x4d402b,0x4504f0,0x04302d,0x4584a8,0x02f03b,0x46045c, + 0x03103d,0x464046,0x033044,0x46853c,0x47049c,0x045036,0x4744dc,0x4a047c, + 0x500480,0x4ac03a,0x4b8484,0x03c04e,0x48c524,0x03e040,0x4984e8,0x50c4a4, + 0x4b0530,0x042047,0x4bc04b,0x4e44c4,0x5184c8,0x52c4cc,0x5204d0,0x04d048, + 0x04a049,0x4e004c,0x51c4ec,0x4f4510,0x5284f8,0x50404f,0x514538,0x540534}; + +/* ********************************************************************************************* */ +/* Table: HuffTree44 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the decode tree for spectral data (Codebook 4). */ +/* bit 23 and 11 not used */ +/* bit 22 and 10 determine end value */ +/* bit 21-12 and 9-0 (offset to next node) or (index value * 4) */ +/* --------------------------------------------------------------------------------------------- */ +/* input: codeword */ +/* --------------------------------------------------------------------------------------------- */ +/* output: index * 4 */ +/* --------------------------------------------------------------------------------------------- */ +const UINT aHuffTree44[80] = {0x001004,0x020002,0x036003,0x490400,0x005008,0x010006,0x01f007,0x404428, + 0x00e009,0x01100a,0x00b018,0x01600c,0x03700d,0x408015,0x00f03e,0x40c424, + 0x410478,0x022012,0x038013,0x01e014,0x454414,0x448418,0x025017,0x47441c, + 0x030019,0x02601a,0x02d01b,0x01c034,0x01d029,0x4204f0,0x4dc42c,0x470430, + 0x02103c,0x4a0434,0x02302a,0x440024,0x4384a8,0x43c44c,0x02703a,0x02802c, + 0x444524,0x4504e0,0x02b03d,0x458480,0x45c4f4,0x04b02e,0x04f02f,0x460520, + 0x042031,0x048032,0x049033,0x514464,0x03504c,0x540468,0x47c46c,0x4844d8, + 0x039044,0x4884fc,0x03b045,0x48c53c,0x49449c,0x4b8498,0x03f046,0x041040, + 0x4c44a4,0x50c4ac,0x04a043,0x5184b0,0x4e44b4,0x4bc4ec,0x04e047,0x4c04e8, + 0x4c8510,0x4cc52c,0x4d0530,0x5044d4,0x53804d,0x5284f8,0x508500,0x51c534}; + +/* ********************************************************************************************* */ +/* Table: HuffTree21 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the decode tree for spectral data (Codebook 5). */ +/* bit 23 and 11 not used */ +/* bit 22 and 10 determine end value */ +/* bit 21-12 and 9-0 (offset to next node) or (index value * 2) */ +/* --------------------------------------------------------------------------------------------- */ +/* input: codeword */ +/* --------------------------------------------------------------------------------------------- */ +/* output: index * 2 */ +/* --------------------------------------------------------------------------------------------- */ +const UINT aHuffTree21[80] = {0x450001,0x044002,0x042003,0x035004,0x026005,0x022006,0x013007,0x010008, + 0x00d009,0x01c00a,0x01f00b,0x01e00c,0x4a0400,0x01b00e,0x03200f,0x47e402, + 0x020011,0x01204d,0x40449c,0x017014,0x015019,0x01603f,0x406458,0x01804f, + 0x448408,0x04901a,0x40a45a,0x48c40c,0x01d031,0x40e48e,0x490410,0x492412, + 0x021030,0x480414,0x033023,0x02402e,0x02503e,0x416482,0x02a027,0x02802c, + 0x029040,0x418468,0x02b04a,0x41a486,0x02d048,0x41c484,0x04e02f,0x41e426, + 0x420434,0x42249e,0x424494,0x03d034,0x428470,0x039036,0x03703b,0x038041, + 0x42a476,0x03a04b,0x42c454,0x03c047,0x42e472,0x430478,0x43246e,0x496436, + 0x488438,0x43a466,0x046043,0x43c464,0x04504c,0x43e462,0x460440,0x44245e, + 0x45c444,0x46a446,0x44a456,0x47444c,0x45244e,0x46c47c,0x48a47a,0x49a498}; + +/* ********************************************************************************************* */ +/* Table: HuffTree22 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the decode tree for spectral data (Codebook 6). */ +/* bit 23 and 11 not used */ +/* bit 22 and 10 determine end value */ +/* bit 21-12 and 9-0 (offset to next node) or (index value * 2) */ +/* --------------------------------------------------------------------------------------------- */ +/* input: codeword */ +/* --------------------------------------------------------------------------------------------- */ +/* output: index * 2 */ +/* --------------------------------------------------------------------------------------------- */ +const UINT aHuffTree22[80] = {0x03c001,0x02f002,0x020003,0x01c004,0x00f005,0x00c006,0x016007,0x04d008, + 0x00b009,0x01500a,0x400490,0x40e402,0x00d013,0x00e02a,0x40c404,0x019010, + 0x011041,0x038012,0x40a406,0x014037,0x40849c,0x4a0410,0x04a017,0x458018, + 0x412422,0x02801a,0x01b029,0x480414,0x02401d,0x01e02b,0x48a01f,0x416432, + 0x02d021,0x026022,0x023039,0x418468,0x025043,0x48641a,0x027040,0x41c488, + 0x41e48c,0x42045a,0x47c424,0x04c02c,0x46e426,0x03602e,0x428478,0x030033, + 0x43c031,0x04b032,0x42e42a,0x03403a,0x035048,0x42c442,0x470430,0x494434, + 0x43649a,0x45c438,0x04403b,0x43a454,0x04503d,0x03e03f,0x43e464,0x440460, + 0x484444,0x049042,0x446448,0x44a456,0x46644c,0x047046,0x44e452,0x450462, + 0x47445e,0x46a496,0x49846c,0x472476,0x47a482,0x04e04f,0x47e492,0x48e49e}; + +/* ********************************************************************************************* */ +/* Table: HuffTree23 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the decode tree for spectral data (Codebook 7). */ +/* bit 23 and 11 not used */ +/* bit 22 and 10 determine end value */ +/* bit 21-12 and 9-0 (offset to next node) or (index value * 2) */ +/* --------------------------------------------------------------------------------------------- */ +/* input: codeword */ +/* --------------------------------------------------------------------------------------------- */ +/* output: index * 2 */ +/* --------------------------------------------------------------------------------------------- */ +const UINT aHuffTree23[63] = {0x400001,0x002003,0x410402,0x004007,0x412005,0x01c006,0x420404,0x00800b, + 0x01d009,0x00a01f,0x406026,0x00c012,0x00d00f,0x02700e,0x408440,0x010022, + 0x028011,0x45440a,0x013017,0x029014,0x024015,0x01602f,0x43c40c,0x02b018, + 0x019033,0x03201a,0x43e01b,0x47040e,0x422414,0x01e025,0x432416,0x020021, + 0x418442,0x41a452,0x036023,0x41c446,0x46441e,0x424430,0x426434,0x436428, + 0x44442a,0x02e02a,0x45642c,0x03002c,0x02d03b,0x46642e,0x43a438,0x460448, + 0x031037,0x47244a,0x45a44c,0x034039,0x038035,0x47844e,0x462450,0x474458, + 0x46a45c,0x03a03c,0x45e47a,0x476468,0x03d03e,0x47c46c,0x46e47e}; + +/* ********************************************************************************************* */ +/* Table: HuffTree24 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the decode tree for spectral data (Codebook 8). */ +/* bit 23 and 11 not used */ +/* bit 22 and 10 determine end value */ +/* bit 21-12 and 9-0 (offset to next node) or (index value * 2) */ +/* --------------------------------------------------------------------------------------------- */ +/* input: codeword */ +/* --------------------------------------------------------------------------------------------- */ +/* output: index * 2 */ +/* --------------------------------------------------------------------------------------------- */ +const UINT aHuffTree24[63] = {0x001006,0x01d002,0x005003,0x424004,0x400420,0x414402,0x00700a,0x008020, + 0x00901f,0x404432,0x00b011,0x00c00e,0x00d032,0x406446,0x02300f,0x033010, + 0x458408,0x025012,0x013016,0x01402f,0x015038,0x46840a,0x028017,0x01801a, + 0x039019,0x40c47a,0x03e01b,0x03b01c,0x40e47e,0x41201e,0x422410,0x416434, + 0x02a021,0x02202b,0x418444,0x02c024,0x41a456,0x02d026,0x027034,0x46241c, + 0x029036,0x41e45c,0x426031,0x428430,0x45242a,0x03702e,0x42c464,0x03003c, + 0x47442e,0x436442,0x438454,0x43a448,0x03503a,0x43c466,0x43e03d,0x44a440, + 0x44c472,0x46044e,0x45a450,0x45e470,0x46a476,0x46c478,0x47c46e}; + +/* ********************************************************************************************* */ +/* Table: HuffTree25 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the decode tree for spectral data (Codebook 9). */ +/* bit 23 and 11 not used */ +/* bit 22 and 10 determine end value */ +/* bit 21-12 and 9-0 (offset to next node) or (index value * 2) */ +/* --------------------------------------------------------------------------------------------- */ +/* input: codeword */ +/* --------------------------------------------------------------------------------------------- */ +/* output: index * 2 */ +/* --------------------------------------------------------------------------------------------- */ +const UINT aHuffTree25[168] = {0x400001,0x002003,0x41a402,0x004007,0x41c005,0x035006,0x434404,0x008010, + 0x00900c,0x04a00a,0x42000b,0x44e406,0x03600d,0x03800e,0x05a00f,0x408468, + 0x01101a,0x012016,0x039013,0x070014,0x46e015,0x40a440,0x03b017,0x01804d, + 0x01904f,0x4b840c,0x01b022,0x01c041,0x03f01d,0x01e020,0x01f05b,0x40e4ee, + 0x02107c,0x45c410,0x02302c,0x024028,0x053025,0x026045,0x02707d,0x412522, + 0x047029,0x05e02a,0x02b08a,0x526414,0x05602d,0x02e081,0x02f032,0x06e030, + 0x031080,0x416544,0x079033,0x034091,0x41852c,0x43641e,0x04b037,0x42246a, + 0x43c424,0x04c03a,0x426456,0x03c066,0x03d03e,0x482428,0x45842a,0x040072, + 0x42c4ba,0x050042,0x04305c,0x044074,0x42e4be,0x06a046,0x4dc430,0x075048, + 0x0490a3,0x44a432,0x450438,0x43a452,0x48443e,0x04e068,0x45a442,0x4d4444, + 0x051088,0x052087,0x44648c,0x077054,0x4da055,0x50a448,0x057060,0x06b058, + 0x05906d,0x44c4f6,0x46c454,0x45e474,0x06905d,0x460520,0x05f07e,0x462494, + 0x061063,0x07f062,0x464496,0x06408b,0x08d065,0x542466,0x067071,0x4d2470, + 0x4724ec,0x478476,0x53a47a,0x09b06c,0x47c4ac,0x4f847e,0x06f078,0x510480, + 0x48649e,0x4884a0,0x07307b,0x49c48a,0x4a648e,0x098076,0x4904c0,0x4924ea, + 0x4c8498,0x07a08e,0x51249a,0x4a24d6,0x5064a4,0x4f24a8,0x4aa4de,0x51e4ae, + 0x4b0538,0x082092,0x083085,0x08f084,0x5464b2,0x096086,0x4ce4b4,0x4d04b6, + 0x089090,0x4bc508,0x4c253e,0x08c0a4,0x5284c4,0x4e04c6,0x4ca4fa,0x5144cc, + 0x4f04d8,0x4e24fc,0x09309c,0x094099,0x095097,0x4e4516,0x4e652e,0x4e84fe, + 0x4f450c,0x09a09f,0x500502,0x50450e,0x09d0a0,0x09e0a5,0x518530,0x51a54a, + 0x0a70a1,0x0a20a6,0x51c534,0x53c524,0x54052a,0x548532,0x536550,0x54c54e}; + +/* ********************************************************************************************* */ +/* Table: HuffTree26 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the decode tree for spectral data (Codebook 10). */ +/* bit 23 and 11 not used */ +/* bit 22 and 10 determine end value */ +/* bit 21-12 and 9-0 (offset to next node) or (index value * 2) */ +/* --------------------------------------------------------------------------------------------- */ +/* input: codeword */ +/* --------------------------------------------------------------------------------------------- */ +/* output: index * 2 */ +/* --------------------------------------------------------------------------------------------- */ +const UINT aHuffTree26[168] = {0x006001,0x002013,0x00300f,0x00400d,0x03b005,0x40046e,0x037007,0x00800a, + 0x009067,0x402420,0x05600b,0x00c057,0x434404,0x06600e,0x406470,0x03c010, + 0x059011,0x06f012,0x49e408,0x014019,0x03f015,0x016044,0x017042,0x079018, + 0x4b840a,0x01a01f,0x01b047,0x07c01c,0x08701d,0x06901e,0x44640c,0x020027, + 0x04b021,0x02204f,0x023025,0x02406b,0x40e4e0,0x081026,0x528410,0x02802c, + 0x06c029,0x08f02a,0x02b078,0x53a412,0x05202d,0x02e033,0x02f031,0x0300a2, + 0x4144ce,0x0a6032,0x416534,0x09a034,0x09f035,0x0360a7,0x54e418,0x03a038, + 0x436039,0x43841a,0x41c41e,0x42246a,0x05803d,0x03e068,0x424484,0x04005b, + 0x04107a,0x42645a,0x043093,0x4d2428,0x05e045,0x046072,0x42a45e,0x048060, + 0x073049,0x04a098,0x42c4c4,0x07504c,0x09504d,0x04e09c,0x51042e,0x063050, + 0x077051,0x43053c,0x053084,0x065054,0x4e4055,0x4fe432,0x43a454,0x43c46c, + 0x43e486,0x07005a,0x4a0440,0x07105c,0x05d07b,0x45c442,0x05f08a,0x476444, + 0x07f061,0x06206a,0x448506,0x06408e,0x52644a,0x54444c,0x45644e,0x452450, + 0x488458,0x4604ec,0x4624f6,0x50e464,0x08206d,0x0a406e,0x542466,0x4a2468, + 0x48a472,0x474089,0x4d8478,0x097074,0x47a508,0x08d076,0x47c4b6,0x51247e, + 0x4804fc,0x4bc482,0x48c4a4,0x48e4d4,0x07d07e,0x4904da,0x49208b,0x094080, + 0x49450c,0x4964e2,0x09d083,0x52a498,0x085091,0x0a5086,0x4cc49a,0x08808c, + 0x4ee49c,0x4a64ba,0x4a84c0,0x4c24aa,0x4ac4f0,0x4ae4d0,0x4ca4b0,0x0900a1, + 0x4b24ea,0x092099,0x4b4516,0x4d64be,0x4c650a,0x522096,0x4c8524,0x4dc4f2, + 0x4de4f4,0x4e6548,0x09e09b,0x5384e8,0x5204f8,0x4fa53e,0x50051a,0x0a30a0, + 0x502536,0x514504,0x51e518,0x54a51c,0x54052c,0x52e546,0x530532,0x54c550}; + +/* ********************************************************************************************* */ +/* Table: HuffTree27 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the decode tree for spectral data (Codebook 11). */ +/* bit 23 and 11 not used */ +/* bit 22 and 10 determine end value */ +/* bit 21-12 and 9-0 (offset to next node) or (index value * 2) */ +/* --------------------------------------------------------------------------------------------- */ +/* input: codeword */ +/* --------------------------------------------------------------------------------------------- */ +/* output: index * 2 */ +/* --------------------------------------------------------------------------------------------- */ +const UINT aHuffTree27[288] = {0x00100d,0x002006,0x003004,0x400424,0x047005,0x402446,0x048007,0x00800a, + 0x00904c,0x44a404,0x07400b,0x00c0bb,0x466406,0x00e014,0x00f054,0x04e010, + 0x051011,0x0a9012,0x0130bc,0x408464,0x01501f,0x01601a,0x017059,0x0af018, + 0x0ca019,0x40a0e4,0x01b05e,0x01c084,0x0bf01d,0x05d01e,0x55a40c,0x020026, + 0x021066,0x043022,0x023062,0x02408d,0x025108,0x40e480,0x027030,0x02802c, + 0x02906b,0x02a0da,0x06502b,0x4105c8,0x0a402d,0x0ec02e,0x0dd02f,0x532412, + 0x06e031,0x032036,0x03303e,0x0fd034,0x0fc035,0x4145b0,0x03703a,0x038117, + 0x10d039,0x5ba416,0x10f03b,0x03c041,0x5fa03d,0x41c418,0x10403f,0x04011d, + 0x41a5f4,0x11c042,0x41e61c,0x087044,0x0f5045,0x0d9046,0x4204a2,0x640422, + 0x04904a,0x426448,0x04b073,0x428468,0x46c04d,0x48a42a,0x04f077,0x076050, + 0x42c4b0,0x0520a7,0x096053,0x42e4a8,0x05507d,0x07a056,0x0d4057,0x0df058, + 0x442430,0x05a081,0x05b09b,0x05c0e2,0x5b8432,0x4fe434,0x05f09e,0x0e6060, + 0x0610d6,0x57c436,0x0cc063,0x112064,0x4384a0,0x43a5ca,0x067089,0x0680b7, + 0x0690a2,0x0a106a,0x43c59c,0x09206c,0x06d0ba,0x60643e,0x0d106f,0x0700ee, + 0x0de071,0x10b072,0x44056c,0x46a444,0x075094,0x48c44c,0x44e490,0x095078, + 0x0ab079,0x4504ce,0x07b097,0x11e07c,0x630452,0x0ac07e,0x07f099,0x080106, + 0x4544b8,0x0820b1,0x0830e5,0x4fc456,0x0b3085,0x08609d,0x45853e,0x0880c2, + 0x5c045a,0x08a08f,0x08b0ce,0x08c0f7,0x58645c,0x11108e,0x45e5c4,0x0c4090, + 0x10a091,0x4604e4,0x0d0093,0x462608,0x48e46e,0x4704b2,0x4d2472,0x0980bd, + 0x4f2474,0x0e309a,0x4764aa,0x0be09c,0x47851a,0x47a4de,0x09f0b5,0x0a00c1, + 0x50047c,0x57847e,0x0a30c3,0x504482,0x0e90a5,0x0a6100,0x4c8484,0x0a811f, + 0x48662a,0x0c70aa,0x488494,0x4924d0,0x0ad0c8,0x0ae0d8,0x496636,0x10e0b0, + 0x4f8498,0x0f30b2,0x49a4dc,0x0f20b4,0x53c49c,0x0b60cb,0x49e57a,0x0b80e0, + 0x0b9109,0x5e44a4,0x5484a6,0x4ac4ae,0x4b44ca,0x4d64b6,0x4ba5da,0x0c60c0, + 0x4bc51e,0x4be556,0x6204c0,0x4c24c4,0x0f80c5,0x5664c6,0x4cc53a,0x4d462c, + 0x0f10c9,0x4d8552,0x4da4fa,0x5be4e0,0x0cd0ff,0x5244e2,0x0cf0e8,0x4e6568, + 0x59a4e8,0x0f90d2,0x1010d3,0x5ac4ea,0x0d50d7,0x4ec634,0x4ee560,0x4f44f0, + 0x4f6638,0x502522,0x0db0dc,0x5065a6,0x508604,0x60050a,0x50c0fb,0x63250e, + 0x1130e1,0x5a4510,0x5125fc,0x516514,0x51863e,0x51c536,0x0e70f4,0x55c520, + 0x602526,0x0eb0ea,0x5cc528,0x5ea52a,0x1140ed,0x60c52c,0x1020ef,0x0f0119, + 0x58e52e,0x530622,0x558534,0x53861e,0x55e540,0x5800f6,0x57e542,0x5445e6, + 0x5465e8,0x0fa115,0x54c54a,0x54e60e,0x5ae550,0x1160fe,0x5f0554,0x564562, + 0x56a58a,0x56e5ee,0x10310c,0x5705d0,0x107105,0x5725d4,0x57463a,0x5765b4, + 0x5825bc,0x5845e2,0x5885de,0x58c592,0x5ce590,0x5945f6,0x63c596,0x11b110, + 0x5d8598,0x5c259e,0x5e05a0,0x5a25c6,0x5a860a,0x5aa5ec,0x5b2610,0x11a118, + 0x6185b6,0x5f25d2,0x5d6616,0x5dc5f8,0x61a5fe,0x612614,0x62e624,0x626628}; + +/* get starting addresses of huffman tables into an array [convert codebook into starting address] */ + /* cb tree */ +const UINT *aHuffTable[MAX_CB] = {aHuffTree41, /* 0 - */ /* use tree 1 as dummy here */ + aHuffTree41, /* 1 1 */ + aHuffTree42, /* 2 2 */ + aHuffTree43, /* 3 3 */ + aHuffTree44, /* 4 4 */ + aHuffTree21, /* 5 5 */ + aHuffTree22, /* 6 6 */ + aHuffTree23, /* 7 7 */ + aHuffTree24, /* 8 8 */ + aHuffTree25, /* 9 9 */ + aHuffTree26, /* 10 10 */ + aHuffTree27, /* 11 11 */ + aHuffTree41, /* 12 - */ /* use tree 1 as dummy here */ + aHuffTree41, /* 13 - */ /* use tree 1 as dummy here */ + aHuffTree41, /* 14 - */ /* use tree 1 as dummy here */ + aHuffTree41, /* 15 - */ /* use tree 1 as dummy here */ + aHuffTree27, /* 16 11 */ + aHuffTree27, /* 17 11 */ + aHuffTree27, /* 18 11 */ + aHuffTree27, /* 19 11 */ + aHuffTree27, /* 20 11 */ + aHuffTree27, /* 21 11 */ + aHuffTree27, /* 22 11 */ + aHuffTree27, /* 23 11 */ + aHuffTree27, /* 24 11 */ + aHuffTree27, /* 25 11 */ + aHuffTree27, /* 26 11 */ + aHuffTree27, /* 27 11 */ + aHuffTree27, /* 28 11 */ + aHuffTree27, /* 29 11 */ + aHuffTree27, /* 30 11 */ + aHuffTree27}; /* 31 11 */ + +/*--------------------------------------------------------------------------------------------- + data-description: + The following tables contain the quantized values. Two or four of the quantized values are + indexed by the result of the decoding in the decoding tree (see tables above). + -------------------------------------------------------------------------------------------- */ + +/* ********************************************************************************************* */ +/* Table: ValTab41 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the quantized values for codebooks 1-2. */ +/* --------------------------------------------------------------------------------------------- */ +const SCHAR aValTab41[324]={-1,-1,-1,-1,-1,-1,-1,0,-1,-1,-1,1,-1,-1,0,-1, + -1,-1,0,0,-1,-1,0,1,-1,-1,1,-1,-1,-1,1,0, + -1,-1,1,1,-1,0,-1,-1,-1,0,-1,0,-1,0,-1,1, + -1,0,0,-1,-1,0,0,0,-1,0,0,1,-1,0,1,-1, + -1,0,1,0,-1,0,1,1,-1,1,-1,-1,-1,1,-1,0, + -1,1,-1,1,-1,1,0,-1,-1,1,0,0,-1,1,0,1, + -1,1,1,-1,-1,1,1,0,-1,1,1,1,0,-1,-1,-1, + 0,-1,-1,0,0,-1,-1,1,0,-1,0,-1,0,-1,0,0, + 0,-1,0,1,0,-1,1,-1,0,-1,1,0,0,-1,1,1, + 0,0,-1,-1,0,0,-1,0,0,0,-1,1,0,0,0,-1, + 0,0,0,0,0,0,0,1,0,0,1,-1,0,0,1,0, + 0,0,1,1,0,1,-1,-1,0,1,-1,0,0,1,-1,1, + 0,1,0,-1,0,1,0,0,0,1,0,1,0,1,1,-1, + 0,1,1,0,0,1,1,1,1,-1,-1,-1,1,-1,-1,0, + 1,-1,-1,1,1,-1,0,-1,1,-1,0,0,1,-1,0,1, + 1,-1,1,-1,1,-1,1,0,1,-1,1,1,1,0,-1,-1, + 1,0,-1,0,1,0,-1,1,1,0,0,-1,1,0,0,0, + 1,0,0,1,1,0,1,-1,1,0,1,0,1,0,1,1, + 1,1,-1,-1,1,1,-1,0,1,1,-1,1,1,1,0,-1, + 1,1,0,0,1,1,0,1,1,1,1,-1,1,1,1,0, + 1,1,1,1}; + +/* ********************************************************************************************* */ +/* Table: ValTab42 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the quantized values for codebooks 3-4. */ +/* --------------------------------------------------------------------------------------------- */ +const SCHAR aValTab42[324]={0,0,0,0,0,0,0,1,0,0,0,2,0,0,1,0, + 0,0,1,1,0,0,1,2,0,0,2,0,0,0,2,1, + 0,0,2,2,0,1,0,0,0,1,0,1,0,1,0,2, + 0,1,1,0,0,1,1,1,0,1,1,2,0,1,2,0, + 0,1,2,1,0,1,2,2,0,2,0,0,0,2,0,1, + 0,2,0,2,0,2,1,0,0,2,1,1,0,2,1,2, + 0,2,2,0,0,2,2,1,0,2,2,2,1,0,0,0, + 1,0,0,1,1,0,0,2,1,0,1,0,1,0,1,1, + 1,0,1,2,1,0,2,0,1,0,2,1,1,0,2,2, + 1,1,0,0,1,1,0,1,1,1,0,2,1,1,1,0, + 1,1,1,1,1,1,1,2,1,1,2,0,1,1,2,1, + 1,1,2,2,1,2,0,0,1,2,0,1,1,2,0,2, + 1,2,1,0,1,2,1,1,1,2,1,2,1,2,2,0, + 1,2,2,1,1,2,2,2,2,0,0,0,2,0,0,1, + 2,0,0,2,2,0,1,0,2,0,1,1,2,0,1,2, + 2,0,2,0,2,0,2,1,2,0,2,2,2,1,0,0, + 2,1,0,1,2,1,0,2,2,1,1,0,2,1,1,1, + 2,1,1,2,2,1,2,0,2,1,2,1,2,1,2,2, + 2,2,0,0,2,2,0,1,2,2,0,2,2,2,1,0, + 2,2,1,1,2,2,1,2,2,2,2,0,2,2,2,1, + 2,2,2,2}; + +/* ********************************************************************************************* */ +/* Table: ValTab21 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the quantized values for codebooks 5-6. */ +/* --------------------------------------------------------------------------------------------- */ +const SCHAR aValTab21[162]={-4,-4,-4,-3,-4,-2,-4,-1,-4,0,-4,1,-4,2,-4,3, + -4,4,-3,-4,-3,-3,-3,-2,-3,-1,-3,0,-3,1,-3,2, + -3,3,-3,4,-2,-4,-2,-3,-2,-2,-2,-1,-2,0,-2,1, + -2,2,-2,3,-2,4,-1,-4,-1,-3,-1,-2,-1,-1,-1,0, + -1,1,-1,2,-1,3,-1,4,0,-4,0,-3,0,-2,0,-1, + 0,0,0,1,0,2,0,3,0,4,1,-4,1,-3,1,-2, + 1,-1,1,0,1,1,1,2,1,3,1,4,2,-4,2,-3, + 2,-2,2,-1,2,0,2,1,2,2,2,3,2,4,3,-4, + 3,-3,3,-2,3,-1,3,0,3,1,3,2,3,3,3,4, + 4,-4,4,-3,4,-2,4,-1,4,0,4,1,4,2,4,3, + 4,4}; + +/* ********************************************************************************************* */ +/* Table: ValTab22 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the quantized values for codebooks 7-8. */ +/* --------------------------------------------------------------------------------------------- */ +const SCHAR aValTab22[128]={0,0,0,1,0,2,0,3,0,4,0,5,0,6,0,7, + 1,0,1,1,1,2,1,3,1,4,1,5,1,6,1,7, + 2,0,2,1,2,2,2,3,2,4,2,5,2,6,2,7, + 3,0,3,1,3,2,3,3,3,4,3,5,3,6,3,7, + 4,0,4,1,4,2,4,3,4,4,4,5,4,6,4,7, + 5,0,5,1,5,2,5,3,5,4,5,5,5,6,5,7, + 6,0,6,1,6,2,6,3,6,4,6,5,6,6,6,7, + 7,0,7,1,7,2,7,3,7,4,7,5,7,6,7,7}; + +/* ********************************************************************************************* */ +/* Table: ValTab23 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the quantized values for codebooks 9-10. */ +/* --------------------------------------------------------------------------------------------- */ +const SCHAR aValTab23[338]={0,0,0,1,0,2,0,3,0,4,0,5,0,6,0,7, + 0,8,0,9,0,10,0,11,0,12,1,0,1,1,1,2, + 1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10, + 1,11,1,12,2,0,2,1,2,2,2,3,2,4,2,5, + 2,6,2,7,2,8,2,9,2,10,2,11,2,12,3,0, + 3,1,3,2,3,3,3,4,3,5,3,6,3,7,3,8, + 3,9,3,10,3,11,3,12,4,0,4,1,4,2,4,3, + 4,4,4,5,4,6,4,7,4,8,4,9,4,10,4,11, + 4,12,5,0,5,1,5,2,5,3,5,4,5,5,5,6, + 5,7,5,8,5,9,5,10,5,11,5,12,6,0,6,1, + 6,2,6,3,6,4,6,5,6,6,6,7,6,8,6,9, + 6,10,6,11,6,12,7,0,7,1,7,2,7,3,7,4, + 7,5,7,6,7,7,7,8,7,9,7,10,7,11,7,12, + 8,0,8,1,8,2,8,3,8,4,8,5,8,6,8,7, + 8,8,8,9,8,10,8,11,8,12,9,0,9,1,9,2, + 9,3,9,4,9,5,9,6,9,7,9,8,9,9,9,10, + 9,11,9,12,10,0,10,1,10,2,10,3,10,4,10,5, + 10,6,10,7,10,8,10,9,10,10,10,11,10,12,11,0, + 11,1,11,2,11,3,11,4,11,5,11,6,11,7,11,8, + 11,9,11,10,11,11,11,12,12,0,12,1,12,2,12,3, + 12,4,12,5,12,6,12,7,12,8,12,9,12,10,12,11, + 12,12}; + +/* ********************************************************************************************* */ +/* Table: ValTab24 */ +/* --------------------------------------------------------------------------------------------- */ +/* description: This table contains the quantized values for codebooks 11. */ +/* --------------------------------------------------------------------------------------------- */ +const SCHAR aValTab24[578]={0,0,0,1,0,2,0,3,0,4,0,5,0,6,0,7, + 0,8,0,9,0,10,0,11,0,12,0,13,0,14,0,15, + 0,16,1,0,1,1,1,2,1,3,1,4,1,5,1,6, + 1,7,1,8,1,9,1,10,1,11,1,12,1,13,1,14, + 1,15,1,16,2,0,2,1,2,2,2,3,2,4,2,5, + 2,6,2,7,2,8,2,9,2,10,2,11,2,12,2,13, + 2,14,2,15,2,16,3,0,3,1,3,2,3,3,3,4, + 3,5,3,6,3,7,3,8,3,9,3,10,3,11,3,12, + 3,13,3,14,3,15,3,16,4,0,4,1,4,2,4,3, + 4,4,4,5,4,6,4,7,4,8,4,9,4,10,4,11, + 4,12,4,13,4,14,4,15,4,16,5,0,5,1,5,2, + 5,3,5,4,5,5,5,6,5,7,5,8,5,9,5,10, + 5,11,5,12,5,13,5,14,5,15,5,16,6,0,6,1, + 6,2,6,3,6,4,6,5,6,6,6,7,6,8,6,9, + 6,10,6,11,6,12,6,13,6,14,6,15,6,16,7,0, + 7,1,7,2,7,3,7,4,7,5,7,6,7,7,7,8, + 7,9,7,10,7,11,7,12,7,13,7,14,7,15,7,16, + 8,0,8,1,8,2,8,3,8,4,8,5,8,6,8,7, + 8,8,8,9,8,10,8,11,8,12,8,13,8,14,8,15, + 8,16,9,0,9,1,9,2,9,3,9,4,9,5,9,6, + 9,7,9,8,9,9,9,10,9,11,9,12,9,13,9,14, + 9,15,9,16,10,0,10,1,10,2,10,3,10,4,10,5, + 10,6,10,7,10,8,10,9,10,10,10,11,10,12,10,13, + 10,14,10,15,10,16,11,0,11,1,11,2,11,3,11,4, + 11,5,11,6,11,7,11,8,11,9,11,10,11,11,11,12, + 11,13,11,14,11,15,11,16,12,0,12,1,12,2,12,3, + 12,4,12,5,12,6,12,7,12,8,12,9,12,10,12,11, + 12,12,12,13,12,14,12,15,12,16,13,0,13,1,13,2, + 13,3,13,4,13,5,13,6,13,7,13,8,13,9,13,10, + 13,11,13,12,13,13,13,14,13,15,13,16,14,0,14,1, + 14,2,14,3,14,4,14,5,14,6,14,7,14,8,14,9, + 14,10,14,11,14,12,14,13,14,14,14,15,14,16,15,0, + 15,1,15,2,15,3,15,4,15,5,15,6,15,7,15,8, + 15,9,15,10,15,11,15,12,15,13,15,14,15,15,15,16, + 16,0,16,1,16,2,16,3,16,4,16,5,16,6,16,7, + 16,8,16,9,16,10,16,11,16,12,16,13,16,14,16,15, + 16,16}; + + /* cb quant. val table */ +const SCHAR *aQuantTable[] = {aValTab41, /* 0 - */ /* use quant. val talble 1 as dummy here */ + aValTab41, /* 1 1 */ + aValTab41, /* 2 1 */ + aValTab42, /* 3 2 */ + aValTab42, /* 4 2 */ + aValTab21, /* 5 3 */ + aValTab21, /* 6 3 */ + aValTab22, /* 7 4 */ + aValTab22, /* 8 4 */ + aValTab23, /* 9 5 */ + aValTab23, /* 10 5 */ + aValTab24, /* 11 6 */ + aValTab41, /* 12 - */ /* use quant. val talble 1 as dummy here */ + aValTab41, /* 13 - */ /* use quant. val talble 1 as dummy here */ + aValTab41, /* 14 - */ /* use quant. val talble 1 as dummy here */ + aValTab41, /* 15 - */ /* use quant. val talble 1 as dummy here */ + aValTab24, /* 16 6 */ + aValTab24, /* 17 6 */ + aValTab24, /* 18 6 */ + aValTab24, /* 19 6 */ + aValTab24, /* 20 6 */ + aValTab24, /* 21 6 */ + aValTab24, /* 22 6 */ + aValTab24, /* 23 6 */ + aValTab24, /* 24 6 */ + aValTab24, /* 25 6 */ + aValTab24, /* 26 6 */ + aValTab24, /* 27 6 */ + aValTab24, /* 28 6 */ + aValTab24, /* 29 6 */ + aValTab24, /* 30 6 */ + aValTab24}; /* 31 6 */ + +/* arrays for HCR_TABLE_INFO structures */ +/* maximum length of codeword in each codebook */ +/* codebook: 0,1, 2,3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 */ +const UCHAR aMaxCwLen[MAX_CB]={0,11,9,20,16,13,11,14,12,17,14,49,0, 0, 0, 0, 14,17,21,21,25,25,29,29,29,29,33,33,33,37,37,41}; + +/* 11 13 15 17 19 21 23 25 27 39 31 */ +/* CB: 0 1 2 3 4 5 6 7 8 9 10 12 14 16 18 20 22 24 26 28 30 */ +const UCHAR aDimCb[MAX_CB] = {2,4,4,4,4,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}; /* codebook dimension - zero cb got a dimension of 2 */ + +/* 11 13 15 17 19 21 23 25 27 39 31 */ +/* CB: 0 1 2 3 4 5 6 7 8 9 10 12 14 16 18 20 22 24 26 28 30 */ +const UCHAR aDimCbShift[MAX_CB]={1,2,2,2,2,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; /* codebook dimension */ + +/* 1 -> decode sign bits */ +/* 0 -> decode no sign bits 11 13 15 17 19 21 23 25 27 39 31 */ +/* CB: 0 1 2 3 4 5 6 7 8 9 10 12 14 16 18 20 22 24 26 28 30 */ +const UCHAR aSignCb[MAX_CB]={0,0,0,1,1,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; + +/* arrays for HCR_CB_PAIRS structures */ +const UCHAR aMinOfCbPair[MAX_CB_PAIRS]={0,1,3,5,7, 9,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,11}; +const UCHAR aMaxOfCbPair[MAX_CB_PAIRS]={0,2,4,6,8,10,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,11}; + +/* priorities of codebooks */ +const UCHAR aCbPriority[MAX_CB]={0,1,1,2,2,3,3,4,4,5,5,22,0,0,0,0,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21}; + +const SCHAR aCodebook2StartInt[] = {STOP_THIS_STATE , /* cb 0 */ + BODY_ONLY , /* cb 1 */ + BODY_ONLY , /* cb 2 */ + BODY_SIGN__BODY , /* cb 3 */ + BODY_SIGN__BODY , /* cb 4 */ + BODY_ONLY , /* cb 5 */ + BODY_ONLY , /* cb 6 */ + BODY_SIGN__BODY , /* cb 7 */ + BODY_SIGN__BODY , /* cb 8 */ + BODY_SIGN__BODY , /* cb 9 */ + BODY_SIGN__BODY , /* cb 10 */ + BODY_SIGN_ESC__BODY, /* cb 11 */ + STOP_THIS_STATE , /* cb 12 */ + STOP_THIS_STATE , /* cb 13 */ + STOP_THIS_STATE , /* cb 14 */ + STOP_THIS_STATE , /* cb 15 */ + BODY_SIGN_ESC__BODY, /* cb 16 */ + BODY_SIGN_ESC__BODY, /* cb 17 */ + BODY_SIGN_ESC__BODY, /* cb 18 */ + BODY_SIGN_ESC__BODY, /* cb 19 */ + BODY_SIGN_ESC__BODY, /* cb 20 */ + BODY_SIGN_ESC__BODY, /* cb 21 */ + BODY_SIGN_ESC__BODY, /* cb 22 */ + BODY_SIGN_ESC__BODY, /* cb 23 */ + BODY_SIGN_ESC__BODY, /* cb 24 */ + BODY_SIGN_ESC__BODY, /* cb 25 */ + BODY_SIGN_ESC__BODY, /* cb 26 */ + BODY_SIGN_ESC__BODY, /* cb 27 */ + BODY_SIGN_ESC__BODY, /* cb 28 */ + BODY_SIGN_ESC__BODY, /* cb 29 */ + BODY_SIGN_ESC__BODY, /* cb 30 */ + BODY_SIGN_ESC__BODY}; /* cb 31 */ + +const STATEFUNC aStateConstant2State[] = {NULL , /* 0 = STOP_THIS_STATE */ + Hcr_State_BODY_ONLY , /* 1 = BODY_ONLY */ + Hcr_State_BODY_SIGN__BODY , /* 2 = BODY_SIGN__BODY */ + Hcr_State_BODY_SIGN__SIGN , /* 3 = BODY_SIGN__SIGN */ + Hcr_State_BODY_SIGN_ESC__BODY , /* 4 = BODY_SIGN_ESC__BODY */ + Hcr_State_BODY_SIGN_ESC__SIGN , /* 5 = BODY_SIGN_ESC__SIGN */ + Hcr_State_BODY_SIGN_ESC__ESC_PREFIX, /* 6 = BODY_SIGN_ESC__ESC_PREFIX */ + Hcr_State_BODY_SIGN_ESC__ESC_WORD }; /* 7 = BODY_SIGN_ESC__ESC_WORD */ + +/* CB: 0 1 2 3 4 5 6 7 8 9 10 12 14 16 18 20 22 24 26 28 30 */ +const USHORT aLargestAbsoluteValue[MAX_CB]={0,1,1,2,2,4,4,7,7,12,12,8191, 0, 0, 0, 0,15,31,47,63,95,127,159,191,223,255,319,383,511,767,1023,2047}; /* lav */ +/* CB: 11 13 15 17 19 21 23 25 27 39 31 */ + + +/* ------------------------------------------------------------------------------------------ + description: The table 'HuffTreeRvlcEscape' contains the decode tree for the rvlc + escape sequences. + bit 23 and 11 not used + bit 22 and 10 determine end value --> if set codeword is decoded + bit 21-12 and 9-0 (offset to next node) or (index value) + The escape sequence is the index value. + + input: codeword + output: index +------------------------------------------------------------------------------------------ */ +const UINT aHuffTreeRvlcEscape[53] = { 0x002001,0x400003,0x401004,0x402005,0x403007,0x404006,0x00a405,0x009008, + 0x00b406,0x00c407,0x00d408,0x00e409,0x40b40a,0x40c00f,0x40d010,0x40e011, + 0x40f012,0x410013,0x411014,0x412015,0x016413,0x414415,0x017416,0x417018, + 0x419019,0x01a418,0x01b41a,0x01c023,0x03201d,0x01e020,0x43501f,0x41b41c, + 0x021022,0x41d41e,0x41f420,0x02402b,0x025028,0x026027,0x421422,0x423424, + 0x02902a,0x425426,0x427428,0x02c02f,0x02d02e,0x42942a,0x42b42c,0x030031, + 0x42d42e,0x42f430,0x033034,0x431432,0x433434 }; + +/* ------------------------------------------------------------------------------------------ + description: The table 'HuffTreeRvlc' contains the huffman decoding tree for the RVLC + scale factors. The table contains 15 allowed, symmetric codewords and 8 + forbidden codewords, which are used for error detection. + + usage of bits: bit 23 and 11 not used + bit 22 and 10 determine end value --> if set codeword is decoded + bit 21-12 and 9-0 (offset to next node within the table) or (index+7). + The decoded (index+7) is in the range from 0,1,..,22. If the (index+7) + is in the range 15,16,..,22, then a forbidden codeword is decoded. + + input: A single bit from a RVLC scalefactor codeword + output: [if codeword is not completely decoded:] offset to next node within table or + [if codeword is decoded:] A dpcm value i.e. (index+7) in range from 0,1,..,22. + The differential scalefactor (DPCM value) named 'index' is calculated by + subtracting 7 from the decoded value (index+7). +------------------------------------------------------------------------------------------ */ +const UINT aHuffTreeRvlCodewds[22] = { 0x407001,0x002009,0x003406,0x004405,0x005404,0x006403,0x007400,0x008402, + 0x411401,0x00a408,0x00c00b,0x00e409,0x01000d,0x40f40a,0x41400f,0x01340b, + 0x011015,0x410012,0x41240c,0x416014,0x41540d,0x41340e }; + + + +const FIXP_WTB LowDelaySynthesis512[1536] = { +/* part 0 */ +WTC(0xdac984c0), WTC(0xdb100080), WTC(0xdb56cd00), WTC(0xdb9dec40), WTC(0xdbe55fc0), WTC(0xdc2d2880), WTC(0xdc754780), WTC(0xdcbdbd80), +WTC(0xdd068a80), WTC(0xdd4fae80), WTC(0xdd992940), WTC(0xdde2f9c0), WTC(0xde2d1fc0), WTC(0xde779a80), WTC(0xdec26a00), WTC(0xdf0d8e00), +WTC(0xdf590680), WTC(0xdfa4d540), WTC(0xdff0fc80), WTC(0xe03d7e20), WTC(0xe08a5900), WTC(0xe0d78a20), WTC(0xe1250cc0), WTC(0xe172dcc0), +WTC(0xe1c0f7a0), WTC(0xe20f59a0), WTC(0xe25dfea0), WTC(0xe2ace400), WTC(0xe2fc0be0), WTC(0xe34b7bc0), WTC(0xe39b3c80), WTC(0xe3eb5260), +WTC(0xe43bbac0), WTC(0xe48c7160), WTC(0xe4dd7140), WTC(0xe52eb600), WTC(0xe5803c00), WTC(0xe5d1fda0), WTC(0xe623f360), WTC(0xe6761700), +WTC(0xe6c86400), WTC(0xe71ad500), WTC(0xe76d63e0), WTC(0xe7c00ba0), WTC(0xe812c8e0), WTC(0xe86598e0), WTC(0xe8b878e0), WTC(0xe90b68a0), +WTC(0xe95e6c40), WTC(0xe9b18ae0), WTC(0xea04ce80), WTC(0xea583ba0), WTC(0xeaabcda0), WTC(0xeaff7ee0), WTC(0xeb5348e0), WTC(0xeba722c0), +WTC(0xebfb0060), WTC(0xec4ed240), WTC(0xeca28540), WTC(0xecf60c20), WTC(0xed496120), WTC(0xed9c7e80), WTC(0xedef5e40), WTC(0xee41fc00), +WTC(0xee945600), WTC(0xeee66ac0), WTC(0xef3839a0), WTC(0xef89c0e0), WTC(0xefdafda0), WTC(0xf02bed60), WTC(0xf07c8e80), WTC(0xf0cce000), +WTC(0xf11ce220), WTC(0xf16c9620), WTC(0xf1bbfe30), WTC(0xf20b19e0), WTC(0xf259e5a0), WTC(0xf2a85dc0), WTC(0xf2f67ed0), WTC(0xf34445b0), +WTC(0xf391aed0), WTC(0xf3deb590), WTC(0xf42b53e0), WTC(0xf4778140), WTC(0xf4c33190), WTC(0xf50e5660), WTC(0xf558df30), WTC(0xf5a2be50), +WTC(0xf5ebea10), WTC(0xf6345780), WTC(0xf67bfab0), WTC(0xf6c2cee0), WTC(0xf708d7b0), WTC(0xf74e19c0), WTC(0xf7929a70), WTC(0xf7d66630), +WTC(0xf8199268), WTC(0xf85c3860), WTC(0xf89e7480), WTC(0xf8e058c0), WTC(0xf921ec08), WTC(0xf9633800), WTC(0xf9a44980), WTC(0xf9e53158), +WTC(0xfa260158), WTC(0xfa66ca18), WTC(0xfaa79ac0), WTC(0xfae87920), WTC(0xfb295fa0), WTC(0xfb6a42b8), WTC(0xfbab1240), WTC(0xfbebd1c0), +WTC(0xfc2c9c24), WTC(0xfc6d8d90), WTC(0xfcaec240), WTC(0xfcf05684), WTC(0xfd326a98), WTC(0xfd75254c), WTC(0xfdb8afd4), WTC(0xfdfccdfc), +WTC(0xfe40d694), WTC(0xfe84161c), WTC(0xfec5cf5a), WTC(0xff04e7fc), WTC(0xff3fdfe3), WTC(0xff751ddf), WTC(0xffa2fb0f), WTC(0xffc87c42), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0xbffb6081), WTC(0xbff22f81), WTC(0xbfe8fc01), WTC(0xbfdfc781), WTC(0xbfd69101), WTC(0xbfcd5a01), WTC(0xbfc42201), WTC(0xbfbae981), +WTC(0xbfb1b101), WTC(0xbfa87901), WTC(0xbf9f4181), WTC(0xbf960b01), WTC(0xbf8cd481), WTC(0xbf839d81), WTC(0xbf7a6681), WTC(0xbf712f01), +WTC(0xbf67f801), WTC(0xbf5ec101), WTC(0xbf558b01), WTC(0xbf4c5681), WTC(0xbf432281), WTC(0xbf39ee81), WTC(0xbf30bb01), WTC(0xbf278801), +WTC(0xbf1e5501), WTC(0xbf152381), WTC(0xbf0bf381), WTC(0xbf02c581), WTC(0xbef99901), WTC(0xbef06d01), WTC(0xbee74281), WTC(0xbede1901), +WTC(0xbed4f081), WTC(0xbecbca81), WTC(0xbec2a781), WTC(0xbeb98681), WTC(0xbeb06881), WTC(0xbea74c81), WTC(0xbe9e3281), WTC(0xbe951a81), +WTC(0xbe8c0501), WTC(0xbe82f301), WTC(0xbe79e481), WTC(0xbe70da01), WTC(0xbe67d381), WTC(0xbe5ed081), WTC(0xbe55d001), WTC(0xbe4cd381), +WTC(0xbe43da81), WTC(0xbe3ae601), WTC(0xbe31f701), WTC(0xbe290d01), WTC(0xbe202801), WTC(0xbe174781), WTC(0xbe0e6c01), WTC(0xbe059481), +WTC(0xbdfcc301), WTC(0xbdf3f701), WTC(0xbdeb3101), WTC(0xbde27201), WTC(0xbdd9b981), WTC(0xbdd10681), WTC(0xbdc85981), WTC(0xbdbfb281), +WTC(0xbdb71201), WTC(0xbdae7881), WTC(0xbda5e601), WTC(0xbd9d5b81), WTC(0xbd94d801), WTC(0xbd8c5c01), WTC(0xbd83e681), WTC(0xbd7b7781), +WTC(0xbd731081), WTC(0xbd6ab101), WTC(0xbd625981), WTC(0xbd5a0b01), WTC(0xbd51c481), WTC(0xbd498601), WTC(0xbd414f01), WTC(0xbd391f81), +WTC(0xbd30f881), WTC(0xbd28d981), WTC(0xbd20c401), WTC(0xbd18b781), WTC(0xbd10b381), WTC(0xbd08b781), WTC(0xbd00c381), WTC(0xbcf8d781), +WTC(0xbcf0f381), WTC(0xbce91801), WTC(0xbce14601), WTC(0xbcd97c81), WTC(0xbcd1bb81), WTC(0xbcca0301), WTC(0xbcc25181), WTC(0xbcbaa801), +WTC(0xbcb30601), WTC(0xbcab6c01), WTC(0xbca3db01), WTC(0xbc9c5281), WTC(0xbc94d201), WTC(0xbc8d5901), WTC(0xbc85e801), WTC(0xbc7e7e01), +WTC(0xbc771c01), WTC(0xbc6fc101), WTC(0xbc686e01), WTC(0xbc612301), WTC(0xbc59df81), WTC(0xbc52a381), WTC(0xbc4b6e81), WTC(0xbc444081), +WTC(0xbc3d1801), WTC(0xbc35f501), WTC(0xbc2ed681), WTC(0xbc27bd81), WTC(0xbc20ae01), WTC(0xbc19ab01), WTC(0xbc12b801), WTC(0xbc0bcf81), +WTC(0xbc04e381), WTC(0xbbfde481), WTC(0xbbf6c601), WTC(0xbbef9b81), WTC(0xbbe89901), WTC(0xbbe1f401), WTC(0xbbdbe201), WTC(0xbbd68c81), +WTC(0xbbd21281), WTC(0xbbce9181), WTC(0xbbcc2681), WTC(0xbbcaca01), WTC(0xbbca5081), WTC(0xbbca8d01), WTC(0xbbcb5301), WTC(0xbbcc8201), +WTC(0xbbce0601), WTC(0xbbcfca81), WTC(0xbbd1bd81), WTC(0xbbd3e101), WTC(0xbbd64d01), WTC(0xbbd91b81), WTC(0xbbdc6481), WTC(0xbbe03801), +WTC(0xbbe49d01), WTC(0xbbe99981), WTC(0xbbef3301), WTC(0xbbf56181), WTC(0xbbfc0f81), WTC(0xbc032601), WTC(0xbc0a8f01), WTC(0xbc123b81), +WTC(0xbc1a2401), WTC(0xbc224181), WTC(0xbc2a8c81), WTC(0xbc330781), WTC(0xbc3bbc01), WTC(0xbc44b481), WTC(0xbc4dfb81), WTC(0xbc57a301), +WTC(0xbc61c401), WTC(0xbc6c7781), WTC(0xbc77d601), WTC(0xbc83f201), WTC(0xbc90d481), WTC(0xbc9e8801), WTC(0xbcad1501), WTC(0xbcbc7e01), +WTC(0xbcccbd01), WTC(0xbcddcc81), WTC(0xbcefa601), WTC(0xbd023f01), WTC(0xbd158801), WTC(0xbd297181), WTC(0xbd3deb81), WTC(0xbd52eb01), +WTC(0xbd686681), WTC(0xbd7e5581), WTC(0xbd94b001), WTC(0xbdab7181), WTC(0xbdc29a81), WTC(0xbdda2a01), WTC(0xbdf22181), WTC(0xbe0a8581), +WTC(0xbe236001), WTC(0xbe3cbc01), WTC(0xbe56a381), WTC(0xbe712001), WTC(0xbe8c3781), WTC(0xbea7f301), WTC(0xbec45881), WTC(0xbee17201), +WTC(0xbeff4801), WTC(0xbf1de601), WTC(0xbf3d5501), WTC(0xbf5d9a81), WTC(0xbf7eb581), WTC(0xbfa0a581), WTC(0xbfc36a01), WTC(0xbfe6ed01), +WTC(0xc00b04c0), WTC(0xc02f86c0), WTC(0xc0544940), WTC(0xc0792ec0), WTC(0xc09e2640), WTC(0xc0c31f00), WTC(0xc0e80a00), WTC(0xc10cf480), +WTC(0xc1320940), WTC(0xc15773c0), WTC(0xc17d5f00), WTC(0xc1a3e340), WTC(0xc1cb05c0), WTC(0xc1f2cbc0), WTC(0xc21b3940), WTC(0xc2444b00), +WTC(0xc26df5c0), WTC(0xc2982d80), WTC(0xc2c2e640), WTC(0xc2ee0a00), WTC(0xc3197940), WTC(0xc34513c0), WTC(0xc370b9c0), WTC(0xc39c4f00), +WTC(0xc3c7bc00), WTC(0xc3f2e940), WTC(0xc41dc140), WTC(0xc44856c0), WTC(0xc472e640), WTC(0xc49dad80), WTC(0xc4c8e880), WTC(0xc4f4acc0), +WTC(0xc520e840), WTC(0xc54d8780), WTC(0xc57a76c0), WTC(0xc5a79640), WTC(0xc5d4bac0), WTC(0xc601b880), WTC(0xc62e6580), WTC(0xc65ab600), +WTC(0xc686bd40), WTC(0xc6b28fc0), WTC(0xc6de41c0), WTC(0xc709de40), WTC(0xc7356640), WTC(0xc760da80), WTC(0xc78c3c40), WTC(0xc7b78640), +WTC(0xc7e2afc0), WTC(0xc80dae80), WTC(0xc83878c0), WTC(0xc86304c0), WTC(0xc88d4900), WTC(0xc8b73b80), WTC(0xc8e0d280), WTC(0xc90a0440), +/* part 1 */ +WTC(0xb5212e81), WTC(0xb4959501), WTC(0xb40ab501), WTC(0xb3808d81), WTC(0xb2f71f01), WTC(0xb26e6881), WTC(0xb1e66a01), WTC(0xb15f2381), +WTC(0xb0d89401), WTC(0xb052bc01), WTC(0xafcd9a81), WTC(0xaf492f01), WTC(0xaec57801), WTC(0xae427481), WTC(0xadc02281), WTC(0xad3e8101), +WTC(0xacbd9081), WTC(0xac3d5001), WTC(0xabbdc001), WTC(0xab3edf01), WTC(0xaac0ad01), WTC(0xaa432981), WTC(0xa9c65401), WTC(0xa94a2c01), +WTC(0xa8ceb201), WTC(0xa853e501), WTC(0xa7d9c681), WTC(0xa7605601), WTC(0xa6e79401), WTC(0xa66f8201), WTC(0xa5f81f81), WTC(0xa5816e81), +WTC(0xa50b6e81), WTC(0xa4962181), WTC(0xa4218801), WTC(0xa3ada281), WTC(0xa33a7201), WTC(0xa2c7f801), WTC(0xa2563501), WTC(0xa1e52a81), +WTC(0xa174da81), WTC(0xa1054701), WTC(0xa0967201), WTC(0xa0285d81), WTC(0x9fbb0981), WTC(0x9f4e7801), WTC(0x9ee2a901), WTC(0x9e779f81), +WTC(0x9e0d5e01), WTC(0x9da3e601), WTC(0x9d3b3b81), WTC(0x9cd35f81), WTC(0x9c6c5481), WTC(0x9c061b81), WTC(0x9ba0b701), WTC(0x9b3c2801), +WTC(0x9ad87081), WTC(0x9a759301), WTC(0x9a139101), WTC(0x99b26c81), WTC(0x99522801), WTC(0x98f2c601), WTC(0x98944901), WTC(0x9836b201), +WTC(0x97da0481), WTC(0x977e4181), WTC(0x97236b01), WTC(0x96c98381), WTC(0x96708b81), WTC(0x96188501), WTC(0x95c17081), WTC(0x956b4f81), +WTC(0x95162381), WTC(0x94c1ee01), WTC(0x946eaf81), WTC(0x941c6901), WTC(0x93cb1c81), WTC(0x937acb01), WTC(0x932b7501), WTC(0x92dd1b01), +WTC(0x928fbe01), WTC(0x92435d01), WTC(0x91f7f981), WTC(0x91ad9281), WTC(0x91642781), WTC(0x911bb981), WTC(0x90d44781), WTC(0x908dd101), +WTC(0x90485401), WTC(0x9003ce81), WTC(0x8fc03f01), WTC(0x8f7da401), WTC(0x8f3bfb01), WTC(0x8efb4181), WTC(0x8ebb7581), WTC(0x8e7c9301), +WTC(0x8e3e9481), WTC(0x8e017581), WTC(0x8dc53001), WTC(0x8d89be81), WTC(0x8d4f1b01), WTC(0x8d154081), WTC(0x8cdc2901), WTC(0x8ca3cb01), +WTC(0x8c6c1b01), WTC(0x8c350d01), WTC(0x8bfe9401), WTC(0x8bc8a401), WTC(0x8b933001), WTC(0x8b5e2c81), WTC(0x8b298b81), WTC(0x8af53e81), +WTC(0x8ac13381), WTC(0x8a8d5801), WTC(0x8a599a81), WTC(0x8a25f301), WTC(0x89f26101), WTC(0x89bee581), WTC(0x898b8301), WTC(0x89586901), +WTC(0x8925f101), WTC(0x88f47901), WTC(0x88c45e81), WTC(0x88962981), WTC(0x886a8a81), WTC(0x88423301), WTC(0x881dd301), WTC(0x87fdd781), +WTC(0x87d0ca81), WTC(0x87c76201), WTC(0x87bcab81), WTC(0x87b0ef01), WTC(0x87a48b01), WTC(0x8797dd81), WTC(0x878b4301), WTC(0x877ede01), +WTC(0x87729701), WTC(0x87665481), WTC(0x8759fd01), WTC(0x874d8681), WTC(0x8740f681), WTC(0x87345381), WTC(0x8727a381), WTC(0x871ae981), +WTC(0x870e2301), WTC(0x87014f81), WTC(0x86f46d81), WTC(0x86e77b81), WTC(0x86da7901), WTC(0x86cd6681), WTC(0x86c04381), WTC(0x86b30f01), +WTC(0x86a5ca81), WTC(0x86987581), WTC(0x868b1001), WTC(0x867d9a81), WTC(0x86701381), WTC(0x86627b01), WTC(0x8654d001), WTC(0x86471281), +WTC(0x86394301), WTC(0x862b6201), WTC(0x861d7081), WTC(0x860f6e01), WTC(0x86015981), WTC(0x85f33281), WTC(0x85e4f801), WTC(0x85d6a981), +WTC(0x85c84801), WTC(0x85b9d481), WTC(0x85ab4f01), WTC(0x859cb781), WTC(0x858e0e01), WTC(0x857f5101), WTC(0x85707f81), WTC(0x85619a01), +WTC(0x8552a181), WTC(0x85439601), WTC(0x85347901), WTC(0x85254a81), WTC(0x85160981), WTC(0x8506b581), WTC(0x84f74e01), WTC(0x84e7d381), +WTC(0x84d84601), WTC(0x84c8a701), WTC(0x84b8f801), WTC(0x84a93801), WTC(0x84996701), WTC(0x84898481), WTC(0x84798f81), WTC(0x84698881), +WTC(0x84597081), WTC(0x84494881), WTC(0x84391081), WTC(0x8428ca01), WTC(0x84187401), WTC(0x84080d81), WTC(0x83f79681), WTC(0x83e70f01), +WTC(0x83d67881), WTC(0x83c5d381), WTC(0x83b52101), WTC(0x83a46181), WTC(0x83939501), WTC(0x8382ba01), WTC(0x8371d081), WTC(0x8360d901), +WTC(0x834fd481), WTC(0x833ec381), WTC(0x832da781), WTC(0x831c8101), WTC(0x830b4f81), WTC(0x82fa1181), WTC(0x82e8c801), WTC(0x82d77201), +WTC(0x82c61101), WTC(0x82b4a601), WTC(0x82a33281), WTC(0x8291b601), WTC(0x82803101), WTC(0x826ea201), WTC(0x825d0901), WTC(0x824b6601), +WTC(0x8239b981), WTC(0x82280581), WTC(0x82164a81), WTC(0x82048881), WTC(0x81f2bf81), WTC(0x81e0ee81), WTC(0x81cf1581), WTC(0x81bd3401), +WTC(0x81ab4b01), WTC(0x81995c01), WTC(0x81876781), WTC(0x81756d81), WTC(0x81636d81), WTC(0x81516701), WTC(0x813f5981), WTC(0x812d4481), +WTC(0x811b2981), WTC(0x81090981), WTC(0x80f6e481), WTC(0x80e4bb81), WTC(0x80d28d81), WTC(0x80c05a01), WTC(0x80ae1f81), WTC(0x809bdf01), +WTC(0x80899881), WTC(0x80774c81), WTC(0x8064fc81), WTC(0x8052a881), WTC(0x80405101), WTC(0x802df701), WTC(0x801b9b01), WTC(0x80093e01), +WTC(0x0a74b120), WTC(0x0aa08a90), WTC(0x0acd2b80), WTC(0x0afa8860), WTC(0x0b289590), WTC(0x0b574790), WTC(0x0b8692d0), WTC(0x0bb66bb0), +WTC(0x0be6c6b0), WTC(0x0c179830), WTC(0x0c48d500), WTC(0x0c7a7ad0), WTC(0x0cac9000), WTC(0x0cdf1b60), WTC(0x0d122390), WTC(0x0d45a8f0), +WTC(0x0d79a5e0), WTC(0x0dae1480), WTC(0x0de2ef30), WTC(0x0e183800), WTC(0x0e4df8c0), WTC(0x0e843b90), WTC(0x0ebb0a20), WTC(0x0ef26430), +WTC(0x0f2a3fc0), WTC(0x0f629280), WTC(0x0f9b5210), WTC(0x0fd47690), WTC(0x100dfa80), WTC(0x1047d8a0), WTC(0x10820b40), WTC(0x10bc8b80), +WTC(0x10f75080), WTC(0x11325100), WTC(0x116d84e0), WTC(0x11a8ece0), WTC(0x11e49420), WTC(0x122085a0), WTC(0x125ccbc0), WTC(0x12995a40), +WTC(0x12d60e80), WTC(0x1312c4c0), WTC(0x134f59e0), WTC(0x138bae60), WTC(0x13c7a740), WTC(0x140329e0), WTC(0x143e1b60), WTC(0x147862a0), +WTC(0x14b1e840), WTC(0x14ea94c0), WTC(0x152250a0), WTC(0x15590380), WTC(0x158e93e0), WTC(0x15c2e820), WTC(0x15f5e6e0), WTC(0x162779a0), +WTC(0x16578ca0), WTC(0x16860ca0), WTC(0x16b2e640), WTC(0x16de0b00), WTC(0x17077140), WTC(0x172f0fa0), WTC(0x1754e200), WTC(0x17796080), +WTC(0x179d7f20), WTC(0x17c23760), WTC(0x17e87da0), WTC(0x1810cc80), WTC(0x183b25a0), WTC(0x18678520), WTC(0x1895e700), WTC(0x18c64540), +WTC(0x18f89780), WTC(0x192cd560), WTC(0x1962f680), WTC(0x199af2a0), WTC(0x19d4c1e0), WTC(0x1a105ca0), WTC(0x1a4dbae0), WTC(0x1a8cd660), +WTC(0x1acdaa60), WTC(0x1b103260), WTC(0x1b546940), WTC(0x1b9a4600), WTC(0x1be1bb80), WTC(0x1c2abc60), WTC(0x1c753b80), WTC(0x1cc13860), +WTC(0x1d0ebe20), WTC(0x1d5dd8c0), WTC(0x1dae9480), WTC(0x1e010060), WTC(0x1e552f40), WTC(0x1eab33e0), WTC(0x1f032060), WTC(0x1f5cfce0), +WTC(0x1fb8c660), WTC(0x201679c0), WTC(0x207611c0), WTC(0x20d75f00), WTC(0x213a0640), WTC(0x219dab80), WTC(0x2201f480), WTC(0x2266ba80), +WTC(0x22cc0ac0), WTC(0x2331f4c0), WTC(0x23988940), WTC(0x23ffff40), WTC(0x2468b340), WTC(0x24d30300), WTC(0x253f4900), WTC(0x25ad8980), +WTC(0x261d72c0), WTC(0x268eaec0), WTC(0x2700e880), WTC(0x2773db40), WTC(0x27e751c0), WTC(0x285b1780), WTC(0x28cefbc0), WTC(0x29431f80), +WTC(0x29b7f680), WTC(0x2a2df780), WTC(0x2aa59880), WTC(0x2b1f3280), WTC(0x2b9b0140), WTC(0x2c194000), WTC(0x2c9a2540), WTC(0x2d1d8dc0), +WTC(0x2da2fc40), WTC(0x2e29ee80), WTC(0x2eb1e340), WTC(0x2f3a4e40), WTC(0x2fc29980), WTC(0x304a2ec0), WTC(0x30d07cc0), WTC(0x315566c0), +WTC(0x31d94480), WTC(0x325c72c0), WTC(0x32df51c0), WTC(0x33628c80), WTC(0x33e71a00), WTC(0x346df400), WTC(0x34f80dc0), WTC(0x3585c640), +WTC(0x3616e700), WTC(0x36ab3380), WTC(0x37426ac0), WTC(0x37dbe840), WTC(0x3876a340), WTC(0x39118f40), WTC(0x39aba2c0), WTC(0x3a4422c0), +WTC(0x3adaa200), WTC(0x3b6eb6c0), WTC(0x3bfffd80), WTC(0x3c8e9380), WTC(0x3d1b1780), WTC(0x3da62e00), WTC(0x3e307b00), WTC(0x3eba97c0), +WTC(0x3f451280), WTC(0x3fd07940), WTC(0x405d577f), WTC(0x40ebf57f), WTC(0x417c59ff), WTC(0x420e897f), WTC(0x42a2857f), WTC(0x4338307f), +WTC(0x43cf4d7f), WTC(0x44679cff), WTC(0x4500dfff), WTC(0x459ac2ff), WTC(0x4634e2ff), WTC(0x46ced9ff), WTC(0x4768437f), WTC(0x4800d27f), +WTC(0x489850ff), WTC(0x492e88ff), WTC(0x49c346ff), WTC(0x4a5678ff), WTC(0x4ae82f7f), WTC(0x4b787c7f), WTC(0x4c07717f), WTC(0x4c95337f), +WTC(0x4d21f77f), WTC(0x4dadf3ff), WTC(0x4e395eff), WTC(0x4ec4657f), WTC(0x4f4f297f), WTC(0x4fd9cd7f), WTC(0x5064737f), WTC(0x50ef3cff), +WTC(0x517a46ff), WTC(0x5205b0ff), WTC(0x529197ff), WTC(0x531e04ff), WTC(0x53aaeb7f), WTC(0x54383eff), WTC(0x54c5ef7f), WTC(0x5553a8ff), +WTC(0x55e0d57f), WTC(0x566cda7f), WTC(0x56f720ff), WTC(0x577f4aff), WTC(0x580534ff), WTC(0x5888bd7f), WTC(0x5909c6ff), WTC(0x598890ff), +WTC(0x5a05b7ff), WTC(0x5a81db7f), WTC(0x5afd99ff), WTC(0x5b794a7f), WTC(0x5bf5007f), WTC(0x5c70cbff), WTC(0x5cecbb7f), WTC(0x5d68c47f), +WTC(0x5de4c3ff), WTC(0x5e6094ff), WTC(0x5edc127f), WTC(0x5f56fdff), WTC(0x5fd1017f), WTC(0x6049c67f), WTC(0x60c0f67f), WTC(0x613650ff), +WTC(0x61a9a9ff), WTC(0x621ad77f), WTC(0x6289b37f), WTC(0x62f67fff), WTC(0x6361e87f), WTC(0x63cc9bff), WTC(0x6437457f), WTC(0x64a2247f), +WTC(0x650d0c7f), WTC(0x6577cc7f), WTC(0x65e2327f), WTC(0x664bf57f), WTC(0x66b4b5ff), WTC(0x671c137f), WTC(0x6781afff), WTC(0x67e579ff), +WTC(0x6847abff), WTC(0x68a882ff), WTC(0x69083bff), WTC(0x6966fbff), WTC(0x69c4cfff), WTC(0x6a21c57f), WTC(0x6a7de87f), WTC(0x6ad9377f), +WTC(0x6b33a5ff), WTC(0x6b8d257f), WTC(0x6be5a8ff), WTC(0x6c3d20ff), WTC(0x6c9380ff), WTC(0x6ce8ba7f), WTC(0x6d3cbfff), WTC(0x6d8f827f), +/* part 2 */ +WTC(0xad98b481), WTC(0xaead9d01), WTC(0xafbfc381), WTC(0xb0cf4d01), WTC(0xb1dc5f81), WTC(0xb2e72081), WTC(0xb3efb501), WTC(0xb4f64381), +WTC(0xb5faf101), WTC(0xb6fde401), WTC(0xb7ff4001), WTC(0xb8ff1601), WTC(0xb9fd6181), WTC(0xbafa1d01), WTC(0xbbf54401), WTC(0xbceed101), +WTC(0xbde6c081), WTC(0xbedd0e81), WTC(0xbfd1b701), WTC(0xc0c4b440), WTC(0xc1b5ffc0), WTC(0xc2a59340), WTC(0xc3936780), WTC(0xc47f78c0), +WTC(0xc569c600), WTC(0xc6524d40), WTC(0xc7390dc0), WTC(0xc81e04c0), WTC(0xc9012e00), WTC(0xc9e28540), WTC(0xcac20700), WTC(0xcb9fb1c0), +WTC(0xcc7b8640), WTC(0xcd558600), WTC(0xce2db200), WTC(0xcf0409c0), WTC(0xcfd88a40), WTC(0xd0ab3080), WTC(0xd17bfa00), WTC(0xd24ae640), +WTC(0xd317f7c0), WTC(0xd3e33080), WTC(0xd4ac9340), WTC(0xd5741f40), WTC(0xd639d2c0), WTC(0xd6fdab00), WTC(0xd7bfa5c0), WTC(0xd87fc300), +WTC(0xd93e0600), WTC(0xd9fa7180), WTC(0xdab50900), WTC(0xdb6dccc0), WTC(0xdc24ba80), WTC(0xdcd9d000), WTC(0xdd8d0b80), WTC(0xde3e6dc0), +WTC(0xdeedf9c0), WTC(0xdf9bb340), WTC(0xe0479e20), WTC(0xe0f1bac0), WTC(0xe19a07e0), WTC(0xe2408380), WTC(0xe2e52c00), WTC(0xe38802e0), +WTC(0xe4290c00), WTC(0xe4c84c20), WTC(0xe565c760), WTC(0xe6017f20), WTC(0xe69b7240), WTC(0xe7339f60), WTC(0xe7ca0500), WTC(0xe85ea480), +WTC(0xe8f18180), WTC(0xe9829fc0), WTC(0xea1202e0), WTC(0xea9fab80), WTC(0xeb2b9700), WTC(0xebb5c2a0), WTC(0xec3e2bc0), WTC(0xecc4d300), +WTC(0xed49bc80), WTC(0xedccec60), WTC(0xee4e66a0), WTC(0xeece2d80), WTC(0xef4c41e0), WTC(0xefc8a480), WTC(0xf0435610), WTC(0xf0bc5c60), +WTC(0xf133c230), WTC(0xf1a99270), WTC(0xf21dd7b0), WTC(0xf29097e0), WTC(0xf301d3d0), WTC(0xf3718c20), WTC(0xf3dfc180), WTC(0xf44c7100), +WTC(0xf4b79480), WTC(0xf52125b0), WTC(0xf5891df0), WTC(0xf5ef6fe0), WTC(0xf6540730), WTC(0xf6b6cf50), WTC(0xf717b490), WTC(0xf776b9a0), +WTC(0xf7d3f720), WTC(0xf82f86e8), WTC(0xf8898260), WTC(0xf8e1fc50), WTC(0xf93900f0), WTC(0xf98e9c28), WTC(0xf9e2d940), WTC(0xfa35b4a0), +WTC(0xfa871bd8), WTC(0xfad6fbd0), WTC(0xfb254250), WTC(0xfb71f0c0), WTC(0xfbbd1c28), WTC(0xfc06da60), WTC(0xfc4f40a4), WTC(0xfc965500), +WTC(0xfcdc0e5c), WTC(0xfd2062f4), WTC(0xfd6348d0), WTC(0xfda4b1b8), WTC(0xfde48b2c), WTC(0xfe22c280), WTC(0xfe5f462a), WTC(0xfe9a1f2e), +WTC(0xfed3711c), WTC(0xff0b60ac), WTC(0xff4212dd), WTC(0xff77b344), WTC(0xffac7407), WTC(0xffe08796), WTC(0x00141e37), WTC(0x00473665), +WTC(0x00799cd0), WTC(0x00ab1bff), WTC(0x00db7d8b), WTC(0x010a75ea), WTC(0x0137a46e), WTC(0x0162a77a), WTC(0x018b20ac), WTC(0x01b0fb7a), +WTC(0x01d46d3c), WTC(0x01f5ae7c), WTC(0x0214f91c), WTC(0x0232a5cc), WTC(0x024f2c04), WTC(0x026b048c), WTC(0x0286a628), WTC(0x02a25808), +WTC(0x02be31c0), WTC(0x02da48e0), WTC(0x02f6b09c), WTC(0x031345dc), WTC(0x032faf50), WTC(0x034b9148), WTC(0x036690e8), WTC(0x0380658c), +WTC(0x0398d8e4), WTC(0x03afb568), WTC(0x03c4c6e0), WTC(0x03d7f770), WTC(0x03e94f9c), WTC(0x03f8d938), WTC(0x04069ee8), WTC(0x0412bef8), +WTC(0x041d6b30), WTC(0x0426d638), WTC(0x042f3288), WTC(0x0436ad98), WTC(0x043d6fd0), WTC(0x0443a170), WTC(0x04496a40), WTC(0x044ee728), +WTC(0x04542a40), WTC(0x04594520), WTC(0x045e4890), WTC(0x04633210), WTC(0x0467ebe8), WTC(0x046c5f80), WTC(0x04707630), WTC(0x047417f0), +WTC(0x04772b58), WTC(0x047996e8), WTC(0x047b4140), WTC(0x047c12a0), WTC(0x047bf520), WTC(0x047ad2e0), WTC(0x04789690), WTC(0x047539c8), +WTC(0x0470c4b8), WTC(0x046b4058), WTC(0x0464b600), WTC(0x045d3a08), WTC(0x0454ebc8), WTC(0x044beb00), WTC(0x04425798), WTC(0x043853b0), +WTC(0x042e0398), WTC(0x04238bd8), WTC(0x04190f98), WTC(0x040e9670), WTC(0x04040c18), WTC(0x03f95b30), WTC(0x03ee6e20), WTC(0x03e32b64), +WTC(0x03d77598), WTC(0x03cb2f24), WTC(0x03be3b18), WTC(0x03b08b18), WTC(0x03a21f64), WTC(0x0392f8d4), WTC(0x038318e0), WTC(0x03728e94), +WTC(0x03617694), WTC(0x034fee18), WTC(0x033e11f4), WTC(0x032bf530), WTC(0x0319a114), WTC(0x03071e80), WTC(0x02f475f4), WTC(0x02e1a7c0), +WTC(0x02ceac04), WTC(0x02bb7a84), WTC(0x02a80af0), WTC(0x029452b0), WTC(0x028044e0), WTC(0x026bd488), WTC(0x0256f558), WTC(0x0241a940), +WTC(0x022c0084), WTC(0x02160c08), WTC(0x01ffdc5a), WTC(0x01e97ad2), WTC(0x01d2e982), WTC(0x01bc2a2a), WTC(0x01a53e8c), WTC(0x018e2860), +WTC(0x0176e94c), WTC(0x015f82fa), WTC(0x0147f70e), WTC(0x013046c2), WTC(0x011872e8), WTC(0x01007c4a), WTC(0x00e863cf), WTC(0x00d02c81), +WTC(0x00b7db94), WTC(0x009f7651), WTC(0x00870204), WTC(0x006e83f8), WTC(0x00560176), WTC(0x003d7fcb), WTC(0x0025043f), WTC(0x000c941f), +WTC(0xd65574c0), WTC(0xd5ebc100), WTC(0xd582d080), WTC(0xd51a9cc0), WTC(0xd4b31f80), WTC(0xd44c5280), WTC(0xd3e62f80), WTC(0xd380b040), +WTC(0xd31bce40), WTC(0xd2b78380), WTC(0xd253ca40), WTC(0xd1f0acc0), WTC(0xd18e4580), WTC(0xd12caf40), WTC(0xd0cc0400), WTC(0xd06c40c0), +WTC(0xd00d4740), WTC(0xcfaef6c0), WTC(0xcf513140), WTC(0xcef3fa80), WTC(0xce977a40), WTC(0xce3bd980), WTC(0xcde13f40), WTC(0xcd87a880), +WTC(0xcd2ee800), WTC(0xccd6cf00), WTC(0xcc7f2f40), WTC(0xcc27e880), WTC(0xcbd0ea00), WTC(0xcb7a2380), WTC(0xcb238380), WTC(0xcaccee80), +WTC(0xca763ec0), WTC(0xca1f4d00), WTC(0xc9c7f480), WTC(0xc9703b40), WTC(0xc9185200), WTC(0xc8c06b00), WTC(0xc868b4c0), WTC(0xc81100c0), +WTC(0xc7b8c280), WTC(0xc75f6a40), WTC(0xc7046900), WTC(0xc6a74340), WTC(0xc6479300), WTC(0xc5e4f200), WTC(0xc57efac0), WTC(0xc5154880), +WTC(0xc4a77780), WTC(0xc4352440), WTC(0xc3bdeac0), WTC(0xc3416740), WTC(0xc2bf33c0), WTC(0xc236eb40), WTC(0xc1a82900), WTC(0xc11290c0), +WTC(0xc075cf00), WTC(0xbfd19081), WTC(0xbf258401), WTC(0xbe716d81), WTC(0xbdb52b81), WTC(0xbcf09a81), WTC(0xbc23af81), WTC(0xbb505c01), +WTC(0xba7a9081), WTC(0xb9a65281), WTC(0xb8d79301), WTC(0xb8104c01), WTC(0xb7508181), WTC(0xb6982201), WTC(0xb5e71b01), WTC(0xb53d5b01), +WTC(0xb49ad081), WTC(0xb3ff6901), WTC(0xb36b1301), WTC(0xb2ddbd01), WTC(0xb2575481), WTC(0xb1d7c801), WTC(0xb15f0601), WTC(0xb0ecfc01), +WTC(0xb0819881), WTC(0xb01cca01), WTC(0xafbe7e01), WTC(0xaf66a301), WTC(0xaf152701), WTC(0xaec9f881), WTC(0xae850601), WTC(0xae463c81), +WTC(0xae0d8b01), WTC(0xaddae001), WTC(0xadae2881), WTC(0xad875381), WTC(0xad664f81), WTC(0xad4b0981), WTC(0xad357081), WTC(0xad257301), +WTC(0xad1afe01), WTC(0xad160081), WTC(0xad166901), WTC(0xad1c2481), WTC(0xad272201), WTC(0xad374f81), WTC(0xad4c9b01), WTC(0xad66f381), +WTC(0xad864601), WTC(0xadaa8101), WTC(0xadd39301), WTC(0xae016a01), WTC(0xae33f481), WTC(0xae6b2001), WTC(0xaea6db01), WTC(0xaee71381), +WTC(0xaf2bb801), WTC(0xaf74b681), WTC(0xafc1fd01), WTC(0xb0137a01), WTC(0xb0691b81), WTC(0xb0c2cf81), WTC(0xb1208481), WTC(0xb1822881), +WTC(0xb1e7a981), WTC(0xb250f601), WTC(0xb2bdfc01), WTC(0xb32eaa01), WTC(0xb3a2ed01), WTC(0xb41ab481), WTC(0xb495ee01), WTC(0xb5148801), +WTC(0xb5967081), WTC(0xb61b9581), WTC(0xb6a3e581), WTC(0xb72f4e01), WTC(0xb7bdbe01), WTC(0xb84f2381), WTC(0xb8e36c81), WTC(0xb97a8701), +WTC(0xba146101), WTC(0xbab0e981), WTC(0xbb500d81), WTC(0xbbf1bc81), WTC(0xbc95e381), WTC(0xbd3c7181), WTC(0xbde55481), WTC(0xbe907a01), +WTC(0xbf3dd101), WTC(0xbfed4701), WTC(0xc09ecac0), WTC(0xc1524a00), WTC(0xc207b300), WTC(0xc2bef440), WTC(0xc377fb80), WTC(0xc432b700), +WTC(0xc4ef1500), WTC(0xc5ad03c0), WTC(0xc66c7140), WTC(0xc72d4bc0), WTC(0xc7ef8180), WTC(0xc8b30080), WTC(0xc977b700), WTC(0xca3d9340), +WTC(0xcb048340), WTC(0xcbcc7540), WTC(0xcc955740), WTC(0xcd5f17c0), WTC(0xce29a480), WTC(0xcef4ec00), WTC(0xcfc0dc80), WTC(0xd08d63c0), +WTC(0xd15a7040), WTC(0xd227f000), WTC(0xd2f5d140), WTC(0xd3c40240), WTC(0xd4927100), WTC(0xd5610b80), WTC(0xd62fc080), WTC(0xd6fe7dc0), +WTC(0xd7cd3140), WTC(0xd89bc980), WTC(0xd96a34c0), WTC(0xda3860c0), WTC(0xdb063c00), WTC(0xdbd3b480), WTC(0xdca0b880), WTC(0xdd6d3640), +WTC(0xde391bc0), WTC(0xdf045740), WTC(0xdfced6c0), WTC(0xe09888c0), WTC(0xe1615b20), WTC(0xe2293c20), WTC(0xe2f01a00), WTC(0xe3b5e2c0), +WTC(0xe47a84c0), WTC(0xe53dee00), WTC(0xe6000cc0), WTC(0xe6c0cf20), WTC(0xe7802360), WTC(0xe83df7a0), WTC(0xe8fa39e0), WTC(0xe9b4d880), +WTC(0xea6dc1a0), WTC(0xeb24e360), WTC(0xebda2be0), WTC(0xec8d8960), WTC(0xed3eea20), WTC(0xedee3c00), WTC(0xee9b6d80), WTC(0xef466ca0), +WTC(0xefef2780), WTC(0xf0958c50), WTC(0xf1398950), WTC(0xf1db0ca0), WTC(0xf27a0470), WTC(0xf3165ed0), WTC(0xf3b00a10), WTC(0xf446f440), +WTC(0xf4db0b90), WTC(0xf56c3e30), WTC(0xf5fa7a50), WTC(0xf685ae10), WTC(0xf70dc7a0), WTC(0xf792b520), WTC(0xf81464c8), WTC(0xf892c4c0), +WTC(0xf90dc330), WTC(0xf9854e40), WTC(0xf9f95418), WTC(0xfa69c2f0), WTC(0xfad688e8), WTC(0xfb3f9428), WTC(0xfba4d2e8), WTC(0xfc063344), +WTC(0xfc63a370), WTC(0xfcbd1194), WTC(0xfd126bdc), WTC(0xfd63a06c), WTC(0xfdb09d78), WTC(0xfdf95124), WTC(0xfe3da99e), WTC(0xfe7d950e), +WTC(0xfeb901a2), WTC(0xfeefdd80), WTC(0xff2216d7), WTC(0xff4f9bcf), WTC(0xff785a93), WTC(0xff9c414e), WTC(0xffbb3e2b), WTC(0xffd53f54), +WTC(0xffea32f4), WTC(0xfffa0735), WTC(0x0004aa43), WTC(0x000a0a47), WTC(0x000a156c), WTC(0x0004b9de), WTC(0xfff9e5c5), WTC(0xffe9874e) +}; + + +const FIXP_WTB LowDelaySynthesis480[1440] = { + +WTC(0xdad2e6c0), WTC(0xdb1da900), WTC(0xdb68ce40), WTC(0xdbb45840), WTC(0xdc004940), WTC(0xdc4ca280), WTC(0xdc996500), WTC(0xdce69140), +WTC(0xdd342780), WTC(0xdd822700), WTC(0xddd08a80), WTC(0xde1f4d00), WTC(0xde6e6ec0), WTC(0xdebdec40), WTC(0xdf0dba80), WTC(0xdf5dd540), +WTC(0xdfae3cc0), WTC(0xdfff0500), WTC(0xe0505140), WTC(0xe0a22980), WTC(0xe0f488e0), WTC(0xe1476180), WTC(0xe19aa480), WTC(0xe1ee4d80), +WTC(0xe2425400), WTC(0xe29689a0), WTC(0xe2eacd60), WTC(0xe33f2420), WTC(0xe393a300), WTC(0xe3e87f20), WTC(0xe43dcee0), WTC(0xe4938a80), +WTC(0xe4e9b0a0), WTC(0xe5404300), WTC(0xe5973e60), WTC(0xe5ee9b80), WTC(0xe64649e0), WTC(0xe69e37e0), WTC(0xe6f65ec0), WTC(0xe74eb6c0), +WTC(0xe7a73000), WTC(0xe7ffbe40), WTC(0xe8585ee0), WTC(0xe8b10740), WTC(0xe9099c40), WTC(0xe96214e0), WTC(0xe9ba79a0), WTC(0xea12e7c0), +WTC(0xea6b89c0), WTC(0xeac46580), WTC(0xeb1d7260), WTC(0xeb76b620), WTC(0xebd036c0), WTC(0xec29e520), WTC(0xec83aa60), WTC(0xecdd5a00), +WTC(0xed36d500), WTC(0xed901540), WTC(0xede91160), WTC(0xee41bc20), WTC(0xee9a0ee0), WTC(0xeef20860), WTC(0xef49a7e0), WTC(0xefa0ec00), +WTC(0xeff7d1c0), WTC(0xf04e56b0), WTC(0xf0a476e0), WTC(0xf0fa2f60), WTC(0xf14f80e0), WTC(0xf1a46e10), WTC(0xf1f8fe80), WTC(0xf24d34a0), +WTC(0xf2a10bb0), WTC(0xf2f48210), WTC(0xf3479cc0), WTC(0xf39a5be0), WTC(0xf3ecb8f0), WTC(0xf43eafa0), WTC(0xf4903b50), WTC(0xf4e14e80), +WTC(0xf531d6a0), WTC(0xf581bc10), WTC(0xf5d0e9c0), WTC(0xf61f5250), WTC(0xf66ce6e0), WTC(0xf6b99330), WTC(0xf7054eb0), WTC(0xf7501f20), +WTC(0xf79a0750), WTC(0xf7e30700), WTC(0xf82b2fc0), WTC(0xf872a138), WTC(0xf8b97f18), WTC(0xf8ffe668), WTC(0xf945e538), WTC(0xf98b8860), +WTC(0xf9d0f380), WTC(0xfa165148), WTC(0xfa5bb8a8), WTC(0xfaa13df8), WTC(0xfae6fb00), WTC(0xfb2cf8c8), WTC(0xfb732a80), WTC(0xfbb97910), +WTC(0xfbffcd10), WTC(0xfc463478), WTC(0xfc8cd3fc), WTC(0xfcd3be5c), WTC(0xfd1afa90), WTC(0xfd62aa84), WTC(0xfdab0288), WTC(0xfdf404b4), +WTC(0xfe3d3006), WTC(0xfe85b20e), WTC(0xfecca4cc), WTC(0xff10d559), WTC(0xff50579b), WTC(0xff8a40d2), WTC(0xffb7d86e), WTC(0xffef6bbb), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), WTC(0x00000000), +WTC(0xbff67a01), WTC(0xbfecaa81), WTC(0xbfe2d901), WTC(0xbfd90601), WTC(0xbfcf3181), WTC(0xbfc55c81), WTC(0xbfbb8701), WTC(0xbfb1b101), +WTC(0xbfa7dc01), WTC(0xbf9e0701), WTC(0xbf943301), WTC(0xbf8a5f81), WTC(0xbf808b81), WTC(0xbf76b701), WTC(0xbf6ce201), WTC(0xbf630d81), +WTC(0xbf593a01), WTC(0xbf4f6801), WTC(0xbf459681), WTC(0xbf3bc601), WTC(0xbf31f501), WTC(0xbf282501), WTC(0xbf1e5501), WTC(0xbf148681), +WTC(0xbf0aba01), WTC(0xbf00ef81), WTC(0xbef72681), WTC(0xbeed5f01), WTC(0xbee39801), WTC(0xbed9d281), WTC(0xbed00f81), WTC(0xbec64e81), +WTC(0xbebc9181), WTC(0xbeb2d681), WTC(0xbea91f01), WTC(0xbe9f6901), WTC(0xbe95b581), WTC(0xbe8c0501), WTC(0xbe825801), WTC(0xbe78b001), +WTC(0xbe6f0c01), WTC(0xbe656c01), WTC(0xbe5bd001), WTC(0xbe523781), WTC(0xbe48a301), WTC(0xbe3f1381), WTC(0xbe358901), WTC(0xbe2c0501), +WTC(0xbe228681), WTC(0xbe190d81), WTC(0xbe0f9a01), WTC(0xbe062b81), WTC(0xbdfcc301), WTC(0xbdf36101), WTC(0xbdea0681), WTC(0xbde0b301), +WTC(0xbdd76701), WTC(0xbdce2181), WTC(0xbdc4e301), WTC(0xbdbbab01), WTC(0xbdb27b01), WTC(0xbda95301), WTC(0xbda03381), WTC(0xbd971c81), +WTC(0xbd8e0e01), WTC(0xbd850701), WTC(0xbd7c0781), WTC(0xbd731081), WTC(0xbd6a2201), WTC(0xbd613d81), WTC(0xbd586281), WTC(0xbd4f9101), +WTC(0xbd46c801), WTC(0xbd3e0801), WTC(0xbd355081), WTC(0xbd2ca281), WTC(0xbd23ff01), WTC(0xbd1b6501), WTC(0xbd12d581), WTC(0xbd0a4f81), +WTC(0xbd01d281), WTC(0xbcf95e81), WTC(0xbcf0f381), WTC(0xbce89281), WTC(0xbce03b81), WTC(0xbcd7ef01), WTC(0xbccfac01), WTC(0xbcc77181), +WTC(0xbcbf4001), WTC(0xbcb71701), WTC(0xbcaef701), WTC(0xbca6e101), WTC(0xbc9ed481), WTC(0xbc96d101), WTC(0xbc8ed701), WTC(0xbc86e581), +WTC(0xbc7efc81), WTC(0xbc771c01), WTC(0xbc6f4401), WTC(0xbc677501), WTC(0xbc5fae81), WTC(0xbc57f101), WTC(0xbc503b81), WTC(0xbc488e81), +WTC(0xbc40e881), WTC(0xbc394901), WTC(0xbc31af01), WTC(0xbc2a1a81), WTC(0xbc228f01), WTC(0xbc1b1081), WTC(0xbc13a481), WTC(0xbc0c4581), +WTC(0xbc04e381), WTC(0xbbfd6c01), WTC(0xbbf5d181), WTC(0xbbee2f81), WTC(0xbbe6c801), WTC(0xbbdfdb81), WTC(0xbbd9a781), WTC(0xbbd45881), +WTC(0xbbd01301), WTC(0xbbccfc81), WTC(0xbbcb2281), WTC(0xbbca5d01), WTC(0xbbca7481), WTC(0xbbcb3201), WTC(0xbbcc6b01), WTC(0xbbce0601), +WTC(0xbbcfea81), WTC(0xbbd20301), WTC(0xbbd45601), WTC(0xbbd70201), WTC(0xbbda2501), WTC(0xbbdddb01), WTC(0xbbe23281), WTC(0xbbe73201), +WTC(0xbbece281), WTC(0xbbf34281), WTC(0xbbfa3c01), WTC(0xbc01b381), WTC(0xbc098d81), WTC(0xbc11b681), WTC(0xbc1a2401), WTC(0xbc22cd81), +WTC(0xbc2bab01), WTC(0xbc34c081), WTC(0xbc3e1981), WTC(0xbc47c281), WTC(0xbc51cb01), WTC(0xbc5c4c81), WTC(0xbc676501), WTC(0xbc733401), +WTC(0xbc7fd301), WTC(0xbc8d5101), WTC(0xbc9bb901), WTC(0xbcab1781), WTC(0xbcbb7001), WTC(0xbcccbd01), WTC(0xbcdef701), WTC(0xbcf21601), +WTC(0xbd060c81), WTC(0xbd1ac801), WTC(0xbd303581), WTC(0xbd464281), WTC(0xbd5ce281), WTC(0xbd740b81), WTC(0xbd8bb281), WTC(0xbda3d081), +WTC(0xbdbc6381), WTC(0xbdd56b81), WTC(0xbdeee981), WTC(0xbe08e181), WTC(0xbe236001), WTC(0xbe3e7201), WTC(0xbe5a2301), WTC(0xbe767e81), +WTC(0xbe938c81), WTC(0xbeb15701), WTC(0xbecfe601), WTC(0xbeef4601), WTC(0xbf0f8301), WTC(0xbf30a901), WTC(0xbf52c101), WTC(0xbf75cc81), +WTC(0xbf99cb01), WTC(0xbfbebb81), WTC(0xbfe48981), WTC(0xc00b04c0), WTC(0xc031f880), WTC(0xc0593340), WTC(0xc0809280), WTC(0xc0a802c0), +WTC(0xc0cf6ec0), WTC(0xc0f6cc00), WTC(0xc11e3a80), WTC(0xc145f040), WTC(0xc16e22c0), WTC(0xc196fb00), WTC(0xc1c08680), WTC(0xc1eaca00), +WTC(0xc215cbc0), WTC(0xc2418940), WTC(0xc26df5c0), WTC(0xc29b02c0), WTC(0xc2c8a140), WTC(0xc2f6b500), WTC(0xc3251740), WTC(0xc353a0c0), +WTC(0xc3822c00), WTC(0xc3b09940), WTC(0xc3deccc0), WTC(0xc40ca800), WTC(0xc43a28c0), WTC(0xc4678a00), WTC(0xc4951780), WTC(0xc4c31d00), +WTC(0xc4f1bdc0), WTC(0xc520e840), WTC(0xc5508440), WTC(0xc5807900), WTC(0xc5b09e80), WTC(0xc5e0bfc0), WTC(0xc610a740), WTC(0xc64029c0), +WTC(0xc66f49c0), WTC(0xc69e2180), WTC(0xc6ccca40), WTC(0xc6fb5700), WTC(0xc729cc80), WTC(0xc7582b40), WTC(0xc7867480), WTC(0xc7b4a480), +WTC(0xc7e2afc0), WTC(0xc8108a80), WTC(0xc83e28c0), WTC(0xc86b7f00), WTC(0xc8988100), WTC(0xc8c52340), WTC(0xc8f15980), WTC(0xc91d1840), +WTC(0xb4d6a381), WTC(0xb4422b81), WTC(0xb3ae8601), WTC(0xb31bb301), WTC(0xb289b181), WTC(0xb1f88181), WTC(0xb1682281), WTC(0xb0d89401), +WTC(0xb049d601), WTC(0xafbbe801), WTC(0xaf2ec901), WTC(0xaea27681), WTC(0xae16f001), WTC(0xad8c3301), WTC(0xad023f01), WTC(0xac791401), +WTC(0xabf0b181), WTC(0xab691681), WTC(0xaae24301), WTC(0xaa5c3601), WTC(0xa9d6ef01), WTC(0xa9526d81), WTC(0xa8ceb201), WTC(0xa84bbb81), +WTC(0xa7c98b01), WTC(0xa7482101), WTC(0xa6c77e01), WTC(0xa647a301), WTC(0xa5c89001), WTC(0xa54a4701), WTC(0xa4ccc901), WTC(0xa4501601), +WTC(0xa3d43001), WTC(0xa3591801), WTC(0xa2dece81), WTC(0xa2655581), WTC(0xa1ecae01), WTC(0xa174da81), WTC(0xa0fddd81), WTC(0xa087b981), +WTC(0xa0127081), WTC(0x9f9e0301), WTC(0x9f2a7281), WTC(0x9eb7c101), WTC(0x9e45f081), WTC(0x9dd50481), WTC(0x9d650081), WTC(0x9cf5e701), +WTC(0x9c87ba81), WTC(0x9c1a7c81), WTC(0x9bae2f81), WTC(0x9b42d581), WTC(0x9ad87081), WTC(0x9a6f0381), WTC(0x9a069001), WTC(0x999f1981), +WTC(0x9938a281), WTC(0x98d32d81), WTC(0x986ebd81), WTC(0x980b5501), WTC(0x97a8f681), WTC(0x9747a481), WTC(0x96e76101), WTC(0x96882e01), +WTC(0x962a0c81), WTC(0x95ccff01), WTC(0x95710601), WTC(0x95162381), WTC(0x94bc5981), WTC(0x9463a881), WTC(0x940c1281), WTC(0x93b59901), +WTC(0x93603d01), WTC(0x930bff81), WTC(0x92b8e101), WTC(0x9266e281), WTC(0x92160301), WTC(0x91c64301), WTC(0x9177a301), WTC(0x912a2201), +WTC(0x90ddc001), WTC(0x90927b81), WTC(0x90485401), WTC(0x8fff4601), WTC(0x8fb74f81), WTC(0x8f706f01), WTC(0x8f2aa101), WTC(0x8ee5e301), +WTC(0x8ea23201), WTC(0x8e5f8881), WTC(0x8e1de001), WTC(0x8ddd3201), WTC(0x8d9d7781), WTC(0x8d5eaa01), WTC(0x8d20c301), WTC(0x8ce3ba81), +WTC(0x8ca78781), WTC(0x8c6c1b01), WTC(0x8c316681), WTC(0x8bf75b01), WTC(0x8bbde981), WTC(0x8b850281), WTC(0x8b4c9701), WTC(0x8b149701), +WTC(0x8adcee01), WTC(0x8aa58681), WTC(0x8a6e4a01), WTC(0x8a372881), WTC(0x8a001f01), WTC(0x89c92f81), WTC(0x89925a81), WTC(0x895bcd01), +WTC(0x8925f101), WTC(0x88f13801), WTC(0x88be1681), WTC(0x888d3181), WTC(0x885f8481), WTC(0x88353501), WTC(0x88124281), WTC(0x87e73d81), +WTC(0x87d4ac81), WTC(0x87cb5101), WTC(0x87c05e81), WTC(0x87b42481), WTC(0x87a70e81), WTC(0x87998f01), WTC(0x878c1881), WTC(0x877ede01), +WTC(0x8771c601), WTC(0x8764b101), WTC(0x87578181), WTC(0x874a2f01), WTC(0x873cc201), WTC(0x872f4201), WTC(0x8721b481), WTC(0x87141b01), +WTC(0x87067281), WTC(0x86f8ba81), WTC(0x86eaf081), WTC(0x86dd1481), WTC(0x86cf2601), WTC(0x86c12401), WTC(0x86b30f01), WTC(0x86a4e781), +WTC(0x8696ad01), WTC(0x86886001), WTC(0x867a0081), WTC(0x866b8d81), WTC(0x865d0581), WTC(0x864e6901), WTC(0x863fb701), WTC(0x8630f181), +WTC(0x86221801), WTC(0x86132c01), WTC(0x86042c01), WTC(0x85f51681), WTC(0x85e5eb81), WTC(0x85d6a981), WTC(0x85c75201), WTC(0x85b7e601), +WTC(0x85a86581), WTC(0x8598d081), WTC(0x85892681), WTC(0x85796601), WTC(0x85698e81), WTC(0x8559a081), WTC(0x85499d01), WTC(0x85398481), +WTC(0x85295881), WTC(0x85191801), WTC(0x8508c181), WTC(0x84f85581), WTC(0x84e7d381), WTC(0x84d73c01), WTC(0x84c69101), WTC(0x84b5d301), +WTC(0x84a50201), WTC(0x84941d81), WTC(0x84832481), WTC(0x84721701), WTC(0x8460f581), WTC(0x844fc081), WTC(0x843e7a81), WTC(0x842d2281), +WTC(0x841bb981), WTC(0x840a3e81), WTC(0x83f8b001), WTC(0x83e70f01), WTC(0x83d55d01), WTC(0x83c39a81), WTC(0x83b1c881), WTC(0x839fe801), +WTC(0x838df801), WTC(0x837bf801), WTC(0x8369e781), WTC(0x8357c701), WTC(0x83459881), WTC(0x83335c81), WTC(0x83211501), WTC(0x830ec081), +WTC(0x82fc5f01), WTC(0x82e9ef01), WTC(0x82d77201), WTC(0x82c4e801), WTC(0x82b25301), WTC(0x829fb401), WTC(0x828d0b01), WTC(0x827a5801), +WTC(0x82679901), WTC(0x8254cf01), WTC(0x8241fa01), WTC(0x822f1b01), WTC(0x821c3401), WTC(0x82094581), WTC(0x81f64f01), WTC(0x81e34f81), +WTC(0x81d04681), WTC(0x81bd3401), WTC(0x81aa1981), WTC(0x8196f781), WTC(0x8183cf81), WTC(0x8170a181), WTC(0x815d6c01), WTC(0x814a2f81), +WTC(0x8136ea01), WTC(0x81239d81), WTC(0x81104a01), WTC(0x80fcf181), WTC(0x80e99401), WTC(0x80d63101), WTC(0x80c2c781), WTC(0x80af5701), +WTC(0x809bdf01), WTC(0x80886081), WTC(0x8074dc01), WTC(0x80615281), WTC(0x804dc481), WTC(0x803a3381), WTC(0x80269f81), WTC(0x80130981), +WTC(0x0a608220), WTC(0x0a8ee7d0), WTC(0x0abe35c0), WTC(0x0aee5de0), WTC(0x0b1f5230), WTC(0x0b5104a0), WTC(0x0b836720), WTC(0x0bb66bb0), +WTC(0x0bea0440), WTC(0x0c1e22c0), WTC(0x0c52ba70), WTC(0x0c87ca90), WTC(0x0cbd5ba0), WTC(0x0cf375e0), WTC(0x0d2a1f50), WTC(0x0d615480), +WTC(0x0d990e40), WTC(0x0dd14500), WTC(0x0e09f730), WTC(0x0e432e90), WTC(0x0e7cf790), WTC(0x0eb75e50), WTC(0x0ef26430), WTC(0x0f2dfd70), +WTC(0x0f6a1d70), WTC(0x0fa6b7e0), WTC(0x0fe3c3d0), WTC(0x10213ac0), WTC(0x105f1640), WTC(0x109d4f20), WTC(0x10dbdb80), WTC(0x111ab0c0), +WTC(0x1159c360), WTC(0x11990fc0), WTC(0x11d8a060), WTC(0x121882c0), WTC(0x1258c480), WTC(0x12995a40), WTC(0x12da1b00), WTC(0x131adb60), +WTC(0x135b70c0), WTC(0x139bb680), WTC(0x13db8c00), WTC(0x141ad080), WTC(0x14596460), WTC(0x149729e0), WTC(0x14d404e0), WTC(0x150fd8e0), +WTC(0x154a88c0), WTC(0x1583f5e0), WTC(0x15bc0120), WTC(0x15f28ba0), WTC(0x162779a0), WTC(0x165ab300), WTC(0x168c2040), WTC(0x16bbaa80), +WTC(0x16e94120), WTC(0x1714d9e0), WTC(0x173e6440), WTC(0x17660680), WTC(0x178ca020), WTC(0x17b36400), WTC(0x17db84e0), WTC(0x1805d920), +WTC(0x18328400), WTC(0x18617cc0), WTC(0x1892bfa0), WTC(0x18c64540), WTC(0x18fc0400), WTC(0x1933f140), WTC(0x196e0320), WTC(0x19aa2fc0), +WTC(0x19e86d80), WTC(0x1a28b2e0), WTC(0x1a6af700), WTC(0x1aaf3320), WTC(0x1af56180), WTC(0x1b3d7ce0), WTC(0x1b877c40), WTC(0x1bd350c0), +WTC(0x1c20ea40), WTC(0x1c703840), WTC(0x1cc13860), WTC(0x1d13f760), WTC(0x1d688420), WTC(0x1dbeed40), WTC(0x1e174660), WTC(0x1e71a640), +WTC(0x1ece2400), WTC(0x1f2cd220), WTC(0x1f8db3c0), WTC(0x1ff0c3e0), WTC(0x20560080), WTC(0x20bd46c0), WTC(0x21263400), WTC(0x21905740), +WTC(0x21fb4100), WTC(0x2266ba80), WTC(0x22d2d140), WTC(0x233f9780), WTC(0x23ad25c0), WTC(0x241bc800), WTC(0x248bf040), WTC(0x24fe1380), +WTC(0x25728180), WTC(0x25e90a00), WTC(0x26614080), WTC(0x26dabdc0), WTC(0x27552540), WTC(0x27d03200), WTC(0x284ba580), WTC(0x28c740c0), +WTC(0x29431f80), WTC(0x29bfc9c0), WTC(0x2a3dd080), WTC(0x2abdc000), WTC(0x2b3ffd00), WTC(0x2bc4cd80), WTC(0x2c4c7d40), WTC(0x2cd72ec0), +WTC(0x2d647f80), WTC(0x2df3cd80), WTC(0x2e847d80), WTC(0x2f15ea40), WTC(0x2fa760c0), WTC(0x30382b80), WTC(0x30c79440), WTC(0x315566c0), +WTC(0x31e20800), WTC(0x326de7c0), WTC(0x32f98200), WTC(0x3385ba00), WTC(0x3413bec0), WTC(0x34a4c480), WTC(0x3539bf00), WTC(0x35d2c4c0), +WTC(0x366f8340), WTC(0x370fb800), WTC(0x37b2cf80), WTC(0x3857a480), WTC(0x38fcee80), WTC(0x39a16840), WTC(0x3a4422c0), WTC(0x3ae495c0), +WTC(0x3b824000), WTC(0x3c1cb500), WTC(0x3cb438c0), WTC(0x3d4994c0), WTC(0x3ddd8f40), WTC(0x3e70ec00), WTC(0x3f045e40), WTC(0x3f989080), +WTC(0x402e32ff), WTC(0x40c5c07f), WTC(0x415f547f), WTC(0x41faf07f), WTC(0x4298997f), WTC(0x4338307f), WTC(0x43d96bff), WTC(0x447bffff), +WTC(0x451f9cff), WTC(0x45c3daff), WTC(0x46683eff), WTC(0x470c4cff), WTC(0x47af93ff), WTC(0x4851c3ff), WTC(0x48f29d7f), WTC(0x4991de7f), +WTC(0x4a2f5e7f), WTC(0x4acb287f), WTC(0x4b65537f), WTC(0x4bfdf37f), WTC(0x4c95337f), WTC(0x4d2b51ff), WTC(0x4dc091ff), WTC(0x4e5533ff), +WTC(0x4ee96b7f), WTC(0x4f7d61ff), WTC(0x501140ff), WTC(0x50a5317f), WTC(0x51395a7f), WTC(0x51cddf7f), WTC(0x5262e6ff), WTC(0x52f885ff), +WTC(0x538eb47f), WTC(0x542560ff), WTC(0x54bc7b7f), WTC(0x5553a8ff), WTC(0x55ea35ff), WTC(0x567f66ff), WTC(0x5712897f), WTC(0x57a33a7f), +WTC(0x583152ff), WTC(0x58bca5ff), WTC(0x594530ff), WTC(0x59cb79ff), WTC(0x5a5047ff), WTC(0x5ad45eff), WTC(0x5b584e7f), WTC(0x5bdc417f), +WTC(0x5c60487f), WTC(0x5ce476ff), WTC(0x5d68c47f), WTC(0x5ded06ff), WTC(0x5e7111ff), WTC(0x5ef4b5ff), WTC(0x5f77a17f), WTC(0x5ff96aff), +WTC(0x6079a7ff), WTC(0x60f7f7ff), WTC(0x617417ff), WTC(0x61edd87f), WTC(0x6264ffff), WTC(0x62d9a6ff), WTC(0x634c817f), WTC(0x63be657f), +WTC(0x6430277f), WTC(0x64a2247f), WTC(0x65142bff), WTC(0x6586027f), WTC(0x65f7697f), WTC(0x666801ff), WTC(0x66d756ff), WTC(0x6744f0ff), +WTC(0x67b0787f), WTC(0x681a077f), WTC(0x6881ebff), WTC(0x68e8707f), WTC(0x694dceff), WTC(0x69b21e7f), WTC(0x6a156cff), WTC(0x6a77ca7f), +WTC(0x6ad9377f), WTC(0x6b39a4ff), WTC(0x6b9901ff), WTC(0x6bf73cff), WTC(0x6c54457f), WTC(0x6cb00aff), WTC(0x6d0a7bff), WTC(0x6d6387ff), +WTC(0xae2cbe01), WTC(0xaf526d01), WTC(0xb0751201), WTC(0xb194da81), WTC(0xb2b1f401), WTC(0xb3cc8d01), WTC(0xb4e4d201), WTC(0xb5faf101), +WTC(0xb70f1881), WTC(0xb8217301), WTC(0xb9321181), WTC(0xba40ee01), WTC(0xbb4e0201), WTC(0xbc594781), WTC(0xbd62b881), WTC(0xbe6a5181), +WTC(0xbf700d01), WTC(0xc073e4c0), WTC(0xc175d240), WTC(0xc275cc80), WTC(0xc373cb80), WTC(0xc46fca00), WTC(0xc569c600), WTC(0xc661bdc0), +WTC(0xc757af80), WTC(0xc84b9840), WTC(0xc93d7300), WTC(0xca2d3a40), WTC(0xcb1aea40), WTC(0xcc068280), WTC(0xccf00480), WTC(0xcdd77200), +WTC(0xcebccb40), WTC(0xcfa00d80), WTC(0xd0813540), WTC(0xd1603f00), WTC(0xd23d2980), WTC(0xd317f7c0), WTC(0xd3f0ac40), WTC(0xd4c74980), +WTC(0xd59bcf80), WTC(0xd66e3b00), WTC(0xd73e8900), WTC(0xd80cb740), WTC(0xd8d8c7c0), WTC(0xd9a2be00), WTC(0xda6a9e40), WTC(0xdb306a40), +WTC(0xdbf42080), WTC(0xdcb5be80), WTC(0xdd754140), WTC(0xde32a900), WTC(0xdeedf9c0), WTC(0xdfa737c0), WTC(0xe05e6740), WTC(0xe1138900), +WTC(0xe1c69ac0), WTC(0xe2779a40), WTC(0xe3268680), WTC(0xe3d36260), WTC(0xe47e33a0), WTC(0xe526ff80), WTC(0xe5cdc960), WTC(0xe6729100), +WTC(0xe7155460), WTC(0xe7b611c0), WTC(0xe854ca20), WTC(0xe8f18180), WTC(0xe98c3ca0), WTC(0xea24ffe0), WTC(0xeabbcb20), WTC(0xeb509b60), +WTC(0xebe36d00), WTC(0xec743e00), WTC(0xed0310e0), WTC(0xed8feaa0), WTC(0xee1ad060), WTC(0xeea3c640), WTC(0xef2acd60), WTC(0xefafe6a0), +WTC(0xf03312f0), WTC(0xf0b45800), WTC(0xf133c230), WTC(0xf1b15ef0), WTC(0xf22d3af0), WTC(0xf2a75c80), WTC(0xf31fc460), WTC(0xf39673b0), +WTC(0xf40b6a00), WTC(0xf47ea230), WTC(0xf4f01450), WTC(0xf55fb930), WTC(0xf5cd84c0), WTC(0xf6396090), WTC(0xf6a333e0), WTC(0xf70ae540), +WTC(0xf7707260), WTC(0xf7d3f720), WTC(0xf83592f0), WTC(0xf8956450), WTC(0xf8f38120), WTC(0xf94ff7c8), WTC(0xf9aad740), WTC(0xfa042920), +WTC(0xfa5be110), WTC(0xfab1e778), WTC(0xfb062478), WTC(0xfb588d78), WTC(0xfba93530), WTC(0xfbf836c8), WTC(0xfc45ace0), WTC(0xfc91a294), +WTC(0xfcdc0e5c), WTC(0xfd24e438), WTC(0xfd6c17dc), WTC(0xfdb19758), WTC(0xfdf54c3c), WTC(0xfe371ef8), WTC(0xfe7701aa), WTC(0xfeb50d62), +WTC(0xfef1700a), WTC(0xff2c5574), WTC(0xff65ee7b), WTC(0xff9e75de), WTC(0xffd62863), WTC(0x000d4401), WTC(0x0043d345), WTC(0x00799cd0), +WTC(0x00ae5f49), WTC(0x00e1d7a4), WTC(0x0113a6f2), WTC(0x0143575c), WTC(0x01707024), WTC(0x019a9346), WTC(0x01c1cf08), WTC(0x01e66c12), +WTC(0x0208ac48), WTC(0x0228e868), WTC(0x0247a6c8), WTC(0x02657aa0), WTC(0x0282f710), WTC(0x02a07e50), WTC(0x02be31c0), WTC(0x02dc2b30), +WTC(0x02fa7f34), WTC(0x0318fb10), WTC(0x03372fdc), WTC(0x0354ae54), WTC(0x03710d18), WTC(0x038bfdb4), WTC(0x03a54084), WTC(0x03bc92b8), +WTC(0x03d1c710), WTC(0x03e4dd20), WTC(0x03f5e25c), WTC(0x0404e218), WTC(0x0411fc30), WTC(0x041d6b30), WTC(0x04276cd0), WTC(0x04303e00), +WTC(0x04381528), WTC(0x043f2310), WTC(0x04459908), WTC(0x044ba430), WTC(0x045161f8), WTC(0x0456e6f8), WTC(0x045c49a8), WTC(0x046192f8), +WTC(0x0466af40), WTC(0x046b8240), WTC(0x046ff0d8), WTC(0x0473de18), WTC(0x04772b58), WTC(0x0479b9a0), WTC(0x047b6a30), WTC(0x047c2088), +WTC(0x047bc230), WTC(0x047a3418), WTC(0x04776098), WTC(0x04734790), WTC(0x046df4c0), WTC(0x04677220), WTC(0x045fd1b0), WTC(0x04573588), +WTC(0x044dc4b8), WTC(0x0443a5b8), WTC(0x04390160), WTC(0x042e0398), WTC(0x0422d8c0), WTC(0x0417aa30), WTC(0x040c7ce0), WTC(0x040136e0), +WTC(0x03f5beb0), WTC(0x03e9f8ec), WTC(0x03ddc484), WTC(0x03d0fd9c), WTC(0x03c37fa0), WTC(0x03b53014), WTC(0x03a60a18), WTC(0x03960f88), +WTC(0x03854110), WTC(0x0373ad9c), WTC(0x03617694), WTC(0x034ebf9c), WTC(0x033bab30), WTC(0x03284ef0), WTC(0x0314b598), WTC(0x0300ea54), +WTC(0x02ecf524), WTC(0x02d8d210), WTC(0x02c476ac), WTC(0x02afd940), WTC(0x029aee4c), WTC(0x0285a6f4), WTC(0x026ff398), WTC(0x0259c448), +WTC(0x024317cc), WTC(0x022c0084), WTC(0x02149310), WTC(0x01fce334), WTC(0x01e4fb24), WTC(0x01ccdd0a), WTC(0x01b48b20), WTC(0x019c077e), +WTC(0x01835432), WTC(0x016a733c), WTC(0x015166a6), WTC(0x0138302e), WTC(0x011ed0f6), WTC(0x010549f8), WTC(0x00eb9c25), WTC(0x00d1caa6), +WTC(0x00b7db94), WTC(0x009dd560), WTC(0x0083be75), WTC(0x00699d41), WTC(0x004f782f), WTC(0x003555ab), WTC(0x001b3c21), WTC(0x000131fe), +WTC(0xd61cfc40), WTC(0xd5acb340), WTC(0xd53d4400), WTC(0xd4cea6c0), WTC(0xd460d440), WTC(0xd3f3c440), WTC(0xd3876f80), WTC(0xd31bce40), +WTC(0xd2b0d900), WTC(0xd2468980), WTC(0xd1dcef00), WTC(0xd17429c0), WTC(0xd10c5b80), WTC(0xd0a59b80), WTC(0xd03fd780), WTC(0xcfdae780), +WTC(0xcf76a380), WTC(0xcf12fac0), WTC(0xceb01100), WTC(0xce4e18c0), WTC(0xcded4440), WTC(0xcd8d9a40), WTC(0xcd2ee800), WTC(0xccd0f440), +WTC(0xcc738780), WTC(0xcc167d40), WTC(0xcbb9c180), WTC(0xcb5d4040), WTC(0xcb00e240), WTC(0xcaa48000), WTC(0xca47eac0), WTC(0xc9eaf1c0), +WTC(0xc98d8100), WTC(0xc92fc580), WTC(0xc8d1fc80), WTC(0xc8746480), WTC(0xc816dc40), WTC(0xc7b8c280), WTC(0xc7596800), WTC(0xc6f81f80), +WTC(0xc6945740), WTC(0xc62d93c0), WTC(0xc5c358c0), WTC(0xc5552b80), WTC(0xc4e29240), WTC(0xc46b1440), WTC(0xc3ee3840), WTC(0xc36b8500), +WTC(0xc2e28040), WTC(0xc252ae80), WTC(0xc1bb9540), WTC(0xc11cc200), WTC(0xc075cf00), WTC(0xbfc65781), WTC(0xbf0df881), WTC(0xbe4c6f01), +WTC(0xbd819401), WTC(0xbcad2d01), WTC(0xbbcfb981), WTC(0xbaeca681), WTC(0xba08e781), WTC(0xb9297081), WTC(0xb851e081), WTC(0xb782ed01), +WTC(0xb6bc6a81), WTC(0xb5fe4981), WTC(0xb5487281), WTC(0xb49ad081), WTC(0xb3f54d81), WTC(0xb357d401), WTC(0xb2c24e01), WTC(0xb234a681), +WTC(0xb1aec701), WTC(0xb1309b01), WTC(0xb0ba0c01), WTC(0xb04b0481), WTC(0xafe36f01), WTC(0xaf833601), WTC(0xaf2a4381), WTC(0xaed88201), +WTC(0xae8ddb81), WTC(0xae4a3b81), WTC(0xae0d8b01), WTC(0xadd7b581), WTC(0xada8a481), WTC(0xad804281), WTC(0xad5e7a81), WTC(0xad433601), +WTC(0xad2e6001), WTC(0xad1fe281), WTC(0xad17a801), WTC(0xad159a81), WTC(0xad19a501), WTC(0xad23b101), WTC(0xad33aa01), WTC(0xad497981), +WTC(0xad650a01), WTC(0xad864601), WTC(0xadad1781), WTC(0xadd96981), WTC(0xae0b2601), WTC(0xae423781), WTC(0xae7e8801), WTC(0xaec00201), +WTC(0xaf069081), WTC(0xaf521c81), WTC(0xafa29201), WTC(0xaff7da01), WTC(0xb051df01), WTC(0xb0b08c81), WTC(0xb113cb81), WTC(0xb17b8701), +WTC(0xb1e7a981), WTC(0xb2581d81), WTC(0xb2cccc81), WTC(0xb345a181), WTC(0xb3c28701), WTC(0xb4436681), WTC(0xb4c82b81), WTC(0xb550bf81), +WTC(0xb5dd0d01), WTC(0xb66cff01), WTC(0xb7007f01), WTC(0xb7977781), WTC(0xb831d381), WTC(0xb8cf7d01), WTC(0xb9705e01), WTC(0xba146101), +WTC(0xbabb7081), WTC(0xbb657781), WTC(0xbc125f01), WTC(0xbcc21281), WTC(0xbd747b81), WTC(0xbe298581), WTC(0xbee11981), WTC(0xbf9b2301), +WTC(0xc0578b80), WTC(0xc1163dc0), WTC(0xc1d72400), WTC(0xc29a28c0), WTC(0xc35f3640), WTC(0xc42636c0), WTC(0xc4ef1500), WTC(0xc5b9bb00), +WTC(0xc6861340), WTC(0xc7540840), WTC(0xc8238400), WTC(0xc8f47100), WTC(0xc9c6b9c0), WTC(0xca9a4840), WTC(0xcb6f0780), WTC(0xcc44e140), +WTC(0xcd1bc000), WTC(0xcdf38e00), WTC(0xcecc3600), WTC(0xcfa5a240), WTC(0xd07fbcc0), WTC(0xd15a7040), WTC(0xd235a6c0), WTC(0xd3114b00), +WTC(0xd3ed4740), WTC(0xd4c98580), WTC(0xd5a5f080), WTC(0xd6827280), WTC(0xd75ef600), WTC(0xd83b6500), WTC(0xd917aa00), WTC(0xd9f3af80), +WTC(0xdacf5fc0), WTC(0xdbaaa540), WTC(0xdc856a00), WTC(0xdd5f98c0), WTC(0xde391bc0), WTC(0xdf11dd40), WTC(0xdfe9c780), WTC(0xe0c0c540), +WTC(0xe196c080), WTC(0xe26ba3c0), WTC(0xe33f5960), WTC(0xe411cba0), WTC(0xe4e2e500), WTC(0xe5b28fc0), WTC(0xe680b640), WTC(0xe74d42e0), +WTC(0xe8181fe0), WTC(0xe8e137e0), WTC(0xe9a87500), WTC(0xea6dc1a0), WTC(0xeb310820), WTC(0xebf23300), WTC(0xecb12c60), WTC(0xed6ddee0), +WTC(0xee2834a0), WTC(0xeee01800), WTC(0xef957380), WTC(0xf0483160), WTC(0xf0f83c00), WTC(0xf1a57db0), WTC(0xf24fe0f0), WTC(0xf2f74ff0), +WTC(0xf39bb530), WTC(0xf43cfaf0), WTC(0xf4db0b90), WTC(0xf575d180), WTC(0xf60d3700), WTC(0xf6a12680), WTC(0xf7318a50), WTC(0xf7be4cc0), +WTC(0xf8475850), WTC(0xf8cc9738), WTC(0xf94df3e0), WTC(0xf9cb58a8), WTC(0xfa44afe0), WTC(0xfab9e3e8), WTC(0xfb2adf20), WTC(0xfb978be8), +WTC(0xfbffd488), WTC(0xfc63a370), WTC(0xfcc2e2f0), WTC(0xfd1d7d64), WTC(0xfd735d2c), WTC(0xfdc46c9c), WTC(0xfe109618), WTC(0xfe57c3f4), +WTC(0xfe99e090), WTC(0xfed6d644), WTC(0xff0e8f6e), WTC(0xff40f667), WTC(0xff6df58c), WTC(0xff957738), WTC(0xffb765c5), WTC(0xffd3ab90), +WTC(0xffea32f4), WTC(0xfffae64c), WTC(0x0005aff3), WTC(0x000a7a44), WTC(0x00092f9c), WTC(0x0001ba54), WTC(0xfff404ca), WTC(0xffdff957) +}; + + + + +/* + * TNS_MAX_BANDS + * entry for each sampling rate + * 1 long window + * 2 SHORT window +*/ +const UCHAR tns_max_bands_tbl[13][2] = +{ + { 31, 9 }, /* 96000 */ + { 31, 9 }, /* 88200 */ + { 34, 10 }, /* 64000 */ + { 40, 14 }, /* 48000 */ + { 42, 14 }, /* 44100 */ + { 51, 14 }, /* 32000 */ + { 46, 14 }, /* 24000 */ + { 46, 14 }, /* 22050 */ + { 42, 14 }, /* 16000 */ + { 42, 14 }, /* 12000 */ + { 42, 14 }, /* 11025 */ + { 39, 14 }, /* 8000 */ + { 39, 14 }, /* 7350 */ +}; + +/* TNS_MAX_BANDS for low delay. The array index is sampleRateIndex-3 */ +const UCHAR tns_max_bands_tbl_480[5] = { + 31, /* 48000 */ + 32, /* 44100 */ + 37, /* 32000 */ + 30, /* 24000 */ + 30 /* 22050 */ +}; +const UCHAR tns_max_bands_tbl_512[5] = { + 31, /* 48000 */ + 32, /* 44100 */ + 37, /* 32000 */ + 31, /* 24000 */ + 31 /* 22050 */ +}; + +#define TCC(x) (FIXP_DBL(x)) + +const FIXP_TCC FDKaacDec_tnsCoeff3 [8] = +{ + TCC(0x81f1d1d4), TCC(0x9126146c), TCC(0xadb922c4), TCC(0xd438af1f), + TCC(0x00000000), TCC(0x3789809b), TCC(0x64130dd4), TCC(0x7cca7016) +}; +const FIXP_TCC FDKaacDec_tnsCoeff4 [16] = +{ + TCC(0x808bc842), TCC(0x84e2e58c), TCC(0x8d6b49d1), TCC(0x99da920a), + TCC(0xa9c45713), TCC(0xbc9ddeb9), TCC(0xd1c2d51b), TCC(0xe87ae53d), + TCC(0x00000000), TCC(0x1a9cd9b6), TCC(0x340ff254), TCC(0x4b3c8c29), + TCC(0x5f1f5ebb), TCC(0x6ed9ebba), TCC(0x79bc385f), TCC(0x7f4c7e5b) +}; + +/* MPEG like mapping (no change). */ +const UCHAR channelMappingTablePassthrough[8][8] = +{ + { 0, 1,255,255,255,255,255,255}, /* mono / PS */ + { 0, 1,255,255,255,255,255,255}, /* stereo */ + { 0, 1, 2,255,255,255,255,255}, /* 3ch */ + { 0, 1, 2, 3,255,255,255,255}, /* 4ch */ + { 0, 1, 2, 3, 4,255,255,255}, /* 5ch */ + { 0, 1, 2, 3, 4, 5,255,255}, /* 5.1ch */ + { 0, 1, 2, 3, 4, 5, 6, 7}, /* 7ch */ + { 0, 1, 2, 3, 4, 5, 6, 7} /* 7.1ch */ +}; + +/* WAV file like mapping (from MPEG mapping). */ +const UCHAR channelMappingTableWAV[8][8] = +{ + { 0, 1,255,255,255,255,255,255}, /* mono / PS */ + { 0, 1,255,255,255,255,255,255}, /* stereo */ + { 2, 0, 1,255,255,255,255,255}, /* 3ch */ + { 2, 0, 1, 3,255,255,255,255}, /* 4ch */ + { 2, 0, 1, 3, 4,255,255,255}, /* 5ch */ + { 2, 0, 1, 4, 5, 3,255,255}, /* 5.1ch */ + { 0, 1, 2, 3, 4, 5, 6, 7}, /* 7ch */ + { 2, 0, 1, 6, 7, 4, 5, 3} /* 7.1ch */ +}; + +/* Lookup tables for elements in ER bitstream */ +const MP4_ELEMENT_ID elementsTab[8][7] = +{ + {ID_SCE, ID_EXT, ID_END, ID_NONE, ID_NONE,ID_NONE,ID_NONE }, /* 1 channel */ + {ID_CPE, ID_EXT, ID_END, ID_NONE, ID_NONE,ID_NONE,ID_NONE } /* 2 channels */ + , + {ID_SCE, ID_CPE, ID_EXT, ID_END, ID_NONE,ID_NONE,ID_NONE }, /* 3 channels */ + {ID_SCE, ID_CPE, ID_SCE, ID_EXT, ID_END, ID_NONE,ID_NONE }, /* 4 channels */ + {ID_SCE, ID_CPE, ID_CPE, ID_EXT, ID_END, ID_NONE,ID_NONE }, /* 5 channels */ + {ID_SCE, ID_CPE, ID_CPE, ID_LFE, ID_EXT, ID_END, ID_NONE }, /* 6 channels */ + {ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_LFE, ID_EXT, ID_END} /* 8 channels */ +}; + +/*! Random sign bit used for concealment +*/ +const USHORT randomSign[AAC_NF_NO_RANDOM_VAL/16] = { +/* + sign bits of FDK_sbrDecoder_sbr_randomPhase[] entries: + LSB ........... MSB -> MSB ... LSB +*/ +/* 1001 0111 0011 1100 -> */ 0x3ce9, +/* 0100 0111 0111 1011 -> */ 0xdee2, +/* 0001 1100 1110 1011 -> */ 0xd738, +/* 0001 0011 0110 1001 -> */ 0x96c8, +/* 0101 0011 1101 0000 -> */ 0x0bca, +/* 0001 0001 1111 0100 -> */ 0x2f88, +/* 1110 1100 1110 1101 -> */ 0xb737, +/* 0010 1010 1011 1001 -> */ 0x9d54, +/* 0111 1100 0110 1010 -> */ 0x563e, +/* 1101 0111 0010 0101 -> */ 0xa4eb, +/* 0001 0101 1011 1100 -> */ 0x3da8, +/* 0101 0111 1001 1011 -> */ 0xd9ea, +/* 1101 0100 0101 0101 -> */ 0xaa2b, +/* 1000 1001 0100 0011 -> */ 0xc291, +/* 1100 1111 1010 1100 -> */ 0x35f3, +/* 1100 1010 1110 0010 -> */ 0x4753, +/* 0110 0001 1010 1000 -> */ 0x1586, +/* 0011 0101 1111 1100 -> */ 0x3fac, +/* 0001 0110 1010 0001 -> */ 0x8568, +/* 0010 1101 0111 0010 -> */ 0x4eb4, +/* 1101 1010 0100 1001 -> */ 0x925b, +/* 1100 1001 0000 1110 -> */ 0x7093, +/* 1000 1100 0110 1010 -> */ 0x5631, +/* 0000 1000 0110 1101 -> */ 0xb610, +/* 1000 0001 1111 1011 -> */ 0xdf81, +/* 1111 0011 0100 0111 -> */ 0xe2cf, +/* 1000 0001 0010 1010 -> */ 0x5481, +/* 1101 0101 1100 1111 -> */ 0xf3ab, +/* 0110 0001 0110 1000 -> */ 0x1686, +/* 0011 0011 1100 0110 -> */ 0x63cc, +/* 0011 0111 0101 0110 -> */ 0x6aec, +/* 1011 0001 1010 0010 -> */ 0x458d +}; + diff --git a/libAACdec/src/aac_rom.h b/libAACdec/src/aac_rom.h new file mode 100644 index 0000000..313b813 --- /dev/null +++ b/libAACdec/src/aac_rom.h @@ -0,0 +1,125 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: Definition of constant tables + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef AAC_ROM_H +#define AAC_ROM_H + +#include "common_fix.h" +#include "FDK_audio.h" +#include "aacdec_hcr_types.h" +#include "aacdec_hcrs.h" + +#define AAC_NF_NO_RANDOM_VAL 512 /*!< Size of random number array for noise floor */ + +#define INV_QUANT_TABLESIZE 256 + +extern const FIXP_DBL InverseQuantTable [INV_QUANT_TABLESIZE + 1] ; +extern const FIXP_DBL MantissaTable [4][14] ; +extern const SCHAR ExponentTable [4][14] ; + +#define NUM_LD_COEF_512 1536 +#define NUM_LD_COEF_480 1440 +/* Window table partition exponents. */ +#define WTS0 (1) +#define WTS1 (0) +#define WTS2 (-2) +extern const FIXP_WTB LowDelaySynthesis512[1536]; +extern const FIXP_WTB LowDelaySynthesis480[1440]; + +typedef struct { + const SHORT *sfbOffsetLong; + const SHORT *sfbOffsetShort; + UCHAR numberOfSfbLong; + UCHAR numberOfSfbShort; +} SFB_INFO; + +extern const SFB_INFO sfbOffsetTables[5][16]; + +/* Huffman tables */ +enum { + HuffmanBits = 2, + HuffmanEntries = (1 << HuffmanBits) +}; + +typedef struct +{ + const USHORT (*CodeBook)[HuffmanEntries]; + UCHAR Dimension; + UCHAR numBits; + UCHAR Offset; +} CodeBookDescription; + +extern const CodeBookDescription AACcodeBookDescriptionTable[13]; +extern const CodeBookDescription AACcodeBookDescriptionSCL; + + +extern const STATEFUNC aStateConstant2State[]; + +extern const SCHAR aCodebook2StartInt[]; + +extern const UCHAR aMinOfCbPair[]; +extern const UCHAR aMaxOfCbPair[]; + +extern const UCHAR aMaxCwLen[]; +extern const UCHAR aDimCb[]; +extern const UCHAR aDimCbShift[]; +extern const UCHAR aSignCb[]; +extern const UCHAR aCbPriority[]; + +extern const UINT *aHuffTable[]; +extern const SCHAR *aQuantTable[]; + +extern const USHORT aLargestAbsoluteValue[]; + +extern const UINT aHuffTreeRvlcEscape[]; +extern const UINT aHuffTreeRvlCodewds[]; + + +extern const UCHAR tns_max_bands_tbl[13][2]; + +extern const UCHAR tns_max_bands_tbl_480[5]; +extern const UCHAR tns_max_bands_tbl_512[5]; + +#define FIXP_TCC FIXP_DBL + +extern const FIXP_TCC FDKaacDec_tnsCoeff3[8]; +extern const FIXP_TCC FDKaacDec_tnsCoeff4[16]; + +extern const USHORT randomSign[AAC_NF_NO_RANDOM_VAL/16]; + +extern const FIXP_DBL pow2_div24minus1[47]; +extern const int offsetTab[2][16]; + +/* Channel mapping indices for time domain I/O. First dimension is channel count-1. */ +extern const UCHAR channelMappingTablePassthrough[8][8]; +extern const UCHAR channelMappingTableWAV[8][8]; + +/* Lookup tables for elements in ER bitstream */ +extern const MP4_ELEMENT_ID elementsTab[8][7]; + +#endif /* #ifndef AAC_ROM_H */ diff --git a/libAACdec/src/aacdec_drc.cpp b/libAACdec/src/aacdec_drc.cpp new file mode 100644 index 0000000..58abea2 --- /dev/null +++ b/libAACdec/src/aacdec_drc.cpp @@ -0,0 +1,997 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Christian Griebel + Description: Dynamic range control (DRC) decoder tool for AAC + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "aacdec_drc.h" + + +#include "channelinfo.h" +#include "aac_rom.h" + + #include "sbrdecoder.h" + +/* + * Dynamic Range Control + */ + +/* For parameter conversion */ +#define DRC_PARAMETER_BITS ( 7 ) +#define DRC_MAX_QUANT_STEPS ( 1<enable = 0; + self->numThreads = 0; + self->digitalNorm = 0; + + /* init params */ + pParams = &self->params; + pParams->bsDelayEnable = 0; + pParams->cut = FL2FXCONST_DBL(0.0f); + pParams->boost = FL2FXCONST_DBL(0.0f); + pParams->targetRefLevel = AACDEC_DRC_DEFAULT_REF_LEVEL; + pParams->expiryFrame = AACDEC_DRC_DFLT_EXPIRY_FRAMES; + + /* initial program ref level = target ref level */ + self->progRefLevel = pParams->targetRefLevel; +} + + +/*! + \brief Initialize DRC control data for one channel + + \self Handle of DRC info + + \return none +*/ +void aacDecoder_drcInitChannelData ( + CDrcChannelData *pDrcChData ) +{ + if (pDrcChData != NULL) { + pDrcChData->expiryCount = 0; + pDrcChData->numBands = 1; + pDrcChData->bandTop[0] = (1024 >> 2) - 1; + pDrcChData->drcValue[0] = 0; + pDrcChData->drcInterpolationScheme = 0; + } +} + + +/*! + \brief Set one single DRC parameter + + \self Handle of DRC info. + \param Parameter to be set. + \value Value to be set. + + \return an error code. +*/ +AAC_DECODER_ERROR aacDecoder_drcSetParam ( + HANDLE_AAC_DRC self, + AACDEC_DRC_PARAM param, + INT value ) +{ + AAC_DECODER_ERROR ErrorStatus = AAC_DEC_OK; + + switch (param) + { + case DRC_CUT_SCALE: + /* set attenuation scale factor */ + if ( (value < 0) + || (value > DRC_MAX_QUANT_FACTOR) ) { + return AAC_DEC_SET_PARAM_FAIL; + } + if (self == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + self->params.cut = (FIXP_DBL)((INT)(DRC_PARAM_QUANT_STEP>>DRC_PARAM_SCALE) * (INT)(value+1)); + break; + case DRC_BOOST_SCALE: + /* set boost factor */ + if ( (value < 0) + || (value > DRC_MAX_QUANT_FACTOR) ) { + return AAC_DEC_SET_PARAM_FAIL; + } + if (self == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + self->params.boost = (FIXP_DBL)((INT)(DRC_PARAM_QUANT_STEP>>DRC_PARAM_SCALE) * (INT)(value+1)); + break; + case TARGET_REF_LEVEL: + if ( value > MAX_REFERENCE_LEVEL + || value < -MAX_REFERENCE_LEVEL ) { + return AAC_DEC_SET_PARAM_FAIL; + } + if (self == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + if (value < 0) { + self->digitalNorm = 0; + } + else { + /* ref_level must be between 0 and MAX_REFERENCE_LEVEL, inclusive */ + self->digitalNorm = 1; + self->progRefLevel = AACDEC_DRC_DEFAULT_REF_LEVEL; + self->params.targetRefLevel = value; + } + break; + case APPLY_HEAVY_COMPRESSION: + if (value < 0 || value > 1) { + return AAC_DEC_SET_PARAM_FAIL; + } + if (self == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + self->params.applyHeavyCompression = (UCHAR)value; + break; + case DRC_BS_DELAY: + if (value < 0 || value > 1) { + return AAC_DEC_SET_PARAM_FAIL; + } + if (self == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + self->params.bsDelayEnable = value; + break; + case DRC_DATA_EXPIRY_FRAME: + if (self == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + self->params.expiryFrame = (UINT)value; + break; + default: + return AAC_DEC_SET_PARAM_FAIL; + } /* switch(param) */ + + /* switch on/off processing */ + self->enable = ( (self->params.boost > (FIXP_DBL)0) + || (self->params.cut > (FIXP_DBL)0) + || (self->params.applyHeavyCompression != 0) + || (self->digitalNorm == 1) ); + + + return ErrorStatus; +} + + +static int parseExcludedChannels( UINT *excludedChnsMask, + HANDLE_FDK_BITSTREAM bs ) +{ + UINT excludeMask = 0; + UINT i, j; + int bitCnt = 9; + + for (i = 0, j = 1; i < 7; i++, j<<=1) { + if (FDKreadBits(bs,1)) { + excludeMask |= j; + } + } + + /* additional_excluded_chns */ + while (FDKreadBits(bs,1)) { + for (i = 0; i < 7; i++, j<<=1) { + if (FDKreadBits(bs,1)) { + excludeMask |= j; + } + } + bitCnt += 9; + FDK_ASSERT(j < (UINT)-1); + } + + *excludedChnsMask = excludeMask; + + return (bitCnt); +} + + +/*! + \brief Save DRC payload bitstream position + + \self Handle of DRC info + \bs Handle of FDK bitstream + + \return The number of DRC payload bits +*/ +int aacDecoder_drcMarkPayload ( + HANDLE_AAC_DRC self, + HANDLE_FDK_BITSTREAM bs, + AACDEC_DRC_PAYLOAD_TYPE type ) +{ + UINT bsStartPos; + int i, numBands = 1, bitCnt = 0; + + if (self == NULL) { + return 0; + } + + bsStartPos = FDKgetValidBits(bs); + + switch (type) { + case MPEG_DRC_EXT_DATA: + { + bitCnt = 4; + + if (FDKreadBits(bs,1)) { /* pce_tag_present */ + FDKreadBits(bs,8); /* pce_instance_tag + drc_tag_reserved_bits */ + bitCnt+=8; + } + + if (FDKreadBits(bs,1)) { /* excluded_chns_present */ + FDKreadBits(bs,7); /* exclude mask [0..7] */ + bitCnt+=8; + while (FDKreadBits(bs,1)) { /* additional_excluded_chns */ + FDKreadBits(bs,7); /* exclude mask [x..y] */ + bitCnt+=8; + } + } + + if (FDKreadBits(bs,1)) { /* drc_bands_present */ + numBands += FDKreadBits(bs, 4); /* drc_band_incr */ + FDKreadBits(bs,4); /* reserved */ + bitCnt+=8; + for (i = 0; i < numBands; i++) { + FDKreadBits(bs,8); /* drc_band_top[i] */ + bitCnt+=8; + } + } + + if (FDKreadBits(bs,1)) { /* prog_ref_level_present */ + FDKreadBits(bs,8); /* prog_ref_level + prog_ref_level_reserved_bits */ + bitCnt+=8; + } + + for (i = 0; i < numBands; i++) { + FDKreadBits(bs,8); /* dyn_rng_sgn[i] + dyn_rng_ctl[i] */ + bitCnt+=8; + } + + if ( (self->numPayloads < MAX_DRC_THREADS) + && ((INT)FDKgetValidBits(bs) >= 0) ) + { + self->drcPayloadPosition[self->numPayloads++] = bsStartPos; + } + } + break; + + case DVB_DRC_ANC_DATA: + /* check sync word */ + if (FDKreadBits(bs, 8) == DVB_ANC_DATA_SYNC_BYTE) + { + int dmxLevelsPresent, compressionPresent; + int coarseGrainTcPresent, fineGrainTcPresent; + + bitCnt+=8; + + /* bs_info field */ + FDKreadBits(bs, 8); /* mpeg_audio_type, dolby_surround_mode, presentation_mode */ + bitCnt+=8; + + /* Evaluate ancillary_data_status */ + FDKreadBits(bs, 3); /* reserved, set to 0 */ + dmxLevelsPresent = FDKreadBits(bs, 1); /* downmixing_levels_MPEG4_status */ + FDKreadBits(bs, 1); /* reserved, set to 0 */ + compressionPresent = FDKreadBits(bs, 1); /* audio_coding_mode_and_compression status */ + coarseGrainTcPresent = FDKreadBits(bs, 1); /* coarse_grain_timecode_status */ + fineGrainTcPresent = FDKreadBits(bs, 1); /* fine_grain_timecode_status */ + bitCnt+=8; + + /* MPEG4 downmixing levels */ + if (dmxLevelsPresent) { + FDKreadBits(bs, 8); /* downmixing_levels_MPEG4 */ + bitCnt+=8; + } + /* audio coding mode and compression status */ + if (compressionPresent) { + FDKreadBits(bs, 16); /* audio_coding_mode, Compression_value */ + bitCnt+=16; + } + /* coarse grain timecode */ + if (coarseGrainTcPresent) { + FDKreadBits(bs, 16); /* coarse_grain_timecode */ + bitCnt+=16; + } + /* fine grain timecode */ + if (fineGrainTcPresent) { + FDKreadBits(bs, 16); /* fine_grain_timecode */ + bitCnt+=16; + } + if ( !self->dvbAncDataAvailable + && ((INT)FDKgetValidBits(bs) >= 0) ) + { + self->dvbAncDataPosition = bsStartPos; + self->dvbAncDataAvailable = 1; + } + } + break; + + default: + break; + } + + return (bitCnt); +} + + +/*! + \brief Parse DRC parameters from bitstream + + \bs Handle of FDK bitstream (in) + \pDrcBs Pointer to DRC payload data container (out) + \payloadPosition Bitstream position of MPEG DRC data junk (in) + + \return Number of bits read (0 in case of a parse error) +*/ +static int aacDecoder_drcParse ( + HANDLE_FDK_BITSTREAM bs, + CDrcPayload *pDrcBs, + UINT payloadPosition ) +{ + int i, numBands, bitCnt = 4; + + /* Move to the beginning of the DRC payload field */ + FDKpushBiDirectional(bs, FDKgetValidBits(bs)-payloadPosition); + + /* pce_tag_present */ + if (FDKreadBits(bs,1)) + { + pDrcBs->pceInstanceTag = FDKreadBits(bs, 4); /* pce_instance_tag */ + /* only one program supported */ + FDKreadBits(bs, 4); /* drc_tag_reserved_bits */ + bitCnt += 8; + } else { + pDrcBs->pceInstanceTag = -1; /* not present */ + } + + if (FDKreadBits(bs,1)) { /* excluded_chns_present */ + /* get excluded_chn_mask */ + bitCnt += parseExcludedChannels(&pDrcBs->excludedChnsMask, bs); + } else { + pDrcBs->excludedChnsMask = 0; + } + + numBands = 1; + if (FDKreadBits(bs,1)) /* drc_bands_present */ + { + /* get band_incr */ + numBands += FDKreadBits(bs, 4); /* drc_band_incr */ + pDrcBs->channelData.drcInterpolationScheme = FDKreadBits(bs, 4); /* drc_interpolation_scheme */ + bitCnt += 8; + /* band_top */ + for (i = 0; i < numBands; i++) + { + pDrcBs->channelData.bandTop[i] = FDKreadBits(bs, 8); /* drc_band_top[i] */ + bitCnt += 8; + } + } + else { + pDrcBs->channelData.bandTop[0] = 255; + } + + pDrcBs->channelData.numBands = numBands; + + if (FDKreadBits(bs,1)) /* prog_ref_level_present */ + { + pDrcBs->progRefLevel = FDKreadBits(bs, 7); /* prog_ref_level */ + FDKreadBits(bs, 1); /* prog_ref_level_reserved_bits */ + bitCnt += 8; + } else { + pDrcBs->progRefLevel = -1; + } + + for (i = 0; i < numBands; i++) + { + pDrcBs->channelData.drcValue[i] = FDKreadBits(bs, 1) << 7; /* dyn_rng_sgn[i] */ + pDrcBs->channelData.drcValue[i] |= FDKreadBits(bs, 7) & 0x7F; /* dyn_rng_ctl[i] */ + bitCnt += 8; + } + + /* Set DRC payload type */ + pDrcBs->type = MPEG_DRC_EXT_DATA; + + return (bitCnt); +} + + +/*! + \brief Parse heavy compression value transported in DSEs of DVB streams with MPEG-4 content. + + \bs Handle of FDK bitstream (in) + \pDrcBs Pointer to DRC payload data container (out) + \payloadPosition Bitstream position of DVB ancillary data junk + + \return Number of bits read (0 in case of a parse error) +*/ +#define DVB_COMPRESSION_SCALE ( 8 ) /* 48,164 dB */ + +static int aacDecoder_drcReadCompression ( + HANDLE_FDK_BITSTREAM bs, + CDrcPayload *pDrcBs, + UINT payloadPosition ) +{ + int bitCnt = 0; + int dmxLevelsPresent, compressionPresent; + int coarseGrainTcPresent, fineGrainTcPresent; + + /* Move to the beginning of the DRC payload field */ + FDKpushBiDirectional(bs, FDKgetValidBits(bs)-payloadPosition); + + /* Sanity checks */ + if ( FDKgetValidBits(bs) < 24 ) { + return 0; + } + + /* Check sync word */ + if (FDKreadBits(bs, 8) != DVB_ANC_DATA_SYNC_BYTE) { + return 0; + } + + /* Evaluate bs_info field */ + if (FDKreadBits(bs, 2) != 3) { /* mpeg_audio_type */ + /* No MPEG-4 audio data */ + return 0; + } + FDKreadBits(bs, 2); /* dolby_surround_mode */ + FDKreadBits(bs, 2); /* presentation_mode */ + if (FDKreadBits(bs, 2) != 0) { /* reserved, set to 0 */ + return 0; + } + + /* Evaluate ancillary_data_status */ + if (FDKreadBits(bs, 3) != 0) { /* reserved, set to 0 */ + return 0; + } + dmxLevelsPresent = FDKreadBits(bs, 1); /* downmixing_levels_MPEG4_status */ + if (FDKreadBits(bs, 1) != 0) { /* reserved, set to 0 */ + return 0; + } + compressionPresent = FDKreadBits(bs, 1); /* audio_coding_mode_and_compression status */ + coarseGrainTcPresent = FDKreadBits(bs, 1); /* coarse_grain_timecode_status */ + fineGrainTcPresent = FDKreadBits(bs, 1); /* fine_grain_timecode_status */ + bitCnt += 24; + + if (dmxLevelsPresent) { + FDKreadBits(bs, 8); /* downmixing_levels_MPEG4 */ + bitCnt += 8; + } + + /* audio_coding_mode_and_compression_status */ + if (compressionPresent) + { + UCHAR compressionOn, compressionValue; + + /* audio_coding_mode */ + if ( FDKreadBits(bs, 7) != 0 ) { /* The reserved bits shall be set to "0". */ + return 0; + } + compressionOn = (UCHAR)FDKreadBits(bs, 1); /* compression_on */ + compressionValue = (UCHAR)FDKreadBits(bs, 8); /* Compression_value */ + bitCnt += 16; + + if ( compressionOn ) { + /* A compression value is available so store the data just like MPEG DRC data */ + pDrcBs->channelData.drcValue[0] = compressionValue; + pDrcBs->channelData.numBands = 1; /* one value for all bands */ + pDrcBs->pceInstanceTag = -1; /* not present */ + pDrcBs->progRefLevel = -1; /* not present */ + } else { + /* No compression value available */ + /* CAUTION: It is not clearly defined by standard how to react in this situation. */ + pDrcBs->channelData.drcValue[0] = 0x7F; /* 0dB */ + pDrcBs->channelData.bandTop[0] = 0; + + /* If compression_on field is set to "0" the compression_value field shall be "0000 0000". */ + if (compressionValue != 0) { + return 0; + } + } + /* Set DRC payload type now because the payload seems to be correct. */ + pDrcBs->type = DVB_DRC_ANC_DATA; + } + + /* Read timecodes if available just to get the right amount of bits. */ + if (coarseGrainTcPresent) { + FDKreadBits(bs, 16); /* coarse_grain_timecode */ + bitCnt += 16; + } + if (fineGrainTcPresent) { + FDKreadBits(bs, 16); /* fine_grain_timecode */ + bitCnt += 16; + } + + return (bitCnt); +} + + +/* + * Prepare DRC processing + */ +static int aacDecoder_drcExtractAndMap ( + HANDLE_AAC_DRC self, + HANDLE_FDK_BITSTREAM hBs, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[], + UCHAR pceInstanceTag, + UCHAR channelMapping[], /* Channel mapping translating drcChannel index to canonical channel index */ + int validChannels ) +{ + CDrcPayload threadBs[MAX_DRC_THREADS]; + CDrcPayload *validThreadBs[MAX_DRC_THREADS]; + UINT backupBsPosition; + int i, thread, validThreads = 0; + int numExcludedChns[MAX_DRC_THREADS]; + + self->numThreads = 0; + backupBsPosition = FDKgetValidBits(hBs); + + for (i = 0; i < self->numPayloads && self->numThreads < MAX_DRC_THREADS; i++) { + int bitsParsed; + + /* Init payload data chunk. The memclear is very important because it initializes + the most values. Without it the module wouldn't work properly or crash. */ + FDKmemclear(&threadBs[self->numThreads], sizeof(CDrcPayload)); + threadBs[self->numThreads].channelData.bandTop[0] = (1024 >> 2) - 1; + + /* Extract payload */ + bitsParsed = aacDecoder_drcParse( hBs, + &threadBs[self->numThreads], + self->drcPayloadPosition[i] ); + if (bitsParsed > 0) { + self->numThreads++; + } + } + self->numPayloads = 0; + + if (self->dvbAncDataAvailable) + { /* Append a DVB heavy compression payload thread if available. */ + int bitsParsed; + + /* Init payload data chunk. The memclear is very important because it initializes + the most values. Without it the module wouldn't work properly or crash. */ + FDKmemclear(&threadBs[self->numThreads], sizeof(CDrcPayload)); + threadBs[self->numThreads].channelData.bandTop[0] = (1024 >> 2) - 1; + + /* Extract payload */ + bitsParsed = aacDecoder_drcReadCompression( hBs, + &threadBs[self->numThreads], + self->dvbAncDataPosition ); + if (bitsParsed > 0) { + self->numThreads++; + } + } + self->dvbAncDataAvailable = 0; + + /* Reset the bitbufffer */ + FDKpushBiDirectional(hBs, FDKgetValidBits(hBs) - backupBsPosition); + + /* calculate number of valid bits in excl_chn_mask */ + + /* coupling channels not supported */ + + /* check for valid threads */ + for (thread = 0; thread < self->numThreads; thread++) { + CDrcPayload *pThreadBs = &threadBs[thread]; + int numExclChns = 0; + + switch (pThreadBs->type) { + default: + continue; + case MPEG_DRC_EXT_DATA: + case DVB_DRC_ANC_DATA: + break; + } + + if (pThreadBs->pceInstanceTag >= 0) { /* if PCE tag present */ + if (pThreadBs->pceInstanceTag != pceInstanceTag) { + continue; /* don't accept */ + } + } + + /* calculate number of excluded channels */ + if (pThreadBs->excludedChnsMask > 0) { + INT exclMask = pThreadBs->excludedChnsMask; + int ch; + for (ch = 0; ch < validChannels; ch++) { + numExclChns += exclMask & 0x1; + exclMask >>= 1; + } + } + if (numExclChns < validChannels) { + validThreadBs[validThreads] = pThreadBs; + numExcludedChns[validThreads] = numExclChns; + validThreads++; + } + } + + if (validThreads > 1) { + int ch; + + /* check consistency of excl_chn_mask amongst valid DRC threads */ + for (ch = 0; ch < validChannels; ch++) { + int present = 0; + + for (thread = 0; thread < validThreads; thread++) { + CDrcPayload *pThreadBs = validThreadBs[thread]; + + + /* thread applies to this channel */ + if ( (pThreadBs->type == MPEG_DRC_EXT_DATA) + && ( (numExcludedChns[thread] == 0) + || (!(pThreadBs->excludedChnsMask & (1< 1) { + return -1; + } + } + } + + /* map DRC bitstream information onto DRC channel information */ + for (thread = 0; thread < validThreads; thread++) + { + CDrcPayload *pThreadBs = validThreadBs[thread]; + INT exclMask = pThreadBs->excludedChnsMask; + int ch; + + /* last progRefLevel transmitted is the one that is used + * (but it should really only be transmitted once per block!) + */ + if (pThreadBs->progRefLevel >= 0) { + self->progRefLevel = pThreadBs->progRefLevel; + } + + /* SCE, CPE and LFE */ + for (ch = 0; ch < validChannels; ch++) { + int mapedChannel = channelMapping[ch]; + + if ( ((exclMask & (1<params.applyHeavyCompression && (pThreadBs->type == DVB_DRC_ANC_DATA)) + || (!self->params.applyHeavyCompression && (pThreadBs->type == MPEG_DRC_EXT_DATA)) ) + ) { + /* copy thread to channel */ + pAacDecoderStaticChannelInfo[ch]->drcData = pThreadBs->channelData; + } + } + /* CCEs not supported by now */ + } + + return 0; +} + + +void aacDecoder_drcApply ( + HANDLE_AAC_DRC self, + void *pSbrDec, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + CDrcChannelData *pDrcChData, + int ch, /* needed only for SBR */ + int aacFrameSize, + int bSbrPresent ) +{ + int band, top, bin, numBands; + int bottom = 0; + + FIXP_DBL max_mantissa; + INT max_exponent; + + FIXP_DBL norm_mantissa = FL2FXCONST_DBL(0.0f); + INT norm_exponent = 0; + + FIXP_DBL fact_mantissa[MAX_DRC_BANDS]; + INT fact_exponent[MAX_DRC_BANDS]; + + CDrcParams *pParams = &self->params; + + FIXP_DBL *pSpectralCoefficient = SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient); + CIcsInfo *pIcsInfo = &pAacDecoderChannelInfo->icsInfo; + SHORT *pSpecScale = pAacDecoderChannelInfo->specScale; + + int winSeq = pIcsInfo->WindowSequence; + + /* Increment and check expiry counter */ + if ( (pParams->expiryFrame > 0) + && (++pDrcChData->expiryCount > pParams->expiryFrame) ) + { /* The DRC data is too old, so delete it. */ + aacDecoder_drcInitChannelData( pDrcChData ); + } + + if (!self->enable) { + sbrDecoder_drcDisable( (HANDLE_SBRDECODER)pSbrDec, ch ); + return; + } + + numBands = pDrcChData->numBands; + top = FDKmax(0, numBands-1); + + pDrcChData->bandTop[0] = fixMin(pDrcChData->bandTop[0], (aacFrameSize >> 2) - 1); + + /* If program reference normalization is done in the digital domain, + modify factor to perform normalization. prog_ref_level can + alternatively be passed to the system for modification of the level in + the analog domain. Analog level modification avoids problems with + reduced DAC SNR (if signal is attenuated) or clipping (if signal is + boosted) */ + + if (self->digitalNorm == 1) + { + /* 0.5^((targetRefLevel - progRefLevel)/24) */ + norm_mantissa = fLdPow( + FL2FXCONST_DBL(-1.0), /* log2(0.5) */ + 0, + (FIXP_DBL)((INT)(FL2FXCONST_DBL(1.0f/24.0)>>3) * (INT)(pParams->targetRefLevel-self->progRefLevel)), + 3, + &norm_exponent ); + } + else { + norm_mantissa = FL2FXCONST_DBL(0.5f); + norm_exponent = 1; + } + + + /* calc scale factors */ + for (band = 0; band < numBands; band++) + { + UCHAR drcVal = pDrcChData->drcValue[band]; + top = fixMin((int)( (pDrcChData->bandTop[band]+1)<<2 ), aacFrameSize); + + if ( pParams->applyHeavyCompression ) { + INT compressionFactorVal_e; + int valX = drcVal >> 4; + int valY = drcVal & 0x0F; + + /* calculate the unscaled heavy compression factor. + compressionFactor = 48.164 - 6.0206*valX - 0.4014*valY dB + range: -48.166 dB to 48.164 dB */ + if ( drcVal != 0x7F ) { + fact_mantissa[band] = + fPowInt( FL2FXCONST_DBL(0.95483867181), /* -0.4014dB = 0.95483867181 */ + 0, + valY, + &compressionFactorVal_e ); + + /* -0.0008dB (48.164 - 6.0206*8 = -0.0008) */ + fact_mantissa[band] = fMult(FL2FXCONST_DBL(0.99990790084), fact_mantissa[band]); + + fact_exponent[band] = DVB_COMPRESSION_SCALE - valX + compressionFactorVal_e; + } + else { + fact_mantissa[band] = FL2FXCONST_DBL(0.5f); + fact_exponent[band] = 1; + } + } else + { + /* apply the scaled dynamic range control words to factor. + * if scaling drc_cut (or drc_boost), or control word drc_mantissa is 0 + * then there is no dynamic range compression + * + * if pDrcChData->drcSgn[band] is + * 1 then gain is < 1 : factor = 2^(-self->cut * pDrcChData->drcMag[band] / 24) + * 0 then gain is > 1 : factor = 2^( self->boost * pDrcChData->drcMag[band] / 24) + */ + + if ((drcVal&0x7F) > 0) { + FIXP_DBL tParamVal = (drcVal & 0x80) ? -pParams->cut : pParams->boost; + + fact_mantissa[band] = + f2Pow( (FIXP_DBL)((INT)fMult(FL2FXCONST_DBL(1.0f/192.0f), tParamVal) * (drcVal&0x7F)), + 3+DRC_PARAM_SCALE, + &fact_exponent[band] ); + } + else { + fact_mantissa[band] = FL2FXCONST_DBL(0.5f); + fact_exponent[band] = 1; + } + } + + fact_mantissa[band] = fMult(fact_mantissa[band], norm_mantissa); + fact_exponent[band] += norm_exponent; + + + bottom = top; + + } /* end loop over bands */ + + + /* normalizations */ + { + int res; + + max_mantissa = FL2FXCONST_DBL(0.0f); + max_exponent = 0; + for (band = 0; band < numBands; band++) { + max_mantissa = fixMax(max_mantissa, fact_mantissa[band]); + max_exponent = fixMax(max_exponent, fact_exponent[band]); + } + + /* left shift factors to gain accurancy */ + res = CntLeadingZeros(max_mantissa) - 1; + + /* above topmost DRC band gain factor is 1 */ + if (((pDrcChData->bandTop[numBands-1]+1)<<2) < aacFrameSize) res = 0; + + if (res > 0) { + res = fixMin(res, max_exponent); + max_exponent -= res; + + for (band = 0; band < numBands; band++) { + fact_mantissa[band] <<= res; + fact_exponent[band] -= res; + } + } + + /* normalize magnitudes to one scale factor */ + for (band = 0; band < numBands; band++) { + if (fact_exponent[band] < max_exponent) { + fact_mantissa[band] >>= max_exponent - fact_exponent[band]; + } + } + } + + /* apply factor to spectral lines + * short blocks must take care that bands fall on + * block boundaries! + */ + if (!bSbrPresent) + { + bottom = 0; + + for (band = 0; band < numBands; band++) + { + top = fixMin((int)( (pDrcChData->bandTop[band]+1)<<2 ), aacFrameSize); /* ... * DRC_BAND_MULT; */ + + for (bin = bottom; bin < top; bin++) { + pSpectralCoefficient[bin] = fMult(pSpectralCoefficient[bin], fact_mantissa[band]); + } + + bottom = top; + } + + /* above topmost DRC band gain factor is 1 */ + if (max_exponent > 0) { + FIXP_DBL fact = FL2FXCONST_DBL(0.5f) >> (max_exponent - 1); + + for (bin = top; bin < aacFrameSize; bin++) { + pSpectralCoefficient[bin] = fMult(pSpectralCoefficient[bin], fact); + } + } + + /* adjust scaling */ + pSpecScale[0] += max_exponent; + + if (winSeq == EightShortSequence) { + int win; + for (win = 1; win < 8; win++) { + pSpecScale[win] += max_exponent; + } + } + } + else { + HANDLE_SBRDECODER hSbrDecoder = (HANDLE_SBRDECODER)pSbrDec; + + /* feed factors into SBR decoder for application in QMF domain. */ + sbrDecoder_drcFeedChannel ( + hSbrDecoder, + ch, + pDrcChData->numBands, + fact_mantissa, + max_exponent, + pDrcChData->drcInterpolationScheme, + winSeq, + pDrcChData->bandTop + ); + } + + return; +} + + +/* + * Prepare DRC processing + */ +int aacDecoder_drcProlog ( + HANDLE_AAC_DRC self, + HANDLE_FDK_BITSTREAM hBs, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[], + UCHAR pceInstanceTag, + UCHAR channelMapping[], /* Channel mapping translating drcChannel index to canonical channel index */ + int validChannels ) +{ + int err = 0; + + if (self == NULL) { + return -1; + } + + if (!self->params.bsDelayEnable) + { + err = aacDecoder_drcExtractAndMap ( + self, + hBs, + pAacDecoderStaticChannelInfo, + pceInstanceTag, + channelMapping, + validChannels ); + } + + return err; +} + + +/* + * Finalize DRC processing + */ +int aacDecoder_drcEpilog ( + HANDLE_AAC_DRC self, + HANDLE_FDK_BITSTREAM hBs, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[], + UCHAR pceInstanceTag, + UCHAR channelMapping[], /* Channel mapping translating drcChannel index to canonical channel index */ + int validChannels ) +{ + int err = 0; + + if (self == NULL) { + return -1; + } + + if (self->params.bsDelayEnable) + { + err = aacDecoder_drcExtractAndMap ( + self, + hBs, + pAacDecoderStaticChannelInfo, + pceInstanceTag, + channelMapping, + validChannels ); + } + + return err; +} + diff --git a/libAACdec/src/aacdec_drc.h b/libAACdec/src/aacdec_drc.h new file mode 100644 index 0000000..c48a720 --- /dev/null +++ b/libAACdec/src/aacdec_drc.h @@ -0,0 +1,105 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Christian Griebel + Description: Dynamic range control (DRC) decoder tool for AAC + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef AACDEC_DRC_H +#define AACDEC_DRC_H + +#include "tp_data.h" /* for program config element support */ + + +#include "aacdec_drc_types.h" +#include "channel.h" +#include "FDK_bitstream.h" + +#define AACDEC_DRC_DEFAULT_REF_LEVEL ( 108 ) /* -27 dB below full scale (typical for movies) */ +#define AACDEC_DRC_DFLT_EXPIRY_FRAMES ( 40 ) /* Default DRC data expiry time in AAC frames */ +#define MAX_SBR_SYN_CHAN ( 64 ) +#define MAX_SBR_COLS ( 32 ) + + +/** + * \brief DRC module setting parameters + */ +typedef enum +{ + DRC_CUT_SCALE = 0, + DRC_BOOST_SCALE, + TARGET_REF_LEVEL, + DRC_BS_DELAY, + DRC_DATA_EXPIRY_FRAME, + APPLY_HEAVY_COMPRESSION + +} AACDEC_DRC_PARAM; + + +/** + * \brief DRC module interface functions + */ +void aacDecoder_drcInit ( + HANDLE_AAC_DRC self ); + +void aacDecoder_drcInitChannelData ( + CDrcChannelData *pDrcChannel ); + +AAC_DECODER_ERROR aacDecoder_drcSetParam ( + HANDLE_AAC_DRC self, + AACDEC_DRC_PARAM param, + INT value ); + +int aacDecoder_drcMarkPayload ( + HANDLE_AAC_DRC self, + HANDLE_FDK_BITSTREAM hBs, + AACDEC_DRC_PAYLOAD_TYPE type ); + +int aacDecoder_drcProlog ( + HANDLE_AAC_DRC self, + HANDLE_FDK_BITSTREAM hBs, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[], + UCHAR pceInstanceTag, + UCHAR channelMapping[], + int numChannels ); + +void aacDecoder_drcApply ( + HANDLE_AAC_DRC self, + void *pSbrDec, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + CDrcChannelData *pDrcDat, + int ch, + int aacFrameSize, + int bSbrPresent ); + +int aacDecoder_drcEpilog ( + HANDLE_AAC_DRC self, + HANDLE_FDK_BITSTREAM hBs, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[], + UCHAR pceInstanceTag, + UCHAR channelMapping[], + int validChannels ); + + +#endif /* AACDEC_DRC_H */ diff --git a/libAACdec/src/aacdec_drc_types.h b/libAACdec/src/aacdec_drc_types.h new file mode 100644 index 0000000..20a593b --- /dev/null +++ b/libAACdec/src/aacdec_drc_types.h @@ -0,0 +1,104 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2010) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Christian Griebel + Description: Dynamic range control (DRC) global data types + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef AACDEC_DRC_TYPES_H +#define AACDEC_DRC_TYPES_H + + + +#include "common_fix.h" + + #define MAX_DRC_THREADS ( 3 ) /* Heavy compression value is handled just like MPEG DRC data */ +#define MAX_DRC_BANDS ( 16 ) /* 2^LEN_DRC_BAND_INCR (LEN_DRC_BAND_INCR = 4) */ + +/** + * \brief DRC module global data types + */ +typedef enum +{ + UNKNOWN_PAYLOAD = 0, + MPEG_DRC_EXT_DATA, + DVB_DRC_ANC_DATA + +} AACDEC_DRC_PAYLOAD_TYPE; + +typedef struct +{ + UINT expiryCount; + UINT numBands; + USHORT bandTop[MAX_DRC_BANDS]; + SHORT drcInterpolationScheme; + UCHAR drcValue[MAX_DRC_BANDS]; + +} CDrcChannelData; + +typedef struct +{ + AACDEC_DRC_PAYLOAD_TYPE type; + UINT excludedChnsMask; + SCHAR progRefLevel; + SCHAR pceInstanceTag; + + CDrcChannelData channelData; + +} CDrcPayload; + +typedef struct +{ + FIXP_DBL cut; + FIXP_DBL boost; + + UINT expiryFrame; + SCHAR targetRefLevel; + UCHAR bsDelayEnable; + UCHAR applyHeavyCompression; + +} CDrcParams; + + +typedef struct +{ + CDrcParams params; /* Module parameters that can be set by user (via SetParam API function) */ + + UCHAR enable; /* Switch that controls dynamic range processing */ + UCHAR digitalNorm; /* Switch to en-/disable reference level normalization in digital domain */ + + USHORT numPayloads; /* The number of DRC data payload elements found within frame */ + USHORT numThreads; /* The number of DRC data threads extracted from the found payload elements */ + SCHAR progRefLevel; /* Program reference level for all channels */ + + UCHAR dvbAncDataAvailable; /* Flag that indicates whether DVB ancillary data is present or not */ + UINT dvbAncDataPosition; /* Used to store the DVB ancillary data payload position in the bitstream (only one per frame) */ + UINT drcPayloadPosition[MAX_DRC_THREADS]; /* Used to store the DRC payload positions in the bitstream */ + +} CDrcInfo; + +typedef CDrcInfo *HANDLE_AAC_DRC; + +#endif /* AACDEC_DRC_TYPES_H */ + diff --git a/libAACdec/src/aacdec_hcr.cpp b/libAACdec/src/aacdec_hcr.cpp new file mode 100644 index 0000000..09dca79 --- /dev/null +++ b/libAACdec/src/aacdec_hcr.cpp @@ -0,0 +1,1529 @@ +/***************************** MPEG-4 AAC Decoder *************************** + + (C) Copyright Fraunhofer IIS 2000-2008 + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Robert Weidner (DSP Solutions) + Description: HCR Decoder: HCR initialization, preprocess HCR sideinfo, + decode priority codewords (PCWs) + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +*******************************************************************************/ + +#include "aacdec_hcr.h" + + + +#include "aacdec_hcr_types.h" +#include "aacdec_hcr_bit.h" +#include "aacdec_hcrs.h" +#include "aac_ram.h" +#include "aac_rom.h" +#include "channel.h" +#include "block.h" + +#include "aacdecoder.h" /* for ID_CPE, ID_SCE ... */ +#include "FDK_bitstream.h" + +extern int mlFileChCurr; + +static void errDetectorInHcrSideinfoShrt(SCHAR cb, + SHORT numLine, + UINT *errorWord); + +static void errDetectorInHcrLengths(SCHAR lengthOfLongestCodeword, + SHORT lengthOfReorderedSpectralData, + UINT *errorWord); + +static void HcrCalcNumCodeword (H_HCR_INFO pHcr); +static void HcrSortCodebookAndNumCodewordInSection(H_HCR_INFO pHcr); +static void HcrPrepareSegmentationGrid (H_HCR_INFO pHcr); +static void HcrExtendedSectionInfo (H_HCR_INFO pHcr); + +static void DeriveNumberOfExtendedSortedSectionsInSets(UINT numSegment, + USHORT *pNumExtendedSortedCodewordInSection, + int numExtendedSortedCodewordInSectionIdx, + USHORT *pNumExtendedSortedSectionsInSets, + int numExtendedSortedSectionsInSetsIdx); + +static INT DecodeEscapeSequence(HANDLE_FDK_BITSTREAM bs, + INT quantSpecCoef, + USHORT *pLeftStartOfSegment, + SCHAR *pRemainingBitsInSegment, + int *pNumDecodedBits + ); + +static int DecodePCW_Sign(HANDLE_FDK_BITSTREAM bs, + UINT codebookDim, + const SCHAR *pQuantVal, + FIXP_DBL *pQuantSpecCoef, + int *quantSpecCoefIdx, + USHORT *pLeftStartOfSegment, + SCHAR *pRemainingBitsInSegment, + int *pNumDecodedBits + ); + +static const SCHAR *DecodePCW_Body(HANDLE_FDK_BITSTREAM bs, + const UINT *pCurrentTree, + const SCHAR *pQuantValBase, + USHORT *pLeftStartOfSegment, + SCHAR *pRemainingBitsInSegment, + int *pNumDecodedBits + ); + +static void DecodePCWs(HANDLE_FDK_BITSTREAM bs, H_HCR_INFO pHcr); + +static void HcrReorderQuantizedSpectralCoefficients( + H_HCR_INFO pHcr, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + const SamplingRateInfo *pSamplingRateInfo + ); + + +#if CHECK_SEGMENTATION_IMMEDIATELY +static UCHAR errDetectPcwSegmentation(SCHAR remainingBitsInSegment, + H_HCR_INFO pHcr, + PCW_TYPE kind, + FIXP_DBL *qsc_base_of_cw, + UCHAR dimension); +#endif + +#if CHECK_SEGMENTATION_FINAL +static void errDetectWithinSegmentationFinal(H_HCR_INFO pHcr); +#endif + +/*--------------------------------------------------------------------------------------------- + description: Check if codebook and numSect are within allowed range (short only) +-------------------------------------------------------------------------------------------- */ +static void errDetectorInHcrSideinfoShrt(SCHAR cb, SHORT numLine,UINT* errorWord) +{ + + + + if ( cb < ZERO_HCB || cb >= MAX_CB_CHECK || cb == BOOKSCL ) { + *errorWord |= CB_OUT_OF_RANGE_SHORT_BLOCK; + } + if ( numLine < 0 || numLine > 1024 ) { + *errorWord |= LINE_IN_SECT_OUT_OF_RANGE_SHORT_BLOCK; + } +} + +/*--------------------------------------------------------------------------------------------- + description: Check both HCR lengths +-------------------------------------------------------------------------------------------- */ +static void errDetectorInHcrLengths(SCHAR lengthOfLongestCodeword, + SHORT lengthOfReorderedSpectralData, + UINT *errorWord) +{ + if ( lengthOfReorderedSpectralData < lengthOfLongestCodeword ) { + *errorWord |= HCR_SI_LENGTHS_FAILURE; + } +} + +/*--------------------------------------------------------------------------------------------- + description: Decode (and adapt if necessary) the two HCR sideinfo components: + 'reordered_spectral_data_length' and 'longest_codeword_length' +-------------------------------------------------------------------------------------------- */ + +void CHcr_Read(HANDLE_FDK_BITSTREAM bs, + CAacDecoderChannelInfo *pAacDecoderChannelInfo) +{ + INT globalHcrType = getHcrType(&pAacDecoderChannelInfo->pComData->overlay.aac.erHcrInfo); + SHORT lengOfReorderedSpectralData; + SCHAR lengOfLongestCodeword; + + pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfReorderedSpectralData = 0; + pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfLongestCodeword = 0; + + + + /* ------- SI-Value No 1 ------- */ + lengOfReorderedSpectralData = FDKreadBits(bs,14) + ERROR_LORSD; + if ( globalHcrType == ID_CPE ) { + if ((lengOfReorderedSpectralData >= 0) && (lengOfReorderedSpectralData <= CPE_TOP_LENGTH)) { + pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfReorderedSpectralData = lengOfReorderedSpectralData; /* the decoded value is within range */ + } + else { + if (lengOfReorderedSpectralData > CPE_TOP_LENGTH) { + pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfReorderedSpectralData = CPE_TOP_LENGTH; /* use valid maximum */ + } + } + } + else if (globalHcrType == ID_SCE || globalHcrType == ID_LFE || globalHcrType == ID_CCE ) { + if ((lengOfReorderedSpectralData >= 0) && (lengOfReorderedSpectralData <= SCE_TOP_LENGTH)) { + pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfReorderedSpectralData = lengOfReorderedSpectralData; /* the decoded value is within range */ + } + else { + if (lengOfReorderedSpectralData > SCE_TOP_LENGTH) { + pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfReorderedSpectralData = SCE_TOP_LENGTH; /* use valid maximum */ + } + } + } + + /* ------- SI-Value No 2 ------- */ + lengOfLongestCodeword = FDKreadBits(bs,6) + ERROR_LOLC; + if ((lengOfLongestCodeword >= 0) && (lengOfLongestCodeword <= LEN_OF_LONGEST_CW_TOP_LENGTH)) { + pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfLongestCodeword = lengOfLongestCodeword; /* the decoded value is within range */ + } + else { + if (lengOfLongestCodeword > LEN_OF_LONGEST_CW_TOP_LENGTH) { + pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfLongestCodeword = LEN_OF_LONGEST_CW_TOP_LENGTH; /* use valid maximum */ + } + } +} + + +/*--------------------------------------------------------------------------------------------- + description: Sets up HCR ROM-Tables +-------------------------------------------------------------------------------------------- */ + +void HcrInitRom(H_HCR_INFO pHcr) +{ + pHcr->cbPairs.pMinOfCbPair = aMinOfCbPair; + pHcr->cbPairs.pMaxOfCbPair = aMaxOfCbPair; + + pHcr->tableInfo.pMaxCwLength = aMaxCwLen; + pHcr->tableInfo.pCbDimension = aDimCb; + pHcr->tableInfo.pCbDimShift = aDimCbShift; + pHcr->tableInfo.pCbSign = aSignCb; + pHcr->tableInfo.pCbPriority = aCbPriority; + pHcr->tableInfo.pLargestAbsVal = aLargestAbsoluteValue; +} + +/*--------------------------------------------------------------------------------------------- + description: Set up HCR - must be called before every call to HcrDecoder(). + For short block a sorting algorithm is applied to get the SI in the order + that HCR could assemble the qsc's as if it is a long block. +----------------------------------------------------------------------------------------------- + return: error log +-------------------------------------------------------------------------------------------- */ + +UINT HcrInit(H_HCR_INFO pHcr, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + const SamplingRateInfo *pSamplingRateInfo, + HANDLE_FDK_BITSTREAM bs) +{ + CIcsInfo *pIcsInfo = &pAacDecoderChannelInfo->icsInfo; + SHORT *pNumLinesInSec; + UCHAR *pCodeBk; + SHORT numSection; + SCHAR cb; + int numLine; + int i; + + pHcr->decInOut.lengthOfReorderedSpectralData = pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfReorderedSpectralData; + pHcr->decInOut.lengthOfLongestCodeword = pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfLongestCodeword; + pHcr->decInOut.pQuantizedSpectralCoefficientsBase = pAacDecoderChannelInfo->pSpectralCoefficient; + pHcr->decInOut.quantizedSpectralCoefficientsIdx = 0; + pHcr->decInOut.pCodebook = pAacDecoderChannelInfo->pDynData->specificTo.aac.aCodeBooks4Hcr; + pHcr->decInOut.pNumLineInSect = pAacDecoderChannelInfo->pDynData->specificTo.aac.aNumLineInSec4Hcr; + pHcr->decInOut.numSection = pAacDecoderChannelInfo->pDynData->specificTo.aac.numberSection; + pHcr->decInOut.errorLog = 0; + pHcr->nonPcwSideinfo.pResultBase = SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient); + + FDKsyncCache(bs); + pHcr->decInOut.bitstreamIndex = FDKgetBitCnt(bs); + + if (!IsLongBlock(&pAacDecoderChannelInfo->icsInfo)) /* short block */ + { + SHORT band; + SHORT maxBand; + SCHAR group; + SCHAR winGroupLen; + SCHAR window; + SCHAR numUnitInBand; + SCHAR cntUnitInBand; + SCHAR groupWin; + SCHAR cb_prev; + + UCHAR *pCodeBook; + const SHORT *BandOffsets; + SCHAR numOfGroups; + + + pCodeBook = pAacDecoderChannelInfo->pDynData->aCodeBook; /* in */ + pNumLinesInSec = pHcr->decInOut.pNumLineInSect; /* out */ + pCodeBk = pHcr->decInOut.pCodebook; /* out */ + BandOffsets = GetScaleFactorBandOffsets(pIcsInfo, pSamplingRateInfo); /* aux */ + numOfGroups = GetWindowGroups(pIcsInfo); + + numLine = 0; + numSection = 0; + cb = pCodeBook[0]; + cb_prev = pCodeBook[0]; + + /* convert HCR-sideinfo into a unitwise manner: When the cb changes, a new section starts */ + + *pCodeBk++ = cb_prev; + + maxBand = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); + for (band = 0; band < maxBand; band++) { /* from low to high sfbs i.e. from low to high frequencies */ + numUnitInBand = ((BandOffsets[band+1] - BandOffsets[band]) >> FOUR_LOG_DIV_TWO_LOG); /* get the number of units in current sfb */ + for (cntUnitInBand = numUnitInBand; cntUnitInBand != 0; cntUnitInBand-- ) { /* for every unit in the band */ + for (window = 0, group = 0; group < numOfGroups; group++) { + winGroupLen = GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo,group); + for (groupWin = winGroupLen; groupWin != 0; groupWin--, window++) { + cb = pCodeBook[group * 16 + band]; + if (cb != cb_prev) { +#if CHECK_VALID_HCR_INPUT /* short-block 1 of 2 */ + errDetectorInHcrSideinfoShrt(cb,numLine,&pHcr->decInOut.errorLog ); + if (pHcr->decInOut.errorLog != 0 ) { + return ( pHcr->decInOut.errorLog ); + } +#endif + *pCodeBk++ = cb; + *pNumLinesInSec++ = numLine; + numSection++; + + cb_prev = cb; + numLine = LINES_PER_UNIT; + } + else { + numLine += LINES_PER_UNIT; + } + } + } + } + } + + numSection++; + +#if CHECK_VALID_HCR_INPUT /* short-block 2 of 2 */ + errDetectorInHcrSideinfoShrt(cb,numLine,&pHcr->decInOut.errorLog ); + if ( numSection <= 0 || numSection > 1024/2 ) { + pHcr->decInOut.errorLog |= NUM_SECT_OUT_OF_RANGE_SHORT_BLOCK; + } + errDetectorInHcrLengths(pHcr->decInOut.lengthOfLongestCodeword, + pHcr->decInOut.lengthOfReorderedSpectralData, + &pHcr->decInOut.errorLog); + if (pHcr->decInOut.errorLog != 0 ) { + return ( pHcr->decInOut.errorLog ); + } +#endif + + *pCodeBk = cb; + *pNumLinesInSec = numLine; + pHcr->decInOut.numSection = numSection; + + } else /* end short block prepare SI */ + { /* long block */ +#if CHECK_VALID_HCR_INPUT /* long-block 1 of 1 */ + errDetectorInHcrLengths(pHcr->decInOut.lengthOfLongestCodeword, + pHcr->decInOut.lengthOfReorderedSpectralData, + &pHcr->decInOut.errorLog); + numSection = pHcr->decInOut.numSection; + pNumLinesInSec = pHcr->decInOut.pNumLineInSect; + pCodeBk = pHcr->decInOut.pCodebook; + if ( numSection <= 0 || numSection > 64 ) { + pHcr->decInOut.errorLog |= NUM_SECT_OUT_OF_RANGE_LONG_BLOCK; + numSection = 0; + } + + for ( i = numSection; i != 0; i-- ) + { + cb = *pCodeBk++; + + if ( cb < ZERO_HCB || cb >= MAX_CB_CHECK || cb == BOOKSCL ) { + pHcr->decInOut.errorLog |= CB_OUT_OF_RANGE_LONG_BLOCK; + } + + numLine = *pNumLinesInSec++; + /* FDK_ASSERT(numLine > 0); */ + + if ( (numLine <= 0) || (numLine > 1024) ) { + pHcr->decInOut.errorLog |= LINE_IN_SECT_OUT_OF_RANGE_LONG_BLOCK; + } + } + if (pHcr->decInOut.errorLog != 0 ) { + return ( pHcr->decInOut.errorLog ); + } +#endif /* CHECK_VALID_HCR_INPUT */ + } + + pCodeBk = pHcr->decInOut.pCodebook; + for ( i = 0; i < numSection; i++ ) { + if ( + (*pCodeBk == NOISE_HCB) || + (*pCodeBk == INTENSITY_HCB2) || + (*pCodeBk == INTENSITY_HCB)) + { + *pCodeBk = 0; + } + pCodeBk++; + } + + /* HCR-sideinfo-input is complete and seems to be valid */ + + + + return ( pHcr->decInOut.errorLog ); +} + + + + +#if USE_HCR_DUMMY + +/*--------------------------------------------------------------------------------------------- + + description: This HCR - dummy - function writes only a dirac-sequence in output buffer + +-------------------------------------------------------------------------------------------- */ +UINT HcrDecoder(H_HCR_INFO pHcr, + const CAacDecoderChannelInfo *pAacDecoderChannelInfo, + HANDLE_FDK_BITSTREAM bs) +{ + for (SHORT i=0; i < 1024; i++ ) { + pHcr->decInOut.pQuantizedSpectralCoefficients->Long[i] = FL2FXCONST_DBL(0.0f); + if ( i % 30 == 0) { + pHcr->decInOut.pQuantizedSpectralCoefficients->Long[i] = (FIXP_DBL)HCR_DIRAC; + } + } + return 0; +} + +#else /* USE_HCR_DUMMY */ + +/*--------------------------------------------------------------------------------------------- + description: This function decodes the codewords of the spectral coefficients from the + bitstream according to the HCR algorithm and stores the quantized spectral + coefficients in correct order in the output buffer. +-------------------------------------------------------------------------------------------- */ + +UINT HcrDecoder(H_HCR_INFO pHcr, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + const SamplingRateInfo *pSamplingRateInfo, + HANDLE_FDK_BITSTREAM bs) +{ + int pTmp1, pTmp2, pTmp3, pTmp4; +#if DETECT_TOO_LONG_CW_READS + int pTmp5; +#endif + + INT bitCntOffst; + UINT saveBitCnt = FDKgetBitCnt(bs); /* save bitstream position */ + + HcrCalcNumCodeword(pHcr); + + HcrSortCodebookAndNumCodewordInSection(pHcr); + + HcrPrepareSegmentationGrid(pHcr); + + HcrExtendedSectionInfo(pHcr); + + if (( pHcr->decInOut.errorLog & HCR_FATAL_PCW_ERROR_MASK ) != 0 ) { + return ( pHcr->decInOut.errorLog ); /* sideinfo is massively corrupt, return from HCR without having decoded anything */ + } + + DeriveNumberOfExtendedSortedSectionsInSets(pHcr->segmentInfo.numSegment, + pHcr->sectionInfo.pNumExtendedSortedCodewordInSection, + pHcr->sectionInfo.numExtendedSortedCodewordInSectionIdx, + pHcr->sectionInfo.pNumExtendedSortedSectionsInSets, + pHcr->sectionInfo.numExtendedSortedSectionsInSetsIdx); + + /* store */ + pTmp1 = pHcr->sectionInfo.numExtendedSortedCodewordInSectionIdx; + pTmp2 = pHcr->sectionInfo.extendedSortedCodebookIdx; + pTmp3 = pHcr->sectionInfo.numExtendedSortedSectionsInSetsIdx; + pTmp4 = pHcr->decInOut.quantizedSpectralCoefficientsIdx; +#if DETECT_TOO_LONG_CW_READS + pTmp5 = pHcr->sectionInfo.maxLenOfCbInExtSrtSecIdx; +#endif + + /* ------- decode meaningful PCWs ------ */ + DecodePCWs(bs, pHcr); + + if (( pHcr->decInOut.errorLog & HCR_FATAL_PCW_ERROR_MASK ) == 0 ) { + /* ------ decode the non-PCWs -------- */ + DecodeNonPCWs(bs, pHcr); + } + + +#if CHECK_SEGMENTATION_FINAL + errDetectWithinSegmentationFinal(pHcr); +#endif + + /* restore */ + pHcr->sectionInfo.numExtendedSortedCodewordInSectionIdx = pTmp1; + pHcr->sectionInfo.extendedSortedCodebookIdx = pTmp2; + pHcr->sectionInfo.numExtendedSortedSectionsInSetsIdx = pTmp3; + pHcr->decInOut.quantizedSpectralCoefficientsIdx = pTmp4; +#if DETECT_TOO_LONG_CW_READS + pHcr->sectionInfo.maxLenOfCbInExtSrtSecIdx = pTmp5; +#endif + + HcrReorderQuantizedSpectralCoefficients(pHcr, pAacDecoderChannelInfo, pSamplingRateInfo); + + /* restore bitstream position */ + bitCntOffst = saveBitCnt - FDKgetBitCnt(bs); + if( bitCntOffst ) { + FDKpushBiDirectional(bs, bitCntOffst); + } + + return ( pHcr->decInOut.errorLog ); +} + + +#endif /* USE_HCR_DUMMY */ + + + + +/*--------------------------------------------------------------------------------------------- + description: This function reorders the quantized spectral coefficients sectionwise for + long- and short-blocks and compares to the LAV (Largest Absolute Value of + the current codebook) -- a counter is incremented if there is an error + detected. + Additional for short-blocks a unit-based-deinterleaving is applied. + Moreover (for short blocks) the scaling is derived (compare plain huffman + decoder). +-------------------------------------------------------------------------------------------- */ + +static void HcrReorderQuantizedSpectralCoefficients( + H_HCR_INFO pHcr, CAacDecoderChannelInfo *pAacDecoderChannelInfo, + const SamplingRateInfo *pSamplingRateInfo + ) +{ + INT qsc; + UINT abs_qsc; + UINT i,j; + USHORT numSpectralValuesInSection; + FIXP_DBL *pTeVa; + USHORT lavErrorCnt = 0; + + UINT numSection = pHcr->decInOut.numSection; + SPECTRAL_PTR pQuantizedSpectralCoefficientsBase = pHcr->decInOut.pQuantizedSpectralCoefficientsBase; + FIXP_DBL *pQuantizedSpectralCoefficients = SPEC_LONG(pHcr->decInOut.pQuantizedSpectralCoefficientsBase); + const UCHAR *pCbDimShift = pHcr->tableInfo.pCbDimShift; + const USHORT *pLargestAbsVal = pHcr->tableInfo.pLargestAbsVal; + UCHAR *pSortedCodebook = pHcr->sectionInfo.pSortedCodebook; + USHORT *pNumSortedCodewordInSection = pHcr->sectionInfo.pNumSortedCodewordInSection; + USHORT *pReorderOffset = pHcr->sectionInfo.pReorderOffset; + FIXP_DBL *pTempValues = pHcr->segmentInfo.pTempValues; + FIXP_DBL *pBak = pHcr->segmentInfo.pTempValues; + + FDKmemclear(pTempValues,1024*sizeof(FIXP_DBL)); + + /* long and short: check if decoded huffman-values (quantized spectral coefficients) are within range */ + for ( i=numSection; i != 0; i-- ) { + numSpectralValuesInSection = *pNumSortedCodewordInSection++ << pCbDimShift[*pSortedCodebook]; + pTeVa = &pTempValues[*pReorderOffset++]; + for( j = numSpectralValuesInSection; j != 0; j-- ) { + qsc = *pQuantizedSpectralCoefficients++; + abs_qsc = FDKabs(qsc); +#if VALID_LAV_ERROR_TRIGGER + if ( abs_qsc <= pLargestAbsVal[*pSortedCodebook] ) { + *pTeVa++ = (FIXP_DBL)qsc; /* the qsc value is within range */ + } + else { /* line is too high .. */ + if ( abs_qsc == Q_VALUE_INVALID ) { /* .. because of previous marking --> dont set LAV flag (would be confusing), just copy out the already marked value */ + *pTeVa++ = (FIXP_DBL) qsc; + } + else { /* .. because a too high value was decoded for this cb --> set LAV flag */ + *pTeVa++ = (FIXP_DBL) Q_VALUE_INVALID; + lavErrorCnt += 1; + } + } +#else + if ( abs_qsc <= pLargestAbsVal[*pSortedCodebook] ) { + *pTeVa++ = qsc; + } + else { + *pTeVa++ = Q_VALUE_INVALID; + lavErrorCnt += 1; + } +#endif + } + pSortedCodebook++; + } + + if (!IsLongBlock(&pAacDecoderChannelInfo->icsInfo)) + { + FIXP_DBL *pOut; + FIXP_DBL locMax; + FIXP_DBL tmp; + SCHAR groupoffset; + SCHAR group; + SCHAR band; + SCHAR groupwin; + SCHAR window; + SCHAR numWinGroup; + SHORT interm; + SCHAR numSfbTransm; + SCHAR winGroupLen; + SHORT index; + INT msb; + INT lsb; + + SHORT *pScaleFacHcr = pAacDecoderChannelInfo->pDynData->aScaleFactor; + SHORT *pSfbSclHcr = pAacDecoderChannelInfo->pDynData->aSfbScale; + const SHORT *BandOffsets = GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo); + + pBak = pHcr->segmentInfo.pTempValues; + /* deinterleave unitwise for short blocks */ + for ( window = 0; window < (8); window++ ) { + pOut = SPEC(pQuantizedSpectralCoefficientsBase, window, pAacDecoderChannelInfo->granuleLength); + for ( i=0; i < (LINES_PER_UNIT_GROUP); i++ ) { + pTeVa = pBak + (window << FOUR_LOG_DIV_TWO_LOG) + i * 32; /* distance of lines between unit groups has to be constant for every framelength (32)! */ + for ( j=(LINES_PER_UNIT); j != 0; j-- ) { + *pOut++ = *pTeVa++; + } + } + } + + /* short blocks only */ + /* derive global scaling-value for every sfb and every window (as it is done in plain-huffman-decoder at short blocks) */ + groupoffset = 0; + + numWinGroup = GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); + numSfbTransm = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); + + for (group = 0; group < numWinGroup; group++) { + winGroupLen = GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo,group); + for (band = 0; band < numSfbTransm; band++) { + interm = group * 16 + band; + msb = pScaleFacHcr[interm] >> 2; + lsb = pScaleFacHcr[interm] & 3; + for (groupwin = 0; groupwin < winGroupLen; groupwin++) { + window = groupoffset + groupwin; + pBak = SPEC(pQuantizedSpectralCoefficientsBase, window, pAacDecoderChannelInfo->granuleLength); + locMax = FL2FXCONST_DBL(0.0f); + for (index = BandOffsets[band]; index < BandOffsets[band+1]; index += LINES_PER_UNIT) { + pTeVa = &pBak[index]; + for ( i = LINES_PER_UNIT; i != 0; i --) { + tmp = (*pTeVa < FL2FXCONST_DBL(0.0f))? -*pTeVa++ : *pTeVa++; + locMax = fixMax(tmp,locMax); + } + } + if ( fixp_abs(locMax) > (FIXP_DBL)MAX_QUANTIZED_VALUE ) { + locMax = (FIXP_DBL)MAX_QUANTIZED_VALUE; + } + pSfbSclHcr[window*16+band] = msb - GetScaleFromValue(locMax, lsb); /* save global scale maxima in this sfb */ + } + } + groupoffset += GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo,group); + } + } else + { + /* copy straight for long-blocks */ + pQuantizedSpectralCoefficients = SPEC_LONG(pQuantizedSpectralCoefficientsBase); + for ( i = 1024; i != 0; i-- ) { + *pQuantizedSpectralCoefficients++ = *pBak++; + } + } + + if ( lavErrorCnt != 0 ) { + pHcr->decInOut.errorLog |= LAV_VIOLATION; + } +} + + +/*--------------------------------------------------------------------------------------------- + description: This function calculates the number of codewords + for each section (numCodewordInSection) and the number of codewords + for all sections (numCodeword). + For zero and intensity codebooks a entry is also done in the variable + numCodewordInSection. It is assumed that the codebook is a two tuples + codebook. This is needed later for the calculation of the base addresses + for the reordering of the quantize spectral coefficients at the end of the + hcr tool. + The variable numCodeword contain the number of codewords which are really + in the bitstream. Zero or intensity codebooks does not increase the + variable numCodewords. +----------------------------------------------------------------------------------------------- + return: - +-------------------------------------------------------------------------------------------- */ + +static void HcrCalcNumCodeword(H_HCR_INFO pHcr) +{ + int hcrSection; + UINT numCodeword; + + UINT numSection = pHcr->decInOut.numSection; + UCHAR *pCodebook = pHcr->decInOut.pCodebook; + SHORT *pNumLineInSection = pHcr->decInOut.pNumLineInSect; + const UCHAR *pCbDimShift = pHcr->tableInfo.pCbDimShift; + USHORT *pNumCodewordInSection = pHcr->sectionInfo.pNumCodewordInSection; + + numCodeword = 0; + for ( hcrSection = numSection; hcrSection != 0; hcrSection-- ) { + *pNumCodewordInSection = *pNumLineInSection++ >> pCbDimShift[*pCodebook]; + if ( *pCodebook != 0 ) { + numCodeword += *pNumCodewordInSection; + } + pNumCodewordInSection++; + pCodebook++; + } + pHcr->sectionInfo.numCodeword = numCodeword; +} + + +/*--------------------------------------------------------------------------------------------- + description: This function calculates the number + of sorted codebooks and sorts the codebooks and the numCodewordInSection + according to the priority. +-------------------------------------------------------------------------------------------- */ + +static void HcrSortCodebookAndNumCodewordInSection(H_HCR_INFO pHcr) +{ + + UINT i,j,k; + UCHAR temp; + UINT counter; + UINT startOffset; + UINT numZeroSection; + UCHAR *pDest; + UINT numSectionDec; + + UINT numSection = pHcr->decInOut.numSection; + UCHAR *pCodebook = pHcr->decInOut.pCodebook; + UCHAR *pSortedCodebook = pHcr->sectionInfo.pSortedCodebook; + USHORT *pNumCodewordInSection = pHcr->sectionInfo.pNumCodewordInSection; + USHORT *pNumSortedCodewordInSection = pHcr->sectionInfo.pNumSortedCodewordInSection; + UCHAR *pCodebookSwitch = pHcr->sectionInfo.pCodebookSwitch; + USHORT *pReorderOffset = pHcr->sectionInfo.pReorderOffset; + const UCHAR *pCbPriority = pHcr->tableInfo.pCbPriority; + const UCHAR *pMinOfCbPair = pHcr->cbPairs.pMinOfCbPair; + const UCHAR *pMaxOfCbPair = pHcr->cbPairs.pMaxOfCbPair; + const UCHAR *pCbDimShift = pHcr->tableInfo.pCbDimShift; + + UINT searchStart = 0; + + /* calculate *pNumSortedSection and store the priorities in array pSortedCdebook */ + pDest = pSortedCodebook; + numZeroSection = 0; + for ( i=numSection; i != 0; i-- ) { + if ( pCbPriority[*pCodebook] == 0 ) { + numZeroSection += 1; + } + *pDest++ = pCbPriority[*pCodebook++]; + } + pHcr->sectionInfo.numSortedSection = numSection - numZeroSection; /* numSortedSection contains no zero or intensity section */ + pCodebook = pHcr->decInOut.pCodebook; + + /* sort priorities of the codebooks in array pSortedCdebook[] */ + numSectionDec = numSection - 1; + if ( numSectionDec > 0 ) { + counter = numSectionDec; + for ( j=numSectionDec; j != 0; j-- ) { + for ( i=0; i < counter; i++ ) { + /* swap priorities */ + if ( pSortedCodebook[i+1] > pSortedCodebook[i] ) { + temp = pSortedCodebook[i]; + pSortedCodebook[i] = pSortedCodebook[i+1]; + pSortedCodebook[i+1] = temp; + } + } + counter -= 1; + } + } + + /* clear codebookSwitch array */ + for ( i = numSection; i != 0; i--) { + *pCodebookSwitch++ = 0; + } + pCodebookSwitch = pHcr->sectionInfo.pCodebookSwitch; + + /* sort sectionCodebooks and numCodwordsInSection and calculate pReorderOffst[j] */ + for ( j = 0; j < numSection; j++ ) { + for ( i = searchStart; i < numSection; i++ ) { + if ( pCodebookSwitch[i] == 0 && ( pMinOfCbPair[pSortedCodebook[j]] == pCodebook[i] || pMaxOfCbPair[pSortedCodebook[j]] == pCodebook[i] )) { + pCodebookSwitch[i] = 1; + pSortedCodebook[j] = pCodebook[i]; /* sort codebook */ + pNumSortedCodewordInSection[j] = pNumCodewordInSection[i]; /* sort NumCodewordInSection */ + + startOffset = 0; + for ( k = 0; k < i; k++ ) { /* make entry in pReorderOffst */ + startOffset += pNumCodewordInSection[k] << pCbDimShift[pCodebook[k]]; + } + pReorderOffset[j] = startOffset; /* offset for reordering the codewords */ + + if(i == searchStart) { + UINT k = i; + while(pCodebookSwitch[k++] == 1) searchStart++; + } + break; + } + } + } +} + + +/*--------------------------------------------------------------------------------------------- + description: This function calculates the segmentation, which includes numSegment, + leftStartOfSegment, rightStartOfSegment and remainingBitsInSegment. + The segmentation could be visualized a as kind of 'overlay-grid' for the + bitstream-block holding the HCR-encoded quantized-spectral-coefficients. +-------------------------------------------------------------------------------------------- */ + +static void HcrPrepareSegmentationGrid(H_HCR_INFO pHcr) +{ + USHORT i,j; + USHORT numSegment = 0; + USHORT segmentStart = 0; + UCHAR segmentWidth; + UCHAR lastSegmentWidth; + UCHAR sortedCodebook; + UCHAR endFlag = 0; + USHORT intermediateResult; + + SCHAR lengthOfLongestCodeword = pHcr->decInOut.lengthOfLongestCodeword; + SHORT lengthOfReorderedSpectralData = pHcr->decInOut.lengthOfReorderedSpectralData; + UINT numSortedSection = pHcr->sectionInfo.numSortedSection; + UCHAR *pSortedCodebook = pHcr->sectionInfo.pSortedCodebook; + USHORT *pNumSortedCodewordInSection = pHcr->sectionInfo.pNumSortedCodewordInSection; + USHORT *pLeftStartOfSegment = pHcr->segmentInfo.pLeftStartOfSegment; + USHORT *pRightStartOfSegment = pHcr->segmentInfo.pRightStartOfSegment; + SCHAR *pRemainingBitsInSegment = pHcr->segmentInfo.pRemainingBitsInSegment; + USHORT bitstreamIndex = pHcr->decInOut.bitstreamIndex; + const UCHAR *pMaxCwLength = pHcr->tableInfo.pMaxCwLength; + + for ( i=numSortedSection; i != 0; i-- ) { + sortedCodebook = *pSortedCodebook++; + segmentWidth = FDKmin(pMaxCwLength[sortedCodebook],lengthOfLongestCodeword); + + for ( j = *pNumSortedCodewordInSection; j != 0 ; j-- ) { + /* width allows a new segment */ + intermediateResult = bitstreamIndex + segmentStart; + if ( (segmentStart + segmentWidth) <= lengthOfReorderedSpectralData ) { + /* store segment start, segment length and increment the number of segments */ + *pLeftStartOfSegment++ = intermediateResult; + *pRightStartOfSegment++ = intermediateResult + segmentWidth - 1; + *pRemainingBitsInSegment++ = segmentWidth; + segmentStart += segmentWidth; + numSegment += 1; + } + /* width does not allow a new segment */ + else { + /* correct the last segment length */ + pLeftStartOfSegment--; + pRightStartOfSegment--; + pRemainingBitsInSegment--; + segmentStart = *pLeftStartOfSegment - bitstreamIndex; + + lastSegmentWidth = lengthOfReorderedSpectralData - segmentStart; + *pRemainingBitsInSegment = lastSegmentWidth; + *pRightStartOfSegment = bitstreamIndex + segmentStart + lastSegmentWidth - 1; + endFlag = 1; + break; + } + } + pNumSortedCodewordInSection++; + if (endFlag != 0) { + break; + } + } + pHcr->segmentInfo.numSegment = numSegment; + +} + + +/*--------------------------------------------------------------------------------------------- + description: This function adapts the sorted section boundaries to the boundaries of + segmentation. If the section lengths does not fit completely into the + current segment, the section is spitted into two so called 'extended + sections'. The extended-section-info (pNumExtendedSortedCodewordInSectin + and pExtendedSortedCodebook) is updated in this case. + +-------------------------------------------------------------------------------------------- */ + +static void HcrExtendedSectionInfo(H_HCR_INFO pHcr) +{ + UINT srtSecCnt = 0; /* counter for sorted sections */ + UINT xSrtScCnt = 0; /* counter for extended sorted sections */ + UINT remainNumCwInSortSec; + UINT inSegmentRemainNumCW; + + UINT numSortedSection = pHcr->sectionInfo.numSortedSection; + UCHAR *pSortedCodebook = pHcr->sectionInfo.pSortedCodebook; + USHORT *pNumSortedCodewordInSection = pHcr->sectionInfo.pNumSortedCodewordInSection; + UCHAR *pExtendedSortedCoBo = pHcr->sectionInfo.pExtendedSortedCodebook; + USHORT *pNumExtSortCwInSect = pHcr->sectionInfo.pNumExtendedSortedCodewordInSection; + UINT numSegment = pHcr->segmentInfo.numSegment; +#if DETECT_TOO_LONG_CW_READS + UCHAR *pMaxLenOfCbInExtSrtSec = pHcr->sectionInfo.pMaxLenOfCbInExtSrtSec; + SCHAR lengthOfLongestCodeword = pHcr->decInOut.lengthOfLongestCodeword; + const UCHAR *pMaxCwLength = pHcr->tableInfo.pMaxCwLength; +#endif + + remainNumCwInSortSec = pNumSortedCodewordInSection[srtSecCnt]; + inSegmentRemainNumCW = numSegment; + + while (srtSecCnt < numSortedSection) { + if (inSegmentRemainNumCW < remainNumCwInSortSec) { + + pNumExtSortCwInSect[xSrtScCnt] = inSegmentRemainNumCW; + pExtendedSortedCoBo[xSrtScCnt] = pSortedCodebook[srtSecCnt]; + + remainNumCwInSortSec -= inSegmentRemainNumCW; + inSegmentRemainNumCW = numSegment; + /* data of a sorted section was not integrated in extended sorted section */ + } + else if (inSegmentRemainNumCW == remainNumCwInSortSec) { + pNumExtSortCwInSect[xSrtScCnt] = inSegmentRemainNumCW; + pExtendedSortedCoBo[xSrtScCnt] = pSortedCodebook[srtSecCnt]; + + srtSecCnt++; + remainNumCwInSortSec = pNumSortedCodewordInSection[srtSecCnt]; + inSegmentRemainNumCW = numSegment; + /* data of a sorted section was integrated in extended sorted section */ + } + else { /* inSegmentRemainNumCW > remainNumCwInSortSec */ + pNumExtSortCwInSect[xSrtScCnt] = remainNumCwInSortSec; + pExtendedSortedCoBo[xSrtScCnt] = pSortedCodebook[srtSecCnt]; + + + inSegmentRemainNumCW -= remainNumCwInSortSec; + srtSecCnt++; + remainNumCwInSortSec = pNumSortedCodewordInSection[srtSecCnt]; + /* data of a sorted section was integrated in extended sorted section */ + } +#if DETECT_TOO_LONG_CW_READS + pMaxLenOfCbInExtSrtSec[xSrtScCnt] = FDKmin(pMaxCwLength[pExtendedSortedCoBo[xSrtScCnt]],lengthOfLongestCodeword); +#endif + + + + xSrtScCnt += 1; + + if ( xSrtScCnt >= (MAX_SFB_HCR + MAX_HCR_SETS) ) { + pHcr->decInOut.errorLog |= EXTENDED_SORTED_COUNTER_OVERFLOW; + return; + } + + } + pNumExtSortCwInSect[xSrtScCnt] = 0; + +} + + +/*--------------------------------------------------------------------------------------------- + description: This function calculates the number of extended sorted sections which + belong to the sets. Each set from set 0 (one and only set for the PCWs) + till to the last set gets a entry in the array to which + 'pNumExtendedSortedSectinsInSets' points to. + + Calculation: The entrys in pNumExtendedSortedCodewordInSectin are added + untill the value numSegment is reached. Then the sum_variable is cleared + and the calculation starts from the beginning. As much extended sorted + Sections are summed up to reach the value numSegment, as much is the + current entry in *pNumExtendedSortedCodewordInSectin. +-------------------------------------------------------------------------------------------- */ +static void DeriveNumberOfExtendedSortedSectionsInSets(UINT numSegment, + USHORT *pNumExtendedSortedCodewordInSection, + int numExtendedSortedCodewordInSectionIdx, + USHORT *pNumExtendedSortedSectionsInSets, + int numExtendedSortedSectionsInSetsIdx) +{ + USHORT counter = 0; + UINT cwSum = 0; + USHORT *pNumExSortCwInSec = pNumExtendedSortedCodewordInSection; + USHORT *pNumExSortSecInSets = pNumExtendedSortedSectionsInSets; + + while (pNumExSortCwInSec[numExtendedSortedCodewordInSectionIdx] != 0) + { + cwSum += pNumExSortCwInSec[numExtendedSortedCodewordInSectionIdx]; + numExtendedSortedCodewordInSectionIdx++; + if (numExtendedSortedCodewordInSectionIdx >= (MAX_SFB_HCR+MAX_HCR_SETS)) { + return; + } + if (cwSum > numSegment) { + return; + } + counter++; + if (counter > 1024/4) { + return; + } + if ( cwSum == numSegment ) { + pNumExSortSecInSets[numExtendedSortedSectionsInSetsIdx] = counter; + numExtendedSortedSectionsInSetsIdx++; + if (numExtendedSortedSectionsInSetsIdx >= MAX_HCR_SETS) { + return; + } + counter = 0; + cwSum = 0; + } + } + pNumExSortSecInSets[numExtendedSortedSectionsInSetsIdx] = counter; /* save last entry for the last - probably shorter - set */ +} + + +/*--------------------------------------------------------------------------------------------- + description: This function decodes all priority codewords (PCWs) in a spectrum (within + set 0). The calculation of the PCWs is managed in two loops. The + loopcounter of the outer loop is set to the first value pointer + pNumExtendedSortedSectionsInSets points to. This value represents the + number of extended sorted sections within set 0. + The loopcounter of the inner loop is set to the first value pointer + pNumExtendedSortedCodewordInSectin points to. The value represents the + number of extended sorted codewords in sections (the original sections have + been splitted to go along with the borders of the sets). + Each time the number of the extended sorted codewords in sections are de- + coded, the pointer 'pNumExtendedSortedCodewordInSectin' is incremented by + one. +-------------------------------------------------------------------------------------------- */ +static void DecodePCWs(HANDLE_FDK_BITSTREAM bs, H_HCR_INFO pHcr) +{ + UINT i; + USHORT extSortSec; + USHORT curExtSortCwInSec; + UCHAR codebook; + UCHAR dimension; + const UINT *pCurrentTree; + const SCHAR *pQuantValBase; + const SCHAR *pQuantVal; + + USHORT *pNumExtendedSortedCodewordInSection = pHcr->sectionInfo.pNumExtendedSortedCodewordInSection; + int numExtendedSortedCodewordInSectionIdx = pHcr->sectionInfo.numExtendedSortedCodewordInSectionIdx; + UCHAR *pExtendedSortedCodebook = pHcr->sectionInfo.pExtendedSortedCodebook; + int extendedSortedCodebookIdx = pHcr->sectionInfo.extendedSortedCodebookIdx; + USHORT *pNumExtendedSortedSectionsInSets = pHcr->sectionInfo.pNumExtendedSortedSectionsInSets; + int numExtendedSortedSectionsInSetsIdx = pHcr->sectionInfo.numExtendedSortedSectionsInSetsIdx; + FIXP_DBL *pQuantizedSpectralCoefficients = SPEC_LONG(pHcr->decInOut.pQuantizedSpectralCoefficientsBase); + int quantizedSpectralCoefficientsIdx = pHcr->decInOut.quantizedSpectralCoefficientsIdx; + USHORT *pLeftStartOfSegment = pHcr->segmentInfo.pLeftStartOfSegment; + SCHAR *pRemainingBitsInSegment = pHcr->segmentInfo.pRemainingBitsInSegment; +#if DETECT_TOO_LONG_CW_READS + UCHAR *pMaxLenOfCbInExtSrtSec = pHcr->sectionInfo.pMaxLenOfCbInExtSrtSec; + int maxLenOfCbInExtSrtSecIdx = pHcr->sectionInfo.maxLenOfCbInExtSrtSecIdx; + UCHAR maxAllowedCwLen; + int numDecodedBits; +#endif + const UCHAR *pCbDimension = pHcr->tableInfo.pCbDimension; + const UCHAR *pCbSign = pHcr->tableInfo.pCbSign; + + /* clear result array */ + //pQSC = &pQuantizedSpectralCoefficients[quantizedSpectralCoefficientsIdx]; + //pQSC = *pQuantizedSpectralCoefficients; + + FDKmemclear(pQuantizedSpectralCoefficients+quantizedSpectralCoefficientsIdx,1024*sizeof(FIXP_DBL)); + + /* decode all PCWs in the extended sorted section(s) belonging to set 0 */ + for ( extSortSec = pNumExtendedSortedSectionsInSets[numExtendedSortedSectionsInSetsIdx]; extSortSec != 0; extSortSec-- ) { + + codebook = pExtendedSortedCodebook[extendedSortedCodebookIdx]; /* get codebook for this extended sorted section and increment ptr to cb of next ext. sort sec */ + extendedSortedCodebookIdx++; + if (extendedSortedCodebookIdx >= (MAX_SFB_HCR+MAX_HCR_SETS)) { + return; + } + dimension = pCbDimension[codebook]; /* get dimension of codebook of this extended sort. sec. */ + pCurrentTree = aHuffTable [codebook]; /* convert codebook to pointer to QSCs */ + pQuantValBase = aQuantTable [codebook]; /* convert codebook to index to table of QSCs */ +#if DETECT_TOO_LONG_CW_READS + maxAllowedCwLen = pMaxLenOfCbInExtSrtSec[maxLenOfCbInExtSrtSecIdx]; + maxLenOfCbInExtSrtSecIdx++; + if (maxLenOfCbInExtSrtSecIdx >= (MAX_SFB_HCR+MAX_HCR_SETS)) { + return; + } +#endif + + /* switch for decoding with different codebooks: */ + if ( pCbSign[codebook] == 0 ) { /* no sign bits follow after the codeword-body */ + /* PCW_BodyONLY */ + /*==============*/ + + for ( curExtSortCwInSec = pNumExtendedSortedCodewordInSection[numExtendedSortedCodewordInSectionIdx] ; curExtSortCwInSec != 0; curExtSortCwInSec--) { + numDecodedBits = 0; + + /* decode PCW_BODY */ + pQuantVal = DecodePCW_Body(bs, + pCurrentTree, + pQuantValBase, + pLeftStartOfSegment, + pRemainingBitsInSegment, + &numDecodedBits + ); + + /* result is written out here because NO sign bits follow the body */ + for( i=dimension; i != 0 ; i-- ) { + pQuantizedSpectralCoefficients[quantizedSpectralCoefficientsIdx] = (FIXP_DBL) *pQuantVal++; /* write quant. spec. coef. into spectrum; sign is already valid */ + quantizedSpectralCoefficientsIdx++; + if (quantizedSpectralCoefficientsIdx >= 1024) { + return; + } + } + + /* one more PCW should be decoded */ + +#if DETECT_TOO_LONG_CW_READS + if ( maxAllowedCwLen < (numDecodedBits + ERROR_PCW_BODY_ONLY_TOO_LONG) ) { + pHcr->decInOut.errorLog |= TOO_MANY_PCW_BODY_BITS_DECODED; + } +#endif + +#if CHECK_SEGMENTATION_IMMEDIATELY + if (1 == errDetectPcwSegmentation(*pRemainingBitsInSegment-ERROR_PCW_BODY,pHcr,PCW_BODY,pQuantizedSpectralCoefficients+quantizedSpectralCoefficientsIdx-dimension,dimension)) { + return; + } +#endif + pLeftStartOfSegment++; /* update pointer for decoding the next PCW */ + pRemainingBitsInSegment++; /* update pointer for decoding the next PCW */ + } + } + else if (( pCbSign[codebook] == 1 ) && ( codebook < 11 )) { /* possibly there follow 1,2,3 or 4 sign bits after the codeword-body */ + /* PCW_Body and PCW_Sign */ + /*=======================*/ + + for ( curExtSortCwInSec = pNumExtendedSortedCodewordInSection[numExtendedSortedCodewordInSectionIdx] ; curExtSortCwInSec != 0; curExtSortCwInSec--) + { + int err; + numDecodedBits = 0; + + pQuantVal = DecodePCW_Body(bs, + pCurrentTree, + pQuantValBase, + pLeftStartOfSegment, + pRemainingBitsInSegment, + &numDecodedBits + ); + + err = DecodePCW_Sign( bs, + dimension, + pQuantVal, + pQuantizedSpectralCoefficients, + &quantizedSpectralCoefficientsIdx, + pLeftStartOfSegment, + pRemainingBitsInSegment, + &numDecodedBits + ); + if (err != 0) { + return; + } + /* one more PCW should be decoded */ + +#if DETECT_TOO_LONG_CW_READS + if ( maxAllowedCwLen < (numDecodedBits + ERROR_PCW_BODY_SIGN_TOO_LONG) ) { + pHcr->decInOut.errorLog |= TOO_MANY_PCW_BODY_SIGN_BITS_DECODED; + } +#endif + +#if CHECK_SEGMENTATION_IMMEDIATELY + if (1 == errDetectPcwSegmentation(*pRemainingBitsInSegment-ERROR_PCW_BODY_SIGN,pHcr,PCW_BODY_SIGN, pQuantizedSpectralCoefficients+quantizedSpectralCoefficientsIdx-dimension,dimension)) { + return; + } +#endif + pLeftStartOfSegment++; + pRemainingBitsInSegment++; + } + } + else if (( pCbSign[codebook] == 1 ) && ( codebook >= 11 )) { /* possibly there follow some sign bits and maybe one or two escape sequences after the cw-body */ + /* PCW_Body, PCW_Sign and maybe PCW_Escape */ + /*=========================================*/ + + for ( curExtSortCwInSec = pNumExtendedSortedCodewordInSection[numExtendedSortedCodewordInSectionIdx] ; curExtSortCwInSec != 0; curExtSortCwInSec--) + { + int err; + numDecodedBits = 0; + + /* decode PCW_BODY */ + pQuantVal = DecodePCW_Body(bs, + pCurrentTree, + pQuantValBase, + pLeftStartOfSegment, + pRemainingBitsInSegment, + &numDecodedBits + ); + + err = DecodePCW_Sign( bs, + dimension, + pQuantVal, + pQuantizedSpectralCoefficients, + &quantizedSpectralCoefficientsIdx, + pLeftStartOfSegment, + pRemainingBitsInSegment, + &numDecodedBits + ); + if (err != 0) { + return; + } + + /* decode PCW_ESCAPE if present */ + quantizedSpectralCoefficientsIdx -= DIMENSION_OF_ESCAPE_CODEBOOK; + + if ( fixp_abs(pQuantizedSpectralCoefficients[quantizedSpectralCoefficientsIdx]) == (FIXP_DBL)ESCAPE_VALUE ) { + pQuantizedSpectralCoefficients[quantizedSpectralCoefficientsIdx] = (FIXP_DBL) DecodeEscapeSequence( bs, + pQuantizedSpectralCoefficients[quantizedSpectralCoefficientsIdx], + pLeftStartOfSegment, + pRemainingBitsInSegment, + &numDecodedBits + ); + } + quantizedSpectralCoefficientsIdx++; + if (quantizedSpectralCoefficientsIdx >= 1024) { + return; + } + + if ( fixp_abs(pQuantizedSpectralCoefficients[quantizedSpectralCoefficientsIdx]) == (FIXP_DBL)ESCAPE_VALUE ) { + pQuantizedSpectralCoefficients[quantizedSpectralCoefficientsIdx] = (FIXP_DBL) DecodeEscapeSequence( bs, + pQuantizedSpectralCoefficients[quantizedSpectralCoefficientsIdx], + pLeftStartOfSegment, + pRemainingBitsInSegment, + &numDecodedBits + ); + } + quantizedSpectralCoefficientsIdx++; + if (quantizedSpectralCoefficientsIdx >= 1024) { + return; + } + + /* one more PCW should be decoded */ + +#if DETECT_TOO_LONG_CW_READS + if ( maxAllowedCwLen < (numDecodedBits + ERROR_PCW_BODY_SIGN_ESC_TOO_LONG) ) { + pHcr->decInOut.errorLog |= TOO_MANY_PCW_BODY_SIGN_ESC_BITS_DECODED; + } +#endif + +#if CHECK_SEGMENTATION_IMMEDIATELY + if (1 == errDetectPcwSegmentation(*pRemainingBitsInSegment-ERROR_PCW_BODY_SIGN_ESC,pHcr,PCW_BODY_SIGN_ESC,pQuantizedSpectralCoefficients+quantizedSpectralCoefficientsIdx-DIMENSION_OF_ESCAPE_CODEBOOK,DIMENSION_OF_ESCAPE_CODEBOOK)) { + return; + } +#endif + pLeftStartOfSegment++; + pRemainingBitsInSegment++; + } + } + + /* all PCWs belonging to this extended section should be decoded */ + numExtendedSortedCodewordInSectionIdx++; + if (numExtendedSortedCodewordInSectionIdx >= MAX_SFB_HCR+MAX_HCR_SETS) { + return; + } + } + /* all PCWs should be decoded */ + + numExtendedSortedSectionsInSetsIdx++; + if (numExtendedSortedSectionsInSetsIdx >= MAX_HCR_SETS) { + return; + } + + /* Write back indexes into structure */ + pHcr->sectionInfo.numExtendedSortedCodewordInSectionIdx = numExtendedSortedCodewordInSectionIdx; + pHcr->sectionInfo.extendedSortedCodebookIdx = extendedSortedCodebookIdx; + pHcr->sectionInfo.numExtendedSortedSectionsInSetsIdx = numExtendedSortedSectionsInSetsIdx; + pHcr->decInOut.quantizedSpectralCoefficientsIdx = quantizedSpectralCoefficientsIdx; + pHcr->sectionInfo.maxLenOfCbInExtSrtSecIdx = maxLenOfCbInExtSrtSecIdx; +} + +#if CHECK_SEGMENTATION_IMMEDIATELY +/*--------------------------------------------------------------------------------------------- + description: This function checks immediately after every decoded PCW, whether out of + the current segment too many bits have been read or not. If an error occurrs, + probably the sideinfo or the HCR-bitstream block holding the huffman + encoded quantized spectral coefficients is distorted. In this case the two + or four quantized spectral coefficients belonging to the current codeword + are marked (for being detected by concealment later). +-------------------------------------------------------------------------------------------- */ +static UCHAR errDetectPcwSegmentation(SCHAR remainingBitsInSegment, + H_HCR_INFO pHcr, + PCW_TYPE kind, + FIXP_DBL *qsc_base_of_cw, + UCHAR dimension) +{ + SCHAR i; + if ( remainingBitsInSegment < 0 ) { + /* log the error */ + switch (kind) { + case PCW_BODY: + pHcr->decInOut.errorLog |= SEGMENT_OVERRIDE_ERR_PCW_BODY; + break; + case PCW_BODY_SIGN: + pHcr->decInOut.errorLog |= SEGMENT_OVERRIDE_ERR_PCW_BODY_SIGN; + break; + case PCW_BODY_SIGN_ESC: + pHcr->decInOut.errorLog |= SEGMENT_OVERRIDE_ERR_PCW_BODY_SIGN_ESC; + break; + } + /* mark the erred lines */ + for ( i = dimension; i != 0; i-- ) { + *qsc_base_of_cw++ = (FIXP_DBL) Q_VALUE_INVALID; + } + return 1; + } + return 0; +} +#endif + +#if CHECK_SEGMENTATION_FINAL +/*--------------------------------------------------------------------------------------------- + description: This function checks if all segments are empty after decoding. There + are _no lines markded_ as invalid because it could not be traced back + where from the remaining bits are. +-------------------------------------------------------------------------------------------- */ +static void errDetectWithinSegmentationFinal(H_HCR_INFO pHcr) +{ + UCHAR segmentationErrorFlag = 0; + USHORT i; + SCHAR *pRemainingBitsInSegment = pHcr->segmentInfo.pRemainingBitsInSegment; + UINT numSegment = pHcr->segmentInfo.numSegment; + + for ( i=numSegment; i != 0 ; i--) { + if (*pRemainingBitsInSegment++ != 0) { + segmentationErrorFlag = 1; + } + } + if (segmentationErrorFlag == 1) { + pHcr->decInOut.errorLog |= BIT_IN_SEGMENTATION_ERROR; + } +} +#endif + +/*--------------------------------------------------------------------------------------------- + description: This function walks one step within the decoding tree. Which branch is + taken depends on the decoded carryBit input parameter. +-------------------------------------------------------------------------------------------- */ +void CarryBitToBranchValue(UCHAR carryBit, + UINT treeNode, + UINT *branchValue, + UINT *branchNode) +{ + if (carryBit == 0) { + *branchNode = (treeNode & MASK_LEFT) >> LEFT_OFFSET; /* MASK_LEFT: 00FFF000 */ + } + else { + *branchNode = treeNode & MASK_RIGHT; /* MASK_RIGHT: 00000FFF */ + } + + *branchValue = *branchNode & CLR_BIT_10; /* clear bit 10 (if set) */ +} + + +/*--------------------------------------------------------------------------------------------- + description: Decodes the body of a priority codeword (PCW) +----------------------------------------------------------------------------------------------- + return: - return value is pointer to first of two or four quantized spectral + coefficients +-------------------------------------------------------------------------------------------- */ +static const SCHAR *DecodePCW_Body(HANDLE_FDK_BITSTREAM bs, + const UINT *pCurrentTree, + const SCHAR *pQuantValBase, + USHORT *pLeftStartOfSegment, + SCHAR *pRemainingBitsInSegment, + int *pNumDecodedBits + ) +{ + UCHAR carryBit; + UINT branchNode; + UINT treeNode; + UINT branchValue; + const SCHAR *pQuantVal; + + /* decode PCW_BODY */ + treeNode = *pCurrentTree; /* get first node of current tree belonging to current codebook */ + + /* decode whole PCW-codeword-body */ + while (1) { + + carryBit = HcrGetABitFromBitstream(bs, + pLeftStartOfSegment, + pLeftStartOfSegment, /* dummy */ + FROM_LEFT_TO_RIGHT); + *pRemainingBitsInSegment -= 1; + *pNumDecodedBits += 1; + + CarryBitToBranchValue(carryBit, + treeNode, + &branchValue, + &branchNode); + + if ((branchNode & TEST_BIT_10) == TEST_BIT_10) { /* test bit 10 ; if set --> codeword-body is complete */ + break; /* end of branch in tree reached i.e. a whole PCW-Body is decoded */ + } + else { + treeNode = *(pCurrentTree + branchValue); /* update treeNode for further step in decoding tree */ + } + + } + + pQuantVal = pQuantValBase + branchValue; /* update pointer to valid first of 2 or 4 quantized values */ + + return pQuantVal; +} + + +/*--------------------------------------------------------------------------------------------- + description: This function decodes one escape sequence. In case of a escape codebook + and in case of the absolute value of the quantized spectral value == 16, + a escapeSequence is decoded in two steps: + 1. escape prefix + 2. escape word +-------------------------------------------------------------------------------------------- */ + +static INT DecodeEscapeSequence(HANDLE_FDK_BITSTREAM bs, + INT quantSpecCoef, + USHORT *pLeftStartOfSegment, + SCHAR *pRemainingBitsInSegment, + int *pNumDecodedBits + ) +{ + UINT i; + INT sign; + UINT escapeOnesCounter = 0; + UINT carryBit; + INT escape_word = 0; + + /* decode escape prefix */ + while (1) { + carryBit = HcrGetABitFromBitstream(bs, + pLeftStartOfSegment, + pLeftStartOfSegment, /* dummy */ + FROM_LEFT_TO_RIGHT); + *pRemainingBitsInSegment -= 1; + *pNumDecodedBits += 1; + + if (carryBit != 0) { + escapeOnesCounter += 1; + } + else { + escapeOnesCounter += 4; + break; + } + } + + /* decode escape word */ + for( i=escapeOnesCounter; i != 0 ; i-- ) { + carryBit = HcrGetABitFromBitstream(bs, + pLeftStartOfSegment, + pLeftStartOfSegment, /* dummy */ + FROM_LEFT_TO_RIGHT); + *pRemainingBitsInSegment -= 1; + *pNumDecodedBits += 1; + + escape_word <<= 1; + escape_word = escape_word | carryBit; + } + + sign = (quantSpecCoef >= 0) ? 1 : -1; + + quantSpecCoef = sign * (((INT ) 1 << escapeOnesCounter) + escape_word); + + return quantSpecCoef; +} + + +/*--------------------------------------------------------------------------------------------- + description: Decodes the Signbits of a priority codeword (PCW) and writes out the + resulting quantized spectral values into unsorted sections +----------------------------------------------------------------------------------------------- + output: - two or four lines at position in corresponding section (which are not + located at the desired position, i.e. they must be reordered in the last + of eight function of HCR) +----------------------------------------------------------------------------------------------- + return: - updated pQuantSpecCoef pointer (to next empty storage for a line) +-------------------------------------------------------------------------------------------- */ +static int DecodePCW_Sign(HANDLE_FDK_BITSTREAM bs, + UINT codebookDim, + const SCHAR *pQuantVal, + FIXP_DBL *pQuantSpecCoef, + int *quantSpecCoefIdx, + USHORT *pLeftStartOfSegment, + SCHAR *pRemainingBitsInSegment, + int *pNumDecodedBits + ) +{ + UINT i; + UINT carryBit; + INT quantSpecCoef; + + for( i=codebookDim; i != 0 ; i-- ) { + quantSpecCoef = *pQuantVal++; + if (quantSpecCoef != 0) { + carryBit = HcrGetABitFromBitstream(bs, + pLeftStartOfSegment, + pLeftStartOfSegment, /* dummy */ + FROM_LEFT_TO_RIGHT); + *pRemainingBitsInSegment -= 1; + *pNumDecodedBits += 1; + if (*pRemainingBitsInSegment < 0 || *pNumDecodedBits >= (1024>>1)) { + return -1; + } + + /* adapt sign of values according to the decoded sign bit */ + if (carryBit != 0) { + pQuantSpecCoef[*quantSpecCoefIdx] = -(FIXP_DBL)quantSpecCoef; + } + else { + pQuantSpecCoef[*quantSpecCoefIdx] = (FIXP_DBL)quantSpecCoef; + } + } + else { + pQuantSpecCoef[*quantSpecCoefIdx] = FL2FXCONST_DBL(0.0f); + } + *quantSpecCoefIdx += 1 ; + if (*quantSpecCoefIdx >= 1024) { + return -1; + } + } + return 0; +} + + +/*--------------------------------------------------------------------------------------------- + description: Mutes spectral lines which have been marked as erroneous (Q_VALUE_INVALID) +-------------------------------------------------------------------------------------------- */ +void HcrMuteErroneousLines(H_HCR_INFO hHcr) +{ + int c; + FIXP_DBL *RESTRICT pLong = SPEC_LONG(hHcr->decInOut.pQuantizedSpectralCoefficientsBase); + + /* if there is a line with value Q_VALUE_INVALID mute it */ + for (c = 0; c < 1024; c++) { + if (pLong[c] == (FIXP_DBL)Q_VALUE_INVALID) { +#if HCR_LISTEN_TO_MUTED_LINES + pLong[c] = (FIXP_DBL)HCR_DIRAC; /* marking */ +#else + pLong[c] = FL2FXCONST_DBL(0.0f); /* muting */ +#endif + } + } +} + + +/*--------------------------------------------------------------------------------------------- + description: Sets global HCR type +-------------------------------------------------------------------------------------------- */ +void setHcrType(H_HCR_INFO hHcr, MP4_ELEMENT_ID type) +{ + switch (type) { + case ID_SCE: + hHcr->globalHcrType = 0; + break; + case ID_CPE: + hHcr->globalHcrType = 1; + break; + default: + break; + } +} + + +/*--------------------------------------------------------------------------------------------- + description: Gets HCR type from the HCR data structure +----------------------------------------------------------------------------------------------- + return: - global HCR type +-------------------------------------------------------------------------------------------- */ +INT getHcrType(H_HCR_INFO hHcr) +{ + return hHcr->globalHcrType; +} + + + + diff --git a/libAACdec/src/aacdec_hcr.h b/libAACdec/src/aacdec_hcr.h new file mode 100644 index 0000000..f053448 --- /dev/null +++ b/libAACdec/src/aacdec_hcr.h @@ -0,0 +1,64 @@ +/***************************** MPEG-4 AAC Decoder *************************** + + (C) Copyright Fraunhofer IIS 2000-2008 + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Robert Weidner (DSP Solutions) + Description: HCR Decoder: Interface function declaration; common defines + and structures; defines for switching error-generator, + -detector, and -concealment + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +*******************************************************************************/ + +#ifndef _AACDEC_HCR_H_ +#define _AACDEC_HCR_H_ + + + +#include "channelinfo.h" +#include "FDK_bitstream.h" + +void HcrInitRom (H_HCR_INFO hHcr); +UINT HcrInit(H_HCR_INFO pHcr, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + const SamplingRateInfo *pSamplingRateInfo, + HANDLE_FDK_BITSTREAM bs); +UINT HcrDecoder (H_HCR_INFO hHcr, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + const SamplingRateInfo *pSamplingRateInfo, + HANDLE_FDK_BITSTREAM bs); +void CarryBitToBranchValue( + UCHAR carryBit, + UINT treeNode, + UINT *branchValue, + UINT *branchNode + ); + +void CHcr_Read (HANDLE_FDK_BITSTREAM bs, + CAacDecoderChannelInfo *pAacDecoderChannelInfo); +void HcrMuteErroneousLines(H_HCR_INFO hHcr); + +void setHcrType(H_HCR_INFO hHcr, MP4_ELEMENT_ID type); +INT getHcrType(H_HCR_INFO hHcr); + + + +#endif /* _AACDEC_HCR_H_ */ diff --git a/libAACdec/src/aacdec_hcr_bit.cpp b/libAACdec/src/aacdec_hcr_bit.cpp new file mode 100644 index 0000000..92695d9 --- /dev/null +++ b/libAACdec/src/aacdec_hcr_bit.cpp @@ -0,0 +1,103 @@ +/***************************** MPEG-4 AAC Decoder *************************** + + (C) Copyright Fraunhofer IIS 2000-2008 + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Robert Weidner (DSP Solutions) + Description: HCR Decoder: Bitstream reading + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +*******************************************************************************/ + +#include "aacdec_hcr_bit.h" + + +/*--------------------------------------------------------------------------------------------- + description: This function toggles the read direction. +----------------------------------------------------------------------------------------------- + input: current read direction +----------------------------------------------------------------------------------------------- + return: new read direction +-------------------------------------------------------------------------------------------- */ +UCHAR ToggleReadDirection(UCHAR readDirection) +{ + if ( readDirection == FROM_LEFT_TO_RIGHT ) { + return FROM_RIGHT_TO_LEFT; + } + else { + return FROM_LEFT_TO_RIGHT; + } +} + + +/*--------------------------------------------------------------------------------------------- + description: This function returns a bit from the bitstream according to read direction. + It is called very often, therefore it makes sense to inline it (runtime). +----------------------------------------------------------------------------------------------- + input: - handle to FDK bitstream + - reference value marking start of bitfield + - pLeftStartOfSegment + - pRightStartOfSegment + - readDirection +----------------------------------------------------------------------------------------------- + return: - bit from bitstream +-------------------------------------------------------------------------------------------- */ +UINT HcrGetABitFromBitstream(HANDLE_FDK_BITSTREAM bs, + USHORT *pLeftStartOfSegment, + USHORT *pRightStartOfSegment, + UCHAR readDirection) +{ + UINT bit; + INT readBitOffset; + + if (readDirection == FROM_LEFT_TO_RIGHT) { + readBitOffset = *pLeftStartOfSegment-FDKgetBitCnt(bs); + if( readBitOffset ) { + FDKpushBiDirectional(bs, readBitOffset); + } + + bit = FDKreadBits(bs, 1); + + *pLeftStartOfSegment += 1; + } + else { + readBitOffset = *pRightStartOfSegment-FDKgetBitCnt(bs); + if( readBitOffset ) { + FDKpushBiDirectional(bs, readBitOffset); + } + + /* to be replaced with a brother function of FDKreadBits() */ + bit = FDKreadBits(bs, 1); + FDKpushBack(bs, 2); + + *pRightStartOfSegment -= 1; + } + + +#if ERROR_GENERATOR_BIT_STREAM_HCR + static int a; + if ((++a % MODULO_DIVISOR_HCR) == 0) { + bit = (bit == 0) ? 1 : 0; + } +#endif + + return (bit); +} + diff --git a/libAACdec/src/aacdec_hcr_bit.h b/libAACdec/src/aacdec_hcr_bit.h new file mode 100644 index 0000000..e49ce5a --- /dev/null +++ b/libAACdec/src/aacdec_hcr_bit.h @@ -0,0 +1,44 @@ +/***************************** MPEG-4 AAC Decoder *************************** + + (C) Copyright Fraunhofer IIS 2000-2008 + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Robert Weidner (DSP Solutions) + Description: HCR Decoder: Bitstream reading prototypes + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +*******************************************************************************/ + +#ifndef _AACDEC_HCR_BIT_H_ +#define _AACDEC_HCR_BIT_H_ + + + +#include "aacdec_hcr.h" + +UCHAR ToggleReadDirection(UCHAR readDirection); + +UINT HcrGetABitFromBitstream(HANDLE_FDK_BITSTREAM bs, + USHORT *pLeftStartOfSegment, + USHORT *pRightStartOfSegment, + UCHAR readDirection); + + +#endif /* _AACDEC_HCR_BIT_H_ */ diff --git a/libAACdec/src/aacdec_hcr_types.h b/libAACdec/src/aacdec_hcr_types.h new file mode 100644 index 0000000..0fe7730 --- /dev/null +++ b/libAACdec/src/aacdec_hcr_types.h @@ -0,0 +1,304 @@ +/***************************** MPEG-4 AAC Decoder *************************** + + (C) Copyright Fraunhofer IIS 2000-2009 + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Robert Weidner (DSP Solutions) + Description: HCR Decoder: Common defines and structures; defines for + switching error-generator, -detector, and -concealment; + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +*******************************************************************************/ + +#ifndef _AACDEC_HCR_TYPES_H_ +#define _AACDEC_HCR_TYPES_H_ + + + +#include "FDK_bitstream.h" +#include "overlapadd.h" + +/* ------------------------------------------------ */ +/* ------------------------------------------------ */ + +#define LINES_PER_UNIT 4 + +/* ------------------------------------------------ */ +/* ------------------------------------------------ */ +/* ----------- basic HCR configuration ------------ */ + + + #define MAX_SFB_HCR (((1024/8) / LINES_PER_UNIT) * 8) /* (8 * 16) is not enough because sfbs are split in units for blocktype short */ + #define NUMBER_OF_UNIT_GROUPS (LINES_PER_UNIT * 8) + #define LINES_PER_UNIT_GROUP (1024 / NUMBER_OF_UNIT_GROUPS) /* 15 16 30 32 */ + + +/* ------------------------------------------------ */ +/* ------------------------------------------------ */ +/* ------------------------------------------------ */ + +#define FROM_LEFT_TO_RIGHT 0 +#define FROM_RIGHT_TO_LEFT 1 + +#define MAX_CB_PAIRS 23 +#define MAX_HCR_SETS 14 + +#define ESCAPE_VALUE 16 +#define POSITION_OF_FLAG_A 21 +#define POSITION_OF_FLAG_B 20 + +#define MAX_CB 32 /* last used CB is cb #31 when VCB11 is used */ + +#define MAX_CB_CHECK 32 /* support for VCB11 available -- is more general, could therefore used in both cases */ + +#define NUMBER_OF_BIT_IN_WORD 32 + +/* log */ +#define THIRTYTWO_LOG_DIV_TWO_LOG 5 +#define EIGHT_LOG_DIV_TWO_LOG 3 +#define FOUR_LOG_DIV_TWO_LOG 2 + +/* borders */ +#define CPE_TOP_LENGTH 12288 +#define SCE_TOP_LENGTH 6144 +#define LEN_OF_LONGEST_CW_TOP_LENGTH 49 + +/* qsc's of high level */ +#define Q_VALUE_INVALID 8192 /* mark a invalid line with this value (to be concealed later on) */ +#define HCR_DIRAC 500 /* a line of high level */ + +/* masks */ +#define MASK_LEFT 0xFFF000 +#define MASK_RIGHT 0xFFF +#define CLR_BIT_10 0x3FF +#define TEST_BIT_10 0x400 + +#define LEFT_OFFSET 12 + +/* when set HCR is replaced by a dummy-module which just fills the outputbuffer with a dirac sequence */ +/* use this if HCR is suspected to write in other modules -- if error is stell there, HCR is innocent */ +#define USE_HCR_DUMMY 0 + + +/* ------------------------------ */ +/* - insert HCR errors - */ +/* ------------------------------ */ + + /* modify input lengths -- high protected */ +#define ERROR_LORSD 0 /* offset: error if different from zero */ +#define ERROR_LOLC 0 /* offset: error if different from zero */ + + /* segments are earlier empty as expected when decoding PCWs */ +#define ERROR_PCW_BODY 0 /* set a positive values to trigger the error (make segments earlyer appear to be empty) */ +#define ERROR_PCW_BODY_SIGN 0 /* set a positive values to trigger the error (make segments earlyer appear to be empty) */ +#define ERROR_PCW_BODY_SIGN_ESC 0 /* set a positive values to trigger the error (make segments earlyer appear to be empty) */ + + /* pretend there are too many bits decoded (enlarge length of codeword) at PCWs -- use a positive value */ +#define ERROR_PCW_BODY_ONLY_TOO_LONG 0 /* set a positive values to trigger the error */ +#define ERROR_PCW_BODY_SIGN_TOO_LONG 0 /* set a positive values to trigger the error */ +#define ERROR_PCW_BODY_SIGN_ESC_TOO_LONG 0 /* set a positive values to trigger the error */ + + /* modify HCR bitstream block */ +#define ERROR_GENERATOR_BIT_STREAM_HCR 0 /* modify every -bit when reading from bitstream */ /* !!! BEWARE!!! if RVLC is active, also RVLC data at ESC2 will be modified !!! */ +#define MODULO_DIVISOR_HCR 30 + + +/* ------------------------------ */ +/* - detect HCR errors - */ +/* ------------------------------ */ + /* check input data */ +#define CHECK_VALID_HCR_INPUT 1 /* it is highly recommended to check input data */ + + /* during decoding */ +#define CHECK_SEGMENTATION_IMMEDIATELY 1 /* the 2 or 4 lines of a detected PCW-decoding-error is marked */ + +#define CHECK_SEGMENTATION_FINAL 1 /* all the segments are checked -- therefore -- if this check passes, its a kind of evidence that the + decoded PCWs and non-PCWs are fine */ + +#define DETECT_TOO_LONG_CW_READS 1 /* if a codeword is decoded there exists a border for the number of bits, which are allowed to read for this + codeword. This border is the minimum of the length of the longest codeword (for the currently used + codebook) and the separately transmitted 'lengthOfLongestCodeword' in this frame and channel. The number + of decoded bits is counted (for PCWs only -- there it makes really sense in my opinion). If this number + exceeds the border (derived as minimum -- see above), a error is detected. */ + +#define STATE_MACHINE_ERROR_CHECK 1 /* test if the number of remaining bits in a segment is _below_ zero. If there are no errors the lowest + allowed value for remainingBitsInSegment is zero. This check also could be set to zero (save runtime) */ + /* other */ +#define VALID_LAV_ERROR_TRIGGER 1 /* when set to '1', avoid setting the LAV-Flag in errorLog due to a previous-line-marking (at PCW decoder). A little + more runtime is needed then when writing values out into output-buffer. */ + +#define HCR_LISTEN_TO_MUTED_LINES 0 /* listen to the "error-concealment" for testing */ + +/* ------------------------------ */ +/* - conceal HCR errors - */ +/* ------------------------------ */ + +#define HCR_ERROR_CONCEALMENT 1 /* if set to '1', HCR _mutes_ the erred quantized spectral coefficients */ + + +// ------------------------------------------------------------------------------------------------------------------ +// errorLog: A word of 32 bits used for logging possible errors within HCR +// in case of distorted bitstreams. Table of all known errors: +// ------------------------------------------------------------------------------------------------------------------------ + // bit fatal location meaning + // ----+-----+-----------+-------------------------------------- +#define SEGMENT_OVERRIDE_ERR_PCW_BODY 0x80000000 // 31 no PCW-Dec During PCW decoding it is checked after every PCW if there are too many bits decoded (immediate check). +#define SEGMENT_OVERRIDE_ERR_PCW_BODY_SIGN 0x40000000 // 30 no PCW-Dec During PCW decoding it is checked after every PCW if there are too many bits decoded (immediate check). +#define SEGMENT_OVERRIDE_ERR_PCW_BODY_SIGN_ESC 0x20000000 // 29 no PCW-Dec During PCW decoding it is checked after every PCW if there are too many bits decoded (immediate check). +#define EXTENDED_SORTED_COUNTER_OVERFLOW 0x10000000 // 28 yes Init-Dec Error during extending sideinfo (neither a PCW nor a nonPCW was decoded so far) + // 0x08000000 // 27 reserved + // 0x04000000 // 26 reserved + // 0x02000000 // 25 reserved + // 0x01000000 // 24 reserved + // 0x00800000 // 23 reserved + // 0x00400000 // 22 reserved + // 0x00200000 // 21 reserved + // 0x00100000 // 20 reserved + + /* special errors */ +#define TOO_MANY_PCW_BODY_BITS_DECODED 0x00080000 // 19 yes PCW-Dec During PCW-body-decoding too many bits have been read from bitstream -- advice: skip non-PCW decoding +#define TOO_MANY_PCW_BODY_SIGN_BITS_DECODED 0x00040000 // 18 yes PCW-Dec During PCW-body-sign-decoding too many bits have been read from bitstream -- advice: skip non-PCW decoding +#define TOO_MANY_PCW_BODY_SIGN_ESC_BITS_DECODED 0x00020000 // 17 yes PCW-Dec During PCW-body-sign-esc-decoding too many bits have been read from bitstream -- advice: skip non-PCW decoding + + + // 0x00010000 // 16 reserved +#define STATE_ERROR_BODY_ONLY 0x00008000 // 15 no NonPCW-Dec State machine returned with error +#define STATE_ERROR_BODY_SIGN__BODY 0x00004000 // 14 no NonPCW-Dec State machine returned with error +#define STATE_ERROR_BODY_SIGN__SIGN 0x00002000 // 13 no NonPCW-Dec State machine returned with error +#define STATE_ERROR_BODY_SIGN_ESC__BODY 0x00001000 // 12 no NonPCW-Dec State machine returned with error +#define STATE_ERROR_BODY_SIGN_ESC__SIGN 0x00000800 // 11 no NonPCW-Dec State machine returned with error +#define STATE_ERROR_BODY_SIGN_ESC__ESC_PREFIX 0x00000400 // 10 no NonPCW-Dec State machine returned with error +#define STATE_ERROR_BODY_SIGN_ESC__ESC_WORD 0x00000200 // 9 no NonPCW-Dec State machine returned with error +#define HCR_SI_LENGTHS_FAILURE 0x00000100 // 8 yes Init-Dec LengthOfLongestCodeword must not be less than lenghtOfReorderedSpectralData +#define NUM_SECT_OUT_OF_RANGE_SHORT_BLOCK 0x00000080 // 7 yes Init-Dec The number of sections is not within the allowed range (short block) +#define NUM_SECT_OUT_OF_RANGE_LONG_BLOCK 0x00000040 // 6 yes Init-Dec The number of sections is not within the allowed range (long block) +#define LINE_IN_SECT_OUT_OF_RANGE_SHORT_BLOCK 0x00000020 // 5 yes Init-Dec The number of lines per section is not within the allowed range (short block) +#define CB_OUT_OF_RANGE_SHORT_BLOCK 0x00000010 // 4 yes Init-Dec The codebook is not within the allowed range (short block) +#define LINE_IN_SECT_OUT_OF_RANGE_LONG_BLOCK 0x00000008 // 3 yes Init-Dec The number of lines per section is not within the allowed range (long block) +#define CB_OUT_OF_RANGE_LONG_BLOCK 0x00000004 // 2 yes Init-Dec The codebook is not within the allowed range (long block) +#define LAV_VIOLATION 0x00000002 // 1 no Final The absolute value of at least one decoded line was too high for the according codebook. +#define BIT_IN_SEGMENTATION_ERROR 0x00000001 // 0 no Final After PCW and non-PWC-decoding at least one segment is not zero (global check). + + /*----------*/ +#define HCR_FATAL_PCW_ERROR_MASK 0x100E01FC + + +typedef enum { + PCW_BODY, + PCW_BODY_SIGN, + PCW_BODY_SIGN_ESC +} PCW_TYPE; + + +/* interface Decoder <---> HCR */ +typedef struct { + UINT errorLog; + SPECTRAL_PTR pQuantizedSpectralCoefficientsBase; + int quantizedSpectralCoefficientsIdx; + SHORT lengthOfReorderedSpectralData; + SHORT numSection; + SHORT *pNumLineInSect; + USHORT bitstreamIndex; + SCHAR lengthOfLongestCodeword; + UCHAR *pCodebook; +} HCR_INPUT_OUTPUT; + +typedef struct { + const UCHAR *pMinOfCbPair; + const UCHAR *pMaxOfCbPair; +} HCR_CB_PAIRS; + +typedef struct{ + const USHORT *pLargestAbsVal; + const UCHAR *pMaxCwLength; + const UCHAR *pCbDimension; + const UCHAR *pCbDimShift; + const UCHAR *pCbSign; + const UCHAR *pCbPriority; +} HCR_TABLE_INFO; + +typedef struct{ + UINT numSegment; + UINT pSegmentBitfield[((1024>>1)/NUMBER_OF_BIT_IN_WORD+1)]; + UINT pCodewordBitfield[((1024>>1)/NUMBER_OF_BIT_IN_WORD+1)]; + UINT segmentOffset; + FIXP_DBL pTempValues[1024]; + USHORT pLeftStartOfSegment[1024>>1]; + USHORT pRightStartOfSegment[1024>>1]; + SCHAR pRemainingBitsInSegment[1024>>1]; + UCHAR readDirection; + UCHAR numWordForBitfield; + USHORT pNumBitValidInLastWord; +} HCR_SEGMENT_INFO; + +typedef struct{ + + UINT numCodeword; + UINT numSortedSection; + USHORT pNumCodewordInSection[MAX_SFB_HCR]; + USHORT pNumSortedCodewordInSection[MAX_SFB_HCR]; + USHORT pNumExtendedSortedCodewordInSection[MAX_SFB_HCR+MAX_HCR_SETS]; + int numExtendedSortedCodewordInSectionIdx; + USHORT pNumExtendedSortedSectionsInSets[MAX_HCR_SETS]; + int numExtendedSortedSectionsInSetsIdx; + USHORT pReorderOffset[MAX_SFB_HCR]; + UCHAR pSortedCodebook[MAX_SFB_HCR]; + + UCHAR pExtendedSortedCodebook[MAX_SFB_HCR+MAX_HCR_SETS]; + int extendedSortedCodebookIdx; +#if DETECT_TOO_LONG_CW_READS + UCHAR pMaxLenOfCbInExtSrtSec[MAX_SFB_HCR+MAX_HCR_SETS]; + int maxLenOfCbInExtSrtSecIdx; +#endif + UCHAR pCodebookSwitch[MAX_SFB_HCR]; +} HCR_SECTION_INFO; + +typedef UINT (*STATEFUNC)(HANDLE_FDK_BITSTREAM, void*); + +typedef struct{ + /* worst-case and 1024/4 non-PCWs exist in worst-case */ + FIXP_DBL *pResultBase; /* Base address for spectral data output target buffer */ + UINT iNode[1024>>2]; /* Helper indices for code books */ + USHORT iResultPointer[1024>>2]; /* Helper indices for accessing pResultBase */ + UINT pEscapeSequenceInfo[1024>>2]; + UINT codewordOffset; + STATEFUNC pState; + UCHAR pCodebook[1024>>2]; + UCHAR pCntSign[1024>>2]; + /* this array holds the states coded as integer values within the range [0,1,..,7] */ + SCHAR pSta[1024>>2]; +} HCR_NON_PCW_SIDEINFO; + +typedef struct{ + HCR_INPUT_OUTPUT decInOut; + HCR_CB_PAIRS cbPairs; + HCR_TABLE_INFO tableInfo; + HCR_SEGMENT_INFO segmentInfo; + HCR_SECTION_INFO sectionInfo; + HCR_NON_PCW_SIDEINFO nonPcwSideinfo; + + INT globalHcrType; +} CErHcrInfo; + + +typedef CErHcrInfo *H_HCR_INFO; + + +#endif /* _AACDEC_HCR_TYPES_H_ */ diff --git a/libAACdec/src/aacdec_hcrs.cpp b/libAACdec/src/aacdec_hcrs.cpp new file mode 100644 index 0000000..da8928e --- /dev/null +++ b/libAACdec/src/aacdec_hcrs.cpp @@ -0,0 +1,1344 @@ +/***************************** MPEG-4 AAC Decoder *************************** + + (C) Copyright Fraunhofer IIS 2000-2008 + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Robert Weidner (DSP Solutions) + Description: HCR Decoder: Prepare decoding of non-PCWs, segmentation- and + bitfield-handling, HCR-Statemachine + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +*******************************************************************************/ + +#include "aacdec_hcrs.h" + + +#include "aacdec_hcr.h" + +#include "aacdec_hcr_bit.h" +#include "aac_rom.h" +#include "aac_ram.h" + + +static UINT InitSegmentBitfield(UINT *pNumSegment, + SCHAR *pRemainingBitsInSegment, + UINT *pSegmentBitfield, + UCHAR *pNumWordForBitfield, + USHORT *pNumBitValidInLastWord); + +static void InitNonPCWSideInformationForCurrentSet(H_HCR_INFO pHcr); + +static INT ModuloValue(INT input, INT bufferlength); + +static void ClearBitFromBitfield(STATEFUNC *ptrState, + UINT offset, + UINT *pBitfield); + + +/*--------------------------------------------------------------------------------------------- + description: This function decodes all non-priority codewords (non-PCWs) by using a + state-machine. +-------------------------------------------------------------------------------------------- */ +void DecodeNonPCWs(HANDLE_FDK_BITSTREAM bs, H_HCR_INFO pHcr) +{ + UINT numValidSegment; + INT segmentOffset; + INT codewordOffsetBase; + INT codewordOffset; + UINT trial; + + UINT *pNumSegment; + SCHAR *pRemainingBitsInSegment; + UINT *pSegmentBitfield; + UCHAR *pNumWordForBitfield; + USHORT *pNumBitValidInLastWord; + UINT *pCodewordBitfield; + INT bitfieldWord; + INT bitInWord; + UINT tempWord; + UINT interMediateWord; + INT tempBit; + INT carry; + + UINT numCodeword; + UCHAR numSet; + UCHAR currentSet; + UINT codewordInSet; + UINT remainingCodewordsInSet; + SCHAR *pSta; + UINT ret; + + pNumSegment = &(pHcr->segmentInfo.numSegment); + pRemainingBitsInSegment = pHcr->segmentInfo.pRemainingBitsInSegment; + pSegmentBitfield = pHcr->segmentInfo.pSegmentBitfield; + pNumWordForBitfield = &(pHcr->segmentInfo.numWordForBitfield); + pNumBitValidInLastWord = &(pHcr->segmentInfo.pNumBitValidInLastWord); + pSta = pHcr->nonPcwSideinfo.pSta; + + numValidSegment = InitSegmentBitfield(pNumSegment, + pRemainingBitsInSegment, + pSegmentBitfield, + pNumWordForBitfield, + pNumBitValidInLastWord); + + if ( numValidSegment != 0 ) { + numCodeword = pHcr->sectionInfo.numCodeword; + numSet = ((numCodeword - 1) / *pNumSegment) + 1; + + + pHcr->segmentInfo.readDirection = FROM_RIGHT_TO_LEFT; + + /* Process sets subsequently */ + for ( currentSet = 1; currentSet < numSet ; currentSet++ ) { + + + + /* step 1 */ + numCodeword -= *pNumSegment; /* number of remaining non PCWs [for all sets] */ + if ( numCodeword < *pNumSegment ) { + codewordInSet = numCodeword; /* for last set */ + } + else { + codewordInSet = *pNumSegment; /* for all sets except last set */ + } + + /* step 2 */ + /* prepare array 'CodewordBitfield'; as much ones are written from left in all words, as much decodedCodewordInSetCounter nonPCWs exist in this set */ + tempWord = 0xFFFFFFFF; + pCodewordBitfield = pHcr->segmentInfo.pCodewordBitfield; + + for ( bitfieldWord = *pNumWordForBitfield; bitfieldWord !=0; bitfieldWord-- ) { /* loop over all used words */ + if ( codewordInSet > NUMBER_OF_BIT_IN_WORD ) { /* more codewords than number of bits => fill ones */ + /* fill a whole word with ones */ + *pCodewordBitfield++ = tempWord; + codewordInSet -= NUMBER_OF_BIT_IN_WORD; /* subtract number of bits */ + } + else { + /* prepare last tempWord */ + for (remainingCodewordsInSet = codewordInSet; remainingCodewordsInSet < NUMBER_OF_BIT_IN_WORD ; remainingCodewordsInSet++ ) { + tempWord = tempWord & ~(1 << (NUMBER_OF_BIT_IN_WORD-1-remainingCodewordsInSet)); /* set a zero at bit number (NUMBER_OF_BIT_IN_WORD-1-i) in tempWord */ + } + *pCodewordBitfield++ = tempWord; + tempWord = 0x00000000; + } + } + pCodewordBitfield = pHcr->segmentInfo.pCodewordBitfield; + + /* step 3 */ + /* build non-PCW sideinfo for each non-PCW of the current set */ + InitNonPCWSideInformationForCurrentSet(pHcr); + + /* step 4 */ + /* decode all non-PCWs belonging to this set */ + + /* loop over trials */ + codewordOffsetBase = 0; + for ( trial = *pNumSegment; trial > 0; trial-- ) { + + /* loop over number of words in bitfields */ + segmentOffset = 0; /* start at zero in every segment */ + pHcr->segmentInfo.segmentOffset = segmentOffset; /* store in structure for states */ + codewordOffset = codewordOffsetBase; + pHcr->nonPcwSideinfo.codewordOffset = codewordOffset; /* store in structure for states */ + + for ( bitfieldWord=0; bitfieldWord < *pNumWordForBitfield; bitfieldWord++ ) { + + /* derive tempWord with bitwise and */ + tempWord = pSegmentBitfield[bitfieldWord] & pCodewordBitfield[bitfieldWord]; + + /* if tempWord is not zero, decode something */ + if ( tempWord != 0 ) { + + + /* loop over all bits in tempWord; start state machine if & is true */ + for ( bitInWord = NUMBER_OF_BIT_IN_WORD; bitInWord > 0; bitInWord-- ) { + + interMediateWord = ((UINT)1 << (bitInWord-1) ); + if ( ( tempWord & interMediateWord ) == interMediateWord ) { + + /* get state and start state machine */ + pHcr->nonPcwSideinfo.pState = aStateConstant2State[pSta[codewordOffset]]; + + while(pHcr->nonPcwSideinfo.pState) { + ret = ((STATEFUNC) pHcr->nonPcwSideinfo.pState)(bs, pHcr); +#if STATE_MACHINE_ERROR_CHECK + if ( ret != 0 ) { + return; + } +#endif + } + } + + /* update both offsets */ + segmentOffset += 1; /* add NUMBER_OF_BIT_IN_WORD times one */ + pHcr->segmentInfo.segmentOffset = segmentOffset; + codewordOffset += 1; /* add NUMBER_OF_BIT_IN_WORD times one */ + codewordOffset = ModuloValue(codewordOffset,*pNumSegment); /* index of the current codeword lies within modulo range */ + pHcr->nonPcwSideinfo.codewordOffset = codewordOffset; + } + } + else { + segmentOffset += NUMBER_OF_BIT_IN_WORD; /* add NUMBER_OF_BIT_IN_WORD at once */ + pHcr->segmentInfo.segmentOffset = segmentOffset; + codewordOffset += NUMBER_OF_BIT_IN_WORD; /* add NUMBER_OF_BIT_IN_WORD at once */ + codewordOffset = ModuloValue(codewordOffset,*pNumSegment); /* index of the current codeword lies within modulo range */ + pHcr->nonPcwSideinfo.codewordOffset = codewordOffset; + } + } /* end of bitfield word loop */ + + /* decrement codeword - pointer */ + codewordOffsetBase -= 1; + codewordOffsetBase = ModuloValue(codewordOffsetBase,*pNumSegment); /* index of the current codeword base lies within modulo range */ + + /* rotate numSegment bits in codewordBitfield */ + /* rotation of *numSegment bits in bitfield of codewords (circle-rotation) */ + /* get last valid bit */ + tempBit = pCodewordBitfield[*pNumWordForBitfield-1] & (1 << (NUMBER_OF_BIT_IN_WORD - *pNumBitValidInLastWord)); + tempBit = tempBit >> (NUMBER_OF_BIT_IN_WORD - *pNumBitValidInLastWord); + + /* write zero into place where tempBit was fetched from */ + pCodewordBitfield[*pNumWordForBitfield-1] = pCodewordBitfield[*pNumWordForBitfield-1] & ~(1 << (NUMBER_OF_BIT_IN_WORD - *pNumBitValidInLastWord)); + + /* rotate last valid word */ + pCodewordBitfield[*pNumWordForBitfield-1] = pCodewordBitfield[*pNumWordForBitfield-1] >> 1; + + /* transfare carry bit 0 from current word into bitposition 31 from next word and rotate current word */ + for ( bitfieldWord = *pNumWordForBitfield-2; bitfieldWord > -1 ; bitfieldWord-- ) { + /* get carry (=bit at position 0) from current word */ + carry = pCodewordBitfield[bitfieldWord] & 1; + + /* put the carry bit at position 31 into word right from current word */ + pCodewordBitfield[bitfieldWord+1] = pCodewordBitfield[bitfieldWord+1] | (carry << (NUMBER_OF_BIT_IN_WORD-1)); + + /* shift current word */ + pCodewordBitfield[bitfieldWord] = pCodewordBitfield[bitfieldWord] >> 1; + } + + /* put tempBit into free bit-position 31 from first word */ + pCodewordBitfield[0] = pCodewordBitfield[0] | (tempBit << (NUMBER_OF_BIT_IN_WORD-1)); + + } /* end of trial loop */ + + /* toggle read direction */ + pHcr->segmentInfo.readDirection = ToggleReadDirection(pHcr->segmentInfo.readDirection); + + } + /* end of set loop */ + + /* all non-PCWs of this spectrum are decoded */ + } + + /* all PCWs and all non PCWs are decoded. They are unbacksorted in output buffer. Here is the Interface with comparing QSCs to asm decoding */ +} + + +/*--------------------------------------------------------------------------------------------- + description: This function prepares the bitfield used for the + segments. The list is set up once to be used in all following sets. If a + segment is decoded empty, the according bit from the Bitfield is removed. +----------------------------------------------------------------------------------------------- + return: numValidSegment = the number of valid segments +-------------------------------------------------------------------------------------------- */ +static UINT InitSegmentBitfield(UINT *pNumSegment, + SCHAR *pRemainingBitsInSegment, + UINT *pSegmentBitfield, + UCHAR *pNumWordForBitfield, + USHORT *pNumBitValidInLastWord) +{ + SHORT i; + USHORT r; + UCHAR bitfieldWord; + UINT tempWord; + USHORT numValidSegment; + + *pNumWordForBitfield = ((*pNumSegment-1) >> THIRTYTWO_LOG_DIV_TWO_LOG) + 1; + + /* loop over all words, which are completely used or only partial */ + /* bit in pSegmentBitfield is zero if segment is empty; bit in pSegmentBitfield is one if segment is not empty */ + numValidSegment = 0; + *pNumBitValidInLastWord = *pNumSegment; + + /* loop over words */ + for ( bitfieldWord=0; bitfieldWord < *pNumWordForBitfield - 1; bitfieldWord++ ) { + tempWord = 0xFFFFFFFF; /* set ones */ + r = bitfieldWord << THIRTYTWO_LOG_DIV_TWO_LOG; + for ( i=0; i < NUMBER_OF_BIT_IN_WORD; i++) { + if ( pRemainingBitsInSegment[r + i] == 0 ) { + tempWord = tempWord & ~(1 << (NUMBER_OF_BIT_IN_WORD-1-i)); /* set a zero at bit number (NUMBER_OF_BIT_IN_WORD-1-i) in tempWord */ + } + else { + numValidSegment += 1; /* count segments which are not empty */ + } + } + pSegmentBitfield[bitfieldWord] = tempWord; /* store result */ + *pNumBitValidInLastWord -= NUMBER_OF_BIT_IN_WORD; /* calculate number of zeros on LSB side in the last word */ + } + + + /* calculate last word: prepare special tempWord */ + tempWord = 0xFFFFFFFF; + for ( i=0; i < ( NUMBER_OF_BIT_IN_WORD - *pNumBitValidInLastWord ); i++ ) { + tempWord = tempWord & ~(1 << i); /* clear bit i in tempWord */ + } + + /* calculate last word */ + r = bitfieldWord << THIRTYTWO_LOG_DIV_TWO_LOG; + for ( i=0; i<*pNumBitValidInLastWord; i++) { + if ( pRemainingBitsInSegment[r + i] == 0 ) { + tempWord = tempWord & ~(1 << (NUMBER_OF_BIT_IN_WORD-1-i)); /* set a zero at bit number (NUMBER_OF_BIT_IN_WORD-1-i) in tempWord */ + } + else { + numValidSegment += 1; /* count segments which are not empty */ + } + } + pSegmentBitfield[bitfieldWord] = tempWord; /* store result */ + + + + return numValidSegment; +} + + +/*--------------------------------------------------------------------------------------------- + description: This function sets up sideinfo for the non-PCW decoder (for the current set). +---------------------------------------------------------------------------------------------*/ +static void InitNonPCWSideInformationForCurrentSet(H_HCR_INFO pHcr) +{ + USHORT i,k; + UCHAR codebookDim; + UINT startNode; + + UCHAR *pCodebook = pHcr->nonPcwSideinfo.pCodebook; + UINT *iNode = pHcr->nonPcwSideinfo.iNode; + UCHAR *pCntSign = pHcr->nonPcwSideinfo.pCntSign; + USHORT *iResultPointer = pHcr->nonPcwSideinfo.iResultPointer; + UINT *pEscapeSequenceInfo = pHcr->nonPcwSideinfo.pEscapeSequenceInfo; + SCHAR *pSta = pHcr->nonPcwSideinfo.pSta; + USHORT *pNumExtendedSortedCodewordInSection = pHcr->sectionInfo.pNumExtendedSortedCodewordInSection; + int numExtendedSortedCodewordInSectionIdx = pHcr->sectionInfo.numExtendedSortedCodewordInSectionIdx; + UCHAR *pExtendedSortedCodebook = pHcr->sectionInfo.pExtendedSortedCodebook; + int extendedSortedCodebookIdx = pHcr->sectionInfo.extendedSortedCodebookIdx; + USHORT *pNumExtendedSortedSectionsInSets = pHcr->sectionInfo.pNumExtendedSortedSectionsInSets; + int numExtendedSortedSectionsInSetsIdx = pHcr->sectionInfo.numExtendedSortedSectionsInSetsIdx; + FIXP_DBL *pQuantizedSpectralCoefficients = SPEC_LONG(pHcr->decInOut.pQuantizedSpectralCoefficientsBase); + int quantizedSpectralCoefficientsIdx = pHcr->decInOut.quantizedSpectralCoefficientsIdx; + const UCHAR *pCbDimension = pHcr->tableInfo.pCbDimension; + int iterationCounter = 0; + + /* loop over number of extended sorted sections in the current set so all codewords sideinfo variables within this set can be prepared for decoding */ + for ( i=pNumExtendedSortedSectionsInSets[numExtendedSortedSectionsInSetsIdx]; i != 0; i-- ) { + + codebookDim = pCbDimension[pExtendedSortedCodebook[extendedSortedCodebookIdx]]; + startNode = *aHuffTable[pExtendedSortedCodebook[extendedSortedCodebookIdx]]; + + for ( k = pNumExtendedSortedCodewordInSection[numExtendedSortedCodewordInSectionIdx]; k != 0; k-- ) { + iterationCounter++; + if (iterationCounter > (1024>>2)) { + return; + } + *pSta++ = aCodebook2StartInt[pExtendedSortedCodebook[extendedSortedCodebookIdx]]; + *pCodebook++ = pExtendedSortedCodebook[extendedSortedCodebookIdx]; + *iNode++ = startNode; + *pCntSign++ = 0; + *iResultPointer++ = quantizedSpectralCoefficientsIdx; + *pEscapeSequenceInfo++ = 0; + quantizedSpectralCoefficientsIdx += codebookDim; /* update pointer by codebookDim --> point to next starting value for writing out */ + if (quantizedSpectralCoefficientsIdx >= 1024) { + return; + } + } + numExtendedSortedCodewordInSectionIdx++; /* inc ptr for next ext sort sec in current set */ + extendedSortedCodebookIdx++; /* inc ptr for next ext sort sec in current set */ + if (numExtendedSortedCodewordInSectionIdx >= (MAX_SFB_HCR+MAX_HCR_SETS) || extendedSortedCodebookIdx >= (MAX_SFB_HCR+MAX_HCR_SETS)) { + return; + } + } + numExtendedSortedSectionsInSetsIdx++; /* inc ptr for next set of non-PCWs */ + if (numExtendedSortedCodewordInSectionIdx >= (MAX_SFB_HCR+MAX_HCR_SETS)) { + return; + } + + /* Write back indexes */ + pHcr->sectionInfo.numExtendedSortedCodewordInSectionIdx = numExtendedSortedCodewordInSectionIdx; + pHcr->sectionInfo.extendedSortedCodebookIdx = extendedSortedCodebookIdx; + pHcr->sectionInfo.numExtendedSortedSectionsInSetsIdx = numExtendedSortedSectionsInSetsIdx; + pHcr->sectionInfo.numExtendedSortedCodewordInSectionIdx = numExtendedSortedCodewordInSectionIdx; + pHcr->decInOut.quantizedSpectralCoefficientsIdx = quantizedSpectralCoefficientsIdx; +} + + +/*--------------------------------------------------------------------------------------------- + description: This function returns the input value if the value is in the + range of bufferlength. If is smaller, one bufferlength is added, + if is bigger one bufferlength is subtracted. +----------------------------------------------------------------------------------------------- + return: modulo result +-------------------------------------------------------------------------------------------- */ +static INT ModuloValue(INT input, INT bufferlength) +{ + if ( input > (bufferlength - 1) ) { + return (input - bufferlength); + } + if ( input < 0 ) { + return (input + bufferlength); + } + return input; +} + + +/*--------------------------------------------------------------------------------------------- + description: This function clears a bit from current bitfield and + switches off the statemachine. + + A bit is cleared in two cases: + a) a codeword is decoded, then a bit is cleared in codeword bitfield + b) a segment is decoded empty, then a bit is cleared in segment bitfield +-------------------------------------------------------------------------------------------- */ +static void ClearBitFromBitfield(STATEFUNC *ptrState, + UINT offset, + UINT *pBitfield) +{ + UINT numBitfieldWord; + UINT numBitfieldBit; + + /* get both values needed for clearing the bit */ + numBitfieldWord = offset >> THIRTYTWO_LOG_DIV_TWO_LOG; /* int = wordNr */ + numBitfieldBit = offset - (numBitfieldWord << THIRTYTWO_LOG_DIV_TWO_LOG); /* fract = bitNr */ + + /* clear a bit in bitfield */ + pBitfield[numBitfieldWord] = pBitfield[numBitfieldWord] & ~(1 << (NUMBER_OF_BIT_IN_WORD-1 - numBitfieldBit)); + + /* switch off state machine because codeword is decoded and/or because segment is empty */ + *ptrState = NULL; +} + + + +/* ========================================================================================= + the states of the statemachine + ========================================================================================= */ + + +/*--------------------------------------------------------------------------------------------- + description: Decodes the body of a codeword. This State is used for codebooks 1,2,5 and 6. + No sign bits are decoded, because the table of the quantized spectral values + has got a valid sign at the quantized spectral lines. +----------------------------------------------------------------------------------------------- + output: Two or four quantizes spectral values written at position where pResultPointr + points to +----------------------------------------------------------------------------------------------- + return: 0 +-------------------------------------------------------------------------------------------- */ +UINT Hcr_State_BODY_ONLY(HANDLE_FDK_BITSTREAM bs, void *ptr) +{ + H_HCR_INFO pHcr = (H_HCR_INFO)ptr; + UINT *pSegmentBitfield; + UINT *pCodewordBitfield; + UINT segmentOffset; + FIXP_DBL *pResultBase; + UINT *iNode; + USHORT *iResultPointer; + UINT codewordOffset; + UINT branchNode; + UINT branchValue; + UINT iQSC; + UINT treeNode; + UCHAR carryBit; + USHORT *pLeftStartOfSegment; + USHORT *pRightStartOfSegment; + SCHAR *pRemainingBitsInSegment; + UCHAR readDirection; + UCHAR *pCodebook; + UCHAR dimCntr; + const UINT *pCurrentTree; + const UCHAR *pCbDimension; + const SCHAR *pQuantVal; + const SCHAR *pQuantValBase; + + pRemainingBitsInSegment = pHcr->segmentInfo.pRemainingBitsInSegment; + pLeftStartOfSegment = pHcr->segmentInfo.pLeftStartOfSegment; + pRightStartOfSegment = pHcr->segmentInfo.pRightStartOfSegment; + readDirection = pHcr->segmentInfo.readDirection; + pSegmentBitfield = pHcr->segmentInfo.pSegmentBitfield; + pCodewordBitfield = pHcr->segmentInfo.pCodewordBitfield; + segmentOffset = pHcr->segmentInfo.segmentOffset; + + pCodebook = pHcr->nonPcwSideinfo.pCodebook; + iNode = pHcr->nonPcwSideinfo.iNode; + pResultBase = pHcr->nonPcwSideinfo.pResultBase; + iResultPointer = pHcr->nonPcwSideinfo.iResultPointer; + codewordOffset = pHcr->nonPcwSideinfo.codewordOffset; + + pCbDimension = pHcr->tableInfo.pCbDimension; + + treeNode = iNode[codewordOffset]; + pCurrentTree = aHuffTable[pCodebook[codewordOffset]]; + + + for ( ; pRemainingBitsInSegment[segmentOffset] > 0 ; pRemainingBitsInSegment[segmentOffset] -= 1 ) { + + carryBit = HcrGetABitFromBitstream( bs, + &pLeftStartOfSegment[segmentOffset], + &pRightStartOfSegment[segmentOffset], + readDirection); + + CarryBitToBranchValue(carryBit, /* make a step in decoding tree */ + treeNode, + &branchValue, + &branchNode); + + /* if end of branch reached write out lines and count bits needed for sign, otherwise store node in codeword sideinfo */ + if ((branchNode & TEST_BIT_10) == TEST_BIT_10) { /* test bit 10 ; ==> body is complete */ + pQuantValBase = aQuantTable[pCodebook[codewordOffset]]; /* get base address of quantized values belonging to current codebook */ + pQuantVal = pQuantValBase + branchValue; /* set pointer to first valid line [of 2 or 4 quantized values] */ + + iQSC = iResultPointer[codewordOffset]; /* get position of first line for writing out result */ + + for ( dimCntr = pCbDimension[pCodebook[codewordOffset]]; dimCntr != 0; dimCntr-- ) { + pResultBase[iQSC++] = (FIXP_DBL)*pQuantVal++; /* write out 2 or 4 lines into spectrum; no Sign bits available in this state */ + } + + ClearBitFromBitfield(&(pHcr->nonPcwSideinfo.pState), + segmentOffset, + pCodewordBitfield); /* clear a bit in bitfield and switch off statemachine */ + pRemainingBitsInSegment[segmentOffset] -= 1; /* last reinitialzation of for loop counter (see above) is done here */ + break; /* end of branch in tree reached i.e. a whole nonPCW-Body is decoded */ + } + else { /* body is not decoded completely: */ + treeNode = *(pCurrentTree + branchValue); /* update treeNode for further step in decoding tree */ + } + } + iNode[codewordOffset] = treeNode; /* store updated treeNode because maybe decoding of codeword body not finished yet */ + + if ( pRemainingBitsInSegment[segmentOffset] <= 0 ) { + ClearBitFromBitfield(&(pHcr->nonPcwSideinfo.pState), + segmentOffset, + pSegmentBitfield); /* clear a bit in bitfield and switch off statemachine */ + +#if STATE_MACHINE_ERROR_CHECK + if ( pRemainingBitsInSegment[segmentOffset] < 0 ) { + pHcr->decInOut.errorLog |= STATE_ERROR_BODY_ONLY; + return BODY_ONLY; + } +#endif + } + + return STOP_THIS_STATE; +} + + +/*--------------------------------------------------------------------------------------------- + description: Decodes the codeword body, writes out result and counts the number of quantized + spectral values, which are different form zero. For those values sign bits are + needed. + + If sign bit counter cntSign is different from zero, switch to next state to + decode sign Bits there. + If sign bit counter cntSign is zero, no sign bits are needed and codeword is + decoded. +----------------------------------------------------------------------------------------------- + output: Two or four written quantizes spectral values written at position where + pResultPointr points to. The signs of those lines may be wrong. If the signs + [on just one signle sign] is wrong, the next state will correct it. +----------------------------------------------------------------------------------------------- + return: 0 +-------------------------------------------------------------------------------------------- */ +UINT Hcr_State_BODY_SIGN__BODY(HANDLE_FDK_BITSTREAM bs, void *ptr) +{ + H_HCR_INFO pHcr = (H_HCR_INFO)ptr; + SCHAR *pRemainingBitsInSegment; + USHORT *pLeftStartOfSegment; + USHORT *pRightStartOfSegment; + UCHAR readDirection; + UINT *pSegmentBitfield; + UINT *pCodewordBitfield; + UINT segmentOffset; + + UCHAR *pCodebook; + UINT *iNode; + UCHAR *pCntSign; + FIXP_DBL *pResultBase; + USHORT *iResultPointer; + UINT codewordOffset; + + UINT iQSC; + UINT cntSign; + UCHAR dimCntr; + UCHAR carryBit; + SCHAR *pSta; + UINT treeNode; + UINT branchValue; + UINT branchNode; + const UCHAR *pCbDimension; + const UINT *pCurrentTree; + const SCHAR *pQuantValBase; + const SCHAR *pQuantVal; + + pRemainingBitsInSegment = pHcr->segmentInfo.pRemainingBitsInSegment; + pLeftStartOfSegment = pHcr->segmentInfo.pLeftStartOfSegment; + pRightStartOfSegment = pHcr->segmentInfo.pRightStartOfSegment; + readDirection = pHcr->segmentInfo.readDirection; + pSegmentBitfield = pHcr->segmentInfo.pSegmentBitfield; + pCodewordBitfield = pHcr->segmentInfo.pCodewordBitfield; + segmentOffset = pHcr->segmentInfo.segmentOffset; + + pCodebook = pHcr->nonPcwSideinfo.pCodebook; + iNode = pHcr->nonPcwSideinfo.iNode; + pCntSign = pHcr->nonPcwSideinfo.pCntSign; + pResultBase = pHcr->nonPcwSideinfo.pResultBase; + iResultPointer = pHcr->nonPcwSideinfo.iResultPointer; + codewordOffset = pHcr->nonPcwSideinfo.codewordOffset; + pSta = pHcr->nonPcwSideinfo.pSta; + + pCbDimension = pHcr->tableInfo.pCbDimension; + + treeNode = iNode[codewordOffset]; + pCurrentTree = aHuffTable[pCodebook[codewordOffset]]; + + + for ( ; pRemainingBitsInSegment[segmentOffset] > 0 ; pRemainingBitsInSegment[segmentOffset] -= 1 ) { + + carryBit = HcrGetABitFromBitstream( bs, + &pLeftStartOfSegment[segmentOffset], + &pRightStartOfSegment[segmentOffset], + readDirection); + + CarryBitToBranchValue(carryBit, /* make a step in decoding tree */ + treeNode, + &branchValue, + &branchNode); + + /* if end of branch reached write out lines and count bits needed for sign, otherwise store node in codeword sideinfo */ + if ((branchNode & TEST_BIT_10) == TEST_BIT_10) { /* test bit 10 ; if set body complete */ + /* body completely decoded; branchValue is valid, set pQuantVal to first (of two or four) quantized spectral coefficients */ + pQuantValBase = aQuantTable[pCodebook[codewordOffset]]; /* get base address of quantized values belonging to current codebook */ + pQuantVal = pQuantValBase + branchValue; /* set pointer to first valid line [of 2 or 4 quantized values] */ + + iQSC = iResultPointer[codewordOffset]; /* get position of first line for writing result */ + + /* codeword decoding result is written out here: Write out 2 or 4 quantized spectral values with probably */ + /* wrong sign and count number of values which are different from zero for sign bit decoding [which happens in next state] */ + cntSign = 0; + for ( dimCntr = pCbDimension[pCodebook[codewordOffset]]; dimCntr != 0; dimCntr-- ) { + pResultBase[iQSC++] = (FIXP_DBL)*pQuantVal; /* write quant. spec. coef. into spectrum */ + if ( *pQuantVal++ != 0 ) { + cntSign += 1; + } + } + + if ( cntSign == 0 ) { + ClearBitFromBitfield(&(pHcr->nonPcwSideinfo.pState), + segmentOffset, + pCodewordBitfield); /* clear a bit in bitfield and switch off statemachine */ + } + else { + pCntSign[codewordOffset] = cntSign; /* write sign count result into codewordsideinfo of current codeword */ + pSta[codewordOffset] = BODY_SIGN__SIGN; /* change state */ + pHcr->nonPcwSideinfo.pState = aStateConstant2State[pSta[codewordOffset]]; /* get state from separate array of cw-sideinfo */ + } + pRemainingBitsInSegment[segmentOffset] -= 1; /* last reinitialzation of for loop counter (see above) is done here */ + break; /* end of branch in tree reached i.e. a whole nonPCW-Body is decoded */ + } + else {/* body is not decoded completely: */ + treeNode = *(pCurrentTree + branchValue); /* update treeNode for further step in decoding tree */ + } + } + iNode[codewordOffset] = treeNode; /* store updated treeNode because maybe decoding of codeword body not finished yet */ + + if ( pRemainingBitsInSegment[segmentOffset] <= 0 ) { + ClearBitFromBitfield(&(pHcr->nonPcwSideinfo.pState), + segmentOffset, + pSegmentBitfield); /* clear a bit in bitfield and switch off statemachine */ + +#if STATE_MACHINE_ERROR_CHECK + if ( pRemainingBitsInSegment[segmentOffset] < 0 ) { + pHcr->decInOut.errorLog |= STATE_ERROR_BODY_SIGN__BODY; + return BODY_SIGN__BODY; + } +#endif + } + + return STOP_THIS_STATE; +} + + +/*--------------------------------------------------------------------------------------------- + description: This state decodes the sign bits belonging to a codeword. The state is called + as often in different "trials" until pCntSgn[codewordOffset] is zero. +----------------------------------------------------------------------------------------------- + output: The two or four quantizes spectral values (written in previous state) have + now the correct sign. +----------------------------------------------------------------------------------------------- + return: 0 +-------------------------------------------------------------------------------------------- */ +UINT Hcr_State_BODY_SIGN__SIGN(HANDLE_FDK_BITSTREAM bs, void *ptr) +{ + H_HCR_INFO pHcr = (H_HCR_INFO)ptr; + SCHAR *pRemainingBitsInSegment; + USHORT *pLeftStartOfSegment; + USHORT *pRightStartOfSegment; + UCHAR readDirection; + UINT *pSegmentBitfield; + UINT *pCodewordBitfield; + UINT segmentOffset; + + UCHAR *pCntSign; + FIXP_DBL *pResultBase; + USHORT *iResultPointer; + UINT codewordOffset; + UCHAR carryBit; + UINT iQSC; + UCHAR cntSign; + + pRemainingBitsInSegment = pHcr->segmentInfo.pRemainingBitsInSegment; + pLeftStartOfSegment = pHcr->segmentInfo.pLeftStartOfSegment; + pRightStartOfSegment = pHcr->segmentInfo.pRightStartOfSegment; + readDirection = pHcr->segmentInfo.readDirection; + pSegmentBitfield = pHcr->segmentInfo.pSegmentBitfield; + pCodewordBitfield = pHcr->segmentInfo.pCodewordBitfield; + segmentOffset = pHcr->segmentInfo.segmentOffset; + + pCntSign = pHcr->nonPcwSideinfo.pCntSign; + pResultBase = pHcr->nonPcwSideinfo.pResultBase; + iResultPointer = pHcr->nonPcwSideinfo.iResultPointer; + codewordOffset = pHcr->nonPcwSideinfo.codewordOffset; + iQSC = iResultPointer[codewordOffset]; + cntSign = pCntSign[codewordOffset]; + + + + /* loop for sign bit decoding */ + for ( ; pRemainingBitsInSegment[segmentOffset] > 0 ; pRemainingBitsInSegment[segmentOffset] -= 1 ) { + + carryBit = HcrGetABitFromBitstream( bs, + &pLeftStartOfSegment[segmentOffset], + &pRightStartOfSegment[segmentOffset], + readDirection); + cntSign -= 1; /* decrement sign counter because one sign bit has been read */ + + /* search for a line (which was decoded in previous state) which is not zero. [This value will get a sign] */ + while ( pResultBase[iQSC] == (FIXP_DBL)0 ) { + iQSC++; /* points to current value different from zero */ + } + + /* put sign together with line; if carryBit is zero, the sign is ok already; no write operation necessary in this case */ + if ( carryBit != 0 ) { + pResultBase[iQSC] = -pResultBase[iQSC]; /* carryBit = 1 --> minus */ + } + + iQSC++; /* update pointer to next (maybe valid) value */ + + if ( cntSign == 0 ) { /* if (cntSign==0) ==> set state CODEWORD_DECODED */ + ClearBitFromBitfield(&(pHcr->nonPcwSideinfo.pState), + segmentOffset, + pCodewordBitfield); /* clear a bit in bitfield and switch off statemachine */ + pRemainingBitsInSegment[segmentOffset] -= 1; /* last reinitialzation of for loop counter (see above) is done here */ + break; /* whole nonPCW-Body and according sign bits are decoded */ + } + } + pCntSign[codewordOffset] = cntSign; + iResultPointer[codewordOffset] = iQSC; /* store updated pResultPointer */ + + if ( pRemainingBitsInSegment[segmentOffset] <= 0 ) { + ClearBitFromBitfield(&(pHcr->nonPcwSideinfo.pState), + segmentOffset, + pSegmentBitfield); /* clear a bit in bitfield and switch off statemachine */ + +#if STATE_MACHINE_ERROR_CHECK + if ( pRemainingBitsInSegment[segmentOffset] < 0 ) { + pHcr->decInOut.errorLog |= STATE_ERROR_BODY_SIGN__SIGN; + return BODY_SIGN__SIGN; + } +#endif + } + + return STOP_THIS_STATE; +} + + +/*--------------------------------------------------------------------------------------------- + description: Decodes the codeword body in case of codebook is 11. Writes out resulting + two or four lines [with probably wrong sign] and counts the number of + lines, which are different form zero. This information is needed in next + state where sign bits will be decoded, if necessary. + If sign bit counter cntSign is zero, no sign bits are needed and codeword is + decoded completely. +----------------------------------------------------------------------------------------------- + output: Two lines (quantizes spectral coefficients) which are probably wrong. The + sign may be wrong and if one or two values is/are 16, the following states + will decode the escape sequence to correct the values which are wirtten here. +----------------------------------------------------------------------------------------------- + return: 0 +-------------------------------------------------------------------------------------------- */ +UINT Hcr_State_BODY_SIGN_ESC__BODY(HANDLE_FDK_BITSTREAM bs, void *ptr) +{ + H_HCR_INFO pHcr = (H_HCR_INFO)ptr; + SCHAR *pRemainingBitsInSegment; + USHORT *pLeftStartOfSegment; + USHORT *pRightStartOfSegment; + UCHAR readDirection; + UINT *pSegmentBitfield; + UINT *pCodewordBitfield; + UINT segmentOffset; + + UINT *iNode; + UCHAR *pCntSign; + FIXP_DBL *pResultBase; + USHORT *iResultPointer; + UINT codewordOffset; + + UCHAR carryBit; + UINT iQSC; + UINT cntSign; + UINT dimCntr; + UINT treeNode; + SCHAR *pSta; + UINT branchNode; + UINT branchValue; + const UINT *pCurrentTree; + const SCHAR *pQuantValBase; + const SCHAR *pQuantVal; + + pRemainingBitsInSegment = pHcr->segmentInfo.pRemainingBitsInSegment; + pLeftStartOfSegment = pHcr->segmentInfo.pLeftStartOfSegment; + pRightStartOfSegment = pHcr->segmentInfo.pRightStartOfSegment; + readDirection = pHcr->segmentInfo.readDirection; + pSegmentBitfield = pHcr->segmentInfo.pSegmentBitfield; + pCodewordBitfield = pHcr->segmentInfo.pCodewordBitfield; + segmentOffset = pHcr->segmentInfo.segmentOffset; + + iNode = pHcr->nonPcwSideinfo.iNode; + pCntSign = pHcr->nonPcwSideinfo.pCntSign; + pResultBase = pHcr->nonPcwSideinfo.pResultBase; + iResultPointer = pHcr->nonPcwSideinfo.iResultPointer; + codewordOffset = pHcr->nonPcwSideinfo.codewordOffset; + pSta = pHcr->nonPcwSideinfo.pSta; + + treeNode = iNode[codewordOffset]; + pCurrentTree = aHuffTable[ESCAPE_CODEBOOK]; + + + for ( ; pRemainingBitsInSegment[segmentOffset] > 0 ; pRemainingBitsInSegment[segmentOffset] -= 1 ) { + + carryBit = HcrGetABitFromBitstream( bs, + &pLeftStartOfSegment[segmentOffset], + &pRightStartOfSegment[segmentOffset], + readDirection); + + /* make a step in tree */ + CarryBitToBranchValue(carryBit, + treeNode, + &branchValue, + &branchNode); + + /* if end of branch reached write out lines and count bits needed for sign, otherwise store node in codeword sideinfo */ + if ((branchNode & TEST_BIT_10) == TEST_BIT_10) { /* test bit 10 ; if set body complete */ + + /* body completely decoded; branchValue is valid */ + /* set pQuantVol to first (of two or four) quantized spectral coefficients */ + pQuantValBase = aQuantTable[ESCAPE_CODEBOOK]; /* get base address of quantized values belonging to current codebook */ + pQuantVal = pQuantValBase + branchValue; /* set pointer to first valid line [of 2 or 4 quantized values] */ + + /* make backup from original resultPointer in node storage for state BODY_SIGN_ESC__SIGN */ + iNode[codewordOffset] = iResultPointer[codewordOffset]; + + /* get position of first line for writing result */ + iQSC = iResultPointer[codewordOffset]; + + /* codeword decoding result is written out here: Write out 2 or 4 quantized spectral values with probably */ + /* wrong sign and count number of values which are different from zero for sign bit decoding [which happens in next state] */ + cntSign = 0; + + for ( dimCntr = DIMENSION_OF_ESCAPE_CODEBOOK; dimCntr != 0; dimCntr-- ) { + pResultBase[iQSC++] = (FIXP_DBL)*pQuantVal; /* write quant. spec. coef. into spectrum */ + if ( *pQuantVal++ != 0 ) { + cntSign += 1; + } + } + + if ( cntSign == 0 ) { + ClearBitFromBitfield(&(pHcr->nonPcwSideinfo.pState), + segmentOffset, + pCodewordBitfield); /* clear a bit in bitfield and switch off statemachine */ + /* codeword decoded */ + } + else { + /* write sign count result into codewordsideinfo of current codeword */ + pCntSign[codewordOffset] = cntSign; + pSta[codewordOffset] = BODY_SIGN_ESC__SIGN; /* change state */ + pHcr->nonPcwSideinfo.pState = aStateConstant2State[pSta[codewordOffset]]; /* get state from separate array of cw-sideinfo */ + } + pRemainingBitsInSegment[segmentOffset] -= 1; /* the last reinitialzation of for loop counter (see above) is done here */ + break; /* end of branch in tree reached i.e. a whole nonPCW-Body is decoded */ + } + else { /* body is not decoded completely: */ + /* update treeNode for further step in decoding tree and store updated treeNode because maybe no more bits left in segment */ + treeNode = *(pCurrentTree + branchValue); + iNode[codewordOffset] = treeNode; + } + } + + if ( pRemainingBitsInSegment[segmentOffset] <= 0 ) { + ClearBitFromBitfield(&(pHcr->nonPcwSideinfo.pState), + segmentOffset, + pSegmentBitfield); /* clear a bit in bitfield and switch off statemachine */ + +#if STATE_MACHINE_ERROR_CHECK + if ( pRemainingBitsInSegment[segmentOffset] < 0 ) { + pHcr->decInOut.errorLog |= STATE_ERROR_BODY_SIGN_ESC__BODY; + return BODY_SIGN_ESC__BODY; + } +#endif + } + + return STOP_THIS_STATE; +} + + +/*--------------------------------------------------------------------------------------------- + description: This state decodes the sign bits, if a codeword of codebook 11 needs some. + A flag named 'flagB' in codeword sideinfo is set, if the second line of + quantized spectral values is 16. The 'flagB' is used in case of decoding + of a escape sequence is necessary as far as the second line is concerned. + + If only the first line needs an escape sequence, the flagB is cleared. + If only the second line needs an escape sequence, the flagB is not used. + + For storing sideinfo in case of escape sequence decoding one single word + can be used for both escape sequences because they are decoded not at the + same time: + + + bit 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + ===== == == =========== =========== =================================== + ^ ^ ^ ^ ^ ^ + | | | | | | + res. flagA flagB escapePrefixUp escapePrefixDown escapeWord + +----------------------------------------------------------------------------------------------- + output: Two lines with correct sign. If one or two values is/are 16, the lines are + not valid, otherwise they are. +----------------------------------------------------------------------------------------------- + return: 0 +-------------------------------------------------------------------------------------------- */ +UINT Hcr_State_BODY_SIGN_ESC__SIGN(HANDLE_FDK_BITSTREAM bs, void *ptr) +{ + H_HCR_INFO pHcr = (H_HCR_INFO)ptr; + SCHAR *pRemainingBitsInSegment; + USHORT *pLeftStartOfSegment; + USHORT *pRightStartOfSegment; + UCHAR readDirection; + UINT *pSegmentBitfield; + UINT *pCodewordBitfield; + UINT segmentOffset; + + UINT *iNode; + UCHAR *pCntSign; + FIXP_DBL *pResultBase; + USHORT *iResultPointer; + UINT *pEscapeSequenceInfo; + UINT codewordOffset; + + UINT iQSC; + UCHAR cntSign; + UINT flagA; + UINT flagB; + UINT flags; + UCHAR carryBit; + SCHAR *pSta; + + pRemainingBitsInSegment = pHcr->segmentInfo.pRemainingBitsInSegment; + pLeftStartOfSegment = pHcr->segmentInfo.pLeftStartOfSegment; + pRightStartOfSegment = pHcr->segmentInfo.pRightStartOfSegment; + readDirection = pHcr->segmentInfo.readDirection; + pSegmentBitfield = pHcr->segmentInfo.pSegmentBitfield; + pCodewordBitfield = pHcr->segmentInfo.pCodewordBitfield; + segmentOffset = pHcr->segmentInfo.segmentOffset; + + iNode = pHcr->nonPcwSideinfo.iNode; + pCntSign = pHcr->nonPcwSideinfo.pCntSign; + pResultBase = pHcr->nonPcwSideinfo.pResultBase; + iResultPointer = pHcr->nonPcwSideinfo.iResultPointer; + pEscapeSequenceInfo = pHcr->nonPcwSideinfo.pEscapeSequenceInfo; + codewordOffset = pHcr->nonPcwSideinfo.codewordOffset; + pSta = pHcr->nonPcwSideinfo.pSta; + + iQSC = iResultPointer[codewordOffset]; + cntSign = pCntSign[codewordOffset]; + + + /* loop for sign bit decoding */ + for ( ; pRemainingBitsInSegment[segmentOffset] > 0 ; pRemainingBitsInSegment[segmentOffset] -= 1 ) { + + carryBit = HcrGetABitFromBitstream( bs, + &pLeftStartOfSegment[segmentOffset], + &pRightStartOfSegment[segmentOffset], + readDirection); + + /* decrement sign counter because one sign bit has been read */ + cntSign -= 1; + pCntSign[codewordOffset] = cntSign; + + /* get a quantized spectral value (which was decoded in previous state) which is not zero. [This value will get a sign] */ + while ( pResultBase[iQSC] == (FIXP_DBL)0 ) { + iQSC++; + } + iResultPointer[codewordOffset] = iQSC; + + /* put negative sign together with quantized spectral value; if carryBit is zero, the sign is ok already; no write operation necessary in this case */ + if ( carryBit != 0 ) { + pResultBase[iQSC] = - pResultBase[iQSC]; /* carryBit = 1 --> minus */ + } + iQSC++; /* update index to next (maybe valid) value */ + iResultPointer[codewordOffset] = iQSC; + + if ( cntSign == 0 ) { + /* all sign bits are decoded now */ + pRemainingBitsInSegment[segmentOffset] -= 1; /* last reinitialzation of for loop counter (see above) is done here */ + + /* check decoded values if codeword is decoded: Check if one or two escape sequences 16 follow */ + + /* step 0 */ + /* restore pointer to first decoded quantized value [ = original pResultPointr] from index iNode prepared in State_BODY_SIGN_ESC__BODY */ + iQSC = iNode[codewordOffset]; + + /* step 1 */ + /* test first value if escape sequence follows */ + flagA = 0; /* for first possible escape sequence */ + if ( fixp_abs(pResultBase[iQSC++]) == (FIXP_DBL)ESCAPE_VALUE ) { + flagA = 1; + } + + /* step 2 */ + /* test second value if escape sequence follows */ + flagB = 0; /* for second possible escape sequence */ + if ( fixp_abs(pResultBase[iQSC]) == (FIXP_DBL)ESCAPE_VALUE ) { + flagB = 1; + } + + + /* step 3 */ + /* evaluate flag result and go on if necessary */ + if ( !flagA && !flagB ) { + ClearBitFromBitfield(&(pHcr->nonPcwSideinfo.pState), + segmentOffset, + pCodewordBitfield); /* clear a bit in bitfield and switch off statemachine */ + } + else { + /* at least one of two lines is 16 */ + /* store both flags at correct positions in non PCW codeword sideinfo pEscapeSequenceInfo[codewordOffset] */ + flags = 0; + flags = flagA << POSITION_OF_FLAG_A; + flags |= (flagB << POSITION_OF_FLAG_B); + pEscapeSequenceInfo[codewordOffset] = flags; + + + /* set next state */ + pSta[codewordOffset] = BODY_SIGN_ESC__ESC_PREFIX; + pHcr->nonPcwSideinfo.pState = aStateConstant2State[pSta[codewordOffset]]; /* get state from separate array of cw-sideinfo */ + + /* set result pointer to the first line of the two decoded lines */ + iResultPointer[codewordOffset] = iNode[codewordOffset]; + + if ( !flagA && flagB ) { + /* update pResultPointr ==> state Stat_BODY_SIGN_ESC__ESC_WORD writes to correct position. Second value is the one and only escape value */ + iQSC = iResultPointer[codewordOffset]; + iQSC++; + iResultPointer[codewordOffset] = iQSC; + } + + } /* at least one of two lines is 16 */ + break; /* nonPCW-Body at cb 11 and according sign bits are decoded */ + + } /* if ( cntSign == 0 ) */ + } /* loop over remaining Bits in segment */ + + if ( pRemainingBitsInSegment[segmentOffset] <= 0 ) { + ClearBitFromBitfield(&(pHcr->nonPcwSideinfo.pState), + segmentOffset, + pSegmentBitfield); /* clear a bit in bitfield and switch off statemachine */ + +#if STATE_MACHINE_ERROR_CHECK + if ( pRemainingBitsInSegment[segmentOffset] < 0 ) { + pHcr->decInOut.errorLog |= STATE_ERROR_BODY_SIGN_ESC__SIGN; + return BODY_SIGN_ESC__SIGN; + } +#endif + + } + return STOP_THIS_STATE; +} + + +/*--------------------------------------------------------------------------------------------- + description: Decode escape prefix of first or second escape sequence. The escape prefix + consists of ones. The following zero is also decoded here. +----------------------------------------------------------------------------------------------- + output: If the single separator-zero which follows the escape-prefix-ones is not yet decoded: + The value 'escapePrefixUp' in word pEscapeSequenceInfo[codewordOffset] is updated. + + If the single separator-zero which follows the escape-prefix-ones is decoded: + Two updated values 'escapePrefixUp' and 'escapePrefixDown' in word + pEscapeSequenceInfo[codewordOffset]. This State is finished. Switch to next state. +----------------------------------------------------------------------------------------------- + return: 0 +-------------------------------------------------------------------------------------------- */ +UINT Hcr_State_BODY_SIGN_ESC__ESC_PREFIX(HANDLE_FDK_BITSTREAM bs, void *ptr) +{ + H_HCR_INFO pHcr = (H_HCR_INFO)ptr; + SCHAR *pRemainingBitsInSegment; + USHORT *pLeftStartOfSegment; + USHORT *pRightStartOfSegment; + UCHAR readDirection; + UINT *pSegmentBitfield; + UINT segmentOffset; + UINT *pEscapeSequenceInfo; + UINT codewordOffset; + UCHAR carryBit; + UINT escapePrefixUp; + SCHAR *pSta; + + pRemainingBitsInSegment = pHcr->segmentInfo.pRemainingBitsInSegment; + pLeftStartOfSegment = pHcr->segmentInfo.pLeftStartOfSegment; + pRightStartOfSegment = pHcr->segmentInfo.pRightStartOfSegment; + readDirection = pHcr->segmentInfo.readDirection; + pSegmentBitfield = pHcr->segmentInfo.pSegmentBitfield; + segmentOffset = pHcr->segmentInfo.segmentOffset; + pEscapeSequenceInfo = pHcr->nonPcwSideinfo.pEscapeSequenceInfo; + codewordOffset = pHcr->nonPcwSideinfo.codewordOffset; + pSta = pHcr->nonPcwSideinfo.pSta; + + escapePrefixUp = (pEscapeSequenceInfo[codewordOffset] & MASK_ESCAPE_PREFIX_UP) >> LSB_ESCAPE_PREFIX_UP; + + + /* decode escape prefix */ + for ( ; pRemainingBitsInSegment[segmentOffset] > 0 ; pRemainingBitsInSegment[segmentOffset] -= 1 ) { + + carryBit = HcrGetABitFromBitstream( bs, + &pLeftStartOfSegment[segmentOffset], + &pRightStartOfSegment[segmentOffset], + readDirection); + + /* count ones and store sum in escapePrefixUp */ + if ( carryBit == 1 ) { + escapePrefixUp += 1; /* update conter for ones */ + + /* store updated counter in sideinfo of current codeword */ + pEscapeSequenceInfo[codewordOffset] &= ~MASK_ESCAPE_PREFIX_UP; /* delete old escapePrefixUp */ + escapePrefixUp <<= LSB_ESCAPE_PREFIX_UP; /* shift to correct position */ + pEscapeSequenceInfo[codewordOffset] |= escapePrefixUp; /* insert new escapePrefixUp */ + escapePrefixUp >>= LSB_ESCAPE_PREFIX_UP; /* shift back down */ + } + else { /* separator [zero] reached */ + pRemainingBitsInSegment[segmentOffset] -= 1; /* last reinitialzation of for loop counter (see above) is done here */ + escapePrefixUp += 4; /* if escape_separator '0' appears, add 4 and ==> break */ + + /* store escapePrefixUp in pEscapeSequenceInfo[codewordOffset] at bit position escapePrefixUp */ + pEscapeSequenceInfo[codewordOffset] &= ~MASK_ESCAPE_PREFIX_UP; /* delete old escapePrefixUp */ + escapePrefixUp <<= LSB_ESCAPE_PREFIX_UP; /* shift to correct position */ + pEscapeSequenceInfo[codewordOffset] |= escapePrefixUp; /* insert new escapePrefixUp */ + escapePrefixUp >>= LSB_ESCAPE_PREFIX_UP; /* shift back down */ + + /* store escapePrefixUp in pEscapeSequenceInfo[codewordOffset] at bit position escapePrefixDown */ + pEscapeSequenceInfo[codewordOffset] &= ~MASK_ESCAPE_PREFIX_DOWN; /* delete old escapePrefixDown */ + escapePrefixUp <<= LSB_ESCAPE_PREFIX_DOWN; /* shift to correct position */ + pEscapeSequenceInfo[codewordOffset] |= escapePrefixUp; /* insert new escapePrefixDown */ + escapePrefixUp >>= LSB_ESCAPE_PREFIX_DOWN; /* shift back down */ + + pSta[codewordOffset] = BODY_SIGN_ESC__ESC_WORD; /* set next state */ + pHcr->nonPcwSideinfo.pState = aStateConstant2State[pSta[codewordOffset]]; /* get state from separate array of cw-sideinfo */ + break; + } + } + + if ( pRemainingBitsInSegment[segmentOffset] <= 0 ) { + ClearBitFromBitfield(&(pHcr->nonPcwSideinfo.pState), + segmentOffset, + pSegmentBitfield); /* clear a bit in bitfield and switch off statemachine */ + +#if STATE_MACHINE_ERROR_CHECK + if ( pRemainingBitsInSegment[segmentOffset] < 0 ) { + pHcr->decInOut.errorLog |= STATE_ERROR_BODY_SIGN_ESC__ESC_PREFIX; + return BODY_SIGN_ESC__ESC_PREFIX; + } +#endif + } + + return STOP_THIS_STATE; +} + + +/*--------------------------------------------------------------------------------------------- + description: Decode escapeWord of escape sequence. If the escape sequence is decoded + completely, assemble quantized-spectral-escape-coefficient and replace the + previous decoded 16 by the new value. + Test flagB. If flagB is set, the second escape sequence must be decoded. If + flagB is not set, the codeword is decoded and the state machine is switched + off. +----------------------------------------------------------------------------------------------- + output: Two lines with valid sign. At least one of both lines has got the correct + value. +----------------------------------------------------------------------------------------------- + return: 0 +-------------------------------------------------------------------------------------------- */ +UINT Hcr_State_BODY_SIGN_ESC__ESC_WORD(HANDLE_FDK_BITSTREAM bs, void *ptr) +{ + H_HCR_INFO pHcr = (H_HCR_INFO)ptr; + SCHAR *pRemainingBitsInSegment; + USHORT *pLeftStartOfSegment; + USHORT *pRightStartOfSegment; + UCHAR readDirection; + UINT *pSegmentBitfield; + UINT *pCodewordBitfield; + UINT segmentOffset; + + FIXP_DBL *pResultBase; + USHORT *iResultPointer; + UINT *pEscapeSequenceInfo; + UINT codewordOffset; + + UINT escapeWord; + UINT escapePrefixDown; + UINT escapePrefixUp; + UCHAR carryBit; + UINT iQSC; + INT sign; + UINT flagA; + UINT flagB; + SCHAR *pSta; + + pRemainingBitsInSegment = pHcr->segmentInfo.pRemainingBitsInSegment; + pLeftStartOfSegment = pHcr->segmentInfo.pLeftStartOfSegment; + pRightStartOfSegment = pHcr->segmentInfo.pRightStartOfSegment; + readDirection = pHcr->segmentInfo.readDirection; + pSegmentBitfield = pHcr->segmentInfo.pSegmentBitfield; + pCodewordBitfield = pHcr->segmentInfo.pCodewordBitfield; + segmentOffset = pHcr->segmentInfo.segmentOffset; + + pResultBase = pHcr->nonPcwSideinfo.pResultBase; + iResultPointer = pHcr->nonPcwSideinfo.iResultPointer; + pEscapeSequenceInfo = pHcr->nonPcwSideinfo.pEscapeSequenceInfo; + codewordOffset = pHcr->nonPcwSideinfo.codewordOffset; + pSta = pHcr->nonPcwSideinfo.pSta; + + escapeWord = pEscapeSequenceInfo[codewordOffset] & MASK_ESCAPE_WORD; + escapePrefixDown = (pEscapeSequenceInfo[codewordOffset] & MASK_ESCAPE_PREFIX_DOWN) >> LSB_ESCAPE_PREFIX_DOWN; + + + /* decode escape word */ + for ( ; pRemainingBitsInSegment[segmentOffset] > 0 ; pRemainingBitsInSegment[segmentOffset] -= 1 ) { + + carryBit = HcrGetABitFromBitstream( bs, + &pLeftStartOfSegment[segmentOffset], + &pRightStartOfSegment[segmentOffset], + readDirection); + + /* build escape word */ + escapeWord <<= 1; /* left shift previous decoded part of escapeWord by on bit */ + escapeWord = escapeWord | carryBit; /* assemble escape word by bitwise or */ + + /* decrement counter for length of escape word because one more bit was decoded */ + escapePrefixDown -= 1; + + /* store updated escapePrefixDown */ + pEscapeSequenceInfo[codewordOffset] &= ~MASK_ESCAPE_PREFIX_DOWN; /* delete old escapePrefixDown */ + escapePrefixDown <<= LSB_ESCAPE_PREFIX_DOWN; /* shift to correct position */ + pEscapeSequenceInfo[codewordOffset] |= escapePrefixDown; /* insert new escapePrefixDown */ + escapePrefixDown >>= LSB_ESCAPE_PREFIX_DOWN; /* shift back */ + + + /* store updated escapeWord */ + pEscapeSequenceInfo[codewordOffset] &= ~MASK_ESCAPE_WORD; /* delete old escapeWord */ + pEscapeSequenceInfo[codewordOffset] |= escapeWord; /* insert new escapeWord */ + + + if ( escapePrefixDown == 0 ) { + pRemainingBitsInSegment[segmentOffset] -= 1; /* last reinitialzation of for loop counter (see above) is done here */ + + /* escape sequence decoded. Assemble escape-line and replace original line */ + + /* step 0 */ + /* derive sign */ + iQSC = iResultPointer[codewordOffset]; + sign = (pResultBase[iQSC] >= (FIXP_DBL)0) ? 1 : -1; /* get sign of escape value 16 */ + + /* step 1 */ + /* get escapePrefixUp */ + escapePrefixUp = (pEscapeSequenceInfo[codewordOffset] & MASK_ESCAPE_PREFIX_UP) >> LSB_ESCAPE_PREFIX_UP; + + /* step 2 */ + /* calculate escape value */ + pResultBase[iQSC] = (FIXP_DBL)(sign * (((INT) 1 << escapePrefixUp) + escapeWord)); + + /* get both flags from sideinfo (flags are not shifted to the lsb-position) */ + flagA = pEscapeSequenceInfo[codewordOffset] & MASK_FLAG_A; + flagB = pEscapeSequenceInfo[codewordOffset] & MASK_FLAG_B; + + /* step 3 */ + /* clear the whole escape sideinfo word */ + pEscapeSequenceInfo[codewordOffset] = 0; + + /* change state in dependence of flag flagB */ + if ( flagA != 0 ) { + /* first escape sequence decoded; previous decoded 16 has been replaced by valid line */ + + /* clear flagA in sideinfo word because this escape sequence has already beed decoded */ + pEscapeSequenceInfo[codewordOffset] &= ~MASK_FLAG_A; + + if ( flagB == 0 ) { + ClearBitFromBitfield(&(pHcr->nonPcwSideinfo.pState), + segmentOffset, + pCodewordBitfield); /* clear a bit in bitfield and switch off statemachine */ + } + else { + /* updated pointer to next and last 16 */ + iQSC++; + iResultPointer[codewordOffset] = iQSC; + + /* change state */ + pSta[codewordOffset] = BODY_SIGN_ESC__ESC_PREFIX; + pHcr->nonPcwSideinfo.pState = aStateConstant2State[pSta[codewordOffset]]; /* get state from separate array of cw-sideinfo */ + } + } + else { + ClearBitFromBitfield(&(pHcr->nonPcwSideinfo.pState), + segmentOffset, + pCodewordBitfield); /* clear a bit in bitfield and switch off statemachine */ + } + break; + } + } + + if ( pRemainingBitsInSegment[segmentOffset] <= 0 ) { + ClearBitFromBitfield(&(pHcr->nonPcwSideinfo.pState), + segmentOffset, + pSegmentBitfield); /* clear a bit in bitfield and switch off statemachine */ + +#if STATE_MACHINE_ERROR_CHECK + if ( pRemainingBitsInSegment[segmentOffset] < 0 ) { + pHcr->decInOut.errorLog |= STATE_ERROR_BODY_SIGN_ESC__ESC_WORD; + return BODY_SIGN_ESC__ESC_WORD; + } +#endif + } + + return STOP_THIS_STATE; +} + diff --git a/libAACdec/src/aacdec_hcrs.h b/libAACdec/src/aacdec_hcrs.h new file mode 100644 index 0000000..012c089 --- /dev/null +++ b/libAACdec/src/aacdec_hcrs.h @@ -0,0 +1,91 @@ +/***************************** MPEG-4 AAC Decoder *************************** + + (C) Copyright Fraunhofer IIS 2000-2008 + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Robert Weidner (DSP Solutions) + Description: HCR Decoder: Defines of state-constants, masks and + state-prototypes + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +*******************************************************************************/ + +#ifndef _AACDEC_HCRS_H_ +#define _AACDEC_HCRS_H_ + + + +#include "FDK_bitstream.h" +#include "aacdec_hcr_types.h" + /* The four different kinds of types of states are: */ +/* different states are defined as constants */ /* start middle=self next stop */ +#define STOP_THIS_STATE 0 /* */ +#define BODY_ONLY 1 /* X X X */ +#define BODY_SIGN__BODY 2 /* X X X X [stop if no sign] */ +#define BODY_SIGN__SIGN 3 /* X X [stop if sign bits decoded] */ +#define BODY_SIGN_ESC__BODY 4 /* X X X X [stop if no sign] */ +#define BODY_SIGN_ESC__SIGN 5 /* X X X [stop if no escape sequence] */ +#define BODY_SIGN_ESC__ESC_PREFIX 6 /* X X */ +#define BODY_SIGN_ESC__ESC_WORD 7 /* X X X [stop if abs(second qsc) != 16] */ + +/* examples: */ + +/* BODY_ONLY means only the codeword body will be decoded; no sign bits will follow and no escapesequence will follow */ + +/* BODY_SIGN__BODY means that the codeword consists of two parts; body and sign part. The part '__BODY' after the two underscores shows */ +/* that the bits which are currently decoded belong to the '__BODY' of the codeword and not to the sign part. */ + +/* BODY_SIGN_ESC__ESC_PB means that the codeword consists of three parts; body, sign and (here: two) escape sequences; */ +/* P = Prefix = ones */ +/* W = Escape Word */ +/* A = first possible (of two) Escape sequeces */ +/* B = second possible (of two) Escape sequeces */ +/* The part after the two underscores shows that the current bits which are decoded belong to the '__ESC_PB' - part of the */ +/* codeword. That means the body and the sign bits are decoded completely and the bits which are decoded now belong to */ +/* the escape sequence [P = prefix; B=second possible escape sequence] */ + + +#define MSB_31_MASK 0x80000000 /* masks MSB (= Bit 31) in a 32 bit word */ +#define DIMENSION_OF_ESCAPE_CODEBOOK 2 /* for cb >= 11 is dimension 2 */ +#define ESCAPE_CODEBOOK 11 + +#define MASK_ESCAPE_PREFIX_UP 0x000F0000 +#define LSB_ESCAPE_PREFIX_UP 16 + +#define MASK_ESCAPE_PREFIX_DOWN 0x0000F000 +#define LSB_ESCAPE_PREFIX_DOWN 12 + +#define MASK_ESCAPE_WORD 0x00000FFF +#define MASK_FLAG_A 0x00200000 +#define MASK_FLAG_B 0x00100000 + + +extern void DecodeNonPCWs(HANDLE_FDK_BITSTREAM bs, H_HCR_INFO hHcr); + +UINT Hcr_State_BODY_ONLY (HANDLE_FDK_BITSTREAM, void*); +UINT Hcr_State_BODY_SIGN__BODY (HANDLE_FDK_BITSTREAM, void*); +UINT Hcr_State_BODY_SIGN__SIGN (HANDLE_FDK_BITSTREAM, void*); +UINT Hcr_State_BODY_SIGN_ESC__BODY (HANDLE_FDK_BITSTREAM, void*); +UINT Hcr_State_BODY_SIGN_ESC__SIGN (HANDLE_FDK_BITSTREAM, void*); +UINT Hcr_State_BODY_SIGN_ESC__ESC_PREFIX (HANDLE_FDK_BITSTREAM, void*); +UINT Hcr_State_BODY_SIGN_ESC__ESC_WORD (HANDLE_FDK_BITSTREAM, void*); + +#endif /* _AACDEC_HCRS_H_ */ + diff --git a/libAACdec/src/aacdec_pns.cpp b/libAACdec/src/aacdec_pns.cpp new file mode 100644 index 0000000..bd92fed --- /dev/null +++ b/libAACdec/src/aacdec_pns.cpp @@ -0,0 +1,320 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: perceptual noise substitution tool + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "aacdec_pns.h" + + +#include "aac_ram.h" +#include "aac_rom.h" +#include "channelinfo.h" +#include "block.h" +#include "FDK_bitstream.h" + +#include "genericStds.h" + + +#define NOISE_OFFSET 90 /* cf. ISO 14496-3 p. 175 */ + +/*! + \brief Reset InterChannel and PNS data + + The function resets the InterChannel and PNS data +*/ +void CPns_ResetData( + CPnsData *pPnsData, + CPnsInterChannelData *pPnsInterChannelData + ) +{ + /* Assign pointer always, since pPnsData is not persistent data */ + pPnsData->pPnsInterChannelData = pPnsInterChannelData; + pPnsData->PnsActive = 0; + pPnsData->CurrentEnergy = 0; + + FDKmemclear(pPnsData->pnsUsed,(8*16)*sizeof(UCHAR)); + FDKmemclear(pPnsInterChannelData->correlated,(8*16)*sizeof(UCHAR)); +} + +/*! + \brief Initialize PNS data + + The function initializes the PNS data +*/ +void CPns_InitPns( + CPnsData *pPnsData, + CPnsInterChannelData *pPnsInterChannelData, + INT* currentSeed, INT* randomSeed) +{ + /* save pointer to inter channel data */ + pPnsData->pPnsInterChannelData = pPnsInterChannelData; + + /* use pointer because seed has to be + same, left and right channel ! */ + pPnsData->currentSeed = currentSeed; + pPnsData->randomSeed = randomSeed; +} + +/*! + \brief Indicates if PNS is used + + The function returns a value indicating whether PNS is used or not + acordding to the noise energy + + \return PNS used +*/ +int CPns_IsPnsUsed (const CPnsData *pPnsData, + const int group, + const int band) +{ + unsigned pns_band = group*16+band; + + return pPnsData->pnsUsed[pns_band] & (UCHAR)1; +} + +/*! + \brief Set correlation + + The function activates the noise correlation between the channel pair +*/ +void CPns_SetCorrelation(CPnsData *pPnsData, + const int group, + const int band, + const int outofphase) +{ + CPnsInterChannelData *pInterChannelData = pPnsData->pPnsInterChannelData; + unsigned pns_band = group*16+band; + + pInterChannelData->correlated[pns_band] = (outofphase) ? 3 : 1; +} + +/*! + \brief Indicates if correlation is used + + The function indicates if the noise correlation between the channel pair + is activated + + \return PNS is correlated +*/ +static +int CPns_IsCorrelated(const CPnsData *pPnsData, + const int group, + const int band) +{ + CPnsInterChannelData *pInterChannelData = pPnsData->pPnsInterChannelData; + unsigned pns_band = group*16+band; + + return (pInterChannelData->correlated[pns_band] & 0x01) ? 1 : 0; +} + +/*! + \brief Indicates if correlated out of phase mode is used. + + The function indicates if the noise correlation between the channel pair + is activated in out-of-phase mode. + + \return PNS is out-of-phase +*/ +static +int CPns_IsOutOfPhase(const CPnsData *pPnsData, + const int group, + const int band) +{ + CPnsInterChannelData *pInterChannelData = pPnsData->pPnsInterChannelData; + unsigned pns_band = group*16+band; + + return (pInterChannelData->correlated[pns_band] & 0x02) ? 1 : 0; +} + +/*! + \brief Read PNS information + + The function reads the PNS information from the bitstream +*/ +void CPns_Read (CPnsData *pPnsData, + HANDLE_FDK_BITSTREAM bs, + const CodeBookDescription *hcb, + SHORT *pScaleFactor, + UCHAR global_gain, + int band, + int group /* = 0 */) +{ + int delta ; + UINT pns_band = group*16+band; + + if (pPnsData->PnsActive) { + /* Next PNS band case */ + delta = CBlock_DecodeHuffmanWord (bs, hcb) - 60; + } else { + /* First PNS band case */ + int noiseStartValue = FDKreadBits(bs,9); + + delta = noiseStartValue - 256 ; + pPnsData->PnsActive = 1; + pPnsData->CurrentEnergy = global_gain - NOISE_OFFSET; + } + + pPnsData->CurrentEnergy += delta ; + pScaleFactor[pns_band] = pPnsData->CurrentEnergy; + + pPnsData->pnsUsed[pns_band] = 1; +} + + +/** + * \brief Generate a vector of noise of given length. The noise values are + * scaled in order to yield a noise energy of 1.0 + * \param spec pointer to were the noise values will be written to. + * \param size amount of noise values to be generated. + * \param pRandomState pointer to the state of the random generator being used. + * \return exponent of generated noise vector. + */ +static int GenerateRandomVector (FIXP_DBL *RESTRICT spec, + int size, + int *pRandomState) +{ + int i, invNrg_e = 0, nrg_e = 0; + FIXP_DBL invNrg_m, nrg_m = FL2FXCONST_DBL(0.0f) ; + FIXP_DBL *RESTRICT ptr = spec; + int randomState = *pRandomState; + +#define GEN_NOISE_NRG_SCALE 7 + + /* Generate noise and calculate energy. */ + for (i=0; i>GEN_NOISE_NRG_SCALE); + *ptr++ = (FIXP_DBL)randomState; + } + nrg_e = GEN_NOISE_NRG_SCALE*2 + 1; + + /* weight noise with = 1 / sqrt_nrg; */ + invNrg_m = invSqrtNorm2(nrg_m<<1, &invNrg_e); + invNrg_e += -((nrg_e-1)>>1); + + for (i=size; i--; ) + { + spec[i] = fMult(spec[i], invNrg_m); + } + + /* Store random state */ + *pRandomState = randomState; + + return invNrg_e; +} + +static void ScaleBand (FIXP_DBL *RESTRICT spec, int size, int scaleFactor, int specScale, int noise_e, int out_of_phase) +{ + int i, shift, sfExponent; + FIXP_DBL sfMatissa; + + /* Get gain from scale factor value = 2^(scaleFactor * 0.25) */ + sfMatissa = MantissaTable[scaleFactor & 0x03][0]; + /* sfExponent = (scaleFactor >> 2) + ExponentTable[scaleFactor & 0x03][0]; */ + /* Note: ExponentTable[scaleFactor & 0x03][0] is always 1. */ + sfExponent = (scaleFactor >> 2) + 1; + + if (out_of_phase != 0) { + sfMatissa = -sfMatissa; + } + + /* +1 because of fMultDiv2 below. */ + shift = sfExponent - specScale + 1 + noise_e; + + /* Apply gain to noise values */ + if (shift>=0) { + shift = fixMin( shift, DFRACT_BITS-1 ); + for (i = size ; i-- != 0; ) { + spec [i] = fMultDiv2 (spec [i], sfMatissa) << shift; + } + } else { + shift = fixMin( -shift, DFRACT_BITS-1 ); + for (i = size ; i-- != 0; ) { + spec [i] = fMultDiv2 (spec [i], sfMatissa) >> shift; + } + } +} + + +/*! + \brief Apply PNS + + The function applies PNS (i.e. it generates noise) on the bands + flagged as noisy bands + +*/ +void CPns_Apply (const CPnsData *pPnsData, + const CIcsInfo *pIcsInfo, + SPECTRAL_PTR pSpectrum, + const SHORT *pSpecScale, + const SHORT *pScaleFactor, + const SamplingRateInfo *pSamplingRateInfo, + const INT granuleLength, + const int channel) +{ + if (pPnsData->PnsActive) { + const short *BandOffsets = GetScaleFactorBandOffsets(pIcsInfo, pSamplingRateInfo); + + int ScaleFactorBandsTransmitted = GetScaleFactorBandsTransmitted(pIcsInfo); + + for (int window = 0, group = 0; group < GetWindowGroups(pIcsInfo); group++) { + for (int groupwin = 0; groupwin < GetWindowGroupLength(pIcsInfo, group); groupwin++, window++) { + FIXP_DBL *spectrum = SPEC(pSpectrum, window, granuleLength); + + for (int band = 0 ; band < ScaleFactorBandsTransmitted; band++) { + if (CPns_IsPnsUsed (pPnsData, group, band)) { + UINT pns_band = group*16+band; + + int bandWidth = BandOffsets [band + 1] - BandOffsets [band] ; + int noise_e; + + FDK_ASSERT(bandWidth >= 0); + + if (channel > 0 && CPns_IsCorrelated(pPnsData, group, band)) + { + noise_e = GenerateRandomVector (spectrum + BandOffsets [band], bandWidth, + &pPnsData->randomSeed [pns_band]) ; + } + else + { + pPnsData->randomSeed [pns_band] = *pPnsData->currentSeed ; + + noise_e = GenerateRandomVector (spectrum + BandOffsets [band], bandWidth, + pPnsData->currentSeed) ; + } + + int outOfPhase = CPns_IsOutOfPhase (pPnsData, group, band); + + ScaleBand (spectrum + BandOffsets [band], bandWidth, + pScaleFactor[pns_band], + pSpecScale[window], noise_e, outOfPhase) ; + } + } + } + } + } +} diff --git a/libAACdec/src/aacdec_pns.h b/libAACdec/src/aacdec_pns.h new file mode 100644 index 0000000..a2d8e98 --- /dev/null +++ b/libAACdec/src/aacdec_pns.h @@ -0,0 +1,58 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: perceptual noise substitution tool + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef PNS_H +#define PNS_H + +#include "common_fix.h" + + +#define NO_OFBANDS ((8*16)) + +typedef struct { + UCHAR correlated[NO_OFBANDS]; +} CPnsInterChannelData; + +typedef struct { + CPnsInterChannelData *pPnsInterChannelData; + UCHAR pnsUsed[NO_OFBANDS]; + int CurrentEnergy; + UCHAR PnsActive; + INT *currentSeed; + INT *randomSeed; +} CPnsData; + +void CPns_InitPns ( CPnsData *pPnsData, + CPnsInterChannelData *pPnsInterChannelData, + INT* currentSeed, + INT* randomSeed ); + +void CPns_ResetData ( CPnsData *pPnsData, CPnsInterChannelData *pPnsInterChannelData ); + + +#endif /* #ifndef PNS_H */ diff --git a/libAACdec/src/aacdec_tns.cpp b/libAACdec/src/aacdec_tns.cpp new file mode 100644 index 0000000..83ae5ae --- /dev/null +++ b/libAACdec/src/aacdec_tns.cpp @@ -0,0 +1,350 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: temporal noise shaping tool + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "aacdec_tns.h" +#include "aac_rom.h" +#include "FDK_bitstream.h" +#include "channelinfo.h" + + + +/*! + \brief Reset tns data + + The function resets the tns data + + \return none +*/ +void CTns_Reset(CTnsData *pTnsData) +{ + /* Note: the following FDKmemclear should not be required. */ + FDKmemclear(pTnsData->Filter, TNS_MAX_WINDOWS*TNS_MAXIMUM_FILTERS*sizeof(CFilter)); + FDKmemclear(pTnsData->NumberOfFilters, TNS_MAX_WINDOWS*sizeof(UCHAR)); + pTnsData->DataPresent = 0; + pTnsData->Active = 0; +} + +void CTns_ReadDataPresentFlag(HANDLE_FDK_BITSTREAM bs, /*!< pointer to bitstream */ + CTnsData *pTnsData) /*!< pointer to aac decoder channel info */ +{ + pTnsData->DataPresent = (UCHAR) FDKreadBits(bs,1); +} + +/*! + \brief Read tns data from bitstream + + The function reads the elements for tns from + the bitstream. + + \return none +*/ +AAC_DECODER_ERROR CTns_Read(HANDLE_FDK_BITSTREAM bs, + CTnsData *pTnsData, + const CIcsInfo *pIcsInfo, + const UINT flags) +{ + UCHAR n_filt,order; + UCHAR length,coef_res,coef_compress; + UCHAR window; + UCHAR wins_per_frame = GetWindowsPerFrame(pIcsInfo); + UCHAR isLongFlag = IsLongBlock(pIcsInfo); + AAC_DECODER_ERROR ErrorStatus = AAC_DEC_OK; + + if (!pTnsData->DataPresent) { + return ErrorStatus; + } + + for (window = 0; window < wins_per_frame; window++) + { + pTnsData->NumberOfFilters[window] = n_filt = (UCHAR) FDKreadBits(bs, isLongFlag ? 2 : 1); + + if (pTnsData->NumberOfFilters[window] > TNS_MAXIMUM_FILTERS){ + pTnsData->NumberOfFilters[window] = n_filt = TNS_MAXIMUM_FILTERS; + } + + if (n_filt) + { + int index; + UCHAR nextstopband; + + coef_res = (UCHAR) FDKreadBits(bs,1); + + nextstopband = GetScaleFactorBandsTotal(pIcsInfo); + + for (index=0; index < n_filt; index++) + { + CFilter *filter = &pTnsData->Filter[window][index]; + + length = (UCHAR)FDKreadBits(bs, isLongFlag ? 6 : 4); + + if (length > nextstopband){ + length = nextstopband; + } + + filter->StartBand = nextstopband - length; + filter->StopBand = nextstopband; + nextstopband = filter->StartBand; + + { + filter->Order = order = (UCHAR) FDKreadBits(bs, isLongFlag ? 5 : 3); + } + + if (filter->Order > TNS_MAXIMUM_ORDER){ + filter->Order = order = TNS_MAXIMUM_ORDER; + } + + if (order) + { + UCHAR coef,s_mask; + UCHAR i; + SCHAR n_mask; + static const UCHAR sgn_mask[] = { 0x2, 0x4, 0x8 }; + static const SCHAR neg_mask[] = { ~0x3, ~0x7, ~0xF }; + + filter->Direction = FDKreadBits(bs,1) ? -1 : 1; + + coef_compress = (UCHAR) FDKreadBits(bs,1); + + filter->Resolution = coef_res + 3; + + s_mask = sgn_mask[coef_res + 1 - coef_compress]; + n_mask = neg_mask[coef_res + 1 - coef_compress]; + + for (i=0; i < order; i++) + { + coef = (UCHAR) FDKreadBits(bs,filter->Resolution - coef_compress); + filter->Coeff[i] = (coef & s_mask) ? (coef | n_mask) : coef; + } + } + } + } + } + + pTnsData->Active = 1; + + return ErrorStatus; +} + + +static void CTns_Filter (FIXP_DBL *spec, int size, int inc, FIXP_TCC coeff [], int order) +{ + // - Simple all-pole filter of order "order" defined by + // y(n) = x(n) - a(2)*y(n-1) - ... - a(order+1)*y(n-order) + // + // - The state variables of the filter are initialized to zero every time + // + // - The output data is written over the input data ("in-place operation") + // + // - An input vector of "size" samples is processed and the index increment + // to the next data sample is given by "inc" + + int i,j,N; + FIXP_DBL *pSpec; + FIXP_DBL maxVal=FL2FXCONST_DBL(0.0); + INT s; + + FDK_ASSERT(order <= TNS_MAXIMUM_ORDER); + C_ALLOC_SCRATCH_START(state, FIXP_DBL, TNS_MAXIMUM_ORDER); + FDKmemclear(state, order*sizeof(FIXP_DBL)); + + for (i=0; i FL2FXCONST_DBL(0.03125*0.70710678118) ) + s = fixMax(CntLeadingZeros(maxVal)-6,0); + else + s = fixMax(CntLeadingZeros(maxVal)-5,0); + + s = fixMin(s,2); + s = s-1; + + if (inc == -1) + pSpec = &spec[size - 1]; + else + pSpec = &spec[0]; + + FIXP_TCC *pCoeff; + +#define FIRST_PART_FLTR \ + FIXP_DBL x, *pState = state; \ + pCoeff = coeff; \ + \ + if (s < 0) \ + x = (pSpec [0]>>1) + fMultDiv2 (*pCoeff++, pState [0]) ; \ + else \ + x = (pSpec [0]<> s; \ + *pState =(-x) << 1; \ + pSpec += inc ; + + + if (order>8) + { + N = (order-1)&7; + + for (i = size ; i != 0 ; i--) + { + FIRST_PART_FLTR + + for (j = N; j > 0 ; j--) { INNER_FLTR_INLINE } + + INNER_FLTR_INLINE INNER_FLTR_INLINE INNER_FLTR_INLINE INNER_FLTR_INLINE + INNER_FLTR_INLINE INNER_FLTR_INLINE INNER_FLTR_INLINE INNER_FLTR_INLINE + + LAST_PART_FLTR + } + + } else if (order>4) { + + N = (order-1)&3; + + for (i = size ; i != 0 ; i--) + { + FIRST_PART_FLTR + for (j = N; j > 0 ; j--) { INNER_FLTR_INLINE } + + INNER_FLTR_INLINE INNER_FLTR_INLINE INNER_FLTR_INLINE INNER_FLTR_INLINE + + LAST_PART_FLTR + } + + } else { + + N = order-1; + + for (i = size ; i != 0 ; i--) + { + FIRST_PART_FLTR + + for (j = N; j > 0 ; j--) { INNER_FLTR_INLINE } + + LAST_PART_FLTR + } + } + + C_ALLOC_SCRATCH_END(state, FIXP_DBL, TNS_MAXIMUM_ORDER); +} + +/*! + \brief Apply tns to spectral lines + + The function applies the tns to the spectrum, + + \return none +*/ +void CTns_Apply ( + CTnsData *RESTRICT pTnsData, /*!< pointer to aac decoder info */ + const CIcsInfo *pIcsInfo, + SPECTRAL_PTR pSpectralCoefficient, + const SamplingRateInfo *pSamplingRateInfo, + const INT granuleLength + ) +{ + int window,index,start,stop,size; + + + if (pTnsData->Active) + { + C_AALLOC_SCRATCH_START(coeff, FIXP_TCC, TNS_MAXIMUM_ORDER); + + for (window=0; window < GetWindowsPerFrame(pIcsInfo); window++) + { + FIXP_DBL *pSpectrum = SPEC(pSpectralCoefficient, window, granuleLength); + + for (index=0; index < pTnsData->NumberOfFilters[window]; index++) + { + CFilter *RESTRICT filter = &pTnsData->Filter[window][index]; + + if (filter->Order > 0) + { + FIXP_TCC *pCoeff; + int tns_max_bands; + + pCoeff = &coeff[filter->Order-1]; + if (filter->Resolution == 3) + { + int i; + for (i=0; i < filter->Order; i++) + *pCoeff-- = FDKaacDec_tnsCoeff3[filter->Coeff[i]+4]; + } + else + { + int i; + for (i=0; i < filter->Order; i++) + *pCoeff-- = FDKaacDec_tnsCoeff4[filter->Coeff[i]+8]; + } + + switch (granuleLength) { + case 480: + tns_max_bands = tns_max_bands_tbl_480[pSamplingRateInfo->samplingRateIndex-3]; + break; + case 512: + tns_max_bands = tns_max_bands_tbl_512[pSamplingRateInfo->samplingRateIndex-3]; + break; + default: + tns_max_bands = GetMaximumTnsBands(pIcsInfo, pSamplingRateInfo->samplingRateIndex); + break; + } + + start = fixMin( fixMin(filter->StartBand, tns_max_bands), + GetScaleFactorBandsTransmitted(pIcsInfo) ); + + start = GetScaleFactorBandOffsets(pIcsInfo, pSamplingRateInfo)[start]; + + stop = fixMin( fixMin(filter->StopBand, tns_max_bands), + GetScaleFactorBandsTransmitted(pIcsInfo) ); + + stop = GetScaleFactorBandOffsets(pIcsInfo, pSamplingRateInfo)[stop]; + + size = stop - start; + + if (size > 0) { + CTns_Filter(&pSpectrum[start], + size, + filter->Direction, + coeff, + filter->Order ); + } + } + } + } + C_AALLOC_SCRATCH_END(coeff, FIXP_TCC, TNS_MAXIMUM_ORDER); + } + +} diff --git a/libAACdec/src/aacdec_tns.h b/libAACdec/src/aacdec_tns.h new file mode 100644 index 0000000..cf3f597 --- /dev/null +++ b/libAACdec/src/aacdec_tns.h @@ -0,0 +1,64 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: temporal noise shaping tool + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef TNS_H +#define TNS_H + +#include "common_fix.h" + +enum +{ + TNS_MAX_WINDOWS = 8, /* 8 */ + TNS_MAXIMUM_ORDER = 12, /* 12 for AAC-LC and AAC-SSR. Set to 20 for AAC-Main (AOT 1). Some broken encoders also do order 20 for AAC-LC :( */ + TNS_MAXIMUM_FILTERS = 3 +}; + +typedef struct +{ + SCHAR Coeff[TNS_MAXIMUM_ORDER]; + + UCHAR StartBand; + UCHAR StopBand; + + SCHAR Direction; + SCHAR Resolution; + + UCHAR Order; +} CFilter; + +typedef struct +{ + CFilter Filter[TNS_MAX_WINDOWS][TNS_MAXIMUM_FILTERS]; + UCHAR NumberOfFilters[TNS_MAX_WINDOWS]; + UCHAR DataPresent; + UCHAR Active; +} CTnsData; + +void CTns_Reset(CTnsData *pTnsData); + +#endif /* #ifndef TNS_H */ diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp new file mode 100644 index 0000000..534d48f --- /dev/null +++ b/libAACdec/src/aacdecoder.cpp @@ -0,0 +1,1667 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + + +/*! + \page default General Overview of the AAC Decoder Implementation + + The main entry point to decode a AAC frame is CAacDecoder_DecodeFrame(). It handles the different + transport multiplexes and bitstream formats supported by this implementation. It extracts the + AAC_raw_data_blocks from these bitstreams to further process then in the actual decoding stages. + + Note: Click on a function of file in the above image to see details about the function. Also note, that + this is just an overview of the most important functions and not a complete call graph. + +

1 Bitstream deformatter

+ The basic bit stream parser function CChannelElement_Read() is called. It uses other subcalls in order + to parse and unpack the bitstreams. Note, that this includes huffmann decoding of the coded spectral data. + This operation can be computational significant specifically at higher bitrates. Optimization is likely in + CBlock_ReadSpectralData(). + + The bitstream deformatter also includes many bitfield operations. Profiling on the target will determine + required optimizations. + +

2 Actual decoding to retain the time domain output

+ The basic bitstream deformatter function CChannelElement_Decode() for CPE elements and SCE elements are called. + Except for the stereo processing (2.1) which is only used for CPE elements, the function calls for CPE or SCE + are similar, except that CPE always processes to independent channels while SCE only processes one channel. + + Often there is the distinction between long blocks and short blocks. However, computational expensive functions + that ususally require optimization are being shared by these two groups, + +

2.1 Stereo processing for CPE elements

+ CChannelPairElement_Decode() first calles the joint stereo tools in stereo.cpp when required. + +

2.2 Scaling of spectral data

+ CBlock_ScaleSpectralData(). + +

2.3 Apply additional coding tools

+ ApplyTools() calles the PNS tools in case of MPEG-4 bitstreams, and TNS filtering CTns_Apply() for MPEG-2 and MPEG-4 bitstreams. + The function TnsFilterIIR() which is called by CTns_Apply() (2.3.1) might require some optimization. + +

3 Frequency-To-Time conversion

+ The filterbank is called using CBlock_FrequencyToTime() using the MDCT module from the FDK Tools + +*/ + + + +#include "aacdecoder.h" + +#include "aac_rom.h" +#include "aac_ram.h" +#include "channel.h" +#include "FDK_audio.h" + +#include "FDK_tools_rom.h" + + #include "aacdec_pns.h" + +/*#ifdef AACDEC_HDAAC_ENABLE +#include "slsdecifc.h" +#endif +*/ + + #include "sbrdecoder.h" + + + + + #include "aacdec_hcr.h" + #include "rvlc.h" + + +#include "tpdec_lib.h" + +#include "conceal.h" + + + +#define CAN_DO_PS(aot) \ + ((aot) == AOT_AAC_LC \ +|| (aot) == AOT_SBR \ +|| (aot) == AOT_PS \ +|| (aot) == AOT_ER_BSAC \ +|| (aot) == AOT_DRM_AAC) + +#define IS_USAC(aot) \ + ((aot) == AOT_USAC \ +|| (aot) == AOT_RSVD50) + +#define IS_LOWDELAY(aot) \ + ((aot) == AOT_ER_AAC_LD \ +|| (aot) == AOT_ER_AAC_ELD) + +void CAacDecoder_SyncQmfMode(HANDLE_AACDECODER self) +{ + + /* Assign user requested mode */ + self->qmfModeCurr = self->qmfModeUser; + + if ( self->qmfModeCurr == NOT_DEFINED ) + { + if ( (IS_LOWDELAY(self->streamInfo.aot) && (self->flags & AC_MPS_PRESENT)) + || ( (self->ascChannels == 1) + && ( (CAN_DO_PS(self->streamInfo.aot) && !(self->flags & AC_MPS_PRESENT)) + || ( IS_USAC(self->streamInfo.aot) && (self->flags & AC_MPS_PRESENT)) ) ) ) + { + self->qmfModeCurr = MODE_HQ; + } else { + self->qmfModeCurr = MODE_LP; + } + } + + + /* Set SBR to current QMF mode. Error does not matter. */ + sbrDecoder_SetParam(self->hSbrDecoder, SBR_QMF_MODE, (self->qmfModeCurr == MODE_LP)); + self->psPossible = ((CAN_DO_PS(self->streamInfo.aot) && self->aacChannels == 1 && ! (self->flags & AC_MPS_PRESENT))) && self->qmfModeCurr == MODE_HQ ; + FDK_ASSERT( ! ( (self->flags & AC_MPS_PRESENT) && self->psPossible ) ); +} + +void CAacDecoder_SignalInterruption(HANDLE_AACDECODER self) +{ +} + +/*! + \brief Reset ancillary data struct. Call before parsing a new frame. + + \ancData Pointer to ancillary data structure + + \return Error code +*/ +static AAC_DECODER_ERROR CAacDecoder_AncDataReset(CAncData *ancData) +{ + int i; + for (i=0; i<8; i++) + { + ancData->offset[i] = 0; + } + ancData->nrElements = 0; + + return AAC_DEC_OK; +} + +/*! + \brief Initialize ancillary buffer + + \ancData Pointer to ancillary data structure + \buffer Pointer to (external) anc data buffer + \size Size of the buffer pointed on by buffer in bytes + + \return Error code +*/ +AAC_DECODER_ERROR CAacDecoder_AncDataInit(CAncData *ancData, unsigned char *buffer, int size) +{ + if (size >= 0) { + ancData->buffer = buffer; + ancData->bufferSize = size; + + CAacDecoder_AncDataReset(ancData); + + return AAC_DEC_OK; + } + + return AAC_DEC_ANC_DATA_ERROR; +} + +/*! + \brief Get one ancillary data element + + \ancData Pointer to ancillary data structure + \index Index of the anc data element to get + \ptr Pointer to a buffer receiving a pointer to the requested anc data element + \size Pointer to a buffer receiving the length of the requested anc data element in bytes + + \return Error code +*/ +AAC_DECODER_ERROR CAacDecoder_AncDataGet(CAncData *ancData, int index, unsigned char **ptr, int *size) +{ + AAC_DECODER_ERROR error = AAC_DEC_OK; + + *ptr = NULL; + *size = 0; + + if (index >= 0 && index < 8 && index < ancData->nrElements) + { + *ptr = &ancData->buffer[ancData->offset[index]]; + *size = ancData->offset[index+1] - ancData->offset[index]; + } + + return error; +} + + +/*! + \brief Parse ancillary data + + \ancData Pointer to ancillary data structure + \hBs Handle to FDK bitstream + \ancBytes Length of ancillary data to read from the bitstream + + \return Error code +*/ +static +AAC_DECODER_ERROR CAacDecoder_AncDataParse ( + CAncData *ancData, + HANDLE_FDK_BITSTREAM hBs, + const int ancBytes ) +{ + AAC_DECODER_ERROR error = AAC_DEC_OK; + int readBytes = 0; + + if (ancData->buffer != NULL) + { + if (ancBytes > 0) { + /* write ancillary data to external buffer */ + int offset = ancData->offset[ancData->nrElements]; + + if ((offset + ancBytes) > ancData->bufferSize) + { + error = AAC_DEC_TOO_SMALL_ANC_BUFFER; + } + else if (ancData->nrElements >= 8-1) + { + error = AAC_DEC_TOO_MANY_ANC_ELEMENTS; + } + else + { + int i; + + for (i = 0; i < ancBytes; i++) { + ancData->buffer[i+offset] = FDKreadBits(hBs, 8); + readBytes++; + } + + ancData->nrElements++; + ancData->offset[ancData->nrElements] = ancBytes + ancData->offset[ancData->nrElements-1]; + } + } + } + + readBytes = ancBytes - readBytes; + + if (readBytes > 0) { + /* skip data */ + FDKpushFor(hBs, readBytes<<3); + } + + return error; +} + +/*! + \brief Read Stream Data Element + + \bs Bitstream Handle + + \return Error code +*/ +static AAC_DECODER_ERROR CDataStreamElement_Read ( + HANDLE_FDK_BITSTREAM bs, + CAncData *ancData, + HANDLE_AAC_DRC hDrcInfo, + HANDLE_TRANSPORTDEC pTp, + UCHAR *elementInstanceTag, + UINT alignmentAnchor ) +{ + AAC_DECODER_ERROR error = AAC_DEC_OK; + UINT dataStart; + int dataByteAlignFlag, count; + + int crcReg = transportDec_CrcStartReg(pTp, 0); + + /* Element Instance Tag */ + *elementInstanceTag = FDKreadBits(bs,4); + /* Data Byte Align Flag */ + dataByteAlignFlag = FDKreadBits(bs,1); + + count = FDKreadBits(bs,8); + + if (count == 255) { + count += FDKreadBits(bs,8); /* EscCount */ + } + + if (dataByteAlignFlag) { + FDKbyteAlign(bs, alignmentAnchor); + } + + dataStart = FDKgetValidBits(bs); + + error = CAacDecoder_AncDataParse(ancData, bs, count); + transportDec_CrcEndReg(pTp, crcReg); + + { + INT readBits, dataBits = count<<3; + + /* Move to the beginning of the data junk */ + FDKpushBack(bs, dataStart-FDKgetValidBits(bs)); + + /* Read Anc data if available */ + readBits = aacDecoder_drcMarkPayload( hDrcInfo, bs, DVB_DRC_ANC_DATA ); + + if (readBits != dataBits) { + /* Move to the end again. */ + FDKpushBiDirectional(bs, FDKgetValidBits(bs)-dataStart+dataBits); + } + } + + return error; +} + +#ifdef TP_PCE_ENABLE +/*! + \brief Read Program Config Element + + \bs Bitstream Handle + \count Pointer to program config element. + + \return Error code +*/ +static AAC_DECODER_ERROR CProgramConfigElement_Read ( + HANDLE_FDK_BITSTREAM bs, + HANDLE_TRANSPORTDEC pTp, + CProgramConfig *pce, + UINT alignAnchor ) +{ + AAC_DECODER_ERROR error = AAC_DEC_OK; + int crcReg; + + /* read PCE to temporal buffer first */ + C_ALLOC_SCRATCH_START(tmpPce, CProgramConfig, 1); + + CProgramConfig_Init(tmpPce); + CProgramConfig_Reset(tmpPce); + + crcReg = transportDec_CrcStartReg(pTp, 0); + + CProgramConfig_Read(tmpPce, bs, alignAnchor); + + transportDec_CrcEndReg(pTp, crcReg); + + if (!pce->isValid && tmpPce->NumChannels <= (6) && tmpPce->Profile == 1) { + /* store PCE data */ + FDKmemcpy(pce, tmpPce, sizeof(CProgramConfig)); + } + + C_ALLOC_SCRATCH_END(tmpPce, CProgramConfig, 1); + + return error; +} +#endif + +/*! + \brief Parse Extension Payload + + \self Handle of AAC decoder + \count Pointer to bit counter. + \previous_element ID of previous element (required by some extension payloads) + + \return Error code +*/ +static +AAC_DECODER_ERROR CAacDecoder_ExtPayloadParse (HANDLE_AACDECODER self, + HANDLE_FDK_BITSTREAM hBs, + int *count, + MP4_ELEMENT_ID previous_element, + int elIndex, + int fIsFillElement) +{ + AAC_DECODER_ERROR error = AAC_DEC_OK; + EXT_PAYLOAD_TYPE extension_type; + int bytes = (*count) >> 3; + int crcFlag = 0; + + if (*count < 4) { + return AAC_DEC_PARSE_ERROR; + } else if ((INT)FDKgetValidBits(hBs) < *count) { + return AAC_DEC_DECODE_FRAME_ERROR; + } + + extension_type = (EXT_PAYLOAD_TYPE) FDKreadBits(hBs, 4); /* bs_extension_type */ + *count -= 4; + + switch (extension_type) + { + case EXT_DYNAMIC_RANGE: + { + INT readBits = aacDecoder_drcMarkPayload( self->hDrcInfo, hBs, MPEG_DRC_EXT_DATA ); + + if (readBits > *count) + { + FDKpushBack(hBs, readBits - *count); + error = AAC_DEC_PARSE_ERROR; + return error; + } + else + { + *count -= (readBits+7) & ~0x7; + } + } + break; + case EXT_LDSAC_DATA: + case EXT_SAC_DATA: + /* Skip MPEG Surround Extension payload */ + FDKpushFor(hBs, *count); + *count = 0; + break; + + case EXT_SBR_DATA_CRC: + crcFlag = 1; + + case EXT_SBR_DATA: + { + SBR_ERROR sbrError; + + CAacDecoder_SyncQmfMode(self); + + sbrError = sbrDecoder_InitElement( + self->hSbrDecoder, + self->streamInfo.aacSampleRate, + self->streamInfo.extSamplingRate, + self->streamInfo.aacSamplesPerFrame, + self->streamInfo.aot, + previous_element, + elIndex + ); + + if (sbrError == SBRDEC_OK) { + sbrError = sbrDecoder_Parse ( + self->hSbrDecoder, + hBs, + count, + *count, + crcFlag, + previous_element, + elIndex, + self->flags & AC_INDEP ); + /* Enable SBR for implicit SBR signalling. */ + if (sbrError == SBRDEC_OK) { + self->sbrEnabled = 1; + } + } else { + /* Do not try to apply SBR because initializing the element failed. */ + self->sbrEnabled = 0; + } + /* Citation from ISO/IEC 14496-3 chapter 4.5.2.1.5.2 + Fill elements containing an extension_payload() with an extension_type of EXT_SBR_DATA + or EXT_SBR_DATA_CRC shall not contain any other extension_payload of any other extension_type. + */ + if (fIsFillElement) { + FDKpushBiDirectional(hBs, *count); + *count = 0; + } else { + /* If this is not a fill element with a known length, we are screwed an no further parsing makes sense. */ + if (sbrError != SBRDEC_OK) { + self->frameOK = 0; + } + } + } + break; + + case EXT_FILL_DATA: + { + int temp; + + temp = FDKreadBits(hBs,4); + bytes--; + if (temp != 0) { + error = AAC_DEC_PARSE_ERROR; + break; + } + while (bytes > 0) { + temp = FDKreadBits(hBs,8); + bytes--; + if (temp != 0xa5) { + error = AAC_DEC_PARSE_ERROR; + break; + } + } + *count = bytes<<3; + } + break; + + case EXT_DATA_ELEMENT: + { + int dataElementVersion; + + dataElementVersion = FDKreadBits(hBs,4); + *count -= 4; + if (dataElementVersion == 0) /* ANC_DATA */ + { + int temp, dataElementLength = 0; + do { + temp = FDKreadBits(hBs,8); + *count -= 8; + dataElementLength += temp; + } while (temp == 255 ); + + CAacDecoder_AncDataParse(&self->ancData, hBs, dataElementLength); + *count -= (dataElementLength<<3); + } else { + /* align = 0 */ + FDKpushFor(hBs, (*count)<<3); + *count = 0; + } + } + break; + + case EXT_DATA_LENGTH: + { + int bitCnt, len = FDKreadBits(hBs, 4); + *count -= 4; + + if (len == 15) { + int add_len = FDKreadBits(hBs, 8); + *count -= 8; + len += add_len; + + if (add_len == 255) { + len += FDKreadBits(hBs, 16); + *count -= 16; + } + } + len <<= 3; + bitCnt = len; + + if ( (EXT_PAYLOAD_TYPE)FDKreadBits(hBs, 4) == EXT_DATA_LENGTH ) { + /* Check NOTE 2: The extension_payload() included here must + not have extension_type == EXT_DATA_LENGTH. */ + error = AAC_DEC_PARSE_ERROR; + } else { + /* rewind and call myself again. */ + FDKpushBack(hBs, 4); + + error = + CAacDecoder_ExtPayloadParse ( + self, + hBs, + &bitCnt, + previous_element, + elIndex, + 0 ); + + *count -= len - bitCnt; + } + } + break; + + case EXT_FIL: + + default: + /* align = 4 */ + FDKpushFor(hBs, *count); + *count = 0; + break; + } + + return error; +} + +/* Stream Configuration and Information. + + This class holds configuration and information data for a stream to be decoded. It + provides the calling application as well as the decoder with substantial information, + e.g. profile, sampling rate, number of channels found in the bitstream etc. +*/ +static +void CStreamInfoInit(CStreamInfo *pStreamInfo) +{ + pStreamInfo->aacSampleRate = 0; + pStreamInfo->profile = -1; + pStreamInfo->aot = AOT_NONE; + + pStreamInfo->channelConfig = -1; + pStreamInfo->bitRate = 0; + pStreamInfo->aacSamplesPerFrame = 0; + + pStreamInfo->extAot = AOT_NONE; + pStreamInfo->extSamplingRate = 0; + + pStreamInfo->flags = 0; + + pStreamInfo->epConfig = -1; /* default is no ER */ + + pStreamInfo->numChannels = 0; + pStreamInfo->sampleRate = 0; + pStreamInfo->frameSize = 0; +} + +/*! + \brief Initialization of AacDecoderChannelInfo + + The function initializes the pointers to AacDecoderChannelInfo for each channel, + set the start values for window shape and window sequence of overlap&add to zero, + set the overlap buffer to zero and initializes the pointers to the window coefficients. + \param bsFormat is the format of the AAC bitstream + + \return AACDECODER instance +*/ +LINKSPEC_CPP HANDLE_AACDECODER CAacDecoder_Open(TRANSPORT_TYPE bsFormat) /*!< bitstream format (adif,adts,loas,...). */ +{ + HANDLE_AACDECODER self; + + self = GetAacDecoder(); + if (self == NULL) { + goto bail; + } + + /* Assign channel mapping info arrays (doing so removes dependency of settings header in API header). */ + self->streamInfo.pChannelIndices = self->channelIndices; + self->streamInfo.pChannelType = self->channelType; + + /* set default output mode */ + self->outputInterleaved = 1; /* interleaved */ + + /* initialize anc data */ + CAacDecoder_AncDataInit(&self->ancData, NULL, 0); + + /* initialize stream info */ + CStreamInfoInit(&self->streamInfo); + + /* initialize error concealment common data */ + CConcealment_InitCommonData(&self->concealCommonData); + + self->hDrcInfo = GetDrcInfo(); + if (self->hDrcInfo == NULL) { + goto bail; + } + /* Init common DRC structure */ + aacDecoder_drcInit( self->hDrcInfo ); + /* Set default frame delay */ + aacDecoder_drcSetParam ( + self->hDrcInfo, + DRC_BS_DELAY, + CConcealment_GetDelay(&self->concealCommonData) + ); + + + self->aacCommonData.workBufferCore1 = GetWorkBufferCore1(); + self->aacCommonData.workBufferCore2 = GetWorkBufferCore2(); + if (self->aacCommonData.workBufferCore1 == NULL + ||self->aacCommonData.workBufferCore2 == NULL ) + goto bail; + + return self; + +bail: + CAacDecoder_Close( self ); + + return NULL; +} + +/* Destroy aac decoder */ +LINKSPEC_CPP void CAacDecoder_Close(HANDLE_AACDECODER self) +{ + int ch; + + if (self == NULL) + return; + + for (ch=0; ch<(6); ch++) { + if (self->pAacDecoderStaticChannelInfo[ch] != NULL) { + FreeOverlapBuffer (&self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer); + FreeAacDecoderStaticChannelInfo (&self->pAacDecoderStaticChannelInfo[ch]); + } + if (self->pAacDecoderChannelInfo[ch] != NULL) { + FreeAacDecoderChannelInfo (&self->pAacDecoderChannelInfo[ch]); + } + } + + self->aacChannels = 0; + + if (self->hDrcInfo) { + FreeDrcInfo(&self->hDrcInfo); + } + + FreeWorkBufferCore1 (&self->aacCommonData.workBufferCore1); + FreeWorkBufferCore2 (&self->aacCommonData.workBufferCore2); + + FreeAacDecoder ( &self); +} + + +/*! + \brief Initialization of decoder instance + + The function initializes the decoder. + + \return error status: 0 for success, <>0 for unsupported configurations +*/ +LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_Init(HANDLE_AACDECODER self, const CSAudioSpecificConfig *asc) +{ + AAC_DECODER_ERROR err = AAC_DEC_OK; + INT ascChannels, ch, ascChanged = 0; + + if (!self) + return AAC_DEC_INVALID_HANDLE; + + // set profile and check for supported aot + // leave profile on default (=-1) for all other supported MPEG-4 aot's except aot=2 (=AAC-LC) + switch (asc->m_aot) { + case AOT_AAC_LC: + self->streamInfo.profile = 1; + break; + + case AOT_SBR: + case AOT_PS: + case AOT_ER_AAC_LD: + case AOT_ER_AAC_ELD: + break; + + default: + return AAC_DEC_UNSUPPORTED_AOT; + } + + CProgramConfig_Init(&self->pce); + + /* set channels */ + switch (asc->m_channelConfiguration) { + case 0: +#ifdef TP_PCE_ENABLE + /* get channels from program config (ASC) */ + if (CProgramConfig_IsValid(&asc->m_progrConfigElement)) { + ascChannels = asc->m_progrConfigElement.NumChannels; + if (ascChannels > 0) { + int el; + /* valid number of channels -> copy program config element (PCE) from ASC */ + FDKmemcpy(&self->pce, &asc->m_progrConfigElement, sizeof(CProgramConfig)); + /* Built element table */ + el = CProgramConfig_GetElementTable(&asc->m_progrConfigElement, self->elements); + for (; el<7; el++) { + self->elements[el] = ID_NONE; + } + } else { + return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; + } + } else { + if (transportDec_GetFormat(self->hInput) == TT_MP4_ADTS) { + /* set default max_channels for memory allocation because in implicit channel mapping mode + we don't know the actual number of channels until we processed at least one raw_data_block(). */ + ascChannels = (6); + } else { + return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; + } + } +#else /* TP_PCE_ENABLE */ + return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; +#endif /* TP_PCE_ENABLE */ + break; + case 1: case 2: case 3: case 4: case 5: case 6: + ascChannels = asc->m_channelConfiguration; + break; + case 7: + ascChannels = 8; + break; + default: + return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; + } + + /* Initialize constant mappings for channel config 1-7 */ + if (asc->m_channelConfiguration > 0) { + int el; + FDKmemcpy(self->elements, elementsTab[asc->m_channelConfiguration-1], sizeof(MP4_ELEMENT_ID)*FDKmin(7,7)); + for (el=7; el<7; el++) { + self->elements[el] = ID_NONE; + } + for (ch=0; chchMapping[ch] = ch; + } + for (; ch<(6); ch++) { + self->chMapping[ch] = 255; + } + } + + self->streamInfo.channelConfig = asc->m_channelConfiguration; + + if (ascChannels > (6)) { + return AAC_DEC_UNSUPPORTED_CHANNELCONFIG; + } + if (self->streamInfo.aot != asc->m_aot) { + self->streamInfo.aot = asc->m_aot; + ascChanged = 1; + } + + if (self->streamInfo.aacSamplesPerFrame != (INT)asc->m_samplesPerFrame) { + self->streamInfo.aacSamplesPerFrame = asc->m_samplesPerFrame; + ascChanged = 1; + } + + self->streamInfo.bitRate = 0; + + /* Set syntax flags */ + self->flags = 0; + + self->streamInfo.extAot = asc->m_extensionAudioObjectType; + self->streamInfo.extSamplingRate = asc->m_extensionSamplingFrequency; + self->flags |= (asc->m_sbrPresentFlag) ? AC_SBR_PRESENT : 0; + self->flags |= (asc->m_psPresentFlag) ? AC_PS_PRESENT : 0; + self->sbrEnabled = 0; + + /* --------- vcb11 ------------ */ + self->flags |= (asc->m_vcb11Flag) ? AC_ER_VCB11 : 0; + + /* ---------- rvlc ------------ */ + self->flags |= (asc->m_rvlcFlag) ? AC_ER_RVLC : 0; + + /* ----------- hcr ------------ */ + self->flags |= (asc->m_hcrFlag) ? AC_ER_HCR : 0; + + if (asc->m_aot == AOT_ER_AAC_ELD) { + self->flags |= AC_ELD; + self->flags |= (asc->m_sc.m_eldSpecificConfig.m_sbrCrcFlag) ? AC_SBRCRC : 0; + self->flags |= (asc->m_sc.m_eldSpecificConfig.m_useLdQmfTimeAlign) ? AC_LD_MPS : 0; + } + self->flags |= (asc->m_aot == AOT_ER_AAC_LD) ? AC_LD : 0; + self->flags |= (asc->m_epConfig >= 0) ? AC_ER : 0; + + + if (asc->m_sbrPresentFlag) { + self->sbrEnabled = 1; + self->sbrEnabledPrev = 1; + } + if (asc->m_psPresentFlag) { + self->flags |= AC_PS_PRESENT; + } + + if ( (asc->m_epConfig >= 0) + && (asc->m_channelConfiguration <= 0) ) { + /* we have to know the number of channels otherwise no decoding is possible */ + return AAC_DEC_UNSUPPORTED_ER_FORMAT; + } + + self->streamInfo.epConfig = asc->m_epConfig; + /* self->hInput->asc.m_epConfig = asc->m_epConfig; */ + + if (asc->m_epConfig > 1) + return AAC_DEC_UNSUPPORTED_ER_FORMAT; + + /* Check if samplerate changed. */ + if (self->streamInfo.aacSampleRate != (INT)asc->m_samplingFrequency) { + AAC_DECODER_ERROR error; + + ascChanged = 1; + + /* Update samplerate info. */ + error = getSamplingRateInfo(&self->samplingRateInfo, asc->m_samplesPerFrame, asc->m_samplingFrequencyIndex, asc->m_samplingFrequency); + if (error != AAC_DEC_OK) { + return error; + } + self->streamInfo.aacSampleRate = self->samplingRateInfo.samplingRate; + } + + /* Check if amount of channels has changed. */ + if (self->ascChannels != ascChannels) + { + ascChanged = 1; + + /* Allocate all memory structures for each channel */ + { + for (ch = 0; ch < ascChannels; ch++) { + CAacDecoderDynamicData *aacDecoderDynamicData = &self->aacCommonData.workBufferCore1->pAacDecoderDynamicData[ch%2]; + + /* initialize pointer to CAacDecoderChannelInfo */ + if (self->pAacDecoderChannelInfo[ch] == NULL) { + self->pAacDecoderChannelInfo[ch] = GetAacDecoderChannelInfo(ch); + /* This is temporary until the DynamicData is split into two or more regions! + The memory could be reused after completed core decoding. */ + if (self->pAacDecoderChannelInfo[ch] == NULL) { + goto bail; + } + /* Hook shared work memory into channel data structure */ + self->pAacDecoderChannelInfo[ch]->pDynData = aacDecoderDynamicData; + self->pAacDecoderChannelInfo[ch]->pComData = &self->aacCommonData; + } + + /* Allocate persistent channel memory */ + if (self->pAacDecoderStaticChannelInfo[ch] == NULL) { + self->pAacDecoderStaticChannelInfo[ch] = GetAacDecoderStaticChannelInfo(ch); + if (self->pAacDecoderStaticChannelInfo[ch] == NULL) { + goto bail; + } + self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer = GetOverlapBuffer(ch); /* This area size depends on the AOT */ + if (self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer == NULL) { + goto bail; + } + self->pAacDecoderChannelInfo[ch]->pSpectralCoefficient = (SPECTRAL_PTR) &self->aacCommonData.workBufferCore2[ch*1024]; + + } + CPns_InitPns(&self->pAacDecoderChannelInfo[ch]->data.aac.PnsData, &self->aacCommonData.pnsInterChannelData, &self->aacCommonData.pnsCurrentSeed, self->aacCommonData.pnsRandomSeed); + } + + + HcrInitRom(&self->aacCommonData.overlay.aac.erHcrInfo); + setHcrType(&self->aacCommonData.overlay.aac.erHcrInfo, ID_SCE); + + /* Make allocated channel count persistent in decoder context. */ + self->aacChannels = ascChannels; + } + + /* Make amount of signalled channels persistent in decoder context. */ + self->ascChannels = ascChannels; + } + + /* Update structures */ + if (ascChanged) { + + /* Things to be done for each channel, which do not involved allocating memory. */ + for (ch = 0; ch < ascChannels; ch++) { + switch (self->streamInfo.aot) { + case AOT_ER_AAC_ELD: + case AOT_ER_AAC_LD: + self->pAacDecoderChannelInfo[ch]->granuleLength = self->streamInfo.aacSamplesPerFrame; + break; + default: + self->pAacDecoderChannelInfo[ch]->granuleLength = self->streamInfo.aacSamplesPerFrame / 8; + break; + } + mdct_init( &self->pAacDecoderStaticChannelInfo[ch]->IMdct, + self->pAacDecoderStaticChannelInfo[ch]->pOverlapBuffer, + OverlapBufferSize ); + + + /* Reset DRC control data for this channel */ + aacDecoder_drcInitChannelData ( &self->pAacDecoderStaticChannelInfo[ch]->drcData ); + + /* Reset concealment only if ASC changed. Otherwise it will be done with any config callback. + E.g. every time the LATM SMC is present. */ + CConcealment_InitChannelData(&self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo, + &self->concealCommonData, + self->streamInfo.aacSamplesPerFrame ); + } + } + + /* Update externally visible copy of flags */ + self->streamInfo.flags = self->flags; + + return err; + +bail: + aacDecoder_Close( self ); + return AAC_DEC_OUT_OF_MEMORY; +} + + +LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( + HANDLE_AACDECODER self, + const UINT flags, + INT_PCM *pTimeData, + const INT timeDataSize, + const INT interleaved + ) +{ + AAC_DECODER_ERROR ErrorStatus = AAC_DEC_OK; + + CProgramConfig *pce; + HANDLE_FDK_BITSTREAM bs = transportDec_GetBitstream(self->hInput, 0); + + MP4_ELEMENT_ID type = ID_NONE; /* Current element type */ + INT aacChannels=0; /* Channel counter for channels found in the bitstream */ + + INT auStartAnchor = (INT)FDKgetValidBits(bs); /* AU start bit buffer position for AU byte alignment */ + + self->frameOK = 1; + + /* Any supported base layer valid AU will require more than 16 bits. */ + if ( (transportDec_GetAuBitsRemaining(self->hInput, 0) < 15) && (flags & (AACDEC_CONCEAL|AACDEC_FLUSH)) == 0) { + self->frameOK = 0; + ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; + } + + + /* Reset Program Config structure */ + pce = &self->pce; + CProgramConfig_Reset(pce); + + CAacDecoder_AncDataReset(&self->ancData); + + { + int ch; + + if (self->streamInfo.channelConfig == 0) { + /* Init Channel/Element mapping table */ + for (ch=0; ch<(6); ch++) { + self->chMapping[ch] = 255; + } + if (!CProgramConfig_IsValid(pce)) { + int el; + for (el=0; el<7; el++) { + self->elements[el] = ID_NONE; + } + } + } + } + + /* Check sampling frequency */ + switch ( self->streamInfo.aacSampleRate ) { + case 16000: + case 12000: + case 11025: + case 8000: + case 7350: + case 48000: + case 44100: + case 32000: + case 24000: + case 22050: + break; + default: + if ( ! (self->flags & (AC_USAC|AC_RSVD50)) ) { + return AAC_DEC_UNSUPPORTED_SAMPLINGRATE; + } + break; + } + + + if ( flags & AACDEC_CLRHIST ) + { + int ch; + /* Clear history */ + for (ch = 0; ch < self->aacChannels; ch++) { + /* Reset concealment */ + CConcealment_InitChannelData(&self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo, + &self->concealCommonData, + self->streamInfo.aacSamplesPerFrame ); + /* Clear concealment buffers to get rid of the complete history */ + FDKmemclear(self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo.spectralCoefficient, 1024 * sizeof(FIXP_CNCL)); + FDKmemclear(self->pAacDecoderStaticChannelInfo[ch]->concealmentInfo.specScale, 8 * sizeof(SHORT)); + /* Clear overlap-add buffers to avoid clicks. */ + FDKmemclear(self->pAacDecoderStaticChannelInfo[ch]->IMdct.overlap.freq, OverlapBufferSize*sizeof(FIXP_DBL)); + } + } + + + +#ifdef TP_PCE_ENABLE + int pceRead = 0; /* Flag indicating a PCE in the current raw_data_block() */ +#endif + + + INT hdaacDecoded = 0; + MP4_ELEMENT_ID previous_element = ID_END; /* Last element ID (required for extension payload mapping */ + UCHAR previous_element_index = 0; /* Canonical index of last element */ + int element_count = 0; /* Element counter for elements found in the bitstream */ + int el_cnt[ID_LAST] = { 0 }; /* element counter ( robustness ) */ + + while ( (type != ID_END) && (! (flags & (AACDEC_CONCEAL | AACDEC_FLUSH))) && self->frameOK ) + { + int el_channels; + + if (! (self->flags & (AC_USAC|AC_RSVD50|AC_ELD|AC_SCALABLE|AC_ER))) + type = (MP4_ELEMENT_ID) FDKreadBits(bs,3); + else + type = self->elements[element_count]; + + setHcrType(&self->aacCommonData.overlay.aac.erHcrInfo, type); + + + if ((INT)FDKgetValidBits(bs) < 0) + self->frameOK = 0; + + switch (type) + { + case ID_SCE: + case ID_CPE: + case ID_LFE: + /* + Consistency check + */ + + if (type == ID_CPE) { + el_channels = 2; + } else { + el_channels = 1; + } + + if ( (el_cnt[type] >= (self->ascChannels>>(el_channels-1))) || (aacChannels > (self->ascChannels-el_channels)) ) { + ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; + self->frameOK = 0; + break; + } + + if ( !(self->flags & (AC_USAC|AC_RSVD50)) ) { + int ch; + for (ch=0; ch < el_channels; ch+=1) { + CPns_ResetData(&self->pAacDecoderChannelInfo[aacChannels+ch]->data.aac.PnsData, + &self->pAacDecoderChannelInfo[aacChannels+ch]->pComData->pnsInterChannelData); + } + } + + if(self->frameOK) { + ErrorStatus = CChannelElement_Read( bs, + &self->pAacDecoderChannelInfo[aacChannels], + &self->pAacDecoderStaticChannelInfo[aacChannels], + self->streamInfo.aot, + &self->samplingRateInfo, + self->flags, + self->streamInfo.aacSamplesPerFrame, + el_channels, + self->streamInfo.epConfig, + self->hInput + ); + if (ErrorStatus) { + self->frameOK = 0; + } + } + + + if ( self->frameOK) { + /* Lookup the element and decode it only if it belongs to the current program */ + if ( CProgramConfig_LookupElement( + pce, + self->streamInfo.channelConfig, + self->pAacDecoderChannelInfo[aacChannels]->ElementInstanceTag, + aacChannels, + self->chMapping, + self->channelType, + self->channelIndices, + &previous_element_index, + self->elements, + type) ) + { + if ( !hdaacDecoded ) { + CChannelElement_Decode( + &self->pAacDecoderChannelInfo[aacChannels], + &self->pAacDecoderStaticChannelInfo[aacChannels], + &self->samplingRateInfo, + self->flags, + el_channels + ); + } + aacChannels += 1; + if (type == ID_CPE) { + aacChannels += 1; + } + } + else { + self->frameOK = 0; + } + /* Create SBR element for SBR for upsampling. */ + if ( (type == ID_LFE) + && ( (self->flags & AC_SBR_PRESENT) + || (self->sbrEnabled == 1) ) ) + { + SBR_ERROR sbrError; + + sbrError = sbrDecoder_InitElement( + self->hSbrDecoder, + self->streamInfo.aacSampleRate, + self->streamInfo.extSamplingRate, + self->streamInfo.aacSamplesPerFrame, + self->streamInfo.aot, + ID_LFE, + previous_element_index + ); + if (sbrError != SBRDEC_OK) { + /* Do not try to apply SBR because initializing the element failed. */ + self->sbrEnabled = 0; + } + } + } + + el_cnt[type]++; + break; + + case ID_CCE: + /* + Consistency check + */ + if ( el_cnt[type] > self->ascChannels ) { + ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; + self->frameOK = 0; + break; + } + + if (self->frameOK) + { + /* memory for spectral lines temporal on scratch */ + C_ALLOC_SCRATCH_START(mdctSpec, FIXP_DBL, 1024); + + /* create dummy channel for CCE parsing on stack */ + CAacDecoderChannelInfo tmpAacDecoderChannelInfo, *pTmpAacDecoderChannelInfo; + + FDKmemclear(mdctSpec, 1024*sizeof(FIXP_DBL)); + + tmpAacDecoderChannelInfo.pDynData = self->aacCommonData.workBufferCore1->pAacDecoderDynamicData; + tmpAacDecoderChannelInfo.pComData = &self->aacCommonData; + tmpAacDecoderChannelInfo.pSpectralCoefficient = (SPECTRAL_PTR)mdctSpec; + /* Assume AAC-LC */ + tmpAacDecoderChannelInfo.granuleLength = self->streamInfo.aacSamplesPerFrame / 8; + + /* Reset PNS data. */ + CPns_ResetData(&tmpAacDecoderChannelInfo.data.aac.PnsData, &tmpAacDecoderChannelInfo.pComData->pnsInterChannelData); + + pTmpAacDecoderChannelInfo = &tmpAacDecoderChannelInfo; + /* do CCE parsing */ + ErrorStatus = CChannelElement_Read( bs, + &pTmpAacDecoderChannelInfo, + NULL, + self->streamInfo.aot, + &self->samplingRateInfo, + self->flags, + self->streamInfo.aacSamplesPerFrame, + 1, + self->streamInfo.epConfig, + self->hInput + ); + + C_ALLOC_SCRATCH_END(mdctSpec, FIXP_DBL, 1024); + + if (ErrorStatus) { + self->frameOK = 0; + } + + if (self->frameOK) { + /* Lookup the element and decode it only if it belongs to the current program */ + if (CProgramConfig_LookupElement( + pce, + self->streamInfo.channelConfig, + pTmpAacDecoderChannelInfo->ElementInstanceTag, + 0, + self->chMapping, + self->channelType, + self->channelIndices, + &previous_element_index, + self->elements, + type) ) + { + /* decoding of CCE not supported */ + } + else { + self->frameOK = 0; + } + } + } + el_cnt[type]++; + break; + + case ID_DSE: + { + UCHAR element_instance_tag; + + CDataStreamElement_Read( bs, + &self->ancData, + self->hDrcInfo, + self->hInput, + &element_instance_tag, + auStartAnchor ); + + if (!CProgramConfig_LookupElement( + pce, + self->streamInfo.channelConfig, + element_instance_tag, + 0, + self->chMapping, + self->channelType, + self->channelIndices, + &previous_element_index, + self->elements, + type) ) + { + /* most likely an error in bitstream occured */ + //self->frameOK = 0; + } + } + +#if defined(PCM_POSTPROCESS_ENABLE) && defined(DVB_MIXDOWN_ENABLE) && defined(AACDEC_DVB_SUPPORT_ENABLE) + { + UCHAR *pDvbAncData = NULL; + AAC_DECODER_ERROR ancErr; + int ancIndex; + int dvbAncDataSize = 0; + + /* Ask how many anc data elements are in buffer */ + ancIndex = self->ancData.nrElements - 1; + /* Get the last one (if available) */ + ancErr = CAacDecoder_AncDataGet( &self->ancData, + ancIndex, + &pDvbAncData, + &dvbAncDataSize ); + + if (ancErr == AAC_DEC_OK) { + pcmDmx_ReadDvbAncData ( + self->hPcmUtils, + pDvbAncData, + dvbAncDataSize, + 0 /* not mpeg2 */ ); + } + } +#endif /* PCM_POSTPROCESS_ENABLE && DVB_MIXDOWN_ENABLE && AACDEC_DVB_SUPPORT_ENABLE */ + break; + +#ifdef TP_PCE_ENABLE + case ID_PCE: + + if ( CProgramConfigElement_Read( bs, + self->hInput, + pce, + auStartAnchor ) ) + { /* Built element table */ + int elIdx = CProgramConfig_GetElementTable(pce, self->elements); + /* Reset the remaining tabs */ + for ( ; elIdx<7; elIdx++) { + self->elements[elIdx] = ID_NONE; + } + /* Make new number of channel persistant */ + self->ascChannels = pce->NumChannels; + /* If PCE is not first element conceal this frame to avoid inconsistencies */ + if ( element_count != 0 ) { + self->frameOK = 0; + } + } + pceRead = 1; + break; +#endif /* TP_PCE_ENABLE */ + + case ID_FIL: + { + int bitCnt = FDKreadBits(bs,4); /* bs_count */ + + if (bitCnt == 15) + { + int esc_count = FDKreadBits(bs,8); /* bs_esc_count */ + bitCnt = esc_count + 14; + } + + /* Convert to bits */ + bitCnt <<= 3; + + while (bitCnt > 0) { + ErrorStatus = CAacDecoder_ExtPayloadParse(self, bs, &bitCnt, previous_element, previous_element_index, 1); + if (ErrorStatus != AAC_DEC_OK) { + self->frameOK = 0; + break; + } + } + } + break; + + case ID_EXT: + { + INT bitCnt = 0; + + /* get the remaining bits of this frame */ + bitCnt = transportDec_GetAuBitsRemaining(self->hInput, 0); + + if ( (bitCnt > 0) && (self->flags & AC_SBR_PRESENT) && (self->flags & (AC_USAC|AC_RSVD50|AC_ELD)) ) + { + SBR_ERROR err; + int elIdx, numChElements = el_cnt[ID_SCE] + el_cnt[ID_CPE]; + + for (elIdx = 0; elIdx < numChElements; elIdx += 1) + { + err = sbrDecoder_Parse ( + self->hSbrDecoder, + bs, + &bitCnt, + -1, + self->flags & AC_SBRCRC, + self->elements[elIdx], + elIdx, + self->flags & AC_INDEP ); + + if (err != SBRDEC_OK) { + break; + } + } + if (err == SBRDEC_OK) { + self->sbrEnabled = 1; + } else { + self->frameOK = 0; + } + } + + + if ( ! (self->flags & (AC_USAC|AC_RSVD50|AC_DRM)) ) + { + while ( bitCnt > 7 ) { + ErrorStatus = CAacDecoder_ExtPayloadParse(self, bs, &bitCnt, previous_element, previous_element_index, 0); + if (ErrorStatus != AAC_DEC_OK) { + self->frameOK = 0; + ErrorStatus = AAC_DEC_PARSE_ERROR; + break; + } + } + } + } + break; + + case ID_END: + break; + + default: + ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; + self->frameOK = 0; + break; + } + + previous_element = type; + element_count++; + + } /* while ( (type != ID_END) ... ) */ + + if ( !(flags & (AACDEC_CONCEAL|AACDEC_FLUSH)) ) + { + /* Byte alignment with respect to the first bit of the raw_data_block(). */ + { + FDKbyteAlign(bs, auStartAnchor); + } + + /* Check if all bits of the raw_data_block() have been read. */ + if ( transportDec_GetAuBitsTotal(self->hInput, 0) > 0 ) { + INT unreadBits = transportDec_GetAuBitsRemaining(self->hInput, 0); + if ( unreadBits != 0 ) { + + self->frameOK = 0; + /* Do not overwrite current error */ + if (ErrorStatus == AAC_DEC_OK && self->frameOK == 0) { + ErrorStatus = AAC_DEC_PARSE_ERROR; + } + /* Always put the bitbuffer at the right position after the current Access Unit. */ + FDKpushBiDirectional(bs, unreadBits); + } + } + + /* Check the last element. The terminator (ID_END) has to be the last one (even if ER syntax is used). */ + if ( self->frameOK && type != ID_END ) { + /* Do not overwrite current error */ + if (ErrorStatus == AAC_DEC_OK) { + ErrorStatus = AAC_DEC_PARSE_ERROR; + } + self->frameOK = 0; + } + } + + /* More AAC channels than specified by the ASC not allowed. */ + if ( (aacChannels == 0 || aacChannels > self->aacChannels) && !(flags & (AACDEC_CONCEAL|AACDEC_FLUSH)) ) { + { + /* Do not overwrite current error */ + if (ErrorStatus == AAC_DEC_OK) { + ErrorStatus = AAC_DEC_DECODE_FRAME_ERROR; + } + self->frameOK = 0; + } + aacChannels = 0; + } + else if ( aacChannels > self->ascChannels ) { + /* Do not overwrite current error */ + if (ErrorStatus == AAC_DEC_OK) { + ErrorStatus = AAC_DEC_UNSUPPORTED_FORMAT; + } + self->frameOK = 0; + aacChannels = 0; + } + + if ( TRANSPORTDEC_OK != transportDec_CrcCheck(self->hInput) ) + { + self->frameOK=0; + } + + /* store or restore the number of channels */ + if ( self->frameOK && !(flags &(AACDEC_CONCEAL|AACDEC_FLUSH)) ) { + self->concealChannels = aacChannels; /* store */ + self->sbrEnabledPrev = self->sbrEnabled; + } else { + if (self->aacChannels > 0) { + aacChannels = self->concealChannels; /* restore */ + self->sbrEnabled = self->sbrEnabledPrev; + } + } + + /* Update number of output channels */ + self->streamInfo.numChannels = aacChannels; + +#if defined(TP_PCE_ENABLE) && defined(PCM_POSTPROCESS_ENABLE) && defined(MPEG_PCE_MIXDOWN_ENABLE) + if (pceRead == 1 || CProgramConfig_IsValid(pce)) { + /* Set matrix mixdown infos if available from PCE. */ + pcmDmx_SetMatrixMixdownFromPce ( self->hPcmUtils, + pce->MatrixMixdownIndexPresent, + pce->MatrixMixdownIndex, + pce->PseudoSurroundEnable ); + } +#endif + + /* If there is no valid data to transfrom into time domain, return. */ + if ( ! IS_OUTPUT_VALID(ErrorStatus) ) { + return ErrorStatus; + } + + /* + Inverse transform + */ + { + int stride, offset, c; + + /* Extract DRC control data and map it to channels (without bitstream delay) */ + aacDecoder_drcProlog ( + self->hDrcInfo, + bs, + self->pAacDecoderStaticChannelInfo, + self->pce.ElementInstanceTag, + self->chMapping, + aacChannels + ); + + /* "c" iterates in canonical MPEG channel order */ + for (c=0; c < aacChannels; c++) + { + CAacDecoderChannelInfo *pAacDecoderChannelInfo; + + /* Select correct pAacDecoderChannelInfo for current channel */ + if (self->chMapping[c] >= aacChannels) { + pAacDecoderChannelInfo = self->pAacDecoderChannelInfo[c]; + } else { + pAacDecoderChannelInfo = self->pAacDecoderChannelInfo[self->chMapping[c]]; + } + + /* Setup offset and stride for time buffer traversal. */ + if (interleaved) { + stride = aacChannels; + offset = self->channelOutputMapping[aacChannels-1][c]; + } else { + stride = 1; + offset = self->channelOutputMapping[aacChannels-1][c] * self->streamInfo.aacSamplesPerFrame; + } + + + /* + Conceal defective spectral data + */ + CConcealment_Apply(&self->pAacDecoderStaticChannelInfo[c]->concealmentInfo, + pAacDecoderChannelInfo, + self->pAacDecoderStaticChannelInfo[c], + &self->samplingRateInfo, + self->streamInfo.aacSamplesPerFrame, + 0, + (self->frameOK && !(flags&AACDEC_CONCEAL)), + self->flags + ); + + + if (flags & (AACDEC_INTR|AACDEC_CLRHIST)) { + /* Reset DRC control data for this channel */ + aacDecoder_drcInitChannelData ( &self->pAacDecoderStaticChannelInfo[c]->drcData ); + } + /* DRC processing */ + aacDecoder_drcApply ( + self->hDrcInfo, + self->hSbrDecoder, + pAacDecoderChannelInfo, + &self->pAacDecoderStaticChannelInfo[c]->drcData, + c, + self->streamInfo.aacSamplesPerFrame, + self->sbrEnabled + ); + + if ( flags&AACDEC_FLUSH ) { + FDKmemclear(pAacDecoderChannelInfo->pSpectralCoefficient, sizeof(FIXP_DBL)*self->streamInfo.aacSamplesPerFrame); + } + + switch (pAacDecoderChannelInfo->renderMode) + { + case AACDEC_RENDER_IMDCT: + CBlock_FrequencyToTime( + self->pAacDecoderStaticChannelInfo[c], + pAacDecoderChannelInfo, + pTimeData + offset, + self->streamInfo.aacSamplesPerFrame, + stride, + (self->frameOK && !(flags&AACDEC_CONCEAL)), + self->aacCommonData.workBufferCore1->mdctOutTemp + ); + break; + case AACDEC_RENDER_ELDFB: + CBlock_FrequencyToTimeLowDelay( + self->pAacDecoderStaticChannelInfo[c], + pAacDecoderChannelInfo, + pTimeData + offset, + self->streamInfo.aacSamplesPerFrame, + stride + ); + break; + default: + ErrorStatus = AAC_DEC_UNKNOWN; + break; + } + if ( flags&AACDEC_FLUSH ) { + FDKmemclear(self->pAacDecoderStaticChannelInfo[c]->pOverlapBuffer, OverlapBufferSize*sizeof(FIXP_DBL)); + } + } + + + /* Extract DRC control data and map it to channels (with bitstream delay) */ + aacDecoder_drcEpilog ( + self->hDrcInfo, + bs, + self->pAacDecoderStaticChannelInfo, + self->pce.ElementInstanceTag, + self->chMapping, + aacChannels + ); + } + + + /* Reorder channel type information tables. */ + { + AUDIO_CHANNEL_TYPE types[(6)]; + UCHAR idx[(6)]; + int c; + + FDK_ASSERT(sizeof(self->channelType) == sizeof(types)); + FDK_ASSERT(sizeof(self->channelIndices) == sizeof(idx)); + + FDKmemcpy(types, self->channelType, sizeof(types)); + FDKmemcpy(idx, self->channelIndices, sizeof(idx)); + + for (c=0; cchannelType[self->channelOutputMapping[aacChannels-1][c]] = types[c]; + self->channelIndices[self->channelOutputMapping[aacChannels-1][c]] = idx[c]; + } + } + + self->blockNumber++; + + return ErrorStatus; +} + +/*! + \brief returns the streaminfo pointer + + The function hands back a pointer to the streaminfo structure + + \return pointer to the struct +*/ +LINKSPEC_CPP CStreamInfo* CAacDecoder_GetStreamInfo ( HANDLE_AACDECODER self ) +{ + if (!self) { + return NULL; + } + return &self->streamInfo; +} + + + + diff --git a/libAACdec/src/aacdecoder.h b/libAACdec/src/aacdecoder.h new file mode 100644 index 0000000..66d6361 --- /dev/null +++ b/libAACdec/src/aacdecoder.h @@ -0,0 +1,250 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef AACDECODER_H +#define AACDECODER_H + +#include "common_fix.h" + +#include "FDK_bitstream.h" + +#include "channel.h" + +#include "tpdec_lib.h" +#include "FDK_audio.h" + +#include "block.h" + +#include "genericStds.h" + + +#include "sbrdecoder.h" + + +#include "aacdec_drc.h" + + #include "pcmutils_lib.h" + + +/* Capabilities flags */ +#define CAPF_AAC_LC 0x00000001 +#define CAPF_AAC_LD 0x00000002 +#define CAPF_AAC_SCAL 0x00000004 +#define CAPF_AAC_ER 0x00000008 +#define CAPF_AAC_480 0x00000010 +#define CAPF_AAC_512 0x00000020 +#define CAPF_AAC_960 0x00000040 +#define CAPF_AAC_1024 0x00000080 +#define CAPF_AAC_HCR 0x00000100 +#define CAPF_AAC_VCB11 0x00000200 +#define CAPF_AAC_RVLC 0x00000400 +#define CAPF_AAC_MPEG4 0x00000800 /* PNS */ +#define CAPF_AAC_DRC 0x00001000 +#define CAPF_AAC_CONCEAL 0x00002000 +#define CAPF_AAC_DRM_BSFORMAT 0x00004000 +#define CAPF_AAC_BSAC 0x00008000 + +typedef struct AAC_DECODER_INSTANCE *HANDLE_AACDECODER; + + +enum +{ + L = 0, + R = 1 +}; + +typedef struct { + unsigned char *buffer; + int bufferSize; + int offset[8]; + int nrElements; +} CAncData; + +typedef enum { + NOT_DEFINED = -1, + MODE_HQ = 0, + MODE_LP = 1 +} QMF_MODE; + +typedef struct { + int bsDelay; +} SBR_PARAMS; + + +/* AAC decoder (opaque toward userland) struct declaration */ +struct AAC_DECODER_INSTANCE { + INT aacChannels; /*!< Amount of AAC decoder channels allocated. */ + INT ascChannels; /*!< Amount of AAC decoder channels signalled in ASC. */ + INT blockNumber; /*!< frame counter */ + + INT nrOfLayers; + + INT outputInterleaved; /*!< PCM output format (interleaved/none interleaved). */ + + HANDLE_TRANSPORTDEC hInput; /*!< Transport layer handle. */ + + SamplingRateInfo samplingRateInfo; /*!< Sampling Rate information table */ + + UCHAR frameOK; /*!< Will be unset if a consistency check, e.g. CRC etc. fails */ + + UINT flags; /*!< Flags for internal decoder use. DO NOT USE self::streaminfo::flags ! */ + + MP4_ELEMENT_ID elements[7]; /*!< Table where the element Id's are listed */ + UCHAR elTags[7]; /*!< Table where the elements id Tags are listed */ + UCHAR chMapping[(6)]; /*!< Table of MPEG canonical order to bitstream channel order mapping. */ + + AUDIO_CHANNEL_TYPE channelType[(6)]; /*!< Audio channel type of each output audio channel (from 0 upto numChannels). */ + UCHAR channelIndices[(6)]; /*!< Audio channel index for each output audio channel (from 0 upto numChannels). */ + /* See ISO/IEC 13818-7:2005(E), 8.5.3.2 Explicit channel mapping using a program_config_element() */ + + + const UCHAR (*channelOutputMapping)[8]; /*!< Table for MPEG canonical order to output channel order mapping. */ + + + CProgramConfig pce; + CStreamInfo streamInfo; /*!< pointer to StreamInfo data (read from the bitstream) */ + CAacDecoderChannelInfo *pAacDecoderChannelInfo[(6)]; /*!< Temporal channel memory */ + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[(6)]; /*!< Persistent channel memory */ + + CAacDecoderCommonData aacCommonData; /*!< Temporal shared data for all channels hooked into pAacDecoderChannelInfo */ + + CConcealParams concealCommonData; + INT concealChannels; + + + HANDLE_SBRDECODER hSbrDecoder; /*!< SBR decoder handle. */ + UCHAR sbrEnabled; /*!< flag to store if SBR has been detected */ + UCHAR sbrEnabledPrev; /*!< flag to store if SBR has been detected from previous frame */ + UCHAR psPossible; /*!< flag to store if PS is possible */ + SBR_PARAMS sbrParams; /*!< struct to store all sbr parameters */ + + QMF_MODE qmfModeCurr; /*!< The current QMF mode */ + QMF_MODE qmfModeUser; /*!< The QMF mode requested by the library user */ + + HANDLE_AAC_DRC hDrcInfo; /*!< handle to DRC data structure */ + + + CAncData ancData; /*!< structure to handle ancillary data */ + + HANDLE_PCM_DOWNMIX hPcmUtils; /*!< privat data for the PCM utils. */ + +}; + + +#define AAC_DEBUG_EXTHLP "\ +--- AAC-Core ---\n\ + 0x00010000 Header data\n\ + 0x00020000 CRC data\n\ + 0x00040000 Channel info\n\ + 0x00080000 Section data\n\ + 0x00100000 Scalefactor data\n\ + 0x00200000 Pulse data\n\ + 0x00400000 Tns data\n\ + 0x00800000 Quantized spectrum\n\ + 0x01000000 Requantized spectrum\n\ + 0x02000000 Time output\n\ + 0x04000000 Fatal errors\n\ + 0x08000000 Buffer fullness\n\ + 0x10000000 Average bitrate\n\ + 0x20000000 Synchronization\n\ + 0x40000000 Concealment\n\ + 0x7FFF0000 all AAC-Core-Info\n\ +" + +/** + * \brief Synchronise QMF mode for all modules using QMF data. + * \param self decoder handle + */ +void CAacDecoder_SyncQmfMode(HANDLE_AACDECODER self); + +/** + * \brief Signal a bit stream interruption to the decoder + * \param self decoder handle + */ +void CAacDecoder_SignalInterruption(HANDLE_AACDECODER self); + +/*! + \brief Initialize ancillary buffer + + \ancData Pointer to ancillary data structure + \buffer Pointer to (external) anc data buffer + \size Size of the buffer pointed on by buffer + + \return Error code +*/ +AAC_DECODER_ERROR CAacDecoder_AncDataInit(CAncData *ancData, unsigned char *buffer, int size); + +/*! + \brief Get one ancillary data element + + \ancData Pointer to ancillary data structure + \index Index of the anc data element to get + \ptr Pointer to a buffer receiving a pointer to the requested anc data element + \size Pointer to a buffer receiving the length of the requested anc data element + + \return Error code +*/ +AAC_DECODER_ERROR CAacDecoder_AncDataGet(CAncData *ancData, int index, unsigned char **ptr, int *size); + + +/* initialization of aac decoder */ +LINKSPEC_H HANDLE_AACDECODER CAacDecoder_Open(TRANSPORT_TYPE bsFormat); + +/* Initialization of stream-info elements */ +LINKSPEC_H AAC_DECODER_ERROR CAacDecoder_Init(HANDLE_AACDECODER self, + const CSAudioSpecificConfig *asc); + +/*! + \brief Decodes one aac frame + + The function decodes one aac frame. The decoding of coupling channel + elements are not supported. The transport layer might signal, that the + data of the current frame is invalid, e.g. as a result of a packet + loss in streaming mode. + The bitstream position of transportDec_GetBitstream(self->hInput) must + be exactly the end of the access unit, including all byte alignment bits. + For this purpose, the variable auStartAnchor is used. + + \return error status +*/ +LINKSPEC_H AAC_DECODER_ERROR CAacDecoder_DecodeFrame( + HANDLE_AACDECODER self, + const UINT flags, + INT_PCM *pTimeData, + const INT timeDataSize, + const INT interleaved + ); + +/* Destroy aac decoder */ +LINKSPEC_H void CAacDecoder_Close ( HANDLE_AACDECODER self ); + +/* get streaminfo handle from decoder */ +LINKSPEC_H CStreamInfo* CAacDecoder_GetStreamInfo ( HANDLE_AACDECODER self ); + + +#endif /* #ifndef AACDECODER_H */ diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp new file mode 100644 index 0000000..379c84c --- /dev/null +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -0,0 +1,925 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS 1999-2008 + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "aacdecoder_lib.h" + +#include "aac_ram.h" +#include "aacdecoder.h" +#include "tpdec_lib.h" +#include "FDK_core.h" /* FDK_tools version info */ + + + #include "sbrdecoder.h" + + + + +#include "conceal.h" + + #include "aacdec_drc.h" + + + +/* Decoder library info */ +#define AACDECODER_LIB_VL0 2 +#define AACDECODER_LIB_VL1 4 +#define AACDECODER_LIB_VL2 0 +#define AACDECODER_LIB_TITLE "AAC Decoder Lib" +#define AACDECODER_LIB_BUILD_DATE __DATE__ +#define AACDECODER_LIB_BUILD_TIME __TIME__ + +static AAC_DECODER_ERROR +setConcealMethod ( const HANDLE_AACDECODER self, + const INT method ); + + +LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_GetFreeBytes ( const HANDLE_AACDECODER self, UINT *pFreeBytes){ + + /* reset free bytes */ + *pFreeBytes = 0; + + /* check handle */ + if(!self) + return AAC_DEC_INVALID_HANDLE; + + /* return nr of free bytes */ + HANDLE_FDK_BITSTREAM hBs = transportDec_GetBitstream(self->hInput, 0); + *pFreeBytes = FDKgetFreeBits(hBs) >> 3; + + /* success */ + return AAC_DEC_OK; +} + +/** + * Config Decoder using a CSAudioSpecificConfig struct. + */ +static +LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_Config(HANDLE_AACDECODER self, const CSAudioSpecificConfig *pAscStruct) +{ + AAC_DECODER_ERROR err; + + /* Initialize AAC core decoder, and update self->streaminfo */ + err = CAacDecoder_Init(self, pAscStruct); + + return err; +} + +LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_ConfigRaw ( + HANDLE_AACDECODER self, + UCHAR *conf[], + const UINT length[] ) +{ + AAC_DECODER_ERROR err = AAC_DEC_OK; + TRANSPORTDEC_ERROR errTp; + UINT layer, nrOfLayers = self->nrOfLayers; + + for(layer = 0; layer < nrOfLayers; layer++){ + if(length[layer] > 0){ + errTp = transportDec_OutOfBandConfig(self->hInput, conf[layer], length[layer], layer); + if (errTp != TRANSPORTDEC_OK) { + switch (errTp) { + case TRANSPORTDEC_NEED_TO_RESTART: + err = AAC_DEC_NEED_TO_RESTART; + break; + case TRANSPORTDEC_UNSUPPORTED_FORMAT: + err = AAC_DEC_UNSUPPORTED_FORMAT; + break; + default: + err = AAC_DEC_UNKNOWN; + break; + } + /* if baselayer is OK we continue decoding */ + if(layer >= 1){ + self->nrOfLayers = layer; + } + break; + } + } + } + + return err; +} + + + +static INT aacDecoder_ConfigCallback(void *handle, const CSAudioSpecificConfig *pAscStruct) +{ + HANDLE_AACDECODER self = (HANDLE_AACDECODER)handle; + AAC_DECODER_ERROR err = AAC_DEC_OK; + TRANSPORTDEC_ERROR errTp; + + { + { + err = aacDecoder_Config(self, pAscStruct); + } + } + if (err == AAC_DEC_OK) { + if ( self->flags & (AC_USAC|AC_RSVD50|AC_LD|AC_ELD) + && CConcealment_GetDelay(&self->concealCommonData) > 0 ) + { + /* Revert to error concealment method Noise Substitution. + Because interpolation is not implemented for USAC/RSVD50 or + the additional delay is unwanted for low delay codecs. */ + setConcealMethod(self, 1); +#ifdef DEBUG + FDKprintf(" Concealment method was reverted to 1 !\n"); +#endif + } + errTp = TRANSPORTDEC_OK; + } else { + if (IS_INIT_ERROR(err)) { + errTp = TRANSPORTDEC_UNSUPPORTED_FORMAT; + } /* Fatal errors */ + else if (err == AAC_DEC_NEED_TO_RESTART) { + errTp = TRANSPORTDEC_NEED_TO_RESTART; + } else { + errTp = TRANSPORTDEC_UNKOWN_ERROR; + } + } + + return errTp; +} + + + +LINKSPEC_CPP AAC_DECODER_ERROR +aacDecoder_AncDataInit ( HANDLE_AACDECODER self, + UCHAR *buffer, + int size ) +{ + CAncData *ancData = &self->ancData; + + return CAacDecoder_AncDataInit(ancData, buffer, size); +} + + +LINKSPEC_CPP AAC_DECODER_ERROR +aacDecoder_AncDataGet ( HANDLE_AACDECODER self, + int index, + UCHAR **ptr, + int *size ) +{ + CAncData *ancData = &self->ancData; + + return CAacDecoder_AncDataGet(ancData, index, ptr, size); +} + + +static AAC_DECODER_ERROR +setConcealMethod ( const HANDLE_AACDECODER self, /*!< Handle of the decoder instance */ + const INT method ) +{ + AAC_DECODER_ERROR errorStatus = AAC_DEC_OK; + CConcealParams *pConcealData = NULL; + HANDLE_SBRDECODER hSbrDec = NULL; + HANDLE_AAC_DRC hDrcInfo = NULL; + HANDLE_PCM_DOWNMIX hPcmDmx = NULL; + CConcealmentMethod backupMethod; + int backupDelay = 0; + int bsDelay = 0; + + /* check decoder handle */ + if (self != NULL) { + pConcealData = &self->concealCommonData; + hSbrDec = self->hSbrDecoder; + hDrcInfo = self->hDrcInfo; + hPcmDmx = self->hPcmUtils; + } + + + /* Get current method/delay */ + backupMethod = CConcealment_GetMethod(pConcealData); + backupDelay = CConcealment_GetDelay(pConcealData); + + /* Be sure to set AAC and SBR concealment method simultaneously! */ + errorStatus = + CConcealment_SetParams( + pConcealData, + (int)method, // concealMethod + AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, // concealFadeOutSlope + AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, // concealFadeInSlope + AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, // concealMuteRelease + AACDEC_CONCEAL_PARAM_NOT_SPECIFIED // concealComfNoiseLevel + ); + if ( (errorStatus != AAC_DEC_OK) + && (errorStatus != AAC_DEC_INVALID_HANDLE) ) { + goto bail; + } + + /* Get new delay */ + bsDelay = CConcealment_GetDelay(pConcealData); + + { + SBR_ERROR sbrErr = SBRDEC_OK; + + /* set SBR bitstream delay */ + sbrErr = sbrDecoder_SetParam ( + hSbrDec, + SBR_SYSTEM_BITSTREAM_DELAY, + bsDelay + ); + + switch (sbrErr) { + case SBRDEC_OK: + case SBRDEC_NOT_INITIALIZED: + if (self != NULL) { + /* save the param value and set later + (when SBR has been initialized) */ + self->sbrParams.bsDelay = bsDelay; + } + break; + default: + errorStatus = AAC_DEC_SET_PARAM_FAIL; + goto bail; + } + } + + errorStatus = + aacDecoder_drcSetParam ( + hDrcInfo, + DRC_BS_DELAY, + bsDelay + ); + if ( (errorStatus != AAC_DEC_OK) + && (errorStatus != AAC_DEC_INVALID_HANDLE) ) { + goto bail; + } + + if (errorStatus == AAC_DEC_OK) { + PCMDMX_ERROR err = + pcmDmx_SetParam ( + hPcmDmx, + DMX_BS_DATA_DELAY, + bsDelay + ); + switch (err) { + case PCMDMX_INVALID_HANDLE: + errorStatus = AAC_DEC_INVALID_HANDLE; + case PCMDMX_OK: + break; + default: + errorStatus = AAC_DEC_SET_PARAM_FAIL; + goto bail; + } + } + + +bail: + if ( (errorStatus != AAC_DEC_OK) + && (errorStatus != AAC_DEC_INVALID_HANDLE) ) + { + /* Revert to the initial state */ + CConcealment_SetParams ( + pConcealData, + (int)backupMethod, + AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, + AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, + AACDEC_CONCEAL_PARAM_NOT_SPECIFIED, + AACDEC_CONCEAL_PARAM_NOT_SPECIFIED + ); + /* Revert SBR bitstream delay */ + sbrDecoder_SetParam ( + hSbrDec, + SBR_SYSTEM_BITSTREAM_DELAY, + backupDelay + ); + /* Revert DRC bitstream delay */ + aacDecoder_drcSetParam ( + hDrcInfo, + DRC_BS_DELAY, + backupDelay + ); + /* Revert PCM mixdown bitstream delay */ + pcmDmx_SetParam ( + hPcmDmx, + DMX_BS_DATA_DELAY, + backupDelay + ); + } + + return errorStatus; +} + + +LINKSPEC_CPP AAC_DECODER_ERROR +aacDecoder_SetParam ( const HANDLE_AACDECODER self, /*!< Handle of the decoder instance */ + const AACDEC_PARAM param, /*!< Parameter to set */ + const INT value) /*!< Parameter valued */ +{ + AAC_DECODER_ERROR errorStatus = AAC_DEC_OK; + CConcealParams *pConcealData = NULL; + HANDLE_AAC_DRC hDrcInfo = NULL; + + /* check decoder handle */ + if (self != NULL) { + pConcealData = &self->concealCommonData; + hDrcInfo = self->hDrcInfo; + } + + /* configure the subsystems */ + switch (param) + { + case AAC_PCM_OUTPUT_INTERLEAVED: + if (value < 0 || value > 1) { + return AAC_DEC_SET_PARAM_FAIL; + } + if (self == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + self->outputInterleaved = value; + break; + + case AAC_PCM_OUTPUT_CHANNELS: + { + PCMDMX_ERROR err; + + err = pcmDmx_SetParam ( + self->hPcmUtils, + NUMBER_OF_OUTPUT_CHANNELS, + value ); + + switch (err) { + case PCMDMX_OK: + break; + case PCMDMX_INVALID_HANDLE: + return AAC_DEC_INVALID_HANDLE; + default: + return AAC_DEC_SET_PARAM_FAIL; + } + } + break; + + case AAC_PCM_DUAL_CHANNEL_OUTPUT_MODE: + { + PCMDMX_ERROR err; + + err = pcmDmx_SetParam ( + self->hPcmUtils, + DUAL_CHANNEL_DOWNMIX_MODE, + value ); + + switch (err) { + case PCMDMX_OK: + break; + case PCMDMX_INVALID_HANDLE: + return AAC_DEC_INVALID_HANDLE; + default: + return AAC_DEC_SET_PARAM_FAIL; + } + } + break; + + case AAC_PCM_OUTPUT_CHANNEL_MAPPING: + switch (value) { + case 0: + self->channelOutputMapping = channelMappingTablePassthrough; + break; + case 1: + self->channelOutputMapping = channelMappingTableWAV; + break; + default: + errorStatus = AAC_DEC_SET_PARAM_FAIL; + break; + } + break; + + + case AAC_QMF_LOWPOWER: + if (self == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + + /** + * Set QMF mode (might be overriden) + * 0:HQ (complex) + * 1:LP (partially complex) + */ + self->qmfModeUser = (QMF_MODE)value; + break; + + + case AAC_DRC_ATTENUATION_FACTOR: + /* DRC compression factor (where 0 is no and 127 is max compression) */ + errorStatus = + aacDecoder_drcSetParam ( + hDrcInfo, + DRC_CUT_SCALE, + value + ); + break; + + case AAC_DRC_BOOST_FACTOR: + /* DRC boost factor (where 0 is no and 127 is max boost) */ + errorStatus = + aacDecoder_drcSetParam ( + hDrcInfo, + DRC_BOOST_SCALE, + value + ); + break; + + case AAC_DRC_REFERENCE_LEVEL: + /* DRC reference level quantized in 0.25dB steps using values [0..127] it is '-' for analog scaling */ + errorStatus = + aacDecoder_drcSetParam ( + hDrcInfo, + TARGET_REF_LEVEL, + value + ); + break; + + case AAC_DRC_HEAVY_COMPRESSION: + /* Don't need to overwrite cut/boost values */ + errorStatus = + aacDecoder_drcSetParam ( + hDrcInfo, + APPLY_HEAVY_COMPRESSION, + value + ); + break; + + + case AAC_TPDEC_CLEAR_BUFFER: + transportDec_SetParam(self->hInput, TPDEC_PARAM_RESET, 1); + self->streamInfo.numLostAccessUnits = 0; + self->streamInfo.numBadBytes = 0; + self->streamInfo.numTotalBytes = 0; + /* aacDecoder_SignalInterruption(self); */ + break; + + case AAC_CONCEAL_METHOD: + /* Changing the concealment method can introduce additional bitstream delay. And + that in turn affects sub libraries and modules which makes the whole thing quite + complex. So the complete changing routine is packed into a helper function which + keeps all modules and libs in a consistent state even in the case an error occures. */ + errorStatus = setConcealMethod ( self, value ); + break; + + default: + return AAC_DEC_SET_PARAM_FAIL; + } /* switch(param) */ + + return (errorStatus); +} + + +LINKSPEC_CPP HANDLE_AACDECODER aacDecoder_Open(TRANSPORT_TYPE transportFmt, UINT nrOfLayers) +{ + AAC_DECODER_INSTANCE *aacDec = NULL; + HANDLE_TRANSPORTDEC pIn; + int err = 0; + + /* Allocate transport layer struct. */ + pIn = transportDec_Open(transportFmt, TP_FLAG_MPEG4); + if (pIn == NULL) { + return NULL; + } + + /* Allocate AAC decoder core struct. */ + aacDec = CAacDecoder_Open(transportFmt); + + if (aacDec == NULL) { + transportDec_Close(&pIn); + goto bail; + } + aacDec->hInput = pIn; + + aacDec->nrOfLayers = nrOfLayers; + + aacDec->channelOutputMapping = channelMappingTableWAV; + + /* Register Config Update callback. */ + transportDec_RegisterAscCallback(pIn, aacDecoder_ConfigCallback, (void*)aacDec); + + /* open SBR decoder */ + if ( SBRDEC_OK != sbrDecoder_Open ( &aacDec->hSbrDecoder )) { + err = -1; + goto bail; + } + aacDec->qmfModeUser = NOT_DEFINED; + transportDec_RegisterSbrCallback(aacDec->hInput, (cbSbr_t)sbrDecoder_Header, (void*)aacDec->hSbrDecoder); + + + pcmDmx_Open( &aacDec->hPcmUtils ); + if (aacDec->hPcmUtils == NULL) { + err = -1; + goto bail; + } + + + + /* Assure that all modules have same delay */ + if ( setConcealMethod(aacDec, CConcealment_GetMethod(&aacDec->concealCommonData)) ) { + err = -1; + goto bail; + } + +bail: + if (err == -1) { + aacDecoder_Close(aacDec); + aacDec = NULL; + } + return aacDec; +} + +LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_Fill( + HANDLE_AACDECODER self, + UCHAR *pBuffer[], + const UINT bufferSize[], + UINT *pBytesValid + ) +{ + TRANSPORTDEC_ERROR tpErr; + /* loop counter for layers; if not TT_MP4_RAWPACKETS used as index for only + available layer */ + INT layer = 0; + INT nrOfLayers = self->nrOfLayers; + + { + for (layer = 0; layer < nrOfLayers; layer++){ + { + tpErr = transportDec_FillData( self->hInput, pBuffer[layer], bufferSize[layer], &pBytesValid[layer], layer ); + if (tpErr != TRANSPORTDEC_OK) { + return AAC_DEC_UNKNOWN; /* Must be an internal error */ + } + } + } + } + + return AAC_DEC_OK; +} + + +static void aacDecoder_SignalInterruption(HANDLE_AACDECODER self) +{ + CAacDecoder_SignalInterruption(self); + + if ( self->hSbrDecoder != NULL ) { + sbrDecoder_SetParam(self->hSbrDecoder, SBR_BS_INTERRUPTION, 0); + } +} + +static void aacDecoder_UpdateBitStreamCounters(CStreamInfo *pSi, HANDLE_FDK_BITSTREAM hBs, int nBits, AAC_DECODER_ERROR ErrorStatus) +{ + /* calculate bit difference (amount of bits moved forward) */ + nBits = nBits - FDKgetValidBits(hBs); + + /* Note: The amount of bits consumed might become negative when parsing a + bit stream with several sub frames, and we find out at the last sub frame + that the total frame length does not match the sum of sub frame length. + If this happens, the transport decoder might want to rewind to the supposed + ending of the transport frame, and this position might be before the last + access unit beginning. */ + + /* Calc bitrate. */ + if (pSi->frameSize > 0) { + pSi->bitRate = (nBits * pSi->sampleRate)/pSi->frameSize; + } + + /* bit/byte counters */ + { + int nBytes; + + nBytes = nBits>>3; + pSi->numTotalBytes += nBytes; + if (IS_OUTPUT_VALID(ErrorStatus)) { + pSi->numTotalAccessUnits++; + } + if (IS_DECODE_ERROR(ErrorStatus)) { + pSi->numBadBytes += nBytes; + pSi->numBadAccessUnits++; + } + } +} + +static INT aacDecoder_EstimateNumberOfLostFrames(HANDLE_AACDECODER self) +{ + INT n; + + transportDec_GetMissingAccessUnitCount( &n, self->hInput); + + return n; +} + +LINKSPEC_CPP AAC_DECODER_ERROR aacDecoder_DecodeFrame( + HANDLE_AACDECODER self, + INT_PCM *pTimeData, + const INT timeDataSize, + const UINT flags) +{ + AAC_DECODER_ERROR ErrorStatus; + INT layer; + INT nBits; + INT interleaved = self->outputInterleaved; + HANDLE_FDK_BITSTREAM hBs; + int fTpInterruption = 0; /* Transport originated interruption detection. */ + int fTpConceal = 0; /* Transport originated concealment. */ + + + if (self == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + + if (flags & AACDEC_INTR) { + self->streamInfo.numLostAccessUnits = 0; + } + + hBs = transportDec_GetBitstream(self->hInput, 0); + + /* Get current bits position for bitrate calculation. */ + nBits = FDKgetValidBits(hBs); + if (! (flags & (AACDEC_CONCEAL | AACDEC_FLUSH) ) ) + { + TRANSPORTDEC_ERROR err; + + for(layer = 0; layer < self->nrOfLayers; layer++) + { + err = transportDec_ReadAccessUnit(self->hInput, layer); + if (err != TRANSPORTDEC_OK) { + switch (err) { + case TRANSPORTDEC_NOT_ENOUGH_BITS: + ErrorStatus = AAC_DEC_NOT_ENOUGH_BITS; + goto bail; + case TRANSPORTDEC_SYNC_ERROR: + self->streamInfo.numLostAccessUnits = aacDecoder_EstimateNumberOfLostFrames(self); + fTpInterruption = 1; + break; + case TRANSPORTDEC_NEED_TO_RESTART: + ErrorStatus = AAC_DEC_NEED_TO_RESTART; + goto bail; + case TRANSPORTDEC_CRC_ERROR: + fTpConceal = 1; + break; + default: + ErrorStatus = AAC_DEC_UNKNOWN; + goto bail; + } + } + } + } else { + if (self->streamInfo.numLostAccessUnits > 0) { + self->streamInfo.numLostAccessUnits--; + } + } + + /* Signal bit stream interruption to other modules if required. */ + if ( fTpInterruption || (flags & (AACDEC_INTR|AACDEC_CLRHIST)) ) + { + aacDecoder_SignalInterruption(self); + if ( ! (flags & AACDEC_INTR) ) { + ErrorStatus = AAC_DEC_TRANSPORT_SYNC_ERROR; + goto bail; + } + } + + /* Empty bit buffer in case of flush request. */ + if (flags & AACDEC_FLUSH) + { + transportDec_SetParam(self->hInput, TPDEC_PARAM_RESET, 1); + self->streamInfo.numLostAccessUnits = 0; + self->streamInfo.numBadBytes = 0; + self->streamInfo.numTotalBytes = 0; + } + + + ErrorStatus = CAacDecoder_DecodeFrame(self, + flags | (fTpConceal ? AACDEC_CONCEAL : 0), + pTimeData, + timeDataSize, + interleaved); + + if (!(flags & (AACDEC_CONCEAL|AACDEC_FLUSH))) { + TRANSPORTDEC_ERROR tpErr; + tpErr = transportDec_EndAccessUnit(self->hInput); + if (tpErr != TRANSPORTDEC_OK) { + self->frameOK = 0; + } + } + + /* If the current pTimeData does not contain a valid signal, there nothing else we can do, so bail. */ + if ( ! IS_OUTPUT_VALID(ErrorStatus) ) { + goto bail; + } + + { + /* Export data into streaminfo structure */ + self->streamInfo.sampleRate = self->streamInfo.aacSampleRate; + self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame; + self->streamInfo.numChannels = self->aacChannels; + } + + + + CAacDecoder_SyncQmfMode(self); + +/* sbr decoder */ + + if (ErrorStatus || (flags & AACDEC_CONCEAL) || self->pAacDecoderStaticChannelInfo[0]->concealmentInfo.concealState > ConcealState_FadeIn) + { + self->frameOK = 0; /* if an error has occured do concealment in the SBR decoder too */ + } + + if (self->sbrEnabled) + { + SBR_ERROR sbrError = SBRDEC_OK; + + /* set params */ + sbrDecoder_SetParam ( self->hSbrDecoder, + SBR_SYSTEM_BITSTREAM_DELAY, + self->sbrParams.bsDelay); + + if ( self->streamInfo.aot == AOT_ER_AAC_ELD ) { + /* Configure QMF */ + sbrDecoder_SetParam ( self->hSbrDecoder, + SBR_LD_QMF_TIME_ALIGN, + (self->flags & AC_LD_MPS) ? 1 : 0 ); + } + + + + + /* apply SBR processing */ + sbrError = sbrDecoder_Apply ( self->hSbrDecoder, + pTimeData, + &self->streamInfo.numChannels, + &self->streamInfo.sampleRate, + self->channelOutputMapping[self->aacChannels-1], + interleaved, + self->frameOK, + &self->psPossible); + + + if (sbrError == SBRDEC_OK) { + + /* Update data in streaminfo structure. Assume that the SBR upsampling factor is either 1 or 2 */ + self->flags |= AC_SBR_PRESENT; + if (self->streamInfo.aacSampleRate != self->streamInfo.sampleRate) { + if (self->streamInfo.frameSize == 768) { + self->streamInfo.frameSize = (self->streamInfo.aacSamplesPerFrame * 8) / 3; + } else { + self->streamInfo.frameSize = self->streamInfo.aacSamplesPerFrame << 1; + } + } + + if (self->psPossible) { + self->flags |= AC_PS_PRESENT; + self->channelType[0] = ACT_FRONT; + self->channelType[1] = ACT_FRONT; + self->channelIndices[0] = 0; + self->channelIndices[1] = 1; + } else { + self->flags &= ~AC_PS_PRESENT; + } + } + } + + + if ( flags & (AACDEC_INTR | AACDEC_CLRHIST) ) { + /* delete data from the past (e.g. mixdown coeficients) */ + pcmDmx_Reset( self->hPcmUtils, PCMDMX_RESET_BS_DATA ); + } + /* do PCM post processing */ + pcmDmx_ApplyFrame ( + self->hPcmUtils, + pTimeData, + self->streamInfo.frameSize, + &self->streamInfo.numChannels, + interleaved, + self->channelType, + self->channelIndices, + self->channelOutputMapping + ); + + + + /* Signal interruption to take effect in next frame. */ + if ( flags & AACDEC_FLUSH ) { + aacDecoder_SignalInterruption(self); + } + + /* Update externally visible copy of flags */ + self->streamInfo.flags = self->flags; + +bail: + + /* Update Statistics */ + aacDecoder_UpdateBitStreamCounters(&self->streamInfo, hBs, nBits, ErrorStatus); + + return ErrorStatus; +} + +LINKSPEC_CPP void aacDecoder_Close ( HANDLE_AACDECODER self ) +{ + if (self == NULL) + return; + + + + if (self->hPcmUtils != NULL) { + pcmDmx_Close( &self->hPcmUtils ); + } + + + + if (self->hSbrDecoder != NULL) { + sbrDecoder_Close(&self->hSbrDecoder); + } + + if (self->hInput != NULL) { + transportDec_Close(&self->hInput); + } + + CAacDecoder_Close(self); +} + + +LINKSPEC_CPP CStreamInfo* aacDecoder_GetStreamInfo ( HANDLE_AACDECODER self ) +{ + return CAacDecoder_GetStreamInfo(self); +} + +LINKSPEC_CPP INT aacDecoder_GetLibInfo ( LIB_INFO *info ) +{ + int i; + + if (info == NULL) { + return -1; + } + + sbrDecoder_GetLibInfo( info ); + transportDec_GetLibInfo( info ); + FDK_toolsGetLibInfo( info ); + pcmDmx_GetLibInfo( info ); + + /* search for next free tab */ + for (i = 0; i < FDK_MODULE_LAST; i++) { + if (info[i].module_id == FDK_NONE) break; + } + if (i == FDK_MODULE_LAST) { + return -1; + } + info += i; + + info->module_id = FDK_AACDEC; + /* build own library info */ + info->version = LIB_VERSION(AACDECODER_LIB_VL0, AACDECODER_LIB_VL1, AACDECODER_LIB_VL2); + LIB_VERSION_STRING(info); + info->build_date = AACDECODER_LIB_BUILD_DATE; + info->build_time = AACDECODER_LIB_BUILD_TIME; + info->title = AACDECODER_LIB_TITLE; + + /* Set flags */ + info->flags = 0 + | CAPF_AAC_LC + | CAPF_AAC_VCB11 + | CAPF_AAC_HCR + | CAPF_AAC_RVLC + | CAPF_ER_AAC_LD + | CAPF_ER_AAC_ELD + | CAPF_AAC_CONCEALMENT + | CAPF_AAC_DRC + + | CAPF_AAC_MPEG4 + + + | CAPF_AAC_1024 + | CAPF_AAC_960 + + | CAPF_AAC_512 + + | CAPF_AAC_480 + + ; + /* End of flags */ + + return 0; +} + + + + diff --git a/libAACdec/src/arm/block_arm.cpp b/libAACdec/src/arm/block_arm.cpp new file mode 100644 index 0000000..d9d0cf8 --- /dev/null +++ b/libAACdec/src/arm/block_arm.cpp @@ -0,0 +1,77 @@ +/******************************** Fraunhofer IIS *************************** + + (C) Copyright Fraunhofer IIS (2010) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Arthur Tritthart + Description: (ARM optimised) Scaling of spectral data + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + + +#define FUNCTION_CBlock_ScaleSpectralData_func1 + +/* Note: This loop is only separated for ARM in order to save cycles + by loop unrolling. The ARM core provides by default a 5-cycle + loop overhead per sample, that goes down to 1-cycle per sample + with an optimal 4x-loop construct (do - 4x - while). +*/ + +FDK_INLINE static void CBlock_ScaleSpectralData_func1( + FIXP_DBL *pSpectrum, + int max_band, + const SHORT * RESTRICT BandOffsets, + int SpecScale_window, + const SHORT * RESTRICT pSfbScale, + int window) +{ + int band_offset = 0; + for (int band=0; band < max_band; band++) + { + int runs = band_offset; + band_offset = BandOffsets[band+1]; + runs = band_offset - runs; /* is always a multiple of 4 */ + int scale = SpecScale_window-pSfbScale[window*16+band]; + if (scale) + { + do + { + FIXP_DBL tmp0, tmp1, tmp2, tmp3; + tmp0 = pSpectrum[0]; + tmp1 = pSpectrum[1]; + tmp2 = pSpectrum[2]; + tmp3 = pSpectrum[3]; + tmp0 >>= scale; + tmp1 >>= scale; + tmp2 >>= scale; + tmp3 >>= scale; + *pSpectrum++ = tmp0; + *pSpectrum++ = tmp1; + *pSpectrum++ = tmp2; + *pSpectrum++ = tmp3; + } while ((runs = runs-4) != 0); + } + else + { + pSpectrum+= runs; + } + } +} diff --git a/libAACdec/src/block.cpp b/libAACdec/src/block.cpp new file mode 100644 index 0000000..d17e9c4 --- /dev/null +++ b/libAACdec/src/block.cpp @@ -0,0 +1,703 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: long/short-block decoding + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "block.h" + +#include "aac_rom.h" +#include "FDK_bitstream.h" +#include "FDK_tools_rom.h" + + + + +#include "aacdec_hcr.h" +#include "rvlc.h" + + +#if defined(__arm__) +#include "arm/block_arm.cpp" +#endif + +/*! + \brief Read escape sequence of codeword + + The function reads the escape sequence from the bitstream, + if the absolute value of the quantized coefficient has the + value 16. + + \return quantized coefficient +*/ +LONG CBlock_GetEscape(HANDLE_FDK_BITSTREAM bs, /*!< pointer to bitstream */ + const LONG q) /*!< quantized coefficient */ +{ + LONG i, off, neg ; + + if (q < 0) + { + if (q != -16) return q; + neg = 1; + } + else + { + if (q != +16) return q; + neg = 0; + } + + for (i=4; ; i++) + { + if (FDKreadBits(bs,1) == 0) + break; + } + + if (i > 16) + { + if (i - 16 > CACHE_BITS) { /* cannot read more than "CACHE_BITS" bits at once in the function FDKreadBits() */ + return (MAX_QUANTIZED_VALUE + 1); /* returning invalid value that will be captured later */ + } + + off = FDKreadBits(bs,i-16) << 16; + off |= FDKreadBits(bs,16); + } + else + { + off = FDKreadBits(bs,i); + } + + i = off + (1 << i); + + if (neg) i = -i; + + return i; +} + +AAC_DECODER_ERROR CBlock_ReadScaleFactorData( + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + HANDLE_FDK_BITSTREAM bs, + UINT flags + ) +{ + int temp; + int band; + int group; + int position = 0; /* accu for intensity delta coding */ + int factor = pAacDecoderChannelInfo->pDynData->RawDataInfo.GlobalGain; /* accu for scale factor delta coding */ + UCHAR *pCodeBook = pAacDecoderChannelInfo->pDynData->aCodeBook; + SHORT *pScaleFactor = pAacDecoderChannelInfo->pDynData->aScaleFactor; + const CodeBookDescription *hcb =&AACcodeBookDescriptionTable[BOOKSCL]; + + int ScaleFactorBandsTransmitted = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); + for (group=0; group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++) + { + for (band=0; band < ScaleFactorBandsTransmitted; band++) + { + switch (pCodeBook[group*16+band]) { + + case ZERO_HCB: /* zero book */ + pScaleFactor[group*16+band] = 0; + break; + + default: /* decode scale factor */ + { + temp = CBlock_DecodeHuffmanWord(bs,hcb); + factor += temp - 60; /* MIDFAC 1.5 dB */ + } + pScaleFactor[group*16+band] = factor - 100; + break; + + case INTENSITY_HCB: /* intensity steering */ + case INTENSITY_HCB2: + temp = CBlock_DecodeHuffmanWord(bs,hcb); + position += temp - 60; + pScaleFactor[group*16+band] = position - 100; + break; + + case NOISE_HCB: /* PNS */ + if (flags & (AC_MPS_RES|AC_USAC|AC_RSVD50)) { + return AAC_DEC_PARSE_ERROR; + } + CPns_Read( &pAacDecoderChannelInfo->data.aac.PnsData, bs, hcb, pAacDecoderChannelInfo->pDynData->aScaleFactor, pAacDecoderChannelInfo->pDynData->RawDataInfo.GlobalGain, band, group); + break; + } + } + } + + return AAC_DEC_OK; +} + +void CBlock_ScaleSpectralData(CAacDecoderChannelInfo *pAacDecoderChannelInfo, SamplingRateInfo *pSamplingRateInfo) +{ + int band; + int window; + const SHORT * RESTRICT pSfbScale = pAacDecoderChannelInfo->pDynData->aSfbScale; + SHORT * RESTRICT pSpecScale = pAacDecoderChannelInfo->specScale; + int groupwin,group; + const SHORT * RESTRICT BandOffsets = GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo); + SPECTRAL_PTR RESTRICT pSpectralCoefficient = pAacDecoderChannelInfo->pSpectralCoefficient; + + + FDKmemclear(pSpecScale, 8*sizeof(SHORT)); + + int max_band = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); + for (window=0, group=0; group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++) + { + for (groupwin=0; groupwin < GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo,group); groupwin++, window++) + { + int SpecScale_window = pSpecScale[window]; + FIXP_DBL *pSpectrum = SPEC(pSpectralCoefficient, window, pAacDecoderChannelInfo->granuleLength); + + /* find scaling for current window */ + for (band=0; band < max_band; band++) + { + SpecScale_window = fMax(SpecScale_window, (int)pSfbScale[window*16+band]); + } + + if (pAacDecoderChannelInfo->pDynData->TnsData.Active) { + SpecScale_window += TNS_SCALE; + } + + /* store scaling of current window */ + pSpecScale[window] = SpecScale_window; + +#ifdef FUNCTION_CBlock_ScaleSpectralData_func1 + + CBlock_ScaleSpectralData_func1(pSpectrum, max_band, BandOffsets, SpecScale_window, pSfbScale, window); + +#else /* FUNCTION_CBlock_ScaleSpectralData_func1 */ + for (band=0; band < max_band; band++) + { + int scale = SpecScale_window - pSfbScale[window*16+band]; + if (scale) + { + /* following relation can be used for optimizations: (BandOffsets[i]%4) == 0 for all i */ + int max_index = BandOffsets[band+1]; + for (int index = BandOffsets[band]; index < max_index; index++) + { + pSpectrum[index] >>= scale; + } + } + } +#endif /* FUNCTION_CBlock_ScaleSpectralData_func1 */ + } + } + +} + +AAC_DECODER_ERROR CBlock_ReadSectionData(HANDLE_FDK_BITSTREAM bs, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + const SamplingRateInfo *pSamplingRateInfo, + const UINT flags) +{ + int top, band; + int sect_len, sect_len_incr; + int group; + UCHAR sect_cb; + UCHAR *pCodeBook = pAacDecoderChannelInfo->pDynData->aCodeBook; + /* HCR input (long) */ + SHORT *pNumLinesInSec = pAacDecoderChannelInfo->pDynData->specificTo.aac.aNumLineInSec4Hcr; + int numLinesInSecIdx = 0; + UCHAR *pHcrCodeBook = pAacDecoderChannelInfo->pDynData->specificTo.aac.aCodeBooks4Hcr; + const SHORT *BandOffsets = GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo); + pAacDecoderChannelInfo->pDynData->specificTo.aac.numberSection = 0; + AAC_DECODER_ERROR ErrorStatus = AAC_DEC_OK; + + FDKmemclear(pCodeBook, sizeof(UCHAR)*(8*16)); + + const int nbits = (IsLongBlock(&pAacDecoderChannelInfo->icsInfo) == 1) ? 5 : 3; + + int sect_esc_val = (1 << nbits) - 1 ; + + UCHAR ScaleFactorBandsTransmitted = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); + for (group=0; groupicsInfo); group++) + { + for (band=0; band < ScaleFactorBandsTransmitted; ) + { + sect_len = 0; + if ( flags & AC_ER_VCB11 ) { + sect_cb = (UCHAR) FDKreadBits(bs,5); + } + else + sect_cb = (UCHAR) FDKreadBits(bs,4); + + if ( ((flags & AC_ER_VCB11) == 0) || ( sect_cb < 11 ) || ((sect_cb > 11) && (sect_cb < 16)) ) { + sect_len_incr = FDKreadBits(bs, nbits); + while (sect_len_incr == sect_esc_val) + { + sect_len += sect_esc_val; + sect_len_incr = FDKreadBits(bs, nbits); + } + } + else { + sect_len_incr = 1; + } + + sect_len += sect_len_incr; + + + top = band + sect_len; + + if (flags & AC_ER_HCR) { + /* HCR input (long) -- collecting sideinfo (for HCR-_long_ only) */ + pNumLinesInSec[numLinesInSecIdx] = BandOffsets[top] - BandOffsets[band]; + numLinesInSecIdx++; + if (numLinesInSecIdx >= MAX_SFB_HCR) { + return AAC_DEC_PARSE_ERROR; + } + if ( + (sect_cb == BOOKSCL) ) + { + return AAC_DEC_INVALID_CODE_BOOK; + } else { + *pHcrCodeBook++ = sect_cb; + } + pAacDecoderChannelInfo->pDynData->specificTo.aac.numberSection++; + } + + /* Check spectral line limits */ + if (IsLongBlock( &(pAacDecoderChannelInfo->icsInfo) )) + { + if (top > 64) { + return AAC_DEC_DECODE_FRAME_ERROR; + } + } else { /* short block */ + if (top + group*16 > (8 * 16)) { + return AAC_DEC_DECODE_FRAME_ERROR; + } + } + + /* Check if decoded codebook index is feasible */ + if ( (sect_cb == BOOKSCL) + || ( (sect_cb == INTENSITY_HCB || sect_cb == INTENSITY_HCB2) && pAacDecoderChannelInfo->pDynData->RawDataInfo.CommonWindow == 0) + ) + { + return AAC_DEC_INVALID_CODE_BOOK; + } + + /* Store codebook index */ + for (; band < top; band++) + { + pCodeBook[group*16+band] = sect_cb; + } + } + } + + + return ErrorStatus; +} + +/* mso: provides a faster way to i-quantize a whole band in one go */ + +/** + * \brief inverse quantize one sfb. Each value of the sfb is processed according to the + * formula: spectrum[i] = Sign(spectrum[i]) * Matissa(spectrum[i])^(4/3) * 2^(lsb/4). + * \param spectrum pointer to first line of the sfb to be inverse quantized. + * \param noLines number of lines belonging to the sfb. + * \param lsb last 2 bits of the scale factor of the sfb. + * \param scale max allowed shift scale for the sfb. + */ +static +void InverseQuantizeBand( FIXP_DBL * RESTRICT spectrum, + INT noLines, + INT lsb, + INT scale ) +{ + const FIXP_DBL * RESTRICT InverseQuantTabler=(FIXP_DBL *)InverseQuantTable; + const FIXP_DBL * RESTRICT MantissaTabler=(FIXP_DBL *)MantissaTable[lsb]; + const SCHAR* RESTRICT ExponentTabler=(SCHAR*)ExponentTable[lsb]; + + FIXP_DBL *ptr = spectrum; + FIXP_DBL signedValue; + + FDK_ASSERT(noLines>2); + for (INT i=noLines; i--; ) + { + if ((signedValue = *ptr++) != FL2FXCONST_DBL(0)) + { + FIXP_DBL value = fAbs(signedValue); + UINT freeBits = CntLeadingZeros(value); + UINT exponent = 32 - freeBits; + + UINT x = (UINT) (LONG)value << (INT) freeBits; + x <<= 1; /* shift out sign bit to avoid masking later on */ + UINT tableIndex = x >> 24; + x = (x >> 20) & 0x0F; + + UINT r0=(UINT)(LONG)InverseQuantTabler[tableIndex+0]; + UINT r1=(UINT)(LONG)InverseQuantTabler[tableIndex+1]; + UINT temp= (r1 - r0)*x + (r0 << 4); + + value = fMultDiv2((FIXP_DBL)temp, MantissaTabler[exponent]); + + /* + 1 compensates fMultDiv2() */ + scaleValueInPlace(&value, scale + ExponentTabler[exponent] + 1); + + signedValue = (signedValue < (FIXP_DBL)0) ? -value : value; + ptr[-1] = signedValue; + } + } +} + +AAC_DECODER_ERROR CBlock_InverseQuantizeSpectralData(CAacDecoderChannelInfo *pAacDecoderChannelInfo, SamplingRateInfo *pSamplingRateInfo) +{ + int window, group, groupwin, band; + int ScaleFactorBandsTransmitted = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); + UCHAR *RESTRICT pCodeBook = pAacDecoderChannelInfo->pDynData->aCodeBook; + SHORT *RESTRICT pSfbScale = pAacDecoderChannelInfo->pDynData->aSfbScale; + SHORT *RESTRICT pScaleFactor = pAacDecoderChannelInfo->pDynData->aScaleFactor; + const SHORT *RESTRICT BandOffsets = GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo); + + FDKmemclear(pAacDecoderChannelInfo->pDynData->aSfbScale, (8*16)*sizeof(SHORT)); + + for (window=0, group=0; group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++) + { + for (groupwin=0; groupwin < GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo,group); groupwin++, window++) + { + /* inverse quantization */ + for (band=0; band < ScaleFactorBandsTransmitted; band++) + { + FIXP_DBL *pSpectralCoefficient = SPEC(pAacDecoderChannelInfo->pSpectralCoefficient, window, pAacDecoderChannelInfo->granuleLength) + BandOffsets[band]; + + int noLines = BandOffsets[band+1] - BandOffsets[band]; + int bnds = group*16+band; + int i; + + if ((pCodeBook[bnds] == ZERO_HCB) + || (pCodeBook[bnds] == INTENSITY_HCB) + || (pCodeBook[bnds] == INTENSITY_HCB2) + ) + continue; + + if (pCodeBook[bnds] == NOISE_HCB) + { + /* Leave headroom for PNS values. + 1 because ceil(log2(2^(0.25*3))) = 1, + worst case of additional headroom required because of the scalefactor. */ + pSfbScale[window*16+band] = (pScaleFactor [bnds] >> 2) + 1 ; + continue; + } + + /* Find max spectral line value of the current sfb */ + FIXP_DBL locMax = (FIXP_DBL)0; + + for (i = noLines; i-- ; ) { + /* Expensive memory access */ + locMax = fMax(fixp_abs(pSpectralCoefficient[i]), locMax); + } + + /* Cheap robustness improvement - Do not remove!!! */ + if (fixp_abs(locMax) > (FIXP_DBL)MAX_QUANTIZED_VALUE) { + return AAC_DEC_DECODE_FRAME_ERROR; + } + + /* + The inverse quantized spectral lines are defined by: + pSpectralCoefficient[i] = Sign(pSpectralCoefficient[i]) * 2^(0.25*pScaleFactor[bnds]) * pSpectralCoefficient[i]^(4/3) + This is equivalent to: + pSpectralCoefficient[i] = Sign(pSpectralCoefficient[i]) * (2^(pScaleFactor[bnds] % 4) * pSpectralCoefficient[i]^(4/3)) + pSpectralCoefficient_e[i] += pScaleFactor[bnds]/4 + */ + { + int msb = pScaleFactor [bnds] >> 2 ; + int lsb = pScaleFactor [bnds] & 0x03 ; + + int scale = GetScaleFromValue(locMax, lsb); + + pSfbScale[window*16+band] = msb - scale; + InverseQuantizeBand(pSpectralCoefficient, noLines, lsb, scale); + } + } + } + } + + + return AAC_DEC_OK; +} + + +AAC_DECODER_ERROR CBlock_ReadSpectralData(HANDLE_FDK_BITSTREAM bs, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + const SamplingRateInfo *pSamplingRateInfo, + const UINT flags) +{ + int i,index; + int window,group,groupwin,groupoffset,band; + UCHAR *RESTRICT pCodeBook = pAacDecoderChannelInfo->pDynData->aCodeBook; + const SHORT *RESTRICT BandOffsets = GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo); + + SPECTRAL_PTR pSpectralCoefficient = pAacDecoderChannelInfo->pSpectralCoefficient; + FIXP_DBL locMax; + + int ScaleFactorBandsTransmitted = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); + + FDK_ASSERT(BandOffsets != NULL); + + FDKmemclear(pSpectralCoefficient, sizeof(SPECTRUM)); + + if ( (flags & AC_ER_HCR) == 0 ) + { + groupoffset = 0; + + /* plain huffman decoder short */ + for (group=0; group < GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); group++) + { + for (band=0; band < ScaleFactorBandsTransmitted; band++) + { + int bnds = group*16+band; + UCHAR currentCB = pCodeBook[bnds]; + + /* patch to run plain-huffman-decoder with vcb11 input codebooks (LAV-checking might be possible below using the virtual cb and a LAV-table) */ + if ((currentCB >= 16) && (currentCB <= 31)) { + pCodeBook[bnds] = currentCB = 11; + } + if ( !((currentCB == ZERO_HCB) + || (currentCB == NOISE_HCB) + || (currentCB == INTENSITY_HCB) + || (currentCB == INTENSITY_HCB2)) ) + { + const CodeBookDescription *hcb = &AACcodeBookDescriptionTable[currentCB]; + int step = hcb->Dimension; + int offset = hcb->Offset; + int bits = hcb->numBits; + int mask = (1<icsInfo,group); groupwin++) + { + window = groupoffset + groupwin; + + FIXP_DBL *mdctSpectrum = SPEC(pSpectralCoefficient, window, pAacDecoderChannelInfo->granuleLength); + + locMax = (FIXP_DBL)0 ; + + for (index=BandOffsets[band]; index < BandOffsets[band+1]; index+=step) + { + int idx = CBlock_DecodeHuffmanWord(bs,hcb); + + for (i=0; i>= bits; + + if (offset == 0) { + if (tmp != FIXP_DBL(0)) + tmp = (FDKreadBits(bs,1))? -tmp : tmp; + } + mdctSpectrum[index+i] = tmp; + } + + if (currentCB == ESCBOOK) + { + mdctSpectrum[index+0] = (FIXP_DBL)CBlock_GetEscape(bs, (LONG)mdctSpectrum[index+0]); + mdctSpectrum[index+1] = (FIXP_DBL)CBlock_GetEscape(bs, (LONG)mdctSpectrum[index+1]); + + } + } + } + } + } + groupoffset += GetWindowGroupLength(&pAacDecoderChannelInfo->icsInfo,group); + } + /* plain huffman decoding (short) finished */ + } + /* HCR - Huffman Codeword Reordering short */ + else /* if ( flags & AC_ER_HCR ) */ + { + H_HCR_INFO hHcr = &pAacDecoderChannelInfo->pComData->overlay.aac.erHcrInfo; + int hcrStatus = 0; + int hcrConcealWholeFrame = 0; + + /* advanced Huffman decoding starts here (HCR decoding :) */ + if ( pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfReorderedSpectralData != 0 ) { + + /* HCR initialization short */ + hcrStatus = HcrInit(hHcr, pAacDecoderChannelInfo, pSamplingRateInfo, bs); + + if (hcrStatus != 0) { +#if HCR_ERROR_CONCEALMENT + hcrConcealWholeFrame = 1; + return AAC_DEC_DECODE_FRAME_ERROR; /* concealment is muting in the first step, therefore return now */ + // hcr decoding is not skipped because of returning above +#else + return AAC_DEC_DECODE_FRAME_ERROR; +#endif + } + + /* HCR decoding short */ + hcrStatus = HcrDecoder(hHcr, pAacDecoderChannelInfo, pSamplingRateInfo, bs); + + +#if HCR_ERROR_CONCEALMENT + HcrMuteErroneousLines(hHcr); +#else + return AAC_DEC_DECODE_FRAME_ERROR; +#endif /* HCR_ERROR_CONCEALMENT */ + + FDKpushFor (bs, pAacDecoderChannelInfo->pDynData->specificTo.aac.lenOfReorderedSpectralData); + } + } + /* HCR - Huffman Codeword Reordering short finished */ + + + + if ( IsLongBlock(&pAacDecoderChannelInfo->icsInfo) && !(flags & (AC_ELD|AC_SCALABLE)) ) + { + /* apply pulse data */ + CPulseData_Apply(&pAacDecoderChannelInfo->pDynData->specificTo.aac.PulseData, + GetScaleFactorBandOffsets(&pAacDecoderChannelInfo->icsInfo, pSamplingRateInfo), + SPEC_LONG(pSpectralCoefficient)); + } + + + return AAC_DEC_OK; +} + + + +void ApplyTools ( CAacDecoderChannelInfo *pAacDecoderChannelInfo[], + const SamplingRateInfo *pSamplingRateInfo, + const UINT flags, + const int channel ) +{ + + if ( !(flags & (AC_USAC|AC_RSVD50|AC_MPS_RES)) ) { + CPns_Apply( + &pAacDecoderChannelInfo[channel]->data.aac.PnsData, + &pAacDecoderChannelInfo[channel]->icsInfo, + pAacDecoderChannelInfo[channel]->pSpectralCoefficient, + pAacDecoderChannelInfo[channel]->specScale, + pAacDecoderChannelInfo[channel]->pDynData->aScaleFactor, + pSamplingRateInfo, + pAacDecoderChannelInfo[channel]->granuleLength, + channel + ); + } + + CTns_Apply ( + &pAacDecoderChannelInfo[channel]->pDynData->TnsData, + &pAacDecoderChannelInfo[channel]->icsInfo, + pAacDecoderChannelInfo[channel]->pSpectralCoefficient, + pSamplingRateInfo, + pAacDecoderChannelInfo[channel]->granuleLength + ); +} + +static +int getWindow2Nr(int length, int shape) +{ + int nr = 0; + + if (shape == 2) { + /* Low Overlap, 3/4 zeroed */ + nr = (length * 3)>>2; + } + + return nr; +} + +void CBlock_FrequencyToTime(CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + INT_PCM outSamples[], + const SHORT frameLen, + const int stride, + const int frameOk, + FIXP_DBL *pWorkBuffer1 ) +{ + int fr, fl, tl, nSamples, nSpec; + + /* Determine left slope length (fl), right slope length (fr) and transform length (tl). + USAC: The slope length may mismatch with the previous frame in case of LPD / FD + transitions. The adjustment is handled by the imdct implementation. + */ + tl = frameLen; + nSpec = 1; + + switch( pAacDecoderChannelInfo->icsInfo.WindowSequence ) { + default: + case OnlyLongSequence: + fl = frameLen; + fr = frameLen - getWindow2Nr(frameLen, GetWindowShape(&pAacDecoderChannelInfo->icsInfo)); + break; + case LongStopSequence: + fl = frameLen >> 3; + fr = frameLen; + break; + case LongStartSequence: /* or StopStartSequence */ + fl = frameLen; + fr = frameLen >> 3; + break; + case EightShortSequence: + fl = fr = frameLen >> 3; + tl >>= 3; + nSpec = 8; + break; + } + + { + int i; + + { + FIXP_DBL *tmp = pAacDecoderChannelInfo->pComData->workBufferCore1->mdctOutTemp; + + nSamples = imdct_block( + &pAacDecoderStaticChannelInfo->IMdct, + tmp, + SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient), + pAacDecoderChannelInfo->specScale, + nSpec, + frameLen, + tl, + FDKgetWindowSlope(fl, GetWindowShape(&pAacDecoderChannelInfo->icsInfo)), + fl, + FDKgetWindowSlope(fr, GetWindowShape(&pAacDecoderChannelInfo->icsInfo)), + fr, + (FIXP_DBL)0 ); + + for (i=0; ipSpectralCoefficient), + pAacDecoderChannelInfo->specScale[0], + outSamples, + pAacDecoderStaticChannelInfo->pOverlapBuffer, + stride, + frameLen + ); +} diff --git a/libAACdec/src/block.h b/libAACdec/src/block.h new file mode 100644 index 0000000..a4ba085 --- /dev/null +++ b/libAACdec/src/block.h @@ -0,0 +1,260 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: long/short-block decoding + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef BLOCK_H +#define BLOCK_H + +#include "common_fix.h" + +#include "channelinfo.h" +#include "FDK_bitstream.h" + +/* PNS (of block) */ +void CPns_Read (CPnsData *pPnsData, + HANDLE_FDK_BITSTREAM bs, + const CodeBookDescription *hcb, + SHORT *pScaleFactor, + UCHAR global_gain, + int band, + int group); + + +void CPns_Apply (const CPnsData *pPnsData, + const CIcsInfo *pIcsInfo, + SPECTRAL_PTR pSpectrum, + const SHORT *pSpecScale, + const SHORT *pScaleFactor, + const SamplingRateInfo *pSamplingRateInfo, + const INT granuleLength, + const int channel); + + + +/* TNS (of block) */ +/*! + \brief Read tns data-present flag from bitstream + + The function reads the data-present flag for tns from + the bitstream. + + \return none +*/ +void CTns_ReadDataPresentFlag(HANDLE_FDK_BITSTREAM bs, + CTnsData *pTnsData); + +void CTns_ReadDataPresentUsac( + HANDLE_FDK_BITSTREAM hBs, + CTnsData *pTnsData0, + CTnsData *pTnsData1, + const CIcsInfo *pIcsInfo, + const UINT flags, + const int fCommonWindow + ); + +AAC_DECODER_ERROR CTns_Read(HANDLE_FDK_BITSTREAM bs, + CTnsData *pTnsData, + const CIcsInfo *pIcsInfo, + const UINT flags); + +void CTns_Apply ( CTnsData *RESTRICT pTnsData, /*!< pointer to aac decoder info */ + const CIcsInfo *pIcsInfo, + SPECTRAL_PTR pSpectralCoefficient, + const SamplingRateInfo *pSamplingRateInfo, + const INT granuleLength); + +/* Block */ + +LONG CBlock_GetEscape(HANDLE_FDK_BITSTREAM bs, const LONG q); + +/** + * \brief Read scale factor data. See chapter 4.6.2.3.2 of ISO/IEC 14496-3. + * The SF_OFFSET = 100 value referenced in chapter 4.6.2.3.3 is already substracted + * from the scale factor values. Also includes PNS data reading. + * \param bs bit stream handle data source + * \param pAacDecoderChannelInfo channel context info were decoded data is stored into. + * \param flags the decoder flags. + */ +AAC_DECODER_ERROR CBlock_ReadScaleFactorData( + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + HANDLE_FDK_BITSTREAM bs, + const UINT flags + ); + +/** + * \brief Read Huffman encoded spectral data. + * \param pAacDecoderChannelInfo channel context info. + * \param pSamplingRateInfo sampling rate info (sfb offsets). + * \param flags syntax flags. + */ +AAC_DECODER_ERROR CBlock_ReadSpectralData(HANDLE_FDK_BITSTREAM bs, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + const SamplingRateInfo *pSamplingRateInfo, + const UINT flags); + + +AAC_DECODER_ERROR CBlock_ReadSectionData(HANDLE_FDK_BITSTREAM bs, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + const SamplingRateInfo *pSamplingRateInfo, + const UINT flags); + +/** + * \brief find a common exponent (shift factor) for all sfb in each Spectral window, and store them into + * CAacDecoderChannelInfo::specScale. + * \param pAacDecoderChannelInfo channel context info. + * \param pSamplingRateInfo sampling rate info (sfb offsets). + */ +void CBlock_ScaleSpectralData(CAacDecoderChannelInfo *pAacDecoderChannelInfo, SamplingRateInfo *pSamplingRateInfo); + +/** + * \brief Apply TNS and PNS tools. + */ +void ApplyTools ( CAacDecoderChannelInfo *pAacDecoderChannelInfo[], + const SamplingRateInfo *pSamplingRateInfo, + const UINT flags, + const int channel ); + +/** + * \brief Transform MDCT spectral data into time domain + */ +void CBlock_FrequencyToTime(CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + INT_PCM outSamples[], + const SHORT frameLen, + const int stride, + const int frameOk, + FIXP_DBL *pWorkBuffer1); + +/** + * \brief Transform double lapped MDCT (AAC-ELD) spectral data into time domain. + */ +void CBlock_FrequencyToTimeLowDelay(CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + INT_PCM outSamples[], + const short frameLen, + const char stride); + +AAC_DECODER_ERROR CBlock_InverseQuantizeSpectralData(CAacDecoderChannelInfo *pAacDecoderChannelInfo, SamplingRateInfo *pSamplingRateInfo); + +/** + * \brief Calculate 2^(lsb/4) * value^(4/3) + * \param pValue pointer to quantized value. The inverse quantized result is stored back here. + * \param lsb 2 LSBs of the scale factor (scaleFactor % 4) applied as power 2 factor to the + * resulting inverse quantized value. + * \return the exponent of the result (mantissa) stored into *pValue. + */ +FDK_INLINE +int EvaluatePower43 ( FIXP_DBL *pValue, + UINT lsb ) +{ + FIXP_DBL value; + UINT freeBits; + UINT exponent; + + value = *pValue; + freeBits = fNormz (value) ; + exponent = DFRACT_BITS - freeBits ; + FDK_ASSERT (exponent < 14); + + UINT x = (((int)value << freeBits) >> 19) ; + UINT tableIndex = (x & 0x0FFF) >> 4 ; + FIXP_DBL invQVal ; + + x = x & 0x0F; + + UINT r0=(LONG)InverseQuantTable [tableIndex+0]; + UINT r1=(LONG)InverseQuantTable [tableIndex+1]; + USHORT nx=16-x; + UINT temp=(r0)*nx+(r1)*x; + invQVal = (FIXP_DBL)temp; + + FDK_ASSERT(lsb < 4); + *pValue = fMultDiv2 (invQVal, MantissaTable [lsb][exponent]) ; + + /* + 1 compensates fMultDiv2(). */ + return ExponentTable [lsb][exponent] + 1; +} + +/** + * \brief determine the required shift scale for the given quantized value and scale (factor % 4) value. + */ +FDK_INLINE int GetScaleFromValue (FIXP_DBL value, unsigned int lsb) +{ + if (value!=(FIXP_DBL)0) + { + int scale = EvaluatePower43 (&value, lsb) ; + return CntLeadingZeros (value) - scale - 2 ; + } + else + return 0; /* Return zero, because its useless to scale a zero value, saves workload and avoids scaling overshifts. */ +} + + +//#ifdef AACDEC_HUFFMANDECODER_ENABLE + +/*! + \brief Read huffman codeword + + The function reads the huffman codeword from the bitstream and + returns the index value. + + \return index value +*/ +inline int CBlock_DecodeHuffmanWord( HANDLE_FDK_BITSTREAM bs, /*!< pointer to bitstream */ + const CodeBookDescription *hcb ) /*!< pointer to codebook description */ +{ + UINT val; + UINT index = 0; + const USHORT (*CodeBook) [HuffmanEntries] = hcb->CodeBook; + + while (1) + { + val = CodeBook[index][FDKreadBits(bs,HuffmanBits)]; /* Expensive memory access */ + + if ((val & 1) == 0) + { + index = val>>2; + continue; + } + else + { + if (val & 2) + { + FDKpushBackCache(bs,1); + } + + val >>= 2; + break; + } + } + + return val; +} + +//#endif /* AACDEC_HUFFMANDECODER_ENABLE */ + +#endif /* #ifndef BLOCK_H */ diff --git a/libAACdec/src/channel.cpp b/libAACdec/src/channel.cpp new file mode 100644 index 0000000..3e1ffb6 --- /dev/null +++ b/libAACdec/src/channel.cpp @@ -0,0 +1,389 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "channel.h" +#include "aacdecoder.h" +#include "block.h" +#include "aacdec_tns.h" +#include "FDK_bitstream.h" +#include "FDK_tools_rom.h" + +#include "conceal.h" + +#include "rvlc.h" + +#include "aacdec_hcr.h" + + +static +void MapMidSideMaskToPnsCorrelation (CAacDecoderChannelInfo *pAacDecoderChannelInfo[2]) +{ + int group; + + for (group = 0 ; group < pAacDecoderChannelInfo[L]->icsInfo.WindowGroups; group++) { + UCHAR groupMask = 1 << group; + + for (UCHAR band = 0 ; band < pAacDecoderChannelInfo[L]->icsInfo.MaxSfBands; band++) { + if (pAacDecoderChannelInfo[L]->pComData->jointStereoData.MsUsed[band] & groupMask) { /* channels are correlated */ + CPns_SetCorrelation(&pAacDecoderChannelInfo[L]->data.aac.PnsData, group, band, 0); + + if (CPns_IsPnsUsed(&pAacDecoderChannelInfo[L]->data.aac.PnsData, group, band) && + CPns_IsPnsUsed(&pAacDecoderChannelInfo[R]->data.aac.PnsData, group, band)) + pAacDecoderChannelInfo[L]->pComData->jointStereoData.MsUsed[band] ^= groupMask; /* clear the groupMask-bit */ + } + } + } +} + +/*! + \brief Decode channel pair element + + The function decodes a channel pair element. + + \return none +*/ +void CChannelElement_Decode( CAacDecoderChannelInfo *pAacDecoderChannelInfo[2], /*!< pointer to aac decoder channel info */ + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[2], + SamplingRateInfo *pSamplingRateInfo, + UINT flags, + int el_channels) +{ + int ch, maybe_jstereo = 0; + + maybe_jstereo = (el_channels > 1); + + for (ch = 0; ch < el_channels; ch++) { + if ( pAacDecoderChannelInfo[ch]->renderMode == AACDEC_RENDER_IMDCT + || pAacDecoderChannelInfo[ch]->renderMode == AACDEC_RENDER_ELDFB ) + { + CBlock_InverseQuantizeSpectralData(pAacDecoderChannelInfo[ch], pSamplingRateInfo); + } + } + + + + if (maybe_jstereo) { + /* apply ms */ + if (pAacDecoderChannelInfo[L]->pDynData->RawDataInfo.CommonWindow) { + int maxSfBandsL = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo[L]->icsInfo); + int maxSfBandsR = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo[R]->icsInfo); + if (pAacDecoderChannelInfo[L]->data.aac.PnsData.PnsActive || pAacDecoderChannelInfo[R]->data.aac.PnsData.PnsActive) { + MapMidSideMaskToPnsCorrelation(pAacDecoderChannelInfo); + } + + CJointStereo_ApplyMS(pAacDecoderChannelInfo, + GetScaleFactorBandOffsets(&pAacDecoderChannelInfo[L]->icsInfo, pSamplingRateInfo), + GetWindowGroupLengthTable(&pAacDecoderChannelInfo[L]->icsInfo), + GetWindowGroups(&pAacDecoderChannelInfo[L]->icsInfo), + maxSfBandsL, + maxSfBandsR); + } + + /* apply intensity stereo */ /* modifies pAacDecoderChannelInfo[]->aSpecSfb */ + CJointStereo_ApplyIS(pAacDecoderChannelInfo, + GetScaleFactorBandOffsets(&pAacDecoderChannelInfo[L]->icsInfo, pSamplingRateInfo), + GetWindowGroupLengthTable(&pAacDecoderChannelInfo[L]->icsInfo), + GetWindowGroups(&pAacDecoderChannelInfo[L]->icsInfo), + GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo[L]->icsInfo), + pAacDecoderChannelInfo[L]->pDynData->RawDataInfo.CommonWindow ? 1 : 0); + + } + + for (ch = 0; ch < el_channels; ch++) + { + { + /* write pAacDecoderChannelInfo[ch]->specScale */ + CBlock_ScaleSpectralData(pAacDecoderChannelInfo[ch], pSamplingRateInfo); + + ApplyTools (pAacDecoderChannelInfo, pSamplingRateInfo, flags, ch); + } + + } + + CRvlc_ElementCheck( + pAacDecoderChannelInfo, + pAacDecoderStaticChannelInfo, + flags, + el_channels + ); +} + +void CChannel_CodebookTableInit(CAacDecoderChannelInfo *pAacDecoderChannelInfo) +{ + int b, w, maxBands, maxWindows; + int maxSfb = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); + UCHAR *pCodeBook = pAacDecoderChannelInfo->pDynData->aCodeBook; + + if ( IsLongBlock(&pAacDecoderChannelInfo->icsInfo) ) { + maxBands = 64; + maxWindows = 1; + } else { + maxBands = 16; + maxWindows = 8; + } + + for (w = 0; wpDynData->TnsData); + if (numberOfChannels == 2) { + CTns_Reset(&pAacDecoderChannelInfo[1]->pDynData->TnsData); + } + + if (flags & (AC_ELD|AC_SCALABLE)) { + pAacDecoderChannelInfo[0]->pDynData->RawDataInfo.CommonWindow = 1; + if (numberOfChannels == 2) { + pAacDecoderChannelInfo[1]->pDynData->RawDataInfo.CommonWindow = pAacDecoderChannelInfo[0]->pDynData->RawDataInfo.CommonWindow; + } + if (numberOfChannels == 2) { + pAacDecoderChannelInfo[1]->pDynData->RawDataInfo.CommonWindow = pAacDecoderChannelInfo[0]->pDynData->RawDataInfo.CommonWindow; + } + } + + /* Iterate through sequence table */ + i = 0; + ch = 0; + decision_bit = 0; + do { + switch (list->id[i]) { + case element_instance_tag: + pAacDecoderChannelInfo[0]->ElementInstanceTag = FDKreadBits(hBs, 4); + if (numberOfChannels == 2) { + pAacDecoderChannelInfo[1]->ElementInstanceTag = pAacDecoderChannelInfo[0]->ElementInstanceTag; + } + break; + case common_window: + decision_bit = pAacDecoderChannelInfo[ch]->pDynData->RawDataInfo.CommonWindow = FDKreadBits(hBs, 1); + if (numberOfChannels == 2) { + pAacDecoderChannelInfo[1]->pDynData->RawDataInfo.CommonWindow = pAacDecoderChannelInfo[0]->pDynData->RawDataInfo.CommonWindow; + } + break; + case ics_info: + /* Read individual channel info */ + error = IcsRead( hBs, + &pAacDecoderChannelInfo[ch]->icsInfo, + pSamplingRateInfo, + flags ); + + if (numberOfChannels == 2 && pAacDecoderChannelInfo[0]->pDynData->RawDataInfo.CommonWindow) { + pAacDecoderChannelInfo[1]->icsInfo = pAacDecoderChannelInfo[0]->icsInfo; + } + break; + + + case ltp_data_present: + if (FDKreadBits(hBs, 1) != 0) { + error = AAC_DEC_UNSUPPORTED_PREDICTION; + } + break; + + case ms: + if ( CJointStereo_Read( + hBs, + &pAacDecoderChannelInfo[0]->pComData->jointStereoData, + GetWindowGroups(&pAacDecoderChannelInfo[0]->icsInfo), + GetScaleMaxFactorBandsTransmitted(&pAacDecoderChannelInfo[0]->icsInfo, + &pAacDecoderChannelInfo[1]->icsInfo), + flags) ) + { + error = AAC_DEC_PARSE_ERROR; + } + break; + + case global_gain: + pAacDecoderChannelInfo[ch]->pDynData->RawDataInfo.GlobalGain = (UCHAR) FDKreadBits(hBs,8); + break; + + case section_data: + error = CBlock_ReadSectionData( hBs, + pAacDecoderChannelInfo[ch], + pSamplingRateInfo, + flags ); + break; + + + case scale_factor_data: + if (flags & AC_ER_RVLC) { + /* read RVLC data from bitstream (error sens. cat. 1) */ + CRvlc_Read(pAacDecoderChannelInfo[ch], hBs); + } + else + { + error = CBlock_ReadScaleFactorData(pAacDecoderChannelInfo[ch], hBs, flags); + } + break; + + case pulse: + if ( CPulseData_Read( hBs, + &pAacDecoderChannelInfo[ch]->pDynData->specificTo.aac.PulseData, + pSamplingRateInfo->ScaleFactorBands_Long, /* pulse data is only allowed to be present in long blocks! */ + (void*)&pAacDecoderChannelInfo[ch]->icsInfo, + frame_length + ) != 0 ) + { + error = AAC_DEC_DECODE_FRAME_ERROR; + } + break; + case tns_data_present: + CTns_ReadDataPresentFlag(hBs, &pAacDecoderChannelInfo[ch]->pDynData->TnsData); + break; + case tns_data: + /* tns_data_present is checked inside CTns_Read(). */ + error = CTns_Read(hBs, &pAacDecoderChannelInfo[ch]->pDynData->TnsData, &pAacDecoderChannelInfo[ch]->icsInfo, flags); + break; + + case gain_control_data: + break; + + case gain_control_data_present: + if (FDKreadBits(hBs, 1)) { + error = AAC_DEC_UNSUPPORTED_GAIN_CONTROL_DATA; + } + break; + + case esc2_rvlc: + if (flags & AC_ER_RVLC) { + CRvlc_Decode( + pAacDecoderChannelInfo[ch], + pAacDecoderStaticChannelInfo[ch], + hBs + ); + } + break; + + case esc1_hcr: + if (flags & AC_ER_HCR) { + CHcr_Read(hBs, pAacDecoderChannelInfo[ch] ); + } + break; + + case spectral_data: + error = CBlock_ReadSpectralData( hBs, + pAacDecoderChannelInfo[ch], + pSamplingRateInfo, + flags ); + if (flags & AC_ELD) { + pAacDecoderChannelInfo[ch]->renderMode = AACDEC_RENDER_ELDFB; + } else { + pAacDecoderChannelInfo[ch]->renderMode = AACDEC_RENDER_IMDCT; + } + break; + + + /* CRC handling */ + case adtscrc_start_reg1: + if (pTpDec != NULL) { + crcReg1 = transportDec_CrcStartReg(pTpDec, 192); + } + break; + case adtscrc_start_reg2: + if (pTpDec != NULL) { + crcReg2 = transportDec_CrcStartReg(pTpDec, 128); + } + break; + case adtscrc_end_reg1: + case drmcrc_end_reg: + if (pTpDec != NULL) { + transportDec_CrcEndReg(pTpDec, crcReg1); + } + break; + case adtscrc_end_reg2: + if (pTpDec != NULL) { + transportDec_CrcEndReg(pTpDec, crcReg2); + } + break; + case drmcrc_start_reg: + if (pTpDec != NULL) { + crcReg1 = transportDec_CrcStartReg(pTpDec, 0); + } + break; + + /* Non data cases */ + case next_channel: + ch = (ch + 1) % numberOfChannels; + break; + case link_sequence: + list = list->next[decision_bit]; + i=-1; + break; + + default: + error = AAC_DEC_UNSUPPORTED_FORMAT; + break; + } + + if (error != AAC_DEC_OK) { + goto bail; + } + + i++; + + } while (list->id[i] != end_of_sequence); + +bail: + return error; +} diff --git a/libAACdec/src/channel.h b/libAACdec/src/channel.h new file mode 100644 index 0000000..6c5441f --- /dev/null +++ b/libAACdec/src/channel.h @@ -0,0 +1,86 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef CHANNEL_H +#define CHANNEL_H + +#include "common_fix.h" + +#include "FDK_bitstream.h" +#include "channelinfo.h" +#include "tpdec_lib.h" + +/** + * \brief Init codeBook SFB indices (section data) with HCB_ESC. Useful for bitstreams + * which do not have any section data, but still SFB's (scale factor bands). This has + * the effect that upto the amount of transmitted SFB are treated as non-zero. + * \param pAacDecoderChannelInfo channel info structure containing a valid icsInfo struct. + */ +void CChannel_CodebookTableInit(CAacDecoderChannelInfo *pAacDecoderChannelInfo); + +/** + * \brief decode a channel element. To be called after CChannelElement_Read() + * \param pAacDecoderChannelInfo pointer to channel data struct. Depending on el_channels either one or two. + * \param pSamplingRateInfo pointer to sample rate information structure + * \param el_channels amount of channels of the element to be decoded. + * \param output pointer to time domain output buffer (ACELP) + * \param stride factor for accessing output + */ +void CChannelElement_Decode ( CAacDecoderChannelInfo *pAacDecoderChannelInfo[2], + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[2], + SamplingRateInfo *pSamplingRateInfo, + UINT flags, + int el_channels ); + + +/** + * \brief Read channel element of given type from bitstream. + * \param hBs bitstream handle to access bitstream data. + * \param pAacDecoderChannelInfo pointer array to store channel information. + * \param aot Audio Object Type + * \param pSamplingRateInfo sampling rate info table. + * \param flags parser guidance flags + * \param numberOfChannels amoun of channels contained in the object to be parsed. + * \param epConfig the current epConfig value obtained from the Audio Specific Config. + * \param pTp transport decoder handle required for ADTS CRC checking. + * ... + * \return an AAC_DECODER_ERROR error code. + */ +AAC_DECODER_ERROR CChannelElement_Read(HANDLE_FDK_BITSTREAM hBs, + CAacDecoderChannelInfo *pAacDecoderChannelInfo[], + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[], + const AUDIO_OBJECT_TYPE aot, + const SamplingRateInfo *pSamplingRateInfo, + const UINT flags, + const UINT frame_length, + const UCHAR numberOfChannels, + const SCHAR epConfig, + HANDLE_TRANSPORTDEC pTpDec + ); + +#endif /* #ifndef CHANNEL_H */ diff --git a/libAACdec/src/channelinfo.cpp b/libAACdec/src/channelinfo.cpp new file mode 100644 index 0000000..5c113aa --- /dev/null +++ b/libAACdec/src/channelinfo.cpp @@ -0,0 +1,214 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: individual channel stream info + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "channelinfo.h" +#include "aac_rom.h" +#include "aac_ram.h" +#include "FDK_bitstream.h" + + +AAC_DECODER_ERROR IcsReadMaxSfb ( + HANDLE_FDK_BITSTREAM bs, + CIcsInfo *pIcsInfo, + const SamplingRateInfo *pSamplingRateInfo + ) +{ + AAC_DECODER_ERROR ErrorStatus = AAC_DEC_OK; + int nbits; + + if (IsLongBlock(pIcsInfo)) { + nbits = 6; + pIcsInfo->TotalSfBands = pSamplingRateInfo->NumberOfScaleFactorBands_Long; + } else { + nbits = 4; + pIcsInfo->TotalSfBands = pSamplingRateInfo->NumberOfScaleFactorBands_Short; + } + pIcsInfo->MaxSfBands = (UCHAR) FDKreadBits(bs, nbits); + + if (pIcsInfo->MaxSfBands > pIcsInfo->TotalSfBands){ + ErrorStatus = AAC_DEC_PARSE_ERROR; + } + + return ErrorStatus; +} + + + +AAC_DECODER_ERROR IcsRead(HANDLE_FDK_BITSTREAM bs, + CIcsInfo *pIcsInfo, + const SamplingRateInfo* pSamplingRateInfo, + const UINT flags) +{ + AAC_DECODER_ERROR ErrorStatus = AAC_DEC_OK; + + pIcsInfo->Valid = 0; + + if (flags & AC_ELD){ + pIcsInfo->WindowSequence = OnlyLongSequence; + pIcsInfo->WindowShape = 0; + } + else { + if ( !(flags & (AC_USAC|AC_RSVD50)) ) { + FDKreadBits(bs,1); + } + pIcsInfo->WindowSequence = (UCHAR) FDKreadBits(bs,2); + pIcsInfo->WindowShape = (UCHAR) FDKreadBits(bs,1); + if (flags & AC_LD) { + if (pIcsInfo->WindowShape) { + pIcsInfo->WindowShape = 2; /* select low overlap instead of KBD */ + } + } + } + + /* Sanity check */ + if ( (flags & (AC_ELD|AC_LD)) && pIcsInfo->WindowSequence != OnlyLongSequence) { + pIcsInfo->WindowSequence = OnlyLongSequence; + ErrorStatus = AAC_DEC_PARSE_ERROR; + goto bail; + } + + ErrorStatus = IcsReadMaxSfb(bs, pIcsInfo, pSamplingRateInfo); + if (ErrorStatus != AAC_DEC_OK) { + goto bail; + } + + if (IsLongBlock(pIcsInfo)) + { + if ( !(flags & (AC_ELD|AC_SCALABLE|AC_BSAC|AC_USAC|AC_RSVD50)) ) /* If not ELD nor Scalable nor BSAC nor USAC syntax then ... */ + { + if ((UCHAR)FDKreadBits(bs,1) != 0 ) /* UCHAR PredictorDataPresent */ + { + ErrorStatus = AAC_DEC_UNSUPPORTED_PREDICTION; + goto bail; + } + } + + pIcsInfo->WindowGroups = 1; + pIcsInfo->WindowGroupLength[0] = 1; + } + else + { + INT i; + UINT mask; + + pIcsInfo->ScaleFactorGrouping = (UCHAR) FDKreadBits(bs,7); + + pIcsInfo->WindowGroups = 0 ; + + for (i=0; i < (8-1); i++) + { + mask = 1 << (6 - i); + pIcsInfo->WindowGroupLength[i] = 1; + + if (pIcsInfo->ScaleFactorGrouping & mask) + { + pIcsInfo->WindowGroupLength[pIcsInfo->WindowGroups]++; + } + else + { + pIcsInfo->WindowGroups++; + } + } + + /* loop runs to i < 7 only */ + pIcsInfo->WindowGroupLength[8-1] = 1; + pIcsInfo->WindowGroups++; + } + + +bail: + if (ErrorStatus == AAC_DEC_OK) + pIcsInfo->Valid = 1; + + return ErrorStatus; +} + + +/* + interleave codebooks the following way + + 9 (84w) | 1 (51w) + 10 (82w) | 2 (39w) + SCL (65w) | 4 (38w) + 3 (39w) | 5 (41w) + | 6 (40w) + | 7 (31w) + | 8 (31w) + (270w) (271w) +*/ + + +/* + Table entries are sorted as following: + | num_swb_long_window | sfbands_long | num_swb_short_window | sfbands_short | +*/ +AAC_DECODER_ERROR getSamplingRateInfo( + SamplingRateInfo *t, + UINT samplesPerFrame, + UINT samplingRateIndex, + UINT samplingRate + ) +{ + int index = 0; + + + t->samplingRateIndex = samplingRateIndex; + t->samplingRate = samplingRate; + + switch (samplesPerFrame) { + case 1024: + index = 0; + break; + case 960: + index = 1; + break; + case 512: + index = 3; + break; + case 480: + index = 4; + break; + + default: + return AAC_DEC_UNSUPPORTED_FORMAT; + } + + t->ScaleFactorBands_Long = sfbOffsetTables[index][samplingRateIndex].sfbOffsetLong; + t->ScaleFactorBands_Short = sfbOffsetTables[index][samplingRateIndex].sfbOffsetShort; + t->NumberOfScaleFactorBands_Long = sfbOffsetTables[index][samplingRateIndex].numberOfSfbLong; + t->NumberOfScaleFactorBands_Short = sfbOffsetTables[index][samplingRateIndex].numberOfSfbShort; + + if (t->ScaleFactorBands_Long == NULL || t->NumberOfScaleFactorBands_Long == 0) { + return AAC_DEC_UNSUPPORTED_FORMAT; + } + + FDK_ASSERT(t->ScaleFactorBands_Long[t->NumberOfScaleFactorBands_Long] == samplesPerFrame); + FDK_ASSERT(t->ScaleFactorBands_Short == NULL || t->ScaleFactorBands_Short[t->NumberOfScaleFactorBands_Short]*8 == samplesPerFrame); + + return AAC_DEC_OK; +} diff --git a/libAACdec/src/channelinfo.h b/libAACdec/src/channelinfo.h new file mode 100644 index 0000000..f74583d --- /dev/null +++ b/libAACdec/src/channelinfo.h @@ -0,0 +1,388 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: individual channel stream info + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef CHANNELINFO_H +#define CHANNELINFO_H + +#include "common_fix.h" + +#include "aac_rom.h" +#include "aacdecoder_lib.h" +#include "FDK_bitstream.h" +#include "overlapadd.h" + +#include "mdct.h" +#include "stereo.h" +#include "pulsedata.h" +#include "aacdec_tns.h" + +#include "aacdec_pns.h" + +#include "aacdec_hcr_types.h" +#include "rvlc_info.h" + + +#include "conceal_types.h" + + #include "aacdec_drc_types.h" + +/* Output rendering mode */ +typedef enum { + AACDEC_RENDER_INVALID = 0, + AACDEC_RENDER_IMDCT, + AACDEC_RENDER_ELDFB, + AACDEC_RENDER_LPD, + AACDEC_RENDER_INTIMDCT +} AACDEC_RENDER_MODE; + +enum { + MAX_QUANTIZED_VALUE = 8191 +}; + +enum +{ + OnlyLongSequence = 0, + LongStartSequence, + EightShortSequence, + LongStopSequence +}; + + +typedef struct +{ + const SHORT *ScaleFactorBands_Long; + const SHORT *ScaleFactorBands_Short; + UCHAR NumberOfScaleFactorBands_Long; + UCHAR NumberOfScaleFactorBands_Short; + UINT samplingRateIndex; + UINT samplingRate; +} SamplingRateInfo; + +typedef struct +{ + UCHAR CommonWindow; + UCHAR GlobalGain; + +} CRawDataInfo; + +typedef struct +{ + UCHAR WindowGroupLength[8]; + UCHAR WindowGroups; + UCHAR Valid; + + UCHAR WindowShape; /* 0: sine window, 1: KBD, 2: low overlap */ + UCHAR WindowSequence; /* See enum above, 0: long, 1: start, 2: short, 3: stop */ + UCHAR MaxSfBands; + UCHAR ScaleFactorGrouping; + + UCHAR TotalSfBands; + +} CIcsInfo; + + +enum +{ + ZERO_HCB = 0, + ESCBOOK = 11, + NSPECBOOKS = ESCBOOK + 1, + BOOKSCL = NSPECBOOKS, + NOISE_HCB = 13, + INTENSITY_HCB2 = 14, + INTENSITY_HCB = 15, + LAST_HCB +}; + +#define TNS_SCALE 3 + +/* + * This struct must be allocated one for every channel and must be persistent. + */ +typedef struct +{ + FIXP_DBL *pOverlapBuffer; + mdct_t IMdct; + + + + CDrcChannelData drcData; + CConcealmentInfo concealmentInfo; + +} CAacDecoderStaticChannelInfo; + + +/* + * This union must be allocated for every element (up to 2 channels). + */ +typedef struct { + + /* Common bit stream data */ + SHORT aScaleFactor[(8*16)]; /* Spectral scale factors for each sfb in each window. */ + SHORT aSfbScale[(8*16)]; /* could be free after ApplyTools() */ + UCHAR aCodeBook[(8*16)]; /* section data: codebook for each window and sfb. */ + CTnsData TnsData; + CRawDataInfo RawDataInfo; + + shouldBeUnion { + + struct { + CPulseData PulseData; + SHORT aNumLineInSec4Hcr[MAX_SFB_HCR]; /* needed once for all channels except for Drm syntax */ + UCHAR aCodeBooks4Hcr[MAX_SFB_HCR]; /* needed once for all channels except for Drm syntax. Same as "aCodeBook" ? */ + SHORT lenOfReorderedSpectralData; + SCHAR lenOfLongestCodeword; + SCHAR numberSection; + SCHAR rvlcCurrentScaleFactorOK; + SCHAR rvlcIntensityUsed; + } aac; + } specificTo; + +} CAacDecoderDynamicData; + +typedef shouldBeUnion { + CAacDecoderDynamicData pAacDecoderDynamicData[2]; + + /* Common signal data, can be used once the bit stream data from above is not used anymore. */ + FIXP_DBL mdctOutTemp[1024]; + FIXP_DBL sbrWorkBuffer[1024*2]; + +} CWorkBufferCore1; + +/* Common data referenced by all channels */ +typedef struct { + + CWorkBufferCore1 *workBufferCore1; + FIXP_DBL* workBufferCore2; + + CPnsInterChannelData pnsInterChannelData; + INT pnsCurrentSeed; + INT pnsRandomSeed[(8*16)]; + + CJointStereoData jointStereoData; /* One for one element */ + + shouldBeUnion { + struct { + CErHcrInfo erHcrInfo; + CErRvlcInfo erRvlcInfo; + SHORT aRvlcScfEsc[RVLC_MAX_SFB]; /* needed once for all channels */ + SHORT aRvlcScfFwd[RVLC_MAX_SFB]; /* needed once for all channels */ + SHORT aRvlcScfBwd[RVLC_MAX_SFB]; /* needed once for all channels */ + } aac; + + } overlay; + +} CAacDecoderCommonData; + + +/* + * This struct must be allocated one for every channels of every element and must be persistent. + * Among its members, the following memory areas can be overwritten under the given conditions: + * - pSpectralCoefficient The memory pointed to can be overwritten after time signal rendering. + * - data can be overwritten after time signal rendering. + * - pDynData memory pointed to can be overwritten after each CChannelElement_Decode() call. + * - pComData->overlay memory pointed to can be overwritten after each CChannelElement_Decode() call.. + */ +typedef struct +{ + SPECTRAL_PTR pSpectralCoefficient; /* Spectral coefficients of each window */ + SHORT specScale[8]; /* Scale shift values of each spectrum window */ + CIcsInfo icsInfo; + INT granuleLength; /* Size of smallest spectrum piece */ + UCHAR ElementInstanceTag; + + AACDEC_RENDER_MODE renderMode; /* Output signal rendering mode */ + + shouldBeUnion { + struct { + CPnsData PnsData; /* Not required for USAC */ + } aac; + + struct { + } usac; + } data; + + CAacDecoderDynamicData *pDynData; /* Data required for one element and discarded after decoding */ + CAacDecoderCommonData *pComData; /* Data required for one channel at a time during decode */ + +} CAacDecoderChannelInfo; + +/* channelinfo.cpp */ + +AAC_DECODER_ERROR getSamplingRateInfo(SamplingRateInfo *t, UINT samplesPerFrame, UINT samplingRateIndex, UINT samplingRate); + +/** + * \brief Read max SFB from bit stream and assign TotalSfBands according + * to the window sequence and sample rate. + * \param hBs bit stream handle as data source + * \param pIcsInfo IcsInfo structure to read the window sequence and store MaxSfBands and TotalSfBands + * \param pSamplingRateInfo read only + */ +AAC_DECODER_ERROR IcsReadMaxSfb ( + HANDLE_FDK_BITSTREAM hBs, + CIcsInfo *pIcsInfo, + const SamplingRateInfo *pSamplingRateInfo + ); + +AAC_DECODER_ERROR IcsRead( + HANDLE_FDK_BITSTREAM bs, + CIcsInfo *pIcsInfo, + const SamplingRateInfo* SamplingRateInfoTable, + const UINT flags + ); + +/* stereo.cpp, only called from this file */ + +/*! + \brief Applies MS stereo. + + The function applies MS stereo. + + \param pAacDecoderChannelInfo aac channel info. + \param pScaleFactorBandOffsets pointer to scalefactor band offsets. + \param pWindowGroupLength pointer to window group length array. + \param windowGroups number of window groups. + \param scaleFactorBandsTransmittedL number of transmitted scalefactor bands in left channel. + \param scaleFactorBandsTransmittedR number of transmitted scalefactor bands in right channel. + May differ from scaleFactorBandsTransmittedL only for USAC. + \return none +*/ +void CJointStereo_ApplyMS(CAacDecoderChannelInfo *pAacDecoderChannelInfo[2], + const short *pScaleFactorBandOffsets, + const UCHAR *pWindowGroupLength, + const int windowGroups, + const int scaleFactorBandsTransmittedL, + const int scaleFactorBandsTransmittedR); + +/*! + \brief Applies intensity stereo + + The function applies intensity stereo. + + \param pAacDecoderChannelInfo aac channel info. + \param pScaleFactorBandOffsets pointer to scalefactor band offsets. + \param pWindowGroupLength pointer to window group length array. + \param windowGroups number of window groups. + \param scaleFactorBandsTransmitted number of transmitted scalefactor bands. + \param CommonWindow common window bit. + \return none +*/ +void CJointStereo_ApplyIS(CAacDecoderChannelInfo *pAacDecoderChannelInfo[2], + const short *pScaleFactorBandOffsets, + const UCHAR *pWindowGroupLength, + const int windowGroups, + const int scaleFactorBandsTransmitted, + const UINT CommonWindow); + + +/* aacdec_pns.cpp */ +int CPns_IsPnsUsed (const CPnsData *pPnsData, + const int group, + const int band); + +void CPns_SetCorrelation(CPnsData *pPnsData, + const int group, + const int band, + const int outofphase); + +/****************** inline functions ******************/ + +inline UCHAR IsValid(const CIcsInfo *pIcsInfo) +{ + return pIcsInfo->Valid; +} + +inline UCHAR IsLongBlock(const CIcsInfo *pIcsInfo) +{ + return (pIcsInfo->WindowSequence != EightShortSequence); +} + +inline UCHAR GetWindowShape(const CIcsInfo *pIcsInfo) +{ + return pIcsInfo->WindowShape; +} + +inline UCHAR GetWindowSequence(const CIcsInfo *pIcsInfo) +{ + return pIcsInfo->WindowSequence; +} + +inline const SHORT *GetScaleFactorBandOffsets(const CIcsInfo *pIcsInfo, const SamplingRateInfo* samplingRateInfo) +{ + if (IsLongBlock(pIcsInfo)) + { + return samplingRateInfo->ScaleFactorBands_Long; + } + else + { + return samplingRateInfo->ScaleFactorBands_Short; + } +} + +inline int GetWindowsPerFrame(const CIcsInfo *pIcsInfo) +{ + return (pIcsInfo->WindowSequence == EightShortSequence) ? 8 : 1; +} + +inline UCHAR GetWindowGroups(const CIcsInfo *pIcsInfo) +{ + return pIcsInfo->WindowGroups; +} + +inline UCHAR GetWindowGroupLength(const CIcsInfo *pIcsInfo, const INT index) +{ + return pIcsInfo->WindowGroupLength[index]; +} + +inline const UCHAR *GetWindowGroupLengthTable(const CIcsInfo *pIcsInfo) +{ + return pIcsInfo->WindowGroupLength; +} + +inline UCHAR GetScaleFactorBandsTransmitted(const CIcsInfo *pIcsInfo) +{ + return pIcsInfo->MaxSfBands; +} + +inline UCHAR GetScaleMaxFactorBandsTransmitted(const CIcsInfo *pIcsInfo0, const CIcsInfo *pIcsInfo1) +{ + return fMax(pIcsInfo0->MaxSfBands, pIcsInfo1->MaxSfBands); +} + +inline UCHAR GetScaleFactorBandsTotal(const CIcsInfo *pIcsInfo) +{ + return pIcsInfo->TotalSfBands; +} + +/* Note: This function applies to AAC-LC only ! */ +inline UCHAR GetMaximumTnsBands(const CIcsInfo *pIcsInfo, const int samplingRateIndex) +{ + return tns_max_bands_tbl[samplingRateIndex][!IsLongBlock(pIcsInfo)]; +} + +#endif /* #ifndef CHANNELINFO_H */ + diff --git a/libAACdec/src/conceal.cpp b/libAACdec/src/conceal.cpp new file mode 100644 index 0000000..9fb2ed3 --- /dev/null +++ b/libAACdec/src/conceal.cpp @@ -0,0 +1,1763 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: independent channel concealment + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +/*! + \page concealment AAC core concealment + + This AAC core implementation includes a concealment function, which can be enabled + using the several defines during compilation. + + There are various tests inside the core, starting with simple CRC tests and ending in + a variety of plausibility checks. If such a check indicates an invalid bitstream, then + concealment is applied. + + Concealment is also applied when the calling main program indicates a distorted or missing + data frame using the frameOK flag. This is used for error detection on the transport layer. + (See below) + + There are three concealment-modes: + + 1) Muting: The spectral data is simply set to zero in case of an detected error. + + 2) Noise substitution: In case of an detected error, concealment copies the last frame and adds + attenuates the spectral data. For this mode you have to set the #CONCEAL_NOISE define. + Noise substitution adds no additional delay. + + 3) Interpolation: The interpolation routine swaps the spectral data from the previous and the + current frame just before the final frequency to time conversion. In case a single frame is + corrupted, concealmant interpolates between the last good and the first good frame to create + the spectral data for the missing frame. If multiple frames are corrupted, concealment + implements first a fade out based on slightly modified spectral values from the last good + frame. As soon as good frames are available, concealmant fades in the new spectral data. + For this mode you have to set the #CONCEAL_INTER define. Note that in this case, you also + need to set #SBR_BS_DELAY_ENABLE, which basically adds approriate delay in the SBR decoder. + Note that the Interpolating-Concealment increases the delay of your decoder by one frame + and that it does require additional resources such as memory and computational complexity. + +

How concealment can be used with errors on the transport layer

+ + Many errors can or have to be detected on the transport layer. For example in IP based systems + packet loss can occur. The transport protocol used should indicate such packet loss by inserting + an empty frame with frameOK=0. +*/ + +#include "conceal.h" + +#include "aac_rom.h" +#include "genericStds.h" + + +/* PNS (of block) */ +#include "aacdec_pns.h" +#include "block.h" + +#include "FDK_tools_rom.h" + +#define CONCEAL_DFLT_COMF_NOISE_LEVEL ( 46 ) /* ~= -70 dB */ + + +/* default settings */ +#define CONCEAL_DFLT_FADEOUT_FRAMES ( 5 ) +#define CONCEAL_DFLT_FADEIN_FRAMES ( 5 ) +#define CONCEAL_DFLT_MUTE_RELEASE_FRAMES ( 3 ) + +#define CONCEAL_DFLT_FADE_FACTOR ( 0.707106781186548f ) /* 1/sqrt(2) */ + +/* some often used constants: */ +#define FIXP_ZERO FL2FXCONST_DBL(0.0f) +#define FIXP_ONE FL2FXCONST_DBL(1.0f) +#define FIXP_FL_CORRECTION FL2FXCONST_DBL(0.53333333333333333f) + +/* For parameter conversion */ +#define CONCEAL_PARAMETER_BITS ( 8 ) +#define CONCEAL_MAX_QUANT_FACTOR ( (1<method = ConcealMethodInter; + + pConcealCommonData->numFadeOutFrames = CONCEAL_DFLT_FADEOUT_FRAMES; + pConcealCommonData->numFadeInFrames = CONCEAL_DFLT_FADEIN_FRAMES; + pConcealCommonData->numMuteReleaseFrames = CONCEAL_DFLT_MUTE_RELEASE_FRAMES; + + pConcealCommonData->comfortNoiseLevel = CONCEAL_DFLT_COMF_NOISE_LEVEL; + + /* Init fade factors (symetric) */ + pConcealCommonData->fadeOutFactor[0] = FL2FXCONST_SGL( CONCEAL_DFLT_FADE_FACTOR ); + pConcealCommonData->fadeInFactor[0] = pConcealCommonData->fadeOutFactor[0]; + + for (i = 1; i < CONCEAL_MAX_NUM_FADE_FACTORS; i++) { + pConcealCommonData->fadeOutFactor[i] = FX_DBL2FX_SGL(fMult(pConcealCommonData->fadeOutFactor[i-1],FL2FXCONST_SGL(CONCEAL_DFLT_FADE_FACTOR))); + pConcealCommonData->fadeInFactor[i] = pConcealCommonData->fadeOutFactor[i]; + } + } +} + + + +/*! + \brief Get current concealment method. + + \pConcealCommonData Pointer to common concealment data (for all channels) + + \return Concealment method. +*/ +CConcealmentMethod + CConcealment_GetMethod( CConcealParams *pConcealCommonData ) +{ + CConcealmentMethod method = ConcealMethodNone; + + if (pConcealCommonData != NULL) { + method = pConcealCommonData->method; + } + + return (method); +} + + +/*! + \brief Init concealment information for each channel + + The function initializes the concealment information. Two methods can be chosen: + 0 = interpolation method (adds delay) + 1 = noise substitution (no delay, low complexity) + + \return none +*/ +void + CConcealment_InitChannelData ( + CConcealmentInfo *pConcealChannelInfo, + CConcealParams *pConcealCommonData, + int samplesPerFrame ) +{ + int i; + + pConcealChannelInfo->pConcealParams = pConcealCommonData; + + FDKmemclear(pConcealChannelInfo->spectralCoefficient, 1024 * sizeof(FIXP_CNCL)); + + for (i = 0; i < 8; i++) { + pConcealChannelInfo->specScale[i] = 0; + } + + pConcealChannelInfo->iRandomPhase = 0; + + pConcealChannelInfo->windowSequence = 0; + pConcealChannelInfo->windowShape = 0; + + pConcealChannelInfo->prevFrameOk[0] = 1; + pConcealChannelInfo->prevFrameOk[1] = 1; + + pConcealChannelInfo->cntFadeFrames = 0; + pConcealChannelInfo->cntValidFrames = 0; + + pConcealChannelInfo->concealState = ConcealState_Ok; + +} + + +/*! + \brief Set error concealment parameters + + \concealParams + \method + \fadeOutSlope + \fadeInSlope + \muteRelease + \comfNoiseLevel + + \return none +*/ +AAC_DECODER_ERROR + CConcealment_SetParams ( + CConcealParams *concealParams, + int method, + int fadeOutSlope, + int fadeInSlope, + int muteRelease, + int comfNoiseLevel ) +{ + /* set concealment technique */ + if (method != AACDEC_CONCEAL_PARAM_NOT_SPECIFIED) { + switch ((CConcealmentMethod)method) + { + case ConcealMethodMute: + case ConcealMethodNoise: + case ConcealMethodInter: + /* Be sure to enable delay adjustment of SBR decoder! */ + if (concealParams == NULL) { + return AAC_DEC_INVALID_HANDLE; + } else { + /* set param */ + concealParams->method = (CConcealmentMethod)method; + } + break; + + default: + return AAC_DEC_SET_PARAM_FAIL; + } + } + + /* set number of frames for fade-out slope */ + if (fadeOutSlope != AACDEC_CONCEAL_PARAM_NOT_SPECIFIED) { + if ( (fadeOutSlope < CONCEAL_MAX_NUM_FADE_FACTORS) + && (fadeOutSlope >= 0) ) + { + if (concealParams == NULL) { + return AAC_DEC_INVALID_HANDLE; + } else { + /* set param */ + concealParams->numFadeOutFrames = fadeOutSlope; + } + } else { + return AAC_DEC_SET_PARAM_FAIL; + } + } + + /* set number of frames for fade-in slope */ + if (fadeInSlope != AACDEC_CONCEAL_PARAM_NOT_SPECIFIED) { + if ( (fadeInSlope < CONCEAL_MAX_NUM_FADE_FACTORS) + && (fadeInSlope >= 1) ) + { + if (concealParams == NULL) { + return AAC_DEC_INVALID_HANDLE; + } else { + /* set param */ + concealParams->numFadeInFrames = fadeInSlope; + } + } else { + return AAC_DEC_SET_PARAM_FAIL; + } + } + + /* set number of error-free frames after which the muting will be released */ + if (muteRelease != AACDEC_CONCEAL_PARAM_NOT_SPECIFIED) { + if ( (muteRelease < (CONCEAL_MAX_NUM_FADE_FACTORS<<1)) + && (muteRelease >= 0) ) + { + if (concealParams == NULL) { + return AAC_DEC_INVALID_HANDLE; + } else { + /* set param */ + concealParams->numMuteReleaseFrames = muteRelease; + } + } else { + return AAC_DEC_SET_PARAM_FAIL; + } + } + + /* set confort noise level which will be inserted while in state 'muting' */ + if (comfNoiseLevel != AACDEC_CONCEAL_PARAM_NOT_SPECIFIED) { + if ( (comfNoiseLevel < 0) + || (comfNoiseLevel > 127) ) { + return AAC_DEC_SET_PARAM_FAIL; + } + if (concealParams == NULL) { + return AAC_DEC_INVALID_HANDLE; + } else { + concealParams->comfortNoiseLevel = comfNoiseLevel; + } + } + + return (AAC_DEC_OK); +} + + +/*! + \brief Set fade-out/in attenuation factor vectors + + \concealParams + \fadeOutAttenuationVector + \fadeInAttenuationVector + + \return 0 if OK all other values indicate errors +*/ +AAC_DECODER_ERROR + CConcealment_SetAttenuation ( + CConcealParams *concealParams, + SHORT *fadeOutAttenuationVector, + SHORT *fadeInAttenuationVector ) +{ + if ( (fadeOutAttenuationVector == NULL) + && (fadeInAttenuationVector == NULL) ) { + return AAC_DEC_SET_PARAM_FAIL; + } + + /* Fade-out factors */ + if (fadeOutAttenuationVector != NULL) + { + int i; + + /* check quantized factors first */ + for (i = 0; i < CONCEAL_MAX_NUM_FADE_FACTORS; i++) { + if ((fadeOutAttenuationVector[i] < 0) || (fadeOutAttenuationVector[i] > CONCEAL_MAX_QUANT_FACTOR)) { + return AAC_DEC_SET_PARAM_FAIL; + } + } + if (concealParams == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + + /* now dequantize factors */ + for (i = 0; i < CONCEAL_MAX_NUM_FADE_FACTORS; i++) + { + concealParams->fadeOutFactor[i] = + FX_DBL2FX_SGL( fLdPow( CONCEAL_MIN_ATTENUATION_FACTOR_025_LD, + 0, + (FIXP_DBL)((INT)(FL2FXCONST_DBL(1.0/2.0)>>(CONCEAL_PARAMETER_BITS-1)) * (INT)fadeOutAttenuationVector[i]), + CONCEAL_PARAMETER_BITS + ) + ); + } + } + + /* Fade-in factors */ + if (fadeInAttenuationVector != NULL) + { + int i; + + /* check quantized factors first */ + for (i = 0; i < CONCEAL_MAX_NUM_FADE_FACTORS; i++) { + if ((fadeInAttenuationVector[i] < 0) || (fadeInAttenuationVector[i] > CONCEAL_MAX_QUANT_FACTOR)) { + return AAC_DEC_SET_PARAM_FAIL; + } + } + if (concealParams == NULL) { + return AAC_DEC_INVALID_HANDLE; + } + + /* now dequantize factors */ + for (i = 0; i < CONCEAL_MAX_NUM_FADE_FACTORS; i++) + { + concealParams->fadeInFactor[i] = + FX_DBL2FX_SGL( fLdPow( CONCEAL_MIN_ATTENUATION_FACTOR_025_LD, + 0, + (FIXP_DBL)((INT)(FIXP_ONE>>CONCEAL_PARAMETER_BITS) * (INT)fadeInAttenuationVector[i]), + CONCEAL_PARAMETER_BITS + ) + ); + } + } + + return (AAC_DEC_OK); +} + + +/*! + \brief Get state of concealment module. + + \pConcealChannelInfo + + \return Concealment state. +*/ +CConcealmentState + CConcealment_GetState ( + CConcealmentInfo *pConcealChannelInfo + ) +{ + CConcealmentState state = ConcealState_Ok; + + if (pConcealChannelInfo != NULL) { + state = pConcealChannelInfo->concealState; + } + + return (state); +} + + +static void CConcealment_fakePnsData ( + CPnsData *pPnsData, + CIcsInfo *pIcsInfo, + const SamplingRateInfo *pSamplingRateInfo, + SHORT *pSpecScale, + SHORT *pScaleFactor, + const int level ) +{ + CPnsInterChannelData *pInterChannelData = pPnsData->pPnsInterChannelData; + + int pnsBand, band, group, win; + //int delta = 0; + int windowsPerFrame = GetWindowsPerFrame(pIcsInfo); + int refLevel = (windowsPerFrame > 1) ? 82 : 91; + + FDK_ASSERT(level >= 0 && level <= 127); + + for (win = 0; win < windowsPerFrame; win++) { + pSpecScale[win] = 31; + } + + /* fake ICS info if necessary */ + if (!IsValid(pIcsInfo)) { + pIcsInfo->WindowGroups = 1; + if (IsLongBlock(pIcsInfo)) { + pIcsInfo->TotalSfBands = pSamplingRateInfo->NumberOfScaleFactorBands_Long; + pIcsInfo->WindowGroupLength[0] = 1; + } + else { + pIcsInfo->TotalSfBands = pSamplingRateInfo->NumberOfScaleFactorBands_Short; + pIcsInfo->WindowGroupLength[0] = 8; + } + pIcsInfo->MaxSfBands = pIcsInfo->TotalSfBands; + } + + /* global activate PNS */ + pPnsData->PnsActive = 1; + /* set energy level */ + pPnsData->CurrentEnergy = fixMax( 0, refLevel - level ); + + /* + value: | Avg. RMS power | Avg. RMS power | + | specScale = 22 | specScale = 31 | + -------+----------------+----------------+ + 5 | | -99.0 dB + 15 | | -90.0 dB + 25 | | -89.7 dB + 35 | | -85.3 dB + ... | ... | ... + 45 | -69.9 dB | -70.0 dB + 50 | -62.2 dB | + 55 | -55.6 dB | -54.6 dB + 60 | -47.0 dB | + 65 | -39.5 dB | -39.5 dB + 70 | -31.9 dB | + 75 | -24.4 dB | -24.4 dB + 80 | -16.9 dB | + 85 | -9.4 dB (c) | -9.4 dB + 90 | -3.9 dB (c) | + 95 | | -2.1 dB + 100 | | -1.6 dB + 105 | | -1.4 dB + */ + + for (group=0; group < GetWindowGroups(pIcsInfo); group++) + { + for (band=0; band < GetScaleFactorBandsTransmitted(pIcsInfo); band++) + { + pnsBand = group * 16 + band; + + if (pnsBand >= NO_OFBANDS) { + return; + } + //pPnsData->CurrentEnergy += delta ; + pScaleFactor[pnsBand] = pPnsData->CurrentEnergy; + pInterChannelData->correlated[pnsBand] = 0; + pPnsData->pnsUsed[pnsBand] = 1; + } + } +} + + +/*! + \brief Store data for concealment techniques applied later + + Interface function to store data for different concealment strategies + + \return none + */ +void + CConcealment_Store ( + CConcealmentInfo *hConcealmentInfo, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo ) +{ + if ( !(pAacDecoderChannelInfo->renderMode == AACDEC_RENDER_LPD + ) ) + { + FIXP_DBL *pSpectralCoefficient = SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient); + SHORT *pSpecScale = pAacDecoderChannelInfo->specScale; + CIcsInfo *pIcsInfo = &pAacDecoderChannelInfo->icsInfo; + + SHORT tSpecScale[8]; + UCHAR tWindowShape, tWindowSequence; + + /* store old window infos for swapping */ + tWindowSequence = hConcealmentInfo->windowSequence; + tWindowShape = hConcealmentInfo->windowShape; + + /* store old scale factors for swapping */ + FDKmemcpy(tSpecScale, hConcealmentInfo->specScale, 8*sizeof(SHORT)); + + /* store new window infos */ + hConcealmentInfo->windowSequence = GetWindowSequence(pIcsInfo); + hConcealmentInfo->windowShape = GetWindowShape(pIcsInfo); + hConcealmentInfo->lastWinGrpLen = *(GetWindowGroupLengthTable(pIcsInfo)+GetWindowGroups(pIcsInfo)-1); + + /* store new scale factors */ + FDKmemcpy(hConcealmentInfo->specScale, pSpecScale, 8*sizeof(SHORT)); + + if (CConcealment_GetDelay(hConcealmentInfo->pConcealParams) == 0) + { + /* store new spectral bins */ +#if (CNCL_FRACT_BITS == DFRACT_BITS) + FDKmemcpy(hConcealmentInfo->spectralCoefficient, pSpectralCoefficient, 1024 * sizeof(FIXP_CNCL)); +#else + FIXP_CNCL *RESTRICT pCncl = &hConcealmentInfo->spectralCoefficient[1024-1]; + FIXP_DBL *RESTRICT pSpec = &pSpectralCoefficient[1024-1]; + int i; + + for (i = 1024; i != 0; i--) { + *pCncl-- = FX_DBL2FX_CNCL(*pSpec--); + } +#endif + } + else + { + FIXP_CNCL *RESTRICT pCncl = &hConcealmentInfo->spectralCoefficient[1024-1]; + FIXP_DBL *RESTRICT pSpec = &pSpectralCoefficient[1024-1]; + int i; + + /* swap spectral data */ + for (i = 1024; i != 0; i--) { + FIXP_DBL tSpec = *pSpec; + *pSpec-- = FX_CNCL2FX_DBL(*pCncl); + *pCncl-- = FX_DBL2FX_CNCL( tSpec); + } + + /* complete swapping of window infos */ + pIcsInfo->WindowSequence = tWindowSequence; + pIcsInfo->WindowShape = tWindowShape; + + /* complete swapping of scale factors */ + FDKmemcpy(pSpecScale, tSpecScale, 8*sizeof(SHORT)); + } + } + +} + + +/*! + \brief Apply concealment + + Interface function to different concealment strategies + + \return none + */ +int + CConcealment_Apply ( + CConcealmentInfo *hConcealmentInfo, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, + const SamplingRateInfo *pSamplingRateInfo, + const int samplesPerFrame, + const UCHAR lastLpdMode, + const int frameOk, + const UINT flags) +{ + int appliedProcessing = 0; + + if ( (frameOk == 0) + && (pAacDecoderChannelInfo->renderMode != (AACDEC_RENDER_MODE)hConcealmentInfo->lastRenderMode) ) { + /* restore the last render mode to stay in the same domain which allows to do a proper concealment */ + pAacDecoderChannelInfo->renderMode = (AACDEC_RENDER_MODE)hConcealmentInfo->lastRenderMode; + } else { + /* otherwise store the current mode */ + hConcealmentInfo->lastRenderMode = (SCHAR)pAacDecoderChannelInfo->renderMode; + } + + if ( frameOk ) + { + /* Rescue current data for concealment in future frames */ + CConcealment_Store ( hConcealmentInfo, + pAacDecoderChannelInfo, + pAacDecoderStaticChannelInfo ); + /* Reset index to random sign vector to make sign calculation frame agnostic + (only depends on number of subsequently concealed spectral blocks) */ + hConcealmentInfo->iRandomPhase = 0; + } + + /* hand current frame status to the state machine */ + CConcealment_UpdateState( hConcealmentInfo, + frameOk ); + + if ( !frameOk ) + { + /* Create data for signal rendering according to the selected concealment method and decoder operating mode. */ + + + if ( !(pAacDecoderChannelInfo->renderMode == AACDEC_RENDER_LPD + ) + ) + { + switch (hConcealmentInfo->pConcealParams->method) + { + default: + case ConcealMethodMute: + /* Mute spectral data in case of errors */ + FDKmemclear(pAacDecoderChannelInfo->pSpectralCoefficient, samplesPerFrame * sizeof(FIXP_DBL)); + /* Set last window shape */ + pAacDecoderChannelInfo->icsInfo.WindowShape = hConcealmentInfo->windowShape; + appliedProcessing = 1; + break; + + case ConcealMethodNoise: + /* Noise substitution error concealment technique */ + appliedProcessing = + CConcealment_ApplyNoise (hConcealmentInfo, + pAacDecoderChannelInfo, + pAacDecoderStaticChannelInfo, + pSamplingRateInfo, + samplesPerFrame, + flags); + break; + + case ConcealMethodInter: + /* Energy interpolation concealment based on 3GPP */ + appliedProcessing = + CConcealment_ApplyInter (hConcealmentInfo, + pAacDecoderChannelInfo, + pSamplingRateInfo, + samplesPerFrame, + 0, /* don't use tonal improvement */ + 0); + break; + + } + } + } + /* update history */ + hConcealmentInfo->prevFrameOk[0] = hConcealmentInfo->prevFrameOk[1]; + hConcealmentInfo->prevFrameOk[1] = frameOk; + + return appliedProcessing; +} + +/*! +\brief Apply concealment noise substitution + + In case of frame lost this function produces a noisy frame with respect to the + energies values of past frame. + +\return none + */ +static int + CConcealment_ApplyNoise (CConcealmentInfo *pConcealmentInfo, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, + const SamplingRateInfo *pSamplingRateInfo, + const int samplesPerFrame, + const UINT flags) +{ + CConcealParams *pConcealCommonData = pConcealmentInfo->pConcealParams; + + FIXP_DBL *pSpectralCoefficient = SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient); + SHORT *pSpecScale = pAacDecoderChannelInfo->specScale; + CIcsInfo *pIcsInfo = &pAacDecoderChannelInfo->icsInfo; + + int appliedProcessing = 0; + + FDK_ASSERT((samplesPerFrame>=480) && (samplesPerFrame<=1024)); + FDK_ASSERT((samplesPerFrame&0x1F) == 0); + + switch (pConcealmentInfo->concealState) + { + case ConcealState_Ok: + /* Nothing to do here! */ + break; + + case ConcealState_Single: + case ConcealState_FadeOut: + { + /* restore frequency coefficients from buffer with a specific muting */ + FIXP_SGL fac; + int win, numWindows = 1; + int windowLen = samplesPerFrame; + int tFadeFrames, lastWindow = 0; + int win_idx_stride = 1; + + FDK_ASSERT(pConcealmentInfo != NULL); + FDK_ASSERT(pConcealmentInfo->cntFadeFrames >= 0); + FDK_ASSERT(pConcealmentInfo->cntFadeFrames < CONCEAL_MAX_NUM_FADE_FACTORS); + FDK_ASSERT(pConcealmentInfo->cntFadeFrames <= pConcealCommonData->numFadeOutFrames); + + /* get attenuation factor */ + tFadeFrames = pConcealmentInfo->cntFadeFrames; + fac = pConcealCommonData->fadeOutFactor[tFadeFrames]; + + /* set old window parameters */ + { + pIcsInfo->WindowShape = pConcealmentInfo->windowShape; + pIcsInfo->WindowSequence = pConcealmentInfo->windowSequence; + + if (pConcealmentInfo->windowSequence == 2) { + /* short block handling */ + numWindows = 8; + windowLen = samplesPerFrame >> 3; + lastWindow = numWindows - pConcealmentInfo->lastWinGrpLen; + } + } + + for (win = 0; win < numWindows; win++) { + FIXP_CNCL *pCncl = pConcealmentInfo->spectralCoefficient + (lastWindow * windowLen); + FIXP_DBL *pOut = pSpectralCoefficient + (win * windowLen); + int i; + + FDK_ASSERT((lastWindow * windowLen + windowLen) <= samplesPerFrame); + + /* restore frequency coefficients from buffer with a specific attenuation */ + for (i = 0; i < windowLen; i++) { + pOut[i] = fMult(pCncl[i], fac); + } + + /* apply random change of sign for spectral coefficients */ + CConcealment_ApplyRandomSign(pConcealmentInfo->iRandomPhase, + pOut, + windowLen ); + + /* Increment random phase index to avoid repetition artifacts. */ + pConcealmentInfo->iRandomPhase = (pConcealmentInfo->iRandomPhase + 1) & (AAC_NF_NO_RANDOM_VAL - 1); + + /* set old scale factors */ + pSpecScale[win*win_idx_stride] = pConcealmentInfo->specScale[win_idx_stride*lastWindow++]; + + if ( (lastWindow >= numWindows) + && (numWindows > 1) ) + { + /* end of sequence -> rewind */ + lastWindow = numWindows - pConcealmentInfo->lastWinGrpLen; + /* update the attenuation factor to get a faster fade-out */ + tFadeFrames += 1; + if (tFadeFrames < pConcealCommonData->numFadeOutFrames) { + fac = pConcealCommonData->fadeOutFactor[tFadeFrames]; + } else { + fac = (FIXP_SGL)0; + } + } + } + + /* store temp vars */ + pConcealmentInfo->cntFadeFrames = tFadeFrames; + appliedProcessing = 1; + } + break; + + case ConcealState_Mute: + { + /* set dummy window parameters */ + pIcsInfo->Valid = 0; /* Trigger the generation of a consitent IcsInfo */ + pIcsInfo->WindowShape = pConcealmentInfo->windowShape; /* Prevent an invalid WindowShape (required for F/T transform) */ + pIcsInfo->WindowSequence = CConcealment_GetWinSeq(pConcealmentInfo->windowSequence); + pConcealmentInfo->windowSequence = pIcsInfo->WindowSequence; /* Store for next frame (spectrum in concealment buffer can't be used at all) */ + + /* mute spectral data */ + FDKmemclear(pSpectralCoefficient, samplesPerFrame * sizeof(FIXP_DBL)); + + if ( !(flags & (AC_USAC|AC_RSVD50)) + && pConcealCommonData->comfortNoiseLevel >= 0 + && pConcealCommonData->comfortNoiseLevel <= 61 /* -90dB */) + { + /* insert comfort noise using PNS */ + CConcealment_fakePnsData ( + &pAacDecoderChannelInfo->data.aac.PnsData, + pIcsInfo, + pSamplingRateInfo, + pAacDecoderChannelInfo->pDynData->aSfbScale, + pAacDecoderChannelInfo->pDynData->aScaleFactor, + pConcealCommonData->comfortNoiseLevel + ); + + CPns_Apply ( + &pAacDecoderChannelInfo->data.aac.PnsData, + pIcsInfo, + pAacDecoderChannelInfo->pSpectralCoefficient, + pAacDecoderChannelInfo->specScale, + pAacDecoderChannelInfo->pDynData->aScaleFactor, + pSamplingRateInfo, + pAacDecoderChannelInfo->granuleLength, + 0 /* always apply to first channel */ + ); + } + appliedProcessing = 1; + } + break; + + case ConcealState_FadeIn: + { + FDK_ASSERT(pConcealmentInfo->cntFadeFrames >= 0); + FDK_ASSERT(pConcealmentInfo->cntFadeFrames < CONCEAL_MAX_NUM_FADE_FACTORS); + FDK_ASSERT(pConcealmentInfo->cntFadeFrames < pConcealCommonData->numFadeInFrames); + + /* attenuate signal to get a smooth fade-in */ + FIXP_DBL *RESTRICT pOut = &pSpectralCoefficient[samplesPerFrame-1]; + FIXP_SGL fac = pConcealCommonData->fadeInFactor[pConcealmentInfo->cntFadeFrames]; + int i; + + for (i = samplesPerFrame; i != 0; i--) { + *pOut = fMult(*pOut, fac); + pOut--; + } + appliedProcessing = 1; + } + break; + + default: + /* we shouldn't come here anyway */ + FDK_ASSERT(0); + break; + } + + return appliedProcessing; +} + + +/*! + \brief Apply concealment interpolation + + The function swaps the data from the current and the previous frame. If an + error has occured, frame interpolation is performed to restore the missing + frame. In case of multiple faulty frames, fade-in and fade-out is applied. + + \return none +*/ +static int + CConcealment_ApplyInter ( + CConcealmentInfo *pConcealmentInfo, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + const SamplingRateInfo *pSamplingRateInfo, + const int samplesPerFrame, + const int improveTonal, + const int frameOk ) +{ + CConcealParams *pConcealCommonData = pConcealmentInfo->pConcealParams; + + FIXP_DBL *pSpectralCoefficient = SPEC_LONG(pAacDecoderChannelInfo->pSpectralCoefficient); + CIcsInfo *pIcsInfo = &pAacDecoderChannelInfo->icsInfo; + SHORT *pSpecScale = pAacDecoderChannelInfo->specScale; + + + int sfbEnergyPrev[64]; + int sfbEnergyAct [64]; + + int i, appliedProcessing = 0; + + /* clear/init */ + FDKmemclear(sfbEnergyPrev, 64 * sizeof(int)); + FDKmemclear(sfbEnergyAct, 64 * sizeof(int)); + + + if (!frameOk) + { + /* Restore last frame from concealment buffer */ + pIcsInfo->WindowShape = pConcealmentInfo->windowShape; + pIcsInfo->WindowSequence = pConcealmentInfo->windowSequence; + + /* Restore spectral data */ + for (i = 0; i < samplesPerFrame; i++) { + pSpectralCoefficient[i] = FX_CNCL2FX_DBL(pConcealmentInfo->spectralCoefficient[i]); + } + + /* Restore scale factors */ + FDKmemcpy(pSpecScale, pConcealmentInfo->specScale, 8*sizeof(SHORT)); + } + + /* if previous frame was not ok */ + if (!pConcealmentInfo->prevFrameOk[1]) { + + /* if current frame (f_n) is ok and the last but one frame (f_(n-2)) + was ok, too, then interpolate both frames in order to generate + the current output frame (f_(n-1)). Otherwise, use the last stored + frame (f_(n-2) or f_(n-3) or ...). */ + if (frameOk && pConcealmentInfo->prevFrameOk[0]) + { + appliedProcessing = 1; + + + /* Interpolate both frames in order to generate the current output frame (f_(n-1)). */ + if (pIcsInfo->WindowSequence == EightShortSequence) { + /* f_(n-2) == EightShortSequence */ + /* short--??????--short, short--??????--long interpolation */ + /* short--short---short, short---long---long interpolation */ + + int wnd; + + if (pConcealmentInfo->windowSequence == EightShortSequence) { /* f_n == EightShortSequence */ + /* short--short---short interpolation */ + + int scaleFactorBandsTotal = pSamplingRateInfo->NumberOfScaleFactorBands_Short; + const SHORT *pSfbOffset = pSamplingRateInfo->ScaleFactorBands_Short; + pIcsInfo->WindowShape = 1; + pIcsInfo->WindowSequence = EightShortSequence; + + for (wnd = 0; wnd < 8; wnd++) + { + CConcealment_CalcBandEnergy( + &pSpectralCoefficient[wnd * (samplesPerFrame / 8)], /* spec_(n-2) */ + pSamplingRateInfo, + EightShortSequence, + CConcealment_NoExpand, + sfbEnergyPrev); + + CConcealment_CalcBandEnergy( + &pConcealmentInfo->spectralCoefficient[wnd * (samplesPerFrame / 8)], /* spec_n */ + pSamplingRateInfo, + EightShortSequence, + CConcealment_NoExpand, + sfbEnergyAct); + + CConcealment_InterpolateBuffer( + &pSpectralCoefficient[wnd * (samplesPerFrame / 8)], /* spec_(n-1) */ + &pSpecScale[wnd], + &pConcealmentInfo->specScale[wnd], + &pSpecScale[wnd], + sfbEnergyPrev, + sfbEnergyAct, + scaleFactorBandsTotal, + pSfbOffset); + + } + } else { /* f_n != EightShortSequence */ + /* short---long---long interpolation */ + + int scaleFactorBandsTotal = pSamplingRateInfo->NumberOfScaleFactorBands_Long; + const SHORT *pSfbOffset = pSamplingRateInfo->ScaleFactorBands_Long; + SHORT specScaleOut; + + CConcealment_CalcBandEnergy(&pSpectralCoefficient[samplesPerFrame - (samplesPerFrame / 8)], /* [wnd] spec_(n-2) */ + pSamplingRateInfo, + EightShortSequence, + CConcealment_Expand, + sfbEnergyAct); + + CConcealment_CalcBandEnergy(pConcealmentInfo->spectralCoefficient, /* spec_n */ + pSamplingRateInfo, + OnlyLongSequence, + CConcealment_NoExpand, + sfbEnergyPrev); + + pIcsInfo->WindowShape = 0; + pIcsInfo->WindowSequence = LongStopSequence; + + for (i = 0; i < samplesPerFrame ; i++) { + pSpectralCoefficient[i] = pConcealmentInfo->spectralCoefficient[i]; /* spec_n */ + } + + for (i = 0; i < 8; i++) { /* search for max(specScale) */ + if (pSpecScale[i] > pSpecScale[0]) { + pSpecScale[0] = pSpecScale[i]; + } + } + + CConcealment_InterpolateBuffer( + pSpectralCoefficient, /* spec_(n-1) */ + &pConcealmentInfo->specScale[0], + &pSpecScale[0], + &specScaleOut, + sfbEnergyPrev, + sfbEnergyAct, + scaleFactorBandsTotal, + pSfbOffset); + + pSpecScale[0] = specScaleOut; + } + } else { + /* long--??????--short, long--??????--long interpolation */ + /* long---long---short, long---long---long interpolation */ + + int scaleFactorBandsTotal = pSamplingRateInfo->NumberOfScaleFactorBands_Long; + const SHORT *pSfbOffset = pSamplingRateInfo->ScaleFactorBands_Long; + SHORT specScaleAct = pConcealmentInfo->specScale[0]; + + CConcealment_CalcBandEnergy(pSpectralCoefficient, /* spec_(n-2) */ + pSamplingRateInfo, + OnlyLongSequence, + CConcealment_NoExpand, + sfbEnergyPrev); + + if (pConcealmentInfo->windowSequence == EightShortSequence) { /* f_n == EightShortSequence */ + /* long---long---short interpolation */ + + pIcsInfo->WindowShape = 1; + pIcsInfo->WindowSequence = LongStartSequence; + + for (i = 1; i < 8; i++) { /* search for max(specScale) */ + if (pConcealmentInfo->specScale[i] > specScaleAct) { + specScaleAct = pConcealmentInfo->specScale[i]; + } + } + + /* Expand first short spectrum */ + CConcealment_CalcBandEnergy(pConcealmentInfo->spectralCoefficient, /* spec_n */ + pSamplingRateInfo, + EightShortSequence, + CConcealment_Expand, /* !!! */ + sfbEnergyAct); + } else { + /* long---long---long interpolation */ + + pIcsInfo->WindowShape = 0; + pIcsInfo->WindowSequence = OnlyLongSequence; + + CConcealment_CalcBandEnergy(pConcealmentInfo->spectralCoefficient, /* spec_n */ + pSamplingRateInfo, + OnlyLongSequence, + CConcealment_NoExpand, + sfbEnergyAct); + } + + CConcealment_InterpolateBuffer( + pSpectralCoefficient, /* spec_(n-1) */ + &pSpecScale[0], + &specScaleAct, + &pSpecScale[0], + sfbEnergyPrev, + sfbEnergyAct, + scaleFactorBandsTotal, + pSfbOffset); + + } + } + + /* Noise substitution of sign of the output spectral coefficients */ + CConcealment_ApplyRandomSign (pConcealmentInfo->iRandomPhase, + pSpectralCoefficient, + samplesPerFrame); + /* Increment random phase index to avoid repetition artifacts. */ + pConcealmentInfo->iRandomPhase = (pConcealmentInfo->iRandomPhase + 1) & (AAC_NF_NO_RANDOM_VAL - 1); + } + + /* scale spectrum according to concealment state */ + switch (pConcealmentInfo->concealState) + { + case ConcealState_Single: + appliedProcessing = 1; + break; + + case ConcealState_FadeOut: + { + FDK_ASSERT(pConcealmentInfo->cntFadeFrames >= 0); + FDK_ASSERT(pConcealmentInfo->cntFadeFrames < CONCEAL_MAX_NUM_FADE_FACTORS); + FDK_ASSERT(pConcealmentInfo->cntFadeFrames < pConcealCommonData->numFadeOutFrames); + + /* restore frequency coefficients from buffer with a specific muting */ + FIXP_DBL *RESTRICT pOut = &pSpectralCoefficient[samplesPerFrame-1]; + FIXP_SGL fac = pConcealCommonData->fadeOutFactor[pConcealmentInfo->cntFadeFrames]; + + for (i = samplesPerFrame; i != 0; i--) { + *pOut = fMult(*pOut, fac); + pOut--; + } + appliedProcessing = 1; + } + break; + + case ConcealState_FadeIn: + { + FDK_ASSERT(pConcealmentInfo->cntFadeFrames >= 0); + FDK_ASSERT(pConcealmentInfo->cntFadeFrames < CONCEAL_MAX_NUM_FADE_FACTORS); + FDK_ASSERT(pConcealmentInfo->cntFadeFrames < pConcealCommonData->numFadeInFrames); + + /* attenuate signal to get a smooth fade-in */ + FIXP_DBL *RESTRICT pOut = &pSpectralCoefficient[samplesPerFrame-1]; + FIXP_SGL fac = pConcealCommonData->fadeInFactor[pConcealmentInfo->cntFadeFrames]; + + for (i = samplesPerFrame; i != 0; i--) { + *pOut = fMult(*pOut, fac); + pOut--; + } + appliedProcessing = 1; + } + break; + + case ConcealState_Mute: + { + int fac = pConcealCommonData->comfortNoiseLevel; + + /* set dummy window parameters */ + pIcsInfo->Valid = 0; /* Trigger the generation of a consitent IcsInfo */ + pIcsInfo->WindowShape = pConcealmentInfo->windowShape; /* Prevent an invalid WindowShape (required for F/T transform) */ + pIcsInfo->WindowSequence = CConcealment_GetWinSeq(pConcealmentInfo->windowSequence); + pConcealmentInfo->windowSequence = pIcsInfo->WindowSequence; /* Store for next frame (spectrum in concealment buffer can't be used at all) */ + + /* mute spectral data */ + FDKmemclear(pSpectralCoefficient, samplesPerFrame * sizeof(FIXP_DBL)); + + if (fac >= 0 && fac <= 61) { + /* insert comfort noise using PNS */ + CConcealment_fakePnsData ( + &pAacDecoderChannelInfo->data.aac.PnsData, + pIcsInfo, + pSamplingRateInfo, + pAacDecoderChannelInfo->specScale, + pAacDecoderChannelInfo->pDynData->aScaleFactor, + fac + ); + + CPns_Apply ( + &pAacDecoderChannelInfo->data.aac.PnsData, + pIcsInfo, + pAacDecoderChannelInfo->pSpectralCoefficient, + pAacDecoderChannelInfo->specScale, + pAacDecoderChannelInfo->pDynData->aScaleFactor, + pSamplingRateInfo, + pAacDecoderChannelInfo->granuleLength, + 0 /* always apply to first channel */ + ); + } + appliedProcessing = 1; + } + break; + + default: + /* nothing to do here */ + break; + } + + return appliedProcessing; +} + + +/*! + \brief Calculate the spectral energy + + The function calculates band-wise the spectral energy. This is used for + frame interpolation. + + \return none +*/ +static void + CConcealment_CalcBandEnergy ( + FIXP_DBL *spectrum, + const SamplingRateInfo *pSamplingRateInfo, + const int blockType, + CConcealmentExpandType expandType, + int *sfbEnergy ) +{ + const SHORT *pSfbOffset; + int line, sfb, scaleFactorBandsTotal = 0; + + /* In the following calculations, enAccu is initialized with LSB-value in order to avoid zero energy-level */ + + line = 0; + + switch(blockType) { + + case OnlyLongSequence: + case LongStartSequence: + case LongStopSequence: + + if (expandType == CConcealment_NoExpand) { + /* standard long calculation */ + scaleFactorBandsTotal = pSamplingRateInfo->NumberOfScaleFactorBands_Long; + pSfbOffset = pSamplingRateInfo->ScaleFactorBands_Long; + + for (sfb = 0; sfb < scaleFactorBandsTotal; sfb++) { + FIXP_DBL enAccu = (FIXP_DBL)(LONG)1; + int sfbScale = (sizeof(LONG)<<3) - CntLeadingZeros(pSfbOffset[sfb+1] - pSfbOffset[sfb]) - 1; + /* scaling depends on sfb width. */ + for ( ; line < pSfbOffset[sfb+1]; line++) { + enAccu += fPow2Div2(*(spectrum + line)) >> sfbScale; + } + *(sfbEnergy + sfb) = CntLeadingZeros(enAccu) - 1; + } + } + else { + /* compress long to short */ + scaleFactorBandsTotal = pSamplingRateInfo->NumberOfScaleFactorBands_Short; + pSfbOffset = pSamplingRateInfo->ScaleFactorBands_Short; + + for (sfb = 0; sfb < scaleFactorBandsTotal; sfb++) { + FIXP_DBL enAccu = (FIXP_DBL)(LONG)1; + int sfbScale = (sizeof(LONG)<<3) - CntLeadingZeros(pSfbOffset[sfb+1] - pSfbOffset[sfb]) - 1; + /* scaling depends on sfb width. */ + for (; line < pSfbOffset[sfb+1] << 3; line++) { + enAccu += (enAccu + (fPow2Div2(*(spectrum + line)) >> sfbScale)) >> 3; + } + *(sfbEnergy + sfb) = CntLeadingZeros(enAccu) - 1; + } + } + break; + + case EightShortSequence: + + if (expandType == CConcealment_NoExpand) { + /* standard short calculation */ + scaleFactorBandsTotal = pSamplingRateInfo->NumberOfScaleFactorBands_Short; + pSfbOffset = pSamplingRateInfo->ScaleFactorBands_Short; + + for (sfb = 0; sfb < scaleFactorBandsTotal; sfb++) { + FIXP_DBL enAccu = (FIXP_DBL)(LONG)1; + int sfbScale = (sizeof(LONG)<<3) - CntLeadingZeros(pSfbOffset[sfb+1] - pSfbOffset[sfb]) - 1; + /* scaling depends on sfb width. */ + for ( ; line < pSfbOffset[sfb+1]; line++) { + enAccu += fPow2Div2(*(spectrum + line)) >> sfbScale; + } + *(sfbEnergy + sfb) = CntLeadingZeros(enAccu) - 1; + } + } + else { + /* expand short to long spectrum */ + scaleFactorBandsTotal = pSamplingRateInfo->NumberOfScaleFactorBands_Long; + pSfbOffset = pSamplingRateInfo->ScaleFactorBands_Long; + + for (sfb = 0; sfb < scaleFactorBandsTotal; sfb++) { + FIXP_DBL enAccu = (FIXP_DBL)(LONG)1; + int sfbScale = (sizeof(LONG)<<3) - CntLeadingZeros(pSfbOffset[sfb+1] - pSfbOffset[sfb]) - 1; + /* scaling depends on sfb width. */ + for ( ; line < pSfbOffset[sfb+1]; line++) { + enAccu += fPow2Div2(*(spectrum + (line >> 3))) >> sfbScale; + } + *(sfbEnergy + sfb) = CntLeadingZeros(enAccu) - 1; + } + } + break; + } +} + + +/*! + \brief Interpolate buffer + + The function creates the interpolated spectral data according to the + energy of the last good frame and the current (good) frame. + + \return none +*/ +static void + CConcealment_InterpolateBuffer ( + FIXP_DBL *spectrum, + SHORT *pSpecScalePrv, + SHORT *pSpecScaleAct, + SHORT *pSpecScaleOut, + int *enPrv, + int *enAct, + int sfbCnt, + const SHORT *pSfbOffset ) +{ + int sfb, line = 0; + int fac_shift; + int fac_mod; + FIXP_DBL accu; + + for (sfb = 0; sfb < sfbCnt; sfb++) { + + fac_shift = enPrv[sfb] - enAct[sfb] + ((*pSpecScaleAct - *pSpecScalePrv) << 1); + fac_mod = fac_shift & 3; + fac_shift = (fac_shift >> 2) + 1; + fac_shift += *pSpecScalePrv - fixMax(*pSpecScalePrv, *pSpecScaleAct); + + for (; line < pSfbOffset[sfb+1]; line++) { + accu = fMult(*(spectrum+line), facMod4Table[fac_mod]); + if (fac_shift < 0) { + accu >>= -fac_shift; + } else { + accu <<= fac_shift; + } + *(spectrum+line) = accu; + } + } + *pSpecScaleOut = fixMax(*pSpecScalePrv, *pSpecScaleAct); +} + + + + +static INT findEquiFadeFrame ( + CConcealParams *pConcealCommonData, + INT actFadeIndex, + int direction ) +{ + FIXP_SGL *pFactor; + FIXP_SGL referenceVal; + FIXP_SGL minDiff = (FIXP_SGL)MAXVAL_SGL; + + INT numFrames = 0; + INT nextFadeIndex = 0; + + int i; + + /* init depending on direction */ + if (direction == 0) { /* FADE-OUT => FADE-IN */ + numFrames = pConcealCommonData->numFadeInFrames; + referenceVal = pConcealCommonData->fadeOutFactor[actFadeIndex] >> 1; + pFactor = pConcealCommonData->fadeInFactor; + } + else { /* FADE-IN => FADE-OUT */ + numFrames = pConcealCommonData->numFadeOutFrames; + referenceVal = pConcealCommonData->fadeInFactor[actFadeIndex] >> 1; + pFactor = pConcealCommonData->fadeOutFactor; + } + + /* search for minimum difference */ + for (i = 0; i < numFrames; i++) { + FIXP_SGL diff = fixp_abs((pFactor[i]>>1) - referenceVal); + if (diff < minDiff) { + minDiff = diff; + nextFadeIndex = i; + } + } + + /* check and adjust depending on direction */ + if (direction == 0) { /* FADE-OUT => FADE-IN */ + if (((pFactor[nextFadeIndex]>>1) <= referenceVal) && (nextFadeIndex > 0)) { + nextFadeIndex -= 1; + } + } + else { /* FADE-IN => FADE-OUT */ + if (((pFactor[nextFadeIndex]>>1) >= referenceVal) && (nextFadeIndex < numFrames-1)) { + nextFadeIndex += 1; + } + } + + return (nextFadeIndex); +} + + +/*! + \brief Update the concealment state + + The function updates the state of the concealment state-machine. The + states are: mute, fade-in, fade-out, interpolate and frame-ok. + + \return none +*/ +static void + CConcealment_UpdateState ( + CConcealmentInfo *pConcealmentInfo, + int frameOk ) +{ + CConcealParams *pConcealCommonData = pConcealmentInfo->pConcealParams; + + switch (pConcealCommonData->method) + { + case ConcealMethodNoise: + { + if (pConcealmentInfo->concealState != ConcealState_Ok) { + /* count the valid frames during concealment process */ + if (frameOk) { + pConcealmentInfo->cntValidFrames += 1; + } else { + pConcealmentInfo->cntValidFrames = 0; + } + } + + /* -- STATE MACHINE for Noise Substitution -- */ + switch (pConcealmentInfo->concealState) + { + case ConcealState_Ok: + if (!frameOk) { + /* change to state SINGLE-FRAME-LOSS */ + pConcealmentInfo->concealState = ConcealState_Single; + pConcealmentInfo->cntFadeFrames = 0; + pConcealmentInfo->cntValidFrames = 0; + } + break; + + case ConcealState_Single: /* Just a pre-stage before fade-out begins. Stay here only one frame! */ + pConcealmentInfo->cntFadeFrames += 1; + if (frameOk) { + if (pConcealmentInfo->cntValidFrames > pConcealCommonData->numMuteReleaseFrames) { + /* change to state FADE-IN */ + pConcealmentInfo->concealState = ConcealState_FadeIn; + pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData, + pConcealmentInfo->cntFadeFrames-1, + 0 /* FadeOut -> FadeIn */); + } else { + /* change to state OK */ + pConcealmentInfo->concealState = ConcealState_Ok; + } + } else { + if (pConcealmentInfo->cntFadeFrames >= pConcealCommonData->numFadeOutFrames) { + /* change to state MUTE */ + pConcealmentInfo->concealState = ConcealState_Mute; + } else { + /* change to state FADE-OUT */ + pConcealmentInfo->concealState = ConcealState_FadeOut; + } + } + break; + + case ConcealState_FadeOut: + pConcealmentInfo->cntFadeFrames += 1; /* used to address the fade-out factors */ + if (pConcealmentInfo->cntValidFrames > pConcealCommonData->numMuteReleaseFrames) { + /* change to state FADE-IN */ + pConcealmentInfo->concealState = ConcealState_FadeIn; + pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData, + pConcealmentInfo->cntFadeFrames-1, + 0 /* FadeOut -> FadeIn */); + } else { + if (pConcealmentInfo->cntFadeFrames >= pConcealCommonData->numFadeOutFrames) { + /* change to state MUTE */ + pConcealmentInfo->concealState = ConcealState_Mute; + } + } + break; + + case ConcealState_Mute: + if (pConcealmentInfo->cntValidFrames > pConcealCommonData->numMuteReleaseFrames) { + /* change to state FADE-IN */ + pConcealmentInfo->concealState = ConcealState_FadeIn; + pConcealmentInfo->cntFadeFrames = pConcealCommonData->numFadeInFrames - 1; + } + break; + + case ConcealState_FadeIn: + pConcealmentInfo->cntFadeFrames -= 1; /* used to address the fade-in factors */ + if (frameOk) { + if (pConcealmentInfo->cntFadeFrames < 0) { + /* change to state OK */ + pConcealmentInfo->concealState = ConcealState_Ok; + } + } else { + /* change to state FADE-OUT */ + pConcealmentInfo->concealState = ConcealState_FadeOut; + pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData, + pConcealmentInfo->cntFadeFrames+1, + 1 /* FadeIn -> FadeOut */); + } + break; + + default: + FDK_ASSERT(0); + break; + } + } + break; + + case ConcealMethodInter: + case ConcealMethodTonal: + { + if (pConcealmentInfo->concealState != ConcealState_Ok) { + /* count the valid frames during concealment process */ + if ( pConcealmentInfo->prevFrameOk[1] || + (pConcealmentInfo->prevFrameOk[0] && !pConcealmentInfo->prevFrameOk[1] && frameOk) ) { + /* The frame is OK even if it can be estimated by the energy interpolation algorithm */ + pConcealmentInfo->cntValidFrames += 1; + } else { + pConcealmentInfo->cntValidFrames = 0; + } + } + + /* -- STATE MACHINE for energy interpolation -- */ + switch (pConcealmentInfo->concealState) + { + case ConcealState_Ok: + if (!(pConcealmentInfo->prevFrameOk[1] || + (pConcealmentInfo->prevFrameOk[0] && !pConcealmentInfo->prevFrameOk[1] && frameOk))) { + /* Fade out only if the energy interpolation algorithm can not be applied! */ + pConcealmentInfo->concealState = ConcealState_FadeOut; + pConcealmentInfo->cntFadeFrames = 0; + pConcealmentInfo->cntValidFrames = 0; + } + break; + + case ConcealState_Single: + pConcealmentInfo->concealState = ConcealState_Ok; + break; + + case ConcealState_FadeOut: + pConcealmentInfo->cntFadeFrames += 1; + + if (pConcealmentInfo->cntValidFrames > pConcealCommonData->numMuteReleaseFrames) { + /* change to state FADE-IN */ + pConcealmentInfo->concealState = ConcealState_FadeIn; + pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData, + pConcealmentInfo->cntFadeFrames-1, + 0 /* FadeOut -> FadeIn */); + } else { + if (pConcealmentInfo->cntFadeFrames >= pConcealCommonData->numFadeOutFrames) { + /* change to state MUTE */ + pConcealmentInfo->concealState = ConcealState_Mute; + } + } + break; + + case ConcealState_Mute: + if (pConcealmentInfo->cntValidFrames > pConcealCommonData->numMuteReleaseFrames) { + /* change to state FADE-IN */ + pConcealmentInfo->concealState = ConcealState_FadeIn; + pConcealmentInfo->cntFadeFrames = pConcealCommonData->numFadeInFrames - 1; + } + break; + + case ConcealState_FadeIn: + pConcealmentInfo->cntFadeFrames -= 1; /* used to address the fade-in factors */ + + if (frameOk || pConcealmentInfo->prevFrameOk[1]) { + if (pConcealmentInfo->cntFadeFrames < 0) { + /* change to state OK */ + pConcealmentInfo->concealState = ConcealState_Ok; + } + } else { + /* change to state FADE-OUT */ + pConcealmentInfo->concealState = ConcealState_FadeOut; + pConcealmentInfo->cntFadeFrames = findEquiFadeFrame( pConcealCommonData, + pConcealmentInfo->cntFadeFrames+1, + 1 /* FadeIn -> FadeOut */); + } + break; + } /* End switch(pConcealmentInfo->concealState) */ + } + break; + + default: + /* Don't need a state machine for other concealment methods. */ + break; + } + +} + + +/*! +\brief Randomizes the sign of the spectral data + + The function toggles the sign of the spectral data randomly. This is + useful to ensure the quality of the concealed frames. + +\return none + */ +static +void CConcealment_ApplyRandomSign (int randomPhase, + FIXP_DBL *spec, + int samplesPerFrame + ) +{ + int i; + USHORT packedSign=0; + + /* random table 512x16bit has been reduced to 512 packed sign bits = 32x16 bit */ + + /* read current packed sign word */ + packedSign = randomSign[randomPhase>>4]; + packedSign >>= (randomPhase&0xf); + + for (i = 0; i < samplesPerFrame ; i++) { + if ((randomPhase & 0xf) == 0) { + packedSign = randomSign[randomPhase>>4]; + } + + if (packedSign & 0x1) { + spec[i] = -spec[i]; + } + packedSign >>= 1; + + randomPhase = (randomPhase + 1) & (AAC_NF_NO_RANDOM_VAL - 1); + } +} + + +/*! + \brief Get fadeing factor for current concealment state. + + The function returns the factor used for fading that belongs to the current internal state. + + \return Fade factor + */ +FIXP_DBL + CConcealment_GetFadeFactor ( + CConcealmentInfo *hConcealmentInfo, + const int fPreviousFactor + ) +{ + FIXP_DBL fac = (FIXP_DBL)0; + + CConcealParams *pConcealCommonData = hConcealmentInfo->pConcealParams; + + if (hConcealmentInfo->pConcealParams->method > ConcealMethodMute) { + switch (hConcealmentInfo->concealState) { + default: + case ConcealState_Mute: + /* Nothing to do here */ + break; + case ConcealState_Ok: + fac = (FIXP_DBL)MAXVAL_DBL; + break; + case ConcealState_Single: + case ConcealState_FadeOut: + { + int idx = hConcealmentInfo->cntFadeFrames - ((fPreviousFactor != 0) ? 1 : 0); + fac = (idx < 0) ? (FIXP_DBL)MAXVAL_DBL : FX_SGL2FX_DBL(pConcealCommonData->fadeOutFactor[idx]); + } + break; + case ConcealState_FadeIn: + { + int idx = hConcealmentInfo->cntFadeFrames + ((fPreviousFactor != 0) ? 1 : 0); + fac = (idx >= hConcealmentInfo->pConcealParams->numFadeInFrames) ? (FIXP_DBL)0 : FX_SGL2FX_DBL(pConcealCommonData->fadeInFactor[idx]); + } + break; + } + } + + return (fac); +} + + +/*! + \brief Get fadeing factor for current concealment state. + + The function returns the state (ok or not) of the previous frame. + If called before the function CConcealment_Apply() set the fBeforeApply + flag to get the correct value. + + \return Frame OK flag of previous frame. + */ +int + CConcealment_GetLastFrameOk ( + CConcealmentInfo *hConcealmentInfo, + const int fBeforeApply + ) +{ + int prevFrameOk = 1; + + if (hConcealmentInfo != NULL) { + prevFrameOk = hConcealmentInfo->prevFrameOk[fBeforeApply & 0x1]; + } + + return prevFrameOk; +} + +/*! + \brief Get the number of delay frames introduced by concealment technique. + + \return Number of delay frames. + */ +UINT + CConcealment_GetDelay ( + CConcealParams *pConcealCommonData + ) +{ + UINT frameDelay = 0; + + if (pConcealCommonData != NULL) { + switch (pConcealCommonData->method) { + case ConcealMethodTonal: + case ConcealMethodInter: + frameDelay = 1; + break; + default: + break; + } + } + + return frameDelay; +} + diff --git a/libAACdec/src/conceal.h b/libAACdec/src/conceal.h new file mode 100644 index 0000000..95736b9 --- /dev/null +++ b/libAACdec/src/conceal.h @@ -0,0 +1,86 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: independent channel concealment + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef _CONCEAL_H_ +#define _CONCEAL_H_ + +#include "aacdecoder_lib.h" + +#include "channelinfo.h" + +#define AACDEC_CONCEAL_PARAM_NOT_SPECIFIED ( 0xFFFE ) + +void CConcealment_InitCommonData (CConcealParams *pConcealCommonData); + +void CConcealment_InitChannelData (CConcealmentInfo *hConcealmentInfo, + CConcealParams *pConcealCommonData, + int samplesPerFrame); + +CConcealmentMethod + CConcealment_GetMethod (CConcealParams *pConcealCommonData); + +UINT + CConcealment_GetDelay (CConcealParams *pConcealCommonData); + +AAC_DECODER_ERROR + CConcealment_SetParams (CConcealParams *concealParams, + int method, + int fadeOutSlope, + int fadeInSlope, + int muteRelease, + int comfNoiseLevel); + +CConcealmentState + CConcealment_GetState (CConcealmentInfo *hConcealmentInfo); + +AAC_DECODER_ERROR + CConcealment_SetAttenuation (CConcealParams *concealParams, + SHORT *fadeOutAttenuationVector, + SHORT *fadeInAttenuationVector); + +void CConcealment_Store (CConcealmentInfo *hConcealmentInfo, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo ); + +int CConcealment_Apply (CConcealmentInfo *hConcealmentInfo, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, + const SamplingRateInfo *pSamplingRateInfo, + const int samplesPerFrame, + const UCHAR lastLpdMode, + const int FrameOk, + const UINT flags); + +FIXP_DBL + CConcealment_GetFadeFactor (CConcealmentInfo *hConcealmentInfo, + const int fPreviousFactor); + +int CConcealment_GetLastFrameOk (CConcealmentInfo *hConcealmentInfo, + const int fBeforeApply); + +#endif /* #ifndef _CONCEAL_H_ */ diff --git a/libAACdec/src/conceal_types.h b/libAACdec/src/conceal_types.h new file mode 100644 index 0000000..5b5eb81 --- /dev/null +++ b/libAACdec/src/conceal_types.h @@ -0,0 +1,116 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Christian Griebel + Description: Error concealment structs and types + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef CONCEAL_TYPES_H +#define CONCEAL_TYPES_H + + + +#include "machine_type.h" +#include "common_fix.h" + +#include "rvlc_info.h" + + +#define CONCEAL_MAX_NUM_FADE_FACTORS ( 16 ) + + #define FIXP_CNCL FIXP_DBL + #define FL2FXCONST_CNCL FL2FXCONST_DBL + #define FX_DBL2FX_CNCL + #define FX_CNCL2FX_DBL + #define CNCL_FRACT_BITS DFRACT_BITS + +/* Warning: Do not ever change these values. */ +typedef enum +{ + ConcealMethodNone = -1, + ConcealMethodMute = 0, + ConcealMethodNoise = 1, + ConcealMethodInter = 2, + ConcealMethodTonal = 3 + +} CConcealmentMethod; + + +typedef enum +{ + ConcealState_Ok, + ConcealState_Single, + ConcealState_FadeIn, + ConcealState_Mute, + ConcealState_FadeOut + +} CConcealmentState; + + +typedef struct +{ + FIXP_SGL fadeOutFactor[CONCEAL_MAX_NUM_FADE_FACTORS]; + FIXP_SGL fadeInFactor [CONCEAL_MAX_NUM_FADE_FACTORS]; + + CConcealmentMethod method; + + int numFadeOutFrames; + int numFadeInFrames; + int numMuteReleaseFrames; + int comfortNoiseLevel; + +} CConcealParams; + + + +typedef struct +{ + CConcealParams *pConcealParams; + + FIXP_CNCL spectralCoefficient[1024]; + SHORT specScale[8]; + + INT iRandomPhase; + INT prevFrameOk[2]; + INT cntFadeFrames; + INT cntValidFrames; + + SHORT aRvlcPreviousScaleFactor[RVLC_MAX_SFB]; /* needed once per channel */ + UCHAR aRvlcPreviousCodebook[RVLC_MAX_SFB]; /* needed once per channel */ + SCHAR rvlcPreviousScaleFactorOK; + SCHAR rvlcPreviousBlockType; + + + SCHAR lastRenderMode; + + UCHAR windowShape; + UCHAR windowSequence; + UCHAR lastWinGrpLen; + + CConcealmentState concealState; + +} CConcealmentInfo; + + +#endif /* #ifndef CONCEAL_TYPES_H */ diff --git a/libAACdec/src/debug.h b/libAACdec/src/debug.h new file mode 100644 index 0000000..8f57d80 --- /dev/null +++ b/libAACdec/src/debug.h @@ -0,0 +1,35 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: debug output + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef DEBUG_H +#define DEBUG_H + +#include "machine_type.h" + + +#endif diff --git a/libAACdec/src/ldfiltbank.cpp b/libAACdec/src/ldfiltbank.cpp new file mode 100644 index 0000000..7a59926 --- /dev/null +++ b/libAACdec/src/ldfiltbank.cpp @@ -0,0 +1,148 @@ +/***************************************************************************\ + * + * (C) copyright Fraunhofer - IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + +* + * filename: ldfiltbank.c + * project : MPEG-4 Audio Decoder + * contents/description: low delay filterbank + * + * This software and/or program is protected by copyright law and + * international treaties. Any reproduction or distribution of this + * software and/or program, or any portion of it, may result in severe + * civil and criminal penalties, and will be prosecuted to the maximum + * extent possible under law. + * + * $Id$ + * +\***************************************************************************/ + +#include "ldfiltbank.h" + + +#include "aac_rom.h" +#include "dct.h" +#include "FDK_tools_rom.h" +#include "mdct.h" + +#define LDFB_HEADROOM 2 + +static void multE2_DinvF_fdk(INT_PCM *output, FIXP_DBL* x, const FIXP_WTB* fb, FIXP_DBL* z, const int N, const int stride) +{ + int i, scale; + + /* scale for FIXP_DBL -> INT_PCM conversion. */ + scale = (DFRACT_BITS - SAMPLE_BITS) - LDFB_HEADROOM; + + for(i=0;i> (-WTS2-1) ); + + z[N/2+i] = x[N/2-1-i] + ( fMultDiv2(z[N + i], fb[2*N + N/2 + i]) >> (-WTS2-1) ); + + tmp = ( fMultDiv2(z[N/2+i], fb[N+N/2-1-i]) + fMultDiv2(z[i], fb[N+N/2+i]) ) ; + +#if (SAMPLE_BITS <= 16) + FDK_ASSERT( (-WTS1-1 + scale) >= 0); + output[(N*3/4-1-i)*stride] = (INT_PCM)SATURATE_RIGHT_SHIFT(tmp, -WTS1-1 + scale, SAMPLE_BITS); +#else + FDK_ASSERT( (WTS1+1 - scale) >= 0); + output[(N*3/4-1-i)*stride] = (INT_PCM)SATURATE_LEFT_SHIFT(tmp, WTS1+1 - scale, SAMPLE_BITS); +#endif + + z[i] = z0; + z[N + i] = z2; + } + + for(i=N/4;i> (-WTS2-1) ); + + z[N/2+i] = x[N/2-1-i] + ( fMultDiv2(z[N + i], fb[2*N + N/2 + i]) >> (-WTS2-1) ); + + tmp0 = ( fMultDiv2(z[N/2+i], fb[N/2-1-i]) + fMultDiv2(z[i], fb[N/2+i]) ) ; + tmp1 = ( fMultDiv2(z[N/2+i], fb[N+N/2-1-i]) + fMultDiv2(z[i], fb[N+N/2+i]) ) ; + +#if (SAMPLE_BITS <= 16) + FDK_ASSERT( (-WTS0-1 + scale) >= 0); + output[(i-N/4)*stride] = (INT_PCM)SATURATE_RIGHT_SHIFT(tmp0, -WTS0-1 + scale, SAMPLE_BITS); + output[(N*3/4-1-i)*stride] = (INT_PCM)SATURATE_RIGHT_SHIFT(tmp1, -WTS1-1 + scale, SAMPLE_BITS); +#else + FDK_ASSERT( (WTS0+1 - scale) >= 0); + output[(i-N/4)*stride] = (INT_PCM)SATURATE_LEFT_SHIFT(tmp0, WTS0+1 - scale, SAMPLE_BITS); + output[(N*3/4-1-i)*stride] = (INT_PCM)SATURATE_LEFT_SHIFT(tmp1, WTS1+1 - scale, SAMPLE_BITS); +#endif + z[i] = z0; + z[N + i] = z2; + } + + /* Exchange quarter parts of x to bring them in the "right" order */ + for(i=0;i= 0); + output[(N*3/4 + i)*stride] = (INT_PCM)SATURATE_RIGHT_SHIFT(tmp0, -WTS0-1 + scale, SAMPLE_BITS); +#else + FDK_ASSERT( (WTS0+1 - scale) >= 0); + output[(N*3/4 + i)*stride] = (INT_PCM)SATURATE_LEFT_SHIFT(tmp0, WTS0+1 - scale, SAMPLE_BITS); +#endif + } +} + +int InvMdctTransformLowDelay_fdk (FIXP_DBL *mdctData, const int mdctData_e, INT_PCM *output, FIXP_DBL *fs_buffer, const int stride, const int N) { + + const FIXP_WTB *coef; + FIXP_DBL gain = (FIXP_DBL)0; + int scale = mdctData_e + MDCT_OUT_HEADROOM - LDFB_HEADROOM; /* The LDFB_HEADROOM is compensated inside multE2_DinvF_fdk() below */ + + /* Select LD window slope */ + if (N == 512) + coef = (FIXP_WTB*)LowDelaySynthesis512; + else + coef = (FIXP_WTB*)LowDelaySynthesis480; + + /* + Apply exponent and 1/N factor. + Note: "scale" is off by one because for LD_MDCT the window length is twice + the window length of a regular MDCT. This is corrected inside multE2_DinvF_fdk(). + Refer to ISO/IEC 14496-3:2009 page 277, chapter 4.6.20.2 "Low Delay Window". + */ + imdct_gain(&gain, &scale, N); + + dct_IV(mdctData, N, &scale); + + if (gain != (FIXP_DBL)0) { + scaleValuesWithFactor(mdctData, gain, N, scale); + } else { + scaleValues(mdctData, N, scale); + } + + /* Since all exponent and factors have been applied, current exponent is zero. */ + multE2_DinvF_fdk(output, mdctData, coef, fs_buffer, N, stride); + + return (1); +} + + + + diff --git a/libAACdec/src/ldfiltbank.h b/libAACdec/src/ldfiltbank.h new file mode 100644 index 0000000..2eee093 --- /dev/null +++ b/libAACdec/src/ldfiltbank.h @@ -0,0 +1,48 @@ +/***************************************************************************\ + * + * (C) copyright Fraunhofer - IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + +* + * filename: ldfiltbank.h + * project : MPEG-4 Audio Decoder + * contents/description: low delay filterbank interface + * + * This software and/or program is protected by copyright law and + * international treaties. Any reproduction or distribution of this + * software and/or program, or any portion of it, may result in severe + * civil and criminal penalties, and will be prosecuted to the maximum + * extent possible under law. + * + * $Header: /home/cvs/amm/menc/mp4objdec/src/aac_eld/ldfiltbank.h,v 1.3 2006/11/07 22:21:27 haertlml Exp $ + * +\***************************************************************************/ + +#ifndef _LDFILTBANK_H +#define _LDFILTBANK_H + +#include "common_fix.h" + + +int InvMdctTransformLowDelay_fdk ( + FIXP_DBL *mdctdata_m, + const int mdctdata_e, + INT_PCM *mdctOut, + FIXP_DBL *fs_buffer, + const int stride, + const int frameLength + ); + + +#endif diff --git a/libAACdec/src/overlapadd.h b/libAACdec/src/overlapadd.h new file mode 100644 index 0000000..b301888 --- /dev/null +++ b/libAACdec/src/overlapadd.h @@ -0,0 +1,43 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef OVERLAPADD_H +#define OVERLAPADD_H + +#include "common_fix.h" + +#define OverlapBufferSize (1024*2) + +typedef FIXP_DBL SPECTRUM[1024]; +typedef FIXP_DBL * SPECTRAL_PTR; + +#define SPEC_LONG(ptr) (ptr) +#define SPEC(ptr,w,gl) ((ptr)+((w)*(gl))) + + +#endif /* #ifndef OVERLAPADD_H */ diff --git a/libAACdec/src/pulsedata.cpp b/libAACdec/src/pulsedata.cpp new file mode 100644 index 0000000..062437a --- /dev/null +++ b/libAACdec/src/pulsedata.cpp @@ -0,0 +1,96 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: pulse data tool + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "pulsedata.h" + + +#include "channelinfo.h" + + +INT CPulseData_Read( + HANDLE_FDK_BITSTREAM bs, + CPulseData *const PulseData, + const SHORT *sfb_startlines, + const void *pIcsInfo, + const SHORT frame_length + ) +{ + int i, k=0; + const UINT MaxSfBands = GetScaleFactorBandsTransmitted((CIcsInfo*)pIcsInfo); + + /* reset pulse data flag */ + PulseData->PulseDataPresent = 0; + + if ((PulseData->PulseDataPresent = (UCHAR) FDKreadBit(bs)) != 0) { + if (!IsLongBlock((CIcsInfo*)pIcsInfo)) { + return AAC_DEC_DECODE_FRAME_ERROR; + } + + PulseData->NumberPulse = (UCHAR) FDKreadBits(bs,2); + PulseData->PulseStartBand = (UCHAR) FDKreadBits(bs,6); + + if (PulseData->PulseStartBand >= MaxSfBands) { + return AAC_DEC_DECODE_FRAME_ERROR; + } + + k = sfb_startlines[PulseData->PulseStartBand]; + + for (i=0; i<=PulseData->NumberPulse; i++) { + PulseData->PulseOffset[i] = (UCHAR) FDKreadBits(bs,5); + PulseData->PulseAmp[i] = (UCHAR) FDKreadBits(bs,4); + k += PulseData->PulseOffset[i]; + } + + if (k >= frame_length) { + return AAC_DEC_DECODE_FRAME_ERROR; + } + } + + + return 0; +} + +void CPulseData_Apply(CPulseData *PulseData, /*!< pointer to pulse data side info */ + const short *pScaleFactorBandOffsets, /*!< pointer to scalefactor band offsets */ + FIXP_DBL *coef) /*!< pointer to spectrum */ +{ + int i,k; + + if (PulseData->PulseDataPresent) + { + k = pScaleFactorBandOffsets[PulseData->PulseStartBand]; + + for (i=0; i<=PulseData->NumberPulse; i++) + { + k += PulseData->PulseOffset[i]; + if (coef [k] > (FIXP_DBL)0) coef[k] += (FIXP_DBL)(int)PulseData->PulseAmp[i]; + else coef[k] -= (FIXP_DBL)(int)PulseData->PulseAmp[i]; + } + } +} + diff --git a/libAACdec/src/pulsedata.h b/libAACdec/src/pulsedata.h new file mode 100644 index 0000000..075a0c4 --- /dev/null +++ b/libAACdec/src/pulsedata.h @@ -0,0 +1,83 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: pulse data tool + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef PULSEDATA_H +#define PULSEDATA_H + + + +#include "common_fix.h" +#include "FDK_bitstream.h" + +#define N_MAX_LINES 4 + +typedef struct +{ + UCHAR PulseDataPresent; + UCHAR NumberPulse; + UCHAR PulseStartBand; + UCHAR PulseOffset[N_MAX_LINES]; + UCHAR PulseAmp[N_MAX_LINES]; +} CPulseData; + +/** + * \brief Read pulse data from bitstream + * + * The function reads the elements for pulse data from + * the bitstream. + * + * \param bs bit stream handle data source. + * \param PulseData pointer to a CPulseData were the decoded data is stored into. + * \param MaxSfBands max number of scale factor bands. + * \return 0 on success, != 0 on parse error. + */ +INT CPulseData_Read( + const HANDLE_FDK_BITSTREAM bs, + CPulseData *const PulseData, + const SHORT *sfb_startlines, + const void *pIcsInfo, + const SHORT frame_length + ); + +/** + * \brief Apply pulse data to spectral lines + * + * The function applies the pulse data to the + * specified spectral lines. + * + * \param PulseData pointer to the previously decoded pulse data. + * \param pScaleFactorBandOffsets scale factor band line offset table. + * \param coef pointer to the spectral data were pulse data should be applied to. + * \return none +*/ +void CPulseData_Apply(CPulseData *PulseData, + const short *pScaleFactorBandOffsets, + FIXP_DBL *coef); + + +#endif /* #ifndef PULSEDATA_H */ diff --git a/libAACdec/src/rvlc.cpp b/libAACdec/src/rvlc.cpp new file mode 100644 index 0000000..f2c6203 --- /dev/null +++ b/libAACdec/src/rvlc.cpp @@ -0,0 +1,1157 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +****************************************************************************/ +/*! + \file + \brief RVLC Decoder + \author Robert Weidner +*/ + +#include "rvlc.h" + + +#include "block.h" + +#include "aac_rom.h" +#include "rvlcbit.h" +#include "rvlcconceal.h" +#include "aacdec_hcr.h" + +/*--------------------------------------------------------------------------------------------- + function: rvlcInit + + description: init RVLC by data from channelinfo, which was decoded previously and + set up pointers +----------------------------------------------------------------------------------------------- + input: - pointer rvlc structure + - pointer channel info structure + - pointer bitstream structure +----------------------------------------------------------------------------------------------- + return: - +-------------------------------------------------------------------------------------------- */ + +static +void rvlcInit (CErRvlcInfo *pRvlc, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + HANDLE_FDK_BITSTREAM bs) +{ + /* RVLC common initialization part 2 of 2 */ + SHORT *pScfEsc = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfEsc; + SHORT *pScfFwd = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd; + SHORT *pScfBwd = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd; + SHORT *pScaleFactor = pAacDecoderChannelInfo->pDynData->aScaleFactor; + int bnds; + + pAacDecoderChannelInfo->pDynData->specificTo.aac.rvlcIntensityUsed = 0; + + pRvlc->numDecodedEscapeWordsEsc = 0; + pRvlc->numDecodedEscapeWordsFwd = 0; + pRvlc->numDecodedEscapeWordsBwd = 0; + + pRvlc->intensity_used = 0; + pRvlc->errorLogRvlc = 0; + + pRvlc->conceal_max = CONCEAL_MAX_INIT; + pRvlc->conceal_min = CONCEAL_MIN_INIT; + + pRvlc->conceal_max_esc = CONCEAL_MAX_INIT; + pRvlc->conceal_min_esc = CONCEAL_MIN_INIT; + + pRvlc->pHuffTreeRvlcEscape = aHuffTreeRvlcEscape; + pRvlc->pHuffTreeRvlCodewds = aHuffTreeRvlCodewds; + + /* init scf arrays (for savety (in case of there are only zero codebooks)) */ + for (bnds = 0; bnds < RVLC_MAX_SFB; bnds++) { + pScfFwd[bnds] = 0; + pScfBwd[bnds] = 0; + pScfEsc[bnds] = 0; + pScaleFactor[bnds] = 0; + } + + /* set base bitstream ptr to the RVL-coded part (start of RVLC data (ESC 2)) */ + FDKsyncCache (bs); + + pRvlc->bitstreamIndexRvlFwd = FDKgetBitCnt(bs); /* first bit within RVL coded block as start address for forward decoding */ + pRvlc->bitstreamIndexRvlBwd = FDKgetBitCnt(bs) + pRvlc->length_of_rvlc_sf - 1; /* last bit within RVL coded block as start address for backward decoding */ + + /* skip RVLC-bitstream-part -- pointing now to escapes (if present) or to TNS data (if present) */ + FDKpushFor (bs, pRvlc->length_of_rvlc_sf); + + if ( pRvlc->sf_escapes_present != 0 ) { + + /* locate internal bitstream ptr at escapes (which is the second part) */ + FDKsyncCache (bs); + pRvlc->bitstreamIndexEsc = FDKgetBitCnt(bs); + + /* skip escapeRVLC-bitstream-part -- pointing to TNS data (if present) to make decoder continue */ + /* decoding of RVLC should work despite this second pushFor during initialization because */ + /* bitstream initialization is valid for both ESC2 data parts (RVL-coded values and ESC-coded values) */ + FDKpushFor (bs, pRvlc->length_of_rvlc_escapes); + } + +#if VERBOSE_RVLC_INIT + DebugOutputInit(pRvlc,pAacDecoderChannelInfo); +#endif +} + + +/*--------------------------------------------------------------------------------------------- + function: rvlcCheckIntensityCb + + description: Check if a intensity codebook is used in the current channel. +----------------------------------------------------------------------------------------------- + input: - pointer rvlc structure + - pointer channel info structure +----------------------------------------------------------------------------------------------- + output: - intensity_used: 0 no intensity codebook is used + 1 intensity codebook is used +----------------------------------------------------------------------------------------------- + return: - +-------------------------------------------------------------------------------------------- */ + +static +void rvlcCheckIntensityCb (CErRvlcInfo *pRvlc, + CAacDecoderChannelInfo *pAacDecoderChannelInfo) +{ + int group, band, bnds; + + pRvlc->intensity_used = 0; + + for (group=0; group < pRvlc->numWindowGroups; group++) { + for (band=0; band < pRvlc->maxSfbTransmitted; band++) { + bnds = 16*group+band; + if ( (pAacDecoderChannelInfo->pDynData->aCodeBook[bnds] == INTENSITY_HCB) || (pAacDecoderChannelInfo->pDynData->aCodeBook[bnds] == INTENSITY_HCB2) ) { + pRvlc->intensity_used = 1; + break; + } + } + } +} + + +/*--------------------------------------------------------------------------------------------- + function: rvlcDecodeEscapeWord + + description: Decode a huffman coded RVLC Escape-word. This value is part of a DPCM coded + scalefactor. +----------------------------------------------------------------------------------------------- + input: - pointer rvlc structure +----------------------------------------------------------------------------------------------- + return: - a single RVLC-Escape value which had to be applied to a DPCM value (which + has a absolute value of 7) +-------------------------------------------------------------------------------------------- */ + +static +SCHAR rvlcDecodeEscapeWord (CErRvlcInfo *pRvlc, + HANDLE_FDK_BITSTREAM bs) +{ + int i; + SCHAR value; + UCHAR carryBit; + UINT treeNode; + UINT branchValue; + UINT branchNode; + + USHORT* pBitstreamIndexEsc; + const UINT* pEscTree; + + pEscTree = pRvlc->pHuffTreeRvlcEscape; + pBitstreamIndexEsc = &(pRvlc->bitstreamIndexEsc); + treeNode = *pEscTree; /* init at starting node */ + + for (i=MAX_LEN_RVLC_ESCAPE_WORD-1; i >= 0; i--) { + carryBit = rvlcReadBitFromBitstream(bs, /* get next bit */ + pBitstreamIndexEsc, + FWD); + + CarryBitToBranchValue(carryBit, /* huffman decoding, do a single step in huffman decoding tree */ + treeNode, + &branchValue, + &branchNode); + + if ((branchNode & TEST_BIT_10) == TEST_BIT_10) { /* test bit 10 ; if set --> a RVLC-escape-word is completely decoded */ + value = (SCHAR) branchNode & CLR_BIT_10; + pRvlc->length_of_rvlc_escapes -= (MAX_LEN_RVLC_ESCAPE_WORD - i); + + if (pRvlc->length_of_rvlc_escapes < 0) { + pRvlc->errorLogRvlc |= RVLC_ERROR_ALL_ESCAPE_WORDS_INVALID; + value = -1; + } + + return value; + } + else { + treeNode = *(pEscTree + branchValue); /* update treeNode for further step in decoding tree */ + } + } + + pRvlc->errorLogRvlc |= RVLC_ERROR_ALL_ESCAPE_WORDS_INVALID; + + return -1; /* should not be reached */ +} + + +/*--------------------------------------------------------------------------------------------- + function: rvlcDecodeEscapes + + description: Decodes all huffman coded RVLC Escape Words. + Here a difference to the pseudo-code-implementation from standard can be + found. A while loop (and not two nested for loops) is used for two reasons: + + 1. The plain huffman encoded escapes are decoded before the RVL-coded + scalefactors. Therefore the escapes are present in the second step + when decoding the RVL-coded-scalefactor values in forward and + backward direction. + + When the RVL-coded scalefactors are decoded and there a escape is + needed, then it is just taken out of the array in ascending order. + + 2. It's faster. +----------------------------------------------------------------------------------------------- + input: - pointer rvlc structure + - handle to FDK bitstream +----------------------------------------------------------------------------------------------- + return: - 0 ok the decoded escapes seem to be valid + - 1 error there was a error detected during decoding escapes + --> all escapes are invalid +-------------------------------------------------------------------------------------------- */ + +static +void rvlcDecodeEscapes (CErRvlcInfo *pRvlc, + SHORT *pEsc, + HANDLE_FDK_BITSTREAM bs) +{ + SCHAR escWord; + SCHAR escCnt=0; + SHORT* pEscBitCntSum; + + pEscBitCntSum = &(pRvlc->length_of_rvlc_escapes); + + /* Decode all RVLC-Escape words with a plain Huffman-Decoder */ + while ( *pEscBitCntSum > 0 ) { + escWord = rvlcDecodeEscapeWord(pRvlc, bs); + + if (escWord >= 0) { + + pEsc[escCnt] = escWord; + escCnt++; + } + else { + pRvlc->errorLogRvlc |= RVLC_ERROR_ALL_ESCAPE_WORDS_INVALID; + pRvlc->numDecodedEscapeWordsEsc = escCnt; + + return; + } + } /* all RVLC escapes decoded */ + + pRvlc->numDecodedEscapeWordsEsc = escCnt; +} + + +/*--------------------------------------------------------------------------------------------- + function: decodeRVLCodeword + + description: Decodes a RVL-coded dpcm-word (-part). +----------------------------------------------------------------------------------------------- + input: - FDK bitstream handle + - pointer rvlc structure +----------------------------------------------------------------------------------------------- + return: - a dpcm value which is within range [0,1,..,14] in case of no errors. + The offset of 7 must be subtracted to get a valid dpcm scalefactor value. + In case of errors a forbidden codeword is detected --> returning -1 +-------------------------------------------------------------------------------------------- */ + +SCHAR decodeRVLCodeword (HANDLE_FDK_BITSTREAM bs, CErRvlcInfo *pRvlc) +{ + int i; + SCHAR value; + UCHAR carryBit; + UINT branchValue; + UINT branchNode; + + const UINT *pRvlCodeTree = pRvlc->pHuffTreeRvlCodewds; + UCHAR direction = pRvlc->direction; + USHORT *pBitstrIndxRvl = pRvlc->pBitstrIndxRvl_RVL; + UINT treeNode = *pRvlCodeTree; + + for (i=MAX_LEN_RVLC_CODE_WORD-1; i >= 0; i--) { + carryBit = rvlcReadBitFromBitstream(bs, /* get next bit */ + pBitstrIndxRvl, + direction); + + CarryBitToBranchValue(carryBit, /* huffman decoding, do a single step in huffman decoding tree */ + treeNode, + &branchValue, + &branchNode); + + if ((branchNode & TEST_BIT_10) == TEST_BIT_10) { /* test bit 10 ; if set --> a RVLC-codeword is completely decoded */ + value = (SCHAR) (branchNode & CLR_BIT_10); + *pRvlc->pRvlBitCnt_RVL -= (MAX_LEN_RVLC_CODE_WORD - i); + + /* check available bits for decoding */ + if (*pRvlc->pRvlBitCnt_RVL < 0) { + if (direction == FWD) { + pRvlc->errorLogRvlc |= RVLC_ERROR_RVL_SUM_BIT_COUNTER_BELOW_ZERO_FWD; } + else { + pRvlc->errorLogRvlc |= RVLC_ERROR_RVL_SUM_BIT_COUNTER_BELOW_ZERO_BWD; } + value = -1; /* signalize an error in return value, because too many bits was decoded */ + } + + /* check max value of dpcm value */ + if (value > MAX_ALLOWED_DPCM_INDEX) { + if (direction == FWD) { + pRvlc->errorLogRvlc |= RVLC_ERROR_FORBIDDEN_CW_DETECTED_FWD; + } + else { + pRvlc->errorLogRvlc |= RVLC_ERROR_FORBIDDEN_CW_DETECTED_BWD; + } + value = -1; /* signalize an error in return value, because a forbidden cw was detected*/ + } + + return value; /* return a dpcm value with offset +7 or an error status */ + } + else { + treeNode = *(pRvlCodeTree + branchValue); /* update treeNode for further step in decoding tree */ + } + } + + return -1; +} + + +/*--------------------------------------------------------------------------------------------- + function: rvlcDecodeForward + + description: Decode RVL-coded codewords in forward direction. +----------------------------------------------------------------------------------------------- + input: - pointer rvlc structure + - pointer channel info structure + - handle to FDK bitstream +----------------------------------------------------------------------------------------------- + return: - +-------------------------------------------------------------------------------------------- */ + +static +void rvlcDecodeForward (CErRvlcInfo *pRvlc, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + HANDLE_FDK_BITSTREAM bs) +{ + int band = 0; + int group = 0; + int bnds = 0; + + SHORT dpcm; + + SHORT factor = pAacDecoderChannelInfo->pDynData->RawDataInfo.GlobalGain - SF_OFFSET; + SHORT position = - SF_OFFSET; + SHORT noisenrg = pAacDecoderChannelInfo->pDynData->RawDataInfo.GlobalGain - SF_OFFSET - 90 - 256; + + SHORT* pScfFwd = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd; + SHORT* pScfEsc = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfEsc; + UCHAR* pEscFwdCnt = &(pRvlc->numDecodedEscapeWordsFwd); + + pRvlc->pRvlBitCnt_RVL = &(pRvlc->length_of_rvlc_sf_fwd); + pRvlc->pBitstrIndxRvl_RVL = &(pRvlc->bitstreamIndexRvlFwd); + + *pEscFwdCnt = 0; + pRvlc->direction = FWD; + pRvlc->noise_used = 0; + pRvlc->sf_used = 0; + pRvlc->lastScf = 0; + pRvlc->lastNrg = 0; + pRvlc->lastIs = 0; + + rvlcCheckIntensityCb(pRvlc,pAacDecoderChannelInfo); + + /* main loop fwd long */ + for (group=0; group < pRvlc->numWindowGroups; group++) { + for (band=0; band < pRvlc->maxSfbTransmitted; band++) { + bnds = 16*group+band; + + switch (pAacDecoderChannelInfo->pDynData->aCodeBook[bnds]) { + + case ZERO_HCB : + pScfFwd[bnds] = 0; + break; + + case INTENSITY_HCB2 : + case INTENSITY_HCB : + /* store dpcm_is_position */ + dpcm = decodeRVLCodeword(bs, pRvlc); + if ( dpcm < 0 ) { + pRvlc->conceal_max = bnds; + return; + } + dpcm -= TABLE_OFFSET; + if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) { + if (pRvlc->length_of_rvlc_escapes) { + pRvlc->conceal_max = bnds; + return; + } + else { + if (dpcm == MIN_RVL) { + dpcm -= *pScfEsc++; + } + else { + dpcm += *pScfEsc++; + } + (*pEscFwdCnt)++; + if (pRvlc->conceal_max_esc == CONCEAL_MAX_INIT) { + pRvlc->conceal_max_esc = bnds; + } + } + } + position += dpcm; + pScfFwd[bnds] = position; + pRvlc->lastIs = position; + break; + + case NOISE_HCB : + if (pRvlc->noise_used == 0) { + pRvlc->noise_used = 1; + pRvlc->first_noise_band = bnds; + noisenrg += pRvlc->dpcm_noise_nrg; + pScfFwd[bnds] = 100 + noisenrg; + pRvlc->lastNrg = noisenrg; + } + else { + dpcm = decodeRVLCodeword(bs, pRvlc); + if ( dpcm < 0 ) { + pRvlc->conceal_max = bnds; + return; + } + dpcm -= TABLE_OFFSET; + if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) { + if (pRvlc->length_of_rvlc_escapes) { + pRvlc->conceal_max = bnds; + return; + } + else { + if (dpcm == MIN_RVL) { + dpcm -= *pScfEsc++; + } + else { + dpcm += *pScfEsc++; + } + (*pEscFwdCnt)++; + if (pRvlc->conceal_max_esc == CONCEAL_MAX_INIT) { + pRvlc->conceal_max_esc = bnds; + } + } + } + noisenrg += dpcm; + pScfFwd[bnds] = 100 + noisenrg; + pRvlc->lastNrg = noisenrg; + } + pAacDecoderChannelInfo->data.aac.PnsData.pnsUsed[bnds] = 1; + break ; + + default : + pRvlc->sf_used = 1; + dpcm = decodeRVLCodeword(bs, pRvlc); + if ( dpcm < 0 ) { + pRvlc->conceal_max = bnds; + return; + } + dpcm -= TABLE_OFFSET; + if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) { + if (pRvlc->length_of_rvlc_escapes) { + pRvlc->conceal_max = bnds; + return; + } + else { + if (dpcm == MIN_RVL) { + dpcm -= *pScfEsc++; } + else { + dpcm += *pScfEsc++; + } + (*pEscFwdCnt)++; + if (pRvlc->conceal_max_esc == CONCEAL_MAX_INIT) { + pRvlc->conceal_max_esc = bnds; + } + } + } + factor += dpcm; + pScfFwd[bnds] = factor; + pRvlc->lastScf = factor; + break; + } + } + } + + /* postfetch fwd long */ + if (pRvlc->intensity_used) { + dpcm = decodeRVLCodeword(bs, pRvlc); /* dpcm_is_last_position */ + if ( dpcm < 0 ) { + pRvlc->conceal_max = bnds; + return; + } + dpcm -= TABLE_OFFSET; + if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) { + if (pRvlc->length_of_rvlc_escapes) { + pRvlc->conceal_max = bnds; + return; + } + else { + if (dpcm == MIN_RVL) { + dpcm -= *pScfEsc++; + } + else { + dpcm += *pScfEsc++; + } + (*pEscFwdCnt)++; + if (pRvlc->conceal_max_esc == CONCEAL_MAX_INIT) { + pRvlc->conceal_max_esc = bnds; + } + } + } + pRvlc->dpcm_is_last_position = dpcm; + } +} + + +/*--------------------------------------------------------------------------------------------- + function: rvlcDecodeBackward + + description: Decode RVL-coded codewords in backward direction. +----------------------------------------------------------------------------------------------- + input: - pointer rvlc structure + - pointer channel info structure + - handle FDK bitstream +----------------------------------------------------------------------------------------------- + return: - +-------------------------------------------------------------------------------------------- */ + +static +void rvlcDecodeBackward (CErRvlcInfo *pRvlc, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + HANDLE_FDK_BITSTREAM bs) +{ + SHORT band, group, dpcm, offset; + SHORT bnds = pRvlc->maxSfbTransmitted-1; + + SHORT factor = pRvlc->rev_global_gain - SF_OFFSET; + SHORT position = pRvlc->dpcm_is_last_position - SF_OFFSET; + SHORT noisenrg = pRvlc->rev_global_gain + pRvlc->dpcm_noise_last_position - SF_OFFSET - 90 - 256; + + SHORT *pScfBwd = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd; + SHORT *pScfEsc = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfEsc; + UCHAR *pEscEscCnt = &(pRvlc->numDecodedEscapeWordsEsc); + UCHAR *pEscBwdCnt = &(pRvlc->numDecodedEscapeWordsBwd); + + pRvlc->pRvlBitCnt_RVL = &(pRvlc->length_of_rvlc_sf_bwd); + pRvlc->pBitstrIndxRvl_RVL = &(pRvlc->bitstreamIndexRvlBwd); + + *pEscBwdCnt = 0; + pRvlc->direction = BWD; + pScfEsc += *pEscEscCnt - 1; /* set pScfEsc to last entry */ + pRvlc->firstScf = 0; + pRvlc->firstNrg = 0; + pRvlc->firstIs = 0; + + /* prefetch long BWD */ + if (pRvlc->intensity_used) { + dpcm = decodeRVLCodeword(bs, pRvlc); /* dpcm_is_last_position */ + if ( dpcm < 0 ) { + pRvlc->dpcm_is_last_position = 0; + pRvlc->conceal_min = bnds; + return; + } + dpcm -= TABLE_OFFSET; + if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) { + if (pRvlc->length_of_rvlc_escapes) { + pRvlc->conceal_min = bnds; + return; + } + else { + if (dpcm == MIN_RVL) { + dpcm -= *pScfEsc--; + } + else { + dpcm += *pScfEsc--; + } + (*pEscBwdCnt)++; + if (pRvlc->conceal_min_esc == CONCEAL_MIN_INIT) { + pRvlc->conceal_min_esc = bnds; + } + } + } + pRvlc->dpcm_is_last_position = dpcm; + } + + /* main loop long BWD */ + for (group=pRvlc->numWindowGroups-1; group >= 0; group--) { + for (band=pRvlc->maxSfbTransmitted-1; band >= 0; band--) { + bnds = 16*group+band; + if ((band == 0) && (pRvlc->numWindowGroups != 1)) + offset = 16 - pRvlc->maxSfbTransmitted + 1; + else + offset = 1; + + switch (pAacDecoderChannelInfo->pDynData->aCodeBook[bnds]) { + + case ZERO_HCB : + pScfBwd[bnds] = 0; + break; + + case INTENSITY_HCB2 : + case INTENSITY_HCB : + /* store dpcm_is_position */ + dpcm = decodeRVLCodeword(bs, pRvlc); + if ( dpcm < 0 ) { + pScfBwd[bnds] = position; + pRvlc->conceal_min = FDKmax(0,bnds-offset); + return; + } + dpcm -= TABLE_OFFSET; + if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) { + if (pRvlc->length_of_rvlc_escapes) { + pScfBwd[bnds] = position; + pRvlc->conceal_min = FDKmax(0,bnds-offset); + return; + } + else { + if (dpcm == MIN_RVL) { + dpcm -= *pScfEsc--; + } + else { + dpcm += *pScfEsc--; + } + (*pEscBwdCnt)++; + if (pRvlc->conceal_min_esc == CONCEAL_MIN_INIT) { + pRvlc->conceal_min_esc = FDKmax(0,bnds-offset); + } + } + } + pScfBwd[bnds] = position; + position -= dpcm; + pRvlc->firstIs = position; + break; + + case NOISE_HCB : + if ( bnds == pRvlc->first_noise_band ) { + pScfBwd[bnds] = pRvlc->dpcm_noise_nrg + pAacDecoderChannelInfo->pDynData->RawDataInfo.GlobalGain - SF_OFFSET - 90 - 256; + pRvlc->firstNrg = pScfBwd[bnds]; + } + else { + dpcm = decodeRVLCodeword(bs, pRvlc); + if ( dpcm < 0 ) { + pScfBwd[bnds] = noisenrg; + pRvlc->conceal_min = FDKmax(0,bnds-offset); + return; + } + dpcm -= TABLE_OFFSET; + if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) { + if (pRvlc->length_of_rvlc_escapes) { + pScfBwd[bnds] = noisenrg; + pRvlc->conceal_min = FDKmax(0,bnds-offset); + return; + } + else { + if (dpcm == MIN_RVL) { + dpcm -= *pScfEsc--; + } + else { + dpcm += *pScfEsc--; + } + (*pEscBwdCnt)++; + if (pRvlc->conceal_min_esc == CONCEAL_MIN_INIT) { + pRvlc->conceal_min_esc = FDKmax(0,bnds-offset); + } + } + } + pScfBwd[bnds] = noisenrg; + noisenrg -= dpcm; + pRvlc->firstNrg = noisenrg; + } + break ; + + default : + dpcm = decodeRVLCodeword(bs, pRvlc); + if ( dpcm < 0 ) { + pScfBwd[bnds] = factor; + pRvlc->conceal_min = FDKmax(0,bnds-offset); + return; + } + dpcm -= TABLE_OFFSET; + if ((dpcm == MIN_RVL) || (dpcm == MAX_RVL)) { + if (pRvlc->length_of_rvlc_escapes) { + pScfBwd[bnds] = factor; + pRvlc->conceal_min = FDKmax(0,bnds-offset); + return; + } + else { + if (dpcm == MIN_RVL) { + dpcm -= *pScfEsc--; + } + else { + dpcm += *pScfEsc--; + } + (*pEscBwdCnt)++; + if (pRvlc->conceal_min_esc == CONCEAL_MIN_INIT) { + pRvlc->conceal_min_esc = FDKmax(0,bnds-offset); + } + } + } + pScfBwd[bnds] = factor; + factor -= dpcm; + pRvlc->firstScf = factor; + break; + } + } + } +} + + +/*--------------------------------------------------------------------------------------------- + function: rvlcFinalErrorDetection + + description: Call RVLC concealment if error was detected in decoding process +----------------------------------------------------------------------------------------------- + input: - pointer rvlc structure + - pointer channel info structure +----------------------------------------------------------------------------------------------- + return: - +-------------------------------------------------------------------------------------------- */ + +static +void rvlcFinalErrorDetection (CAacDecoderChannelInfo *pAacDecoderChannelInfo, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo) +{ + CErRvlcInfo *pRvlc = &pAacDecoderChannelInfo->pComData->overlay.aac.erRvlcInfo; + UCHAR ErrorStatusComplete = 0; + UCHAR ErrorStatusLengthFwd = 0; + UCHAR ErrorStatusLengthBwd = 0; + UCHAR ErrorStatusLengthEscapes = 0; + UCHAR ErrorStatusFirstScf = 0; + UCHAR ErrorStatusLastScf = 0; + UCHAR ErrorStatusFirstNrg = 0; + UCHAR ErrorStatusLastNrg = 0; + UCHAR ErrorStatusFirstIs = 0; + UCHAR ErrorStatusLastIs = 0; + UCHAR ErrorStatusForbiddenCwFwd = 0; + UCHAR ErrorStatusForbiddenCwBwd = 0; + UCHAR ErrorStatusNumEscapesFwd = 0; + UCHAR ErrorStatusNumEscapesBwd = 0; + UCHAR ConcealStatus = 1; + UCHAR currentBlockType; /* short: 0, not short: 1*/ + +#if VERBOSE_RVLC_OUTPUT + CHAR Strategy[60]="No"; + SHORT conceal_max; + SHORT conceal_min; +#endif + + pAacDecoderChannelInfo->pDynData->specificTo.aac.rvlcCurrentScaleFactorOK = 1; + + /* invalid escape words, bit counter unequal zero, forbidden codeword detected */ + if (pRvlc->errorLogRvlc & RVLC_ERROR_FORBIDDEN_CW_DETECTED_FWD) + ErrorStatusForbiddenCwFwd = 1; + + if (pRvlc->errorLogRvlc & RVLC_ERROR_FORBIDDEN_CW_DETECTED_BWD) + ErrorStatusForbiddenCwBwd = 1; + + /* bit counter forward unequal zero */ + if (pRvlc->length_of_rvlc_sf_fwd) + ErrorStatusLengthFwd = 1; + + /* bit counter backward unequal zero */ + if (pRvlc->length_of_rvlc_sf_bwd) + ErrorStatusLengthBwd = 1; + + /* bit counter escape sequences unequal zero */ + if (pRvlc->sf_escapes_present) + if (pRvlc->length_of_rvlc_escapes) + ErrorStatusLengthEscapes = 1; + + if (pRvlc->sf_used) { + /* first decoded scf does not match to global gain in backward direction */ + if (pRvlc->firstScf != (pAacDecoderChannelInfo->pDynData->RawDataInfo.GlobalGain - SF_OFFSET) ) + ErrorStatusFirstScf = 1; + + /* last decoded scf does not match to rev global gain in forward direction */ + if (pRvlc->lastScf != (pRvlc->rev_global_gain - SF_OFFSET) ) + ErrorStatusLastScf = 1; + } + + if (pRvlc->noise_used) { + /* first decoded nrg does not match to dpcm_noise_nrg in backward direction */ + if (pRvlc->firstNrg != (pAacDecoderChannelInfo->pDynData->RawDataInfo.GlobalGain + pRvlc->dpcm_noise_nrg - SF_OFFSET -90 - 256) ) + ErrorStatusFirstNrg = 1; + + /* last decoded nrg does not match to dpcm_noise_last_position in forward direction */ + if (pRvlc->lastNrg != (pRvlc->rev_global_gain + pRvlc->dpcm_noise_last_position - SF_OFFSET - 90 - 256) ) + ErrorStatusLastNrg = 1; + } + + if (pRvlc->intensity_used) { + /* first decoded is position does not match in backward direction */ + if (pRvlc->firstIs != (-SF_OFFSET) ) + ErrorStatusFirstIs = 1; + + /* last decoded is position does not match in forward direction */ + if (pRvlc->lastIs != (pRvlc->dpcm_is_last_position - SF_OFFSET) ) + ErrorStatusLastIs = 1; + } + + /* decoded escapes and used escapes in forward direction do not fit */ + if ((pRvlc->numDecodedEscapeWordsFwd != pRvlc->numDecodedEscapeWordsEsc) && (pRvlc->conceal_max == CONCEAL_MAX_INIT)) { + ErrorStatusNumEscapesFwd = 1; + } + + /* decoded escapes and used escapes in backward direction do not fit */ + if ((pRvlc->numDecodedEscapeWordsBwd != pRvlc->numDecodedEscapeWordsEsc) && (pRvlc->conceal_min == CONCEAL_MIN_INIT)) { + ErrorStatusNumEscapesBwd = 1; + } + +#if VERBOSE_RVLC_OUTPUT + conceal_max = pRvlc->conceal_max; + conceal_min = pRvlc->conceal_min; +#endif + + if ( ErrorStatusLengthEscapes + || ( + ( (pRvlc->conceal_max == CONCEAL_MAX_INIT) + && (pRvlc->numDecodedEscapeWordsFwd != pRvlc->numDecodedEscapeWordsEsc) + && (ErrorStatusLastScf || ErrorStatusLastNrg || ErrorStatusLastIs) ) + + && + + ( (pRvlc->conceal_min == CONCEAL_MIN_INIT) + && (pRvlc->numDecodedEscapeWordsBwd != pRvlc->numDecodedEscapeWordsEsc) + && (ErrorStatusFirstScf || ErrorStatusFirstNrg || ErrorStatusFirstIs) ) + ) + || ( (pRvlc->conceal_max == CONCEAL_MAX_INIT) + && ((pRvlc->rev_global_gain - SF_OFFSET - pRvlc->lastScf) < -15) + ) + || ( (pRvlc->conceal_min == CONCEAL_MIN_INIT) + && ((pAacDecoderChannelInfo->pDynData->RawDataInfo.GlobalGain - SF_OFFSET - pRvlc->firstScf) < -15) + ) + ) { + if ((pRvlc->conceal_max == CONCEAL_MAX_INIT) || (pRvlc->conceal_min == CONCEAL_MIN_INIT)) { + pRvlc->conceal_max = 0; + pRvlc->conceal_min = FDKmax(0, (pRvlc->numWindowGroups-1)*16+pRvlc->maxSfbTransmitted-1); + } + else { + pRvlc->conceal_max = FDKmin(pRvlc->conceal_max,pRvlc->conceal_max_esc); + pRvlc->conceal_min = FDKmax(pRvlc->conceal_min,pRvlc->conceal_min_esc); + } + } + + ErrorStatusComplete = ErrorStatusLastScf || ErrorStatusFirstScf || ErrorStatusLastNrg || ErrorStatusFirstNrg + || ErrorStatusLastIs || ErrorStatusFirstIs || ErrorStatusForbiddenCwFwd || ErrorStatusForbiddenCwBwd + || ErrorStatusLengthFwd || ErrorStatusLengthBwd || ErrorStatusLengthEscapes || ErrorStatusNumEscapesFwd + || ErrorStatusNumEscapesBwd; + + currentBlockType = (GetWindowSequence(&pAacDecoderChannelInfo->icsInfo) == EightShortSequence) ? 0 : 1; + + + if (!ErrorStatusComplete) { + int band; + int group; + int bnds; + int lastSfbIndex; + + lastSfbIndex = (pRvlc->numWindowGroups > 1) ? 16 : 64; + + for (group=0; group < pRvlc->numWindowGroups; group++) { + for (band=0; bandmaxSfbTransmitted; band++) { + bnds = 16*group+band; + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousScaleFactor[bnds] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds]; + } + } + + for (group=0; group < pRvlc->numWindowGroups; group++) + { + for (band=0; bandmaxSfbTransmitted; band++) { + bnds = 16*group+band; + pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds] = pAacDecoderChannelInfo->pDynData->aCodeBook[bnds]; + } + for (; band = 0 && bnds < RVLC_MAX_SFB); + pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds] = ZERO_HCB; + } + } + } + else { + int band; + int group; + + /* A single bit error was detected in decoding of dpcm values. It also could be an error with more bits in decoding + of escapes and dpcm values whereby an illegal codeword followed not directly after the corrupted bits but just + after decoding some more (wrong) scalefactors. Use the smaller scalefactor from forward decoding, backward decoding + and previous frame. */ + if ( ((pRvlc->conceal_min != CONCEAL_MIN_INIT) || (pRvlc->conceal_max != CONCEAL_MAX_INIT)) && (pRvlc->conceal_min <= pRvlc->conceal_max) + && (pAacDecoderStaticChannelInfo->concealmentInfo.rvlcPreviousBlockType == currentBlockType) && pAacDecoderStaticChannelInfo->concealmentInfo.rvlcPreviousScaleFactorOK + && pRvlc->sf_concealment && ConcealStatus ) + { + BidirectionalEstimation_UseScfOfPrevFrameAsReference (pAacDecoderChannelInfo, pAacDecoderStaticChannelInfo); + ConcealStatus=0; +#if VERBOSE_RVLC_OUTPUT + FDKstrcpy(Strategy,"Yes (BidirectionalEstimation_UseScfOfPrevFrameAsReference)"); +#endif + } + + /* A single bit error was detected in decoding of dpcm values. It also could be an error with more bits in decoding + of escapes and dpcm values whereby an illegal codeword followed not directly after the corrupted bits but just + after decoding some more (wrong) scalefactors. Use the smaller scalefactor from forward and backward decoding. */ + if ( (pRvlc->conceal_min <= pRvlc->conceal_max) && ((pRvlc->conceal_min != CONCEAL_MIN_INIT) || (pRvlc->conceal_max != CONCEAL_MAX_INIT)) + && !(pAacDecoderStaticChannelInfo->concealmentInfo.rvlcPreviousScaleFactorOK && pRvlc->sf_concealment && (pAacDecoderStaticChannelInfo->concealmentInfo.rvlcPreviousBlockType == currentBlockType)) + && ConcealStatus ) + { + BidirectionalEstimation_UseLowerScfOfCurrentFrame (pAacDecoderChannelInfo); + ConcealStatus=0; +#if VERBOSE_RVLC_OUTPUT + FDKstrcpy(Strategy,"Yes (BidirectionalEstimation_UseLowerScfOfCurrentFrame)"); +#endif + } + + /* No errors were detected in decoding of escapes and dpcm values however the first and last value + of a group (is,nrg,sf) is incorrect */ + if ( (pRvlc->conceal_min <= pRvlc->conceal_max) && ((ErrorStatusLastScf && ErrorStatusFirstScf) + || (ErrorStatusLastNrg && ErrorStatusFirstNrg) || (ErrorStatusLastIs && ErrorStatusFirstIs)) + && !(ErrorStatusForbiddenCwFwd || ErrorStatusForbiddenCwBwd || ErrorStatusLengthEscapes ) && ConcealStatus) + { + StatisticalEstimation (pAacDecoderChannelInfo); + ConcealStatus=0; +#if VERBOSE_RVLC_OUTPUT + FDKstrcpy(Strategy,"Yes (StatisticalEstimation)"); +#endif + } + + /* A error with more bits in decoding of escapes and dpcm values was detected. Use the smaller scalefactor from forward + decoding, backward decoding and previous frame. */ + if ( (pRvlc->conceal_min <= pRvlc->conceal_max) && pAacDecoderStaticChannelInfo->concealmentInfo.rvlcPreviousScaleFactorOK && pRvlc->sf_concealment + && (pAacDecoderStaticChannelInfo->concealmentInfo.rvlcPreviousBlockType == currentBlockType) && ConcealStatus ) + { + PredictiveInterpolation(pAacDecoderChannelInfo, pAacDecoderStaticChannelInfo); + ConcealStatus=0; +#if VERBOSE_RVLC_OUTPUT + FDKstrcpy(Strategy,"Yes (PredictiveInterpolation)"); +#endif + } + + /* Call frame concealment, because no better strategy was found. Setting the scalefactors to zero is done for debugging + purposes */ + if (ConcealStatus) { + for (group=0; group < pRvlc->numWindowGroups; group++) { + for (band=0; bandmaxSfbTransmitted; band++) { + pAacDecoderChannelInfo->pDynData->aScaleFactor[16*group+band] = 0; + } + } + pAacDecoderChannelInfo->pDynData->specificTo.aac.rvlcCurrentScaleFactorOK = 0; +#if VERBOSE_RVLC_OUTPUT + FDKstrcpy(Strategy,"Yes (FrameConcealment)"); +#endif + } + } + +#if VERBOSE_RVLC_OUTPUT + DebugOutputDistortedBitstreams(pRvlc,pAacDecoderChannelInfo,ErrorStatusLengthFwd,ErrorStatusLengthBwd, + ErrorStatusLengthEscapes,ErrorStatusFirstScf,ErrorStatusLastScf, + ErrorStatusFirstNrg,ErrorStatusLastNrg,ErrorStatusFirstIs,ErrorStatusLastIs, + ErrorStatusForbiddenCwFwd,ErrorStatusForbiddenCwBwd,ErrorStatusNumEscapesFwd, + ErrorStatusNumEscapesBwd,conceal_max,conceal_min,Strategy); +#endif +} + + +/*--------------------------------------------------------------------------------------------- + function: CRvlc_Read + + description: Read RVLC ESC1 data (side info) from bitstream. +----------------------------------------------------------------------------------------------- + input: - pointer rvlc structure + - pointer channel info structure + - pointer bitstream structure +----------------------------------------------------------------------------------------------- + return: - +-------------------------------------------------------------------------------------------- */ + +void CRvlc_Read ( + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + HANDLE_FDK_BITSTREAM bs) +{ + CErRvlcInfo *pRvlc = &pAacDecoderChannelInfo->pComData->overlay.aac.erRvlcInfo; + + int group,band; + + /* RVLC long specific initialization Init part 1 of 2 */ + pRvlc->numWindowGroups = GetWindowGroups(&pAacDecoderChannelInfo->icsInfo); + pRvlc->maxSfbTransmitted = GetScaleFactorBandsTransmitted(&pAacDecoderChannelInfo->icsInfo); + pRvlc->noise_used = 0; /* noise detection */ + pRvlc->dpcm_noise_nrg = 0; /* only for debugging */ + pRvlc->dpcm_noise_last_position = 0; /* only for debugging */ + pRvlc->length_of_rvlc_escapes = -1; /* default value is used for error detection and concealment */ + + /* read only error sensitivity class 1 data (ESC 1 - data) */ + pRvlc->sf_concealment = FDKreadBits(bs,1); /* #1 */ + pRvlc->rev_global_gain = FDKreadBits(bs,8); /* #2 */ + + if (GetWindowSequence(&pAacDecoderChannelInfo->icsInfo) == EightShortSequence) { + pRvlc->length_of_rvlc_sf = FDKreadBits(bs,11); /* #3 */ + } + else { + pRvlc->length_of_rvlc_sf = FDKreadBits(bs,9); /* #3 */ + } + + /* check if noise codebook is used */ + for (group = 0; group < pRvlc->numWindowGroups; group++) { + for (band=0; band < pRvlc->maxSfbTransmitted; band++) { + if (pAacDecoderChannelInfo->pDynData->aCodeBook[16*group+band] == NOISE_HCB) { + pRvlc->noise_used = 1; + break; + } + } + } + + if (pRvlc->noise_used) + pRvlc->dpcm_noise_nrg = FDKreadBits(bs, 9); /* #4 PNS */ + + pRvlc->sf_escapes_present = FDKreadBits(bs, 1); /* #5 */ + + if ( pRvlc->sf_escapes_present) { + pRvlc->length_of_rvlc_escapes = FDKreadBits(bs, 8); /* #6 */ + } + + if (pRvlc->noise_used) { + pRvlc->dpcm_noise_last_position = FDKreadBits(bs, 9); /* #7 PNS */ + pRvlc->length_of_rvlc_sf -= 9; + } + + pRvlc->length_of_rvlc_sf_fwd = pRvlc->length_of_rvlc_sf; + pRvlc->length_of_rvlc_sf_bwd = pRvlc->length_of_rvlc_sf; +} + + +/*--------------------------------------------------------------------------------------------- + function: CRvlc_Decode + + description: Decode rvlc data + The function reads both the escape sequences and the scalefactors in forward + and backward direction. If an error occured during decoding process which can + not be concealed with the rvlc concealment frame concealment will be initiated. + Then the element "rvlcCurrentScaleFactorOK" in the decoder channel info is set + to 0 otherwise it is set to 1. +----------------------------------------------------------------------------------------------- + input: - pointer rvlc structure + - pointer channel info structure + - pointer to persistent channel info structure + - pointer bitstream structure +----------------------------------------------------------------------------------------------- + return: ErrorStatus = AAC_DEC_OK +-------------------------------------------------------------------------------------------- */ + +void CRvlc_Decode ( + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, + HANDLE_FDK_BITSTREAM bs + ) +{ + CErRvlcInfo *pRvlc = &pAacDecoderChannelInfo->pComData->overlay.aac.erRvlcInfo; + INT bitCntOffst; + UINT saveBitCnt; + + rvlcInit(pRvlc,pAacDecoderChannelInfo,bs); + + /* save bitstream position */ + saveBitCnt = FDKgetBitCnt(bs); + +#if RVLC_ADVANCED_BITSTREAM_ERROR_GENERATOR_SF + GenerateSingleBitError(pRvlc, + &(pRvlc->bitstreamIndexRvlFwd), + pRvlc->length_of_rvlc_sf, + 0); +#endif + +#if RVLC_ADVANCED_BITSTREAM_ERROR_GENERATOR_ESC + if (pRvlc->sf_escapes_present) + GenerateSingleBitError(pRvlc, + &(pRvlc->bitstreamIndexEsc), + pRvlc->length_of_rvlc_escapes, + 1); +#endif + + if ( pRvlc->sf_escapes_present) + rvlcDecodeEscapes(pRvlc, pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfEsc, bs); + + rvlcDecodeForward(pRvlc,pAacDecoderChannelInfo, bs); + rvlcDecodeBackward(pRvlc,pAacDecoderChannelInfo, bs); + rvlcFinalErrorDetection(pAacDecoderChannelInfo, pAacDecoderStaticChannelInfo); + + pAacDecoderChannelInfo->pDynData->specificTo.aac.rvlcIntensityUsed = pRvlc->intensity_used; + pAacDecoderChannelInfo->data.aac.PnsData.PnsActive = pRvlc->noise_used; + + /* restore bitstream position */ + bitCntOffst = saveBitCnt - FDKgetBitCnt(bs); + if( bitCntOffst ) { + FDKpushBiDirectional(bs, bitCntOffst); + } +} + +void CRvlc_ElementCheck ( + CAacDecoderChannelInfo *pAacDecoderChannelInfo[], + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[], + const UINT flags, + const INT elChannels + ) +{ + int ch; + + /* Required for MPS residuals. */ + if (pAacDecoderStaticChannelInfo == NULL) { + return; + } + + /* RVLC specific sanity checks */ + if ( (flags & AC_ER_RVLC) && (elChannels == 2)) { /* to be reviewed */ + if ( ( (pAacDecoderChannelInfo[0]->pDynData->specificTo.aac.rvlcCurrentScaleFactorOK == 0) || + (pAacDecoderChannelInfo[1]->pDynData->specificTo.aac.rvlcCurrentScaleFactorOK == 0) ) + && pAacDecoderChannelInfo[0]->pComData->jointStereoData.MsMaskPresent ) { + pAacDecoderChannelInfo[0]->pDynData->specificTo.aac.rvlcCurrentScaleFactorOK = 0; + pAacDecoderChannelInfo[1]->pDynData->specificTo.aac.rvlcCurrentScaleFactorOK = 0; + } + + if ( (pAacDecoderChannelInfo[0]->pDynData->specificTo.aac.rvlcCurrentScaleFactorOK == 0) + && (pAacDecoderChannelInfo[1]->pDynData->specificTo.aac.rvlcCurrentScaleFactorOK == 1) + && (pAacDecoderChannelInfo[1]->pDynData->specificTo.aac.rvlcIntensityUsed == 1) ){ + pAacDecoderChannelInfo[1]->pDynData->specificTo.aac.rvlcCurrentScaleFactorOK = 0; + } + } + + for (ch = 0; ch < elChannels; ch ++) + { + pAacDecoderStaticChannelInfo[ch]->concealmentInfo.rvlcPreviousBlockType = (GetWindowSequence(&pAacDecoderChannelInfo[ch]->icsInfo) == EightShortSequence) ? 0 : 1; + if (flags & AC_ER_RVLC) { + pAacDecoderStaticChannelInfo[ch]->concealmentInfo.rvlcPreviousScaleFactorOK = pAacDecoderChannelInfo[ch]->pDynData->specificTo.aac.rvlcCurrentScaleFactorOK; + } + else { + pAacDecoderStaticChannelInfo[ch]->concealmentInfo.rvlcPreviousScaleFactorOK = 0; + } + } +} + + diff --git a/libAACdec/src/rvlc.h b/libAACdec/src/rvlc.h new file mode 100644 index 0000000..e80e80e --- /dev/null +++ b/libAACdec/src/rvlc.h @@ -0,0 +1,76 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +****************************************************************************/ +/*! + \file + \brief Defines structures and prototypes for RVLC + \author Robert Weidner +*/ + +#ifndef RVLC_H +#define RVLC_H + + + +#include "aacdecoder.h" +#include "channel.h" +#include "rvlc_info.h" + +/* ------------------------------------------------------------------- */ +/* errorLogRvlc: A word of 32 bits used for logging possible errors */ +/* within RVLC in case of distorted bitstreams. */ +/* ------------------------------------------------------------------- */ +#define RVLC_ERROR_ALL_ESCAPE_WORDS_INVALID 0x80000000 /* ESC-Dec During RVLC-Escape-decoding there have been more bits decoded as there are available */ +#define RVLC_ERROR_RVL_SUM_BIT_COUNTER_BELOW_ZERO_FWD 0x40000000 /* RVL-Dec negative sum-bitcounter during RVL-fwd-decoding (long+shrt) */ +#define RVLC_ERROR_RVL_SUM_BIT_COUNTER_BELOW_ZERO_BWD 0x20000000 /* RVL-Dec negative sum-bitcounter during RVL-fwd-decoding (long+shrt) */ +#define RVLC_ERROR_FORBIDDEN_CW_DETECTED_FWD 0x08000000 /* RVL-Dec forbidden codeword detected fwd (long+shrt) */ +#define RVLC_ERROR_FORBIDDEN_CW_DETECTED_BWD 0x04000000 /* RVL-Dec forbidden codeword detected bwd (long+shrt) */ + + + +void CRvlc_Read (CAacDecoderChannelInfo *pAacDecoderChannelInfo, + HANDLE_FDK_BITSTREAM bs); + +void CRvlc_Decode (CAacDecoderChannelInfo *pAacDecoderChannelInfo, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, + HANDLE_FDK_BITSTREAM bs); + +/** + * \brief performe sanity checks to the channel data corresponding to one channel element. + * \param pAacDecoderChannelInfo + * \param pAacDecoderStaticChannelInfo + * \param elChannels amount of channels of the channel element. + */ +void CRvlc_ElementCheck ( + CAacDecoderChannelInfo *pAacDecoderChannelInfo[], + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[], + const UINT flags, + const INT elChannels + ); + + + + +#endif /* RVLC_H */ diff --git a/libAACdec/src/rvlc_info.h b/libAACdec/src/rvlc_info.h new file mode 100644 index 0000000..2edc1b3 --- /dev/null +++ b/libAACdec/src/rvlc_info.h @@ -0,0 +1,118 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +****************************************************************************/ +/*! + \file + \brief Defines structures for RVLC + \author Robert Weidner +*/ +#ifndef RVLC_INFO_H +#define RVLC_INFO_H + + + +#define FWD 0 /* bitstream decoding direction forward (RVL coded part) */ +#define BWD 1 /* bitstream decoding direction backward (RVL coded part) */ + +#define MAX_RVL 7 /* positive RVLC escape */ +#define MIN_RVL -7 /* negative RVLC escape */ +#define MAX_ALLOWED_DPCM_INDEX 14 /* the maximum allowed index of a decoded dpcm value (offset 'TABLE_OFFSET' incl --> must be subtracted) */ +#define TABLE_OFFSET 7 /* dpcm offset of valid output values of rvl table decoding, the rvl table ouly returns positive values, therefore the offset */ +#define MAX_LEN_RVLC_CODE_WORD 9 /* max length of a RVL codeword in bits */ +#define MAX_LEN_RVLC_ESCAPE_WORD 20 /* max length of huffman coded RVLC escape word in bits */ + +#define DPCM_NOISE_NRG_BITS 9 +#define SF_OFFSET 100 /* offset for correcting scf value */ + +#define CONCEAL_MAX_INIT 1311 /* arbitrary value */ +#define CONCEAL_MIN_INIT -1311 /* arbitrary value */ + +#define RVLC_MAX_SFB ((8) * (16)) + +/* sideinfo of RVLC */ +typedef struct +{ + /* ------- ESC 1 Data: --------- */ /* order of RVLC-bitstream components in bitstream (RVLC-initialization), every component appears only once in bitstream */ + INT sf_concealment; /* 1 */ + INT rev_global_gain; /* 2 */ + SHORT length_of_rvlc_sf; /* 3 */ /* original value, gets modified (subtract 9) in case of noise (PNS); is kept for later use */ + INT dpcm_noise_nrg; /* 4 optional */ + INT sf_escapes_present; /* 5 */ + SHORT length_of_rvlc_escapes; /* 6 optional */ + INT dpcm_noise_last_position; /* 7 optional */ + + INT dpcm_is_last_position; + + SHORT length_of_rvlc_sf_fwd; /* length_of_rvlc_sf used for forward decoding */ + SHORT length_of_rvlc_sf_bwd; /* length_of_rvlc_sf used for backward decoding */ + + /* for RVL-Codeword decoder to distinguish between fwd and bwd decoding */ + SHORT *pRvlBitCnt_RVL; + USHORT *pBitstrIndxRvl_RVL; + + UCHAR numWindowGroups; + UCHAR maxSfbTransmitted; + UCHAR first_noise_group; + UCHAR first_noise_band; + UCHAR direction; + + /* bitstream indices */ + USHORT bitstreamIndexRvlFwd; /* base address of RVL-coded-scalefactor data (ESC 2) for forward decoding */ + USHORT bitstreamIndexRvlBwd; /* base address of RVL-coded-scalefactor data (ESC 2) for backward decoding */ + USHORT bitstreamIndexEsc; /* base address where RVLC-escapes start (ESC 2) */ + + /* decoding trees */ + const UINT *pHuffTreeRvlCodewds; + const UINT *pHuffTreeRvlcEscape; + + /* escape counters */ + UCHAR numDecodedEscapeWordsFwd; /* when decoding RVL-codes forward */ + UCHAR numDecodedEscapeWordsBwd; /* when decoding RVL-codes backward */ + UCHAR numDecodedEscapeWordsEsc; /* when decoding the escape-Words */ + + SCHAR noise_used; + SCHAR intensity_used; + SCHAR sf_used; + + SHORT firstScf; + SHORT lastScf; + SHORT firstNrg; + SHORT lastNrg; + SHORT firstIs; + SHORT lastIs; + + /* ------ RVLC error detection ------ */ + UINT errorLogRvlc; /* store RVLC errors */ + SHORT conceal_min; /* is set at backward decoding */ + SHORT conceal_max; /* is set at forward decoding */ + SHORT conceal_min_esc; /* is set at backward decoding */ + SHORT conceal_max_esc; /* is set at forward decoding */ +} CErRvlcInfo; + +typedef CErRvlcInfo RVLC_INFO; /* temp */ + + + +#endif /* RVLC_INFO_H */ diff --git a/libAACdec/src/rvlcbit.cpp b/libAACdec/src/rvlcbit.cpp new file mode 100644 index 0000000..c3ffc59 --- /dev/null +++ b/libAACdec/src/rvlcbit.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +****************************************************************************/ +/*! + \file + \brief RVLC bitstream reading + \author Robert Weidner +*/ + +#include "rvlcbit.h" + + +/*--------------------------------------------------------------------------------------------- + function: rvlcReadBitFromBitstream + + description: This function returns a bit from the bitstream according to read direction. + It is called very often, therefore it makes sense to inline it (runtime). +----------------------------------------------------------------------------------------------- + input: - bitstream + - pPosition + - readDirection +----------------------------------------------------------------------------------------------- + return: - bit from bitstream +-------------------------------------------------------------------------------------------- */ + +UCHAR rvlcReadBitFromBitstream (HANDLE_FDK_BITSTREAM bs, + USHORT *pPosition, + UCHAR readDirection) +{ + UINT bit; + INT readBitOffset = *pPosition-FDKgetBitCnt(bs); + + if( readBitOffset ) { + FDKpushBiDirectional(bs, readBitOffset); + } + + if (readDirection == FWD) { + bit = FDKreadBits(bs, 1); + + *pPosition += 1; + } else { + /* to be replaced with a brother function of FDKreadBits() */ + bit = FDKreadBits(bs, 1); + FDKpushBack(bs, 2); + + *pPosition -= 1; + } + + return (bit); +} + diff --git a/libAACdec/src/rvlcbit.h b/libAACdec/src/rvlcbit.h new file mode 100644 index 0000000..5cb9e88 --- /dev/null +++ b/libAACdec/src/rvlcbit.h @@ -0,0 +1,41 @@ +/***************************** MPEG-4 AAC Decoder *************************** + + (C) Copyright Fraunhofer IIS 2000-2008 + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Robert Weidner (DSP Solutions) + Description: RVLC Decoder: Bitstream reading + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +*******************************************************************************/ + +#ifndef RVLCBIT_H +#define RVLCBIT_H + + + +#include "rvlc.h" + +UCHAR rvlcReadBitFromBitstream (HANDLE_FDK_BITSTREAM bs, + USHORT *pPosition, + UCHAR readDirection); + + +#endif /* RVLCBIT_H */ diff --git a/libAACdec/src/rvlcconceal.cpp b/libAACdec/src/rvlcconceal.cpp new file mode 100644 index 0000000..161c336 --- /dev/null +++ b/libAACdec/src/rvlcconceal.cpp @@ -0,0 +1,639 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +****************************************************************************/ +/*! + \file + \brief rvlc concealment + \author Josef Hoepfl +*/ + +#include "rvlcconceal.h" + + +#include "block.h" +#include "rvlc.h" + +/*--------------------------------------------------------------------------------------------- + function: calcRefValFwd + + description: The function determines the scalefactor which is closed to the scalefactorband + conceal_min. The same is done for intensity data and noise energies. +----------------------------------------------------------------------------------------------- + output: - reference value scf + - reference value internsity data + - reference value noise energy +----------------------------------------------------------------------------------------------- + return: - +-------------------------------------------------------------------------------------------- */ + +static +void calcRefValFwd (CErRvlcInfo *pRvlc, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + int *refIsFwd, + int *refNrgFwd, + int *refScfFwd) +{ + int band,bnds,group,startBand; + int idIs,idNrg,idScf; + int conceal_min,conceal_group_min; + int MaximumScaleFactorBands; + + + if (GetWindowSequence(&pAacDecoderChannelInfo->icsInfo) == EightShortSequence) + MaximumScaleFactorBands = 16; + else + MaximumScaleFactorBands = 64; + + conceal_min = pRvlc->conceal_min % MaximumScaleFactorBands; + conceal_group_min = pRvlc->conceal_min / MaximumScaleFactorBands; + + /* calculate first reference value for approach in forward direction */ + idIs = idNrg = idScf = 1; + + /* set reference values */ + *refIsFwd = - SF_OFFSET; + *refNrgFwd = pAacDecoderChannelInfo->pDynData->RawDataInfo.GlobalGain - SF_OFFSET - 90 - 256; + *refScfFwd = pAacDecoderChannelInfo->pDynData->RawDataInfo.GlobalGain - SF_OFFSET; + + startBand = conceal_min-1; + for (group=conceal_group_min; group >= 0; group--) { + for (band=startBand; band >= 0; band--) { + bnds = 16*group+band; + switch (pAacDecoderChannelInfo->pDynData->aCodeBook[bnds]) { + case ZERO_HCB: + break; + case INTENSITY_HCB: + case INTENSITY_HCB2: + if (idIs) { + *refIsFwd = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds]; + idIs=0; /* reference value has been set */ + } + break; + case NOISE_HCB: + if (idNrg) { + *refNrgFwd = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds]; + idNrg=0; /* reference value has been set */ + } + break ; + default: + if (idScf) { + *refScfFwd = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds]; + idScf=0; /* reference value has been set */ + } + break; + } + } + startBand = pRvlc->maxSfbTransmitted-1; + } + +} + +/*--------------------------------------------------------------------------------------------- + function: calcRefValBwd + + description: The function determines the scalefactor which is closed to the scalefactorband + conceal_max. The same is done for intensity data and noise energies. +----------------------------------------------------------------------------------------------- + output: - reference value scf + - reference value internsity data + - reference value noise energy +----------------------------------------------------------------------------------------------- + return: - +-------------------------------------------------------------------------------------------- */ + +static +void calcRefValBwd (CErRvlcInfo *pRvlc, + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + int *refIsBwd, + int *refNrgBwd, + int *refScfBwd) +{ + int band,bnds,group,startBand; + int idIs,idNrg,idScf; + int conceal_max,conceal_group_max; + int MaximumScaleFactorBands; + + if (GetWindowSequence(&pAacDecoderChannelInfo->icsInfo) == EightShortSequence) + MaximumScaleFactorBands = 16; + else + MaximumScaleFactorBands = 64; + + conceal_max = pRvlc->conceal_max % MaximumScaleFactorBands; + conceal_group_max = pRvlc->conceal_max / MaximumScaleFactorBands; + + /* calculate first reference value for approach in backward direction */ + idIs = idNrg = idScf = 1; + + /* set reference values */ + *refIsBwd = pRvlc->dpcm_is_last_position - SF_OFFSET; + *refNrgBwd = pRvlc->rev_global_gain + pRvlc->dpcm_noise_last_position - SF_OFFSET - 90 - 256 + pRvlc->dpcm_noise_nrg; + *refScfBwd = pRvlc->rev_global_gain - SF_OFFSET; + + startBand=conceal_max+1; + + /* if needed, re-set reference values */ + for (group=conceal_group_max; group < pRvlc->numWindowGroups; group++) { + for (band=startBand; band < pRvlc->maxSfbTransmitted; band++) { + bnds = 16*group+band; + switch (pAacDecoderChannelInfo->pDynData->aCodeBook[bnds]) { + case ZERO_HCB: + break; + case INTENSITY_HCB: + case INTENSITY_HCB2: + if (idIs) { + *refIsBwd = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]; + idIs=0; /* reference value has been set */ + } + break; + case NOISE_HCB: + if (idNrg) { + *refNrgBwd = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]; + idNrg=0; /* reference value has been set */ + } + break ; + default: + if (idScf) { + *refScfBwd = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]; + idScf=0; /* reference value has been set */ + } + break; + } + } + startBand=0; + } + +} + + +/*--------------------------------------------------------------------------------------------- + function: BidirectionalEstimation_UseLowerScfOfCurrentFrame + + description: This approach by means of bidirectional estimation is generally performed when + a single bit error has been detected, the bit error can be isolated between + 'conceal_min' and 'conceal_max' and the 'sf_concealment' flag is not set. The + sets of scalefactors decoded in forward and backward direction are compared + with each other. The smaller scalefactor will be considered as the correct one + respectively. The reconstruction of the scalefactors with this approach archieve + good results in audio quality. The strategy must be applied to scalefactors, + intensity data and noise energy seperately. +----------------------------------------------------------------------------------------------- + output: Concealed scalefactor, noise energy and intensity data between conceal_min and + conceal_max +----------------------------------------------------------------------------------------------- + return: - +-------------------------------------------------------------------------------------------- */ + +void BidirectionalEstimation_UseLowerScfOfCurrentFrame (CAacDecoderChannelInfo *pAacDecoderChannelInfo) +{ + CErRvlcInfo *pRvlc = &pAacDecoderChannelInfo->pComData->overlay.aac.erRvlcInfo; + int band,bnds,startBand,endBand,group; + int conceal_min,conceal_max; + int conceal_group_min,conceal_group_max; + int MaximumScaleFactorBands; + + if (GetWindowSequence(&pAacDecoderChannelInfo->icsInfo) == EightShortSequence) { + MaximumScaleFactorBands = 16; + } + else { + MaximumScaleFactorBands = 64; + } + + /* If an error was detected just in forward or backward direction, set the corresponding border for concealment to a + appropriate scalefactor band. The border is set to first or last sfb respectively, because the error will possibly + not follow directly after the corrupt bit but just after decoding some more (wrong) scalefactors. */ + if (pRvlc->conceal_min == CONCEAL_MIN_INIT) + pRvlc->conceal_min = 0; + + if (pRvlc->conceal_max == CONCEAL_MAX_INIT) + pRvlc->conceal_max = (pRvlc->numWindowGroups-1)*16+pRvlc->maxSfbTransmitted-1; + + conceal_min = pRvlc->conceal_min % MaximumScaleFactorBands; + conceal_group_min = pRvlc->conceal_min / MaximumScaleFactorBands; + conceal_max = pRvlc->conceal_max % MaximumScaleFactorBands; + conceal_group_max = pRvlc->conceal_max / MaximumScaleFactorBands; + + if (pRvlc->conceal_min == pRvlc->conceal_max) { + + int refIsFwd,refNrgFwd,refScfFwd; + int refIsBwd,refNrgBwd,refScfBwd; + + bnds = pRvlc->conceal_min; + calcRefValFwd(pRvlc,pAacDecoderChannelInfo,&refIsFwd,&refNrgFwd,&refScfFwd); + calcRefValBwd(pRvlc,pAacDecoderChannelInfo,&refIsBwd,&refNrgBwd,&refScfBwd); + + switch (pAacDecoderChannelInfo->pDynData->aCodeBook[bnds]) { + case ZERO_HCB: + break; + case INTENSITY_HCB: + case INTENSITY_HCB2: + if (refIsFwd < refIsBwd) + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = refIsFwd; + else + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = refIsBwd; + break; + case NOISE_HCB: + if (refNrgFwd < refNrgBwd) + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = refNrgFwd; + else + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = refNrgBwd; + break; + default: + if (refScfFwd < refScfBwd) + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = refScfFwd; + else + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = refScfBwd; + break; + } + } + else { + pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[pRvlc->conceal_max] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[pRvlc->conceal_max]; + pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[pRvlc->conceal_min] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[pRvlc->conceal_min]; + + /* consider the smaller of the forward and backward decoded value as the correct one */ + startBand = conceal_min; + if (conceal_group_min == conceal_group_max) + endBand = conceal_max; + else + endBand = pRvlc->maxSfbTransmitted-1; + + for (group=conceal_group_min; group <= conceal_group_max; group++) { + for (band=startBand; band <= endBand; band++) { + bnds = 16*group+band; + if (pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds] < pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]) + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds]; + else + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]; + } + startBand = 0; + if ((group+1) == conceal_group_max) + endBand = conceal_max; + } + } + + /* now copy all data to the output buffer which needs not to be concealed */ + if (conceal_group_min == 0) + endBand = conceal_min; + else + endBand = pRvlc->maxSfbTransmitted; + for (group=0; group <= conceal_group_min; group++) { + for (band=0; band < endBand; band++) { + bnds = 16*group+band; + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds]; + } + if ((group+1) == conceal_group_min) + endBand = conceal_min; + } + + startBand = conceal_max+1; + for (group=conceal_group_max; group < pRvlc->numWindowGroups; group++) { + for (band=startBand; band < pRvlc->maxSfbTransmitted; band++) { + bnds = 16*group+band; + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]; + } + startBand = 0; + } +} + +/*--------------------------------------------------------------------------------------------- + function: BidirectionalEstimation_UseScfOfPrevFrameAsReference + + description: This approach by means of bidirectional estimation is generally performed when + a single bit error has been detected, the bit error can be isolated between + 'conceal_min' and 'conceal_max', the 'sf_concealment' flag is set and the + previous frame has the same block type as the current frame. The scalefactor + decoded in forward and backward direction and the scalefactor of the previous + frame are compared with each other. The smaller scalefactor will be considered + as the correct one. At this the codebook of the previous and current frame must + be of the same set (scf, nrg, is) in each scalefactorband. Otherwise the + scalefactor of the previous frame is not considered in the minimum calculation. + The reconstruction of the scalefactors with this approach archieve good results + in audio quality. The strategy must be applied to scalefactors, intensity data + and noise energy seperately. +----------------------------------------------------------------------------------------------- + output: Concealed scalefactor, noise energy and intensity data between conceal_min and + conceal_max +----------------------------------------------------------------------------------------------- + return: - +-------------------------------------------------------------------------------------------- */ + +void BidirectionalEstimation_UseScfOfPrevFrameAsReference ( + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo + ) +{ + CErRvlcInfo *pRvlc = &pAacDecoderChannelInfo->pComData->overlay.aac.erRvlcInfo; + int band,bnds,startBand,endBand,group; + int conceal_min,conceal_max; + int conceal_group_min,conceal_group_max; + int MaximumScaleFactorBands; + int commonMin; + + if (GetWindowSequence(&pAacDecoderChannelInfo->icsInfo) == EightShortSequence) { + MaximumScaleFactorBands = 16; + } + else { + MaximumScaleFactorBands = 64; + } + + /* If an error was detected just in forward or backward direction, set the corresponding border for concealment to a + appropriate scalefactor band. The border is set to first or last sfb respectively, because the error will possibly + not follow directly after the corrupt bit but just after decoding some more (wrong) scalefactors. */ + if (pRvlc->conceal_min == CONCEAL_MIN_INIT) + pRvlc->conceal_min = 0; + + if (pRvlc->conceal_max == CONCEAL_MAX_INIT) + pRvlc->conceal_max = (pRvlc->numWindowGroups-1)*16+pRvlc->maxSfbTransmitted-1; + + conceal_min = pRvlc->conceal_min % MaximumScaleFactorBands; + conceal_group_min = pRvlc->conceal_min / MaximumScaleFactorBands; + conceal_max = pRvlc->conceal_max % MaximumScaleFactorBands; + conceal_group_max = pRvlc->conceal_max / MaximumScaleFactorBands; + + pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[pRvlc->conceal_max] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[pRvlc->conceal_max]; + pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[pRvlc->conceal_min] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[pRvlc->conceal_min]; + + /* consider the smaller of the forward and backward decoded value as the correct one */ + startBand = conceal_min; + if (conceal_group_min == conceal_group_max) + endBand = conceal_max; + else + endBand = pRvlc->maxSfbTransmitted-1; + + for (group=conceal_group_min; group <= conceal_group_max; group++) { + for (band=startBand; band <= endBand; band++) { + bnds = 16*group+band; + switch (pAacDecoderChannelInfo->pDynData->aCodeBook[bnds]) { + case ZERO_HCB: + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = 0; + break; + + case INTENSITY_HCB: + case INTENSITY_HCB2: + if ( (pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds]==INTENSITY_HCB) || (pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds]==INTENSITY_HCB2) ) { + commonMin = FDKmin(pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds],pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]); + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = FDKmin(commonMin, pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousScaleFactor[bnds]); + } + else { + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = FDKmin(pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds],pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]); + } + break; + + case NOISE_HCB: + if ( (pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds]==NOISE_HCB) ) { + commonMin = FDKmin(pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds],pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]); + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = FDKmin(commonMin, pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousScaleFactor[bnds]); + } else { + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = FDKmin(pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds],pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]); + } + break; + + default: + if ( (pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds]!=ZERO_HCB) + && (pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds]!=NOISE_HCB) + && (pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds]!=INTENSITY_HCB) + && (pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds]!=INTENSITY_HCB2) ) + { + commonMin = FDKmin(pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds], pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]); + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = FDKmin(commonMin, pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousScaleFactor[bnds]); + } else { + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = FDKmin(pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds],pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]); + } + break; + } + } + startBand = 0; + if ((group+1) == conceal_group_max) + endBand = conceal_max; + } + + /* now copy all data to the output buffer which needs not to be concealed */ + if (conceal_group_min == 0) + endBand = conceal_min; + else + endBand = pRvlc->maxSfbTransmitted; + for (group=0; group <= conceal_group_min; group++) { + for (band=0; band < endBand; band++) { + bnds = 16*group+band; + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds]; + } + if ((group+1) == conceal_group_min) + endBand = conceal_min; + } + + startBand = conceal_max+1; + for (group=conceal_group_max; group < pRvlc->numWindowGroups; group++) { + for (band=startBand; band < pRvlc->maxSfbTransmitted; band++) { + bnds = 16*group+band; + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]; + } + startBand = 0; + } +} + +/*--------------------------------------------------------------------------------------------- + function: StatisticalEstimation + + description: This approach by means of statistical estimation is generally performed when + both the start value and the end value are different and no further errors have + been detected. Considering the forward and backward decoded scalefactors, the + set with the lower scalefactors in sum will be considered as the correct one. + The scalefactors are differentially encoded. Normally it would reach to compare + one pair of the forward and backward decoded scalefactors to specify the lower + set. But having detected no further errors does not necessarily mean the absence + of errors. Therefore all scalefactors decoded in forward and backward direction + are summed up seperately. The set with the lower sum will be used. The strategy + must be applied to scalefactors, intensity data and noise energy seperately. +----------------------------------------------------------------------------------------------- + output: Concealed scalefactor, noise energy and intensity data +----------------------------------------------------------------------------------------------- + return: - +-------------------------------------------------------------------------------------------- */ + +void StatisticalEstimation (CAacDecoderChannelInfo *pAacDecoderChannelInfo) +{ + CErRvlcInfo *pRvlc = &pAacDecoderChannelInfo->pComData->overlay.aac.erRvlcInfo; + int band,bnds,group; + int sumIsFwd,sumIsBwd; /* sum of intensity data forward/backward */ + int sumNrgFwd,sumNrgBwd; /* sum of noise energy data forward/backward */ + int sumScfFwd,sumScfBwd; /* sum of scalefactor data forward/backward */ + int useIsFwd,useNrgFwd,useScfFwd; /* the flags signals the elements which are used for the final result */ + int MaximumScaleFactorBands; + + if (GetWindowSequence(&pAacDecoderChannelInfo->icsInfo) == EightShortSequence) + MaximumScaleFactorBands = 16; + else + MaximumScaleFactorBands = 64; + + sumIsFwd = sumIsBwd = sumNrgFwd = sumNrgBwd = sumScfFwd = sumScfBwd = 0; + useIsFwd = useNrgFwd = useScfFwd = 0; + + /* calculate sum of each group (scf,nrg,is) of forward and backward direction */ + for (group=0; groupnumWindowGroups; group++) { + for (band=0; band < pRvlc->maxSfbTransmitted; band++) { + bnds = 16*group+band; + switch (pAacDecoderChannelInfo->pDynData->aCodeBook[bnds]) { + case ZERO_HCB: + break; + + case INTENSITY_HCB: + case INTENSITY_HCB2: + sumIsFwd += pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds]; + sumIsBwd += pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]; + break; + + case NOISE_HCB: + sumNrgFwd += pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds]; + sumNrgBwd += pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]; + break ; + + default: + sumScfFwd += pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds]; + sumScfBwd += pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]; + break; + } + } + } + + /* find for each group (scf,nrg,is) the correct direction */ + if ( sumIsFwd < sumIsBwd ) + useIsFwd = 1; + + if ( sumNrgFwd < sumNrgBwd ) + useNrgFwd = 1; + + if ( sumScfFwd < sumScfBwd ) + useScfFwd = 1; + + /* conceal each group (scf,nrg,is) */ + for (group=0; groupnumWindowGroups; group++) { + for (band=0; band < pRvlc->maxSfbTransmitted; band++) { + bnds = 16*group+band; + switch (pAacDecoderChannelInfo->pDynData->aCodeBook[bnds]) { + case ZERO_HCB: + break; + + case INTENSITY_HCB: + case INTENSITY_HCB2: + if (useIsFwd) + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds]; + else + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]; + break; + + case NOISE_HCB: + if (useNrgFwd) + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds]; + else + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]; + break ; + + default: + if (useScfFwd) + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds]; + else + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]; + break; + } + } + } +} + + +/*--------------------------------------------------------------------------------------------- + description: Approach by means of predictive interpolation + This approach by means of predictive estimation is generally performed when + the error cannot be isolated between 'conceal_min' and 'conceal_max', the + 'sf_concealment' flag is set and the previous frame has the same block type + as the current frame. Check for each scalefactorband if the same type of data + (scalefactor, internsity data, noise energies) is transmitted. If so use the + scalefactor (intensity data, noise energy) in the current frame. Otherwise set + the scalefactor (intensity data, noise energy) for this scalefactorband to zero. +----------------------------------------------------------------------------------------------- + output: Concealed scalefactor, noise energy and intensity data +----------------------------------------------------------------------------------------------- + return: - +-------------------------------------------------------------------------------------------- */ + +void PredictiveInterpolation ( + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo + ) +{ + CErRvlcInfo *pRvlc = &pAacDecoderChannelInfo->pComData->overlay.aac.erRvlcInfo; + int band,bnds,group; + int MaximumScaleFactorBands; + int commonMin; + + if (GetWindowSequence(&pAacDecoderChannelInfo->icsInfo) == EightShortSequence) + MaximumScaleFactorBands = 16; + else + MaximumScaleFactorBands = 64; + + for (group=0; groupnumWindowGroups; group++) { + for (band=0; band < pRvlc->maxSfbTransmitted; band++) { + bnds = 16*group+band; + switch (pAacDecoderChannelInfo->pDynData->aCodeBook[bnds]) { + case ZERO_HCB: + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = 0; + break; + + case INTENSITY_HCB: + case INTENSITY_HCB2: + if ( (pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds]==INTENSITY_HCB) || (pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds]==INTENSITY_HCB2) ) { + commonMin = FDKmin(pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds],pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]); + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = FDKmin(commonMin, pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousScaleFactor[bnds]); + } + else { + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = -110; + } + break; + + case NOISE_HCB: + if ( (pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds]==NOISE_HCB) ) { + commonMin = FDKmin(pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds],pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]); + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = FDKmin(commonMin, pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousScaleFactor[bnds]); + } + else { + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = -110; + } + break; + + default: + if ( (pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds]!=ZERO_HCB) + && (pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds]!=NOISE_HCB) + && (pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds]!=INTENSITY_HCB) + && (pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousCodebook[bnds]!=INTENSITY_HCB2) ) { + commonMin = FDKmin(pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfFwd[bnds],pAacDecoderChannelInfo->pComData->overlay.aac.aRvlcScfBwd[bnds]); + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = FDKmin(commonMin, pAacDecoderStaticChannelInfo->concealmentInfo.aRvlcPreviousScaleFactor[bnds]); + } + else { + pAacDecoderChannelInfo->pDynData->aScaleFactor[bnds] = 0; + } + break; + } + } + } +} + diff --git a/libAACdec/src/rvlcconceal.h b/libAACdec/src/rvlcconceal.h new file mode 100644 index 0000000..0be0afa --- /dev/null +++ b/libAACdec/src/rvlcconceal.h @@ -0,0 +1,54 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +****************************************************************************/ +/*! + \file + \brief rvlc concealment + \author Josef Hoepfl +*/ + +#ifndef RVLCCONCEAL_H +#define RVLCCONCEAL_H + + + +#include "rvlc.h" + +void BidirectionalEstimation_UseLowerScfOfCurrentFrame(CAacDecoderChannelInfo *pAacDecoderChannelInfo); + +void BidirectionalEstimation_UseScfOfPrevFrameAsReference( + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo + ); + +void StatisticalEstimation (CAacDecoderChannelInfo *pAacDecoderChannelInfo); + +void PredictiveInterpolation ( + CAacDecoderChannelInfo *pAacDecoderChannelInfo, + CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo + ); + + +#endif /* RVLCCONCEAL_H */ diff --git a/libAACdec/src/stereo.cpp b/libAACdec/src/stereo.cpp new file mode 100644 index 0000000..b2e5e79 --- /dev/null +++ b/libAACdec/src/stereo.cpp @@ -0,0 +1,235 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: joint stereo processing + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "stereo.h" + + +#include "aac_rom.h" +#include "FDK_bitstream.h" +#include "channelinfo.h" + +enum +{ + L = 0, + R = 1 +}; + + +int CJointStereo_Read( + HANDLE_FDK_BITSTREAM bs, + CJointStereoData *pJointStereoData, + const int windowGroups, + const int scaleFactorBandsTransmitted, + const UINT flags + ) +{ + int group,band; + + pJointStereoData->MsMaskPresent = (UCHAR) FDKreadBits(bs,2); + + FDKmemclear(pJointStereoData->MsUsed, scaleFactorBandsTransmitted*sizeof(UCHAR)); + + switch (pJointStereoData->MsMaskPresent) + { + case 0 : /* no M/S */ + /* all flags are already cleared */ + break ; + + case 1 : /* read ms_used */ + + for (group=0; groupMsUsed[band] |= (FDKreadBits(bs,1) << group); + } + } + break ; + + case 2 : /* full spectrum M/S */ + + for (band=0; bandMsUsed[band] = 255 ; /* set all flags to 1 */ + } + break ; + } + + return 0; +} + +void CJointStereo_ApplyMS( + CAacDecoderChannelInfo *pAacDecoderChannelInfo[2], + const SHORT *pScaleFactorBandOffsets, + const UCHAR *pWindowGroupLength, + const int windowGroups, + const int scaleFactorBandsTransmittedL, + const int scaleFactorBandsTransmittedR + ) +{ + CJointStereoData *pJointStereoData = &pAacDecoderChannelInfo[L]->pComData->jointStereoData; + int window, group, scaleFactorBandsTransmitted; + + FDK_ASSERT(scaleFactorBandsTransmittedL == scaleFactorBandsTransmittedR); + scaleFactorBandsTransmitted = scaleFactorBandsTransmittedL; + for (window = 0, group = 0; group < windowGroups; group++) + { + UCHAR groupMask = 1 << group; + + for (int groupwin=0; groupwinpDynData->aSfbScale[window*16]; + SHORT *rightScale = &pAacDecoderChannelInfo[R]->pDynData->aSfbScale[window*16]; + + leftSpectrum = SPEC(pAacDecoderChannelInfo[L]->pSpectralCoefficient, window, pAacDecoderChannelInfo[L]->granuleLength); + rightSpectrum = SPEC(pAacDecoderChannelInfo[R]->pSpectralCoefficient, window, pAacDecoderChannelInfo[R]->granuleLength); + + for (band=0; bandMsUsed[band] & groupMask) + { + int lScale=leftScale[band]; + int rScale=rightScale[band]; + int commonScale=lScale > rScale ? lScale:rScale; + + /* ISO/IEC 14496-3 Chapter 4.6.8.1.1 : + M/S joint channel coding can only be used if common_window is ‘1’. */ + FDK_ASSERT(GetWindowSequence(&pAacDecoderChannelInfo[L]->icsInfo) == GetWindowSequence(&pAacDecoderChannelInfo[R]->icsInfo)); + FDK_ASSERT(GetWindowShape(&pAacDecoderChannelInfo[L]->icsInfo) == GetWindowShape(&pAacDecoderChannelInfo[R]->icsInfo)); + + commonScale++; + leftScale[band]=commonScale; + rightScale[band]=commonScale; + + lScale = fMin(DFRACT_BITS-1, commonScale - lScale); + rScale = fMin(DFRACT_BITS-1, commonScale - rScale); + + FDK_ASSERT(lScale >= 0 && rScale >= 0); + + for (int index=pScaleFactorBandOffsets[band]; index>= lScale ; + rightCoefficient >>= rScale ; + + leftSpectrum [index] = leftCoefficient + rightCoefficient ; + rightSpectrum [index] = leftCoefficient - rightCoefficient ; + } + } + } + } + } + + /* Reset MsUsed flags if no explicit signalling was transmitted. Necessary for intensity coding. + PNS correlation signalling was mapped before calling CJointStereo_ApplyMS(). */ + if (pJointStereoData->MsMaskPresent == 2) { + FDKmemclear(pJointStereoData->MsUsed, JointStereoMaximumBands * sizeof(UCHAR)); + } +} + +void CJointStereo_ApplyIS( + CAacDecoderChannelInfo *pAacDecoderChannelInfo[2], + const SHORT *pScaleFactorBandOffsets, + const UCHAR *pWindowGroupLength, + const int windowGroups, + const int scaleFactorBandsTransmitted, + const UINT CommonWindow + ) +{ + CJointStereoData *pJointStereoData = &pAacDecoderChannelInfo[L]->pComData->jointStereoData; + + for (int window=0,group=0; grouppDynData->aCodeBook[group*16]; + ScaleFactor = &pAacDecoderChannelInfo[R]->pDynData->aScaleFactor[group*16]; + + for (int groupwin=0; groupwinpDynData->aSfbScale[window*16]; + SHORT *rightScale = &pAacDecoderChannelInfo[R]->pDynData->aSfbScale[window*16]; + int band; + + leftSpectrum = SPEC(pAacDecoderChannelInfo[L]->pSpectralCoefficient, window, pAacDecoderChannelInfo[L]->granuleLength); + rightSpectrum = SPEC(pAacDecoderChannelInfo[R]->pSpectralCoefficient, window, pAacDecoderChannelInfo[R]->granuleLength); + + for (band=0; band> 2 ; + int lsb = bandScale & 0x03 ; + + /* exponent of MantissaTable[lsb][0] is 1, thus msb+1 below. */ + FIXP_DBL scale = MantissaTable[lsb][0]; + + /* ISO/IEC 14496-3 Chapter 4.6.8.2.3 : + The use of intensity stereo coding is signaled by the use of the pseudo codebooks + INTENSITY_HCB and INTENSITY_HCB2 (15 and 14) only in the right channel of a + channel_pair_element() having a common ics_info() (common_window == 1). */ + FDK_ASSERT(GetWindowSequence(&pAacDecoderChannelInfo[L]->icsInfo) == GetWindowSequence(&pAacDecoderChannelInfo[R]->icsInfo)); + FDK_ASSERT(GetWindowShape(&pAacDecoderChannelInfo[L]->icsInfo) == GetWindowShape(&pAacDecoderChannelInfo[R]->icsInfo)); + + rightScale[band] = leftScale[band]+msb+1; + + if (CommonWindow && (pJointStereoData->MsUsed[band] & groupMask)) + { + + if (CodeBook[band] == INTENSITY_HCB) /* _NOT_ in-phase */ + { + scale = -scale ; + } + } + else + { + if (CodeBook[band] == INTENSITY_HCB2) /* out-of-phase */ + { + scale = -scale ; + } + } + + for (int index=pScaleFactorBandOffsets[band]; index0 +\until } + +\section writeOutData Output Bitstream Data +If any AAC bitstream data is available, write it to output file or device. This can be done once the +following condition is true: +\dontinclude main.cpp +\skip Valid bitstream available +\skipline outargs + +\skipline outBytes>0 + +If you use file I/O then for example call mpegFileWrite_Write() from the library libMpegFileWrite + +\dontinclude main.cpp +\skipline mpegFileWrite_Write + +\section cfgMetaData Meta Data Configuration + +If the present library is configured with Metadata support, it is possible to insert meta data side info into the generated +audio bitstream while encoding. + +To work with meta data the encoder instance has to be \ref encOpen "allocated" with meta data support. The meta data mode must be be configured with +the ::AACENC_METADATA_MODE parameter and aacEncoder_SetParam() function. +\code aacEncoder_SetParam(hAacEncoder, AACENC_METADATA_MODE, 0-2); \endcode + +This configuration indicates how to embed meta data into bitstrem. Either no insertion, MPEG or ETSI style. +The meta data itself must be specified within the meta data setup structure AACENC_MetaData. + +Changing one of the AACENC_MetaData setup parameters can be achieved from outside the library within ::IN_METADATA_SETUP input +buffer. There is no need to supply meta data setup structure every frame. If there is no new meta setup data available, the +encoder uses the previous setup or the default configuration in initial state. + +In general the audio compressor and limiter within the encoder library can be configured with the ::AACENC_METADATA_DRC_PROFILE parameter +AACENC_MetaData::drc_profile and and AACENC_MetaData::comp_profile. +\n + +\section encReconf Encoder Reconfiguration + +The encoder library allows reconfiguration of the encoder instance with new settings +continuously between encoding frames. Each parameter to be changed must be set with +a single aacEncoder_SetParam() call. The internal status of each parameter can be +retrieved with an aacEncoder_GetParam() call.\n +There is no stand-alone reconfiguration function available. When parameters were +modified from outside the library, an internal control mechanism triggers the necessary +reconfiguration process which will be applied at the beginning of the following +aacEncEncode() call. This state can be observed from external via the AACENC_INIT_STATUS +and aacEncoder_GetParam() function. The reconfiguration process can also be applied +immediately when all parameters of an aacEncEncode() call are NULL with a valid encoder +handle.\n\n +The internal reconfiguration process can be controlled from extern with the following access. +\code aacEncoder_SetParam(hAacEncoder, AACENC_CONTROL_STATE, AACENC_CTRLFLAGS); \endcode + + +\section encParams Encoder Parametrization + +All parameteres listed in ::AACENC_PARAM can be modified within an encoder instance. + +\subsection encMandatory Mandatory Encoder Parameters +The following parameters must be specified when the encoder instance is initialized. +\code +aacEncoder_SetParam(hAacEncoder, AACENC_AOT, value); +aacEncoder_SetParam(hAacEncoder, AACENC_BITRATE, value); +aacEncoder_SetParam(hAacEncoder, AACENC_SAMPLERATE, value); +aacEncoder_SetParam(hAacEncoder, AACENC_CHANNELMODE, value); +\endcode +Beyond that is an internal auto mode which preinitizializes the ::AACENC_BITRATE parameter +if the parameter was not set from extern. The bitrate depends on the number of effective +channels and sampling rate and is determined as follows. +\code +AAC-LC (AOT_AAC_LC): 1.5 bits per sample +HE-AAC (AOT_SBR): 0.625 bits per sample +HE-AAC v2 (AOT_PS): 0.5 bits per sample +\endcode + +\subsection channelMode Channel Mode Configuration +The input audio data is described with the ::AACENC_CHANNELMODE parameter in the +aacEncoder_SetParam() call. It is not possible to use the encoder instance with a 'number of +input channels' argument. Instead, the channelMode must be set as follows. +\code aacEncoder_SetParam(hAacEncoder, AACENC_CHANNELMODE, value); \endcode +The parameter is specified in ::CHANNEL_MODE and can be mapped from the number of input channels +in the following way. +\dontinclude main.cpp +\skip CHANNEL_MODE chMode = MODE_INVALID; +\until return + +\subsection encQual Audio Quality Considerations +The default encoder configuration is suggested to be used. Encoder tools such as TNS and PNS +are activated by default and are internally controlled (see \ref BEHAVIOUR_TOOLS). + +There is an additional quality parameter called ::AACENC_AFTERBURNER. In the default +configuration this quality switch is deactivated because it would cause a workload +increase which might be significant. If workload is not an issue in the application +we recommended to activate this feature. +\code aacEncoder_SetParam(hAacEncoder, AACENC_AFTERBURNER, 1); \endcode + + +\section audiochCfg Audio Channel Configuration +The MPEG standard refers often to the so-called Channel Configuration. This Channel Configuration is used for a fixed Channel +Mapping. The configurations 1-7 are predefined in MPEG standard and used for implicit signalling within the encoded bitstream. +For user defined Configurations the Channel Configuration is set to 0 and the Channel Mapping must be explecitly described with an appropriate +Program Config Element. The present Encoder implementation does not allow the user to configure this Channel Configuration from +extern. The Encoder implementation supports fixed Channel Modes which are mapped to Channel Configuration as follow. +\verbatim +-------------------------------------------------------------------- + ChannelMode | ChCfg | front_El | side_El | back_El | lfe_El +-----------------+--------+----------+----------+----------+-------- +MODE_1 | 1 | SCE | | | +MODE_2 | 2 | CPE | | | +MODE_1_2 | 3 | SCE, CPE | | | +MODE_1_2_1 | 4 | SCE, CPE | | SCE | +MODE_1_2_2 | 5 | SCE, CPE | | CPE | +MODE_1_2_2_1 | 6 | SCE, CPE | | CPE | LFE +-------------------------------------------------------------------- + - SCE: Single Channel Element. + - CPE: Channel Pair. + - SCE: Low Frequency Element. +\endverbatim + +Moreover, the Table describes all fixed Channel Elements for each Channel Mode which are assigned to a speaker arrangement. The +arrangement includes front, side, back and lfe Audio Channel Elements.\n +This mapping of Audio Channel Elements is defined in MPEG standard for Channel Config 1-7. The Channel assignment for MODE_1_1, +MODE_2_2 and MODE_2_1 is used from the ARIB standard. All other configurations are defined as suggested in MPEG.\n +In case of Channel Config 0 or writing matrix mixdown coefficients, the encoder enables the writing of Program Config Element +itself as described in \ref encPCE. The configuration used in Program Config Element refers to the denoted Table.\n +Beside the Channel Element assignment the Channel Modes are resposible for audio input data channel mapping. The Channel Mapping +of the audio data depends on the selected ::AACENC_CHANNELORDER which can be MPEG or WAV like order.\n +Following Table describes the complete channel mapping for both Channel Order configurations. +\verbatim +--------------------------------------------------------------------------------- +ChannelMode | MPEG-Channelorder | WAV-Channelorder +-----------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+--- +MODE_1 | 0 | | | | | | | | 0 | | | | | | | +MODE_2 | 0 | 1 | | | | | | | 0 | 1 | | | | | | +MODE_1_2 | 0 | 1 | 2 | | | | | | 2 | 0 | 1 | | | | | +MODE_1_2_1 | 0 | 1 | 2 | 3 | | | | | 2 | 0 | 1 | 3 | | | | +MODE_1_2_2 | 0 | 1 | 2 | 3 | 4 | | | | 2 | 0 | 1 | 3 | 4 | | | +MODE_1_2_2_1 | 0 | 1 | 2 | 3 | 4 | 5 | | | 2 | 0 | 1 | 4 | 5 | 3 | | +--------------------------------------------------------------------------------- +\endverbatim + +The denoted mapping is important for correct audio channel assignment when using MPEG or WAV ordering. The incoming audio +channels are distributed MPEG like starting at the front channels and ending at the back channels. The distribution is used as +described in Table concering Channel Config and fix channel elements. Please see the following example for clarification. + +\verbatim +Example: MODE_1_2_2_1 - WAV-Channelorder 5.1 +------------------------------------------ + Input Channel | Coder Channel +--------------------+--------------------- + 2 (front center) | 0 (SCE channel) + 0 (left center) | 1 (1st of 1st CPE) + 1 (right center) | 2 (2nd of 1st CPE) + 4 (left surround) | 3 (1st of 2nd CPE) + 5 (right surround) | 4 (2nd of 2nd CPE) + 3 (LFE) | 5 (LFE) +------------------------------------------ +\endverbatim + + +\section suppBitrates Supported Bitrates + +The FDK AAC Encoder provides a wide range of supported bitrates. +The minimum and maximum allowed bitrate depends on the Audio Object Type. For AAC-LC the minimum +bitrate is the bitrate that is required to write the most basic and minimal valid bitstream. +It consists of the bitstream format header information and other static/mandatory information +within the AAC payload. The maximum AAC framesize allowed by the MPEG-4 standard +determines the maximum allowed bitrate for AAC-LC. For HE-AAC and HE-AAC v2 a library internal +look-up table is used. + +A good working point in terms of audio quality, sampling rate and bitrate, is at 1 to 1.5 +bits/audio sample for AAC-LC, 0.625 bits/audio sample for HE-AAC and 0.5 bits/audio sample +for HE-AAC v2. For example for one channel with a sampling frequency of 48 kHz, the range from +48 kbit/s to 72 kbit/s achieves reasonable audio quality for AAC-LC. + +For HE-AAC and HE-AAC v2 the lowest possible audio input sampling frequency is 16 kHz because then the +AAC-LC core encoder operates in dual rate mode at its lowest possible sampling frequency, which is 8 kHz. +HE-AAC v2 requires stereo input audio data. + +The following table lists the supported bitrates for AAC-LC, HE-AAC and HE-AAC v2 encoding depending +on input sampling frequency ("Hz") and number of input channels ("chan"). The minimum and maximum +allowed bitrate ("BR Min", "BR Max") is given in bits per second. +In case the desired combination of bitrate and sampling frequency is not available ("NA") for HE-AAC or +HE-AAC v2 then the encoder will automatically switch to AAC-LC and give a command line warning. +Please note that in HE-AAC or HE-AAC v2 mode the encoder supports much higher bitrates than are +appropriate for HE-AAC or HE-AAC v2. For example, at a bitrate of more than 64 kbit/s for a stereo +audio signal at 44.1 kHz it usually makes sense to use AAC-LC, which will produce better audio +quality at that bitrate than HE-AAC or HE-AAC v2. + + +\verbatim + Config AAC-LC HE-AAC (SBR) HE-AACv2 (SBR+PS) + + Hz chan BR Min BR Max BR Min BR Max BR Min BR Max + +8000 1 758 48000 NA NA NA NA +11025 1 1045 66150 NA NA NA NA +12000 1 1137 72000 NA NA NA NA +16000 1 1516 96000 8000 48000 NA NA +22050 1 2089 132300 8000 64000 NA NA +24000 1 2274 144000 8000 64000 NA NA +32000 1 3032 192000 8000 64000 NA NA +44100 1 4178 264576 8000 64000 NA NA +48000 1 4547 288000 12000 64000 NA NA +64000 1 6063 384000 24000 160000 NA NA +88200 1 8355 529200 24000 160000 NA NA +96000 1 9094 576000 24000 160000 NA NA +----------------------------------------------------------------------------------- +8000 2 1071 96000 NA NA NA NA +11025 2 1476 132300 NA NA NA NA +12000 2 1606 144000 NA NA NA NA +16000 2 2141 192000 16000 96000 8000 48000 +22050 2 2951 264600 16000 128000 8000 64000 +24000 2 3211 288000 16000 128000 8000 64000 +32000 2 4282 384000 16000 128000 8000 64000 +44100 2 5900 529152 16000 128000 8000 64000 +48000 2 6422 576000 16000 128000 12000 64000 +64000 2 8563 768000 32000 256000 24000 160000 +88200 2 11801 1058400 32000 256000 24000 160000 +96000 2 12844 1152000 32000 256000 24000 160000 +----------------------------------------------------------------------------------- +8000 3 1383 144000 NA NA NA NA +11025 3 1906 198450 NA NA NA NA +12000 3 2075 216000 NA NA NA NA +16000 3 2766 288000 26667 120000 NA NA +22050 3 3812 396900 26667 160000 NA NA +24000 3 4149 432000 26667 160000 NA NA +32000 3 5532 576000 26667 160000 NA NA +44100 3 7623 793728 26667 160000 NA NA +48000 3 8297 864000 29996 160000 NA NA +64000 3 11063 1152000 59996 400000 NA NA +88200 3 15246 1587600 59996 400000 NA NA +96000 3 16594 1728000 59996 400000 NA NA +----------------------------------------------------------------------------------- +8000 4 1696 192000 NA NA NA NA +11025 4 2337 264600 NA NA NA NA +12000 4 2543 288000 NA NA NA NA +16000 4 3391 384000 40000 160000 NA NA +22050 4 4673 529200 40000 213330 NA NA +24000 4 5086 576000 40000 213330 NA NA +32000 4 6782 768000 40000 213330 NA NA +44100 4 9345 1058304 40000 213330 NA NA +48000 4 10172 1152000 40000 213330 NA NA +64000 4 13563 1536000 80000 533330 NA NA +88200 4 18691 2116800 80000 533330 NA NA +96000 4 20344 2304000 80000 533330 NA NA +----------------------------------------------------------------------------------- +8000 5 2008 240000 NA NA NA NA +11025 5 2768 330750 NA NA NA NA +12000 5 3012 360000 NA NA NA NA +16000 5 4016 480000 43244 184612 NA NA +22050 5 5535 661500 43244 246152 NA NA +24000 5 6024 720000 43244 246152 NA NA +32000 5 8032 960000 43244 246152 NA NA +44100 5 11068 1322880 43244 246152 NA NA +48000 5 12047 1440000 46140 246152 NA NA +64000 5 16063 1920000 92296 615384 NA NA +88200 5 22137 2646000 92296 615384 NA NA +96000 5 24094 2880000 92296 615384 NA NA +----------------------------------------------------------------------------------- +8000 5.1 2321 240000 NA NA NA NA +11025 5.1 3198 330750 NA NA NA NA +12000 5.1 3481 360000 NA NA NA NA +16000 5.1 4641 480000 45715 199990 NA NA +22050 5.1 6396 661500 45715 266658 NA NA +24000 5.1 6961 720000 45715 266658 NA NA +32000 5.1 9282 960000 45715 266658 NA NA +44100 5.1 12790 1322880 45715 266658 NA NA +48000 5.1 13922 1440000 49982 266658 NA NA +64000 5.1 18563 1920000 99982 666658 NA NA +88200 5.1 25582 2646000 99982 666658 NA NA +96000 5.1 27844 2880000 99982 666658 NA NA + +\endverbatim \n + +\section reommendedConfig Recommended Sampling Rate and Bitrate Combinations + +The following table provides an overview of recommended encoder configuration parameters +which we determined by virtue of numerous listening tests. + +\subsection reommendedConfigLC AAC-LC, HE-AAC, HE-AACv2. +\verbatim +----------------------------------------------------------------------------------- +Audio Object Type | Bit Rate Range | Supported | Preferred | No. of + | [bit/s] | Sampling Rates | Sampl. | Chan. + | | [kHz] | Rate | + | | | [kHz] | +-------------------+------------------+-----------------------+------------+------- +AAC LC + SBR + PS | 8000 - 11999 | 22.05, 24.00 | 24.00 | 2 +AAC LC + SBR + PS | 12000 - 17999 | 32.00 | 32.00 | 2 +AAC LC + SBR + PS | 18000 - 39999 | 32.00, 44.10, 48.00 | 44.10 | 2 +AAC LC + SBR + PS | 40000 - 56000 | 32.00, 44.10, 48.00 | 48.00 | 2 +-------------------+------------------+-----------------------+------------+------- +AAC LC + SBR | 8000 - 11999 | 22.05, 24.00 | 24.00 | 1 +AAC LC + SBR | 12000 - 17999 | 32.00 | 32.00 | 1 +AAC LC + SBR | 18000 - 39999 | 32.00, 44.10, 48.00 | 44.10 | 1 +AAC LC + SBR | 40000 - 56000 | 32.00, 44.10, 48.00 | 48.00 | 1 +AAC LC + SBR | 16000 - 27999 | 32.00, 44.10, 48.00 | 32.00 | 2 +AAC LC + SBR | 28000 - 63999 | 32.00, 44.10, 48.00 | 44.10 | 2 +AAC LC + SBR | 64000 - 128000 | 32.00, 44.10, 48.00 | 48.00 | 2 +-------------------+------------------+-----------------------+------------+------- +AAC LC + SBR | 64000 - 69999 | 32.00, 44.10, 48.00 | 32.00 | 5, 5.1 +AAC LC + SBR | 70000 - 159999 | 32.00, 44.10, 48.00 | 44.10 | 5, 5.1 +AAC LC + SBR | 160000 - 319999 | 32.00, 44.10, 48.00 | 48.00 | 5, 5.1 +AAC LC + SBR | 320000 - 640000 | 64.00, 88.20, 96.00 | 96.00 | 5, 5.1 +-------------------+------------------+-----------------------+------------+------- +AAC LC | 8000 - 15999 | 11.025, 12.00, 16.00 | 12.00 | 1 +AAC LC | 16000 - 23999 | 16.00 | 16.00 | 1 +AAC LC | 24000 - 31999 | 16.00, 22.05, 24.00 | 24.00 | 1 +AAC LC | 32000 - 55999 | 32.00 | 32.00 | 1 +AAC LC | 56000 - 160000 | 32.00, 44.10, 48.00 | 44.10 | 1 +AAC LC | 160001 - 288000 | 48.00 | 48.00 | 1 +-------------------+------------------+-----------------------+------------+------- +AAC LC | 16000 - 23999 | 11.025, 12.00, 16.00 | 12.00 | 2 +AAC LC | 24000 - 31999 | 16.00 | 16.00 | 2 +AAC LC | 32000 - 39999 | 16.00, 22.05, 24.00 | 22.05 | 2 +AAC LC | 40000 - 95999 | 32.00 | 32.00 | 2 +AAC LC | 96000 - 111999 | 32.00, 44.10, 48.00 | 32.00 | 2 +AAC LC | 112000 - 320001 | 32.00, 44.10, 48.00 | 44.10 | 2 +AAC LC | 320002 - 576000 | 48.00 | 48.00 | 2 +-------------------+------------------+-----------------------+------------+------- +AAC LC | 160000 - 239999 | 32.00 | 32.00 | 5, 5.1 +AAC LC | 240000 - 279999 | 32.00, 44.10, 48.00 | 32.00 | 5, 5.1 +AAC LC | 280000 - 800000 | 32.00, 44.10, 48.00 | 44.10 | 5, 5.1 +----------------------------------------------------------------------------------- +\endverbatim \n + +\subsection reommendedConfigLD AAC-LD, AAC-ELD, AAC-ELD with SBR. +\verbatim +----------------------------------------------------------------------------------- +Audio Object Type | Bit Rate Range | Supported | Preferred | No. of + | [bit/s] | Sampling Rates | Sampl. | Chan. + | | [kHz] | Rate | + | | | [kHz] | +-------------------+------------------+-----------------------+------------+------- +ELD + SBR | 16000 - 24999 | 32.00 - 44.10 | 32.00 | 1 +ELD + SBR | 25000 - 31999 | 32.00 - 48.00 | 32.00 | 1 +ELD + SBR | 32000 - 64000 | 32.00 - 48.00 | 48.00 | 1 +-------------------+------------------+-----------------------+------------+------- +ELD + SBR | 32000 - 51999 | 32.00 - 48.00 | 44.10 | 2 +ELD + SBR | 52000 - 128000 | 32.00 - 48.00 | 48.00 | 2 +-------------------+------------------+-----------------------+------------+------- +ELD + SBR | 72000 - 192000 | 44.10 - 48.00 | 48.00 | 3 +-------------------+------------------+-----------------------+------------+------- +ELD + SBR | 96000 - 256000 | 44.10 - 48.00 | 48.00 | 4 +-------------------+------------------+-----------------------+------------+------- +ELD + SBR | 120000 - 320000 | 44.10 - 48.00 | 48.00 | 5 +-------------------+------------------+-----------------------+------------+------- +LD, ELD | 16000 - 19999 | 16.00 - 24.00 | 16.00 | 1 +LD, ELD | 20000 - 39999 | 16.00 - 32.00 | 24.00 | 1 +LD, ELD | 40000 - 49999 | 22.05 - 32.00 | 32.00 | 1 +LD, ELD | 50000 - 61999 | 24.00 - 44.10 | 32.00 | 1 +LD, ELD | 62000 - 84999 | 32.00 - 48.00 | 44.10 | 1 +LD, ELD | 85000 - 192000 | 44.10 - 48.00 | 48.00 | 1 +-------------------+------------------+-----------------------+------------+------- +LD, ELD | 64000 - 75999 | 24.00 - 32.00 | 32.00 | 2 +LD, ELD | 76000 - 97999 | 24.00 - 44.10 | 32.00 | 2 +LD, ELD | 98000 - 135999 | 32.00 - 48.00 | 44.10 | 2 +LD, ELD | 136000 - 384000 | 44.10 - 48.00 | 48.00 | 2 +-------------------+------------------+-----------------------+------------+------- +LD, ELD | 96000 - 113999 | 24.00 - 32.00 | 32.00 | 3 +LD, ELD | 114000 - 146999 | 24.00 - 44.10 | 32.00 | 3 +LD, ELD | 147000 - 203999 | 32.00 - 48.00 | 44.10 | 3 +LD, ELD | 204000 - 576000 | 44.10 - 48.00 | 48.00 | 3 +-------------------+------------------+-----------------------+------------+------- +LD, ELD | 128000 - 151999 | 24.00 - 32.00 | 32.00 | 4 +LD, ELD | 152000 - 195999 | 24.00 - 44.10 | 32.00 | 4 +LD, ELD | 196000 - 271999 | 32.00 - 48.00 | 44.10 | 4 +LD, ELD | 272000 - 768000 | 44.10 - 48.00 | 48.00 | 4 +-------------------+------------------+-----------------------+------------+------- +LD, ELD | 160000 - 189999 | 24.00 - 32.00 | 32.00 | 5 +LD, ELD | 190000 - 244999 | 24.00 - 44.10 | 32.00 | 5 +LD, ELD | 245000 - 339999 | 32.00 - 48.00 | 44.10 | 5 +LD, ELD | 340000 - 960000 | 44.10 - 48.00 | 48.00 | 5 +----------------------------------------------------------------------------------- +\endverbatim \n + +\page ENCODERBEHAVIOUR Encoder Behaviour + +\section BEHAVIOUR_BANDWIDTH Bandwidth + +The FDK AAC encoder usually does not use the full frequency range of the input signal, but restricts the bandwidth +according to certain library-internal settings. They can be changed in the table "bandWidthTable" in the +file bandwidth.cpp (if available), or via command-line argument "-w" (see chapter \ref CommandLineUsage). + +However it is not recommended to change these settings, because they are based on numerious listening +tests and careful tweaks to ensure the best overall encoding quality. + +Theoretically a signal of for example 48 kHz can contain frequencies up to 24 kHz, but to use this full range +in an audio encoder usually does not make sense. Usually the encoder has a very limited amount of +bits to spend (typically 128 kbit/s for stereo 48 kHz content) and to allow full range bandwidth would +waste a lot of these bits for frequencies the human ear is hardly able to perceive anyway, if at all. Hence it +is wise to use the available bits for the really important frequency range and just skip the rest. +At lower bitrates (e. g. <= 80 kbit/s for stereo 48 kHz content) the encoder will choose an even smaller +bandwidth, because an encoded signal with smaller bandwidth and hence less artifacts sounds better than a signal +with higher bandwidth but then more coding artefacts across all frequencies. These artefacts would occur if +small bitrates and high bandwidths are chosen because the available bits are just not enough to encode all +frequencies well. + +Unfortunately some people evaluate encoding quality based on possible bandwidth as well, but it is a two-sided +sword considering the trade-off described above. + +Another aspect is workload consumption. The higher the allowed bandwidth, the more frequency lines have to be +processed, which in turn increases the workload. + +\section FRAMESIZES_AND_BIT_RESERVOIR Frame Sizes & Bit Reservoir + +For AAC there is a difference between constant bit rate and constant frame +length due to the so-called bit reservoir technique, which allows the encoder to use less +bits in an AAC frame for those audio signal sections which are easy to encode, +and then spend them at a later point in +time for more complex audio sections. The extent to which this "bit exchange" +is done is limited to allow for reliable and relatively low delay real time +streaming. +Over a longer period in time the bitrate will be constant in the AAC constant +bitrate mode, e.g. for ISDN transmission. This means that in AAC each bitstream +frame will in general have a different length in bytes but over time it +will reach the target bitrate. One could also make an MPEG compliant +AAC encoder which always produces constant length packages for each AAC frame, +but the audio quality would be considerably worse since the bit reservoir +technique would have to be switched off completely. A higher bit rate would have +to be used to get the same audio quality as with an enabled bit reservoir. + +The maximum AAC frame length, regardless of the available bit reservoir, is defined +as 6144 bits per channel. + +For mp3 by the way, the same bit reservoir technique exists, but there each bit +stream frame has a constant length for a given bit rate (ignoring the +padding byte). In mp3 there is a so-called "back pointer" which tells +the decoder which bits belong to the current mp3 frame - and in general some or +many bits have been transmitted in an earlier mp3 frame. Basically this leads to +the same "bit exchange between mp3 frames" as in AAC but with virtually constant +length frames. + +This variable frame length at "constant bit rate" is not something special +in this Fraunhofer IIS AAC encoder. AAC has been designed in that way. + +\subsection BEHAVIOUR_ESTIM_AVG_FRAMESIZES Estimating Average Frame Sizes + +A HE-AAC v1 or v2 audio frame contains 2048 PCM samples per channel (there is +also one mode with 1920 samples per channel but this is only for special purposes +such as DAB+ digital radio). + +The number of HE-AAC frames \f$N\_FRAMES\f$ per second at 44.1 kHz is: + +\f[ +N\_FRAMES = 44100 / 2048 = 21.5332 +\f] + +At a bit rate of 8 kbps the average number of bits per frame \f$N\_BITS\_PER\_FRAME\f$ is: + +\f[ +N\_BITS\_PER\_FRAME = 8000 / 21.5332 = 371.52 +\f] + +which is about 46.44 bytes per encoded frame. + +At a bit rate of 32 kbps, which is quite high for single channel HE-AAC v1, it is: + +\f[ +N\_BITS\_PER\_FRAME = 32000 / 21.5332 = 1486 +\f] + +which is about 185.76 bytes per encoded frame. + +These bits/frame figures are average figures where each AAC frame generally has a different +size in bytes. To calculate the same for AAC-LC just use 1024 instead of 2048 PCM samples per +frame and channel. +For AAC-LD/ELD it is either 480 or 512 PCM samples per frame and channel. + + +\section BEHAVIOUR_TOOLS Encoder Tools + +The AAC encoder supports TNS, PNS, MS, Intensity and activates these tools depending on the audio signal and +the encoder configuration (i.e. bitrate or AOT). It is not required to configure these tools manually. + +PNS improves encoding quality only for certain bitrates. Therefore it makes sense to activate PNS only for +these bitrates and save the processing power required for PNS (about 10 % of the encoder) when using other +bitrates. This is done automatically inside the encoder library. PNS is disabled inside the encoder library if +an MPEG-2 AOT is choosen since PNS is an MPEG-4 AAC feature. + +If SBR is activated, the encoder automatically deactivates PNS internally. If TNS is disabled but PNS is allowed, +the encoder deactivates PNS calculation internally. + + +*/ + +#ifndef _AAC_ENC_LIB_H_ +#define _AAC_ENC_LIB_H_ + +#include "machine_type.h" +#include "FDK_audio.h" + + +/** + * AAC encoder error codes. + */ +typedef enum { + AACENC_OK = 0x0000, /*!< No error happened. All fine. */ + + AACENC_INVALID_HANDLE = 0x0020, /*!< Handle passed to function call was invalid. */ + AACENC_MEMORY_ERROR = 0x0021, /*!< Memory allocation failed. */ + AACENC_UNSUPPORTED_PARAMETER = 0x0022, /*!< Parameter not available. */ + AACENC_INVALID_CONFIG = 0x0023, /*!< Configuration not provided. */ + + AACENC_INIT_ERROR = 0x0040, /*!< General initialization error. */ + AACENC_INIT_AAC_ERROR = 0x0041, /*!< AAC library initialization error. */ + AACENC_INIT_SBR_ERROR = 0x0042, /*!< SBR library initialization error. */ + AACENC_INIT_TP_ERROR = 0x0043, /*!< Transport library initialization error. */ + AACENC_INIT_META_ERROR = 0x0044, /*!< Meta data library initialization error. */ + + AACENC_ENCODE_ERROR = 0x0060, /*!< The encoding process was interrupted by an unexpected error. */ + + AACENC_ENCODE_EOF = 0x0080 /*!< End of file reached. */ + +} AACENC_ERROR; + + +/** + * AAC encoder buffer descriptors identifier. + * This identifier are used within buffer descriptors AACENC_BufDesc::bufferIdentifiers. + */ +typedef enum { + /* Input buffer identifier. */ + IN_AUDIO_DATA = 0, /*!< Audio input buffer, interleaved INT_PCM samples. */ + IN_ANCILLRY_DATA = 1, /*!< Ancillary data to be embedded into bitstream. */ + IN_METADATA_SETUP = 2, /*!< Setup structure for embedding meta data. */ + + /* Output buffer identifier. */ + OUT_BITSTREAM_DATA = 3, /*!< Buffer holds bitstream output data. */ + OUT_AU_SIZES = 4 /*!< Buffer contains sizes of each access unit. This information + is necessary for superframing. */ + +} AACENC_BufferIdentifier; + + +/** + * AAC encoder handle. + */ +typedef struct AACENCODER *HANDLE_AACENCODER; + + +/** + * Provides some info about the encoder configuration. + */ +typedef struct { + + UINT maxOutBufBytes; /*!< Maximum number of encoder bitstream bytes within one frame. + Size depends on maximum number of supported channels in encoder instance. + For superframing (as used for example in DAB+), size has to be a multiple accordingly. */ + + UINT maxAncBytes; /*!< Maximum number of ancillary data bytes which can be inserted into + bitstream within one frame. */ + + UINT inBufFillLevel; /*!< Internal input buffer fill level in samples per channel. This parameter + will automatically be cleared if samplingrate or channel(Mode/Order) changes. */ + + UINT inputChannels; /*!< Number of input channels expected in encoding process. */ + + UINT frameLength; /*!< Amount of input audio samples consumed each frame per channel, depending + on audio object type configuration. */ + + UINT encoderDelay; /*!< Codec delay in PCM samples/channel. Depends on framelength and AOT. Does not + include framing delay for filling up encoder PCM input buffer. */ + + UCHAR confBuf[64]; /*!< Configuration buffer in binary format as an AudioSpecificConfig + or StreamMuxConfig according to the selected transport type. */ + + UINT confSize; /*!< Number of valid bytes in confBuf. */ + +} AACENC_InfoStruct; + + +/** + * Describes the input and output buffers for an aacEncEncode() call. + */ +typedef struct { + INT numBufs; /*!< Number of buffers. */ + void **bufs; /*!< Pointer to vector containing buffer addresses. */ + INT *bufferIdentifiers; /*!< Identifier of each buffer element. See ::AACENC_BufferIdentifier. */ + INT *bufSizes; /*!< Size of each buffer in 8-bit bytes. */ + INT *bufElSizes; /*!< Size of each buffer element in bytes. */ + +} AACENC_BufDesc; + + +/** + * Defines the input arguments for an aacEncEncode() call. + */ +typedef struct { + INT numInSamples; /*!< Number of valid input audio samples (multiple of input channels). */ + INT numAncBytes; /*!< Number of ancillary data bytes to be encoded. */ + +} AACENC_InArgs; + + +/** + * Defines the output arguments for an aacEncEncode() call. + */ +typedef struct { + INT numOutBytes; /*!< Number of valid bitstream bytes generated during aacEncEncode(). */ + INT numInSamples; /*!< Number of input audio samples consumed by the encoder. */ + INT numAncBytes; /*!< Number of ancillary data bytes consumed by the encoder. */ + +} AACENC_OutArgs; + + +/** + * Meta Data Compression Profiles. + */ +typedef enum { + AACENC_METADATA_DRC_NONE = 0, /*!< None. */ + AACENC_METADATA_DRC_FILMSTANDARD = 1, /*!< Film standard. */ + AACENC_METADATA_DRC_FILMLIGHT = 2, /*!< Film light. */ + AACENC_METADATA_DRC_MUSICSTANDARD = 3, /*!< Music standard. */ + AACENC_METADATA_DRC_MUSICLIGHT = 4, /*!< Music light. */ + AACENC_METADATA_DRC_SPEECH = 5 /*!< Speech. */ + +} AACENC_METADATA_DRC_PROFILE; + + +/** + * Meta Data setup structure. + */ +typedef struct { + + AACENC_METADATA_DRC_PROFILE drc_profile; /*!< MPEG DRC compression profile. See ::AACENC_METADATA_DRC_PROFILE. */ + AACENC_METADATA_DRC_PROFILE comp_profile; /*!< ETSI heavy compression profile. See ::AACENC_METADATA_DRC_PROFILE. */ + + INT drc_TargetRefLevel; /*!< Used to define expected level to: + Scaled with 16 bit. x*2^16. */ + INT comp_TargetRefLevel; /*!< Adjust limiter to avoid overload. + Scaled with 16 bit. x*2^16. */ + + INT prog_ref_level_present; /*!< Flag, if prog_ref_level is present */ + INT prog_ref_level; /*!< Programme Reference Level = Dialogue Level: + -31.75dB .. 0 dB ; stepsize: 0.25dB + Scaled with 16 bit. x*2^16.*/ + + UCHAR PCE_mixdown_idx_present; /*!< Flag, if dmx-idx should be written in programme config element */ + UCHAR ETSI_DmxLvl_present; /*!< Flag, if dmx-lvl should be written in ETSI-ancData */ + + SCHAR centerMixLevel; /*!< Center downmix level (0...7, according to table) */ + SCHAR surroundMixLevel; /*!< Surround downmix level (0...7, according to table) */ + + UCHAR dolbySurroundMode; /*!< Indication for Dolby Surround Encoding Mode. + - 0: Dolby Surround mode not indicated + - 1: 2-ch audio part is not Dolby surround encoded + - 2: 2-ch audio part is Dolby surround encoded */ +} AACENC_MetaData; + + +/** + * AAC encoder control flags. + * + * In interaction with the ::AACENC_CONTROL_STATE parameter it is possible to get information about the internal + * initialization process. It is also possible to overwrite the internal state from extern when necessary. + */ +typedef enum +{ + AACENC_INIT_NONE = 0x0000, /*!< Do not trigger initialization. */ + AACENC_INIT_CONFIG = 0x0001, /*!< Initialize all encoder modules configuration. */ + AACENC_INIT_STATES = 0x0002, /*!< Reset all encoder modules history buffer. */ + AACENC_INIT_TRANSPORT = 0x1000, /*!< Initialize transport lib with new parameters. */ + AACENC_RESET_INBUFFER = 0x2000, /*!< Reset fill level of internal input buffer. */ + AACENC_INIT_ALL = 0xFFFF /*!< Initialize all. */ +} +AACENC_CTRLFLAGS; + + +/** + * \brief AAC encoder setting parameters. + * + * Use aacEncoder_SetParam() function to configure, or use aacEncoder_GetParam() function to read + * the internal status of the following parameters. + */ +typedef enum +{ + AACENC_AOT = 0x0100, /*!< Audio object type. See ::AUDIO_OBJECT_TYPE in FDK_audio.h. + - 2: MPEG-4 AAC Low Complexity. + - 5: MPEG-4 AAC Low Complexity with Spectral Band Replication (HE-AAC). + - 29: MPEG-4 AAC Low Complexity with Spectral Band Replication and Parametric Stereo (HE-AAC v2). + This configuration can be used only with stereo input audio data. + - 23: MPEG-4 AAC Low-Delay. + - 39: MPEG-4 AAC Enhanced Low-Delay. Since there is no ::AUDIO_OBJECT_TYPE for ELD in + combination with SBR defined, enable SBR explicitely by ::AACENC_SBR_MODE parameter. + - 129: MPEG-2 AAC Low Complexity. + - 132: MPEG-2 AAC Low Complexity with Spectral Band Replication (HE-AAC). + - 156: MPEG-2 AAC Low Complexity with Spectral Band Replication and Parametric Stereo (HE-AAC v2). + This configuration can be used only with stereo input audio data. */ + + AACENC_BITRATE = 0x0101, /*!< Total encoder bitrate. This parameter is mandatory and interacts with ::AACENC_BITRATEMODE. + - CBR: Bitrate in bits/second. + See \ref suppBitrates for details. */ + + AACENC_BITRATEMODE = 0x0102, /*!< Bitrate mode. Configuration can be different kind of bitrate configurations: + - 0: Constant bitrate, use bitrate according to ::AACENC_BITRATE. (default) + Within none LD/ELD ::AUDIO_OBJECT_TYPE, the CBR mode makes use of full allowed bitreservoir. + In contrast, at Low-Delay ::AUDIO_OBJECT_TYPE the bitreservoir is kept very small. + - 8: LD/ELD full bitreservoir for packet based transmission. */ + + AACENC_SAMPLERATE = 0x0103, /*!< Audio input data sampling rate. Encoder supports following sampling rates: + 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 */ + + AACENC_SBR_MODE = 0x0104, /*!< Configure SBR independently of the chosen Audio Object Type ::AUDIO_OBJECT_TYPE:. + This parameter is only available for ELD. + - 0: Disable Spectral Band Replication. + - 1: Enable Spectral Band Replication. */ + + AACENC_GRANULE_LENGTH = 0x0105, /*!< Core encoder (AAC) audio frame length in samples: + - 1024: Default configuration. + - 512: Optional length in LD/ELD configuration. + - 480: Default LD/ELD configuration. */ + + AACENC_CHANNELMODE = 0x0106, /*!< Set explicit channel mode. Channel mode must match with number of input channels. + - 1-6: MPEG channel modes supported, see ::CHANNEL_MODE in FDK_audio.h. */ + + AACENC_CHANNELORDER = 0x0107, /*!< Input audio data channel ordering scheme: + - 0: MPEG channel ordering (e. g. 5.1: C, L, R, SL, SR, LFE). (default) + - 1: WAVE file format channel ordering (e. g. 5.1: L, R, C, LFE, SL, SR). */ + + AACENC_AFTERBURNER = 0x0200, /*!< This parameter controls the use of the afterburner feature. + The afterburner is a type of analysis by synthesis algorithm which increases the + audio quality but also the required processing power. It is recommended to always + activate this if additional memory consumption and processing power consumption + is not a problem. If increased MHz and memory consumption are an issue then the MHz + and memory cost of this optional module need to be evaluated against the improvement + in audio quality on a case by case basis. + - 0: Disable afterburner (default). + - 1: Enable afterburner. */ + + AACENC_BANDWIDTH = 0x0203, /*!< Core encoder audio bandwidth: + - 0: Determine bandwidth internally (default, see chapter \ref BEHAVIOUR_BANDWIDTH). + - 1 to fs/2: Frequency bandwidth in Hertz. (Experts only, better do not + touch this value to avoid degraded audio quality) */ + + AACENC_TRANSMUX = 0x0300, /*!< Transport type to be used. See ::TRANSPORT_TYPE in FDK_audio.h. Following + types can be configured in encoder library: + - 0: raw access units + - 1: ADIF bitstream format + - 2: ADTS bitstream format + - 6: Audio Mux Elements (LATM) with muxConfigPresent = 1 + - 7: Audio Mux Elements (LATM) with muxConfigPresent = 0, out of band StreamMuxConfig + - 10: Audio Sync Stream (LOAS) */ + + AACENC_HEADER_PERIOD = 0x0301, /*!< Frame count period for sending in-band configuration buffers within LATM/LOAS + transport layer. Additionally this parameter configures the PCE repetition period + in raw_data_block(). See \ref encPCE. + - 0xFF: auto-mode default 10 for TT_MP4_ADTS, TT_MP4_LOAS and TT_MP4_LATM_MCP1, otherwise 0. + - n: Frame count period. */ + + AACENC_SIGNALING_MODE = 0x0302, /*!< Signaling mode of the extension AOT: + - 0: Implicit backward compatible signaling. (default) + - 1: Explicit SBR and implicit PS signaling. + - 2: Explicit hierarchical signaling. + + The use of backward-compatible implicit signaling is recommended if the user specically + aims at preserving compatibility with decoders only capable of decoding AAC-LC. Otherwise + use non-backward-compatible explicit signaling. + Bitstream formats ADTS and ADIF can only do implicit signaling. */ + + AACENC_TPSUBFRAMES = 0x0303, /*!< Number of sub frames in a transport frame for LOAS/LATM or ADTS (default 1). + - ADTS: Maximum number of sub frames restricted to 4. + - LOAS/LATM: Maximum number of sub frames restricted to 2.*/ + + AACENC_PROTECTION = 0x0306, /*!< Configure protection in tranpsort layer: + - 0: No protection. (default) + - 1: CRC active for ADTS bitstream format. */ + + AACENC_ANCILLARY_BITRATE = 0x0500, /*!< Constant ancillary data bitrate in bits/second. + - 0: Either no ancillary data or insert exact number of bytes, denoted via + input parameter, numAncBytes in AACENC_InArgs. + - else: Insert ancillary data with specified bitrate. */ + + AACENC_METADATA_MODE = 0x0600, /*!< Configure Meta Data. See ::AACENC_MetaData for further details: + - 0: Do not embed any metadata. + - 1: Embed MPEG defined metadata only. + - 2: Embed all metadata. */ + + AACENC_CONTROL_STATE = 0xFF00, /*!< There is an automatic process which internally reconfigures the encoder instance + when a configuration parameter changed or an error occured. This paramerter allows + overwriting or getting the control status of this process. See ::AACENC_CTRLFLAGS. */ + + AACENC_NONE = 0xFFFF /*!< ------ */ + +} AACENC_PARAM; + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Open an instance of the encoder. + * + * Allocate memory for an encoder instance with a functional range denoted by the function parameters. + * Preinitialize encoder instance with default configuration. + * + * \param phAacEncoder A pointer to an encoder handle. Initialized on return. + * \param encModules Specify encoder modules to be supported in this encoder instance: + * - 0x0: Allocate memory for all available encoder modules. + * - else: Select memory allocation regarding encoder modules. Following flags are possible and can be combined. + * - 0x01: AAC module. + * - 0x02: SBR module. + * - 0x04: PS module. + * - 0x10: Metadata module. + * - example: (0x01|0x02|0x04|0x10) allocates all modules and is equivalent to default configuration denotet by 0x0. + * \param maxChannels Number of channels to be allocated. This parameter can be used in different ways: + * - 0: Allocate maximum number of AAC and SBR channels as supported by the library. + * - nChannels: Use same maximum number of channels for allocating memory in AAC and SBR module. + * - nChannels | (nSbrCh<<8): Number of SBR channels can be different to AAC channels to save data memory. + * + * \return + * - AACENC_OK, on succes. + * - AACENC_INVALID_HANDLE, AACENC_MEMORY_ERROR, AACENC_INVALID_CONFIG, on failure. + */ +AACENC_ERROR aacEncOpen( + HANDLE_AACENCODER *phAacEncoder, + const UINT encModules, + const UINT maxChannels + ); + + +/** + * \brief Close the encoder instance. + * + * Deallocate encoder instance and free whole memory. + * + * \param phAacEncoder Pointer to the encoder handle to be deallocated. + * + * \return + * - AACENC_OK, on success. + * - AACENC_INVALID_HANDLE, on failure. + */ +AACENC_ERROR aacEncClose( + HANDLE_AACENCODER *phAacEncoder + ); + + +/** + * \brief Encode audio data. + * + * This function is mainly for encoding audio data. In addition the function can be used for an encoder (re)configuration + * process. + * - PCM input data will be retrieved from external input buffer until the fill level allows encoding a single frame. + * This functionality allows an external buffer with reduced size in comparison to the AAC or HE-AAC audio frame length. + * - If the value of the input samples argument is zero, just internal reinitialization will be applied if it is + * requested. + * - At the end of a file the flushing process can be triggerd via setting the value of the input samples argument to -1. + * The encoder delay lines are fully flushed when the encoder returns no valid bitstream data AACENC_OutArgs::numOutBytes. + * Furthermore the end of file is signaled by the return value AACENC_ENCODE_EOF. + * - If an error occured in the previous frame or any of the encoder parameters changed, an internal reinitialization + * process will be applied before encoding the incoming audio samples. + * - The function can also be used for an independent reconfiguration process without encoding. The first parameter has to be a + * valid encoder handle and all other parameters can be set to NULL. + * - If the size of the external bitbuffer in outBufDesc is not sufficient for writing the whole bitstream, an internal + * error will be the return value and a reconfiguration will be triggered. + * + * \param hAacEncoder A valid AAC encoder handle. + * \param inBufDesc Input buffer descriptor, see AACENC_BufDesc: + * - At least one input buffer with audio data is expected. + * - Optionally a second input buffer with ancillary data can be fed. + * \param outBufDesc Output buffer descriptor, see AACENC_BufDesc: + * - Provide one output buffer for the encoded bitstream. + * \param inargs Input arguments, see AACENC_InArgs. + * \param outargs Output arguments, AACENC_OutArgs. + * + * \return + * - AACENC_OK, on success. + * - AACENC_INVALID_HANDLE, AACENC_ENCODE_ERROR, on failure in encoding process. + * - AACENC_INVALID_CONFIG, AACENC_INIT_ERROR, AACENC_INIT_AAC_ERROR, AACENC_INIT_SBR_ERROR, AACENC_INIT_TP_ERROR, + * AACENC_INIT_META_ERROR, on failure in encoder initialization. + * - AACENC_ENCODE_EOF, when flushing fully concluded. + */ +AACENC_ERROR aacEncEncode( + const HANDLE_AACENCODER hAacEncoder, + const AACENC_BufDesc *inBufDesc, + const AACENC_BufDesc *outBufDesc, + const AACENC_InArgs *inargs, + AACENC_OutArgs *outargs + ); + + +/** + * \brief Acquire info about present encoder instance. + * + * This function retrieves information of the encoder configuration. In addition to informative internal states, + * a configuration data block of the current encoder settings will be returned. The format is either Audio Specific Config + * in case of Raw Packets transport format or StreamMuxConfig in case of LOAS/LATM transport format. The configuration + * data block is binary coded as specified in ISO/IEC 14496-3 (MPEG-4 audio), to be used directly for MPEG-4 File Format + * or RFC3016 or RFC3640 applications. + * + * \param hAacEncoder A valid AAC encoder handle. + * \param pInfo Pointer to AACENC_InfoStruct. Filled on return. + * + * \return + * - AACENC_OK, on succes. + * - AACENC_INIT_ERROR, on failure. + */ +AACENC_ERROR aacEncInfo( + const HANDLE_AACENCODER hAacEncoder, + AACENC_InfoStruct *pInfo + ); + + +/** + * \brief Set one single AAC encoder parameter. + * + * This function allows configuration of all encoder parameters specified in ::AACENC_PARAM. Each parameter must be + * set with a separate function call. An internal validation of the configuration value range will be done and an + * internal reconfiguration will be signaled. The actual configuration adoption is part of the subsequent aacEncEncode() call. + * + * \param hAacEncoder A valid AAC encoder handle. + * \param param Parameter to be set. See ::AACENC_PARAM. + * \param value Parameter value. See parameter description in ::AACENC_PARAM. + * + * \return + * - AACENC_OK, on success. + * - AACENC_INVALID_HANDLE, AACENC_UNSUPPORTED_PARAMETER, AACENC_INVALID_CONFIG, on failure. + */ +AACENC_ERROR aacEncoder_SetParam( + const HANDLE_AACENCODER hAacEncoder, + const AACENC_PARAM param, + const UINT value + ); + + +/** + * \brief Get one single AAC encoder parameter. + * + * This function is the complement to aacEncoder_SetParam(). After encoder reinitialization with user defined settings, + * the internal status can be obtained of each parameter, specified with ::AACENC_PARAM. + * + * \param hAacEncoder A valid AAC encoder handle. + * \param param Parameter to be returned. See ::AACENC_PARAM. + * + * \return Internal configuration value of specifed parameter ::AACENC_PARAM. + */ +UINT aacEncoder_GetParam( + const HANDLE_AACENCODER hAacEncoder, + const AACENC_PARAM param + ); + + +/** + * \brief Get information about encoder library build. + * + * Fill a given LIB_INFO structure with library version information. + * + * \param info Pointer to an allocated LIB_INFO struct. + * + * \return + * - AACENC_OK, on success. + * - AACENC_INVALID_HANDLE, AACENC_INIT_ERROR, on failure. + */ +AACENC_ERROR aacEncGetLibInfo( + LIB_INFO *info + ); + + +#ifdef __cplusplus +} +#endif + +#endif /* _AAC_ENC_LIB_H_ */ diff --git a/libAACenc/src/Android.mk b/libAACenc/src/Android.mk new file mode 100644 index 0000000..d3bbb9b --- /dev/null +++ b/libAACenc/src/Android.mk @@ -0,0 +1,53 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + aacenc.cpp \ + aacEnc_ram.cpp \ + band_nrg.cpp \ + block_switch.cpp \ + grp_data.cpp \ + metadata_main.cpp \ + pre_echo_control.cpp \ + quantize.cpp \ + tonality.cpp \ + aacenc_hcr.cpp \ + aacEnc_rom.cpp \ + bandwidth.cpp \ + channel_map.cpp \ + intensity.cpp \ + ms_stereo.cpp \ + psy_configuration.cpp \ + sf_estim.cpp \ + transform.cpp \ + aacenc_lib.cpp \ + aacenc_tns.cpp \ + bit_cnt.cpp \ + chaosmeasure.cpp \ + line_pe.cpp \ + noisedet.cpp \ + psy_main.cpp \ + spreading.cpp \ + aacenc_pns.cpp \ + adj_thr.cpp \ + bitenc.cpp \ + dyn_bits.cpp \ + metadata_compressor.cpp \ + pnsparam.cpp \ + qc_main.cpp \ + tns_param.cpp + +LOCAL_CFLAGS := -DANDROID + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../../libPCMutils/include \ + $(LOCAL_PATH)/../../libFDK/include \ + $(LOCAL_PATH)/../../libSYS/include \ + $(LOCAL_PATH)/../../libMpegTPEnc/include \ + $(LOCAL_PATH)/../../libSBRenc/include + +LOCAL_MODULE:= libAACenc + +include $(BUILD_STATIC_LIBRARY) diff --git a/libAACenc/src/aacEnc_ram.cpp b/libAACenc/src/aacEnc_ram.cpp new file mode 100644 index 0000000..3122bb8 --- /dev/null +++ b/libAACenc/src/aacEnc_ram.cpp @@ -0,0 +1,132 @@ +/****************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id: + Initial authors: M. Lohwasser, M. Gayer + Contents/description: + +******************************************************************************/ +/*! + \file + \brief Memory layout $Revision: 36838 $ + \author Markus Lohwasser +*/ + +#include "aacEnc_ram.h" + + C_ALLOC_MEM (AACdynamic_RAM, FIXP_DBL, AAC_ENC_DYN_RAM_SIZE/sizeof(FIXP_DBL)) + +/* + Static memory areas, must not be overwritten in other sections of the decoder ! +*/ + +/* + The structure AacEncoder contains all Encoder structures. +*/ + +C_ALLOC_MEM (Ram_aacEnc_AacEncoder, AAC_ENC, 1) + + +/* + The structure PSY_INTERNAl contains all psych configuration and data pointer. + * PsyStatic holds last and current Psych data. + * PsyInputBuffer contains time input. Signal is needed at the beginning of Psych. + Memory can be reused after signal is in time domain. + * PsyData contains spectral, nrg and threshold information. Necessary data are + copied into PsyOut, so memory is available after leaving psych. + * TnsData, ChaosMeasure, PnsData are temporarily necessary, e.g. use memory from + PsyInputBuffer. +*/ + +C_ALLOC_MEM2 (Ram_aacEnc_PsyElement, PSY_ELEMENT, 1, (6)) + +C_ALLOC_MEM (Ram_aacEnc_PsyInternal, PSY_INTERNAL, 1) +C_ALLOC_MEM2 (Ram_aacEnc_PsyStatic, PSY_STATIC, 1, (6)) + +C_ALLOC_MEM2 (Ram_aacEnc_PsyInputBuffer, INT_PCM, MAX_INPUT_BUFFER_SIZE, (6)) + + PSY_DYNAMIC *GetRam_aacEnc_PsyDynamic (int n, UCHAR* dynamic_RAM) { + FDK_ASSERT(dynamic_RAM!=0); + return ((PSY_DYNAMIC*) (dynamic_RAM + P_BUF_1 + n*sizeof(PSY_DYNAMIC))); + } + + C_ALLOC_MEM (Ram_bsOutbuffer, UCHAR, OUTPUTBUFFER_SIZE) + +/* + The structure PSY_OUT holds all psychoaccoustic data needed + in quantization module +*/ +C_ALLOC_MEM2 (Ram_aacEnc_PsyOut, PSY_OUT, 1, (1)) + +C_ALLOC_MEM2 (Ram_aacEnc_PsyOutElements, PSY_OUT_ELEMENT, 1, (1)*(6)) +C_ALLOC_MEM2 (Ram_aacEnc_PsyOutChannel, PSY_OUT_CHANNEL, 1, (1)*(6)) + + +/* + The structure QC_STATE contains preinitialized settings and quantizer structures. + * AdjustThreshold structure contains element-wise settings. + * ElementBits contains elemnt-wise bit consumption settings. + * When CRC is active, lookup table is necessary for fast crc calculation. + * Bitcounter contains buffer to find optimal codebooks and minimal bit consumption. + Values are temporarily, so dynamic memory can be used. +*/ + +C_ALLOC_MEM (Ram_aacEnc_QCstate, QC_STATE, 1) +C_ALLOC_MEM (Ram_aacEnc_AdjustThreshold, ADJ_THR_STATE, 1) + +C_ALLOC_MEM2 (Ram_aacEnc_AdjThrStateElement, ATS_ELEMENT, 1, (6)) +C_ALLOC_MEM2 (Ram_aacEnc_ElementBits, ELEMENT_BITS, 1, (6)) +C_ALLOC_MEM (Ram_aacEnc_BitCntrState, BITCNTR_STATE, 1) + + INT *GetRam_aacEnc_BitLookUp(int n, UCHAR* dynamic_RAM) { + FDK_ASSERT(dynamic_RAM!=0); + return ((INT*) (dynamic_RAM + P_BUF_1)); + } + INT *GetRam_aacEnc_MergeGainLookUp(int n, UCHAR* dynamic_RAM) { + FDK_ASSERT(dynamic_RAM!=0); + return ((INT*) (dynamic_RAM + P_BUF_1 + sizeof(INT)*(MAX_SFB_LONG*(CODE_BOOK_ESC_NDX+1)))); + } + + +/* + The structure QC_OUT contains settings and structures holding all necessary information + needed in bitstreamwriter. +*/ + +C_ALLOC_MEM2 (Ram_aacEnc_QCout, QC_OUT, 1, (1)) +C_ALLOC_MEM2 (Ram_aacEnc_QCelement, QC_OUT_ELEMENT, 1, (1)*(6)) + QC_OUT_CHANNEL *GetRam_aacEnc_QCchannel (int n, UCHAR* dynamic_RAM) { + FDK_ASSERT(dynamic_RAM!=0); + return ((QC_OUT_CHANNEL*) (dynamic_RAM + P_BUF_0 + n*sizeof(QC_OUT_CHANNEL))); + } + + + + + + + + + + + + diff --git a/libAACenc/src/aacEnc_ram.h b/libAACenc/src/aacEnc_ram.h new file mode 100644 index 0000000..1e87fc4 --- /dev/null +++ b/libAACenc/src/aacEnc_ram.h @@ -0,0 +1,163 @@ +/****************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id: + Initial authors: M. Lohwasser, M. Gayer + Contents/description: + +******************************************************************************/ +/*! + \file + \brief Memory layout $Revision: 36838 $ + \author Markus Lohwasser +*/ + +#ifndef AAC_ENC_RAM_H +#define AAC_ENC_RAM_H + +#include "common_fix.h" + +#include "aacenc.h" +#include "psy_data.h" +#include "interface.h" +#include "psy_main.h" +#include "bitenc.h" +#include "bit_cnt.h" +#include "psy_const.h" + + #define OUTPUTBUFFER_SIZE (8192) /*!< Output buffer size has to be at least 6144 bits per channel (768 bytes). FDK bitbuffer implementation expects buffer of size 2^n. */ + + +/* + Moved AAC_ENC struct definition from aac_enc.cpp into aacEnc_ram.h to get size and respective + static memory in aacEnc_ram.cpp. + aac_enc.h is the outward visible header file and putting the struct into would cause necessity + of additional visible header files outside library. +*/ + +/* define hBitstream size: max AAC framelength is 6144 bits/channel */ +/*#define BUFFER_BITSTR_SIZE ((6400*(6)/bbWordSize) +((bbWordSize - 1) / bbWordSize))*/ + +struct AAC_ENC { + + AACENC_CONFIG *config; + + INT ancillaryBitsPerFrame; /* ancillary bits per frame calculated from ancillary rate */ + + CHANNEL_MAPPING channelMapping; + + QC_STATE *qcKernel; + QC_OUT *qcOut[(1)]; + + PSY_OUT *psyOut[(1)]; + PSY_INTERNAL *psyKernel; + + /* lifetime vars */ + + CHANNEL_MODE encoderMode; + INT bandwidth90dB; + AACENC_BITRATE_MODE bitrateMode; + + INT dontWriteAdif; /* use: write ADIF header only before 1st frame */ + + FIXP_DBL *dynamic_RAM; + + + INT maxChannels; /* used while allocation */ + INT maxElements; + INT maxFrames; + + AUDIO_OBJECT_TYPE aot; /* AOT to be used while encoding. */ + +} ; + +#define maxSize(a,b) ( ((a)>(b)) ? (a) : (b) ) + +#define BIT_LOOK_UP_SIZE ( sizeof(INT)*(MAX_SFB_LONG*(CODE_BOOK_ESC_NDX+1)) ) +#define MERGE_GAIN_LOOK_UP_SIZE ( sizeof(INT)*MAX_SFB_LONG ) + + + +/* Dynamic RAM - Allocation */ +/* + ++++++++++++++++++++++++++++++++++++++++++++ + | P_BUF_0 | P_BUF_1 | + ++++++++++++++++++++++++++++++++++++++++++++ + | QC_OUT_CH | PSY_DYN | + ++++++++++++++++++++++++++++++++++++++++++++ + | | BitLookUp+MergeGainLookUp | + ++++++++++++++++++++++++++++++++++++++++++++ + | | Bitstream output buffer | + ++++++++++++++++++++++++++++++++++++++++++++ +*/ + +#define BUF_SIZE_0 ( ALIGN_SIZE(sizeof(QC_OUT_CHANNEL)*(6)) ) +#define BUF_SIZE_1 ( ALIGN_SIZE(maxSize(sizeof(PSY_DYNAMIC), \ + (BIT_LOOK_UP_SIZE+MERGE_GAIN_LOOK_UP_SIZE))) ) + +#define P_BUF_0 ( 0 ) +#define P_BUF_1 ( P_BUF_0 + BUF_SIZE_0 ) + +#define AAC_ENC_DYN_RAM_SIZE ( BUF_SIZE_0 + BUF_SIZE_1 ) + + + H_ALLOC_MEM (AACdynamic_RAM, FIXP_DBL) +/* + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +END - Dynamic RAM - Allocation */ + +/* + See further Memory Allocation details in aacEnc_ram.cpp +*/ + H_ALLOC_MEM (Ram_aacEnc_AacEncoder, AAC_ENC) + + H_ALLOC_MEM (Ram_aacEnc_PsyElement, PSY_ELEMENT) + + H_ALLOC_MEM (Ram_aacEnc_PsyInternal, PSY_INTERNAL) + H_ALLOC_MEM (Ram_aacEnc_PsyStatic, PSY_STATIC) + H_ALLOC_MEM (Ram_aacEnc_PsyInputBuffer, INT_PCM) + + PSY_DYNAMIC *GetRam_aacEnc_PsyDynamic (int n, UCHAR* dynamic_RAM); + H_ALLOC_MEM (Ram_bsOutbuffer, UCHAR) + + H_ALLOC_MEM (Ram_aacEnc_PsyOutChannel, PSY_OUT_CHANNEL) + + H_ALLOC_MEM (Ram_aacEnc_PsyOut, PSY_OUT) + H_ALLOC_MEM (Ram_aacEnc_PsyOutElements, PSY_OUT_ELEMENT) + + H_ALLOC_MEM (Ram_aacEnc_QCstate, QC_STATE) + H_ALLOC_MEM (Ram_aacEnc_AdjustThreshold, ADJ_THR_STATE) + + H_ALLOC_MEM (Ram_aacEnc_AdjThrStateElement, ATS_ELEMENT) + H_ALLOC_MEM (Ram_aacEnc_ElementBits, ELEMENT_BITS) + H_ALLOC_MEM (Ram_aacEnc_BitCntrState, BITCNTR_STATE) + + INT *GetRam_aacEnc_BitLookUp(int n, UCHAR* dynamic_RAM); + INT *GetRam_aacEnc_MergeGainLookUp(int n, UCHAR* dynamic_RAM); + QC_OUT_CHANNEL *GetRam_aacEnc_QCchannel (int n, UCHAR* dynamic_RAM); + + H_ALLOC_MEM (Ram_aacEnc_QCout, QC_OUT) + H_ALLOC_MEM (Ram_aacEnc_QCelement, QC_OUT_ELEMENT) + + +#endif /* #ifndef AAC_ENC_RAM_H */ + diff --git a/libAACenc/src/aacEnc_rom.cpp b/libAACenc/src/aacEnc_rom.cpp new file mode 100644 index 0000000..5349a43 --- /dev/null +++ b/libAACenc/src/aacEnc_rom.cpp @@ -0,0 +1,1170 @@ +/****************************************************************************** + + (C) copyright Fraunhofer-IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id: + Initial authors: M. Lohwasser, M. Gayer + Contents/description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "aacEnc_rom.h" + +/* + Huffman Tables +*/ +const INT FDKaacEnc_huff_ltab1_2[3][3][3][3]= +{ + { + { {0x000b0009,0x00090007,0x000b0009}, {0x000a0008,0x00070006,0x000a0008}, {0x000b0009,0x00090008,0x000b0009} }, + { {0x000a0008,0x00070006,0x000a0007}, {0x00070006,0x00050005,0x00070006}, {0x00090007,0x00070006,0x000a0008} }, + { {0x000b0009,0x00090007,0x000b0008}, {0x00090008,0x00070006,0x00090008}, {0x000b0009,0x00090007,0x000b0009} } + }, + { + { {0x00090008,0x00070006,0x00090007}, {0x00070006,0x00050005,0x00070006}, {0x00090007,0x00070006,0x00090008} }, + { {0x00070006,0x00050005,0x00070006}, {0x00050005,0x00010003,0x00050005}, {0x00070006,0x00050005,0x00070006} }, + { {0x00090008,0x00070006,0x00090007}, {0x00070006,0x00050005,0x00070006}, {0x00090008,0x00070006,0x00090008} } + }, + { + { {0x000b0009,0x00090007,0x000b0009}, {0x00090008,0x00070006,0x00090008}, {0x000b0008,0x00090007,0x000b0009} }, + { {0x000a0008,0x00070006,0x00090007}, {0x00070006,0x00050004,0x00070006}, {0x00090008,0x00070006,0x000a0007} }, + { {0x000b0009,0x00090007,0x000b0009}, {0x000a0007,0x00070006,0x00090008}, {0x000b0009,0x00090007,0x000b0009} } + } +}; + + +const INT FDKaacEnc_huff_ltab3_4[3][3][3][3]= +{ + { + { {0x00010004,0x00040005,0x00080008}, {0x00040005,0x00050004,0x00080008}, {0x00090009,0x00090008,0x000a000b} }, + { {0x00040005,0x00060005,0x00090008}, {0x00060005,0x00060004,0x00090008}, {0x00090008,0x00090007,0x000a000a} }, + { {0x00090009,0x000a0008,0x000d000b}, {0x00090008,0x00090008,0x000b000a}, {0x000b000b,0x000a000a,0x000c000b} } + }, + { + { {0x00040004,0x00060005,0x000a0008}, {0x00060004,0x00070004,0x000a0008}, {0x000a0008,0x000a0008,0x000c000a} }, + { {0x00050004,0x00070004,0x000b0008}, {0x00060004,0x00070004,0x000a0007}, {0x00090008,0x00090007,0x000b0009} }, + { {0x00090008,0x000a0008,0x000d000a}, {0x00080007,0x00090007,0x000c0009}, {0x000a000a,0x000b0009,0x000c000a} } + }, + { + { {0x00080008,0x000a0008,0x000f000b}, {0x00090008,0x000b0007,0x000f000a}, {0x000d000b,0x000e000a,0x0010000c} }, + { {0x00080008,0x000a0007,0x000e000a}, {0x00090007,0x000a0007,0x000e0009}, {0x000c000a,0x000c0009,0x000f000b} }, + { {0x000b000b,0x000c000a,0x0010000c}, {0x000a000a,0x000b0009,0x000f000b}, {0x000c000b,0x000c000a,0x000f000b} } + } +}; + +const INT FDKaacEnc_huff_ltab5_6[9][9]= +{ + {0x000d000b, 0x000c000a, 0x000b0009, 0x000b0009, 0x000a0009, 0x000b0009, 0x000b0009, 0x000c000a, 0x000d000b}, + {0x000c000a, 0x000b0009, 0x000a0008, 0x00090007, 0x00080007, 0x00090007, 0x000a0008, 0x000b0009, 0x000c000a}, + {0x000c0009, 0x000a0008, 0x00090006, 0x00080006, 0x00070006, 0x00080006, 0x00090006, 0x000a0008, 0x000b0009}, + {0x000b0009, 0x00090007, 0x00080006, 0x00050004, 0x00040004, 0x00050004, 0x00080006, 0x00090007, 0x000b0009}, + {0x000a0009, 0x00080007, 0x00070006, 0x00040004, 0x00010004, 0x00040004, 0x00070006, 0x00080007, 0x000b0009}, + {0x000b0009, 0x00090007, 0x00080006, 0x00050004, 0x00040004, 0x00050004, 0x00080006, 0x00090007, 0x000b0009}, + {0x000b0009, 0x000a0008, 0x00090006, 0x00080006, 0x00070006, 0x00080006, 0x00090006, 0x000a0008, 0x000b0009}, + {0x000c000a, 0x000b0009, 0x000a0008, 0x00090007, 0x00080007, 0x00090007, 0x000a0007, 0x000b0008, 0x000c000a}, + {0x000d000b, 0x000c000a, 0x000c0009, 0x000b0009, 0x000a0009, 0x000a0009, 0x000b0009, 0x000c000a, 0x000d000b} +}; + +const INT FDKaacEnc_huff_ltab7_8[8][8]= +{ + {0x00010005, 0x00030004, 0x00060005, 0x00070006, 0x00080007, 0x00090008, 0x000a0009, 0x000b000a}, + {0x00030004, 0x00040003, 0x00060004, 0x00070005, 0x00080006, 0x00080007, 0x00090007, 0x00090008}, + {0x00060005, 0x00060004, 0x00070004, 0x00080005, 0x00080006, 0x00090007, 0x00090007, 0x000a0008}, + {0x00070006, 0x00070005, 0x00080005, 0x00080006, 0x00090006, 0x00090007, 0x000a0008, 0x000a0008}, + {0x00080007, 0x00080006, 0x00090006, 0x00090006, 0x000a0007, 0x000a0007, 0x000a0008, 0x000b0009}, + {0x00090008, 0x00080007, 0x00090006, 0x00090007, 0x000a0007, 0x000a0008, 0x000b0008, 0x000b000a}, + {0x000a0009, 0x00090007, 0x00090007, 0x000a0008, 0x000a0008, 0x000b0008, 0x000c0009, 0x000c0009}, + {0x000b000a, 0x000a0008, 0x000a0008, 0x000a0008, 0x000b0009, 0x000b0009, 0x000c0009, 0x000c000a} +}; + +const INT FDKaacEnc_huff_ltab9_10[13][13]= +{ + {0x00010006, 0x00030005, 0x00060006, 0x00080006, 0x00090007, 0x000a0008, 0x000a0009, 0x000b000a, 0x000b000a, 0x000c000a, 0x000c000b, 0x000d000b, 0x000d000c}, + {0x00030005, 0x00040004, 0x00060004, 0x00070005, 0x00080006, 0x00080007, 0x00090007, 0x000a0008, 0x000a0008, 0x000a0009, 0x000b000a, 0x000c000a, 0x000c000b}, + {0x00060006, 0x00060004, 0x00070005, 0x00080005, 0x00080006, 0x00090006, 0x000a0007, 0x000a0008, 0x000a0008, 0x000b0009, 0x000c0009, 0x000c000a, 0x000c000a}, + {0x00080006, 0x00070005, 0x00080005, 0x00090005, 0x00090006, 0x000a0007, 0x000a0007, 0x000b0008, 0x000b0008, 0x000b0009, 0x000c0009, 0x000c000a, 0x000d000a}, + {0x00090007, 0x00080006, 0x00090006, 0x00090006, 0x000a0006, 0x000a0007, 0x000b0007, 0x000b0008, 0x000b0008, 0x000c0009, 0x000c0009, 0x000c000a, 0x000d000a}, + {0x000a0008, 0x00090007, 0x00090006, 0x000a0007, 0x000b0007, 0x000b0007, 0x000b0008, 0x000c0008, 0x000b0008, 0x000c0009, 0x000c000a, 0x000d000a, 0x000d000b}, + {0x000b0009, 0x00090007, 0x000a0007, 0x000b0007, 0x000b0007, 0x000b0008, 0x000c0008, 0x000c0009, 0x000c0009, 0x000c0009, 0x000d000a, 0x000d000a, 0x000d000b}, + {0x000b0009, 0x000a0008, 0x000a0008, 0x000b0008, 0x000b0008, 0x000c0008, 0x000c0009, 0x000d0009, 0x000d0009, 0x000d000a, 0x000d000a, 0x000d000b, 0x000d000b}, + {0x000b0009, 0x000a0008, 0x000a0008, 0x000b0008, 0x000b0008, 0x000b0008, 0x000c0009, 0x000c0009, 0x000d000a, 0x000d000a, 0x000e000a, 0x000d000b, 0x000e000b}, + {0x000b000a, 0x000a0009, 0x000b0009, 0x000b0009, 0x000c0009, 0x000c0009, 0x000c0009, 0x000c000a, 0x000d000a, 0x000d000a, 0x000e000b, 0x000e000b, 0x000e000c}, + {0x000c000a, 0x000b0009, 0x000b0009, 0x000c0009, 0x000c0009, 0x000c000a, 0x000d000a, 0x000d000a, 0x000d000a, 0x000e000b, 0x000e000b, 0x000e000b, 0x000f000c}, + {0x000c000b, 0x000b000a, 0x000c0009, 0x000c000a, 0x000c000a, 0x000d000a, 0x000d000a, 0x000d000a, 0x000d000b, 0x000e000b, 0x000e000b, 0x000f000b, 0x000f000c}, + {0x000d000b, 0x000c000a, 0x000c000a, 0x000c000a, 0x000d000a, 0x000d000a, 0x000d000a, 0x000d000b, 0x000e000b, 0x000e000c, 0x000e000c, 0x000e000c, 0x000f000c} +}; + +const UCHAR FDKaacEnc_huff_ltab11[17][17]= +{ + {0x04, 0x05, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0b, 0x0c, 0x0c, 0x0a}, + {0x05, 0x04, 0x05, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x08}, + {0x06, 0x05, 0x05, 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x08}, + {0x07, 0x06, 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x08}, + {0x08, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x08}, + {0x08, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x08}, + {0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x08}, + {0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x08}, + {0x0a, 0x09, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x08}, + {0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x08}, + {0x0b, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0a, 0x0b, 0x0b, 0x08}, + {0x0b, 0x0a, 0x09, 0x09, 0x0a, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x08}, + {0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x09}, + {0x0b, 0x0a, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x09}, + {0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x09}, + {0x0c, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x09}, + {0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x05} +}; + +const UCHAR FDKaacEnc_huff_ltabscf[121]= +{ + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x12, 0x13, 0x12, 0x11, 0x11, 0x10, 0x11, 0x10, 0x10, 0x10, 0x10, 0x0f, 0x0f, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0c, 0x0b, 0x0a, 0x0a, + 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x01, 0x04, 0x04, 0x05, + 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, + 0x0c, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x10, 0x0f, 0x10, 0x0f, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13 +}; + + +const USHORT FDKaacEnc_huff_ctab1[3][3][3][3]= +{ + { + { {0x07f8,0x01f1,0x07fd}, {0x03f5,0x0068,0x03f0}, {0x07f7,0x01ec,0x07f5} }, + { {0x03f1,0x0072,0x03f4}, {0x0074,0x0011,0x0076}, {0x01eb,0x006c,0x03f6} }, + { {0x07fc,0x01e1,0x07f1}, {0x01f0,0x0061,0x01f6}, {0x07f2,0x01ea,0x07fb} } + }, + { + { {0x01f2,0x0069,0x01ed}, {0x0077,0x0017,0x006f}, {0x01e6,0x0064,0x01e5} }, + { {0x0067,0x0015,0x0062}, {0x0012,0x0000,0x0014}, {0x0065,0x0016,0x006d} }, + { {0x01e9,0x0063,0x01e4}, {0x006b,0x0013,0x0071}, {0x01e3,0x0070,0x01f3} } + }, + { + { {0x07fe,0x01e7,0x07f3}, {0x01ef,0x0060,0x01ee}, {0x07f0,0x01e2,0x07fa} }, + { {0x03f3,0x006a,0x01e8}, {0x0075,0x0010,0x0073}, {0x01f4,0x006e,0x03f7} }, + { {0x07f6,0x01e0,0x07f9}, {0x03f2,0x0066,0x01f5}, {0x07ff,0x01f7,0x07f4} } + } +}; + +const USHORT FDKaacEnc_huff_ctab2[3][3][3][3]= +{ + { + { {0x01f3,0x006f,0x01fd}, {0x00eb,0x0023,0x00ea}, {0x01f7,0x00e8,0x01fa} }, + { {0x00f2,0x002d,0x0070}, {0x0020,0x0006,0x002b}, {0x006e,0x0028,0x00e9} }, + { {0x01f9,0x0066,0x00f8}, {0x00e7,0x001b,0x00f1}, {0x01f4,0x006b,0x01f5} } + }, + { + { {0x00ec,0x002a,0x006c}, {0x002c,0x000a,0x0027}, {0x0067,0x001a,0x00f5} }, + { {0x0024,0x0008,0x001f}, {0x0009,0x0000,0x0007}, {0x001d,0x000b,0x0030} }, + { {0x00ef,0x001c,0x0064}, {0x001e,0x000c,0x0029}, {0x00f3,0x002f,0x00f0} } + }, + { + { {0x01fc,0x0071,0x01f2}, {0x00f4,0x0021,0x00e6}, {0x00f7,0x0068,0x01f8} }, + { {0x00ee,0x0022,0x0065}, {0x0031,0x0002,0x0026}, {0x00ed,0x0025,0x006a} }, + { {0x01fb,0x0072,0x01fe}, {0x0069,0x002e,0x00f6}, {0x01ff,0x006d,0x01f6} } + } +}; + +const USHORT FDKaacEnc_huff_ctab3[3][3][3][3]= +{ + { + { {0x0000,0x0009,0x00ef}, {0x000b,0x0019,0x00f0}, {0x01eb,0x01e6,0x03f2} }, + { {0x000a,0x0035,0x01ef}, {0x0034,0x0037,0x01e9}, {0x01ed,0x01e7,0x03f3} }, + { {0x01ee,0x03ed,0x1ffa}, {0x01ec,0x01f2,0x07f9}, {0x07f8,0x03f8,0x0ff8} } + }, + { + { {0x0008,0x0038,0x03f6}, {0x0036,0x0075,0x03f1}, {0x03eb,0x03ec,0x0ff4} }, + { {0x0018,0x0076,0x07f4}, {0x0039,0x0074,0x03ef}, {0x01f3,0x01f4,0x07f6} }, + { {0x01e8,0x03ea,0x1ffc}, {0x00f2,0x01f1,0x0ffb}, {0x03f5,0x07f3,0x0ffc} } + }, + { + { {0x00ee,0x03f7,0x7ffe}, {0x01f0,0x07f5,0x7ffd}, {0x1ffb,0x3ffa,0xffff} }, + { {0x00f1,0x03f0,0x3ffc}, {0x01ea,0x03ee,0x3ffb}, {0x0ff6,0x0ffa,0x7ffc} }, + { {0x07f2,0x0ff5,0xfffe}, {0x03f4,0x07f7,0x7ffb}, {0x0ff7,0x0ff9,0x7ffa} } + } +}; + +const USHORT FDKaacEnc_huff_ctab4[3][3][3][3]= +{ + { + { {0x0007,0x0016,0x00f6}, {0x0018,0x0008,0x00ef}, {0x01ef,0x00f3,0x07f8} }, + { {0x0019,0x0017,0x00ed}, {0x0015,0x0001,0x00e2}, {0x00f0,0x0070,0x03f0} }, + { {0x01ee,0x00f1,0x07fa}, {0x00ee,0x00e4,0x03f2}, {0x07f6,0x03ef,0x07fd} } + }, + { + { {0x0005,0x0014,0x00f2}, {0x0009,0x0004,0x00e5}, {0x00f4,0x00e8,0x03f4} }, + { {0x0006,0x0002,0x00e7}, {0x0003,0x0000,0x006b}, {0x00e3,0x0069,0x01f3} }, + { {0x00eb,0x00e6,0x03f6}, {0x006e,0x006a,0x01f4}, {0x03ec,0x01f0,0x03f9} } + }, + { + { {0x00f5,0x00ec,0x07fb}, {0x00ea,0x006f,0x03f7}, {0x07f9,0x03f3,0x0fff} }, + { {0x00e9,0x006d,0x03f8}, {0x006c,0x0068,0x01f5}, {0x03ee,0x01f2,0x07f4} }, + { {0x07f7,0x03f1,0x0ffe}, {0x03ed,0x01f1,0x07f5}, {0x07fe,0x03f5,0x07fc} } + } +}; +const USHORT FDKaacEnc_huff_ctab5[9][9]= +{ + {0x1fff, 0x0ff7, 0x07f4, 0x07e8, 0x03f1, 0x07ee, 0x07f9, 0x0ff8, 0x1ffd}, + {0x0ffd, 0x07f1, 0x03e8, 0x01e8, 0x00f0, 0x01ec, 0x03ee, 0x07f2, 0x0ffa}, + {0x0ff4, 0x03ef, 0x01f2, 0x00e8, 0x0070, 0x00ec, 0x01f0, 0x03ea, 0x07f3}, + {0x07eb, 0x01eb, 0x00ea, 0x001a, 0x0008, 0x0019, 0x00ee, 0x01ef, 0x07ed}, + {0x03f0, 0x00f2, 0x0073, 0x000b, 0x0000, 0x000a, 0x0071, 0x00f3, 0x07e9}, + {0x07ef, 0x01ee, 0x00ef, 0x0018, 0x0009, 0x001b, 0x00eb, 0x01e9, 0x07ec}, + {0x07f6, 0x03eb, 0x01f3, 0x00ed, 0x0072, 0x00e9, 0x01f1, 0x03ed, 0x07f7}, + {0x0ff6, 0x07f0, 0x03e9, 0x01ed, 0x00f1, 0x01ea, 0x03ec, 0x07f8, 0x0ff9}, + {0x1ffc, 0x0ffc, 0x0ff5, 0x07ea, 0x03f3, 0x03f2, 0x07f5, 0x0ffb, 0x1ffe} +}; + +const USHORT FDKaacEnc_huff_ctab6[9][9]= +{ + {0x07fe, 0x03fd, 0x01f1, 0x01eb, 0x01f4, 0x01ea, 0x01f0, 0x03fc, 0x07fd}, + {0x03f6, 0x01e5, 0x00ea, 0x006c, 0x0071, 0x0068, 0x00f0, 0x01e6, 0x03f7}, + {0x01f3, 0x00ef, 0x0032, 0x0027, 0x0028, 0x0026, 0x0031, 0x00eb, 0x01f7}, + {0x01e8, 0x006f, 0x002e, 0x0008, 0x0004, 0x0006, 0x0029, 0x006b, 0x01ee}, + {0x01ef, 0x0072, 0x002d, 0x0002, 0x0000, 0x0003, 0x002f, 0x0073, 0x01fa}, + {0x01e7, 0x006e, 0x002b, 0x0007, 0x0001, 0x0005, 0x002c, 0x006d, 0x01ec}, + {0x01f9, 0x00ee, 0x0030, 0x0024, 0x002a, 0x0025, 0x0033, 0x00ec, 0x01f2}, + {0x03f8, 0x01e4, 0x00ed, 0x006a, 0x0070, 0x0069, 0x0074, 0x00f1, 0x03fa}, + {0x07ff, 0x03f9, 0x01f6, 0x01ed, 0x01f8, 0x01e9, 0x01f5, 0x03fb, 0x07fc} +}; + +const USHORT FDKaacEnc_huff_ctab7[8][8]= +{ + {0x0000, 0x0005, 0x0037, 0x0074, 0x00f2, 0x01eb, 0x03ed, 0x07f7}, + {0x0004, 0x000c, 0x0035, 0x0071, 0x00ec, 0x00ee, 0x01ee, 0x01f5}, + {0x0036, 0x0034, 0x0072, 0x00ea, 0x00f1, 0x01e9, 0x01f3, 0x03f5}, + {0x0073, 0x0070, 0x00eb, 0x00f0, 0x01f1, 0x01f0, 0x03ec, 0x03fa}, + {0x00f3, 0x00ed, 0x01e8, 0x01ef, 0x03ef, 0x03f1, 0x03f9, 0x07fb}, + {0x01ed, 0x00ef, 0x01ea, 0x01f2, 0x03f3, 0x03f8, 0x07f9, 0x07fc}, + {0x03ee, 0x01ec, 0x01f4, 0x03f4, 0x03f7, 0x07f8, 0x0ffd, 0x0ffe}, + {0x07f6, 0x03f0, 0x03f2, 0x03f6, 0x07fa, 0x07fd, 0x0ffc, 0x0fff} +}; + +const USHORT FDKaacEnc_huff_ctab8[8][8]= +{ + {0x000e, 0x0005, 0x0010, 0x0030, 0x006f, 0x00f1, 0x01fa, 0x03fe}, + {0x0003, 0x0000, 0x0004, 0x0012, 0x002c, 0x006a, 0x0075, 0x00f8}, + {0x000f, 0x0002, 0x0006, 0x0014, 0x002e, 0x0069, 0x0072, 0x00f5}, + {0x002f, 0x0011, 0x0013, 0x002a, 0x0032, 0x006c, 0x00ec, 0x00fa}, + {0x0071, 0x002b, 0x002d, 0x0031, 0x006d, 0x0070, 0x00f2, 0x01f9}, + {0x00ef, 0x0068, 0x0033, 0x006b, 0x006e, 0x00ee, 0x00f9, 0x03fc}, + {0x01f8, 0x0074, 0x0073, 0x00ed, 0x00f0, 0x00f6, 0x01f6, 0x01fd}, + {0x03fd, 0x00f3, 0x00f4, 0x00f7, 0x01f7, 0x01fb, 0x01fc, 0x03ff} +}; + +const USHORT FDKaacEnc_huff_ctab9[13][13]= +{ + {0x0000, 0x0005, 0x0037, 0x00e7, 0x01de, 0x03ce, 0x03d9, 0x07c8, 0x07cd, 0x0fc8, 0x0fdd, 0x1fe4, 0x1fec}, + {0x0004, 0x000c, 0x0035, 0x0072, 0x00ea, 0x00ed, 0x01e2, 0x03d1, 0x03d3, 0x03e0, 0x07d8, 0x0fcf, 0x0fd5}, + {0x0036, 0x0034, 0x0071, 0x00e8, 0x00ec, 0x01e1, 0x03cf, 0x03dd, 0x03db, 0x07d0, 0x0fc7, 0x0fd4, 0x0fe4}, + {0x00e6, 0x0070, 0x00e9, 0x01dd, 0x01e3, 0x03d2, 0x03dc, 0x07cc, 0x07ca, 0x07de, 0x0fd8, 0x0fea, 0x1fdb}, + {0x01df, 0x00eb, 0x01dc, 0x01e6, 0x03d5, 0x03de, 0x07cb, 0x07dd, 0x07dc, 0x0fcd, 0x0fe2, 0x0fe7, 0x1fe1}, + {0x03d0, 0x01e0, 0x01e4, 0x03d6, 0x07c5, 0x07d1, 0x07db, 0x0fd2, 0x07e0, 0x0fd9, 0x0feb, 0x1fe3, 0x1fe9}, + {0x07c4, 0x01e5, 0x03d7, 0x07c6, 0x07cf, 0x07da, 0x0fcb, 0x0fda, 0x0fe3, 0x0fe9, 0x1fe6, 0x1ff3, 0x1ff7}, + {0x07d3, 0x03d8, 0x03e1, 0x07d4, 0x07d9, 0x0fd3, 0x0fde, 0x1fdd, 0x1fd9, 0x1fe2, 0x1fea, 0x1ff1, 0x1ff6}, + {0x07d2, 0x03d4, 0x03da, 0x07c7, 0x07d7, 0x07e2, 0x0fce, 0x0fdb, 0x1fd8, 0x1fee, 0x3ff0, 0x1ff4, 0x3ff2}, + {0x07e1, 0x03df, 0x07c9, 0x07d6, 0x0fca, 0x0fd0, 0x0fe5, 0x0fe6, 0x1feb, 0x1fef, 0x3ff3, 0x3ff4, 0x3ff5}, + {0x0fe0, 0x07ce, 0x07d5, 0x0fc6, 0x0fd1, 0x0fe1, 0x1fe0, 0x1fe8, 0x1ff0, 0x3ff1, 0x3ff8, 0x3ff6, 0x7ffc}, + {0x0fe8, 0x07df, 0x0fc9, 0x0fd7, 0x0fdc, 0x1fdc, 0x1fdf, 0x1fed, 0x1ff5, 0x3ff9, 0x3ffb, 0x7ffd, 0x7ffe}, + {0x1fe7, 0x0fcc, 0x0fd6, 0x0fdf, 0x1fde, 0x1fda, 0x1fe5, 0x1ff2, 0x3ffa, 0x3ff7, 0x3ffc, 0x3ffd, 0x7fff} +}; + +const USHORT FDKaacEnc_huff_ctab10[13][13]= +{ + {0x0022, 0x0008, 0x001d, 0x0026, 0x005f, 0x00d3, 0x01cf, 0x03d0, 0x03d7, 0x03ed, 0x07f0, 0x07f6, 0x0ffd}, + {0x0007, 0x0000, 0x0001, 0x0009, 0x0020, 0x0054, 0x0060, 0x00d5, 0x00dc, 0x01d4, 0x03cd, 0x03de, 0x07e7}, + {0x001c, 0x0002, 0x0006, 0x000c, 0x001e, 0x0028, 0x005b, 0x00cd, 0x00d9, 0x01ce, 0x01dc, 0x03d9, 0x03f1}, + {0x0025, 0x000b, 0x000a, 0x000d, 0x0024, 0x0057, 0x0061, 0x00cc, 0x00dd, 0x01cc, 0x01de, 0x03d3, 0x03e7}, + {0x005d, 0x0021, 0x001f, 0x0023, 0x0027, 0x0059, 0x0064, 0x00d8, 0x00df, 0x01d2, 0x01e2, 0x03dd, 0x03ee}, + {0x00d1, 0x0055, 0x0029, 0x0056, 0x0058, 0x0062, 0x00ce, 0x00e0, 0x00e2, 0x01da, 0x03d4, 0x03e3, 0x07eb}, + {0x01c9, 0x005e, 0x005a, 0x005c, 0x0063, 0x00ca, 0x00da, 0x01c7, 0x01ca, 0x01e0, 0x03db, 0x03e8, 0x07ec}, + {0x01e3, 0x00d2, 0x00cb, 0x00d0, 0x00d7, 0x00db, 0x01c6, 0x01d5, 0x01d8, 0x03ca, 0x03da, 0x07ea, 0x07f1}, + {0x01e1, 0x00d4, 0x00cf, 0x00d6, 0x00de, 0x00e1, 0x01d0, 0x01d6, 0x03d1, 0x03d5, 0x03f2, 0x07ee, 0x07fb}, + {0x03e9, 0x01cd, 0x01c8, 0x01cb, 0x01d1, 0x01d7, 0x01df, 0x03cf, 0x03e0, 0x03ef, 0x07e6, 0x07f8, 0x0ffa}, + {0x03eb, 0x01dd, 0x01d3, 0x01d9, 0x01db, 0x03d2, 0x03cc, 0x03dc, 0x03ea, 0x07ed, 0x07f3, 0x07f9, 0x0ff9}, + {0x07f2, 0x03ce, 0x01e4, 0x03cb, 0x03d8, 0x03d6, 0x03e2, 0x03e5, 0x07e8, 0x07f4, 0x07f5, 0x07f7, 0x0ffb}, + {0x07fa, 0x03ec, 0x03df, 0x03e1, 0x03e4, 0x03e6, 0x03f0, 0x07e9, 0x07ef, 0x0ff8, 0x0ffe, 0x0ffc, 0x0fff} +}; + +const USHORT FDKaacEnc_huff_ctab11[21][17]= +{ + {0x0000, 0x0006, 0x0019, 0x003d, 0x009c, 0x00c6, 0x01a7, 0x0390, 0x03c2, 0x03df, 0x07e6, 0x07f3, 0x0ffb, 0x07ec, 0x0ffa, 0x0ffe, 0x038e}, + {0x0005, 0x0001, 0x0008, 0x0014, 0x0037, 0x0042, 0x0092, 0x00af, 0x0191, 0x01a5, 0x01b5, 0x039e, 0x03c0, 0x03a2, 0x03cd, 0x07d6, 0x00ae}, + {0x0017, 0x0007, 0x0009, 0x0018, 0x0039, 0x0040, 0x008e, 0x00a3, 0x00b8, 0x0199, 0x01ac, 0x01c1, 0x03b1, 0x0396, 0x03be, 0x03ca, 0x009d}, + {0x003c, 0x0015, 0x0016, 0x001a, 0x003b, 0x0044, 0x0091, 0x00a5, 0x00be, 0x0196, 0x01ae, 0x01b9, 0x03a1, 0x0391, 0x03a5, 0x03d5, 0x0094}, + {0x009a, 0x0036, 0x0038, 0x003a, 0x0041, 0x008c, 0x009b, 0x00b0, 0x00c3, 0x019e, 0x01ab, 0x01bc, 0x039f, 0x038f, 0x03a9, 0x03cf, 0x0093}, + {0x00bf, 0x003e, 0x003f, 0x0043, 0x0045, 0x009e, 0x00a7, 0x00b9, 0x0194, 0x01a2, 0x01ba, 0x01c3, 0x03a6, 0x03a7, 0x03bb, 0x03d4, 0x009f}, + {0x01a0, 0x008f, 0x008d, 0x0090, 0x0098, 0x00a6, 0x00b6, 0x00c4, 0x019f, 0x01af, 0x01bf, 0x0399, 0x03bf, 0x03b4, 0x03c9, 0x03e7, 0x00a8}, + {0x01b6, 0x00ab, 0x00a4, 0x00aa, 0x00b2, 0x00c2, 0x00c5, 0x0198, 0x01a4, 0x01b8, 0x038c, 0x03a4, 0x03c4, 0x03c6, 0x03dd, 0x03e8, 0x00ad}, + {0x03af, 0x0192, 0x00bd, 0x00bc, 0x018e, 0x0197, 0x019a, 0x01a3, 0x01b1, 0x038d, 0x0398, 0x03b7, 0x03d3, 0x03d1, 0x03db, 0x07dd, 0x00b4}, + {0x03de, 0x01a9, 0x019b, 0x019c, 0x01a1, 0x01aa, 0x01ad, 0x01b3, 0x038b, 0x03b2, 0x03b8, 0x03ce, 0x03e1, 0x03e0, 0x07d2, 0x07e5, 0x00b7}, + {0x07e3, 0x01bb, 0x01a8, 0x01a6, 0x01b0, 0x01b2, 0x01b7, 0x039b, 0x039a, 0x03ba, 0x03b5, 0x03d6, 0x07d7, 0x03e4, 0x07d8, 0x07ea, 0x00ba}, + {0x07e8, 0x03a0, 0x01bd, 0x01b4, 0x038a, 0x01c4, 0x0392, 0x03aa, 0x03b0, 0x03bc, 0x03d7, 0x07d4, 0x07dc, 0x07db, 0x07d5, 0x07f0, 0x00c1}, + {0x07fb, 0x03c8, 0x03a3, 0x0395, 0x039d, 0x03ac, 0x03ae, 0x03c5, 0x03d8, 0x03e2, 0x03e6, 0x07e4, 0x07e7, 0x07e0, 0x07e9, 0x07f7, 0x0190}, + {0x07f2, 0x0393, 0x01be, 0x01c0, 0x0394, 0x0397, 0x03ad, 0x03c3, 0x03c1, 0x03d2, 0x07da, 0x07d9, 0x07df, 0x07eb, 0x07f4, 0x07fa, 0x0195}, + {0x07f8, 0x03bd, 0x039c, 0x03ab, 0x03a8, 0x03b3, 0x03b9, 0x03d0, 0x03e3, 0x03e5, 0x07e2, 0x07de, 0x07ed, 0x07f1, 0x07f9, 0x07fc, 0x0193}, + {0x0ffd, 0x03dc, 0x03b6, 0x03c7, 0x03cc, 0x03cb, 0x03d9, 0x03da, 0x07d3, 0x07e1, 0x07ee, 0x07ef, 0x07f5, 0x07f6, 0x0ffc, 0x0fff, 0x019d}, + {0x01c2, 0x00b5, 0x00a1, 0x0096, 0x0097, 0x0095, 0x0099, 0x00a0, 0x00a2, 0x00ac, 0x00a9, 0x00b1, 0x00b3, 0x00bb, 0x00c0, 0x018f, 0x0004}, + {0x0018, 0x002e, 0x0000, 0x005a, 0x00a5, 0x00f8, 0x00b7, 0x0094, 0x00f9, 0x004d, 0x0021, 0x002b, 0x004f, 0x007b, 0x00bc, 0x0046, 0x0015}, + {0x0042, 0x0037, 0x0078, 0x000d, 0x0068, 0x005f, 0x000d, 0x005e, 0x005a, 0x00be, 0x0063, 0x007e, 0x001f, 0x0092, 0x001a, 0x00ab, 0x0032}, + {0x00e6, 0x0037, 0x0000, 0x0058, 0x000b, 0x005a, 0x00e1, 0x005d, 0x0029, 0x0017, 0x007e, 0x0069, 0x00aa, 0x0054, 0x0029, 0x0032, 0x0041}, + {0x0046, 0x00ea, 0x0034, 0x00ea, 0x0011, 0x001b, 0x00a9, 0x0094, 0x00e2, 0x0031, 0x00d0, 0x00e5, 0x0007, 0x0070, 0x0069, 0x003e, 0x0021} +}; + +const INT FDKaacEnc_huff_ctabscf[121]= +{ + 0x0003ffe8, 0x0003ffe6, 0x0003ffe7, 0x0003ffe5, 0x0007fff5, 0x0007fff1, 0x0007ffed, 0x0007fff6, + 0x0007ffee, 0x0007ffef, 0x0007fff0, 0x0007fffc, 0x0007fffd, 0x0007ffff, 0x0007fffe, 0x0007fff7, + 0x0007fff8, 0x0007fffb, 0x0007fff9, 0x0003ffe4, 0x0007fffa, 0x0003ffe3, 0x0001ffef, 0x0001fff0, + 0x0000fff5, 0x0001ffee, 0x0000fff2, 0x0000fff3, 0x0000fff4, 0x0000fff1, 0x00007ff6, 0x00007ff7, + 0x00003ff9, 0x00003ff5, 0x00003ff7, 0x00003ff3, 0x00003ff6, 0x00003ff2, 0x00001ff7, 0x00001ff5, + 0x00000ff9, 0x00000ff7, 0x00000ff6, 0x000007f9, 0x00000ff4, 0x000007f8, 0x000003f9, 0x000003f7, + 0x000003f5, 0x000001f8, 0x000001f7, 0x000000fa, 0x000000f8, 0x000000f6, 0x00000079, 0x0000003a, + 0x00000038, 0x0000001a, 0x0000000b, 0x00000004, 0x00000000, 0x0000000a, 0x0000000c, 0x0000001b, + 0x00000039, 0x0000003b, 0x00000078, 0x0000007a, 0x000000f7, 0x000000f9, 0x000001f6, 0x000001f9, + 0x000003f4, 0x000003f6, 0x000003f8, 0x000007f5, 0x000007f4, 0x000007f6, 0x000007f7, 0x00000ff5, + 0x00000ff8, 0x00001ff4, 0x00001ff6, 0x00001ff8, 0x00003ff8, 0x00003ff4, 0x0000fff0, 0x00007ff4, + 0x0000fff6, 0x00007ff5, 0x0003ffe2, 0x0007ffd9, 0x0007ffda, 0x0007ffdb, 0x0007ffdc, 0x0007ffdd, + 0x0007ffde, 0x0007ffd8, 0x0007ffd2, 0x0007ffd3, 0x0007ffd4, 0x0007ffd5, 0x0007ffd6, 0x0007fff2, + 0x0007ffdf, 0x0007ffe7, 0x0007ffe8, 0x0007ffe9, 0x0007ffea, 0x0007ffeb, 0x0007ffe6, 0x0007ffe0, + 0x0007ffe1, 0x0007ffe2, 0x0007ffe3, 0x0007ffe4, 0x0007ffe5, 0x0007ffd7, 0x0007ffec, 0x0007fff4, + 0x0007fff3 +}; + +/* + table of (0.50000...1.00000) ^0.75 +*/ +const FIXP_QTD FDKaacEnc_mTab_3_4[MANT_SIZE] = +{ + QTC(0x4c1bf829), QTC(0x4c3880de), QTC(0x4c550603), QTC(0x4c71879c), QTC(0x4c8e05aa), QTC(0x4caa8030), QTC(0x4cc6f72f), QTC(0x4ce36aab), + QTC(0x4cffdaa4), QTC(0x4d1c471d), QTC(0x4d38b019), QTC(0x4d55159a), QTC(0x4d7177a1), QTC(0x4d8dd631), QTC(0x4daa314b), QTC(0x4dc688f3), + QTC(0x4de2dd2a), QTC(0x4dff2df2), QTC(0x4e1b7b4d), QTC(0x4e37c53d), QTC(0x4e540bc5), QTC(0x4e704ee6), QTC(0x4e8c8ea3), QTC(0x4ea8cafd), + QTC(0x4ec503f7), QTC(0x4ee13992), QTC(0x4efd6bd0), QTC(0x4f199ab4), QTC(0x4f35c640), QTC(0x4f51ee75), QTC(0x4f6e1356), QTC(0x4f8a34e4), + QTC(0x4fa65321), QTC(0x4fc26e10), QTC(0x4fde85b2), QTC(0x4ffa9a0a), QTC(0x5016ab18), QTC(0x5032b8e0), QTC(0x504ec362), QTC(0x506acaa1), + QTC(0x5086cea0), QTC(0x50a2cf5e), QTC(0x50becce0), QTC(0x50dac725), QTC(0x50f6be31), QTC(0x5112b205), QTC(0x512ea2a3), QTC(0x514a900d), + QTC(0x51667a45), QTC(0x5182614c), QTC(0x519e4524), QTC(0x51ba25cf), QTC(0x51d60350), QTC(0x51f1dda7), QTC(0x520db4d6), QTC(0x522988e0), + QTC(0x524559c6), QTC(0x52612789), QTC(0x527cf22d), QTC(0x5298b9b1), QTC(0x52b47e19), QTC(0x52d03f65), QTC(0x52ebfd98), QTC(0x5307b8b4), + QTC(0x532370b9), QTC(0x533f25aa), QTC(0x535ad789), QTC(0x53768656), QTC(0x53923215), QTC(0x53addac6), QTC(0x53c9806b), QTC(0x53e52306), + QTC(0x5400c298), QTC(0x541c5f24), QTC(0x5437f8ab), QTC(0x54538f2e), QTC(0x546f22af), QTC(0x548ab330), QTC(0x54a640b3), QTC(0x54c1cb38), + QTC(0x54dd52c2), QTC(0x54f8d753), QTC(0x551458eb), QTC(0x552fd78d), QTC(0x554b5339), QTC(0x5566cbf3), QTC(0x558241bb), QTC(0x559db492), + QTC(0x55b9247b), QTC(0x55d49177), QTC(0x55effb87), QTC(0x560b62ad), QTC(0x5626c6eb), QTC(0x56422842), QTC(0x565d86b4), QTC(0x5678e242), + QTC(0x56943aee), QTC(0x56af90b9), QTC(0x56cae3a4), QTC(0x56e633b2), QTC(0x570180e4), QTC(0x571ccb3b), QTC(0x573812b8), QTC(0x5753575e), + QTC(0x576e992e), QTC(0x5789d829), QTC(0x57a51450), QTC(0x57c04da6), QTC(0x57db842b), QTC(0x57f6b7e1), QTC(0x5811e8c9), QTC(0x582d16e6), + QTC(0x58484238), QTC(0x58636ac0), QTC(0x587e9081), QTC(0x5899b37c), QTC(0x58b4d3b1), QTC(0x58cff123), QTC(0x58eb0bd3), QTC(0x590623c2), + QTC(0x592138f2), QTC(0x593c4b63), QTC(0x59575b19), QTC(0x59726812), QTC(0x598d7253), QTC(0x59a879da), QTC(0x59c37eab), QTC(0x59de80c6), + QTC(0x59f9802d), QTC(0x5a147ce0), QTC(0x5a2f76e2), QTC(0x5a4a6e34), QTC(0x5a6562d6), QTC(0x5a8054cb), QTC(0x5a9b4414), QTC(0x5ab630b2), + QTC(0x5ad11aa6), QTC(0x5aec01f1), QTC(0x5b06e696), QTC(0x5b21c895), QTC(0x5b3ca7ef), QTC(0x5b5784a6), QTC(0x5b725ebc), QTC(0x5b8d3631), + QTC(0x5ba80b06), QTC(0x5bc2dd3e), QTC(0x5bddacd9), QTC(0x5bf879d8), QTC(0x5c13443d), QTC(0x5c2e0c09), QTC(0x5c48d13e), QTC(0x5c6393dc), + QTC(0x5c7e53e5), QTC(0x5c99115a), QTC(0x5cb3cc3c), QTC(0x5cce848d), QTC(0x5ce93a4e), QTC(0x5d03ed80), QTC(0x5d1e9e24), QTC(0x5d394c3b), + QTC(0x5d53f7c7), QTC(0x5d6ea0c9), QTC(0x5d894742), QTC(0x5da3eb33), QTC(0x5dbe8c9e), QTC(0x5dd92b84), QTC(0x5df3c7e5), QTC(0x5e0e61c3), + QTC(0x5e28f920), QTC(0x5e438dfc), QTC(0x5e5e2059), QTC(0x5e78b037), QTC(0x5e933d99), QTC(0x5eadc87e), QTC(0x5ec850e9), QTC(0x5ee2d6da), + QTC(0x5efd5a53), QTC(0x5f17db54), QTC(0x5f3259e0), QTC(0x5f4cd5f6), QTC(0x5f674f99), QTC(0x5f81c6c8), QTC(0x5f9c3b87), QTC(0x5fb6add4), + QTC(0x5fd11db3), QTC(0x5feb8b23), QTC(0x6005f626), QTC(0x60205ebd), QTC(0x603ac4e9), QTC(0x605528ac), QTC(0x606f8a05), QTC(0x6089e8f7), + QTC(0x60a44583), QTC(0x60be9fa9), QTC(0x60d8f76b), QTC(0x60f34cca), QTC(0x610d9fc7), QTC(0x6127f062), QTC(0x61423e9e), QTC(0x615c8a7a), + QTC(0x6176d3f9), QTC(0x61911b1b), QTC(0x61ab5fe1), QTC(0x61c5a24d), QTC(0x61dfe25f), QTC(0x61fa2018), QTC(0x62145b7a), QTC(0x622e9485), + QTC(0x6248cb3b), QTC(0x6262ff9d), QTC(0x627d31ab), QTC(0x62976167), QTC(0x62b18ed1), QTC(0x62cbb9eb), QTC(0x62e5e2b6), QTC(0x63000933), + QTC(0x631a2d62), QTC(0x63344f45), QTC(0x634e6edd), QTC(0x63688c2b), QTC(0x6382a730), QTC(0x639cbfec), QTC(0x63b6d661), QTC(0x63d0ea90), + QTC(0x63eafc7a), QTC(0x64050c1f), QTC(0x641f1982), QTC(0x643924a2), QTC(0x64532d80), QTC(0x646d341f), QTC(0x6487387e), QTC(0x64a13a9e), + QTC(0x64bb3a81), QTC(0x64d53828), QTC(0x64ef3393), QTC(0x65092cc4), QTC(0x652323bb), QTC(0x653d1879), QTC(0x65570b00), QTC(0x6570fb50), + QTC(0x658ae96b), QTC(0x65a4d550), QTC(0x65bebf01), QTC(0x65d8a680), QTC(0x65f28bcc), QTC(0x660c6ee8), QTC(0x66264fd3), QTC(0x66402e8f), + QTC(0x665a0b1c), QTC(0x6673e57d), QTC(0x668dbdb0), QTC(0x66a793b8), QTC(0x66c16795), QTC(0x66db3949), QTC(0x66f508d4), QTC(0x670ed636), + QTC(0x6728a172), QTC(0x67426a87), QTC(0x675c3177), QTC(0x6775f643), QTC(0x678fb8eb), QTC(0x67a97971), QTC(0x67c337d5), QTC(0x67dcf418), + QTC(0x67f6ae3b), QTC(0x6810663f), QTC(0x682a1c25), QTC(0x6843cfed), QTC(0x685d8199), QTC(0x68773129), QTC(0x6890de9f), QTC(0x68aa89fa), + QTC(0x68c4333d), QTC(0x68ddda67), QTC(0x68f77f7a), QTC(0x69112277), QTC(0x692ac35e), QTC(0x69446230), QTC(0x695dfeee), QTC(0x6977999a), + QTC(0x69913232), QTC(0x69aac8ba), QTC(0x69c45d31), QTC(0x69ddef98), QTC(0x69f77ff0), QTC(0x6a110e3a), QTC(0x6a2a9a77), QTC(0x6a4424a8), + QTC(0x6a5daccc), QTC(0x6a7732e6), QTC(0x6a90b6f6), QTC(0x6aaa38fd), QTC(0x6ac3b8fb), QTC(0x6add36f2), QTC(0x6af6b2e2), QTC(0x6b102ccd), + QTC(0x6b29a4b2), QTC(0x6b431a92), QTC(0x6b5c8e6f), QTC(0x6b76004a), QTC(0x6b8f7022), QTC(0x6ba8ddf9), QTC(0x6bc249d0), QTC(0x6bdbb3a7), + QTC(0x6bf51b80), QTC(0x6c0e815a), QTC(0x6c27e537), QTC(0x6c414718), QTC(0x6c5aa6fd), QTC(0x6c7404e7), QTC(0x6c8d60d7), QTC(0x6ca6bace), + QTC(0x6cc012cc), QTC(0x6cd968d2), QTC(0x6cf2bce1), QTC(0x6d0c0ef9), QTC(0x6d255f1d), QTC(0x6d3ead4b), QTC(0x6d57f985), QTC(0x6d7143cc), + QTC(0x6d8a8c21), QTC(0x6da3d283), QTC(0x6dbd16f5), QTC(0x6dd65976), QTC(0x6def9a08), QTC(0x6e08d8ab), QTC(0x6e221560), QTC(0x6e3b5027), + QTC(0x6e548902), QTC(0x6e6dbff1), QTC(0x6e86f4f5), QTC(0x6ea0280e), QTC(0x6eb9593e), QTC(0x6ed28885), QTC(0x6eebb5e3), QTC(0x6f04e15a), + QTC(0x6f1e0aea), QTC(0x6f373294), QTC(0x6f505859), QTC(0x6f697c39), QTC(0x6f829e35), QTC(0x6f9bbe4e), QTC(0x6fb4dc85), QTC(0x6fcdf8d9), + QTC(0x6fe7134d), QTC(0x70002be0), QTC(0x70194293), QTC(0x70325767), QTC(0x704b6a5d), QTC(0x70647b76), QTC(0x707d8ab1), QTC(0x70969811), + QTC(0x70afa394), QTC(0x70c8ad3d), QTC(0x70e1b50c), QTC(0x70fabb01), QTC(0x7113bf1d), QTC(0x712cc161), QTC(0x7145c1ce), QTC(0x715ec064), + QTC(0x7177bd24), QTC(0x7190b80f), QTC(0x71a9b124), QTC(0x71c2a866), QTC(0x71db9dd4), QTC(0x71f49170), QTC(0x720d8339), QTC(0x72267331), + QTC(0x723f6159), QTC(0x72584db0), QTC(0x72713838), QTC(0x728a20f1), QTC(0x72a307db), QTC(0x72bbecf9), QTC(0x72d4d049), QTC(0x72edb1ce), + QTC(0x73069187), QTC(0x731f6f75), QTC(0x73384b98), QTC(0x735125f3), QTC(0x7369fe84), QTC(0x7382d54d), QTC(0x739baa4e), QTC(0x73b47d89), + QTC(0x73cd4efd), QTC(0x73e61eab), QTC(0x73feec94), QTC(0x7417b8b8), QTC(0x74308319), QTC(0x74494bb6), QTC(0x74621291), QTC(0x747ad7aa), + QTC(0x74939b02), QTC(0x74ac5c98), QTC(0x74c51c6f), QTC(0x74ddda86), QTC(0x74f696de), QTC(0x750f5178), QTC(0x75280a54), QTC(0x7540c174), + QTC(0x755976d7), QTC(0x75722a7e), QTC(0x758adc69), QTC(0x75a38c9b), QTC(0x75bc3b12), QTC(0x75d4e7cf), QTC(0x75ed92d4), QTC(0x76063c21), + QTC(0x761ee3b6), QTC(0x76378994), QTC(0x76502dbc), QTC(0x7668d02e), QTC(0x768170eb), QTC(0x769a0ff3), QTC(0x76b2ad47), QTC(0x76cb48e7), + QTC(0x76e3e2d5), QTC(0x76fc7b10), QTC(0x7715119a), QTC(0x772da673), QTC(0x7746399b), QTC(0x775ecb13), QTC(0x77775adc), QTC(0x778fe8f6), + QTC(0x77a87561), QTC(0x77c1001f), QTC(0x77d98930), QTC(0x77f21095), QTC(0x780a964d), QTC(0x78231a5b), QTC(0x783b9cbd), QTC(0x78541d75), + QTC(0x786c9c84), QTC(0x788519e9), QTC(0x789d95a6), QTC(0x78b60fbb), QTC(0x78ce8828), QTC(0x78e6feef), QTC(0x78ff740f), QTC(0x7917e78a), + QTC(0x7930595f), QTC(0x7948c990), QTC(0x7961381d), QTC(0x7979a506), QTC(0x7992104c), QTC(0x79aa79f0), QTC(0x79c2e1f1), QTC(0x79db4852), + QTC(0x79f3ad11), QTC(0x7a0c1031), QTC(0x7a2471b0), QTC(0x7a3cd191), QTC(0x7a552fd3), QTC(0x7a6d8c76), QTC(0x7a85e77d), QTC(0x7a9e40e6), + QTC(0x7ab698b2), QTC(0x7aceeee3), QTC(0x7ae74378), QTC(0x7aff9673), QTC(0x7b17e7d2), QTC(0x7b303799), QTC(0x7b4885c5), QTC(0x7b60d259), + QTC(0x7b791d55), QTC(0x7b9166b9), QTC(0x7ba9ae86), QTC(0x7bc1f4bc), QTC(0x7bda395c), QTC(0x7bf27c66), QTC(0x7c0abddb), QTC(0x7c22fdbb), + QTC(0x7c3b3c07), QTC(0x7c5378c0), QTC(0x7c6bb3e5), QTC(0x7c83ed78), QTC(0x7c9c2579), QTC(0x7cb45be9), QTC(0x7ccc90c7), QTC(0x7ce4c414), + QTC(0x7cfcf5d2), QTC(0x7d152600), QTC(0x7d2d549f), QTC(0x7d4581b0), QTC(0x7d5dad32), QTC(0x7d75d727), QTC(0x7d8dff8f), QTC(0x7da6266a), + QTC(0x7dbe4bba), QTC(0x7dd66f7d), QTC(0x7dee91b6), QTC(0x7e06b264), QTC(0x7e1ed188), QTC(0x7e36ef22), QTC(0x7e4f0b34), QTC(0x7e6725bd), + QTC(0x7e7f3ebd), QTC(0x7e975636), QTC(0x7eaf6c28), QTC(0x7ec78093), QTC(0x7edf9378), QTC(0x7ef7a4d7), QTC(0x7f0fb4b1), QTC(0x7f27c307), + QTC(0x7f3fcfd8), QTC(0x7f57db25), QTC(0x7f6fe4ef), QTC(0x7f87ed36), QTC(0x7f9ff3fb), QTC(0x7fb7f93e), QTC(0x7fcffcff), QTC(0x7fe7ff40) +}; + +/* + table of pow(2.0,0.25*q)/2.0, q[0..4) +*/ +const FIXP_QTD FDKaacEnc_quantTableQ[4] = { QTC(0x40000000), QTC(0x4c1bf7ff), QTC(0x5a82797f), QTC(0x6ba27e7f) }; + +/* + table of pow(2.0,0.75*e)/8.0, e[0..4) +*/ +const FIXP_QTD FDKaacEnc_quantTableE[4] = { QTC(0x10000000), QTC(0x1ae89f99), QTC(0x2d413ccd), QTC(0x4c1bf828) }; + + +/* + table to count used number of bits +*/ +const SHORT FDKaacEnc_sideInfoTabLong[MAX_SFB_LONG + 1] = +{ + 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, + 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, + 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, + 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x000e, + 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, + 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, + 0x000e, 0x000e, 0x000e, 0x000e +}; + + +const SHORT FDKaacEnc_sideInfoTabShort[MAX_SFB_SHORT + 1] = +{ + 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x000a, + 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000d, 0x000d +}; + + + + + + +/* + Psy Configuration constants +*/ + +const SFB_PARAM_LONG p_FDKaacEnc_8000_long_1024 = { + 40, + { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 16, 16, 16, 16, 16, 16, 16, + 20, 20, 20, 20, 24, 24, 24, 28, 28, 32, 36, 36, 40, 44, 48, 52, 56, 60, 64, 80 } +}; +const SFB_PARAM_SHORT p_FDKaacEnc_8000_short_128 = { + 15, + { 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 12, 16, 20, 20 } +}; + +const SFB_PARAM_LONG p_FDKaacEnc_11025_long_1024 = { + 43, + { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 16, 16, 16, 16, 20, 20, 20, 24, 24, 28, 28, 32, 36, 40, 40, 44, 48, 52, 56, 60, + 64, 64, 64 } +}; +const SFB_PARAM_SHORT p_FDKaacEnc_11025_short_128 = { + 15, + { 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 12, 12, 16, 20, 20 } +}; + +const SFB_PARAM_LONG p_FDKaacEnc_12000_long_1024 = { + 43, + { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 16, 16, 16, 16, 20, 20, 20, 24, 24, 28, 28, 32, 36, 40, 40, 44, 48, 52, 56, 60, + 64, 64, 64 } +}; +const SFB_PARAM_SHORT p_FDKaacEnc_12000_short_128 = { + 15, + { 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 12, 12, 16, 20, 20 } +}; + +const SFB_PARAM_LONG p_FDKaacEnc_16000_long_1024 = { + 43, + { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 16, 16, 16, 16, 20, 20, 20, 24, 24, 28, 28, 32, 36, 40, 40, 44, 48, 52, 56, 60, + 64, 64, 64 } +}; +const SFB_PARAM_SHORT p_FDKaacEnc_16000_short_128 = { + 15, + { 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 12, 12, 16, 20, 20 } +}; +const SFB_PARAM_LONG p_FDKaacEnc_22050_long_1024 = { + 47, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 12, 12, 12, 12, 16, 16, 16, 20, 20, 24, 24, 28, 28, 32, 36, 36, 40, 44, 48, + 52, 52, 64, 64, 64, 64, 64 } +}; +const SFB_PARAM_SHORT p_FDKaacEnc_22050_short_128 = { + 15, + { 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 12, 12, 16, 16, 20 } +}; +const SFB_PARAM_LONG p_FDKaacEnc_24000_long_1024 = { + 47, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 12, 12, 12, 12, 16, 16, 16, 20, 20, 24, 24, 28, 28, 32, 36, 36, 40, 44, 48, + 52, 52, 64, 64, 64, 64, 64 } +}; +const SFB_PARAM_SHORT p_FDKaacEnc_24000_short_128 = { + 15, + { 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 12, 12, 16, 16, 20 } +}; +const SFB_PARAM_LONG p_FDKaacEnc_32000_long_1024 = { + 51, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, + 12, 16, 16, 20, 20, 24, 24, 28, 28, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 } +}; +const SFB_PARAM_SHORT p_FDKaacEnc_32000_short_128 = { + 14, + { 4, 4, 4, 4, 4, 8, 8, 8, 12, 12, 12, 16, 16, 16 } +}; +const SFB_PARAM_LONG p_FDKaacEnc_44100_long_1024 = { + 49, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, + 12, 16, 16, 20, 20, 24, 24, 28, 28, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 96 } +}; +const SFB_PARAM_SHORT p_FDKaacEnc_44100_short_128 = { + 14, + { 4, 4, 4, 4, 4, 8, 8, 8, 12, 12, 12, 16, 16, 16 } +}; +const SFB_PARAM_LONG p_FDKaacEnc_48000_long_1024 = { + 49, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, + 12, 16, 16, 20, 20, 24, 24, 28, 28, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 96 } +}; +const SFB_PARAM_SHORT p_FDKaacEnc_48000_short_128 = { + 14, + { 4, 4, 4, 4, 4, 8, 8, 8, 12, 12, 12, 16, 16, 16 } +}; +const SFB_PARAM_LONG p_FDKaacEnc_64000_long_1024 = { + 47, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, + 12, 16, 16, 16, 20, 24, 24, 28, 36, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40 } +}; +const SFB_PARAM_SHORT p_FDKaacEnc_64000_short_128 = { + 12, + { 4, 4, 4, 4, 4, 4, 8, 8, 8, 16, 28, 36 } +}; +const SFB_PARAM_LONG p_FDKaacEnc_88200_long_1024 = { + 41, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 12, + 12, 12, 12, 12, 16, 16, 24, 28, 36, 44, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64 } +}; +const SFB_PARAM_SHORT p_FDKaacEnc_88200_short_128 = { + 12, + { 4, 4, 4, 4, 4, 4, 8, 8, 8, 16, 28, 36 } +}; +const SFB_PARAM_LONG p_FDKaacEnc_96000_long_1024 = { + 41, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 12, + 12, 12, 12, 12, 16, 16, 24, 28, 36, 44, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64 } +}; +const SFB_PARAM_SHORT p_FDKaacEnc_96000_short_128 = { + 12, + { 4, 4, 4, 4, 4, 4, 8, 8, 8, 16, 28, 36 } +}; + + +/* + TNS filter coefficients +*/ + +/* + 3 bit resolution +*/ +const FIXP_DBL FDKaacEnc_tnsEncCoeff3[8]= +{ + 0x81f1d201, 0x91261481, 0xadb92301, 0xd438af00, 0x00000000, 0x37898080, 0x64130dff, 0x7cca6fff +}; +const FIXP_DBL FDKaacEnc_tnsCoeff3Borders[8]={ + 0x80000001 /*-4*/, 0x87b826df /*-3*/, 0x9df24154 /*-2*/, 0xbfffffe5 /*-1*/, + 0xe9c5e578 /* 0*/, 0x1c7b90f0 /* 1*/, 0x4fce83a9 /* 2*/, 0x7352f2c3 /* 3*/ +}; + +/* + 4 bit resolution +*/ +const FIXP_DBL FDKaacEnc_tnsEncCoeff4[16]= +{ + 0x808bc881, 0x84e2e581, 0x8d6b4a01, 0x99da9201, 0xa9c45701, 0xbc9dde81, 0xd1c2d500, 0xe87ae540, + 0x00000000, 0x1a9cd9c0, 0x340ff240, 0x4b3c8bff, 0x5f1f5e7f, 0x6ed9eb7f, 0x79bc387f, 0x7f4c7e7f +}; +const FIXP_DBL FDKaacEnc_tnsCoeff4Borders[16]= +{ + 0x80000001 /*-8*/, 0x822deff0 /*-7*/, 0x88a4bfe6 /*-6*/, 0x932c159d /*-5*/, + 0xa16827c2 /*-4*/, 0xb2dcde27 /*-3*/, 0xc6f20b91 /*-2*/, 0xdcf89c64 /*-1*/, + 0xf4308ce1 /* 0*/, 0x0d613054 /* 1*/, 0x278dde80 /* 2*/, 0x4000001b /* 3*/, + 0x55a6127b /* 4*/, 0x678dde8f /* 5*/, 0x74ef0ed7 /* 6*/, 0x7d33f0da /* 7*/ +}; +const FIXP_DBL FDKaacEnc_mTab_4_3Elc[512]={ + FL2FXCONST_DBL(0.3968502629920499),FL2FXCONST_DBL(0.3978840634868335),FL2FXCONST_DBL(0.3989185359354711),FL2FXCONST_DBL(0.3999536794661432), + FL2FXCONST_DBL(0.4009894932098531),FL2FXCONST_DBL(0.4020259763004115),FL2FXCONST_DBL(0.4030631278744227),FL2FXCONST_DBL(0.4041009470712695), + FL2FXCONST_DBL(0.4051394330330996),FL2FXCONST_DBL(0.4061785849048110),FL2FXCONST_DBL(0.4072184018340380),FL2FXCONST_DBL(0.4082588829711372), + FL2FXCONST_DBL(0.4093000274691739),FL2FXCONST_DBL(0.4103418344839078),FL2FXCONST_DBL(0.4113843031737798),FL2FXCONST_DBL(0.4124274326998980), + FL2FXCONST_DBL(0.4134712222260245),FL2FXCONST_DBL(0.4145156709185620),FL2FXCONST_DBL(0.4155607779465400),FL2FXCONST_DBL(0.4166065424816022), + FL2FXCONST_DBL(0.4176529636979932),FL2FXCONST_DBL(0.4187000407725452),FL2FXCONST_DBL(0.4197477728846652),FL2FXCONST_DBL(0.4207961592163222), + FL2FXCONST_DBL(0.4218451989520345),FL2FXCONST_DBL(0.4228948912788567),FL2FXCONST_DBL(0.4239452353863673),FL2FXCONST_DBL(0.4249962304666564), + FL2FXCONST_DBL(0.4260478757143130),FL2FXCONST_DBL(0.4271001703264124),FL2FXCONST_DBL(0.4281531135025046),FL2FXCONST_DBL(0.4292067044446017), + FL2FXCONST_DBL(0.4302609423571658),FL2FXCONST_DBL(0.4313158264470970),FL2FXCONST_DBL(0.4323713559237216),FL2FXCONST_DBL(0.4334275299987803), + FL2FXCONST_DBL(0.4344843478864161),FL2FXCONST_DBL(0.4355418088031630),FL2FXCONST_DBL(0.4365999119679339),FL2FXCONST_DBL(0.4376586566020096), + FL2FXCONST_DBL(0.4387180419290272),FL2FXCONST_DBL(0.4397780671749683),FL2FXCONST_DBL(0.4408387315681480),FL2FXCONST_DBL(0.4419000343392039), + FL2FXCONST_DBL(0.4429619747210847),FL2FXCONST_DBL(0.4440245519490388),FL2FXCONST_DBL(0.4450877652606038),FL2FXCONST_DBL(0.4461516138955953), + FL2FXCONST_DBL(0.4472160970960963),FL2FXCONST_DBL(0.4482812141064458),FL2FXCONST_DBL(0.4493469641732286),FL2FXCONST_DBL(0.4504133465452648), + FL2FXCONST_DBL(0.4514803604735984),FL2FXCONST_DBL(0.4525480052114875),FL2FXCONST_DBL(0.4536162800143939),FL2FXCONST_DBL(0.4546851841399719), + FL2FXCONST_DBL(0.4557547168480591),FL2FXCONST_DBL(0.4568248774006652),FL2FXCONST_DBL(0.4578956650619623),FL2FXCONST_DBL(0.4589670790982746), + FL2FXCONST_DBL(0.4600391187780688),FL2FXCONST_DBL(0.4611117833719430),FL2FXCONST_DBL(0.4621850721526184),FL2FXCONST_DBL(0.4632589843949278), + FL2FXCONST_DBL(0.4643335193758069),FL2FXCONST_DBL(0.4654086763742842),FL2FXCONST_DBL(0.4664844546714713),FL2FXCONST_DBL(0.4675608535505532), + FL2FXCONST_DBL(0.4686378722967790),FL2FXCONST_DBL(0.4697155101974522),FL2FXCONST_DBL(0.4707937665419216),FL2FXCONST_DBL(0.4718726406215713), + FL2FXCONST_DBL(0.4729521317298118),FL2FXCONST_DBL(0.4740322391620711),FL2FXCONST_DBL(0.4751129622157845),FL2FXCONST_DBL(0.4761943001903867), + FL2FXCONST_DBL(0.4772762523873015),FL2FXCONST_DBL(0.4783588181099338),FL2FXCONST_DBL(0.4794419966636599),FL2FXCONST_DBL(0.4805257873558190), + FL2FXCONST_DBL(0.4816101894957042),FL2FXCONST_DBL(0.4826952023945537),FL2FXCONST_DBL(0.4837808253655421),FL2FXCONST_DBL(0.4848670577237714), + FL2FXCONST_DBL(0.4859538987862632),FL2FXCONST_DBL(0.4870413478719488),FL2FXCONST_DBL(0.4881294043016621),FL2FXCONST_DBL(0.4892180673981298), + FL2FXCONST_DBL(0.4903073364859640),FL2FXCONST_DBL(0.4913972108916533),FL2FXCONST_DBL(0.4924876899435545),FL2FXCONST_DBL(0.4935787729718844), + FL2FXCONST_DBL(0.4946704593087116),FL2FXCONST_DBL(0.4957627482879484),FL2FXCONST_DBL(0.4968556392453423),FL2FXCONST_DBL(0.4979491315184684), + FL2FXCONST_DBL(0.4990432244467211),FL2FXCONST_DBL(0.5001379173713062),FL2FXCONST_DBL(0.5012332096352328),FL2FXCONST_DBL(0.5023291005833056), + FL2FXCONST_DBL(0.5034255895621171),FL2FXCONST_DBL(0.5045226759200399),FL2FXCONST_DBL(0.5056203590072181),FL2FXCONST_DBL(0.5067186381755611), + FL2FXCONST_DBL(0.5078175127787346),FL2FXCONST_DBL(0.5089169821721536),FL2FXCONST_DBL(0.5100170457129749),FL2FXCONST_DBL(0.5111177027600893), + FL2FXCONST_DBL(0.5122189526741143),FL2FXCONST_DBL(0.5133207948173868),FL2FXCONST_DBL(0.5144232285539552),FL2FXCONST_DBL(0.5155262532495726), + FL2FXCONST_DBL(0.5166298682716894),FL2FXCONST_DBL(0.5177340729894460),FL2FXCONST_DBL(0.5188388667736652),FL2FXCONST_DBL(0.5199442489968457), + FL2FXCONST_DBL(0.5210502190331544),FL2FXCONST_DBL(0.5221567762584198),FL2FXCONST_DBL(0.5232639200501247),FL2FXCONST_DBL(0.5243716497873989), + FL2FXCONST_DBL(0.5254799648510130),FL2FXCONST_DBL(0.5265888646233705),FL2FXCONST_DBL(0.5276983484885021),FL2FXCONST_DBL(0.5288084158320574), + FL2FXCONST_DBL(0.5299190660412995),FL2FXCONST_DBL(0.5310302985050975),FL2FXCONST_DBL(0.5321421126139198),FL2FXCONST_DBL(0.5332545077598274), + FL2FXCONST_DBL(0.5343674833364678),FL2FXCONST_DBL(0.5354810387390675),FL2FXCONST_DBL(0.5365951733644262),FL2FXCONST_DBL(0.5377098866109097), + FL2FXCONST_DBL(0.5388251778784438),FL2FXCONST_DBL(0.5399410465685075),FL2FXCONST_DBL(0.5410574920841272),FL2FXCONST_DBL(0.5421745138298695), + FL2FXCONST_DBL(0.5432921112118353),FL2FXCONST_DBL(0.5444102836376534),FL2FXCONST_DBL(0.5455290305164744),FL2FXCONST_DBL(0.5466483512589642), + FL2FXCONST_DBL(0.5477682452772976),FL2FXCONST_DBL(0.5488887119851529),FL2FXCONST_DBL(0.5500097507977050),FL2FXCONST_DBL(0.5511313611316194), + FL2FXCONST_DBL(0.5522535424050467),FL2FXCONST_DBL(0.5533762940376158),FL2FXCONST_DBL(0.5544996154504284),FL2FXCONST_DBL(0.5556235060660528), + FL2FXCONST_DBL(0.5567479653085183),FL2FXCONST_DBL(0.5578729926033087),FL2FXCONST_DBL(0.5589985873773569),FL2FXCONST_DBL(0.5601247490590389), + FL2FXCONST_DBL(0.5612514770781683),FL2FXCONST_DBL(0.5623787708659898),FL2FXCONST_DBL(0.5635066298551742),FL2FXCONST_DBL(0.5646350534798125), + FL2FXCONST_DBL(0.5657640411754097),FL2FXCONST_DBL(0.5668935923788799),FL2FXCONST_DBL(0.5680237065285404),FL2FXCONST_DBL(0.5691543830641059), + FL2FXCONST_DBL(0.5702856214266832),FL2FXCONST_DBL(0.5714174210587655),FL2FXCONST_DBL(0.5725497814042271),FL2FXCONST_DBL(0.5736827019083177), + FL2FXCONST_DBL(0.5748161820176573),FL2FXCONST_DBL(0.5759502211802304),FL2FXCONST_DBL(0.5770848188453810),FL2FXCONST_DBL(0.5782199744638067), + FL2FXCONST_DBL(0.5793556874875542),FL2FXCONST_DBL(0.5804919573700131),FL2FXCONST_DBL(0.5816287835659116),FL2FXCONST_DBL(0.5827661655313104), + FL2FXCONST_DBL(0.5839041027235979),FL2FXCONST_DBL(0.5850425946014850),FL2FXCONST_DBL(0.5861816406250000),FL2FXCONST_DBL(0.5873212402554834), + FL2FXCONST_DBL(0.5884613929555826),FL2FXCONST_DBL(0.5896020981892474),FL2FXCONST_DBL(0.5907433554217242),FL2FXCONST_DBL(0.5918851641195517), + FL2FXCONST_DBL(0.5930275237505556),FL2FXCONST_DBL(0.5941704337838434),FL2FXCONST_DBL(0.5953138936897999),FL2FXCONST_DBL(0.5964579029400819), + FL2FXCONST_DBL(0.5976024610076139),FL2FXCONST_DBL(0.5987475673665825),FL2FXCONST_DBL(0.5998932214924321),FL2FXCONST_DBL(0.6010394228618597), + FL2FXCONST_DBL(0.6021861709528106),FL2FXCONST_DBL(0.6033334652444733),FL2FXCONST_DBL(0.6044813052172748),FL2FXCONST_DBL(0.6056296903528761), + FL2FXCONST_DBL(0.6067786201341671),FL2FXCONST_DBL(0.6079280940452625),FL2FXCONST_DBL(0.6090781115714966),FL2FXCONST_DBL(0.6102286721994192), + FL2FXCONST_DBL(0.6113797754167908),FL2FXCONST_DBL(0.6125314207125777),FL2FXCONST_DBL(0.6136836075769482),FL2FXCONST_DBL(0.6148363355012674), + FL2FXCONST_DBL(0.6159896039780929),FL2FXCONST_DBL(0.6171434125011708),FL2FXCONST_DBL(0.6182977605654305),FL2FXCONST_DBL(0.6194526476669808), + FL2FXCONST_DBL(0.6206080733031054),FL2FXCONST_DBL(0.6217640369722584),FL2FXCONST_DBL(0.6229205381740598),FL2FXCONST_DBL(0.6240775764092919), + FL2FXCONST_DBL(0.6252351511798939),FL2FXCONST_DBL(0.6263932619889586),FL2FXCONST_DBL(0.6275519083407275),FL2FXCONST_DBL(0.6287110897405869), + FL2FXCONST_DBL(0.6298708056950635),FL2FXCONST_DBL(0.6310310557118203),FL2FXCONST_DBL(0.6321918392996523),FL2FXCONST_DBL(0.6333531559684823), + FL2FXCONST_DBL(0.6345150052293571),FL2FXCONST_DBL(0.6356773865944432),FL2FXCONST_DBL(0.6368402995770224),FL2FXCONST_DBL(0.6380037436914881), + FL2FXCONST_DBL(0.6391677184533411),FL2FXCONST_DBL(0.6403322233791856),FL2FXCONST_DBL(0.6414972579867254),FL2FXCONST_DBL(0.6426628217947594), + FL2FXCONST_DBL(0.6438289143231779),FL2FXCONST_DBL(0.6449955350929588),FL2FXCONST_DBL(0.6461626836261636),FL2FXCONST_DBL(0.6473303594459330), + FL2FXCONST_DBL(0.6484985620764839),FL2FXCONST_DBL(0.6496672910431047),FL2FXCONST_DBL(0.6508365458721518),FL2FXCONST_DBL(0.6520063260910459), + FL2FXCONST_DBL(0.6531766312282679),FL2FXCONST_DBL(0.6543474608133552),FL2FXCONST_DBL(0.6555188143768979),FL2FXCONST_DBL(0.6566906914505349), + FL2FXCONST_DBL(0.6578630915669509),FL2FXCONST_DBL(0.6590360142598715),FL2FXCONST_DBL(0.6602094590640603),FL2FXCONST_DBL(0.6613834255153149), + FL2FXCONST_DBL(0.6625579131504635),FL2FXCONST_DBL(0.6637329215073610),FL2FXCONST_DBL(0.6649084501248851),FL2FXCONST_DBL(0.6660844985429335), + FL2FXCONST_DBL(0.6672610663024197),FL2FXCONST_DBL(0.6684381529452691),FL2FXCONST_DBL(0.6696157580144163),FL2FXCONST_DBL(0.6707938810538011), + FL2FXCONST_DBL(0.6719725216083646),FL2FXCONST_DBL(0.6731516792240465),FL2FXCONST_DBL(0.6743313534477807),FL2FXCONST_DBL(0.6755115438274927), + FL2FXCONST_DBL(0.6766922499120955),FL2FXCONST_DBL(0.6778734712514865),FL2FXCONST_DBL(0.6790552073965435),FL2FXCONST_DBL(0.6802374578991223), + FL2FXCONST_DBL(0.6814202223120524),FL2FXCONST_DBL(0.6826035001891340),FL2FXCONST_DBL(0.6837872910851345),FL2FXCONST_DBL(0.6849715945557853), + FL2FXCONST_DBL(0.6861564101577784),FL2FXCONST_DBL(0.6873417374487629),FL2FXCONST_DBL(0.6885275759873420),FL2FXCONST_DBL(0.6897139253330697), + FL2FXCONST_DBL(0.6909007850464473),FL2FXCONST_DBL(0.6920881546889198),FL2FXCONST_DBL(0.6932760338228737),FL2FXCONST_DBL(0.6944644220116332), + FL2FXCONST_DBL(0.6956533188194565),FL2FXCONST_DBL(0.6968427238115332),FL2FXCONST_DBL(0.6980326365539813),FL2FXCONST_DBL(0.6992230566138435), + FL2FXCONST_DBL(0.7004139835590845),FL2FXCONST_DBL(0.7016054169585869),FL2FXCONST_DBL(0.7027973563821499),FL2FXCONST_DBL(0.7039898014004843), + FL2FXCONST_DBL(0.7051827515852106),FL2FXCONST_DBL(0.7063762065088554),FL2FXCONST_DBL(0.7075701657448483),FL2FXCONST_DBL(0.7087646288675196), + FL2FXCONST_DBL(0.7099595954520960),FL2FXCONST_DBL(0.7111550650746988),FL2FXCONST_DBL(0.7123510373123402),FL2FXCONST_DBL(0.7135475117429202), + FL2FXCONST_DBL(0.7147444879452244),FL2FXCONST_DBL(0.7159419654989200),FL2FXCONST_DBL(0.7171399439845538),FL2FXCONST_DBL(0.7183384229835486), + FL2FXCONST_DBL(0.7195374020782005),FL2FXCONST_DBL(0.7207368808516762),FL2FXCONST_DBL(0.7219368588880097),FL2FXCONST_DBL(0.7231373357720997), + FL2FXCONST_DBL(0.7243383110897066),FL2FXCONST_DBL(0.7255397844274496),FL2FXCONST_DBL(0.7267417553728043),FL2FXCONST_DBL(0.7279442235140992), + FL2FXCONST_DBL(0.7291471884405130),FL2FXCONST_DBL(0.7303506497420724),FL2FXCONST_DBL(0.7315546070096487),FL2FXCONST_DBL(0.7327590598349553), + FL2FXCONST_DBL(0.7339640078105445),FL2FXCONST_DBL(0.7351694505298055),FL2FXCONST_DBL(0.7363753875869610),FL2FXCONST_DBL(0.7375818185770647), + FL2FXCONST_DBL(0.7387887430959987),FL2FXCONST_DBL(0.7399961607404706),FL2FXCONST_DBL(0.7412040711080108),FL2FXCONST_DBL(0.7424124737969701), + FL2FXCONST_DBL(0.7436213684065166),FL2FXCONST_DBL(0.7448307545366334),FL2FXCONST_DBL(0.7460406317881158),FL2FXCONST_DBL(0.7472509997625686), + FL2FXCONST_DBL(0.7484618580624036),FL2FXCONST_DBL(0.7496732062908372),FL2FXCONST_DBL(0.7508850440518872),FL2FXCONST_DBL(0.7520973709503704), + FL2FXCONST_DBL(0.7533101865919009),FL2FXCONST_DBL(0.7545234905828862),FL2FXCONST_DBL(0.7557372825305252),FL2FXCONST_DBL(0.7569515620428062), + FL2FXCONST_DBL(0.7581663287285035),FL2FXCONST_DBL(0.7593815821971756),FL2FXCONST_DBL(0.7605973220591619),FL2FXCONST_DBL(0.7618135479255810), + FL2FXCONST_DBL(0.7630302594083277),FL2FXCONST_DBL(0.7642474561200708),FL2FXCONST_DBL(0.7654651376742505),FL2FXCONST_DBL(0.7666833036850760), + FL2FXCONST_DBL(0.7679019537675227),FL2FXCONST_DBL(0.7691210875373307),FL2FXCONST_DBL(0.7703407046110011),FL2FXCONST_DBL(0.7715608046057948), + FL2FXCONST_DBL(0.7727813871397293),FL2FXCONST_DBL(0.7740024518315765),FL2FXCONST_DBL(0.7752239983008605),FL2FXCONST_DBL(0.7764460261678551), + FL2FXCONST_DBL(0.7776685350535814),FL2FXCONST_DBL(0.7788915245798054),FL2FXCONST_DBL(0.7801149943690360),FL2FXCONST_DBL(0.7813389440445223), + FL2FXCONST_DBL(0.7825633732302513),FL2FXCONST_DBL(0.7837882815509458),FL2FXCONST_DBL(0.7850136686320621),FL2FXCONST_DBL(0.7862395340997874), + FL2FXCONST_DBL(0.7874658775810378),FL2FXCONST_DBL(0.7886926987034559),FL2FXCONST_DBL(0.7899199970954088),FL2FXCONST_DBL(0.7911477723859853), + FL2FXCONST_DBL(0.7923760242049944),FL2FXCONST_DBL(0.7936047521829623),FL2FXCONST_DBL(0.7948339559511308),FL2FXCONST_DBL(0.7960636351414546), + FL2FXCONST_DBL(0.7972937893865995),FL2FXCONST_DBL(0.7985244183199399),FL2FXCONST_DBL(0.7997555215755570),FL2FXCONST_DBL(0.8009870987882359), + FL2FXCONST_DBL(0.8022191495934644),FL2FXCONST_DBL(0.8034516736274301),FL2FXCONST_DBL(0.8046846705270185),FL2FXCONST_DBL(0.8059181399298110), + FL2FXCONST_DBL(0.8071520814740822),FL2FXCONST_DBL(0.8083864947987989),FL2FXCONST_DBL(0.8096213795436166),FL2FXCONST_DBL(0.8108567353488784), + FL2FXCONST_DBL(0.8120925618556127),FL2FXCONST_DBL(0.8133288587055308),FL2FXCONST_DBL(0.8145656255410253),FL2FXCONST_DBL(0.8158028620051674), + FL2FXCONST_DBL(0.8170405677417053),FL2FXCONST_DBL(0.8182787423950622),FL2FXCONST_DBL(0.8195173856103341),FL2FXCONST_DBL(0.8207564970332875), + FL2FXCONST_DBL(0.8219960763103580),FL2FXCONST_DBL(0.8232361230886477),FL2FXCONST_DBL(0.8244766370159234),FL2FXCONST_DBL(0.8257176177406150), + FL2FXCONST_DBL(0.8269590649118125),FL2FXCONST_DBL(0.8282009781792650),FL2FXCONST_DBL(0.8294433571933784),FL2FXCONST_DBL(0.8306862016052132), + FL2FXCONST_DBL(0.8319295110664831),FL2FXCONST_DBL(0.8331732852295520),FL2FXCONST_DBL(0.8344175237474336),FL2FXCONST_DBL(0.8356622262737878), + FL2FXCONST_DBL(0.8369073924629202),FL2FXCONST_DBL(0.8381530219697793),FL2FXCONST_DBL(0.8393991144499545),FL2FXCONST_DBL(0.8406456695596752), + FL2FXCONST_DBL(0.8418926869558079),FL2FXCONST_DBL(0.8431401662958544),FL2FXCONST_DBL(0.8443881072379507),FL2FXCONST_DBL(0.8456365094408642), + FL2FXCONST_DBL(0.8468853725639923),FL2FXCONST_DBL(0.8481346962673606),FL2FXCONST_DBL(0.8493844802116208),FL2FXCONST_DBL(0.8506347240580492), + FL2FXCONST_DBL(0.8518854274685442),FL2FXCONST_DBL(0.8531365901056253),FL2FXCONST_DBL(0.8543882116324307),FL2FXCONST_DBL(0.8556402917127157), + FL2FXCONST_DBL(0.8568928300108512),FL2FXCONST_DBL(0.8581458261918209),FL2FXCONST_DBL(0.8593992799212207),FL2FXCONST_DBL(0.8606531908652563), + FL2FXCONST_DBL(0.8619075586907414),FL2FXCONST_DBL(0.8631623830650962),FL2FXCONST_DBL(0.8644176636563452),FL2FXCONST_DBL(0.8656734001331161), + FL2FXCONST_DBL(0.8669295921646375),FL2FXCONST_DBL(0.8681862394207371),FL2FXCONST_DBL(0.8694433415718407),FL2FXCONST_DBL(0.8707008982889695), + FL2FXCONST_DBL(0.8719589092437391),FL2FXCONST_DBL(0.8732173741083574),FL2FXCONST_DBL(0.8744762925556232),FL2FXCONST_DBL(0.8757356642589241), + FL2FXCONST_DBL(0.8769954888922352),FL2FXCONST_DBL(0.8782557661301171),FL2FXCONST_DBL(0.8795164956477146),FL2FXCONST_DBL(0.8807776771207545), + FL2FXCONST_DBL(0.8820393102255443),FL2FXCONST_DBL(0.8833013946389704),FL2FXCONST_DBL(0.8845639300384969),FL2FXCONST_DBL(0.8858269161021629), + FL2FXCONST_DBL(0.8870903525085819),FL2FXCONST_DBL(0.8883542389369399),FL2FXCONST_DBL(0.8896185750669933),FL2FXCONST_DBL(0.8908833605790678), + FL2FXCONST_DBL(0.8921485951540565),FL2FXCONST_DBL(0.8934142784734187),FL2FXCONST_DBL(0.8946804102191776),FL2FXCONST_DBL(0.8959469900739191), + FL2FXCONST_DBL(0.8972140177207906),FL2FXCONST_DBL(0.8984814928434985),FL2FXCONST_DBL(0.8997494151263077),FL2FXCONST_DBL(0.9010177842540390), + FL2FXCONST_DBL(0.9022865999120682),FL2FXCONST_DBL(0.9035558617863242),FL2FXCONST_DBL(0.9048255695632878),FL2FXCONST_DBL(0.9060957229299895), + FL2FXCONST_DBL(0.9073663215740092),FL2FXCONST_DBL(0.9086373651834729),FL2FXCONST_DBL(0.9099088534470528),FL2FXCONST_DBL(0.9111807860539647), + FL2FXCONST_DBL(0.9124531626939672),FL2FXCONST_DBL(0.9137259830573594),FL2FXCONST_DBL(0.9149992468349805),FL2FXCONST_DBL(0.9162729537182071), + FL2FXCONST_DBL(0.9175471033989524),FL2FXCONST_DBL(0.9188216955696648),FL2FXCONST_DBL(0.9200967299233258),FL2FXCONST_DBL(0.9213722061534494), + FL2FXCONST_DBL(0.9226481239540795),FL2FXCONST_DBL(0.9239244830197896),FL2FXCONST_DBL(0.9252012830456805),FL2FXCONST_DBL(0.9264785237273793), + FL2FXCONST_DBL(0.9277562047610376),FL2FXCONST_DBL(0.9290343258433305),FL2FXCONST_DBL(0.9303128866714547),FL2FXCONST_DBL(0.9315918869431275), + FL2FXCONST_DBL(0.9328713263565848),FL2FXCONST_DBL(0.9341512046105802),FL2FXCONST_DBL(0.9354315214043836),FL2FXCONST_DBL(0.9367122764377792), + FL2FXCONST_DBL(0.9379934694110648),FL2FXCONST_DBL(0.9392751000250497),FL2FXCONST_DBL(0.9405571679810542),FL2FXCONST_DBL(0.9418396729809072), + FL2FXCONST_DBL(0.9431226147269456),FL2FXCONST_DBL(0.9444059929220124),FL2FXCONST_DBL(0.9456898072694558),FL2FXCONST_DBL(0.9469740574731275), + FL2FXCONST_DBL(0.9482587432373810),FL2FXCONST_DBL(0.9495438642670713),FL2FXCONST_DBL(0.9508294202675522),FL2FXCONST_DBL(0.9521154109446763), + FL2FXCONST_DBL(0.9534018360047926),FL2FXCONST_DBL(0.9546886951547455),FL2FXCONST_DBL(0.9559759881018738),FL2FXCONST_DBL(0.9572637145540087), + FL2FXCONST_DBL(0.9585518742194732),FL2FXCONST_DBL(0.9598404668070802),FL2FXCONST_DBL(0.9611294920261317),FL2FXCONST_DBL(0.9624189495864168), + FL2FXCONST_DBL(0.9637088391982110),FL2FXCONST_DBL(0.9649991605722750),FL2FXCONST_DBL(0.9662899134198524),FL2FXCONST_DBL(0.9675810974526697), + FL2FXCONST_DBL(0.9688727123829343),FL2FXCONST_DBL(0.9701647579233330),FL2FXCONST_DBL(0.9714572337870316),FL2FXCONST_DBL(0.9727501396876727), + FL2FXCONST_DBL(0.9740434753393749),FL2FXCONST_DBL(0.9753372404567313),FL2FXCONST_DBL(0.9766314347548087),FL2FXCONST_DBL(0.9779260579491460), + FL2FXCONST_DBL(0.9792211097557527),FL2FXCONST_DBL(0.9805165898911081),FL2FXCONST_DBL(0.9818124980721600),FL2FXCONST_DBL(0.9831088340163232), + FL2FXCONST_DBL(0.9844055974414786),FL2FXCONST_DBL(0.9857027880659716),FL2FXCONST_DBL(0.9870004056086111),FL2FXCONST_DBL(0.9882984497886684), + FL2FXCONST_DBL(0.9895969203258759),FL2FXCONST_DBL(0.9908958169404255),FL2FXCONST_DBL(0.9921951393529680),FL2FXCONST_DBL(0.9934948872846116), + FL2FXCONST_DBL(0.9947950604569206),FL2FXCONST_DBL(0.9960956585919144),FL2FXCONST_DBL(0.9973966814120665),FL2FXCONST_DBL(0.9986981286403025) +}; + +const FIXP_DBL FDKaacEnc_specExpMantTableCombElc[4][14] = +{ + {FL2FXCONST_DBL(0.5000000000000000), FL2FXCONST_DBL(0.6299605249474366), FL2FXCONST_DBL(0.7937005259840998), FL2FXCONST_DBL(0.5000000000000000), + FL2FXCONST_DBL(0.6299605249474366), FL2FXCONST_DBL(0.7937005259840998), FL2FXCONST_DBL(0.5000000000000000), FL2FXCONST_DBL(0.6299605249474366), + FL2FXCONST_DBL(0.7937005259840998), FL2FXCONST_DBL(0.5000000000000000), FL2FXCONST_DBL(0.6299605249474366), FL2FXCONST_DBL(0.7937005259840998), + FL2FXCONST_DBL(0.5000000000000000), FL2FXCONST_DBL(0.6299605249474366)}, + + {FL2FXCONST_DBL(0.5946035575013605), FL2FXCONST_DBL(0.7491535384383408), FL2FXCONST_DBL(0.9438743126816935), FL2FXCONST_DBL(0.5946035575013605), + FL2FXCONST_DBL(0.7491535384383408), FL2FXCONST_DBL(0.9438743126816935), FL2FXCONST_DBL(0.5946035575013605), FL2FXCONST_DBL(0.7491535384383408), + FL2FXCONST_DBL(0.9438743126816935), FL2FXCONST_DBL(0.5946035575013605), FL2FXCONST_DBL(0.7491535384383408), FL2FXCONST_DBL(0.9438743126816935), + FL2FXCONST_DBL(0.5946035575013605), FL2FXCONST_DBL(0.7491535384383408)}, + + {FL2FXCONST_DBL(0.7071067811865476), FL2FXCONST_DBL(0.8908987181403393), FL2FXCONST_DBL(0.5612310241546865), FL2FXCONST_DBL(0.7071067811865476), + FL2FXCONST_DBL(0.8908987181403393), FL2FXCONST_DBL(0.5612310241546865), FL2FXCONST_DBL(0.7071067811865476), FL2FXCONST_DBL(0.8908987181403393), + FL2FXCONST_DBL(0.5612310241546865), FL2FXCONST_DBL(0.7071067811865476), FL2FXCONST_DBL(0.8908987181403393), FL2FXCONST_DBL(0.5612310241546865), + FL2FXCONST_DBL(0.7071067811865476), FL2FXCONST_DBL(0.8908987181403393)}, + + {FL2FXCONST_DBL(0.8408964152537145), FL2FXCONST_DBL(0.5297315471796477), FL2FXCONST_DBL(0.6674199270850172), FL2FXCONST_DBL(0.8408964152537145), + FL2FXCONST_DBL(0.5297315471796477), FL2FXCONST_DBL(0.6674199270850172), FL2FXCONST_DBL(0.8408964152537145), FL2FXCONST_DBL(0.5297315471796477), + FL2FXCONST_DBL(0.6674199270850172), FL2FXCONST_DBL(0.8408964152537145), FL2FXCONST_DBL(0.5297315471796477), FL2FXCONST_DBL(0.6674199270850172), + FL2FXCONST_DBL(0.8408964152537145), FL2FXCONST_DBL(0.5297315471796477)} +}; + +const UCHAR FDKaacEnc_specExpTableComb[4][14] = +{ + {1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17, 18}, + {1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17, 18}, + {1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 16, 17, 18}, + {1, 3, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 17, 19} +}; + + +#define WTS0 1 +#define WTS1 0 +#define WTS2 -2 + +const FIXP_WTB ELDAnalysis512[1536] = { + /* part 0 */ + WTC0(0xfac5a770), WTC0(0xfaafbab8), WTC0(0xfa996a40), WTC0(0xfa82bbd0), WTC0(0xfa6bb538), WTC0(0xfa545c38), WTC0(0xfa3cb698), WTC0(0xfa24ca28), + WTC0(0xfa0c9ca8), WTC0(0xf9f433e8), WTC0(0xf9db9580), WTC0(0xf9c2c298), WTC0(0xf9a9b800), WTC0(0xf9907250), WTC0(0xf976ee38), WTC0(0xf95d2b88), + WTC0(0xf9432d10), WTC0(0xf928f5c0), WTC0(0xf90e8868), WTC0(0xf8f3e400), WTC0(0xf8d903a0), WTC0(0xf8bde238), WTC0(0xf8a27af0), WTC0(0xf886cde8), + WTC0(0xf86ae020), WTC0(0xf84eb6c0), WTC0(0xf83256f8), WTC0(0xf815c4b8), WTC0(0xf7f902c0), WTC0(0xf7dc13b0), WTC0(0xf7befa60), WTC0(0xf7a1ba40), + WTC0(0xf78457c0), WTC0(0xf766d780), WTC0(0xf7493d90), WTC0(0xf72b8990), WTC0(0xf70db5f0), WTC0(0xf6efbd30), WTC0(0xf6d19a20), WTC0(0xf6b352e0), + WTC0(0xf694f8c0), WTC0(0xf6769da0), WTC0(0xf6585310), WTC0(0xf63a28d0), WTC0(0xf61c2c60), WTC0(0xf5fe6b10), WTC0(0xf5e0f250), WTC0(0xf5c3ceb0), + WTC0(0xf5a70be0), WTC0(0xf58ab5a0), WTC0(0xf56ed7b0), WTC0(0xf5537e40), WTC0(0xf538b610), WTC0(0xf51e8bf0), WTC0(0xf5050c90), WTC0(0xf4ec4330), + WTC0(0xf4d439b0), WTC0(0xf4bcf9b0), WTC0(0xf4a68ce0), WTC0(0xf490fa80), WTC0(0xf47c4760), WTC0(0xf4687830), WTC0(0xf4558f00), WTC0(0xf4434fc0), + WTC0(0xf4314070), WTC0(0xf41ee450), WTC0(0xf40bc130), WTC0(0xf3f799c0), WTC0(0xf3e26d30), WTC0(0xf3cc3d70), WTC0(0xf3b50c80), WTC0(0xf39cdd60), + WTC0(0xf383b440), WTC0(0xf3699550), WTC0(0xf34e84c0), WTC0(0xf33286b0), WTC0(0xf3159f10), WTC0(0xf2f7d1b0), WTC0(0xf2d92290), WTC0(0xf2b994d0), + WTC0(0xf2992ad0), WTC0(0xf277e6d0), WTC0(0xf255cb60), WTC0(0xf232dd00), WTC0(0xf20f2240), WTC0(0xf1eaa1d0), WTC0(0xf1c56240), WTC0(0xf19f63d0), + WTC0(0xf178a0f0), WTC0(0xf15113a0), WTC0(0xf128b5c0), WTC0(0xf0ff7fd0), WTC0(0xf0d56860), WTC0(0xf0aa6610), WTC0(0xf07e6fd0), WTC0(0xf0518190), + WTC0(0xf0239cd0), WTC0(0xeff4c320), WTC0(0xefc4f720), WTC0(0xef945080), WTC0(0xef62fce0), WTC0(0xef312a40), WTC0(0xeeff05c0), WTC0(0xeecca2c0), + WTC0(0xee99faa0), WTC0(0xee6705a0), WTC0(0xee33bb60), WTC0(0xee000060), WTC0(0xedcba660), WTC0(0xed967e80), WTC0(0xed605b80), WTC0(0xed293b40), + WTC0(0xecf146a0), WTC0(0xecb8a8a0), WTC0(0xec7f8bc0), WTC0(0xec461260), WTC0(0xec0c5720), WTC0(0xebd27440), WTC0(0xeb988220), WTC0(0xeb5e7040), + WTC0(0xeb2404c0), WTC0(0xeae90440), WTC0(0xeaad33c0), WTC0(0xea7066c0), WTC0(0xea327f60), WTC0(0xe9f36000), WTC0(0xe9b2ed60), WTC0(0xe9713920), + WTC0(0xe92e81e0), WTC0(0xe8eb08c0), WTC0(0xe8a70e60), WTC0(0xe862d8e0), WTC0(0xe81eb340), WTC0(0xe7dae8a0), WTC0(0xe797c1a0), WTC0(0xe7554ca0), + WTC0(0xe7135dc0), WTC0(0xe6d1c6a0), WTC0(0xe6905720), WTC0(0xe64eb9c0), WTC0(0xe60c7300), WTC0(0xe5c90600), WTC0(0xe583f920), WTC0(0xe53d1ce0), + WTC0(0xe4f48c80), WTC0(0xe4aa6640), WTC0(0xe45ecaa0), WTC0(0xe4120be0), WTC0(0xe3c4ae60), WTC0(0xe3773860), WTC0(0xe32a2ea0), WTC0(0xe2ddeea0), + WTC0(0xe292af00), WTC0(0xe248a4a0), WTC0(0xe2000140), WTC0(0xe1b8b640), WTC0(0xe1727440), WTC0(0xe12ce900), WTC0(0xe0e7c280), WTC0(0xe0a2b420), + WTC0(0xe05d76c0), WTC0(0xe017c360), WTC0(0xdfd15440), WTC0(0xdf8a0540), WTC0(0xdf41d300), WTC0(0xdef8bb40), WTC0(0xdeaebd40), WTC0(0xde63e7c0), + WTC0(0xde185940), WTC0(0xddcc3180), WTC0(0xdd7f9000), WTC0(0xdd329e80), WTC0(0xdce58e80), WTC0(0xdc989300), WTC0(0xdc4bde40), WTC0(0xdbff96c0), + WTC0(0xdbb3d780), WTC0(0xdb68bb80), WTC0(0xdb1e5c80), WTC0(0xdad4c380), WTC0(0xda8be840), WTC0(0xda43c1c0), WTC0(0xd9fc4740), WTC0(0xd9b56640), + WTC0(0xd96f0440), WTC0(0xd9290600), WTC0(0xd8e35080), WTC0(0xd89dcd40), WTC0(0xd8586b40), WTC0(0xd8131940), WTC0(0xd7cdc640), WTC0(0xd7886180), + WTC0(0xd742dc80), WTC0(0xd6fd2780), WTC0(0xd6b73400), WTC0(0xd670fd80), WTC0(0xd62a8a40), WTC0(0xd5e3e080), WTC0(0xd59d0840), WTC0(0xd5562b80), + WTC0(0xd50f9540), WTC0(0xd4c992c0), WTC0(0xd4846f80), WTC0(0xd4405a80), WTC0(0xd3fd6580), WTC0(0xd3bba140), WTC0(0xd37b1c80), WTC0(0xd33bb780), + WTC0(0xd2fd2400), WTC0(0xd2bf1240), WTC0(0xd2813300), WTC0(0xd2435ac0), WTC0(0xd2057fc0), WTC0(0xd1c79a00), WTC0(0xd189a240), WTC0(0xd14b9dc0), + WTC0(0xd10d9e00), WTC0(0xd0cfb580), WTC0(0xd091f6c0), WTC0(0xd0548100), WTC0(0xd0177f40), WTC0(0xcfdb1cc0), WTC0(0xcf9f84c0), WTC0(0xcf64d780), + WTC0(0xcf2b2b00), WTC0(0xcef29440), WTC0(0xcebb2640), WTC0(0xce84c000), WTC0(0xce4f0bc0), WTC0(0xce19b200), WTC0(0xcde45d40), WTC0(0xcdaeedc0), + WTC0(0xcd7979c0), WTC0(0xcd4419c0), WTC0(0xcd0ee6c0), WTC0(0xccda0540), WTC0(0xcca5a500), WTC0(0xcc71f640), WTC0(0xcc3f2800), WTC0(0xcc0d4300), + WTC0(0xcbdc2a00), WTC0(0xcbabbe80), WTC0(0xcb7be200), WTC0(0xcb4c8200), WTC0(0xcb1d9800), WTC0(0xcaef1d40), WTC0(0xcac10bc0), WTC0(0xca936440), + WTC0(0xca662d00), WTC0(0xca396d40), WTC0(0xca0d2b80), WTC0(0xc9e16f80), WTC0(0xc9b63f80), WTC0(0xc98ba2c0), WTC0(0xc961a000), WTC0(0xc9383ec0), + WTC0(0xc90a0440), WTC0(0xc8e0d280), WTC0(0xc8b73b80), WTC0(0xc88d4900), WTC0(0xc86304c0), WTC0(0xc83878c0), WTC0(0xc80dae80), WTC0(0xc7e2afc0), + WTC0(0xc7b78640), WTC0(0xc78c3c40), WTC0(0xc760da80), WTC0(0xc7356640), WTC0(0xc709de40), WTC0(0xc6de41c0), WTC0(0xc6b28fc0), WTC0(0xc686bd40), + WTC0(0xc65ab600), WTC0(0xc62e6580), WTC0(0xc601b880), WTC0(0xc5d4bac0), WTC0(0xc5a79640), WTC0(0xc57a76c0), WTC0(0xc54d8780), WTC0(0xc520e840), + WTC0(0xc4f4acc0), WTC0(0xc4c8e880), WTC0(0xc49dad80), WTC0(0xc472e640), WTC0(0xc44856c0), WTC0(0xc41dc140), WTC0(0xc3f2e940), WTC0(0xc3c7bc00), + WTC0(0xc39c4f00), WTC0(0xc370b9c0), WTC0(0xc34513c0), WTC0(0xc3197940), WTC0(0xc2ee0a00), WTC0(0xc2c2e640), WTC0(0xc2982d80), WTC0(0xc26df5c0), + WTC0(0xc2444b00), WTC0(0xc21b3940), WTC0(0xc1f2cbc0), WTC0(0xc1cb05c0), WTC0(0xc1a3e340), WTC0(0xc17d5f00), WTC0(0xc15773c0), WTC0(0xc1320940), + WTC0(0xc10cf480), WTC0(0xc0e80a00), WTC0(0xc0c31f00), WTC0(0xc09e2640), WTC0(0xc0792ec0), WTC0(0xc0544940), WTC0(0xc02f86c0), WTC0(0xc00b04c0), + WTC0(0xbfe6ed01), WTC0(0xbfc36a01), WTC0(0xbfa0a581), WTC0(0xbf7eb581), WTC0(0xbf5d9a81), WTC0(0xbf3d5501), WTC0(0xbf1de601), WTC0(0xbeff4801), + WTC0(0xbee17201), WTC0(0xbec45881), WTC0(0xbea7f301), WTC0(0xbe8c3781), WTC0(0xbe712001), WTC0(0xbe56a381), WTC0(0xbe3cbc01), WTC0(0xbe236001), + WTC0(0xbe0a8581), WTC0(0xbdf22181), WTC0(0xbdda2a01), WTC0(0xbdc29a81), WTC0(0xbdab7181), WTC0(0xbd94b001), WTC0(0xbd7e5581), WTC0(0xbd686681), + WTC0(0xbd52eb01), WTC0(0xbd3deb81), WTC0(0xbd297181), WTC0(0xbd158801), WTC0(0xbd023f01), WTC0(0xbcefa601), WTC0(0xbcddcc81), WTC0(0xbcccbd01), + WTC0(0xbcbc7e01), WTC0(0xbcad1501), WTC0(0xbc9e8801), WTC0(0xbc90d481), WTC0(0xbc83f201), WTC0(0xbc77d601), WTC0(0xbc6c7781), WTC0(0xbc61c401), + WTC0(0xbc57a301), WTC0(0xbc4dfb81), WTC0(0xbc44b481), WTC0(0xbc3bbc01), WTC0(0xbc330781), WTC0(0xbc2a8c81), WTC0(0xbc224181), WTC0(0xbc1a2401), + WTC0(0xbc123b81), WTC0(0xbc0a8f01), WTC0(0xbc032601), WTC0(0xbbfc0f81), WTC0(0xbbf56181), WTC0(0xbbef3301), WTC0(0xbbe99981), WTC0(0xbbe49d01), + WTC0(0xbbe03801), WTC0(0xbbdc6481), WTC0(0xbbd91b81), WTC0(0xbbd64d01), WTC0(0xbbd3e101), WTC0(0xbbd1bd81), WTC0(0xbbcfca81), WTC0(0xbbce0601), + WTC0(0xbbcc8201), WTC0(0xbbcb5301), WTC0(0xbbca8d01), WTC0(0xbbca5081), WTC0(0xbbcaca01), WTC0(0xbbcc2681), WTC0(0xbbce9181), WTC0(0xbbd21281), + WTC0(0xbbd68c81), WTC0(0xbbdbe201), WTC0(0xbbe1f401), WTC0(0xbbe89901), WTC0(0xbbef9b81), WTC0(0xbbf6c601), WTC0(0xbbfde481), WTC0(0xbc04e381), + WTC0(0xbc0bcf81), WTC0(0xbc12b801), WTC0(0xbc19ab01), WTC0(0xbc20ae01), WTC0(0xbc27bd81), WTC0(0xbc2ed681), WTC0(0xbc35f501), WTC0(0xbc3d1801), + WTC0(0xbc444081), WTC0(0xbc4b6e81), WTC0(0xbc52a381), WTC0(0xbc59df81), WTC0(0xbc612301), WTC0(0xbc686e01), WTC0(0xbc6fc101), WTC0(0xbc771c01), + WTC0(0xbc7e7e01), WTC0(0xbc85e801), WTC0(0xbc8d5901), WTC0(0xbc94d201), WTC0(0xbc9c5281), WTC0(0xbca3db01), WTC0(0xbcab6c01), WTC0(0xbcb30601), + WTC0(0xbcbaa801), WTC0(0xbcc25181), WTC0(0xbcca0301), WTC0(0xbcd1bb81), WTC0(0xbcd97c81), WTC0(0xbce14601), WTC0(0xbce91801), WTC0(0xbcf0f381), + WTC0(0xbcf8d781), WTC0(0xbd00c381), WTC0(0xbd08b781), WTC0(0xbd10b381), WTC0(0xbd18b781), WTC0(0xbd20c401), WTC0(0xbd28d981), WTC0(0xbd30f881), + WTC0(0xbd391f81), WTC0(0xbd414f01), WTC0(0xbd498601), WTC0(0xbd51c481), WTC0(0xbd5a0b01), WTC0(0xbd625981), WTC0(0xbd6ab101), WTC0(0xbd731081), + WTC0(0xbd7b7781), WTC0(0xbd83e681), WTC0(0xbd8c5c01), WTC0(0xbd94d801), WTC0(0xbd9d5b81), WTC0(0xbda5e601), WTC0(0xbdae7881), WTC0(0xbdb71201), + WTC0(0xbdbfb281), WTC0(0xbdc85981), WTC0(0xbdd10681), WTC0(0xbdd9b981), WTC0(0xbde27201), WTC0(0xbdeb3101), WTC0(0xbdf3f701), WTC0(0xbdfcc301), + WTC0(0xbe059481), WTC0(0xbe0e6c01), WTC0(0xbe174781), WTC0(0xbe202801), WTC0(0xbe290d01), WTC0(0xbe31f701), WTC0(0xbe3ae601), WTC0(0xbe43da81), + WTC0(0xbe4cd381), WTC0(0xbe55d001), WTC0(0xbe5ed081), WTC0(0xbe67d381), WTC0(0xbe70da01), WTC0(0xbe79e481), WTC0(0xbe82f301), WTC0(0xbe8c0501), + WTC0(0xbe951a81), WTC0(0xbe9e3281), WTC0(0xbea74c81), WTC0(0xbeb06881), WTC0(0xbeb98681), WTC0(0xbec2a781), WTC0(0xbecbca81), WTC0(0xbed4f081), + WTC0(0xbede1901), WTC0(0xbee74281), WTC0(0xbef06d01), WTC0(0xbef99901), WTC0(0xbf02c581), WTC0(0xbf0bf381), WTC0(0xbf152381), WTC0(0xbf1e5501), + WTC0(0xbf278801), WTC0(0xbf30bb01), WTC0(0xbf39ee81), WTC0(0xbf432281), WTC0(0xbf4c5681), WTC0(0xbf558b01), WTC0(0xbf5ec101), WTC0(0xbf67f801), + WTC0(0xbf712f01), WTC0(0xbf7a6681), WTC0(0xbf839d81), WTC0(0xbf8cd481), WTC0(0xbf960b01), WTC0(0xbf9f4181), WTC0(0xbfa87901), WTC0(0xbfb1b101), + WTC0(0xbfbae981), WTC0(0xbfc42201), WTC0(0xbfcd5a01), WTC0(0xbfd69101), WTC0(0xbfdfc781), WTC0(0xbfe8fc01), WTC0(0xbff22f81), WTC0(0xbffb6081), + /* part 1 */ + WTC1(0x80093e01), WTC1(0x801b9b01), WTC1(0x802df701), WTC1(0x80405101), WTC1(0x8052a881), WTC1(0x8064fc81), WTC1(0x80774c81), WTC1(0x80899881), + WTC1(0x809bdf01), WTC1(0x80ae1f81), WTC1(0x80c05a01), WTC1(0x80d28d81), WTC1(0x80e4bb81), WTC1(0x80f6e481), WTC1(0x81090981), WTC1(0x811b2981), + WTC1(0x812d4481), WTC1(0x813f5981), WTC1(0x81516701), WTC1(0x81636d81), WTC1(0x81756d81), WTC1(0x81876781), WTC1(0x81995c01), WTC1(0x81ab4b01), + WTC1(0x81bd3401), WTC1(0x81cf1581), WTC1(0x81e0ee81), WTC1(0x81f2bf81), WTC1(0x82048881), WTC1(0x82164a81), WTC1(0x82280581), WTC1(0x8239b981), + WTC1(0x824b6601), WTC1(0x825d0901), WTC1(0x826ea201), WTC1(0x82803101), WTC1(0x8291b601), WTC1(0x82a33281), WTC1(0x82b4a601), WTC1(0x82c61101), + WTC1(0x82d77201), WTC1(0x82e8c801), WTC1(0x82fa1181), WTC1(0x830b4f81), WTC1(0x831c8101), WTC1(0x832da781), WTC1(0x833ec381), WTC1(0x834fd481), + WTC1(0x8360d901), WTC1(0x8371d081), WTC1(0x8382ba01), WTC1(0x83939501), WTC1(0x83a46181), WTC1(0x83b52101), WTC1(0x83c5d381), WTC1(0x83d67881), + WTC1(0x83e70f01), WTC1(0x83f79681), WTC1(0x84080d81), WTC1(0x84187401), WTC1(0x8428ca01), WTC1(0x84391081), WTC1(0x84494881), WTC1(0x84597081), + WTC1(0x84698881), WTC1(0x84798f81), WTC1(0x84898481), WTC1(0x84996701), WTC1(0x84a93801), WTC1(0x84b8f801), WTC1(0x84c8a701), WTC1(0x84d84601), + WTC1(0x84e7d381), WTC1(0x84f74e01), WTC1(0x8506b581), WTC1(0x85160981), WTC1(0x85254a81), WTC1(0x85347901), WTC1(0x85439601), WTC1(0x8552a181), + WTC1(0x85619a01), WTC1(0x85707f81), WTC1(0x857f5101), WTC1(0x858e0e01), WTC1(0x859cb781), WTC1(0x85ab4f01), WTC1(0x85b9d481), WTC1(0x85c84801), + WTC1(0x85d6a981), WTC1(0x85e4f801), WTC1(0x85f33281), WTC1(0x86015981), WTC1(0x860f6e01), WTC1(0x861d7081), WTC1(0x862b6201), WTC1(0x86394301), + WTC1(0x86471281), WTC1(0x8654d001), WTC1(0x86627b01), WTC1(0x86701381), WTC1(0x867d9a81), WTC1(0x868b1001), WTC1(0x86987581), WTC1(0x86a5ca81), + WTC1(0x86b30f01), WTC1(0x86c04381), WTC1(0x86cd6681), WTC1(0x86da7901), WTC1(0x86e77b81), WTC1(0x86f46d81), WTC1(0x87014f81), WTC1(0x870e2301), + WTC1(0x871ae981), WTC1(0x8727a381), WTC1(0x87345381), WTC1(0x8740f681), WTC1(0x874d8681), WTC1(0x8759fd01), WTC1(0x87665481), WTC1(0x87729701), + WTC1(0x877ede01), WTC1(0x878b4301), WTC1(0x8797dd81), WTC1(0x87a48b01), WTC1(0x87b0ef01), WTC1(0x87bcab81), WTC1(0x87c76201), WTC1(0x87d0ca81), + WTC1(0x87fdd781), WTC1(0x881dd301), WTC1(0x88423301), WTC1(0x886a8a81), WTC1(0x88962981), WTC1(0x88c45e81), WTC1(0x88f47901), WTC1(0x8925f101), + WTC1(0x89586901), WTC1(0x898b8301), WTC1(0x89bee581), WTC1(0x89f26101), WTC1(0x8a25f301), WTC1(0x8a599a81), WTC1(0x8a8d5801), WTC1(0x8ac13381), + WTC1(0x8af53e81), WTC1(0x8b298b81), WTC1(0x8b5e2c81), WTC1(0x8b933001), WTC1(0x8bc8a401), WTC1(0x8bfe9401), WTC1(0x8c350d01), WTC1(0x8c6c1b01), + WTC1(0x8ca3cb01), WTC1(0x8cdc2901), WTC1(0x8d154081), WTC1(0x8d4f1b01), WTC1(0x8d89be81), WTC1(0x8dc53001), WTC1(0x8e017581), WTC1(0x8e3e9481), + WTC1(0x8e7c9301), WTC1(0x8ebb7581), WTC1(0x8efb4181), WTC1(0x8f3bfb01), WTC1(0x8f7da401), WTC1(0x8fc03f01), WTC1(0x9003ce81), WTC1(0x90485401), + WTC1(0x908dd101), WTC1(0x90d44781), WTC1(0x911bb981), WTC1(0x91642781), WTC1(0x91ad9281), WTC1(0x91f7f981), WTC1(0x92435d01), WTC1(0x928fbe01), + WTC1(0x92dd1b01), WTC1(0x932b7501), WTC1(0x937acb01), WTC1(0x93cb1c81), WTC1(0x941c6901), WTC1(0x946eaf81), WTC1(0x94c1ee01), WTC1(0x95162381), + WTC1(0x956b4f81), WTC1(0x95c17081), WTC1(0x96188501), WTC1(0x96708b81), WTC1(0x96c98381), WTC1(0x97236b01), WTC1(0x977e4181), WTC1(0x97da0481), + WTC1(0x9836b201), WTC1(0x98944901), WTC1(0x98f2c601), WTC1(0x99522801), WTC1(0x99b26c81), WTC1(0x9a139101), WTC1(0x9a759301), WTC1(0x9ad87081), + WTC1(0x9b3c2801), WTC1(0x9ba0b701), WTC1(0x9c061b81), WTC1(0x9c6c5481), WTC1(0x9cd35f81), WTC1(0x9d3b3b81), WTC1(0x9da3e601), WTC1(0x9e0d5e01), + WTC1(0x9e779f81), WTC1(0x9ee2a901), WTC1(0x9f4e7801), WTC1(0x9fbb0981), WTC1(0xa0285d81), WTC1(0xa0967201), WTC1(0xa1054701), WTC1(0xa174da81), + WTC1(0xa1e52a81), WTC1(0xa2563501), WTC1(0xa2c7f801), WTC1(0xa33a7201), WTC1(0xa3ada281), WTC1(0xa4218801), WTC1(0xa4962181), WTC1(0xa50b6e81), + WTC1(0xa5816e81), WTC1(0xa5f81f81), WTC1(0xa66f8201), WTC1(0xa6e79401), WTC1(0xa7605601), WTC1(0xa7d9c681), WTC1(0xa853e501), WTC1(0xa8ceb201), + WTC1(0xa94a2c01), WTC1(0xa9c65401), WTC1(0xaa432981), WTC1(0xaac0ad01), WTC1(0xab3edf01), WTC1(0xabbdc001), WTC1(0xac3d5001), WTC1(0xacbd9081), + WTC1(0xad3e8101), WTC1(0xadc02281), WTC1(0xae427481), WTC1(0xaec57801), WTC1(0xaf492f01), WTC1(0xafcd9a81), WTC1(0xb052bc01), WTC1(0xb0d89401), + WTC1(0xb15f2381), WTC1(0xb1e66a01), WTC1(0xb26e6881), WTC1(0xb2f71f01), WTC1(0xb3808d81), WTC1(0xb40ab501), WTC1(0xb4959501), WTC1(0xb5212e81), + WTC1(0x4a6cf67f), WTC1(0x49dffeff), WTC1(0x495265ff), WTC1(0x48c4277f), WTC1(0x4835407f), WTC1(0x47a5aeff), WTC1(0x471570ff), WTC1(0x468484ff), + WTC1(0x45f2eaff), WTC1(0x4560a2ff), WTC1(0x44cdad7f), WTC1(0x443a0c7f), WTC1(0x43a5c07f), WTC1(0x4310caff), WTC1(0x427b2bff), WTC1(0x41e4e3ff), + WTC1(0x414df2ff), WTC1(0x40b6557f), WTC1(0x401e06ff), WTC1(0x3f8503c0), WTC1(0x3eeb4e00), WTC1(0x3e50ebc0), WTC1(0x3db5e680), WTC1(0x3d1a4680), + WTC1(0x3c7e10c0), WTC1(0x3be14cc0), WTC1(0x3b4402c0), WTC1(0x3aa63800), WTC1(0x3a07e840), WTC1(0x39690880), WTC1(0x38c98700), WTC1(0x38295b40), + WTC1(0x37888a80), WTC1(0x36e71d40), WTC1(0x36451d80), WTC1(0x35a29400), WTC1(0x34ff8800), WTC1(0x345c04c0), WTC1(0x33b81940), WTC1(0x3313d200), + WTC1(0x326f3800), WTC1(0x31ca5600), WTC1(0x31253840), WTC1(0x307fe8c0), WTC1(0x2fda6e40), WTC1(0x2f34ce40), WTC1(0x2e8f0e40), WTC1(0x2de92ec0), + WTC1(0x2d432780), WTC1(0x2c9cea40), WTC1(0x2bf66300), WTC1(0x2b4f88c0), WTC1(0x2aa864c0), WTC1(0x2a010240), WTC1(0x29596e40), WTC1(0x28b1ba80), + WTC1(0x2809ff40), WTC1(0x27625b80), WTC1(0x26baf580), WTC1(0x2613e7c0), WTC1(0x256d3dc0), WTC1(0x24c70300), WTC1(0x24214380), WTC1(0x237c0800), + WTC1(0x22d75400), WTC1(0x22332a80), WTC1(0x218f8cc0), WTC1(0x20ec7e40), WTC1(0x204a04c0), WTC1(0x1fa82540), WTC1(0x1f06e300), WTC1(0x1e664000), + WTC1(0x1dc63bc0), WTC1(0x1d26d3c0), WTC1(0x1c8803a0), WTC1(0x1be9cc40), WTC1(0x1b4c34c0), WTC1(0x1aaf4480), WTC1(0x1a130260), WTC1(0x197774a0), + WTC1(0x18dca260), WTC1(0x184294e0), WTC1(0x17a95840), WTC1(0x1710fd80), WTC1(0x16799ce0), WTC1(0x15e35340), WTC1(0x154e41a0), WTC1(0x14ba8360), + WTC1(0x14282be0), WTC1(0x13975100), WTC1(0x13080aa0), WTC1(0x127a6240), WTC1(0x11ee50a0), WTC1(0x1163cc80), WTC1(0x10dacb20), WTC1(0x105333a0), + WTC1(0x0fccdb30), WTC1(0x0f478f40), WTC1(0x0ec31700), WTC1(0x0e3f4e80), WTC1(0x0dbc27f0), WTC1(0x0d399000), WTC1(0x0cb76d00), WTC1(0x0c359d50), + WTC1(0x0bb3fd50), WTC1(0x0b326bd0), WTC1(0x0ab0ca80), WTC1(0x0a2f0dc0), WTC1(0x09ad40c0), WTC1(0x092b7a90), WTC1(0x08a9db80), WTC1(0x08285c80), + WTC1(0x07a6c7b8), WTC1(0x0724e4e0), WTC1(0x06a27b80), WTC1(0x061f52f8), WTC1(0x059b2ad0), WTC1(0x0515b568), WTC1(0x048ea058), WTC1(0x04066408), + WTC1(0x037e52d8), WTC1(0x02f7d3c8), WTC1(0x0274614c), WTC1(0x01f63008), WTC1(0x0180403a), WTC1(0x0115c442), WTC1(0x00ba09e2), WTC1(0x006f077c), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + /* part 2 */ + WTC2(0xfff36be1), WTC2(0xffdafbc1), WTC2(0xffc28035), WTC2(0xffa9fe8a), WTC2(0xff917c08), WTC2(0xff78fdfc), WTC2(0xff6089af), WTC2(0xff48246c), + WTC2(0xff2fd37f), WTC2(0xff179c31), WTC2(0xfeff83b6), WTC2(0xfee78d18), WTC2(0xfecfb93e), WTC2(0xfeb808f2), WTC2(0xfea07d06), WTC2(0xfe8916b4), + WTC2(0xfe71d7a0), WTC2(0xfe5ac174), WTC2(0xfe43d5d6), WTC2(0xfe2d167e), WTC2(0xfe16852e), WTC2(0xfe0023a6), WTC2(0xfde9f3f8), WTC2(0xfdd3ff7c), + WTC2(0xfdbe56c0), WTC2(0xfda90aa8), WTC2(0xfd942b78), WTC2(0xfd7fbb20), WTC2(0xfd6bad50), WTC2(0xfd57f510), WTC2(0xfd44857c), WTC2(0xfd3153fc), + WTC2(0xfd1e5840), WTC2(0xfd0b8a0c), WTC2(0xfcf8e180), WTC2(0xfce65eec), WTC2(0xfcd40ad0), WTC2(0xfcc1ee0c), WTC2(0xfcb011e8), WTC2(0xfc9e896c), + WTC2(0xfc8d716c), WTC2(0xfc7ce720), WTC2(0xfc6d072c), WTC2(0xfc5de09c), WTC2(0xfc4f74e8), WTC2(0xfc41c4e8), WTC2(0xfc34d0dc), WTC2(0xfc288a68), + WTC2(0xfc1cd49c), WTC2(0xfc1191e0), WTC2(0xfc06a4d0), WTC2(0xfbfbf3e8), WTC2(0xfbf16990), WTC2(0xfbe6f068), WTC2(0xfbdc7428), WTC2(0xfbd1fc68), + WTC2(0xfbc7ac50), WTC2(0xfbbda868), WTC2(0xfbb41500), WTC2(0xfbab1438), WTC2(0xfba2c5f8), WTC2(0xfb9b4a00), WTC2(0xfb94bfa8), WTC2(0xfb8f3b48), + WTC2(0xfb8ac638), WTC2(0xfb876970), WTC2(0xfb852d20), WTC2(0xfb840ae0), WTC2(0xfb83ed60), WTC2(0xfb84bec0), WTC2(0xfb866918), WTC2(0xfb88d4a8), + WTC2(0xfb8be810), WTC2(0xfb8f89d0), WTC2(0xfb93a080), WTC2(0xfb981418), WTC2(0xfb9ccdf0), WTC2(0xfba1b770), WTC2(0xfba6bae0), WTC2(0xfbabd5c0), + WTC2(0xfbb118d8), WTC2(0xfbb695c0), WTC2(0xfbbc5e90), WTC2(0xfbc29030), WTC2(0xfbc95268), WTC2(0xfbd0cd78), WTC2(0xfbd929c8), WTC2(0xfbe294d0), + WTC2(0xfbed4108), WTC2(0xfbf96118), WTC2(0xfc0726c8), WTC2(0xfc16b064), WTC2(0xfc280890), WTC2(0xfc3b3920), WTC2(0xfc504a98), WTC2(0xfc67271c), + WTC2(0xfc7f9a74), WTC2(0xfc996f18), WTC2(0xfcb46eb8), WTC2(0xfcd050b0), WTC2(0xfcecba24), WTC2(0xfd094f64), WTC2(0xfd25b720), WTC2(0xfd41ce40), + WTC2(0xfd5da7f8), WTC2(0xfd7959d8), WTC2(0xfd94fb74), WTC2(0xfdb0d3fc), WTC2(0xfdcd5a34), WTC2(0xfdeb06e4), WTC2(0xfe0a5184), WTC2(0xfe2b92c4), + WTC2(0xfe4f0486), WTC2(0xfe74df54), WTC2(0xfe9d5886), WTC2(0xfec85b92), WTC2(0xfef58a16), WTC2(0xff248275), WTC2(0xff54e401), WTC2(0xff866330), + WTC2(0xffb8c99b), WTC2(0xffebe1c9), WTC2(0x001f786a), WTC2(0x00538bf9), WTC2(0x00884cbc), WTC2(0x00bded23), WTC2(0x00f49f54), WTC2(0x012c8ee4), + WTC2(0x0165e0d2), WTC2(0x01a0b9d6), WTC2(0x01dd3d80), WTC2(0x021b74d4), WTC2(0x025b4e48), WTC2(0x029cb730), WTC2(0x02df9d0c), WTC2(0x0323f1a4), + WTC2(0x0369ab00), WTC2(0x03b0bf5c), WTC2(0x03f925a0), WTC2(0x0442e3d8), WTC2(0x048e0f40), WTC2(0x04dabdb0), WTC2(0x05290430), WTC2(0x0578e428), + WTC2(0x05ca4b60), WTC2(0x061d26c0), WTC2(0x067163d8), WTC2(0x06c6ff10), WTC2(0x071e03b0), WTC2(0x07767da0), WTC2(0x07d07918), WTC2(0x082c08e0), + WTC2(0x08894660), WTC2(0x08e84b70), WTC2(0x094930b0), WTC2(0x09abf8d0), WTC2(0x0a109020), WTC2(0x0a76e210), WTC2(0x0adeda50), WTC2(0x0b486b80), + WTC2(0x0bb38f00), WTC2(0x0c203e80), WTC2(0x0c8e73e0), WTC2(0x0cfe2c30), WTC2(0x0d6f6820), WTC2(0x0de22850), WTC2(0x0e566d90), WTC2(0x0ecc3dd0), + WTC2(0x0f43a3a0), WTC2(0x0fbca9f0), WTC2(0x10375b80), WTC2(0x10b3be20), WTC2(0x1131d280), WTC2(0x11b19960), WTC2(0x123313a0), WTC2(0x12b64380), + WTC2(0x133b2d00), WTC2(0x13c1d440), WTC2(0x144a3d60), WTC2(0x14d46900), WTC2(0x15605480), WTC2(0x15edfd20), WTC2(0x167d6040), WTC2(0x170e7e80), + WTC2(0x17a15b80), WTC2(0x1835fb00), WTC2(0x18cc60a0), WTC2(0x19648dc0), WTC2(0x19fe80e0), WTC2(0x1a9a38a0), WTC2(0x1b37b3e0), WTC2(0x1bd6f400), + WTC2(0x1c77fd20), WTC2(0x1d1ad400), WTC2(0x1dbf7c80), WTC2(0x1e65f820), WTC2(0x1f0e4540), WTC2(0x1fb861e0), WTC2(0x20644cc0), WTC2(0x21120640), + WTC2(0x21c19240), WTC2(0x2272f480), WTC2(0x23263000), WTC2(0x23db4580), WTC2(0x24923340), WTC2(0x254af700), WTC2(0x26058e80), WTC2(0x26c1fa00), + WTC2(0x27803d00), WTC2(0x28405a40), WTC2(0x29025500), WTC2(0x29c62d40), WTC2(0x2a8be0c0), WTC2(0x2b536cc0), WTC2(0x2c1ccf80), WTC2(0x2ce80840), + WTC2(0x2db519c0), WTC2(0x2e840600), WTC2(0x2f54cf80), WTC2(0x302775c0), WTC2(0x30fbf640), WTC2(0x31d24e00), WTC2(0x32aa7a00), WTC2(0x338479c0), + WTC2(0x34604e40), WTC2(0x353df900), WTC2(0x361d7ac0), WTC2(0x36fed200), WTC2(0x37e1fb40), WTC2(0x38c6f240), WTC2(0x39adb2c0), WTC2(0x3a963a00), + WTC2(0x3b808740), WTC2(0x3c6c9880), WTC2(0x3d5a6cc0), WTC2(0x3e4a0040), WTC2(0x3f3b4bc0), WTC2(0x402e48ff), WTC2(0x4122f17f), WTC2(0x42193f7f), + WTC2(0x43112eff), WTC2(0x440abbff), WTC2(0x4505e2ff), WTC2(0x46029e7f), WTC2(0x4700e9ff), WTC2(0x4800bfff), WTC2(0x49021bff), WTC2(0x4a050eff), + WTC2(0x4b09bc7f), WTC2(0x4c104aff), WTC2(0x4d18df7f), WTC2(0x4e23a07f), WTC2(0x4f30b2ff), WTC2(0x50403c7f), WTC2(0x515262ff), WTC2(0x52674b7f), + WTC2(0x001678b2), WTC2(0x00061a3b), WTC2(0xfffb4622), WTC2(0xfff5ea94), WTC2(0xfff5f5b9), WTC2(0xfffb55bd), WTC2(0x0005f8cb), WTC2(0x0015cd0c), + WTC2(0x002ac0ac), WTC2(0x0044c1d5), WTC2(0x0063beb2), WTC2(0x0087a56d), WTC2(0x00b06431), WTC2(0x00dde929), WTC2(0x01102280), WTC2(0x0146fe5e), + WTC2(0x01826af2), WTC2(0x01c25662), WTC2(0x0206aedc), WTC2(0x024f6288), WTC2(0x029c5f94), WTC2(0x02ed9424), WTC2(0x0342ee6c), WTC2(0x039c5c90), + WTC2(0x03f9ccbc), WTC2(0x045b2d18), WTC2(0x04c06bd8), WTC2(0x05297718), WTC2(0x05963d10), WTC2(0x0606abe8), WTC2(0x067ab1c0), WTC2(0x06f23cd0), + WTC2(0x076d3b40), WTC2(0x07eb9b38), WTC2(0x086d4ae0), WTC2(0x08f23860), WTC2(0x097a51f0), WTC2(0x0a0585b0), WTC2(0x0a93c1d0), WTC2(0x0b24f470), + WTC2(0x0bb90bc0), WTC2(0x0c4ff5f0), WTC2(0x0ce9a130), WTC2(0x0d85fb90), WTC2(0x0e24f360), WTC2(0x0ec676b0), WTC2(0x0f6a73b0), WTC2(0x1010d880), + WTC2(0x10b99360), WTC2(0x11649280), WTC2(0x1211c400), WTC2(0x12c115e0), WTC2(0x137276a0), WTC2(0x1425d420), WTC2(0x14db1ca0), WTC2(0x15923e60), + WTC2(0x164b2780), WTC2(0x1705c620), WTC2(0x17c20860), WTC2(0x187fdca0), WTC2(0x193f30e0), WTC2(0x19fff340), WTC2(0x1ac21200), WTC2(0x1b857b40), + WTC2(0x1c4a1d40), WTC2(0x1d0fe600), WTC2(0x1dd6c3e0), WTC2(0x1e9ea4e0), WTC2(0x1f677740), WTC2(0x20312940), WTC2(0x20fba8c0), WTC2(0x21c6e440), + WTC2(0x2292c9c0), WTC2(0x235f4780), WTC2(0x242c4b80), WTC2(0x24f9c400), WTC2(0x25c79f40), WTC2(0x2695cb40), WTC2(0x27643680), WTC2(0x2832cec0), + WTC2(0x29018240), WTC2(0x29d03f80), WTC2(0x2a9ef480), WTC2(0x2b6d8f00), WTC2(0x2c3bfdc0), WTC2(0x2d0a2ec0), WTC2(0x2dd81000), WTC2(0x2ea58fc0), + WTC2(0x2f729c40), WTC2(0x303f2380), WTC2(0x310b1400), WTC2(0x31d65b80), WTC2(0x32a0e840), WTC2(0x336aa8c0), WTC2(0x34338ac0), WTC2(0x34fb7cc0), + WTC2(0x35c26cc0), WTC2(0x36884900), WTC2(0x374cff80), WTC2(0x38107e80), WTC2(0x38d2b440), WTC2(0x39938ec0), WTC2(0x3a52fc40), WTC2(0x3b10eb00), + WTC2(0x3bcd4900), WTC2(0x3c880480), WTC2(0x3d410bc0), WTC2(0x3df84d00), WTC2(0x3eadb600), WTC2(0x3f613540), WTC2(0x4012b8ff), WTC2(0x40c22eff), + WTC2(0x416f85ff), WTC2(0x421aab7f), WTC2(0x42c38e7f), WTC2(0x436a1c7f), WTC2(0x440e437f), WTC2(0x44aff27f), WTC2(0x454f167f), WTC2(0x45eb9eff), + WTC2(0x468578ff), WTC2(0x471c937f), WTC2(0x47b0dc7f), WTC2(0x484241ff), WTC2(0x48d0b1ff), WTC2(0x495c1a7f), WTC2(0x49e46a7f), WTC2(0x4a698f7f), + WTC2(0x4aeb77ff), WTC2(0x4b6a11ff), WTC2(0x4be54b7f), WTC2(0x4c5d12ff), WTC2(0x4cd155ff), WTC2(0x4d4203ff), WTC2(0x4daf09ff), WTC2(0x4e18567f), + WTC2(0x4e7dd77f), WTC2(0x4edf7b7f), WTC2(0x4f3d307f), WTC2(0x4f96e47f), WTC2(0x4fec85ff), WTC2(0x503e02ff), WTC2(0x508b497f), WTC2(0x50d447ff), + WTC2(0x5118ec7f), WTC2(0x515924ff), WTC2(0x5194dfff), WTC2(0x51cc0b7f), WTC2(0x51fe95ff), WTC2(0x522c6cff), WTC2(0x52557eff), WTC2(0x5279b9ff), + WTC2(0x52990c7f), WTC2(0x52b364ff), WTC2(0x52c8b07f), WTC2(0x52d8ddff), WTC2(0x52e3db7f), WTC2(0x52e996ff), WTC2(0x52e9ff7f), WTC2(0x52e501ff), + WTC2(0x52da8cff), WTC2(0x52ca8f7f), WTC2(0x52b4f67f), WTC2(0x5299b07f), WTC2(0x5278ac7f), WTC2(0x5251d77f), WTC2(0x52251fff), WTC2(0x51f274ff), + WTC2(0x51b9c37f), WTC2(0x517af9ff), WTC2(0x5136077f), WTC2(0x50ead8ff), WTC2(0x50995cff), WTC2(0x504181ff), WTC2(0x4fe335ff), WTC2(0x4f7e677f), + WTC2(0x4f1303ff), WTC2(0x4ea0f9ff), WTC2(0x4e2837ff), WTC2(0x4da8ab7f), WTC2(0x4d2242ff), WTC2(0x4c94ecff), WTC2(0x4c0096ff), WTC2(0x4b652f7f), + WTC2(0x4ac2a4ff), WTC2(0x4a18e4ff), WTC2(0x4967ddff), WTC2(0x48af7e7f), WTC2(0x47efb3ff), WTC2(0x47286cff), WTC2(0x4659ad7f), WTC2(0x45856f7f), + WTC2(0x44afa3ff), WTC2(0x43dc507f), WTC2(0x430f657f), WTC2(0x424ad47f), WTC2(0x418e927f), WTC2(0x40da7bff), WTC2(0x402e6f7f), WTC2(0x3f8a3100), + WTC2(0x3eed6f40), WTC2(0x3e57d700), WTC2(0x3dc914c0), WTC2(0x3d40cc40), WTC2(0x3cbe98c0), WTC2(0x3c421540), WTC2(0x3bcadbc0), WTC2(0x3b588880), + WTC2(0x3aeab780), WTC2(0x3a810540), WTC2(0x3a1b0e00), WTC2(0x39b86d00), WTC2(0x3958bcc0), WTC2(0x38fb9700), WTC2(0x38a095c0), WTC2(0x38473d80), + WTC2(0x37eeff40), WTC2(0x37974b40), WTC2(0x373f9500), WTC2(0x36e7ae00), WTC2(0x368fc4c0), WTC2(0x36380b80), WTC2(0x35e0b300), WTC2(0x3589c140), + WTC2(0x35331180), WTC2(0x34dc7c80), WTC2(0x3485dc80), WTC2(0x342f1600), WTC2(0x33d81780), WTC2(0x3380d0c0), WTC2(0x33293100), WTC2(0x32d11800), + WTC2(0x32785780), WTC2(0x321ec0c0), WTC2(0x31c42680), WTC2(0x316885c0), WTC2(0x310c0580), WTC2(0x30aecec0), WTC2(0x30510940), WTC2(0x2ff2b8c0), + WTC2(0x2f93bf40), WTC2(0x2f33fc00), WTC2(0x2ed350c0), WTC2(0x2e71ba80), WTC2(0x2e0f5340), WTC2(0x2dac35c0), WTC2(0x2d487c80), WTC2(0x2ce431c0), + WTC2(0x2c7f4fc0), WTC2(0x2c19d080), WTC2(0x2bb3ad80), WTC2(0x2b4ce080), WTC2(0x2ae56340), WTC2(0x2a7d2f80), WTC2(0x2a143f00), WTC2(0x29aa8b40) +}; + +const FIXP_WTB ELDAnalysis480[1440] = { + WTC0(0xfacfbef0), WTC0(0xfab88c18), WTC0(0xfaa0e520), WTC0(0xfa88d110), WTC0(0xfa7056e8), WTC0(0xfa577db0), WTC0(0xfa3e4c70), WTC0(0xfa24ca28), + WTC0(0xfa0afde0), WTC0(0xf9f0eea0), WTC0(0xf9d6a2c8), WTC0(0xf9bc1ab8), WTC0(0xf9a15230), WTC0(0xf9864510), WTC0(0xf96af058), WTC0(0xf94f55c0), + WTC0(0xf93378e0), WTC0(0xf9175d80), WTC0(0xf8fb0468), WTC0(0xf8de68b8), WTC0(0xf8c18438), WTC0(0xf8a450d8), WTC0(0xf886cde8), WTC0(0xf8690148), + WTC0(0xf84af148), WTC0(0xf82ca410), WTC0(0xf80e1e18), WTC0(0xf7ef62a0), WTC0(0xf7d074e0), WTC0(0xf7b15870), WTC0(0xf7921240), WTC0(0xf772a7a0), + WTC0(0xf7531e50), WTC0(0xf7337820), WTC0(0xf713afd0), WTC0(0xf6f3bea0), WTC0(0xf6d39dc0), WTC0(0xf6b352e0), WTC0(0xf692f280), WTC0(0xf6729250), + WTC0(0xf65247a0), WTC0(0xf63224c0), WTC0(0xf6123a00), WTC0(0xf5f297c0), WTC0(0xf5d34dd0), WTC0(0xf5b46b10), WTC0(0xf595fd90), WTC0(0xf5781390), + WTC0(0xf55abba0), WTC0(0xf53e0510), WTC0(0xf521ff70), WTC0(0xf506ba30), WTC0(0xf4ec4330), WTC0(0xf4d2a680), WTC0(0xf4b9efe0), WTC0(0xf4a22ac0), + WTC0(0xf48b5f70), WTC0(0xf4759310), WTC0(0xf460cde0), WTC0(0xf44cfcc0), WTC0(0xf439aff0), WTC0(0xf4264e00), WTC0(0xf4123d90), WTC0(0xf3fd1370), + WTC0(0xf3e6be00), WTC0(0xf3cf41a0), WTC0(0xf3b6a030), WTC0(0xf39cdd60), WTC0(0xf381fe00), WTC0(0xf3660760), WTC0(0xf348fe70), WTC0(0xf32ae820), + WTC0(0xf30bc940), WTC0(0xf2eba690), WTC0(0xf2ca8480), WTC0(0xf2a86670), WTC0(0xf2854f40), WTC0(0xf2614190), WTC0(0xf23c41e0), WTC0(0xf21657a0), + WTC0(0xf1ef8ae0), WTC0(0xf1c7e3e0), WTC0(0xf19f63d0), WTC0(0xf1760450), WTC0(0xf14bbdf0), WTC0(0xf1208960), WTC0(0xf0f45cd0), WTC0(0xf0c72ce0), + WTC0(0xf098ee00), WTC0(0xf06996f0), WTC0(0xf0392620), WTC0(0xf0079e10), WTC0(0xefd4ffc0), WTC0(0xefa15ca0), WTC0(0xef6ce600), WTC0(0xef37d460), + WTC0(0xef025f80), WTC0(0xeecca2c0), WTC0(0xee969760), WTC0(0xee603440), WTC0(0xee296d20), WTC0(0xedf21c00), WTC0(0xedba07e0), WTC0(0xed80f640), + WTC0(0xed46bf40), WTC0(0xed0b7b00), WTC0(0xeccf5fc0), WTC0(0xec92a120), WTC0(0xec556d60), WTC0(0xec17e700), WTC0(0xebda2d40), WTC0(0xeb9c5fa0), + WTC0(0xeb5e7040), WTC0(0xeb201b20), WTC0(0xeae117c0), WTC0(0xeaa12000), WTC0(0xea600180), WTC0(0xea1d9940), WTC0(0xe9d9c160), WTC0(0xe99468a0), + WTC0(0xe94dc040), WTC0(0xe9061940), WTC0(0xe8bdc140), WTC0(0xe8750ae0), WTC0(0xe82c4fa0), WTC0(0xe7e3ea40), WTC0(0xe79c35e0), WTC0(0xe7554ca0), + WTC0(0xe70efc00), WTC0(0xe6c90c20), WTC0(0xe6833f00), WTC0(0xe63d2300), WTC0(0xe5f620a0), WTC0(0xe5ad9dc0), WTC0(0xe5632080), WTC0(0xe5169da0), + WTC0(0xe4c83e60), WTC0(0xe4782400), WTC0(0xe4269840), WTC0(0xe3d42dc0), WTC0(0xe38188c0), WTC0(0xe32f4be0), WTC0(0xe2ddeea0), WTC0(0xe28db520), + WTC0(0xe23ee000), WTC0(0xe1f1a580), WTC0(0xe1a5e3a0), WTC0(0xe15b35a0), WTC0(0xe1113860), WTC0(0xe0c78a00), WTC0(0xe07dd0e0), WTC0(0xe033b7c0), + WTC0(0xdfe8e680), WTC0(0xdf9d1fc0), WTC0(0xdf5055c0), WTC0(0xdf0287c0), WTC0(0xdeb3b340), WTC0(0xde63e7c0), WTC0(0xde134a00), WTC0(0xddc20000), + WTC0(0xdd703180), WTC0(0xdd1e1280), WTC0(0xdccbe080), WTC0(0xdc79d980), WTC0(0xdc283600), WTC0(0xdbd71e00), WTC0(0xdb86b140), WTC0(0xdb3710c0), + WTC0(0xdae850c0), WTC0(0xda9a6bc0), WTC0(0xda4d5640), WTC0(0xda010640), WTC0(0xd9b56640), WTC0(0xd96a5700), WTC0(0xd91fb700), WTC0(0xd8d56600), + WTC0(0xd88b4a40), WTC0(0xd8414f00), WTC0(0xd7f75f80), WTC0(0xd7ad6740), WTC0(0xd76352c0), WTC0(0xd7191040), WTC0(0xd6ce8c80), WTC0(0xd683bd00), + WTC0(0xd638a5c0), WTC0(0xd5ed4f80), WTC0(0xd5a1c240), WTC0(0xd5562b80), WTC0(0xd50ae500), WTC0(0xd4c04c80), WTC0(0xd476bb40), WTC0(0xd42e62c0), + WTC0(0xd3e75680), WTC0(0xd3a1ad00), WTC0(0xd35d6780), WTC0(0xd31a4300), WTC0(0xd2d7dc00), WTC0(0xd295d080), WTC0(0xd253d8c0), WTC0(0xd211df40), + WTC0(0xd1cfdbc0), WTC0(0xd18dc480), WTC0(0xd14b9dc0), WTC0(0xd1097c80), WTC0(0xd0c77700), WTC0(0xd085a500), WTC0(0xd0442f40), WTC0(0xd0034a80), + WTC0(0xcfc32c00), WTC0(0xcf840400), WTC0(0xcf45f400), WTC0(0xcf0913c0), WTC0(0xcecd8000), WTC0(0xce932c80), WTC0(0xce59bf40), WTC0(0xce20cd40), + WTC0(0xcde7ec40), WTC0(0xcdaeedc0), WTC0(0xcd75ea00), WTC0(0xcd3cfec0), WTC0(0xcd044b40), WTC0(0xcccbff00), WTC0(0xcc945480), WTC0(0xcc5d8780), + WTC0(0xcc27c3c0), WTC0(0xcbf2fc40), WTC0(0xcbbf0a00), WTC0(0xcb8bc7c0), WTC0(0xcb591880), WTC0(0xcb26f0c0), WTC0(0xcaf54980), WTC0(0xcac41ac0), + WTC0(0xca936440), WTC0(0xca632d80), WTC0(0xca337f00), WTC0(0xca046180), WTC0(0xc9d5dd40), WTC0(0xc9a7fa80), WTC0(0xc97ac200), WTC0(0xc94e3c00), + WTC0(0xc91d1840), WTC0(0xc8f15980), WTC0(0xc8c52340), WTC0(0xc8988100), WTC0(0xc86b7f00), WTC0(0xc83e28c0), WTC0(0xc8108a80), WTC0(0xc7e2afc0), + WTC0(0xc7b4a480), WTC0(0xc7867480), WTC0(0xc7582b40), WTC0(0xc729cc80), WTC0(0xc6fb5700), WTC0(0xc6ccca40), WTC0(0xc69e2180), WTC0(0xc66f49c0), + WTC0(0xc64029c0), WTC0(0xc610a740), WTC0(0xc5e0bfc0), WTC0(0xc5b09e80), WTC0(0xc5807900), WTC0(0xc5508440), WTC0(0xc520e840), WTC0(0xc4f1bdc0), + WTC0(0xc4c31d00), WTC0(0xc4951780), WTC0(0xc4678a00), WTC0(0xc43a28c0), WTC0(0xc40ca800), WTC0(0xc3deccc0), WTC0(0xc3b09940), WTC0(0xc3822c00), + WTC0(0xc353a0c0), WTC0(0xc3251740), WTC0(0xc2f6b500), WTC0(0xc2c8a140), WTC0(0xc29b02c0), WTC0(0xc26df5c0), WTC0(0xc2418940), WTC0(0xc215cbc0), + WTC0(0xc1eaca00), WTC0(0xc1c08680), WTC0(0xc196fb00), WTC0(0xc16e22c0), WTC0(0xc145f040), WTC0(0xc11e3a80), WTC0(0xc0f6cc00), WTC0(0xc0cf6ec0), + WTC0(0xc0a802c0), WTC0(0xc0809280), WTC0(0xc0593340), WTC0(0xc031f880), WTC0(0xc00b04c0), WTC0(0xbfe48981), WTC0(0xbfbebb81), WTC0(0xbf99cb01), + WTC0(0xbf75cc81), WTC0(0xbf52c101), WTC0(0xbf30a901), WTC0(0xbf0f8301), WTC0(0xbeef4601), WTC0(0xbecfe601), WTC0(0xbeb15701), WTC0(0xbe938c81), + WTC0(0xbe767e81), WTC0(0xbe5a2301), WTC0(0xbe3e7201), WTC0(0xbe236001), WTC0(0xbe08e181), WTC0(0xbdeee981), WTC0(0xbdd56b81), WTC0(0xbdbc6381), + WTC0(0xbda3d081), WTC0(0xbd8bb281), WTC0(0xbd740b81), WTC0(0xbd5ce281), WTC0(0xbd464281), WTC0(0xbd303581), WTC0(0xbd1ac801), WTC0(0xbd060c81), + WTC0(0xbcf21601), WTC0(0xbcdef701), WTC0(0xbcccbd01), WTC0(0xbcbb7001), WTC0(0xbcab1781), WTC0(0xbc9bb901), WTC0(0xbc8d5101), WTC0(0xbc7fd301), + WTC0(0xbc733401), WTC0(0xbc676501), WTC0(0xbc5c4c81), WTC0(0xbc51cb01), WTC0(0xbc47c281), WTC0(0xbc3e1981), WTC0(0xbc34c081), WTC0(0xbc2bab01), + WTC0(0xbc22cd81), WTC0(0xbc1a2401), WTC0(0xbc11b681), WTC0(0xbc098d81), WTC0(0xbc01b381), WTC0(0xbbfa3c01), WTC0(0xbbf34281), WTC0(0xbbece281), + WTC0(0xbbe73201), WTC0(0xbbe23281), WTC0(0xbbdddb01), WTC0(0xbbda2501), WTC0(0xbbd70201), WTC0(0xbbd45601), WTC0(0xbbd20301), WTC0(0xbbcfea81), + WTC0(0xbbce0601), WTC0(0xbbcc6b01), WTC0(0xbbcb3201), WTC0(0xbbca7481), WTC0(0xbbca5d01), WTC0(0xbbcb2281), WTC0(0xbbccfc81), WTC0(0xbbd01301), + WTC0(0xbbd45881), WTC0(0xbbd9a781), WTC0(0xbbdfdb81), WTC0(0xbbe6c801), WTC0(0xbbee2f81), WTC0(0xbbf5d181), WTC0(0xbbfd6c01), WTC0(0xbc04e381), + WTC0(0xbc0c4581), WTC0(0xbc13a481), WTC0(0xbc1b1081), WTC0(0xbc228f01), WTC0(0xbc2a1a81), WTC0(0xbc31af01), WTC0(0xbc394901), WTC0(0xbc40e881), + WTC0(0xbc488e81), WTC0(0xbc503b81), WTC0(0xbc57f101), WTC0(0xbc5fae81), WTC0(0xbc677501), WTC0(0xbc6f4401), WTC0(0xbc771c01), WTC0(0xbc7efc81), + WTC0(0xbc86e581), WTC0(0xbc8ed701), WTC0(0xbc96d101), WTC0(0xbc9ed481), WTC0(0xbca6e101), WTC0(0xbcaef701), WTC0(0xbcb71701), WTC0(0xbcbf4001), + WTC0(0xbcc77181), WTC0(0xbccfac01), WTC0(0xbcd7ef01), WTC0(0xbce03b81), WTC0(0xbce89281), WTC0(0xbcf0f381), WTC0(0xbcf95e81), WTC0(0xbd01d281), + WTC0(0xbd0a4f81), WTC0(0xbd12d581), WTC0(0xbd1b6501), WTC0(0xbd23ff01), WTC0(0xbd2ca281), WTC0(0xbd355081), WTC0(0xbd3e0801), WTC0(0xbd46c801), + WTC0(0xbd4f9101), WTC0(0xbd586281), WTC0(0xbd613d81), WTC0(0xbd6a2201), WTC0(0xbd731081), WTC0(0xbd7c0781), WTC0(0xbd850701), WTC0(0xbd8e0e01), + WTC0(0xbd971c81), WTC0(0xbda03381), WTC0(0xbda95301), WTC0(0xbdb27b01), WTC0(0xbdbbab01), WTC0(0xbdc4e301), WTC0(0xbdce2181), WTC0(0xbdd76701), + WTC0(0xbde0b301), WTC0(0xbdea0681), WTC0(0xbdf36101), WTC0(0xbdfcc301), WTC0(0xbe062b81), WTC0(0xbe0f9a01), WTC0(0xbe190d81), WTC0(0xbe228681), + WTC0(0xbe2c0501), WTC0(0xbe358901), WTC0(0xbe3f1381), WTC0(0xbe48a301), WTC0(0xbe523781), WTC0(0xbe5bd001), WTC0(0xbe656c01), WTC0(0xbe6f0c01), + WTC0(0xbe78b001), WTC0(0xbe825801), WTC0(0xbe8c0501), WTC0(0xbe95b581), WTC0(0xbe9f6901), WTC0(0xbea91f01), WTC0(0xbeb2d681), WTC0(0xbebc9181), + WTC0(0xbec64e81), WTC0(0xbed00f81), WTC0(0xbed9d281), WTC0(0xbee39801), WTC0(0xbeed5f01), WTC0(0xbef72681), WTC0(0xbf00ef81), WTC0(0xbf0aba01), + WTC0(0xbf148681), WTC0(0xbf1e5501), WTC0(0xbf282501), WTC0(0xbf31f501), WTC0(0xbf3bc601), WTC0(0xbf459681), WTC0(0xbf4f6801), WTC0(0xbf593a01), + WTC0(0xbf630d81), WTC0(0xbf6ce201), WTC0(0xbf76b701), WTC0(0xbf808b81), WTC0(0xbf8a5f81), WTC0(0xbf943301), WTC0(0xbf9e0701), WTC0(0xbfa7dc01), + WTC0(0xbfb1b101), WTC0(0xbfbb8701), WTC0(0xbfc55c81), WTC0(0xbfcf3181), WTC0(0xbfd90601), WTC0(0xbfe2d901), WTC0(0xbfecaa81), WTC0(0xbff67a01), + /* part 1 */ + WTC1(0x80130981), WTC1(0x80269f81), WTC1(0x803a3381), WTC1(0x804dc481), WTC1(0x80615281), WTC1(0x8074dc01), WTC1(0x80886081), WTC1(0x809bdf01), + WTC1(0x80af5701), WTC1(0x80c2c781), WTC1(0x80d63101), WTC1(0x80e99401), WTC1(0x80fcf181), WTC1(0x81104a01), WTC1(0x81239d81), WTC1(0x8136ea01), + WTC1(0x814a2f81), WTC1(0x815d6c01), WTC1(0x8170a181), WTC1(0x8183cf81), WTC1(0x8196f781), WTC1(0x81aa1981), WTC1(0x81bd3401), WTC1(0x81d04681), + WTC1(0x81e34f81), WTC1(0x81f64f01), WTC1(0x82094581), WTC1(0x821c3401), WTC1(0x822f1b01), WTC1(0x8241fa01), WTC1(0x8254cf01), WTC1(0x82679901), + WTC1(0x827a5801), WTC1(0x828d0b01), WTC1(0x829fb401), WTC1(0x82b25301), WTC1(0x82c4e801), WTC1(0x82d77201), WTC1(0x82e9ef01), WTC1(0x82fc5f01), + WTC1(0x830ec081), WTC1(0x83211501), WTC1(0x83335c81), WTC1(0x83459881), WTC1(0x8357c701), WTC1(0x8369e781), WTC1(0x837bf801), WTC1(0x838df801), + WTC1(0x839fe801), WTC1(0x83b1c881), WTC1(0x83c39a81), WTC1(0x83d55d01), WTC1(0x83e70f01), WTC1(0x83f8b001), WTC1(0x840a3e81), WTC1(0x841bb981), + WTC1(0x842d2281), WTC1(0x843e7a81), WTC1(0x844fc081), WTC1(0x8460f581), WTC1(0x84721701), WTC1(0x84832481), WTC1(0x84941d81), WTC1(0x84a50201), + WTC1(0x84b5d301), WTC1(0x84c69101), WTC1(0x84d73c01), WTC1(0x84e7d381), WTC1(0x84f85581), WTC1(0x8508c181), WTC1(0x85191801), WTC1(0x85295881), + WTC1(0x85398481), WTC1(0x85499d01), WTC1(0x8559a081), WTC1(0x85698e81), WTC1(0x85796601), WTC1(0x85892681), WTC1(0x8598d081), WTC1(0x85a86581), + WTC1(0x85b7e601), WTC1(0x85c75201), WTC1(0x85d6a981), WTC1(0x85e5eb81), WTC1(0x85f51681), WTC1(0x86042c01), WTC1(0x86132c01), WTC1(0x86221801), + WTC1(0x8630f181), WTC1(0x863fb701), WTC1(0x864e6901), WTC1(0x865d0581), WTC1(0x866b8d81), WTC1(0x867a0081), WTC1(0x86886001), WTC1(0x8696ad01), + WTC1(0x86a4e781), WTC1(0x86b30f01), WTC1(0x86c12401), WTC1(0x86cf2601), WTC1(0x86dd1481), WTC1(0x86eaf081), WTC1(0x86f8ba81), WTC1(0x87067281), + WTC1(0x87141b01), WTC1(0x8721b481), WTC1(0x872f4201), WTC1(0x873cc201), WTC1(0x874a2f01), WTC1(0x87578181), WTC1(0x8764b101), WTC1(0x8771c601), + WTC1(0x877ede01), WTC1(0x878c1881), WTC1(0x87998f01), WTC1(0x87a70e81), WTC1(0x87b42481), WTC1(0x87c05e81), WTC1(0x87cb5101), WTC1(0x87d4ac81), + WTC1(0x87e73d81), WTC1(0x88124281), WTC1(0x88353501), WTC1(0x885f8481), WTC1(0x888d3181), WTC1(0x88be1681), WTC1(0x88f13801), WTC1(0x8925f101), + WTC1(0x895bcd01), WTC1(0x89925a81), WTC1(0x89c92f81), WTC1(0x8a001f01), WTC1(0x8a372881), WTC1(0x8a6e4a01), WTC1(0x8aa58681), WTC1(0x8adcee01), + WTC1(0x8b149701), WTC1(0x8b4c9701), WTC1(0x8b850281), WTC1(0x8bbde981), WTC1(0x8bf75b01), WTC1(0x8c316681), WTC1(0x8c6c1b01), WTC1(0x8ca78781), + WTC1(0x8ce3ba81), WTC1(0x8d20c301), WTC1(0x8d5eaa01), WTC1(0x8d9d7781), WTC1(0x8ddd3201), WTC1(0x8e1de001), WTC1(0x8e5f8881), WTC1(0x8ea23201), + WTC1(0x8ee5e301), WTC1(0x8f2aa101), WTC1(0x8f706f01), WTC1(0x8fb74f81), WTC1(0x8fff4601), WTC1(0x90485401), WTC1(0x90927b81), WTC1(0x90ddc001), + WTC1(0x912a2201), WTC1(0x9177a301), WTC1(0x91c64301), WTC1(0x92160301), WTC1(0x9266e281), WTC1(0x92b8e101), WTC1(0x930bff81), WTC1(0x93603d01), + WTC1(0x93b59901), WTC1(0x940c1281), WTC1(0x9463a881), WTC1(0x94bc5981), WTC1(0x95162381), WTC1(0x95710601), WTC1(0x95ccff01), WTC1(0x962a0c81), + WTC1(0x96882e01), WTC1(0x96e76101), WTC1(0x9747a481), WTC1(0x97a8f681), WTC1(0x980b5501), WTC1(0x986ebd81), WTC1(0x98d32d81), WTC1(0x9938a281), + WTC1(0x999f1981), WTC1(0x9a069001), WTC1(0x9a6f0381), WTC1(0x9ad87081), WTC1(0x9b42d581), WTC1(0x9bae2f81), WTC1(0x9c1a7c81), WTC1(0x9c87ba81), + WTC1(0x9cf5e701), WTC1(0x9d650081), WTC1(0x9dd50481), WTC1(0x9e45f081), WTC1(0x9eb7c101), WTC1(0x9f2a7281), WTC1(0x9f9e0301), WTC1(0xa0127081), + WTC1(0xa087b981), WTC1(0xa0fddd81), WTC1(0xa174da81), WTC1(0xa1ecae01), WTC1(0xa2655581), WTC1(0xa2dece81), WTC1(0xa3591801), WTC1(0xa3d43001), + WTC1(0xa4501601), WTC1(0xa4ccc901), WTC1(0xa54a4701), WTC1(0xa5c89001), WTC1(0xa647a301), WTC1(0xa6c77e01), WTC1(0xa7482101), WTC1(0xa7c98b01), + WTC1(0xa84bbb81), WTC1(0xa8ceb201), WTC1(0xa9526d81), WTC1(0xa9d6ef01), WTC1(0xaa5c3601), WTC1(0xaae24301), WTC1(0xab691681), WTC1(0xabf0b181), + WTC1(0xac791401), WTC1(0xad023f01), WTC1(0xad8c3301), WTC1(0xae16f001), WTC1(0xaea27681), WTC1(0xaf2ec901), WTC1(0xafbbe801), WTC1(0xb049d601), + WTC1(0xb0d89401), WTC1(0xb1682281), WTC1(0xb1f88181), WTC1(0xb289b181), WTC1(0xb31bb301), WTC1(0xb3ae8601), WTC1(0xb4422b81), WTC1(0xb4d6a381), + WTC1(0x4a5a327f), WTC1(0x49c4adff), WTC1(0x492e637f), WTC1(0x48974f7f), WTC1(0x47ff6d7f), WTC1(0x4766baff), WTC1(0x46cd35ff), WTC1(0x4632dd7f), + WTC1(0x4597b0ff), WTC1(0x44fbb1ff), WTC1(0x445eeaff), WTC1(0x43c165ff), WTC1(0x4323227f), WTC1(0x4284277f), WTC1(0x41e48aff), WTC1(0x4144557f), + WTC1(0x40a3867f), WTC1(0x4001f5ff), WTC1(0x3f5f5d80), WTC1(0x3ebbad00), WTC1(0x3e16ee40), WTC1(0x3d713d00), WTC1(0x3ccab700), WTC1(0x3c236500), + WTC1(0x3b7b5800), WTC1(0x3ad2ecc0), WTC1(0x3a2a6540), WTC1(0x3981b7c0), WTC1(0x38d8ba00), WTC1(0x382f01c0), WTC1(0x37846240), WTC1(0x36d8eb00), + WTC1(0x362c9ec0), WTC1(0x357f7a00), WTC1(0x34d18340), WTC1(0x3422c900), WTC1(0x33736c40), WTC1(0x32c39040), WTC1(0x32134280), WTC1(0x31629280), + WTC1(0x30b1a000), WTC1(0x30008380), WTC1(0x2f4f4240), WTC1(0x2e9df180), WTC1(0x2decc780), WTC1(0x2d3bd640), WTC1(0x2c8b0cc0), WTC1(0x2bda3080), + WTC1(0x2b28ec80), WTC1(0x2a773500), WTC1(0x29c51b40), WTC1(0x291293c0), WTC1(0x285f9280), WTC1(0x27ac35c0), WTC1(0x26f8ab40), WTC1(0x26454c00), + WTC1(0x25925600), WTC1(0x24dfd580), WTC1(0x242ddd40), WTC1(0x237c87c0), WTC1(0x22cbe240), WTC1(0x221bef40), WTC1(0x216cb040), WTC1(0x20be2800), + WTC1(0x20105c80), WTC1(0x1f6352a0), WTC1(0x1eb71240), WTC1(0x1e0ba140), WTC1(0x1d60fe40), WTC1(0x1cb723e0), WTC1(0x1c0e0300), WTC1(0x1b6596c0), + WTC1(0x1abde8a0), WTC1(0x1a16fbe0), WTC1(0x1970c680), WTC1(0x18cb4840), WTC1(0x18268e20), WTC1(0x1782a0c0), WTC1(0x16df8960), WTC1(0x163d6300), + WTC1(0x159c52c0), WTC1(0x14fc87e0), WTC1(0x145e2c80), WTC1(0x13c15b60), WTC1(0x13263240), WTC1(0x128cd9a0), WTC1(0x11f562a0), WTC1(0x115fc1c0), + WTC1(0x10cbf160), WTC1(0x1039f200), WTC1(0x0fa9a080), WTC1(0x0f1abd90), WTC1(0x0e8d01d0), WTC1(0x0e003330), WTC1(0x0d743590), WTC1(0x0ce8ef40), + WTC1(0x0c5e1900), WTC1(0x0bd35d70), WTC1(0x0b488eb0), WTC1(0x0abd8410), WTC1(0x0a320a00), WTC1(0x09a60e70), WTC1(0x0919ab00), WTC1(0x088d0de0), + WTC1(0x080065e0), WTC1(0x07739710), WTC1(0x06e65808), WTC1(0x06588348), WTC1(0x05ca0ae0), WTC1(0x053aaaf8), WTC1(0x04a9faf0), WTC1(0x0417f698), + WTC1(0x03859ff4), WTC1(0x02f49be4), WTC1(0x0266b668), WTC1(0x01de554e), WTC1(0x015f50ca), WTC1(0x00eb7e5d), WTC1(0x00904f24), WTC1(0x00212889), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), + /* part 2 */ + WTC2(0xfffece02), WTC2(0xffe4c3df), WTC2(0xffcaaa55), WTC2(0xffb087d1), WTC2(0xff9662bf), WTC2(0xff7c418b), WTC2(0xff622aa0), WTC2(0xff48246c), + WTC2(0xff2e355a), WTC2(0xff1463db), WTC2(0xfefab608), WTC2(0xfee12f0a), WTC2(0xfec7cfd2), WTC2(0xfeae995a), WTC2(0xfe958cc4), WTC2(0xfe7cabce), + WTC2(0xfe63f882), WTC2(0xfe4b74e0), WTC2(0xfe3322f6), WTC2(0xfe1b04dc), WTC2(0xfe031ccc), WTC2(0xfdeb6cf0), WTC2(0xfdd3ff7c), WTC2(0xfdbce834), + WTC2(0xfda63bb8), WTC2(0xfd900c68), WTC2(0xfd7a590c), WTC2(0xfd6511b4), WTC2(0xfd5026c0), WTC2(0xfd3b8954), WTC2(0xfd272df0), WTC2(0xfd130adc), + WTC2(0xfcff15ac), WTC2(0xfceb4a68), WTC2(0xfcd7b110), WTC2(0xfcc454d0), WTC2(0xfcb14064), WTC2(0xfc9e896c), WTC2(0xfc8c5264), WTC2(0xfc7abef0), + WTC2(0xfc69f078), WTC2(0xfc59f5e8), WTC2(0xfc4acfec), WTC2(0xfc3c8060), WTC2(0xfc2f0264), WTC2(0xfc223b7c), WTC2(0xfc160714), WTC2(0xfc0a4150), + WTC2(0xfbfec920), WTC2(0xfbf38320), WTC2(0xfbe855d0), WTC2(0xfbdd2740), WTC2(0xfbd1fc68), WTC2(0xfbc6fea0), WTC2(0xfbbc5a48), WTC2(0xfbb23b48), + WTC2(0xfba8ca78), WTC2(0xfba02e50), WTC2(0xfb988de0), WTC2(0xfb920b40), WTC2(0xfb8cb870), WTC2(0xfb889f68), WTC2(0xfb85cbe8), WTC2(0xfb843dd0), + WTC2(0xfb83df78), WTC2(0xfb8495d0), WTC2(0xfb864660), WTC2(0xfb88d4a8), WTC2(0xfb8c21e8), WTC2(0xfb900f28), WTC2(0xfb947dc0), WTC2(0xfb9950c0), + WTC2(0xfb9e6d08), WTC2(0xfba3b658), WTC2(0xfba91908), WTC2(0xfbae9e08), WTC2(0xfbb45bd0), WTC2(0xfbba66f8), WTC2(0xfbc0dcf0), WTC2(0xfbc7ead8), + WTC2(0xfbcfc200), WTC2(0xfbd89330), WTC2(0xfbe294d0), WTC2(0xfbee03d0), WTC2(0xfbfb1de8), WTC2(0xfc0a1da4), WTC2(0xfc1b22e0), WTC2(0xfc2e38f0), + WTC2(0xfc436d48), WTC2(0xfc5abf7c), WTC2(0xfc74024c), WTC2(0xfc8ef2e8), WTC2(0xfcab51ac), WTC2(0xfcc8d024), WTC2(0xfce704f0), WTC2(0xfd0580cc), + WTC2(0xfd23d4d0), WTC2(0xfd41ce40), WTC2(0xfd5f81b0), WTC2(0xfd7d08f0), WTC2(0xfd9a8560), WTC2(0xfdb85938), WTC2(0xfdd71798), WTC2(0xfdf753b8), + WTC2(0xfe1993ee), WTC2(0xfe3e30f8), WTC2(0xfe656cba), WTC2(0xfe8f8fdc), WTC2(0xfebca8a4), WTC2(0xfeec590e), WTC2(0xff1e285c), WTC2(0xff51a0b7), + WTC2(0xff866330), WTC2(0xffbc2cbb), WTC2(0xfff2bbff), WTC2(0x0029d79d), WTC2(0x00618a22), WTC2(0x009a1185), WTC2(0x00d3aa8c), WTC2(0x010e8ff6), + WTC2(0x014af29e), WTC2(0x0188fe56), WTC2(0x01c8e108), WTC2(0x020ab3c4), WTC2(0x024e68a8), WTC2(0x0293e824), WTC2(0x02db1bc8), WTC2(0x0323f1a4), + WTC2(0x036e5d6c), WTC2(0x03ba5320), WTC2(0x0407c938), WTC2(0x0456cad0), WTC2(0x04a77288), WTC2(0x04f9db88), WTC2(0x054e1888), WTC2(0x05a41ef0), + WTC2(0x05fbd6e0), WTC2(0x065528c0), WTC2(0x06b00838), WTC2(0x070c7ee0), WTC2(0x076a9bb0), WTC2(0x07ca6d10), WTC2(0x082c08e0), WTC2(0x088f8da0), + WTC2(0x08f51ac0), WTC2(0x095ccc20), WTC2(0x09c69f70), WTC2(0x0a327b40), WTC2(0x0aa046d0), WTC2(0x0b0febb0), WTC2(0x0b815dd0), WTC2(0x0bf49600), + WTC2(0x0c698c50), WTC2(0x0ce03ba0), WTC2(0x0d58a380), WTC2(0x0dd2c510), WTC2(0x0e4ea110), WTC2(0x0ecc3dd0), WTC2(0x0f4ba800), WTC2(0x0fcced10), + WTC2(0x10501960), WTC2(0x10d532a0), WTC2(0x115c39c0), WTC2(0x11e52fa0), WTC2(0x12701560), WTC2(0x12fcef20), WTC2(0x138bc200), WTC2(0x141c9300), + WTC2(0x14af64a0), WTC2(0x154434e0), WTC2(0x15db0020), WTC2(0x1673c360), WTC2(0x170e7e80), WTC2(0x17ab35e0), WTC2(0x1849ee40), WTC2(0x18eaaba0), + WTC2(0x198d6f00), WTC2(0x1a3236a0), WTC2(0x1ad90080), WTC2(0x1b81cc60), WTC2(0x1c2c9da0), WTC2(0x1cd97980), WTC2(0x1d8865c0), WTC2(0x1e396540), + WTC2(0x1eec7700), WTC2(0x1fa198c0), WTC2(0x2058c840), WTC2(0x21120640), WTC2(0x21cd5700), WTC2(0x228abec0), WTC2(0x234a4180), WTC2(0x240bdf80), + WTC2(0x24cf95c0), WTC2(0x259561c0), WTC2(0x265d4200), WTC2(0x27273840), WTC2(0x27f348c0), WTC2(0x28c17700), WTC2(0x2991c500), WTC2(0x2a643080), + WTC2(0x2b38b680), WTC2(0x2c0f53c0), WTC2(0x2ce80840), WTC2(0x2dc2d680), WTC2(0x2e9fc100), WTC2(0x2f7ecac0), WTC2(0x305ff280), WTC2(0x314334c0), + WTC2(0x32288e00), WTC2(0x330ffb80), WTC2(0x33f97d80), WTC2(0x34e515c0), WTC2(0x35d2c5c0), WTC2(0x36c28d00), WTC2(0x37b467c0), WTC2(0x38a85080), + WTC2(0x399e4240), WTC2(0x3a963a00), WTC2(0x3b903600), WTC2(0x3c8c3480), WTC2(0x3d8a3380), WTC2(0x3e8a2dc0), WTC2(0x3f8c1b40), WTC2(0x408ff2ff), + WTC2(0x4195ae7f), WTC2(0x429d477f), WTC2(0x43a6b87f), WTC2(0x44b1fdff), WTC2(0x45bf11ff), WTC2(0x46cdee7f), WTC2(0x47de8cff), WTC2(0x48f0e77f), + WTC2(0x4a050eff), WTC2(0x4b1b2dff), WTC2(0x4c3372ff), WTC2(0x4d4e0bff), WTC2(0x4e6b257f), WTC2(0x4f8aedff), WTC2(0x50ad92ff), WTC2(0x51d341ff), + WTC2(0x002006a9), WTC2(0x000bfb36), WTC2(0xfffe45ac), WTC2(0xfff6d064), WTC2(0xfff585bc), WTC2(0xfffa500d), WTC2(0x000519b4), WTC2(0x0015cd0c), + WTC2(0x002c5470), WTC2(0x00489a3b), WTC2(0x006a88c8), WTC2(0x00920a74), WTC2(0x00bf0999), WTC2(0x00f17092), WTC2(0x012929bc), WTC2(0x01661f70), + WTC2(0x01a83c0c), WTC2(0x01ef69e8), WTC2(0x023b9364), WTC2(0x028ca2d4), WTC2(0x02e2829c), WTC2(0x033d1d10), WTC2(0x039c5c90), WTC2(0x04002b78), + WTC2(0x04687418), WTC2(0x04d520e0), WTC2(0x05461c18), WTC2(0x05bb5020), WTC2(0x0634a758), WTC2(0x06b20c20), WTC2(0x073368c8), WTC2(0x07b8a7b0), + WTC2(0x0841b340), WTC2(0x08ce75b0), WTC2(0x095ed980), WTC2(0x09f2c900), WTC2(0x0a8a2e80), WTC2(0x0b24f470), WTC2(0x0bc30510), WTC2(0x0c644ad0), + WTC2(0x0d08b010), WTC2(0x0db01f10), WTC2(0x0e5a8250), WTC2(0x0f07c400), WTC2(0x0fb7cea0), WTC2(0x106a8c80), WTC2(0x111fe800), WTC2(0x11d7cb60), + WTC2(0x12922120), WTC2(0x134ed3a0), WTC2(0x140dcd00), WTC2(0x14cef7e0), WTC2(0x15923e60), WTC2(0x16578b00), WTC2(0x171ec820), WTC2(0x17e7e020), + WTC2(0x18b2bd20), WTC2(0x197f49c0), WTC2(0x1a4d7040), WTC2(0x1b1d1b00), WTC2(0x1bee3460), WTC2(0x1cc0a6a0), WTC2(0x1d945c40), WTC2(0x1e693f80), + WTC2(0x1f3f3ac0), WTC2(0x20163880), WTC2(0x20ee22c0), WTC2(0x21c6e440), WTC2(0x22a06740), WTC2(0x237a9600), WTC2(0x24555ac0), WTC2(0x2530a040), + WTC2(0x260c5080), WTC2(0x26e85600), WTC2(0x27c49b00), WTC2(0x28a10a00), WTC2(0x297d8d80), WTC2(0x2a5a0f80), WTC2(0x2b367a80), WTC2(0x2c12b8c0), + WTC2(0x2ceeb500), WTC2(0x2dca5940), WTC2(0x2ea58fc0), WTC2(0x2f804340), WTC2(0x305a5dc0), WTC2(0x3133ca00), WTC2(0x320c7200), WTC2(0x32e44000), + WTC2(0x33bb1ec0), WTC2(0x3490f880), WTC2(0x3565b7c0), WTC2(0x36394640), WTC2(0x370b8f00), WTC2(0x37dc7c00), WTC2(0x38abf7c0), WTC2(0x3979ecc0), + WTC2(0x3a464500), WTC2(0x3b10eb00), WTC2(0x3bd9c940), WTC2(0x3ca0c9c0), WTC2(0x3d65d740), WTC2(0x3e28dc00), WTC2(0x3ee9c240), WTC2(0x3fa87480), + WTC2(0x4064dcff), WTC2(0x411ee67f), WTC2(0x41d67a7f), WTC2(0x428b847f), WTC2(0x433ded7f), WTC2(0x43eda0ff), WTC2(0x449a887f), WTC2(0x45448f7f), + WTC2(0x45eb9eff), WTC2(0x468fa1ff), WTC2(0x473082ff), WTC2(0x47ce2c7f), WTC2(0x4868887f), WTC2(0x48ff80ff), WTC2(0x499300ff), WTC2(0x4a22f2ff), + WTC2(0x4aaf407f), WTC2(0x4b37d47f), WTC2(0x4bbc997f), WTC2(0x4c3d78ff), WTC2(0x4cba5e7f), WTC2(0x4d33337f), WTC2(0x4da7e27f), WTC2(0x4e18567f), + WTC2(0x4e8478ff), WTC2(0x4eec347f), WTC2(0x4f4f737f), WTC2(0x4fae20ff), WTC2(0x500825ff), WTC2(0x505d6dff), WTC2(0x50ade37f), WTC2(0x50f96f7f), + WTC2(0x513ffdff), WTC2(0x518177ff), WTC2(0x51bdc87f), WTC2(0x51f4d9ff), WTC2(0x5226967f), WTC2(0x5252e87f), WTC2(0x5279b9ff), WTC2(0x529af5ff), + WTC2(0x52b6867f), WTC2(0x52cc55ff), WTC2(0x52dc4eff), WTC2(0x52e65aff), WTC2(0x52ea657f), WTC2(0x52e857ff), WTC2(0x52e01d7f), WTC2(0x52d19fff), + WTC2(0x52bcc9ff), WTC2(0x52a1857f), WTC2(0x527fbd7f), WTC2(0x52575b7f), WTC2(0x52284a7f), WTC2(0x51f274ff), WTC2(0x51b5c47f), WTC2(0x5172247f), + WTC2(0x51277dff), WTC2(0x50d5bc7f), WTC2(0x507cc9ff), WTC2(0x501c90ff), WTC2(0x4fb4fb7f), WTC2(0x4f45f3ff), WTC2(0x4ecf64ff), WTC2(0x4e5138ff), + WTC2(0x4dcb597f), WTC2(0x4d3db1ff), WTC2(0x4ca82bff), WTC2(0x4c0ab27f), WTC2(0x4b652f7f), WTC2(0x4ab78d7f), WTC2(0x4a01b67f), WTC2(0x4943957f), + WTC2(0x487d12ff), WTC2(0x47ae1f7f), WTC2(0x46d68f7f), WTC2(0x45f7187f), WTC2(0x4513597f), WTC2(0x4430467f), WTC2(0x4352d2ff), WTC2(0x427e6bff), + WTC2(0x41b390ff), WTC2(0x40f2077f), WTC2(0x4039a87f), WTC2(0x3f8a3100), WTC2(0x3ee33e00), WTC2(0x3e446ac0), WTC2(0x3dad5180), WTC2(0x3d1d7fc0), + WTC2(0x3c947b00), WTC2(0x3c11c7c0), WTC2(0x3b94ebc0), WTC2(0x3b1d6dc0), WTC2(0x3aaad480), WTC2(0x3a3ca740), WTC2(0x39d26c40), WTC2(0x396ba8c0), + WTC2(0x3907e080), WTC2(0x38a69800), WTC2(0x38473d80), WTC2(0x37e923c0), WTC2(0x378b9b80), WTC2(0x372e0380), WTC2(0x36d03a80), WTC2(0x36727f00), + WTC2(0x36150e40), WTC2(0x35b81540), WTC2(0x355b8000), WTC2(0x34ff1dc0), WTC2(0x34a2bfc0), WTC2(0x34463e80), WTC2(0x33e982c0), WTC2(0x338c7880), + WTC2(0x332f0bc0), WTC2(0x32d11800), WTC2(0x327265c0), WTC2(0x3212bbc0), WTC2(0x31b1e740), WTC2(0x314fef00), WTC2(0x30ed0540), WTC2(0x30895c80), + WTC2(0x30251880), WTC2(0x2fc02880), WTC2(0x2f5a6480), WTC2(0x2ef3a480), WTC2(0x2e8bd640), WTC2(0x2e231100), WTC2(0x2db97680), WTC2(0x2d4f2700), + WTC2(0x2ce431c0), WTC2(0x2c789080), WTC2(0x2c0c3bc0), WTC2(0x2b9f2bc0), WTC2(0x2b315940), WTC2(0x2ac2bc00), WTC2(0x2a534cc0), WTC2(0x29e303c0) +}; + + diff --git a/libAACenc/src/aacEnc_rom.h b/libAACenc/src/aacEnc_rom.h new file mode 100644 index 0000000..e96e0e7 --- /dev/null +++ b/libAACenc/src/aacEnc_rom.h @@ -0,0 +1,141 @@ +/****************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id: + Initial authors: M. Lohwasser, M. Gayer + Contents/description: + +******************************************************************************/ +/*! + \file + \brief Memory layout $Revision: 36838 $ + \author Markus Lohwasser +*/ + +#ifndef AAC_ENC_ROM_H +#define AAC_ENC_ROM_H + +#include "common_fix.h" + +#include "psy_const.h" +#include "psy_configuration.h" +#include "FDK_tools_rom.h" + +/* + Huffman Tables +*/ +extern const INT FDKaacEnc_huff_ltab1_2[3][3][3][3]; +extern const INT FDKaacEnc_huff_ltab3_4[3][3][3][3]; +extern const INT FDKaacEnc_huff_ltab5_6[9][9]; +extern const INT FDKaacEnc_huff_ltab7_8[8][8]; +extern const INT FDKaacEnc_huff_ltab9_10[13][13]; +extern const UCHAR FDKaacEnc_huff_ltab11[17][17]; +extern const UCHAR FDKaacEnc_huff_ltabscf[121]; +extern const USHORT FDKaacEnc_huff_ctab1[3][3][3][3]; +extern const USHORT FDKaacEnc_huff_ctab2[3][3][3][3]; +extern const USHORT FDKaacEnc_huff_ctab3[3][3][3][3]; +extern const USHORT FDKaacEnc_huff_ctab4[3][3][3][3]; +extern const USHORT FDKaacEnc_huff_ctab5[9][9]; +extern const USHORT FDKaacEnc_huff_ctab6[9][9]; +extern const USHORT FDKaacEnc_huff_ctab7[8][8]; +extern const USHORT FDKaacEnc_huff_ctab8[8][8]; +extern const USHORT FDKaacEnc_huff_ctab9[13][13]; +extern const USHORT FDKaacEnc_huff_ctab10[13][13]; +extern const USHORT FDKaacEnc_huff_ctab11[21][17]; +extern const INT FDKaacEnc_huff_ctabscf[121]; + +/* + quantizer +*/ +#define MANT_DIGITS 9 +#define MANT_SIZE (1<nChannelsEff; + + return bitrate; +} + +/** + * \brief Convert encoder bitreservoir value for transport library. + * + * \param bitrateMode Bitratemode used in current encoder instance. Se ::AACENC_BITRATE_MODE + * \param bitresTotal Encoder bitreservoir level in bits. + * + * \return Corrected bitreservoir level used in transport library. + */ +static INT FDKaacEnc_EncBitresToTpBitres( + const AACENC_BITRATE_MODE bitrateMode, + const INT bitresTotal + ) +{ + INT transporBitreservoir = 0; + + switch (bitrateMode) { + case AACENC_BR_MODE_CBR: + transporBitreservoir = bitresTotal; /* encoder bitreservoir level */ + break; + case AACENC_BR_MODE_VBR_1: + case AACENC_BR_MODE_VBR_2: + case AACENC_BR_MODE_VBR_3: + case AACENC_BR_MODE_VBR_4: + case AACENC_BR_MODE_VBR_5: + transporBitreservoir = FDK_INT_MAX; /* signal variable bitrate */ + break; + case AACENC_BR_MODE_FF: + case AACENC_BR_MODE_SFR: + transporBitreservoir = 0; /* super framing and fixed framing */ + break; /* without bitreservoir signaling */ + default: + case AACENC_BR_MODE_INVALID: + transporBitreservoir = 0; /* invalid configuration*/ + FDK_ASSERT(0); + } + + return transporBitreservoir; +} + +/*----------------------------------------------------------------------------- + + functionname: FDKaacEnc_AacInitDefaultConfig + description: gives reasonable default configuration + returns: --- + + ------------------------------------------------------------------------------*/ +void FDKaacEnc_AacInitDefaultConfig(AACENC_CONFIG *config) +{ + /* make thepre initialization of the structs flexible */ + FDKmemclear(config, sizeof(AACENC_CONFIG)); + + /* default ancillary */ + config->anc_Rate = 0; /* no ancillary data */ + config->ancDataBitRate = 0; /* no additional consumed bitrate */ + + /* default configurations */ + config->bitRate = -1; /* bitrate must be set*/ + config->averageBits = -1; /* instead of bitrate/s we can configure bits/superframe */ + config->bitrateMode = 0; + config->bandWidth = 0; /* get bandwidth from table */ + config->useTns = TNS_ENABLE_MASK; /* tns enabled completly */ + config->usePns = 1; /* depending on channelBitrate this might be set to 0 later */ + config->useIS = 1; /* Intensity Stereo Configuration */ + config->framelength = DEFAULT_FRAMELENGTH; /* used frame size */ + config->syntaxFlags = 0; /* default syntax with no specialities */ + config->epConfig = -1; /* no ER syntax -> no additional error protection */ + config->nSubFrames = 1; /* default, no sub frames */ + config->channelOrder = CH_ORDER_MPEG; /* Use MPEG channel ordering. */ + config->channelMode = MODE_UNKNOWN; + config->minBitsPerFrame = -1; /* minum number of bits in each AU */ + config->maxBitsPerFrame = -1; /* minum number of bits in each AU */ + config->bitreservoir = -1; /* default, uninitialized value */ + + /* init tabs in fixpoint_math */ + InitLdInt(); + InitInvSqrtTab(); +} + + +/*--------------------------------------------------------------------------- + + functionname: FDKaacEnc_Open + description: allocate and initialize a new encoder instance + returns: error code + + ---------------------------------------------------------------------------*/ +AAC_ENCODER_ERROR FDKaacEnc_Open(HANDLE_AAC_ENC *phAacEnc, + const INT nElements, + const INT nChannels, + const INT nSubFrames) +{ + AAC_ENCODER_ERROR ErrorStatus; + AAC_ENC *hAacEnc = NULL; + UCHAR *dynamicRAM = NULL; + + if (phAacEnc==NULL) { + return AAC_ENC_INVALID_HANDLE; + } + + /* allocate encoder structure */ + hAacEnc = GetRam_aacEnc_AacEncoder(); + if (hAacEnc == NULL) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto bail; + } + FDKmemclear(hAacEnc, sizeof(AAC_ENC)); + + hAacEnc->dynamic_RAM = GetAACdynamic_RAM(); + dynamicRAM = (UCHAR*)hAacEnc->dynamic_RAM; + + /* allocate the Psy aud Psy Out structure */ + ErrorStatus = FDKaacEnc_PsyNew(&hAacEnc->psyKernel, + nElements, + nChannels + ,dynamicRAM + ); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + ErrorStatus = FDKaacEnc_PsyOutNew(hAacEnc->psyOut, + nElements, + nChannels, + nSubFrames + ,dynamicRAM + ); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + /* allocate the Q&C Out structure */ + ErrorStatus = FDKaacEnc_QCOutNew(hAacEnc->qcOut, + nElements, + nChannels, + nSubFrames + ,dynamicRAM + ); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + /* allocate the Q&C kernel */ + ErrorStatus = FDKaacEnc_QCNew(&hAacEnc->qcKernel, + nElements + ,dynamicRAM + ); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + hAacEnc->maxChannels = nChannels; + hAacEnc->maxElements = nElements; + hAacEnc->maxFrames = nSubFrames; + +bail: + *phAacEnc = hAacEnc; + return ErrorStatus; +} + + +AAC_ENCODER_ERROR FDKaacEnc_Initialize(HANDLE_AAC_ENC hAacEnc, + AACENC_CONFIG *config, /* pre-initialized config struct */ + HANDLE_TRANSPORTENC hTpEnc, + ULONG initFlags) +{ + AAC_ENCODER_ERROR ErrorStatus; + INT psyBitrate, tnsMask; //INT profile = 1; + CHANNEL_MAPPING *cm = NULL; + + INT qmbfac, qbw; + FIXP_DBL mbfac, bw_ratio; + QC_INIT qcInit; + INT averageBitsPerFrame = 0; + + if (config==NULL) + return AAC_ENC_INVALID_HANDLE; + + /******************* sanity checks *******************/ + + /* check config structure */ + if (config->nChannels < 1 || config->nChannels > (6)) { + return AAC_ENC_UNSUPPORTED_CHANNELCONFIG; + } + + /* check sample rate */ + switch (config->sampleRate) + { + case 8000: + case 11025: + case 12000: + case 16000: + case 22050: + case 24000: + case 32000: + case 44100: + case 48000: + case 64000: + case 88200: + case 96000: + break; + default: + return AAC_ENC_UNSUPPORTED_SAMPLINGRATE; + } + + /* bitrate has to be set */ + if (config->bitRate==-1) { + return AAC_ENC_UNSUPPORTED_BITRATE; + } + + /* check bit rate */ + + /* check if bitRate is not too low or high */ + averageBitsPerFrame = (config->bitRate*(config->framelength>>GetSrSf(config->sampleRate))) / (config->sampleRate>>GetSrSf(config->sampleRate)) / config->nSubFrames; + + /* assume minimum static bits of 40 in each channel. */ + if ( (averageBitsPerFrame <= ((40*config->nChannels) + transportEnc_GetStaticBits(hTpEnc, averageBitsPerFrame))) || + ( ((config->bitRate*(config->framelength>>GetSrSf(config->sampleRate)))) > + ((FDKaacEnc_GetChannelModeConfiguration(config->channelMode)->nChannelsEff * MIN_BUFSIZE_PER_EFF_CHAN))*(config->sampleRate>>GetSrSf(config->sampleRate)) ) + ) + { + return AAC_ENC_UNSUPPORTED_BITRATE; + } + + if (config->syntaxFlags & AC_ER_VCB11) { + return AAC_ENC_UNSUPPORTED_ER_FORMAT; + } + if (config->syntaxFlags & AC_ER_HCR) { + return AAC_ENC_UNSUPPORTED_ER_FORMAT; + } + + /* check frame length */ + switch (config->framelength) + { + case 1024: + if ( config->audioObjectType != AOT_AAC_LC + && config->audioObjectType != AOT_SBR + && config->audioObjectType != AOT_PS + && config->audioObjectType != AOT_ER_AAC_LC + && config->audioObjectType != AOT_AAC_SCAL ) + { + return AAC_ENC_INVALID_FRAME_LENGTH; + } + break; + case 512: + case 480: + if ( config->audioObjectType != AOT_ER_AAC_LD + && config->audioObjectType != AOT_ER_AAC_ELD ) + { + return AAC_ENC_INVALID_FRAME_LENGTH; + } + break; + default: + return AAC_ENC_INVALID_FRAME_LENGTH; + } + + if (config->anc_Rate != 0) { + + ErrorStatus = FDKaacEnc_InitCheckAncillary(config->bitRate, + config->framelength, + config->anc_Rate, + &hAacEnc->ancillaryBitsPerFrame, + config->sampleRate); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + + /* update estimated consumed bitrate */ + config->ancDataBitRate += ( (hAacEnc->ancillaryBitsPerFrame * config->sampleRate) / config->framelength ); + + } + + /* maximal allowed DSE bytes in frame */ + { + /* fixpoint calculation*/ + INT q_res, encBitrate, sc; + FIXP_DBL tmp = fDivNorm(config->framelength, config->sampleRate, &q_res); + encBitrate = (config->bitRate/*-config->ancDataBitRate*/)- (INT)(config->nChannels*8000); + sc = CountLeadingBits(encBitrate); + config->maxAncBytesPerAU = FDKmin( (256), FDKmax(0,(INT)(fMultDiv2(tmp, (FIXP_DBL)(encBitrate<>(-q_res+sc-1+3))) ); + } + + /* bind config to hAacEnc->config */ + hAacEnc->config = config; + + /* set hAacEnc->bitrateMode */ + hAacEnc->bitrateMode = (AACENC_BITRATE_MODE)config->bitrateMode; + + hAacEnc->encoderMode = config->channelMode; + + ErrorStatus = FDKaacEnc_InitChannelMapping(hAacEnc->encoderMode, config->channelOrder, &hAacEnc->channelMapping); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + cm = &hAacEnc->channelMapping; + + ErrorStatus = FDKaacEnc_DetermineBandWidth(&hAacEnc->config->bandWidth, + config->bandWidth, + config->bitRate - config->ancDataBitRate, + hAacEnc->bitrateMode, + config->sampleRate, + config->framelength, + cm, + hAacEnc->encoderMode); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + hAacEnc->bandwidth90dB = (INT)hAacEnc->config->bandWidth; + + tnsMask = config->useTns ? TNS_ENABLE_MASK : 0x0; + psyBitrate = config->bitRate - config->ancDataBitRate; + + ErrorStatus = FDKaacEnc_psyInit(hAacEnc->psyKernel, + hAacEnc->psyOut, + hAacEnc->maxFrames, + hAacEnc->maxChannels, + config->audioObjectType, + cm); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + ErrorStatus = FDKaacEnc_psyMainInit(hAacEnc->psyKernel, + config->audioObjectType, + cm, + config->sampleRate, + config->framelength, + psyBitrate, + tnsMask, + hAacEnc->bandwidth90dB, + config->usePns, + config->useIS, + config->syntaxFlags, + initFlags); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + ErrorStatus = FDKaacEnc_QCOutInit(hAacEnc->qcOut, hAacEnc->maxFrames, cm); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + + + qcInit.channelMapping = &hAacEnc->channelMapping; + qcInit.sceCpe = 0; + + { + int maxBitres; + qcInit.averageBits = (averageBitsPerFrame+7)&~7; + maxBitres = (MIN_BUFSIZE_PER_EFF_CHAN*cm->nChannelsEff) - qcInit.averageBits; + qcInit.bitRes = (config->bitreservoir!=-1) ? FDKmin(config->bitreservoir, maxBitres) : maxBitres; + + qcInit.maxBits = fixMin(MIN_BUFSIZE_PER_EFF_CHAN*cm->nChannelsEff, ((averageBitsPerFrame+7)&~7)+qcInit.bitRes); + qcInit.maxBits = (config->maxBitsPerFrame!=-1) ? fixMin(qcInit.maxBits, config->maxBitsPerFrame) : qcInit.maxBits; + + qcInit.minBits = fixMax(0, ((averageBitsPerFrame-1)&~7)-qcInit.bitRes-transportEnc_GetStaticBits(hTpEnc, ((averageBitsPerFrame+7)&~7)+qcInit.bitRes)); + qcInit.minBits = (config->minBitsPerFrame!=-1) ? fixMax(qcInit.minBits, config->minBitsPerFrame) : qcInit.minBits; + } + + qcInit.nSubFrames = config->nSubFrames; + qcInit.padding.paddingRest = config->sampleRate; + + /* Calc meanPe */ + bw_ratio = fDivNorm((FIXP_DBL)hAacEnc->bandwidth90dB, (FIXP_DBL)(config->sampleRate>>1), &qbw); + qbw = DFRACT_BITS-1-qbw; + /* qcInit.meanPe = 10.0f * FRAME_LEN_LONG * hAacEnc->bandwidth90dB/(config->sampleRate/2.0f); */ + qcInit.meanPe = fMult(bw_ratio, (FIXP_DBL)((10*config->framelength)<<16)) >> (qbw-15); + + /* Calc maxBitFac */ + mbfac = fDivNorm((MIN_BUFSIZE_PER_EFF_CHAN-744)*cm->nChannelsEff, qcInit.averageBits/qcInit.nSubFrames, &qmbfac); + qmbfac = DFRACT_BITS-1-qmbfac; + qcInit.maxBitFac = (qmbfac > 24) ? (mbfac >> (qmbfac - 24)):(mbfac << (24 - qmbfac)); + + switch(config->bitrateMode){ + case AACENC_BR_MODE_CBR: + qcInit.bitrateMode = QCDATA_BR_MODE_CBR; + break; + case AACENC_BR_MODE_VBR_1: + qcInit.bitrateMode = QCDATA_BR_MODE_VBR_1; + break; + case AACENC_BR_MODE_VBR_2: + qcInit.bitrateMode = QCDATA_BR_MODE_VBR_2; + break; + case AACENC_BR_MODE_VBR_3: + qcInit.bitrateMode = QCDATA_BR_MODE_VBR_3; + break; + case AACENC_BR_MODE_VBR_4: + qcInit.bitrateMode = QCDATA_BR_MODE_VBR_4; + break; + case AACENC_BR_MODE_VBR_5: + qcInit.bitrateMode = QCDATA_BR_MODE_VBR_5; + break; + case AACENC_BR_MODE_SFR: + qcInit.bitrateMode = QCDATA_BR_MODE_SFR; + break; + case AACENC_BR_MODE_FF: + qcInit.bitrateMode = QCDATA_BR_MODE_FF; + break; + default: + ErrorStatus = AAC_ENC_UNSUPPORTED_BITRATE_MODE; + goto bail; + } + + qcInit.invQuant = (config->useRequant)?2:0; + + /* maxIterations should be set to the maximum number of requantization iterations that are + * allowed before the crash recovery functionality is activated. This setting should be adjusted + * to the processing power available, i.e. to the processing power headroom in one frame that is + * still left after normal encoding without requantization. Please note that if activated this + * functionality is used most likely only in cases where the encoder is operating beyond + * recommended settings, i.e. the audio quality is suboptimal anyway. Activating the crash + * recovery does not further reduce audio quality significantly in these cases. */ + if ( (config->audioObjectType == AOT_ER_AAC_LD) || (config->audioObjectType == AOT_ER_AAC_ELD) ) { + qcInit.maxIterations = 2; + } + else + { + qcInit.maxIterations = 5; + } + + qcInit.bitrate = config->bitRate - config->ancDataBitRate; + + qcInit.staticBits = transportEnc_GetStaticBits(hTpEnc, qcInit.averageBits/qcInit.nSubFrames); + + ErrorStatus = FDKaacEnc_QCInit(hAacEnc->qcKernel, &qcInit); + if (ErrorStatus != AAC_ENC_OK) + goto bail; + + /* Map virtual aot's to intern aot used in bitstream writer. */ + switch (hAacEnc->config->audioObjectType) { + case AOT_MP2_AAC_LC: + case AOT_DABPLUS_AAC_LC: + hAacEnc->aot = AOT_AAC_LC; + break; + case AOT_MP2_SBR: + case AOT_DABPLUS_SBR: + hAacEnc->aot = AOT_SBR; + break; + case AOT_MP2_PS: + case AOT_DABPLUS_PS: + hAacEnc->aot = AOT_PS; + break; + default: + hAacEnc->aot = hAacEnc->config->audioObjectType; + } + + /* common things */ + + return AAC_ENC_OK; + +bail: + + return ErrorStatus; +} + + +/*--------------------------------------------------------------------------- + + functionname: FDKaacEnc_EncodeFrame + description: encodes one frame + returns: error code + + ---------------------------------------------------------------------------*/ +AAC_ENCODER_ERROR FDKaacEnc_EncodeFrame( HANDLE_AAC_ENC hAacEnc, /* encoder handle */ + HANDLE_TRANSPORTENC hTpEnc, + INT_PCM* RESTRICT inputBuffer, + INT* nOutBytes, + AACENC_EXT_PAYLOAD extPayload[MAX_TOTAL_EXT_PAYLOADS] + ) +{ + AAC_ENCODER_ERROR ErrorStatus; + int el, n, c=0; + UCHAR extPayloadUsed[MAX_TOTAL_EXT_PAYLOADS]; + + CHANNEL_MAPPING *cm = &hAacEnc->channelMapping; + + + + PSY_OUT *psyOut = hAacEnc->psyOut[c]; + QC_OUT *qcOut = hAacEnc->qcOut[c]; + + FDKmemclear(extPayloadUsed, MAX_TOTAL_EXT_PAYLOADS * sizeof(UCHAR)); + + qcOut->elementExtBits = 0; /* sum up all extended bit of each element */ + qcOut->staticBits = 0; /* sum up side info bits of each element */ + qcOut->totalNoRedPe = 0; /* sum up PE */ + + /* advance psychoacoustics */ + for (el=0; elnElements; el++) { + ELEMENT_INFO elInfo = cm->elInfo[el]; + + if ( (elInfo.elType == ID_SCE) + || (elInfo.elType == ID_CPE) + || (elInfo.elType == ID_LFE) ) + { + int ch; + + /* update pointer!*/ + for(ch=0;chpsyOutElement[el]->psyOutChannel[ch]; + QC_OUT_CHANNEL *qcOutChan = qcOut->qcElement[el]->qcOutChannel[ch]; + + psyOutChan->mdctSpectrum = qcOutChan->mdctSpectrum; + psyOutChan->sfbSpreadEnergy = qcOutChan->sfbSpreadEnergy; + psyOutChan->sfbEnergy = qcOutChan->sfbEnergy; + psyOutChan->sfbEnergyLdData = qcOutChan->sfbEnergyLdData; + psyOutChan->sfbMinSnrLdData = qcOutChan->sfbMinSnrLdData; + psyOutChan->sfbThresholdLdData = qcOutChan->sfbThresholdLdData; + + } + + FDKaacEnc_psyMain(elInfo.nChannelsInEl, + hAacEnc->psyKernel->psyElement[el], + hAacEnc->psyKernel->psyDynamic, + hAacEnc->psyKernel->psyConf, + psyOut->psyOutElement[el], + inputBuffer, + cm->elInfo[el].ChannelIndex, + cm->nChannels + + ); + + /* FormFactor, Pe and staticBitDemand calculation */ + ErrorStatus = FDKaacEnc_QCMainPrepare(&elInfo, + hAacEnc->qcKernel->hAdjThr->adjThrStateElem[el], + psyOut->psyOutElement[el], + qcOut->qcElement[el], + hAacEnc->aot, + hAacEnc->config->syntaxFlags, + hAacEnc->config->epConfig); + + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + + /*-------------------------------------------- */ + + qcOut->qcElement[el]->extBitsUsed = 0; + qcOut->qcElement[el]->nExtensions = 0; + /* reset extension payload */ + FDKmemclear(&qcOut->qcElement[el]->extension, (1)*sizeof(QC_OUT_EXTENSION)); + + for ( n = 0; n < MAX_TOTAL_EXT_PAYLOADS; n++ ) { + if ( !extPayloadUsed[n] + && (extPayload[n].associatedChElement == el) + && (extPayload[n].dataSize > 0) + && (extPayload[n].pData != NULL) ) + { + int idx = qcOut->qcElement[el]->nExtensions++; + + qcOut->qcElement[el]->extension[idx].type = extPayload[n].dataType; /* Perform a sanity check on the type? */ + qcOut->qcElement[el]->extension[idx].nPayloadBits = extPayload[n].dataSize; + qcOut->qcElement[el]->extension[idx].pPayload = extPayload[n].pData; + /* Now ask the bitstream encoder how many bits we need to encode the data with the current bitstream syntax: */ + qcOut->qcElement[el]->extBitsUsed += + FDKaacEnc_writeExtensionData( NULL, + &qcOut->qcElement[el]->extension[idx], + 0, 0, + hAacEnc->config->syntaxFlags, + hAacEnc->aot, + hAacEnc->config->epConfig ); + extPayloadUsed[n] = 1; + } + } + + /* sum up extension and static bits for all channel elements */ + qcOut->elementExtBits += qcOut->qcElement[el]->extBitsUsed; + qcOut->staticBits += qcOut->qcElement[el]->staticBitsUsed; + + /* sum up pe */ + qcOut->totalNoRedPe += qcOut->qcElement[el]->peData.pe; + } + } + + qcOut->nExtensions = 0; + qcOut->globalExtBits = 0; + + /* reset extension payload */ + FDKmemclear(&qcOut->extension, (2+2)*sizeof(QC_OUT_EXTENSION)); + + /* Add extension payload not assigned to an channel element + (Ancillary data is the only supported type up to now) */ + for ( n = 0; n < MAX_TOTAL_EXT_PAYLOADS; n++ ) { + if ( !extPayloadUsed[n] + && (extPayload[n].associatedChElement == -1) + && (extPayload[n].pData != NULL) ) + { + UINT payloadBits = 0; + + if (extPayload[n].dataType == EXT_DATA_ELEMENT) { + if (hAacEnc->ancillaryBitsPerFrame) { + /* granted frame dse bitrate */ + payloadBits = hAacEnc->ancillaryBitsPerFrame; + } + else { + /* write anc data if bitrate constraint fulfilled */ + if ((extPayload[n].dataSize>>3) <= hAacEnc->config->maxAncBytesPerAU) { + payloadBits = extPayload[n].dataSize; + } + } + payloadBits = fixMin( extPayload[n].dataSize, payloadBits ); + } else { + payloadBits = extPayload[n].dataSize; + } + + if (payloadBits > 0) + { + int idx = qcOut->nExtensions++; + + qcOut->extension[idx].type = extPayload[n].dataType; /* Perform a sanity check on the type? */ + qcOut->extension[idx].nPayloadBits = payloadBits; + qcOut->extension[idx].pPayload = extPayload[n].pData; + /* Now ask the bitstream encoder how many bits we need to encode the data with the current bitstream syntax: */ + qcOut->globalExtBits += FDKaacEnc_writeExtensionData( NULL, + &qcOut->extension[idx], + 0, 0, + hAacEnc->config->syntaxFlags, + hAacEnc->aot, + hAacEnc->config->epConfig ); + if (extPayload[n].dataType == EXT_DATA_ELEMENT) { + /* substract the processed bits */ + extPayload[n].dataSize -= payloadBits; + } + extPayloadUsed[n] = 1; + } + } + } + + if (!(hAacEnc->config->syntaxFlags & (AC_SCALABLE|AC_ER))) { + qcOut->globalExtBits += EL_ID_BITS; /* add bits for ID_END */ + } + + /* build bitstream all nSubFrames */ + { + INT totalBits = 0; /* Total AU bits */; + INT avgTotalBits = 0; + + /*-------------------------------------------- */ + /* Get average total bits */ + /*-------------------------------------------- */ + { + /* frame wise bitrate adaption */ + FDKaacEnc_AdjustBitrate(hAacEnc->qcKernel, + cm, + &avgTotalBits, + hAacEnc->config->bitRate, + hAacEnc->config->sampleRate, + hAacEnc->config->framelength); + + /* adjust super frame bitrate */ + avgTotalBits *= hAacEnc->config->nSubFrames; + } + + /* Make first estimate of transport header overhead. + Take maximum possible frame size into account to prevent bitreservoir underrun. */ + hAacEnc->qcKernel->globHdrBits = transportEnc_GetStaticBits(hTpEnc, avgTotalBits + hAacEnc->qcKernel->bitResTot); + + + /*-------------------------------------------- */ + /*-------------------------------------------- */ + /*-------------------------------------------- */ + + ErrorStatus = FDKaacEnc_QCMain(hAacEnc->qcKernel, + hAacEnc->psyOut, + hAacEnc->qcOut, + avgTotalBits, + cm + ,hAacEnc->aot, + hAacEnc->config->syntaxFlags, + hAacEnc->config->epConfig); + + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + /*-------------------------------------------- */ + + /*-------------------------------------------- */ + ErrorStatus = FDKaacEnc_updateFillBits(cm, + hAacEnc->qcKernel, + hAacEnc->qcKernel->elementBits, + hAacEnc->qcOut); + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + + /*-------------------------------------------- */ + ErrorStatus = FDKaacEnc_FinalizeBitConsumption(cm, + hAacEnc->qcKernel, + qcOut, + qcOut->qcElement, + hTpEnc, + hAacEnc->aot, + hAacEnc->config->syntaxFlags, + hAacEnc->config->epConfig); + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + /*-------------------------------------------- */ + totalBits += qcOut->totalBits; + + + /*-------------------------------------------- */ + FDKaacEnc_updateBitres(cm, + hAacEnc->qcKernel, + hAacEnc->qcOut); + + /*-------------------------------------------- */ + + /* for ( all sub frames ) ... */ + /* write bitstream header */ + transportEnc_WriteAccessUnit( + hTpEnc, + totalBits, + FDKaacEnc_EncBitresToTpBitres(hAacEnc->bitrateMode, hAacEnc->qcKernel->bitResTot), + cm->nChannelsEff); + + /* write bitstream */ + ErrorStatus = FDKaacEnc_WriteBitstream( + hTpEnc, + cm, + qcOut, + psyOut, + hAacEnc->qcKernel, + hAacEnc->aot, + hAacEnc->config->syntaxFlags, + hAacEnc->config->epConfig); + + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + + /* transportEnc_EndAccessUnit() is being called inside FDKaacEnc_WriteBitstream() */ + transportEnc_GetFrame(hTpEnc, nOutBytes); + + } /* -end- if (curFrame==hAacEnc->qcKernel->nSubFrames) */ + + + /*-------------------------------------------- */ + return AAC_ENC_OK; +} + +/*--------------------------------------------------------------------------- + + functionname:FDKaacEnc_Close + description: delete encoder instance + returns: + + ---------------------------------------------------------------------------*/ + +void FDKaacEnc_Close( HANDLE_AAC_ENC* phAacEnc) /* encoder handle */ +{ + if (*phAacEnc == NULL) { + return; + } + AAC_ENC *hAacEnc = (AAC_ENC*)*phAacEnc; + + if (hAacEnc->dynamic_RAM != NULL) + FreeAACdynamic_RAM(&hAacEnc->dynamic_RAM); + + FDKaacEnc_PsyClose(&hAacEnc->psyKernel,hAacEnc->psyOut); + + FDKaacEnc_QCClose(&hAacEnc->qcKernel, hAacEnc->qcOut); + + FreeRam_aacEnc_AacEncoder(phAacEnc); +} + + +/* The following functions are in this source file only for convenience and */ +/* need not be visible outside of a possible encoder library. */ + +/* basic defines for ancillary data */ +#define MAX_ANCRATE 19200 /* ancillary rate >= 19200 isn't valid */ + +/*--------------------------------------------------------------------------- + + functionname: FDKaacEnc_InitCheckAncillary + description: initialize and check ancillary data struct + return: if success or NULL if error + + ---------------------------------------------------------------------------*/ +static AAC_ENCODER_ERROR FDKaacEnc_InitCheckAncillary(INT bitRate, + INT framelength, + INT ancillaryRate, + INT *ancillaryBitsPerFrame, + INT sampleRate) +{ + INT diffToByteAlign; + + /* don't use negative ancillary rates */ + if ( ancillaryRate < -1 ) + return AAC_ENC_UNSUPPORTED_ANC_BITRATE; + + /* check if ancillary rate is ok */ + if ( (ancillaryRate != (-1)) && (ancillaryRate != 0) ) { + /* ancRate <= 15% of bitrate && ancRate < 19200 */ + if ( ( ancillaryRate >= MAX_ANCRATE ) || + ( (ancillaryRate * 20) > (bitRate * 3) ) ) { + return AAC_ENC_UNSUPPORTED_ANC_BITRATE; + } + } + else if (ancillaryRate == -1) { + /* if no special ancRate is requested but a ancillary file is + stated, then generate a ancillary rate matching to the bitrate */ + if (bitRate >= (MAX_ANCRATE * 10)) { + /* ancillary rate is 19199 */ + ancillaryRate = (MAX_ANCRATE - 1); + } + else { /* 10% of bitrate */ + ancillaryRate = bitRate / 10; + } + } + + /* make ancillaryBitsPerFrame byte align */ + *ancillaryBitsPerFrame = (ancillaryRate * framelength ) / sampleRate; + diffToByteAlign = *ancillaryBitsPerFrame % 8; + *ancillaryBitsPerFrame = *ancillaryBitsPerFrame - diffToByteAlign; + + return AAC_ENC_OK; +} diff --git a/libAACenc/src/aacenc.h b/libAACenc/src/aacenc.h new file mode 100644 index 0000000..66ef2b9 --- /dev/null +++ b/libAACenc/src/aacenc.h @@ -0,0 +1,232 @@ +/************************* Fast MPEG AAC Audio Encoder ********************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Schug / A. Groeschel + contents/description: fast aac coder interface library functions + +******************************************************************************/ + +#ifndef _aacenc_h_ +#define _aacenc_h_ + +#include "common_fix.h" +#include "FDK_audio.h" + +#include "tpenc_lib.h" + +#include "sbr_encoder.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * AAC-LC error codes. + */ +typedef enum { + AAC_ENC_OK = 0x0000, /*!< All fine. */ + + AAC_ENC_UNKNOWN = 0x0002, /*!< Error condition is of unknown reason, or from another module. */ + + /* initialization errors */ + aac_enc_init_error_start = 0x2000, + AAC_ENC_INVALID_HANDLE = 0x2020, /*!< The handle passed to the function call was invalid (probably NULL). */ + AAC_ENC_INVALID_FRAME_LENGTH = 0x2080, /*!< Invalid frame length (must be 1024 or 960). */ + AAC_ENC_INVALID_N_CHANNELS = 0x20e0, /*!< Invalid amount of audio input channels. */ + AAC_ENC_INVALID_SFB_TABLE = 0x2140, /*!< Internal encoder error. */ + + AAC_ENC_UNSUPPORTED_AOT = 0x3000, /*!< The Audio Object Type (AOT) is not supported. */ + AAC_ENC_UNSUPPORTED_BITRATE = 0x3020, /*!< The chosen bitrate is not supported. */ + AAC_ENC_UNSUPPORTED_BITRATE_MODE = 0x3028, /*!< Unsupported bit rate mode (CBR or VBR). */ + AAC_ENC_UNSUPPORTED_ANC_BITRATE = 0x3040, /*!< Unsupported ancillay bitrate. */ + AAC_ENC_UNSUPPORTED_ANC_MODE = 0x3060, + AAC_ENC_UNSUPPORTED_TRANSPORT_TYPE = 0x3080, /*!< The bitstream format is not supported. */ + AAC_ENC_UNSUPPORTED_ER_FORMAT = 0x30a0, /*!< The error resilience tool format is not supported. */ + AAC_ENC_UNSUPPORTED_EPCONFIG = 0x30c0, /*!< The error protection format is not supported. */ + AAC_ENC_UNSUPPORTED_CHANNELCONFIG = 0x30e0, /*!< The channel configuration (either number or arrangement) is not supported. */ + AAC_ENC_UNSUPPORTED_SAMPLINGRATE = 0x3100, /*!< Sample rate of audio input is not supported. */ + AAC_ENC_NO_MEMORY = 0x3120, /*!< Could not allocate memory. */ + AAC_ENC_PE_INIT_TABLE_NOT_FOUND = 0x3140, /*!< Internal encoder error. */ + + aac_enc_init_error_end, + + /* encode errors */ + aac_enc_error_start = 0x4000, + AAC_ENC_QUANT_ERROR = 0x4020, /*!< Too many bits used in quantization. */ + AAC_ENC_WRITTEN_BITS_ERROR = 0x4040, /*!< Unexpected number of written bits, differs to + calculated number of bits. */ + AAC_ENC_PNS_TABLE_ERROR = 0x4060, /*!< PNS level out of range. */ + AAC_ENC_GLOBAL_GAIN_TOO_HIGH = 0x4080, /*!< Internal quantizer error. */ + AAC_ENC_BITRES_TOO_LOW = 0x40a0, /*!< Too few bits in bit reservoir. */ + AAC_ENC_BITRES_TOO_HIGH = 0x40a1, /*!< Too many bits in bit reservoir. */ + AAC_ENC_INVALID_CHANNEL_BITRATE = 0x4100, + AAC_ENC_INVALID_ELEMENTINFO_TYPE = 0x4120, /*!< Internal encoder error. */ + + AAC_ENC_WRITE_SCAL_ERROR = 0x41e0, /*!< Error writing scalefacData. */ + AAC_ENC_WRITE_SEC_ERROR = 0x4200, /*!< Error writing sectionData. */ + AAC_ENC_WRITE_SPEC_ERROR = 0x4220, /*!< Error writing spectralData. */ + aac_enc_error_end + +} AAC_ENCODER_ERROR; +/*-------------------------- defines --------------------------------------*/ + +#define ANC_DATA_BUFFERSIZE 1024 /* ancBuffer size */ +#define DEFAULT_FRAMELENGTH 1024 /* size of AAC core frame in (new) PCM samples */ + +#define MAX_TOTAL_EXT_PAYLOADS (((6) * (1)) + (2+2)) + + +typedef enum { + AACENC_BR_MODE_INVALID = -1, /*!< Invalid bitrate mode. */ + AACENC_BR_MODE_CBR = 0, /*!< Constant bitrate mode. */ + AACENC_BR_MODE_VBR_1 = 1, /*!< Variable bitrate mode, about 32 kbps/channel. */ + AACENC_BR_MODE_VBR_2 = 2, /*!< Variable bitrate mode, about 40 kbps/channel. */ + AACENC_BR_MODE_VBR_3 = 3, /*!< Variable bitrate mode, about 48-56 kbps/channel. */ + AACENC_BR_MODE_VBR_4 = 4, /*!< Variable bitrate mode, about 64 kbps/channel. */ + AACENC_BR_MODE_VBR_5 = 5, /*!< Variable bitrate mode, about 80-96 kbps/channel. */ + AACENC_BR_MODE_FF = 6, /*!< Fixed frame mode. */ + AACENC_BR_MODE_SFR = 7 /*!< Superframe mode. */ + +} AACENC_BITRATE_MODE; + +typedef enum { + + CH_ORDER_MPEG = 0, /*!< MPEG channel ordering (e. g. 5.1: C, L, R, SL, SR, LFE) */ + CH_ORDER_WAV /*!< WAV fileformat channel ordering (e. g. 5.1: L, R, C, LFE, SL, SR) */ + +} CHANNEL_ORDER; + +/*-------------------- structure definitions ------------------------------*/ + +struct AACENC_CONFIG { + INT sampleRate; /* encoder sample rate */ + INT bitRate; /* encoder bit rate in bits/sec */ + INT ancDataBitRate; /* additional bits consumed by anc data or sbr have to be consiedered while configuration */ + + INT nSubFrames; /* number of frames in super frame (not ADTS/LATM subframes !) */ + AUDIO_OBJECT_TYPE audioObjectType; /* Audio Object Type */ + + INT averageBits; /* encoder bit rate in bits/superframe */ + INT bitrateMode; /* encoder bitrate mode (CBR/VBR) */ + INT nChannels; /* number of channels to process */ + CHANNEL_ORDER channelOrder; /* Input Channel ordering scheme. */ + INT bandWidth; /* targeted audio bandwidth in Hz */ + CHANNEL_MODE channelMode; /* encoder channel mode configuration */ + INT framelength; /* used frame size */ + + UINT syntaxFlags; /* bitstreams syntax configuration */ + SCHAR epConfig; /* error protection configuration */ + + INT anc_Rate; /* ancillary rate, 0 (disabled), -1 (default) else desired rate */ + UINT maxAncBytesPerAU; + INT minBitsPerFrame; /* minimum number of bits in AU */ + INT maxBitsPerFrame; /* maximum number of bits in AU */ + INT bitreservoir; /* size of bitreservoir */ + + UCHAR useTns; /* flag: use temporal noise shaping */ + UCHAR usePns; /* flag: use perceptual noise substitution */ + UCHAR useIS; /* flag: use intensity coding */ + + UCHAR useRequant; /* flag: use afterburner */ +}; + +typedef struct { + UCHAR *pData; /* pointer to extension payload data */ + UINT dataSize; /* extension payload data size in bits */ + EXT_PAYLOAD_TYPE dataType; /* extension payload data type */ + INT associatedChElement; /* number of the channel element the data is assigned to */ +} AACENC_EXT_PAYLOAD; + +typedef struct AAC_ENC *HANDLE_AAC_ENC; + + /*----------------------------------------------------------------------------- + + functionname: FDKaacEnc_GetVBRBitrate + description: Get VBR bitrate from vbr quality + input params: int vbrQuality (VBR0, VBR1, VBR2) + channelMode + returns: vbr bitrate + + ------------------------------------------------------------------------------*/ + INT FDKaacEnc_GetVBRBitrate(INT bitrateMode, CHANNEL_MODE channelMode); + + +/*----------------------------------------------------------------------------- + + functionname: FDKaacEnc_AacInitDefaultConfig + description: gives reasonable default configuration + returns: --- + + ------------------------------------------------------------------------------*/ +void FDKaacEnc_AacInitDefaultConfig(AACENC_CONFIG *config); + +/*--------------------------------------------------------------------------- + + functionname:FDKaacEnc_Open + description: allocate and initialize a new encoder instance + returns: 0 if success + + ---------------------------------------------------------------------------*/ +AAC_ENCODER_ERROR FDKaacEnc_Open(HANDLE_AAC_ENC *phAacEnc, /* pointer to an encoder handle, initialized on return */ + const INT nElements, /* number of maximal elements in instance to support */ + const INT nChannels, /* number of maximal channels in instance to support */ + const INT nSubFrames); /* support superframing in instance */ + + +AAC_ENCODER_ERROR FDKaacEnc_Initialize(HANDLE_AAC_ENC hAacEncoder, /* pointer to an encoder handle, initialized on return */ + AACENC_CONFIG *config, /* pre-initialized config struct */ + HANDLE_TRANSPORTENC hTpEnc, + ULONG initFlags); + + +/*--------------------------------------------------------------------------- + + functionname: FDKaacEnc_EncodeFrame + description: encode one frame + returns: 0 if success + + ---------------------------------------------------------------------------*/ + +AAC_ENCODER_ERROR FDKaacEnc_EncodeFrame( HANDLE_AAC_ENC hAacEnc, /* encoder handle */ + HANDLE_TRANSPORTENC hTpEnc, + INT_PCM* inputBuffer, + INT* numOutBytes, + AACENC_EXT_PAYLOAD extPayload[MAX_TOTAL_EXT_PAYLOADS] + ); + +/*--------------------------------------------------------------------------- + + functionname:FDKaacEnc_Close + description: delete encoder instance + returns: + + ---------------------------------------------------------------------------*/ + +void FDKaacEnc_Close( HANDLE_AAC_ENC* phAacEnc); /* encoder handle */ + +#ifdef __cplusplus +} +#endif + +#endif /* _aacenc_h_ */ + diff --git a/libAACenc/src/aacenc_hcr.cpp b/libAACenc/src/aacenc_hcr.cpp new file mode 100644 index 0000000..d648847 --- /dev/null +++ b/libAACenc/src/aacenc_hcr.cpp @@ -0,0 +1,31 @@ +/*************************** MPEG AAC Audio Encoder ************************* + + (C) Copyright Fraunhofer IIS (2000-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: R. Boehm + contents/description: huffman codeword reordering + based on source from aacErrRobTrans + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "aacenc_hcr.h" + diff --git a/libAACenc/src/aacenc_hcr.h b/libAACenc/src/aacenc_hcr.h new file mode 100644 index 0000000..b6bd5b8 --- /dev/null +++ b/libAACenc/src/aacenc_hcr.h @@ -0,0 +1,33 @@ +/*************************** MPEG AAC Audio Encoder ************************* + + (C) Copyright Fraunhofer IIS (2000-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: R. Boehm + contents/description: huffman codeword reordering + based on source from aacErrRobTrans + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#ifndef _AACENC_HCR +#define _AACENC_HCR_H + + +#endif /* ifndef _AACENC_HCR */ diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp new file mode 100644 index 0000000..65a9bfc --- /dev/null +++ b/libAACenc/src/aacenc_lib.cpp @@ -0,0 +1,1696 @@ +/**************************** MPEG-4 HE-AAC Encoder ************************* + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Lohwasser + contents/description: FDK HE-AAC Encoder interface library functions + +****************************************************************************/ + +#include "aacenc_lib.h" +#include "FDK_audio.h" +#include "aacenc.h" + +#include "aacEnc_ram.h" +#include "FDK_core.h" /* FDK_tools versioning info */ + +/* Encoder library info */ +#define AACENCODER_LIB_VL0 3 +#define AACENCODER_LIB_VL1 3 +#define AACENCODER_LIB_VL2 0 +#define AACENCODER_LIB_TITLE "AAC Encoder" +#define AACENCODER_LIB_BUILD_DATE __DATE__ +#define AACENCODER_LIB_BUILD_TIME __TIME__ + + +#include "sbr_encoder.h" +#include "../src/sbr_ram.h" +#include "channel_map.h" + +#include "psy_const.h" +#include "bitenc.h" + +#include "tpenc_lib.h" + +#include "metadata_main.h" + +#define SBL(fl) (fl/8) /*!< Short block length (hardcoded to 8 short blocks per long block) */ +#define BSLA(fl) (4*SBL(fl)+SBL(fl)/2) /*!< AAC block switching look-ahead */ +#define DELAY_AAC(fl) (fl+BSLA(fl)) /*!< MDCT + blockswitching */ +#define DELAY_AACELD(fl) ( (fl) + ((fl)/2) ) /*!< ELD FB delay */ + +#define INPUTBUFFER_SIZE (1537+100+2048) + +//////////////////////////////////////////////////////////////////////////////////// +/** + * Flags to characterize encoder modules to be supported in present instance. + */ +enum { + ENC_MODE_FLAG_AAC = 0x0001, + ENC_MODE_FLAG_SBR = 0x0002, + ENC_MODE_FLAG_PS = 0x0004, + ENC_MODE_FLAG_SAC = 0x0008, + ENC_MODE_FLAG_META = 0x0010 +}; + +//////////////////////////////////////////////////////////////////////////////////// +typedef struct { + AUDIO_OBJECT_TYPE userAOT; /*!< Audio Object Type. */ + UINT userSamplerate; /*!< Sampling frequency. */ + UINT nChannels; /*!< will be set via channelMode. */ + CHANNEL_MODE userChannelMode; + UINT userBitrate; + UINT userBitrateMode; + UINT userBandwidth; + UINT userAfterburner; + UINT userFramelength; + UINT userAncDataRate; + + UCHAR userTns; /*!< Use TNS coding. */ + UCHAR userPns; /*!< Use PNS coding. */ + UCHAR userIntensity; /*!< Use Intensity coding. */ + + TRANSPORT_TYPE userTpType; /*!< Transport type */ + UCHAR userTpSignaling; /*!< Extension AOT signaling mode. */ + UCHAR userTpNsubFrames; /*!< Number of sub frames in a transport frame for LOAS/LATM or ADTS (default 1). */ + UCHAR userTpAmxv; /*!< AudioMuxVersion to be used for LATM (default 0). */ + UCHAR userTpProtection; + UCHAR userTpHeaderPeriod; /*!< Parameter used to configure LATM/LOAS SMC rate. Moreover this parameters is + used to configure repetition rate of PCE in raw_data_block. */ + + UCHAR userErTools; /*!< Use VCB11, HCR and/or RVLC ER tool. */ + UINT userPceAdditions; /*!< Configure additional bits in PCE. */ + + UCHAR userMetaDataMode; /*!< Meta data library configuration. */ + + UCHAR userSbrEnabled; + +} USER_PARAM; + +//////////////////////////////////////////////////////////////////////////////////// + +/**************************************************************************** + Structure Definitions +****************************************************************************/ + +typedef struct AACENC_CONFIG *HANDLE_AACENC_CONFIG; + + +struct AACENCODER +{ + USER_PARAM extParam; + CODER_CONFIG coderConfig; + + /* AAC */ + AACENC_CONFIG aacConfig; + HANDLE_AAC_ENC hAacEnc; + + /* SBR */ + HANDLE_SBR_ENCODER hEnvEnc; + + /* Meta Data */ + HANDLE_FDK_METADATA_ENCODER hMetadataEnc; + INT metaDataAllowed; /* Signal whether chosen configuration allows metadata. Necessary for delay + compensation. Metadata mode is a separate parameter. */ + + /* Transport */ + HANDLE_TRANSPORTENC hTpEnc; + + /* Output */ + UCHAR *outBuffer; /* Internal bitstream buffer */ + INT outBufferInBytes; /* Size of internal bitstream buffer*/ + + /* Input */ + INT_PCM *inputBuffer; /* Internal input buffer. Input source for AAC encoder */ + INT inputBufferOffset; /* Where to write new input samples. */ + + INT nSamplesToRead; /* number of input samples neeeded for encoding one frame */ + INT nSamplesRead; /* number of input samples already in input buffer */ + INT nZerosAppended; /* appended zeros at end of file*/ + INT nDelay; /* encoder delay */ + + AACENC_EXT_PAYLOAD extPayload [MAX_TOTAL_EXT_PAYLOADS]; + /* Extension payload */ + UCHAR extPayloadData [(1)][(6)][MAX_PAYLOAD_SIZE]; + UINT extPayloadSize [(1)][(6)]; /* payload sizes in bits */ + + ULONG InitFlags; /* internal status to treggier re-initialization */ + + + /* Memory allocation info. */ + INT nMaxAacElements; + INT nMaxAacChannels; + INT nMaxSbrElements; + INT nMaxSbrChannels; + UINT nMaxSubFrames; + + UINT encoder_modis; + + /* Capabity flags */ + UINT CAPF_tpEnc; + +} ; + +//////////////////////////////////////////////////////////////////////////////////// + +static inline INT isSbrActive(const HANDLE_AACENC_CONFIG hAacConfig) +{ + INT sbrUsed = 0; + + if ( (hAacConfig->audioObjectType==AOT_SBR) || (hAacConfig->audioObjectType==AOT_PS) + || (hAacConfig->audioObjectType==AOT_MP2_SBR) || (hAacConfig->audioObjectType==AOT_MP2_PS) + || (hAacConfig->audioObjectType==AOT_DABPLUS_SBR) || (hAacConfig->audioObjectType==AOT_DABPLUS_PS) + || (hAacConfig->audioObjectType==AOT_DRM_SBR) || (hAacConfig->audioObjectType==AOT_DRM_MPEG_PS) ) + { + sbrUsed = 1; + } + if (hAacConfig->audioObjectType == AOT_ER_AAC_ELD && (hAacConfig->syntaxFlags & AC_SBR_PRESENT)) + { + sbrUsed = 1; + } + + return ( sbrUsed ); +} + +/**************************************************************************** + Allocate Encoder +****************************************************************************/ + +H_ALLOC_MEM (_AacEncoder, AACENCODER) +C_ALLOC_MEM (_AacEncoder, AACENCODER, 1) + + + + +/* + * Map Encoder specific config structures to CODER_CONFIG. + */ +static +void FDKaacEnc_MapConfig(CODER_CONFIG *cc, USER_PARAM *extCfg, HANDLE_AACENC_CONFIG hAacConfig) +{ + AUDIO_OBJECT_TYPE transport_AOT = AOT_NULL_OBJECT; + FDKmemclear(cc, sizeof(CODER_CONFIG)); + + cc->flags = 0; + + /* Map virtual aot to transport aot. */ + switch (hAacConfig->audioObjectType) { + case AOT_MP2_AAC_LC: + transport_AOT = AOT_AAC_LC; + break; + case AOT_MP2_SBR: + transport_AOT = AOT_SBR; + cc->flags |= CC_SBR; + break; + case AOT_MP2_PS: + transport_AOT = AOT_PS; + cc->flags |= CC_SBR; + break; + default: + transport_AOT = hAacConfig->audioObjectType; + } + + if (hAacConfig->audioObjectType == AOT_ER_AAC_ELD) { + cc->flags |= (hAacConfig->syntaxFlags & AC_SBR_PRESENT) ? CC_SBR : 0; + } + + /* transport type is usually AAC-LC. */ + if ( (transport_AOT == AOT_SBR) || (transport_AOT == AOT_PS) ) { + cc->aot = AOT_AAC_LC; + } + else { + cc->aot = transport_AOT; + } + + /* Configure extension aot. */ + if (extCfg->userTpSignaling==0) { + cc->extAOT = AOT_NULL_OBJECT; /* implicit */ + } + else { + if ( (extCfg->userTpSignaling==1) && ( (transport_AOT==AOT_SBR) || (transport_AOT==AOT_PS) ) ) { + cc->extAOT = AOT_SBR; /* explicit backward compatible */ + } + else { + cc->extAOT = transport_AOT; /* explicit hierarchical */ + } + } + cc->extSamplingRate = extCfg->userSamplerate; + cc->bitRate = hAacConfig->bitRate; + cc->noChannels = hAacConfig->nChannels; + cc->flags |= CC_IS_BASELAYER; + cc->channelMode = hAacConfig->channelMode; + + cc->nSubFrames = (hAacConfig->nSubFrames > 1 && extCfg->userTpNsubFrames == 1) + ? hAacConfig->nSubFrames + : extCfg->userTpNsubFrames; + + cc->flags |= (extCfg->userTpProtection) ? CC_PROTECTION : 0; + + if (extCfg->userTpHeaderPeriod!=0xFF) { + cc->headerPeriod = extCfg->userTpHeaderPeriod; + } + else { /* auto-mode */ + switch (extCfg->userTpType) { + case TT_MP4_ADTS: + case TT_MP4_LOAS: + case TT_MP4_LATM_MCP1: + cc->headerPeriod = 10; + break; + default: + cc->headerPeriod = 0; + } + } + + cc->samplesPerFrame = hAacConfig->framelength; + cc->samplingRate = hAacConfig->sampleRate; + + /* Mpeg-4 signaling for transport library. */ + switch ( hAacConfig->audioObjectType ) { + case AOT_MP2_AAC_LC: + case AOT_MP2_SBR: + case AOT_MP2_PS: + cc->flags &= ~CC_MPEG_ID; /* Required for ADTS. */ + //config->userTpSignaling=0; + cc->extAOT = AOT_NULL_OBJECT; + break; + default: + cc->flags |= CC_MPEG_ID; + } + + /* ER-tools signaling. */ + cc->flags |= (hAacConfig->syntaxFlags & AC_ER_VCB11) ? CC_VCB11 : 0; + cc->flags |= (hAacConfig->syntaxFlags & AC_ER_HCR) ? CC_HCR : 0; + cc->flags |= (hAacConfig->syntaxFlags & AC_ER_RVLC) ? CC_RVLC : 0; + + /* Matrix mixdown coefficient configuration. */ + if ( (extCfg->userPceAdditions&0x1) && (hAacConfig->epConfig==-1) + && ((cc->channelMode==MODE_1_2_2)||(cc->channelMode==MODE_1_2_2_1)) ) + { + cc->matrixMixdownA = ((extCfg->userPceAdditions>>1)&0x3)+1; + cc->flags |= (extCfg->userPceAdditions>>3)&0x1 ? CC_PSEUDO_SURROUND : 0; + } + else { + cc->matrixMixdownA = 0; + } +} + +/* + * Examine buffer descriptor regarding choosen identifier. + * + * \param pBufDesc Pointer to buffer descriptor + * \param identifier Buffer identifier to look for. + + * \return - Buffer descriptor index. + * -1, if there is no entry available. + */ +static INT getBufDescIdx( + const AACENC_BufDesc *pBufDesc, + const AACENC_BufferIdentifier identifier +) +{ + INT i, idx = -1; + + for (i=0; inumBufs; i++) { + if ( (AACENC_BufferIdentifier)pBufDesc->bufferIdentifiers[i] == identifier ) { + idx = i; + break; + } + } + return idx; +} + + +/**************************************************************************** + Function Declarations +****************************************************************************/ + +AAC_ENCODER_ERROR aacEncDefaultConfig(HANDLE_AACENC_CONFIG hAacConfig, + USER_PARAM *config) +{ + /* make reasonable default settings */ + FDKaacEnc_AacInitDefaultConfig (hAacConfig); + + /* clear confure structure and copy default settings */ + FDKmemclear(config, sizeof(USER_PARAM)); + + /* copy encoder configuration settings */ + config->nChannels = hAacConfig->nChannels; + config->userAOT = hAacConfig->audioObjectType = AOT_AAC_LC; + config->userSamplerate = hAacConfig->sampleRate; + config->userChannelMode = hAacConfig->channelMode; + config->userBitrate = hAacConfig->bitRate; + config->userBitrateMode = hAacConfig->bitrateMode; + config->userBandwidth = hAacConfig->bandWidth; + config->userTns = hAacConfig->useTns; + config->userPns = hAacConfig->usePns; + config->userIntensity = hAacConfig->useIS; + config->userAfterburner = hAacConfig->useRequant; + config->userFramelength = (UINT)-1; + + if (hAacConfig->syntaxFlags & AC_ER_VCB11) { + config->userErTools |= 0x01; + } + if (hAacConfig->syntaxFlags & AC_ER_HCR) { + config->userErTools |= 0x02; + } + + /* initialize transport parameters */ + config->userTpType = TT_UNKNOWN; + config->userTpAmxv = 0; + config->userTpSignaling = 0; /* default, implicit signaling */ + config->userTpNsubFrames = 1; + config->userTpProtection = 0; /* not crc protected*/ + config->userTpHeaderPeriod = 0xFF; /* header period in auto mode */ + config->userPceAdditions = 0; /* no matrix mixdown coefficient */ + config->userMetaDataMode = 0; /* do not embed any meta data info */ + + config->userAncDataRate = 0; + + return AAC_ENC_OK; +} + +/* + * \brief Consistency check of given USER_PARAM struct and + * copy back configuration from public struct into internal + * encoder configuration struct. + * + * \hAacEncoder Internal encoder config which is to be updated + * \param config User provided config (public struct) + * \return ´returns always AAC_ENC_OK + */ +static +AACENC_ERROR FDKaacEnc_AdjustEncSettings(HANDLE_AACENCODER hAacEncoder, + USER_PARAM *config) +{ + AACENC_ERROR err = AACENC_OK; + + /* Get struct pointers. */ + HANDLE_AACENC_CONFIG hAacConfig = &hAacEncoder->aacConfig; + + hAacConfig->nChannels = config->nChannels; + + /* Encoder settings update. */ + hAacConfig->sampleRate = config->userSamplerate; + hAacConfig->useTns = config->userTns; + hAacConfig->usePns = config->userPns; + hAacConfig->useIS = config->userIntensity; + hAacConfig->bitRate = config->userBitrate; + hAacConfig->channelMode = config->userChannelMode; + hAacConfig->bitrateMode = config->userBitrateMode; + hAacConfig->bandWidth = config->userBandwidth; + hAacConfig->useRequant = config->userAfterburner; + + hAacConfig->audioObjectType = config->userAOT; + hAacConfig->anc_Rate = config->userAncDataRate; + hAacConfig->syntaxFlags = 0; + hAacConfig->epConfig = -1; + + /* Adapt internal AOT when necessary. */ + switch ( hAacConfig->audioObjectType ) { + case AOT_MP2_AAC_LC: + case AOT_MP2_SBR: + case AOT_MP2_PS: + hAacConfig->usePns = 0; + if (config->userTpSignaling!=0) { + return AACENC_INVALID_CONFIG; /* only implicit signaling allowed */ + } + case AOT_AAC_LC: + case AOT_SBR: + case AOT_PS: + config->userTpType = (config->userTpType!=TT_UNKNOWN) ? config->userTpType : TT_MP4_ADTS; + hAacConfig->framelength = (config->userFramelength!=(UINT)-1) ? config->userFramelength : 1024; + if (hAacConfig->framelength != 1024 && hAacConfig->framelength != 960) { + return AACENC_INVALID_CONFIG; + } + break; + case AOT_ER_AAC_LC: + hAacConfig->epConfig = 0; + hAacConfig->syntaxFlags |= AC_ER; + hAacConfig->syntaxFlags |= ((config->userErTools & 0x1) ? AC_ER_VCB11 : 0); + hAacConfig->syntaxFlags |= ((config->userErTools & 0x2) ? AC_ER_HCR : 0); + config->userTpType = (config->userTpType!=TT_UNKNOWN) ? config->userTpType : TT_MP4_LOAS; + hAacConfig->framelength = (config->userFramelength!=(UINT)-1) ? config->userFramelength : 1024; + if (hAacConfig->framelength != 1024 && hAacConfig->framelength != 960) { + return AACENC_INVALID_CONFIG; + } + break; + case AOT_ER_AAC_LD: + hAacConfig->epConfig = 0; + hAacConfig->syntaxFlags |= AC_ER|AC_LD; + hAacConfig->syntaxFlags |= ((config->userErTools & 0x1) ? AC_ER_VCB11 : 0); + hAacConfig->syntaxFlags |= ((config->userErTools & 0x2) ? AC_ER_HCR : 0); + hAacConfig->syntaxFlags |= ((config->userErTools & 0x4) ? AC_ER_RVLC : 0); + config->userTpType = (config->userTpType!=TT_UNKNOWN) ? config->userTpType : TT_MP4_LOAS; + hAacConfig->framelength = (config->userFramelength!=(UINT)-1) ? config->userFramelength : 512; + if (hAacConfig->framelength != 512 && hAacConfig->framelength != 480) { + return AACENC_INVALID_CONFIG; + } + break; + case AOT_ER_AAC_ELD: + hAacConfig->epConfig = 0; + hAacConfig->syntaxFlags |= AC_ER|AC_ELD; + hAacConfig->syntaxFlags |= ((config->userErTools & 0x1) ? AC_ER_VCB11 : 0); + hAacConfig->syntaxFlags |= ((config->userErTools & 0x2) ? AC_ER_HCR : 0); + hAacConfig->syntaxFlags |= ((config->userErTools & 0x4) ? AC_ER_RVLC : 0); + hAacConfig->syntaxFlags |= ((config->userSbrEnabled) ? AC_SBR_PRESENT : 0); + config->userTpType = (config->userTpType!=TT_UNKNOWN) ? config->userTpType : TT_MP4_LOAS; + hAacConfig->framelength = (config->userFramelength!=(UINT)-1) ? config->userFramelength : 512; + if (hAacConfig->framelength != 512 && hAacConfig->framelength != 480) { + return AACENC_INVALID_CONFIG; + } + break; + default: + break; + } + + switch ( hAacConfig->audioObjectType ) { + case AOT_ER_AAC_LD: + case AOT_ER_AAC_ELD: + if (config->userBitrateMode==8) { + hAacConfig->bitrateMode = 0; + } + if (config->userBitrateMode==0) { + hAacConfig->bitreservoir = 50*config->nChannels; /* default, reduced bitreservoir */ + } + if (hAacConfig->bitrateMode!=0) { + return AACENC_INVALID_CONFIG; + } + break; + default: + break; + } + + if (hAacConfig->epConfig >= 0) { + hAacConfig->syntaxFlags |= AC_ER; + if (((INT)hAacConfig->channelMode < 1) || ((INT)hAacConfig->channelMode > 7)) { + return AACENC_INVALID_CONFIG; /* Cannel config 0 not supported. */ + } + } + + if ( FDKaacEnc_DetermineEncoderMode(&hAacConfig->channelMode, hAacConfig->nChannels) != AAC_ENC_OK) { + return AACENC_INVALID_CONFIG; /* nChannels doesn't match chMode, this is just a check-up */ + } + + if ( (hAacConfig->nChannels > hAacEncoder->nMaxAacChannels) + || ( (FDKaacEnc_GetChannelModeConfiguration(hAacConfig->channelMode)->nChannelsEff > hAacEncoder->nMaxSbrChannels) && + isSbrActive(hAacConfig) ) + ) + { + return AACENC_INVALID_CONFIG; /* not enough channels allocated */ + } + + /* get bitrate in VBR configuration */ + if ( (hAacConfig->bitrateMode>=1) && (hAacConfig->bitrateMode<=5) ) { + /* In VBR mode; SBR-modul depends on bitrate, core encoder on bitrateMode. */ + hAacConfig->bitRate = FDKaacEnc_GetVBRBitrate(hAacConfig->bitrateMode, hAacConfig->channelMode); + } + + + + /* Set default bitrate if no external bitrate declared. */ + if (hAacConfig->bitRate==-1) { + INT bitrate = FDKaacEnc_GetChannelModeConfiguration(hAacConfig->channelMode)->nChannelsEff * hAacConfig->sampleRate; + switch (hAacConfig->audioObjectType) + { + case AOT_AAC_LC: + hAacConfig->bitRate = bitrate + (bitrate>>1); /* 1.5 bits per sample */ + break; + case AOT_SBR: + hAacConfig->bitRate = (bitrate + (bitrate>>2))>>1; /* 0.625 bits per sample */ + break; + case AOT_PS: + hAacConfig->bitRate = (bitrate>>1); /* 0.5 bit per sample */ + break; + default: + hAacConfig->bitRate = bitrate; + break; + } + } + + /* Configure PNS */ + if ( ((hAacConfig->bitrateMode>=1) && (hAacConfig->bitrateMode<=5)) /* VBR without PNS. */ + || (hAacConfig->useTns == 0) ) /* TNS required. */ + { + hAacConfig->usePns = 0; + } + + /* Meta data restriction. */ + switch (hAacConfig->audioObjectType) + { + /* Allow metadata support */ + case AOT_AAC_LC: + case AOT_SBR: + hAacEncoder->metaDataAllowed = 1; + if (((INT)hAacConfig->channelMode < 1) || ((INT)hAacConfig->channelMode > 7)) { + config->userMetaDataMode = 0; + } + break; + /* Prohibit metadata support */ + default: + hAacEncoder->metaDataAllowed = 0; + } + + return err; +} + +static +INT aacenc_SbrCallback( + void * self, + HANDLE_FDK_BITSTREAM hBs, + const INT sampleRateIn, + const INT sampleRateOut, + const INT samplesPerFrame, + const AUDIO_OBJECT_TYPE coreCodec, + const MP4_ELEMENT_ID elementID, + const INT elementIndex + ) +{ + HANDLE_AACENCODER hAacEncoder = (HANDLE_AACENCODER)self; + + sbrEncoder_GetHeader(hAacEncoder->hEnvEnc, hBs, elementIndex, 0); + + return 0; +} + +static AACENC_ERROR aacEncInit(HANDLE_AACENCODER hAacEncoder, + ULONG InitFlags, + USER_PARAM *config) +{ + AACENC_ERROR err = AACENC_OK; + + INT aacBufferOffset = 0; + HANDLE_SBR_ENCODER *hSbrEncoder = &hAacEncoder->hEnvEnc; + HANDLE_AACENC_CONFIG hAacConfig = &hAacEncoder->aacConfig; + + hAacEncoder->nZerosAppended = 0; /* count appended zeros */ + + INT frameLength = hAacConfig->framelength; + + + if ( (InitFlags & AACENC_INIT_CONFIG) ) + { + CHANNEL_MODE prevChMode = hAacConfig->channelMode; + + /* Verify settings and update: config -> heAacEncoder */ + if ( (err=FDKaacEnc_AdjustEncSettings(hAacEncoder, config)) != AACENC_OK ) { + return err; + } + frameLength = hAacConfig->framelength; /* adapt temporal framelength */ + + /* Seamless channel reconfiguration in sbr not fully implemented */ + if ( (prevChMode!=hAacConfig->channelMode) && isSbrActive(hAacConfig) ) { + InitFlags |= AACENC_INIT_STATES; + } + } + + /* Clear input buffer */ + if ( (InitFlags == AACENC_INIT_ALL) ) { + FDKmemclear(hAacEncoder->inputBuffer, sizeof(INT_PCM)*hAacEncoder->nMaxAacChannels*INPUTBUFFER_SIZE); + } + + if ( (InitFlags & AACENC_INIT_CONFIG) ) + { + aacBufferOffset = 0; + if (hAacConfig->audioObjectType == AOT_ER_AAC_ELD) { + hAacEncoder->nDelay = DELAY_AACELD(hAacConfig->framelength); + } else + { + hAacEncoder->nDelay = DELAY_AAC(hAacConfig->framelength); /* AAC encoder delay */ + } + hAacConfig->ancDataBitRate = 0; + } + + if ( isSbrActive(hAacConfig) && + ((InitFlags & AACENC_INIT_CONFIG) || (InitFlags & AACENC_INIT_STATES)) ) + { + INT sbrError; + SBR_ELEMENT_INFO sbrElInfo[(6)]; + CHANNEL_MAPPING channelMapping; + int el; + INT codebits = hAacConfig->bitRate; + INT bitrateSc = CountLeadingBits(codebits); + AUDIO_OBJECT_TYPE aot = hAacConfig->audioObjectType; + + if ( FDKaacEnc_InitChannelMapping(hAacConfig->channelMode, + hAacConfig->channelOrder, + &channelMapping) != AAC_ENC_OK ) + { + return AACENC_INIT_ERROR; + } + + /* Check return value and if the SBR encoder can handle enough elements */ + if (channelMapping.nElements > (6)) { + return AACENC_INIT_ERROR; + } + + /* Copy Element info */ + for (el=0; elbitRate<>(bitrateSc)); + sbrElInfo[el].instanceTag = channelMapping.elInfo[el].instanceTag; + sbrElInfo[el].nChannelsInEl = channelMapping.elInfo[el].nChannelsInEl; + + sbrElInfo[el].bitRate = fMult(channelMapping.elInfo[el].relativeBits, (FIXP_DBL)hAacConfig->bitRate); + codebits -= sbrElInfo[el].bitRate; + } + sbrElInfo[0].bitRate += codebits; + + UINT initFlag = 0; + initFlag += (InitFlags & AACENC_INIT_STATES) ? 1 : 0; + + /* Let the SBR encoder take a look at the configuration and change if required. */ + sbrError = sbrEncoder_Init( + *hSbrEncoder, + sbrElInfo, + channelMapping.nElements, + hAacEncoder->inputBuffer, + &hAacConfig->bandWidth, + &aacBufferOffset, + &hAacConfig->nChannels, + &hAacConfig->sampleRate, + &frameLength, + &hAacConfig->audioObjectType, + &hAacEncoder->nDelay, + (hAacConfig->audioObjectType == AOT_ER_AAC_ELD) ? 1 : TRANS_FAC, + initFlag + ); + + /* Suppress AOT reconfiguration and check error status. */ + if ( sbrError || (hAacConfig->audioObjectType!=aot) ) { + return AACENC_INIT_SBR_ERROR; + } + + if (hAacConfig->nChannels == 1) { + hAacConfig->channelMode = MODE_1; + } + + /* Never use PNS if SBR is active */ + if ( hAacConfig->usePns ) { + hAacConfig->usePns = 0; + } + + /* estimated bitrate consumed by SBR or PS */ + hAacConfig->ancDataBitRate = sbrEncoder_GetEstimateBitrate(*hSbrEncoder) ; + + } /* sbr initialization */ + + + /* + * Initialize Transport - Module. + */ + if ( (InitFlags & AACENC_INIT_TRANSPORT) ) + { + UINT flags = 0; + + FDKaacEnc_MapConfig(&hAacEncoder->coderConfig, config, hAacConfig); + + /* create flags for transport encoder */ + if (config->userTpAmxv == 1) { + flags |= TP_FLAG_LATM_AMV; + } + /* Clear output buffer */ + FDKmemclear(hAacEncoder->outBuffer, hAacEncoder->outBufferInBytes*sizeof(UCHAR)); + + /* Initialize Bitstream encoder */ + if ( transportEnc_Init(hAacEncoder->hTpEnc, hAacEncoder->outBuffer, hAacEncoder->outBufferInBytes, config->userTpType, &hAacEncoder->coderConfig, flags) != 0) { + return AACENC_INIT_TP_ERROR; + } + + } /* transport initialization */ + + /* + * Initialize AAC - Core. + */ + if ( (InitFlags & AACENC_INIT_CONFIG) || + (InitFlags & AACENC_INIT_STATES) ) + { + AAC_ENCODER_ERROR err; + err = FDKaacEnc_Initialize(hAacEncoder->hAacEnc, + hAacConfig, + hAacEncoder->hTpEnc, + (InitFlags & AACENC_INIT_STATES) ? 1 : 0); + + if (err != AAC_ENC_OK) { + return AACENC_INIT_AAC_ERROR; + } + + } /* aac initialization */ + + /* + * Initialize Meta Data - Encoder. + */ + if ( hAacEncoder->hMetadataEnc && (hAacEncoder->metaDataAllowed!=0) && + ((InitFlags & AACENC_INIT_CONFIG) ||(InitFlags & AACENC_INIT_STATES)) ) + { + INT inputDataDelay = DELAY_AAC(hAacConfig->framelength); + + if ( isSbrActive(hAacConfig) && hSbrEncoder!=NULL) { + inputDataDelay = 2*inputDataDelay + sbrEncoder_GetInputDataDelay(*hSbrEncoder); + } + + if ( FDK_MetadataEnc_Init(hAacEncoder->hMetadataEnc, + ((InitFlags&AACENC_INIT_STATES) ? 1 : 0), + config->userMetaDataMode, + inputDataDelay, + frameLength, + config->userSamplerate, + config->nChannels, + config->userChannelMode, + hAacConfig->channelOrder) != 0) + { + return AACENC_INIT_META_ERROR; + } + + hAacEncoder->nDelay += FDK_MetadataEnc_GetDelay(hAacEncoder->hMetadataEnc); + } + + /* + * Update pointer to working buffer. + */ + if ( (InitFlags & AACENC_INIT_CONFIG) ) + { + hAacEncoder->inputBufferOffset = aacBufferOffset; + + hAacEncoder->nSamplesToRead = frameLength * config->nChannels; + + /* Make nDelay comparison compatible with config->nSamplesRead */ + hAacEncoder->nDelay *= config->nChannels; + + } /* parameter changed */ + + return AACENC_OK; +} + + +AACENC_ERROR aacEncOpen( + HANDLE_AACENCODER *phAacEncoder, + const UINT encModules, + const UINT maxChannels + ) +{ + AACENC_ERROR err = AACENC_OK; + HANDLE_AACENCODER hAacEncoder = NULL; + + if (phAacEncoder == NULL) { + err = AACENC_INVALID_HANDLE; + goto bail; + } + + /* allocate memory */ + hAacEncoder = Get_AacEncoder(); + + if (hAacEncoder == NULL) { + err = AACENC_MEMORY_ERROR; + goto bail; + } + + FDKmemclear(hAacEncoder, sizeof(AACENCODER)); + + /* Specify encoder modules to be allocated. */ + if (encModules==0) { + hAacEncoder->encoder_modis = ENC_MODE_FLAG_AAC; + hAacEncoder->encoder_modis |= ENC_MODE_FLAG_SBR; + hAacEncoder->encoder_modis |= ENC_MODE_FLAG_PS; + hAacEncoder->encoder_modis |= ENC_MODE_FLAG_META; + } + else { + /* consider SAC and PS module */ + hAacEncoder->encoder_modis = encModules; + } + + /* Determine max channel configuration. */ + if (maxChannels==0) { + hAacEncoder->nMaxAacChannels = (6); + hAacEncoder->nMaxSbrChannels = (6); + } + else { + hAacEncoder->nMaxAacChannels = (maxChannels&0x00FF); + if ( (hAacEncoder->encoder_modis&ENC_MODE_FLAG_SBR) ) { + hAacEncoder->nMaxSbrChannels = (maxChannels&0xFF00) ? (maxChannels>>8) : hAacEncoder->nMaxAacChannels; + } + + if ( (hAacEncoder->nMaxAacChannels>(6)) || (hAacEncoder->nMaxSbrChannels>(6)) ) { + err = AACENC_INVALID_CONFIG; + goto bail; + } + } /* maxChannels==0 */ + + /* Max number of elements could be tuned any more. */ + hAacEncoder->nMaxAacElements = fixMin((6), hAacEncoder->nMaxAacChannels); + hAacEncoder->nMaxSbrElements = fixMin((6), hAacEncoder->nMaxSbrChannels); + hAacEncoder->nMaxSubFrames = (1); + + + /* In case of memory overlay, allocate memory out of libraries */ + + hAacEncoder->inputBuffer = (INT_PCM*)FDKcalloc(hAacEncoder->nMaxAacChannels*INPUTBUFFER_SIZE, sizeof(INT_PCM)); + + /* Open SBR Encoder */ + if (hAacEncoder->encoder_modis&ENC_MODE_FLAG_SBR) { + if ( sbrEncoder_Open(&hAacEncoder->hEnvEnc, + hAacEncoder->nMaxSbrElements, + hAacEncoder->nMaxSbrChannels, + (hAacEncoder->encoder_modis&ENC_MODE_FLAG_PS) ? 1 : 0 ) ) + { + err = AACENC_MEMORY_ERROR; + goto bail; + } + } /* (encoder_modis&ENC_MODE_FLAG_SBR) */ + + + /* Open Aac Encoder */ + if ( FDKaacEnc_Open(&hAacEncoder->hAacEnc, + hAacEncoder->nMaxAacElements, + hAacEncoder->nMaxAacChannels, + (1)) != AAC_ENC_OK ) + { + err = AACENC_MEMORY_ERROR; + goto bail; + } + + { /* Get bitstream outputbuffer size */ + UINT ld_M; + for (ld_M=1; (UINT)(1<nMaxSubFrames*hAacEncoder->nMaxAacChannels*6144)>>3; ld_M++) ; + hAacEncoder->outBufferInBytes = (1<outBuffer = GetRam_bsOutbuffer(); + if (OUTPUTBUFFER_SIZE < hAacEncoder->outBufferInBytes ) { + err = AACENC_MEMORY_ERROR; + goto bail; + } + + /* Open Meta Data Encoder */ + if (hAacEncoder->encoder_modis&ENC_MODE_FLAG_META) { + if ( FDK_MetadataEnc_Open(&hAacEncoder->hMetadataEnc) ) + { + err = AACENC_MEMORY_ERROR; + goto bail; + } + } /* (encoder_modis&ENC_MODE_FLAG_META) */ + + /* Open Transport Encoder */ + if ( transportEnc_Open(&hAacEncoder->hTpEnc) != 0 ) + { + err = AACENC_MEMORY_ERROR; + goto bail; + } + else { + C_ALLOC_SCRATCH_START(pLibInfo, LIB_INFO, FDK_MODULE_LAST); + + FDKinitLibInfo( pLibInfo); + transportEnc_GetLibInfo( pLibInfo ); + + /* Get capabilty flag for transport encoder. */ + hAacEncoder->CAPF_tpEnc = FDKlibInfo_getCapabilities( pLibInfo, FDK_TPENC); + + C_ALLOC_SCRATCH_END(pLibInfo, LIB_INFO, FDK_MODULE_LAST); + } + if ( transportEnc_RegisterSbrCallback(hAacEncoder->hTpEnc, aacenc_SbrCallback, hAacEncoder) != 0 ) { + err = AACENC_INIT_TP_ERROR; + goto bail; + } + + /* Initialize encoder instance with default parameters. */ + aacEncDefaultConfig(&hAacEncoder->aacConfig, &hAacEncoder->extParam); + + /* Initialize headerPeriod in coderConfig for aacEncoder_GetParam(). */ + hAacEncoder->coderConfig.headerPeriod = hAacEncoder->extParam.userTpHeaderPeriod; + + /* All encoder modules have to be initialized */ + hAacEncoder->InitFlags = AACENC_INIT_ALL; + + /* Return encoder instance */ + *phAacEncoder = hAacEncoder; + + return err; + +bail: + aacEncClose(&hAacEncoder); + + return err; +} + + + +AACENC_ERROR aacEncClose(HANDLE_AACENCODER *phAacEncoder) +{ + AACENC_ERROR err = AACENC_OK; + + if (phAacEncoder == NULL) { + err = AACENC_INVALID_HANDLE; + goto bail; + } + + if (*phAacEncoder != NULL) { + HANDLE_AACENCODER hAacEncoder = *phAacEncoder; + + + if (hAacEncoder->inputBuffer!=NULL) { + FDKfree(hAacEncoder->inputBuffer); + hAacEncoder->inputBuffer = NULL; + } + + if (hAacEncoder->outBuffer) { + FreeRam_bsOutbuffer(&hAacEncoder->outBuffer); + } + + if (hAacEncoder->hEnvEnc) { + sbrEncoder_Close (&hAacEncoder->hEnvEnc); + } + if (hAacEncoder->hAacEnc) { + FDKaacEnc_Close (&hAacEncoder->hAacEnc); + } + + transportEnc_Close(&hAacEncoder->hTpEnc); + + if (hAacEncoder->hMetadataEnc) { + FDK_MetadataEnc_Close (&hAacEncoder->hMetadataEnc); + } + + Free_AacEncoder(phAacEncoder); + } + +bail: + return err; +} + +AACENC_ERROR aacEncEncode( + const HANDLE_AACENCODER hAacEncoder, + const AACENC_BufDesc *inBufDesc, + const AACENC_BufDesc *outBufDesc, + const AACENC_InArgs *inargs, + AACENC_OutArgs *outargs + ) +{ + AACENC_ERROR err = AACENC_OK; + INT i, nBsBytes = 0; + INT outBytes[(1)]; + int nExtensions = 0; + int ancDataExtIdx = -1; + + /* deal with valid encoder handle */ + if (hAacEncoder==NULL) { + err = AACENC_INVALID_HANDLE; + goto bail; + } + + + /* + * Adjust user settings and trigger reinitialization. + */ + if (hAacEncoder->InitFlags!=0) { + + err = aacEncInit(hAacEncoder, + hAacEncoder->InitFlags, + &hAacEncoder->extParam); + + if (err!=AACENC_OK) { + /* keep init flags alive! */ + goto bail; + } + hAacEncoder->InitFlags = AACENC_INIT_NONE; + } + + if (outargs!=NULL) { + FDKmemclear(outargs, sizeof(AACENC_OutArgs)); + } + + if (outBufDesc!=NULL) { + for (i=0; inumBufs; i++) { + if (outBufDesc->bufs[i]!=NULL) { + FDKmemclear(outBufDesc->bufs[i], outBufDesc->bufSizes[i]); + } + } + } + + /* + * If only encoder handle given, independent (re)initialization can be triggered. + */ + if ( (hAacEncoder!=NULL) & (inBufDesc==NULL) && (outBufDesc==NULL) && (inargs==NULL) && (outargs==NULL) ) { + goto bail; + } + + /* reset buffer wich signals number of valid bytes in output bitstream buffer */ + FDKmemclear(outBytes, hAacEncoder->aacConfig.nSubFrames*sizeof(INT)); + + /* + * Manage incoming audio samples. + */ + if ( (inargs->numInSamples > 0) && (getBufDescIdx(inBufDesc,IN_AUDIO_DATA) != -1) ) + { + /* Fetch data until nSamplesToRead reached */ + INT idx = getBufDescIdx(inBufDesc,IN_AUDIO_DATA); + INT newSamples = fixMax(0,fixMin(inargs->numInSamples, hAacEncoder->nSamplesToRead-hAacEncoder->nSamplesRead)); + INT_PCM *pIn = hAacEncoder->inputBuffer+hAacEncoder->inputBufferOffset+hAacEncoder->nSamplesRead; + + /* Copy new input samples to internal buffer */ + if (inBufDesc->bufElSizes[idx]==(INT)sizeof(INT_PCM)) { + FDKmemcpy(pIn, (INT_PCM*)inBufDesc->bufs[idx], newSamples*sizeof(INT_PCM)); /* Fast copy. */ + } + else if (inBufDesc->bufElSizes[idx]>(INT)sizeof(INT_PCM)) { + for (i=0; ibufs[idx])[i]>>16); /* Convert 32 to 16 bit. */ + } + } + else { + for (i=0; ibufs[idx])[i]))<<16; /* Convert 16 to 32 bit. */ + } + } + hAacEncoder->nSamplesRead += newSamples; + + /* Number of fetched input buffer samples. */ + outargs->numInSamples = newSamples; + } + + /* input buffer completely filled ? */ + if (hAacEncoder->nSamplesRead < hAacEncoder->nSamplesToRead) + { + /* - eof reached and flushing enabled, or + - return to main and wait for further incoming audio samples */ + if (inargs->numInSamples==-1) + { + if ( (hAacEncoder->nZerosAppended < hAacEncoder->nDelay) + ) + { + int nZeros = hAacEncoder->nSamplesToRead - hAacEncoder->nSamplesRead; + + FDK_ASSERT(nZeros >= 0); + + /* clear out until end-of-buffer */ + if (nZeros) { + FDKmemclear(hAacEncoder->inputBuffer+hAacEncoder->inputBufferOffset+hAacEncoder->nSamplesRead, sizeof(INT_PCM)*nZeros ); + hAacEncoder->nZerosAppended += nZeros; + hAacEncoder->nSamplesRead = hAacEncoder->nSamplesToRead; + } + } + else { /* flushing completed */ + err = AACENC_ENCODE_EOF; /* eof reached */ + goto bail; + } + } + else { /* inargs->numInSamples!= -1 */ + goto bail; /* not enough samples in input buffer and no flushing enabled */ + } + } + + /* init payload */ + FDKmemclear(hAacEncoder->extPayload, sizeof(AACENC_EXT_PAYLOAD) * MAX_TOTAL_EXT_PAYLOADS); + for (i = 0; i < MAX_TOTAL_EXT_PAYLOADS; i++) { + hAacEncoder->extPayload[i].associatedChElement = -1; + } + FDKmemclear(hAacEncoder->extPayloadData, sizeof(hAacEncoder->extPayloadData)); + FDKmemclear(hAacEncoder->extPayloadSize, sizeof(hAacEncoder->extPayloadSize)); + + + /* + * Calculate Meta Data info. + */ + if ( (hAacEncoder->hMetadataEnc!=NULL) && (hAacEncoder->metaDataAllowed!=0) ) { + + const AACENC_MetaData *pMetaData = NULL; + AACENC_EXT_PAYLOAD *pMetaDataExtPayload = NULL; + UINT nMetaDataExtensions = 0; + INT matrix_mixdown_idx = 0; + + /* New meta data info available ? */ + if ( getBufDescIdx(inBufDesc,IN_METADATA_SETUP) != -1 ) { + pMetaData = (AACENC_MetaData*)inBufDesc->bufs[getBufDescIdx(inBufDesc,IN_METADATA_SETUP)]; + } + + FDK_MetadataEnc_Process(hAacEncoder->hMetadataEnc, + hAacEncoder->inputBuffer+hAacEncoder->inputBufferOffset, + hAacEncoder->nSamplesRead, + pMetaData, + &pMetaDataExtPayload, + &nMetaDataExtensions, + &matrix_mixdown_idx + ); + + for (i=0; i<(INT)nMetaDataExtensions; i++) { /* Get meta data extension payload. */ + hAacEncoder->extPayload[nExtensions++] = pMetaDataExtPayload[i]; + } + if (matrix_mixdown_idx!=-1) { /* Set matrix mixdown coefficient. */ + UINT pceValue = (UINT)( (1<<3) | ((matrix_mixdown_idx&0x2)<<1) | 1 ); + if (hAacEncoder->extParam.userPceAdditions != pceValue) { + hAacEncoder->extParam.userPceAdditions = pceValue; + hAacEncoder->InitFlags |= AACENC_INIT_TRANSPORT; + } + } + } + + + if ( isSbrActive(&hAacEncoder->aacConfig) ) { + + INT nPayload = 0; + + /* + * Encode SBR data. + */ + if (sbrEncoder_EncodeFrame(hAacEncoder->hEnvEnc, + hAacEncoder->inputBuffer, + hAacEncoder->extParam.nChannels, + hAacEncoder->extPayloadSize[nPayload], + hAacEncoder->extPayloadData[nPayload] +#if defined(EVAL_PACKAGE_SILENCE) || defined(EVAL_PACKAGE_SBR_SILENCE) + ,hAacEncoder->hAacEnc->clearOutput +#endif + )) + { + err = AACENC_ENCODE_ERROR; + goto bail; + } + else { + /* Add SBR extension payload */ + for (i = 0; i < (6); i++) { + if (hAacEncoder->extPayloadSize[nPayload][i] > 0) { + hAacEncoder->extPayload[nExtensions].pData = hAacEncoder->extPayloadData[nPayload][i]; + { + hAacEncoder->extPayload[nExtensions].dataSize = hAacEncoder->extPayloadSize[nPayload][i]; + hAacEncoder->extPayload[nExtensions].associatedChElement = i; + } + hAacEncoder->extPayload[nExtensions].dataType = EXT_SBR_DATA; /* Once SBR Encoder supports SBR CRC set EXT_SBR_DATA_CRC */ + nExtensions++; /* or EXT_SBR_DATA according to configuration. */ + FDK_ASSERT(nExtensions<=MAX_TOTAL_EXT_PAYLOADS); + } + } + nPayload++; + } + } /* sbrEnabled */ + + if ( (inargs->numAncBytes > 0) && ( getBufDescIdx(inBufDesc,IN_ANCILLRY_DATA)!=-1 ) ) { + INT idx = getBufDescIdx(inBufDesc,IN_ANCILLRY_DATA); + hAacEncoder->extPayload[nExtensions].dataSize = inargs->numAncBytes * 8; + hAacEncoder->extPayload[nExtensions].pData = (UCHAR*)inBufDesc->bufs[idx]; + hAacEncoder->extPayload[nExtensions].dataType = EXT_DATA_ELEMENT; + hAacEncoder->extPayload[nExtensions].associatedChElement = -1; + ancDataExtIdx = nExtensions; /* store index */ + nExtensions++; + } + + /* + * Encode AAC - Core. + */ + if ( FDKaacEnc_EncodeFrame( hAacEncoder->hAacEnc, + hAacEncoder->hTpEnc, + hAacEncoder->inputBuffer, + outBytes, + hAacEncoder->extPayload + ) != AAC_ENC_OK ) + { + err = AACENC_ENCODE_ERROR; + goto bail; + } + + if (ancDataExtIdx >= 0) { + outargs->numAncBytes = inargs->numAncBytes - (hAacEncoder->extPayload[ancDataExtIdx].dataSize>>3); + } + + /* samples exhausted */ + hAacEncoder->nSamplesRead -= hAacEncoder->nSamplesToRead; + + /* + * Delay balancing buffer handling + */ + if (isSbrActive(&hAacEncoder->aacConfig)) { + sbrEncoder_UpdateBuffers(hAacEncoder->hEnvEnc, hAacEncoder->inputBuffer); + } + + /* + * Make bitstream public + */ + if (outBufDesc->numBufs>=1) { + + INT bsIdx = getBufDescIdx(outBufDesc,OUT_BITSTREAM_DATA); + INT auIdx = getBufDescIdx(outBufDesc,OUT_AU_SIZES); + + for (i=0,nBsBytes=0; iaacConfig.nSubFrames; i++) { + nBsBytes += outBytes[i]; + + if (auIdx!=-1) { + ((INT*)outBufDesc->bufs[auIdx])[i] = outBytes[i]; + } + } + + if ( (bsIdx!=-1) && (outBufDesc->bufSizes[bsIdx]>=nBsBytes) ) { + FDKmemcpy(outBufDesc->bufs[bsIdx], hAacEncoder->outBuffer, sizeof(UCHAR)*nBsBytes); + outargs->numOutBytes = nBsBytes; + } + else { + /* output buffer too small, can't write valid bitstream */ + err = AACENC_ENCODE_ERROR; + goto bail; + } + } + +bail: + if (err == AACENC_ENCODE_ERROR) { + /* All encoder modules have to be initialized */ + hAacEncoder->InitFlags = AACENC_INIT_ALL; + } + + return err; +} + +static +AAC_ENCODER_ERROR aacEncGetConf(HANDLE_AACENCODER hAacEncoder, + UINT *size, + UCHAR *confBuffer) +{ + FDK_BITSTREAM tmpConf; + UINT confType; + UCHAR buf[64]; + int err; + + /* Init bit buffer */ + FDKinitBitStream(&tmpConf, buf, 64, 0, BS_WRITER); + + /* write conf in tmp buffer */ + err = transportEnc_GetConf(hAacEncoder->hTpEnc, &hAacEncoder->coderConfig, &tmpConf, &confType); + + /* copy data to outbuffer: length in bytes */ + FDKbyteAlign(&tmpConf, 0); + + /* Check buffer size */ + if (FDKgetValidBits(&tmpConf) > ((*size)<<3)) + return AAC_ENC_UNKNOWN; + + FDKfetchBuffer(&tmpConf, confBuffer, size); + + if (err != 0) + return AAC_ENC_UNKNOWN; + else + return AAC_ENC_OK; +} + + +AACENC_ERROR aacEncGetLibInfo(LIB_INFO *info) +{ + int i = 0; + + if (info == NULL) { + return AACENC_INVALID_HANDLE; + } + + FDK_toolsGetLibInfo( info ); + transportEnc_GetLibInfo( info ); + + sbrEncoder_GetLibInfo( info ); + + /* search for next free tab */ + for (i = 0; i < FDK_MODULE_LAST; i++) { + if (info[i].module_id == FDK_NONE) break; + } + if (i == FDK_MODULE_LAST) { + return AACENC_INIT_ERROR; + } + + info[i].module_id = FDK_AACENC; + info[i].build_date = (char*)AACENCODER_LIB_BUILD_DATE; + info[i].build_time = (char*)AACENCODER_LIB_BUILD_TIME; + info[i].title = (char*)AACENCODER_LIB_TITLE; + info[i].version = LIB_VERSION(AACENCODER_LIB_VL0, AACENCODER_LIB_VL1, AACENCODER_LIB_VL2);; + LIB_VERSION_STRING(&info[i]); + + /* Capability flags */ + info[i].flags = 0 + | CAPF_AAC_1024 | CAPF_AAC_LC + | CAPF_AAC_512 + | CAPF_AAC_480 + | CAPF_AAC_DRC + ; + /* End of flags */ + + return AACENC_OK; +} + +AACENC_ERROR aacEncoder_SetParam( + const HANDLE_AACENCODER hAacEncoder, + const AACENC_PARAM param, + const UINT value + ) +{ + AACENC_ERROR err = AACENC_OK; + USER_PARAM *settings = &hAacEncoder->extParam; + + /* check encoder handle */ + if (hAacEncoder == NULL) { + err = AACENC_INVALID_HANDLE; + goto bail; + } + + /* apply param value */ + switch (param) + { + case AACENC_AOT: + if (settings->userAOT != (AUDIO_OBJECT_TYPE)value) { + /* check if AOT matches the allocated modules */ + switch ( value ) { + case AOT_PS: + case AOT_MP2_PS: + if (!(hAacEncoder->encoder_modis & (ENC_MODE_FLAG_PS))) { + err = AACENC_INVALID_CONFIG; + goto bail; + } + case AOT_SBR: + case AOT_MP2_SBR: + if (!(hAacEncoder->encoder_modis & (ENC_MODE_FLAG_SBR))) { + err = AACENC_INVALID_CONFIG; + goto bail; + } + case AOT_AAC_LC: + case AOT_MP2_AAC_LC: + case AOT_ER_AAC_LC: + case AOT_ER_AAC_LD: + case AOT_ER_AAC_ELD: + if (!(hAacEncoder->encoder_modis & (ENC_MODE_FLAG_AAC))) { + err = AACENC_INVALID_CONFIG; + goto bail; + } + break; + default: + err = AACENC_INVALID_CONFIG; + goto bail; + }/* switch value */ + settings->userAOT = (AUDIO_OBJECT_TYPE)value; + hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_STATES | AACENC_INIT_TRANSPORT; + } + break; + case AACENC_BITRATE: + if (settings->userBitrate != value) { + settings->userBitrate = value; + hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_TRANSPORT; + } + break; + case AACENC_BITRATEMODE: + if (settings->userBitrateMode != value) { + switch ( value ) { + case 0: + case 8: + settings->userBitrateMode = value; + hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_TRANSPORT; + break; + default: + err = AACENC_INVALID_CONFIG; + break; + } /* switch value */ + } + break; + case AACENC_SAMPLERATE: + if (settings->userSamplerate != value) { + if ( !( (value==8000) || (value==11025) || (value==12000) || (value==16000) || (value==22050) || (value==24000) || + (value==32000) || (value==44100) || (value==48000) || (value==64000) || (value==88200) || (value==96000) ) ) + { + err = AACENC_INVALID_CONFIG; + break; + } + settings->userSamplerate = value; + hAacEncoder->nSamplesRead = 0; /* reset internal inputbuffer */ + hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_STATES | AACENC_INIT_TRANSPORT; + } + break; + case AACENC_CHANNELMODE: + if (settings->userChannelMode != (CHANNEL_MODE)value) { + const CHANNEL_MODE_CONFIG_TAB* pConfig = FDKaacEnc_GetChannelModeConfiguration((CHANNEL_MODE)value); + if (pConfig==NULL) { + err = AACENC_INVALID_CONFIG; + break; + } + if ( (pConfig->nElements > hAacEncoder->nMaxAacElements) + || (pConfig->nChannelsEff > hAacEncoder->nMaxAacChannels) + || !((value>=1) && (value<=6)) + ) + { + err = AACENC_INVALID_CONFIG; + break; + } + + settings->userChannelMode = (CHANNEL_MODE)value; + settings->nChannels = pConfig->nChannels; + hAacEncoder->nSamplesRead = 0; /* reset internal inputbuffer */ + hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_TRANSPORT; + } + break; + case AACENC_BANDWIDTH: + if (settings->userBandwidth != value) { + settings->userBandwidth = value; + hAacEncoder->InitFlags |= AACENC_INIT_CONFIG; + } + break; + case AACENC_CHANNELORDER: + if (hAacEncoder->aacConfig.channelOrder != (CHANNEL_ORDER)value) { + if (! ((value==0) || (value==1)) ) { + err = AACENC_INVALID_CONFIG; + break; + } + hAacEncoder->aacConfig.channelOrder = (CHANNEL_ORDER)value; + hAacEncoder->nSamplesRead = 0; /* reset internal inputbuffer */ + hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_STATES | AACENC_INIT_TRANSPORT; + } + break; + case AACENC_AFTERBURNER: + if (settings->userAfterburner != value) { + if (! ((value==0) || (value==1)) ) { + err = AACENC_INVALID_CONFIG; + break; + } + settings->userAfterburner = value; + hAacEncoder->InitFlags |= AACENC_INIT_CONFIG; + } + break; + case AACENC_GRANULE_LENGTH: + if (settings->userFramelength != value) { + switch (value) { + case 1024: + case 512: + case 480: + settings->userFramelength = value; + hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_TRANSPORT; + break; + default: + err = AACENC_INVALID_CONFIG; + break; + } + } + break; + case AACENC_SBR_MODE: + if (settings->userSbrEnabled != value) { + settings->userSbrEnabled = value; + hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_STATES | AACENC_INIT_TRANSPORT; + } + break; + case AACENC_TRANSMUX: + if (settings->userTpType != (TRANSPORT_TYPE)value) { + + TRANSPORT_TYPE type = (TRANSPORT_TYPE)value; + UINT flags = hAacEncoder->CAPF_tpEnc; + + if ( !( ((type==TT_MP4_ADIF) && (flags&CAPF_ADIF)) + || ((type==TT_MP4_ADTS) && (flags&CAPF_ADTS)) + || ((type==TT_MP4_LATM_MCP0) && ((flags&CAPF_LATM) && (flags&CAPF_RAWPACKETS))) + || ((type==TT_MP4_LATM_MCP1) && ((flags&CAPF_LATM) && (flags&CAPF_RAWPACKETS))) + || ((type==TT_MP4_LOAS) && (flags&CAPF_LOAS)) + || ((type==TT_MP4_RAW) && (flags&CAPF_RAWPACKETS)) + ) ) + { + err = AACENC_INVALID_CONFIG; + break; + } + settings->userTpType = (TRANSPORT_TYPE)value; + hAacEncoder->InitFlags |= AACENC_INIT_TRANSPORT; + } + break; + case AACENC_SIGNALING_MODE: + if (settings->userTpSignaling != value) { + if ( !((value==0) || (value==1) || (value==2)) ) { + err = AACENC_INVALID_CONFIG; + break; + } + settings->userTpSignaling = value; + hAacEncoder->InitFlags |= AACENC_INIT_TRANSPORT; + } + break; + case AACENC_PROTECTION: + if (settings->userTpProtection != value) { + if ( !((value==0) || (value==1)) ) { + err = AACENC_INVALID_CONFIG; + break; + } + settings->userTpProtection = value; + hAacEncoder->InitFlags |= AACENC_INIT_TRANSPORT; + } + break; + case AACENC_HEADER_PERIOD: + if (settings->userTpHeaderPeriod != value) { + settings->userTpHeaderPeriod = value; + hAacEncoder->InitFlags |= AACENC_INIT_TRANSPORT; + } + break; + case AACENC_TPSUBFRAMES: + if (settings->userTpNsubFrames != value) { + if (! ( (value>=1) && (value<=4) ) ) { + err = AACENC_INVALID_CONFIG; + break; + } + settings->userTpNsubFrames = value; + hAacEncoder->InitFlags |= AACENC_INIT_TRANSPORT; + } + break; + case AACENC_ANCILLARY_BITRATE: + if (settings->userAncDataRate != value) { + settings->userAncDataRate = value; + } + break; + case AACENC_CONTROL_STATE: + if (hAacEncoder->InitFlags != value) { + if (value&AACENC_RESET_INBUFFER) { + hAacEncoder->nSamplesRead = 0; + } + hAacEncoder->InitFlags = value; + } + break; + case AACENC_METADATA_MODE: + if ((UINT)settings->userMetaDataMode != value) { + if ( !((value>=0) && (value<=2)) ) { + err = AACENC_INVALID_CONFIG; + break; + } + settings->userMetaDataMode = value; + hAacEncoder->InitFlags |= AACENC_INIT_CONFIG; + } + break; + default: + err = AACENC_UNSUPPORTED_PARAMETER; + break; + } /* switch(param) */ + +bail: + return err; +} + +UINT aacEncoder_GetParam( + const HANDLE_AACENCODER hAacEncoder, + const AACENC_PARAM param + ) +{ + UINT value = 0; + USER_PARAM *settings = &hAacEncoder->extParam; + + /* check encoder handle */ + if (hAacEncoder == NULL) { + goto bail; + } + + /* apply param value */ + switch (param) + { + case AACENC_AOT: + value = (UINT)hAacEncoder->aacConfig.audioObjectType; + break; + case AACENC_BITRATE: + value = (UINT)((hAacEncoder->aacConfig.bitrateMode==AACENC_BR_MODE_CBR) ? hAacEncoder->aacConfig.bitRate : -1); + break; + case AACENC_BITRATEMODE: + value = (UINT)hAacEncoder->aacConfig.bitrateMode; + break; + case AACENC_SAMPLERATE: + value = (UINT)settings->userSamplerate; + break; + case AACENC_CHANNELMODE: + value = (UINT)hAacEncoder->aacConfig.channelMode; + break; + case AACENC_BANDWIDTH: + value = (UINT)hAacEncoder->aacConfig.bandWidth; + break; + case AACENC_CHANNELORDER: + value = (UINT)hAacEncoder->aacConfig.channelOrder; + break; + case AACENC_AFTERBURNER: + value = (UINT)hAacEncoder->aacConfig.useRequant; + break; + case AACENC_GRANULE_LENGTH: + value = (UINT)hAacEncoder->aacConfig.framelength; + break; + case AACENC_SBR_MODE: + value = (UINT) (hAacEncoder->aacConfig.syntaxFlags & AC_SBR_PRESENT) ? 1 : 0; + break; + case AACENC_TRANSMUX: + value = (UINT)settings->userTpType; + break; + case AACENC_SIGNALING_MODE: + value = (UINT)settings->userTpSignaling; + break; + case AACENC_PROTECTION: + value = (UINT)settings->userTpProtection; + break; + case AACENC_HEADER_PERIOD: + value = (UINT)hAacEncoder->coderConfig.headerPeriod; + break; + case AACENC_TPSUBFRAMES: + value = (UINT)settings->userTpNsubFrames; + break; + case AACENC_ANCILLARY_BITRATE: + value = (UINT)hAacEncoder->aacConfig.anc_Rate; + break; + case AACENC_CONTROL_STATE: + value = (UINT)hAacEncoder->InitFlags; + break; + case AACENC_METADATA_MODE: + value = (hAacEncoder->metaDataAllowed==0) ? 0 : (UINT)settings->userMetaDataMode; + break; + default: + //err = MPS_INVALID_PARAMETER; + break; + } /* switch(param) */ + +bail: + return value; +} + +AACENC_ERROR aacEncInfo( + const HANDLE_AACENCODER hAacEncoder, + AACENC_InfoStruct *pInfo + ) +{ + AACENC_ERROR err = AACENC_OK; + + FDKmemclear(pInfo, sizeof(AACENC_InfoStruct)); + pInfo->confSize = 64; /* pre-initialize */ + + pInfo->maxOutBufBytes = ((hAacEncoder->nMaxAacChannels*6144)+7)>>3; + pInfo->maxAncBytes = hAacEncoder->aacConfig.maxAncBytesPerAU; + pInfo->inBufFillLevel = hAacEncoder->nSamplesRead/hAacEncoder->extParam.nChannels; + pInfo->inputChannels = hAacEncoder->extParam.nChannels; + pInfo->frameLength = hAacEncoder->nSamplesToRead/hAacEncoder->extParam.nChannels; + pInfo->encoderDelay = hAacEncoder->nDelay/hAacEncoder->extParam.nChannels; + + /* Get encoder configuration */ + if ( aacEncGetConf(hAacEncoder, &pInfo->confSize, &pInfo->confBuf[0]) != AAC_ENC_OK) { + err = AACENC_INIT_ERROR; + goto bail; + } +bail: + return err; +} + diff --git a/libAACenc/src/aacenc_pns.cpp b/libAACenc/src/aacenc_pns.cpp new file mode 100644 index 0000000..8437132 --- /dev/null +++ b/libAACenc/src/aacenc_pns.cpp @@ -0,0 +1,532 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (2001) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + + Initial author: M. Lohwasser + contents/description: pns.c + +******************************************************************************/ + +#define PNS_CONFORMANCE_TEST 0 + +#include "aacenc_pns.h" +#include "psy_data.h" +#include "pnsparam.h" +#include "noisedet.h" +#include "bit_cnt.h" +#include "interface.h" + + +/* minCorrelationEnergy = (1.0e-10f)^2 ~ 2^-67 = 2^-47 * 2^-20 */ +static const FIXP_DBL minCorrelationEnergy = FL2FXCONST_DBL(0.0); /* FL2FXCONST_DBL((float)FDKpow(2.0,-47)); */ +/* noiseCorrelationThresh = 0.6^2 */ +static const FIXP_DBL noiseCorrelationThresh = FL2FXCONST_DBL(0.36); + +static void FDKaacEnc_FDKaacEnc_noiseDetection( PNS_CONFIG *pnsConf, + PNS_DATA *pnsData, + const INT sfbActive, + const INT *sfbOffset, + INT tnsOrder, + INT tnsPredictionGain, + INT tnsActive, + FIXP_DBL *mdctSpectrum, + INT *sfbMaxScaleSpec, + FIXP_SGL *sfbtonality ); + +static void FDKaacEnc_CalcNoiseNrgs( const INT sfbActive, + INT *pnsFlag, + FIXP_DBL *sfbEnergyLdData, + INT *noiseNrg ); + +/***************************************************************************** + + functionname: initPnsConfiguration + description: fill pnsConf with pns parameters + returns: error status + input: PNS Config struct (modified) + bitrate, samplerate, usePns, + number of sfb's, pointer to sfb offset + output: error code + +*****************************************************************************/ + +AAC_ENCODER_ERROR FDKaacEnc_InitPnsConfiguration(PNS_CONFIG *pnsConf, + INT bitRate, + INT sampleRate, + INT usePns, + INT sfbCnt, + const INT *sfbOffset, + const INT numChan, + const INT isLC) +{ + AAC_ENCODER_ERROR ErrorStatus; + + /* init noise detection */ + ErrorStatus = FDKaacEnc_GetPnsParam(&pnsConf->np, + bitRate, + sampleRate, + sfbCnt, + sfbOffset, + &usePns, + numChan, + isLC); + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + + pnsConf->minCorrelationEnergy = minCorrelationEnergy; + pnsConf->noiseCorrelationThresh = noiseCorrelationThresh; + + pnsConf->usePns = usePns; + + return AAC_ENC_OK; +} + + + +/***************************************************************************** + + functionname: FDKaacEnc_PnsDetect + description: do decision, if PNS shall used or not + returns: + input: pns config structure + pns data structure (modified), + lastWindowSequence (long or short blocks) + sfbActive + pointer to Sfb Energy, Threshold, Offset + pointer to mdct Spectrum + length of each group + pointer to tonality calculated in chaosmeasure + tns order and prediction gain + calculated noiseNrg at active PNS + output: pnsFlag in pns data structure + +*****************************************************************************/ +void FDKaacEnc_PnsDetect(PNS_CONFIG *pnsConf, + PNS_DATA *pnsData, + const INT lastWindowSequence, + const INT sfbActive, + const INT maxSfbPerGroup, + FIXP_DBL *sfbThresholdLdData, + const INT *sfbOffset, + FIXP_DBL *mdctSpectrum, + INT *sfbMaxScaleSpec, + FIXP_SGL *sfbtonality, + INT tnsOrder, + INT tnsPredictionGain, + INT tnsActive, + FIXP_DBL *sfbEnergyLdData, + INT *noiseNrg ) + +{ + int sfb; + int startNoiseSfb; + + if (pnsConf->np.detectionAlgorithmFlags & IS_LOW_COMLEXITY) { + if ( (!pnsConf->usePns) || /* pns enabled? */ + (lastWindowSequence == SHORT_WINDOW) ) /* currently only long blocks */ + { + FDKmemclear(pnsData->pnsFlag, MAX_GROUPED_SFB*sizeof(INT)); /* clear all pnsFlags */ + for (sfb=0; sfbusePns) + return; + + /* PNS only for long Windows */ + if (pnsConf->np.detectionAlgorithmFlags & JUST_LONG_WINDOW) { + if(lastWindowSequence != LONG_WINDOW) { + for (sfb = 0; sfb < sfbActive; sfb++) { + pnsData->pnsFlag[sfb] = 0; /* clear all pnsFlags */ + } + return; + } + } + } + /* + call noise detection + */ + FDKaacEnc_FDKaacEnc_noiseDetection( pnsConf, + pnsData, + sfbActive, + sfbOffset, + tnsOrder, + tnsPredictionGain, + tnsActive, + mdctSpectrum, + sfbMaxScaleSpec, + sfbtonality ); + + /* set startNoiseSfb (long) */ + startNoiseSfb = pnsConf->np.startSfb; + + /* Set noise substitution status */ + for(sfb = 0; sfb < sfbActive; sfb++) { + + /* No PNS below startNoiseSfb */ + if(sfb < startNoiseSfb){ + pnsData->pnsFlag[sfb] = 0; + continue; + } + + /* + do noise substitution if + fuzzy measure is high enough + sfb freq > minimum sfb freq + signal in coder band is not masked + */ + + if((pnsData->noiseFuzzyMeasure[sfb] > FL2FXCONST_SGL(0.5)) && + ( (sfbThresholdLdData[sfb] + FL2FXCONST_DBL(0.5849625f/64.0f)) /* thr * 1.5 = thrLd +ld(1.5)/64 */ + < sfbEnergyLdData[sfb] ) ) + { + /* + mark in psyout flag array that we will code + this band with PNS + */ + pnsData->pnsFlag[sfb] = 1; /* PNS_ON */ + } + else{ + pnsData->pnsFlag[sfb] = 0; /* PNS_OFF */ + } + + /* no PNS if LTP is active */ + } + + /* avoid PNS holes */ + if((pnsData->noiseFuzzyMeasure[0]>FL2FXCONST_SGL(0.5f)) && (pnsData->pnsFlag[1])) { + pnsData->pnsFlag[0] = 1; + } + + for(sfb=1; sfbnoiseFuzzyMeasure[sfb]>pnsConf->np.gapFillThr) && + (pnsData->pnsFlag[sfb-1]) && (pnsData->pnsFlag[sfb+1])) { + pnsData->pnsFlag[sfb] = 1; + } + } + + if(maxSfbPerGroup>0) { + /* avoid PNS hole */ + if((pnsData->noiseFuzzyMeasure[maxSfbPerGroup-1]>pnsConf->np.gapFillThr) && (pnsData->pnsFlag[maxSfbPerGroup-2])) { + pnsData->pnsFlag[maxSfbPerGroup-1] = 1; + } + /* avoid single PNS band */ + if(pnsData->pnsFlag[maxSfbPerGroup-2]==0) { + pnsData->pnsFlag[maxSfbPerGroup-1] = 0; + } + } + + /* avoid single PNS bands */ + if(pnsData->pnsFlag[1]==0) { + pnsData->pnsFlag[0] = 0; + } + + for(sfb=1; sfbpnsFlag[sfb-1]==0)&&(pnsData->pnsFlag[sfb+1]==0)) { + pnsData->pnsFlag[sfb] = 0; + } + } + + + /* + calculate noiseNrg's + */ + FDKaacEnc_CalcNoiseNrgs( sfbActive, + pnsData->pnsFlag, + sfbEnergyLdData, + noiseNrg ); +} + + +/***************************************************************************** + + functionname:FDKaacEnc_FDKaacEnc_noiseDetection + description: wrapper for noisedet.c + returns: + input: pns config structure + pns data structure (modified), + sfbActive + tns order and prediction gain + pointer to mdct Spectrumand Sfb Energy + pointer to Sfb tonality + output: noiseFuzzyMeasure in structure pnsData + flags tonal / nontonal + +*****************************************************************************/ +static void FDKaacEnc_FDKaacEnc_noiseDetection( PNS_CONFIG *pnsConf, + PNS_DATA *pnsData, + const INT sfbActive, + const INT *sfbOffset, + int tnsOrder, + INT tnsPredictionGain, + INT tnsActive, + FIXP_DBL *mdctSpectrum, + INT *sfbMaxScaleSpec, + FIXP_SGL *sfbtonality ) +{ + INT condition = TRUE; + if ( !(pnsConf->np.detectionAlgorithmFlags & IS_LOW_COMLEXITY) ) { + condition = (tnsOrder > 3); + } + /* + no PNS if heavy TNS activity + clear pnsData->noiseFuzzyMeasure + */ + if((pnsConf->np.detectionAlgorithmFlags & USE_TNS_GAIN_THR) && + (tnsPredictionGain >= pnsConf->np.tnsGainThreshold) && condition && + !((pnsConf->np.detectionAlgorithmFlags & USE_TNS_PNS) && (tnsPredictionGain >= pnsConf->np.tnsPNSGainThreshold) && (tnsActive)) ) + { + /* clear all noiseFuzzyMeasure */ + FDKmemclear(pnsData->noiseFuzzyMeasure, sfbActive*sizeof(FIXP_SGL)); + } + else + { + /* + call noise detection, output in pnsData->noiseFuzzyMeasure, + use real mdct spectral data + */ + FDKaacEnc_noiseDetect( mdctSpectrum, + sfbMaxScaleSpec, + sfbActive, + sfbOffset, + pnsData->noiseFuzzyMeasure, + &pnsConf->np, + sfbtonality); + } +} + + +/***************************************************************************** + + functionname:FDKaacEnc_CalcNoiseNrgs + description: Calculate the NoiseNrg's + returns: + input: sfbActive + if pnsFlag calculate NoiseNrg + pointer to sfbEnergy and groupLen + pointer to noiseNrg (modified) + output: noiseNrg's in pnsFlaged sfb's + +*****************************************************************************/ + +static void FDKaacEnc_CalcNoiseNrgs( const INT sfbActive, + INT *RESTRICT pnsFlag, + FIXP_DBL *RESTRICT sfbEnergyLdData, + INT *RESTRICT noiseNrg ) +{ + int sfb; + INT tmp = (-LOG_NORM_PCM)<<2; + + for(sfb = 0; sfb < sfbActive; sfb++) { + if(pnsFlag[sfb]) { + INT nrg = (-sfbEnergyLdData[sfb]+FL2FXCONST_DBL(0.5f/64.0f))>>(DFRACT_BITS-1-7); + noiseNrg[sfb] = tmp - nrg; + } + } +} + + +/***************************************************************************** + + functionname:FDKaacEnc_CodePnsChannel + description: Execute pns decission + returns: + input: sfbActive + pns config structure + use PNS if pnsFlag + pointer to Sfb Energy, noiseNrg, Threshold + output: set sfbThreshold high to code pe with 0, + noiseNrg marks flag for pns coding + +*****************************************************************************/ + +void FDKaacEnc_CodePnsChannel(const INT sfbActive, + PNS_CONFIG *pnsConf, + INT *RESTRICT pnsFlag, + FIXP_DBL *RESTRICT sfbEnergyLdData, + INT *RESTRICT noiseNrg, + FIXP_DBL *RESTRICT sfbThresholdLdData) +{ + INT sfb; + INT lastiNoiseEnergy = 0; + INT firstPNSband = 1; /* TRUE for first PNS-coded band */ + + /* no PNS */ + if(!pnsConf->usePns) { + for(sfb = 0; sfb < sfbActive; sfb++) { + /* no PNS coding */ + noiseNrg[sfb] = NO_NOISE_PNS; + } + return; + } + + /* code PNS */ + for(sfb = 0; sfb < sfbActive; sfb++) { + if(pnsFlag[sfb]) { + /* high sfbThreshold causes pe = 0 */ + if(noiseNrg[sfb] != NO_NOISE_PNS) + sfbThresholdLdData[sfb] = sfbEnergyLdData[sfb] + FL2FXCONST_DBL(1.0f/LD_DATA_SCALING); + + /* set noiseNrg in valid region */ + if(!firstPNSband) { + INT deltaiNoiseEnergy = noiseNrg[sfb] - lastiNoiseEnergy; + + if(deltaiNoiseEnergy > CODE_BOOK_PNS_LAV) + noiseNrg[sfb] -= deltaiNoiseEnergy - CODE_BOOK_PNS_LAV; + else if(deltaiNoiseEnergy < -CODE_BOOK_PNS_LAV) + noiseNrg[sfb] -= deltaiNoiseEnergy + CODE_BOOK_PNS_LAV; + } + else { + firstPNSband = 0; + } + lastiNoiseEnergy = noiseNrg[sfb]; + } + else { + /* no PNS coding */ + noiseNrg[sfb] = NO_NOISE_PNS; + } + } +} + + +/***************************************************************************** + + functionname:FDKaacEnc_PreProcessPnsChannelPair + description: Calculate the correlation of noise in a channel pair + + returns: + input: sfbActive + pointer to sfb energies left, right and mid channel + pns config structure + pns data structure left and right (modified) + + output: noiseEnergyCorrelation in pns data structure + +*****************************************************************************/ + +void FDKaacEnc_PreProcessPnsChannelPair(const INT sfbActive, + FIXP_DBL *RESTRICT sfbEnergyLeft, + FIXP_DBL *RESTRICT sfbEnergyRight, + FIXP_DBL *RESTRICT sfbEnergyLeftLD, + FIXP_DBL *RESTRICT sfbEnergyRightLD, + FIXP_DBL *RESTRICT sfbEnergyMid, + PNS_CONFIG *RESTRICT pnsConf, + PNS_DATA *pnsDataLeft, + PNS_DATA *pnsDataRight) +{ + INT sfb; + FIXP_DBL ccf; + + if(!pnsConf->usePns) + return; + + FIXP_DBL *RESTRICT pNoiseEnergyCorrelationL = pnsDataLeft->noiseEnergyCorrelation; + FIXP_DBL *RESTRICT pNoiseEnergyCorrelationR = pnsDataRight->noiseEnergyCorrelation; + + for(sfb=0;sfb< sfbActive;sfb++) { + FIXP_DBL quot = (sfbEnergyLeftLD[sfb]>>1) + (sfbEnergyRightLD[sfb]>>1); + + if(quot < FL2FXCONST_DBL(-32.0f/(float)LD_DATA_SCALING)) + ccf = FL2FXCONST_DBL(0.0f); + else { + FIXP_DBL accu = sfbEnergyMid[sfb]- (((sfbEnergyLeft[sfb]>>1)+(sfbEnergyRight[sfb]>>1))>>1); + INT sign = (accu < FL2FXCONST_DBL(0.0f)) ? 1 : 0 ; + accu = fixp_abs(accu); + + ccf = CalcLdData(accu) + FL2FXCONST_DBL((float)1.0f/(float)LD_DATA_SCALING) - quot; /* ld(accu*2) = ld(accu) + 1 */ + ccf = (ccf>=FL2FXCONST_DBL(0.0)) ? ((FIXP_DBL)MAXVAL_DBL) : (sign) ? -CalcInvLdData(ccf) : CalcInvLdData(ccf); + } + + pNoiseEnergyCorrelationL[sfb] = ccf; + pNoiseEnergyCorrelationR[sfb] = ccf; + } +} + + + +/***************************************************************************** + + functionname:FDKaacEnc_PostProcessPnsChannelPair + description: if PNS used at left and right channel, + use msMask to flag correlation + returns: + input: sfbActive + pns config structure + pns data structure left and right (modified) + pointer to msMask, flags correlation by pns coding (modified) + Digest of MS coding + output: pnsFlag in pns data structure, + msFlag in msMask (flags correlation) + +*****************************************************************************/ + +void FDKaacEnc_PostProcessPnsChannelPair(const INT sfbActive, + PNS_CONFIG *pnsConf, + PNS_DATA *pnsDataLeft, + PNS_DATA *pnsDataRight, + INT *RESTRICT msMask, + INT *msDigest ) +{ + INT sfb; + + if(!pnsConf->usePns) + return; + + for(sfb=0;sfbpnsFlag[sfb]) && + (pnsDataRight->pnsFlag[sfb]) ) { + /* AAC only: Standard */ + /* do this to avoid ms flags in layers that should not have it */ + if(pnsDataLeft->noiseEnergyCorrelation[sfb] <= pnsConf->noiseCorrelationThresh){ + msMask[sfb] = 0; + *msDigest = MS_SOME; + } + } + else { + /* + No PNS coding + */ + pnsDataLeft->pnsFlag[sfb] = 0; + pnsDataRight->pnsFlag[sfb] = 0; + } + } + + /* + Use MS flag to signal noise correlation if + pns is active in both channels + */ + if( (pnsDataLeft->pnsFlag[sfb]) && (pnsDataRight->pnsFlag[sfb]) ) { + if(pnsDataLeft->noiseEnergyCorrelation[sfb] > pnsConf->noiseCorrelationThresh) { + msMask[sfb] = 1; + *msDigest = MS_SOME; + } + } + } +} diff --git a/libAACenc/src/aacenc_pns.h b/libAACenc/src/aacenc_pns.h new file mode 100644 index 0000000..f0b29d0 --- /dev/null +++ b/libAACenc/src/aacenc_pns.h @@ -0,0 +1,52 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (2001) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + + Initial author: M. Lohwasser + contents/description: pns.h + +******************************************************************************/ + +#ifndef __PNS_H +#define __PNS_H + +#include "common_fix.h" + +#include "pnsparam.h" + +#define NO_NOISE_PNS FDK_INT_MIN + +typedef struct{ + NOISEPARAMS np; + FIXP_DBL minCorrelationEnergy; + FIXP_DBL noiseCorrelationThresh; + INT usePns; +} PNS_CONFIG; + +typedef struct{ + FIXP_SGL noiseFuzzyMeasure[MAX_GROUPED_SFB]; + FIXP_DBL noiseEnergyCorrelation[MAX_GROUPED_SFB]; + INT pnsFlag[MAX_GROUPED_SFB]; +} PNS_DATA; + +#endif diff --git a/libAACenc/src/aacenc_tns.cpp b/libAACenc/src/aacenc_tns.cpp new file mode 100644 index 0000000..f795e24 --- /dev/null +++ b/libAACenc/src/aacenc_tns.cpp @@ -0,0 +1,1286 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: Alex Groeschel + contents/description: Temporal noise shaping + +******************************************************************************/ + +#include "aacenc_tns.h" +#include "psy_const.h" +#include "psy_configuration.h" +#include "tns_func.h" +#include "aacEnc_rom.h" +#include "aacenc_tns.h" + +enum { + HIFILT = 0, /* index of higher filter */ + LOFILT = 1 /* index of lower filter */ +}; + + +#define FILTER_DIRECTION 0 + +static const FIXP_DBL acfWindowLong[12+3+1] = { + 0x7fffffff,0x7fb80000,0x7ee00000,0x7d780000,0x7b800000,0x78f80000,0x75e00000,0x72380000, + 0x6e000000,0x69380000,0x63e00000,0x5df80000,0x57800000,0x50780000,0x48e00000,0x40b80000 +}; + +static const FIXP_DBL acfWindowShort[4+3+1] = { + 0x7fffffff,0x7e000000,0x78000000,0x6e000000,0x60000000,0x4e000000,0x38000000,0x1e000000 +}; + + +typedef struct { + INT filterEnabled[MAX_NUM_OF_FILTERS]; + INT threshOn[MAX_NUM_OF_FILTERS]; /* min. prediction gain for using tns TABUL*/ + INT filterStartFreq[MAX_NUM_OF_FILTERS]; /* lowest freq for lpc TABUL*/ + INT tnsLimitOrder[MAX_NUM_OF_FILTERS]; /* Limit for TNS order TABUL*/ + INT tnsFilterDirection[MAX_NUM_OF_FILTERS]; /* Filtering direction, 0=up, 1=down TABUL */ + INT acfSplit[MAX_NUM_OF_FILTERS]; + FIXP_DBL tnsTimeResolution[MAX_NUM_OF_FILTERS]; /* TNS max. time resolution TABUL. Should be fract but MSVC won't compile then */ + INT seperateFiltersAllowed; + +} TNS_PARAMETER_TABULATED; + + +typedef struct{ + INT bitRateFrom[2]; /* noneSbr=0, useSbr=1 */ + INT bitRateTo[2]; /* noneSbr=0, useSbr=1 */ + TNS_PARAMETER_TABULATED paramTab[2]; /* mono=0, stereo=1 */ + +} TNS_INFO_TAB; + +#define TNS_TIMERES_SCALE (1) +#define FL2_TIMERES_FIX(a) ( FL2FXCONST_DBL(a/(float)(1<= tnsInfoTab[i].bitRateFrom[sbrLd?1:0]) && + bitRate <= tnsInfoTab[i].bitRateTo[sbrLd?1:0]) + { + tnsConfigTab = &tnsInfoTab[i].paramTab[(channels==1)?0:1]; + } + } + + return tnsConfigTab; +} + + +static INT getTnsMaxBands( + const INT sampleRate, + const INT granuleLength, + const INT isShortBlock + ) +{ + int i; + INT numBands = -1; + const TNS_MAX_TAB_ENTRY *pMaxBandsTab = NULL; + int maxBandsTabSize = 0; + + switch (granuleLength) { + case 960: + case 1024: + pMaxBandsTab = tnsMaxBandsTab1024; + maxBandsTabSize = sizeof(tnsMaxBandsTab1024)/sizeof(TNS_MAX_TAB_ENTRY); + break; + case 480: + pMaxBandsTab = tnsMaxBandsTab480; + maxBandsTabSize = sizeof(tnsMaxBandsTab480)/sizeof(TNS_MAX_TAB_ENTRY); + break; + case 512: + pMaxBandsTab = tnsMaxBandsTab512; + maxBandsTabSize = sizeof(tnsMaxBandsTab512)/sizeof(TNS_MAX_TAB_ENTRY); + break; + default: + numBands = -1; + } + + if (pMaxBandsTab!=NULL) { + for (i=0; i= pMaxBandsTab[i].samplingRate) { + break; + } + } + } + + return numBands; +} + +/***************************************************************************/ +/*! + \brief FDKaacEnc_FreqToBandWithRounding + + Returns index of nearest band border + + \param frequency + \param sampling frequency + \param total number of bands + \param pointer to table of band borders + + \return band border +****************************************************************************/ + +INT FDKaacEnc_FreqToBandWithRounding( + const INT freq, + const INT fs, + const INT numOfBands, + const INT *bandStartOffset + ) +{ + INT lineNumber, band; + + /* assert(freq >= 0); */ + lineNumber = (freq*bandStartOffset[numOfBands]*4/fs+1)/2; + + /* freq > fs/2 */ + if (lineNumber >= bandStartOffset[numOfBands]) + return numOfBands; + + /* find band the line number lies in */ + for (band=0; bandlineNumber) break; + } + + /* round to nearest band border */ + if (lineNumber - bandStartOffset[band] > + bandStartOffset[band+1] - lineNumber ) + { + band++; + } + + return(band); +} + + +/***************************************************************************** + + functionname: FDKaacEnc_InitTnsConfiguration + description: fill TNS_CONFIG structure with sensible content + returns: + input: bitrate, samplerate, number of channels, + blocktype (long or short), + TNS Config struct (modified), + psy config struct, + tns active flag + output: + +*****************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_InitTnsConfiguration(INT bitRate, + INT sampleRate, + INT channels, + INT blockType, + INT granuleLength, + INT ldSbrPresent, + TNS_CONFIG *tC, + PSY_CONFIGURATION *pC, + INT active, + INT useTnsPeak) +{ + int i; + //float acfTimeRes = (blockType == SHORT_WINDOW) ? 0.125f : 0.046875f; + + if (channels <= 0) + return (AAC_ENCODER_ERROR)1; + + /* initialize TNS filter flag, order, and coefficient resolution (in bits per coeff) */ + tC->tnsActive = (active) ? TRUE : FALSE; + tC->maxOrder = (blockType == SHORT_WINDOW) ? 5 : 12; /* maximum: 7, 20 */ + if (bitRate < 16000) + tC->maxOrder -= 2; + tC->coefRes = (blockType == SHORT_WINDOW) ? 3 : 4; + + /* LPC stop line: highest MDCT line to be coded, but do not go beyond TNS_MAX_BANDS! */ + tC->lpcStopBand = getTnsMaxBands(sampleRate, granuleLength, (blockType == SHORT_WINDOW) ? 1 : 0); + + if (tC->lpcStopBand < 0) { + return (AAC_ENCODER_ERROR)1; + } + + tC->lpcStopBand = FDKmin(tC->lpcStopBand, pC->sfbActive); + tC->lpcStopLine = pC->sfbOffset[tC->lpcStopBand]; + + switch (granuleLength) { + case 960: + case 1024: + /* TNS start line: skip lower MDCT lines to prevent artifacts due to filter mismatch */ + tC->lpcStartBand[LOFILT] = (blockType == SHORT_WINDOW) ? 0 : ((sampleRate < 18783) ? 4 : 8); + tC->lpcStartLine[LOFILT] = pC->sfbOffset[tC->lpcStartBand[LOFILT]]; + + i = tC->lpcStopBand; + while (pC->sfbOffset[i] > (tC->lpcStartLine[LOFILT] + (tC->lpcStopLine - tC->lpcStartLine[LOFILT]) / 4)) i--; + tC->lpcStartBand[HIFILT] = i; + tC->lpcStartLine[HIFILT] = pC->sfbOffset[i]; + + tC->confTab.threshOn[HIFILT] = 1437; + tC->confTab.threshOn[LOFILT] = 1500; + + tC->confTab.tnsLimitOrder[HIFILT] = tC->maxOrder; + tC->confTab.tnsLimitOrder[LOFILT] = tC->maxOrder - 7; + + tC->confTab.tnsFilterDirection[HIFILT] = FILTER_DIRECTION; + tC->confTab.tnsFilterDirection[LOFILT] = FILTER_DIRECTION; + + tC->confTab.acfSplit[HIFILT] = -1; /* signal Merged4to2QuartersAutoCorrelation in FDKaacEnc_MergedAutoCorrelation*/ + tC->confTab.acfSplit[LOFILT] = -1; /* signal Merged4to2QuartersAutoCorrelation in FDKaacEnc_MergedAutoCorrelation */ + + tC->confTab.filterEnabled[HIFILT] = 1; + tC->confTab.filterEnabled[LOFILT] = 1; + tC->confTab.seperateFiltersAllowed = 1; + + /* compute autocorrelation window based on maximum filter order for given block type */ + /* for (i = 0; i <= tC->maxOrder + 3; i++) { + float acfWinTemp = acfTimeRes * i; + acfWindow[i] = FL2FXCONST_DBL(1.0f - acfWinTemp * acfWinTemp); + } + */ + if (blockType == SHORT_WINDOW) { + FDKmemcpy(tC->acfWindow[HIFILT], acfWindowShort, FDKmin(sizeof(acfWindowShort), sizeof(tC->acfWindow[HIFILT]))); + FDKmemcpy(tC->acfWindow[LOFILT], acfWindowShort, FDKmin(sizeof(acfWindowShort), sizeof(tC->acfWindow[HIFILT]))); + } + else { + FDKmemcpy(tC->acfWindow[HIFILT], acfWindowLong, FDKmin(sizeof(acfWindowLong), sizeof(tC->acfWindow[HIFILT]))); + FDKmemcpy(tC->acfWindow[LOFILT], acfWindowLong, FDKmin(sizeof(acfWindowLong), sizeof(tC->acfWindow[HIFILT]))); + } + break; + case 480: + case 512: + { + const TNS_PARAMETER_TABULATED* pCfg = FDKaacEnc_GetTnsParam(bitRate, channels, ldSbrPresent); + + if ( pCfg != NULL ) { + tC->lpcStartBand[HIFILT] = FDKaacEnc_FreqToBandWithRounding(pCfg->filterStartFreq[HIFILT], sampleRate, pC->sfbCnt, pC->sfbOffset); + tC->lpcStartLine[HIFILT] = pC->sfbOffset[tC->lpcStartBand[HIFILT]]; + tC->lpcStartBand[LOFILT] = FDKaacEnc_FreqToBandWithRounding(pCfg->filterStartFreq[LOFILT], sampleRate, pC->sfbCnt, pC->sfbOffset); + tC->lpcStartLine[LOFILT] = pC->sfbOffset[tC->lpcStartBand[LOFILT]]; + + tC->confTab.threshOn[HIFILT] = pCfg->threshOn[HIFILT]; + tC->confTab.threshOn[LOFILT] = pCfg->threshOn[LOFILT]; + + tC->confTab.tnsLimitOrder[HIFILT] = pCfg->tnsLimitOrder[HIFILT]; + tC->confTab.tnsLimitOrder[LOFILT] = pCfg->tnsLimitOrder[LOFILT]; + + tC->confTab.tnsFilterDirection[HIFILT] = pCfg->tnsFilterDirection[HIFILT]; + tC->confTab.tnsFilterDirection[LOFILT] = pCfg->tnsFilterDirection[LOFILT]; + + tC->confTab.acfSplit[HIFILT] = pCfg->acfSplit[HIFILT]; + tC->confTab.acfSplit[LOFILT] = pCfg->acfSplit[LOFILT]; + + tC->confTab.filterEnabled[HIFILT] = pCfg->filterEnabled[HIFILT]; + tC->confTab.filterEnabled[LOFILT] = pCfg->filterEnabled[LOFILT]; + tC->confTab.seperateFiltersAllowed = pCfg->seperateFiltersAllowed; + + FDKaacEnc_CalcGaussWindow(tC->acfWindow[HIFILT], tC->maxOrder+1, sampleRate, granuleLength, pCfg->tnsTimeResolution[HIFILT], TNS_TIMERES_SCALE); + FDKaacEnc_CalcGaussWindow(tC->acfWindow[LOFILT], tC->maxOrder+1, sampleRate, granuleLength, pCfg->tnsTimeResolution[LOFILT], TNS_TIMERES_SCALE); + } + else { + tC->tnsActive = FALSE; /* no configuration available, disable tns tool */ + } + } + break; + default: + tC->tnsActive = FALSE; /* no configuration available, disable tns tool */ + } + + return AAC_ENC_OK; + +} + +/***************************************************************************/ +/*! + \brief FDKaacEnc_ScaleUpSpectrum + + Scales up spectrum lines in a given frequency section + + \param scaled spectrum + \param original spectrum + \param frequency line to start scaling + \param frequency line to enc scaling + + \return scale factor + +****************************************************************************/ +static inline INT FDKaacEnc_ScaleUpSpectrum( + FIXP_DBL *dest, + const FIXP_DBL *src, + const INT startLine, + const INT stopLine + ) +{ + INT i, scale; + + FIXP_DBL maxVal = FL2FXCONST_DBL(0.f); + + /* Get highest value in given spectrum */ + for (i=startLine; i>scale); + } + } + else { + for (i=startLine; i<(stopLine-lag); i++) { + result += (fMult(spectrum[i], spectrum[i+lag])>>scale); + } + } + + return result; +} + +/***************************************************************************/ +/*! + \brief FDKaacEnc_AutoCorrNormFac + + Autocorrelation function for 1st and 2nd half of the spectrum + + \param pointer to spectrum + \param pointer to autocorrelation window + \param filter start line + +****************************************************************************/ +static inline FIXP_DBL FDKaacEnc_AutoCorrNormFac( + const FIXP_DBL value, + const INT scale, + INT *sc + ) +{ + #define HLM_MIN_NRG 0.0000000037252902984619140625f /* 2^-28 */ + #define MAX_INV_NRGFAC (1.f/HLM_MIN_NRG) + + FIXP_DBL retValue; + FIXP_DBL A, B; + + if (scale>=0) { + A = value; + B = FL2FXCONST_DBL(HLM_MIN_NRG)>>fixMin(DFRACT_BITS-1,scale); + } + else { + A = value>>fixMin(DFRACT_BITS-1,(-scale)); + B = FL2FXCONST_DBL(HLM_MIN_NRG); + } + + if (A > B) { + int shift = 0; + FIXP_DBL tmp = invSqrtNorm2(value,&shift); + + retValue = fMult(tmp,tmp); + *sc += (2*shift); + } + else { + /* MAX_INV_NRGFAC*FDKpow(2,-28) = 1/2^-28 * 2^-28 = 1.0 */ + retValue = /*FL2FXCONST_DBL(MAX_INV_NRGFAC*FDKpow(2,-28))*/ (FIXP_DBL)MAXVAL_DBL; + *sc += scale+28; + } + + return retValue; +} + +static void FDKaacEnc_MergedAutoCorrelation( + const FIXP_DBL *spectrum, + const FIXP_DBL acfWindow[MAX_NUM_OF_FILTERS][TNS_MAX_ORDER+3+1], + const INT lpcStartLine[MAX_NUM_OF_FILTERS], + const INT lpcStopLine, + const INT maxOrder, + const INT acfSplit[MAX_NUM_OF_FILTERS], + FIXP_DBL *_rxx1, + FIXP_DBL *_rxx2 + ) +{ + int i, idx0, idx1, idx2, idx3, idx4, lag; + FIXP_DBL rxx1_0, rxx2_0, rxx3_0, rxx4_0; + + /* buffer for temporal spectrum */ + C_ALLOC_SCRATCH_START(pSpectrum, FIXP_DBL, (1024)); + + /* pre-initialization output */ + FDKmemclear(&_rxx1[0], sizeof(FIXP_DBL)*(maxOrder+1)); + FDKmemclear(&_rxx2[0], sizeof(FIXP_DBL)*(maxOrder+1)); + + /* MDCT line indices separating the 1st, 2nd, 3rd, and 4th analysis quarters */ + if ( (acfSplit[LOFILT]==-1) || (acfSplit[HIFILT]==-1) ) { + /* autocorrelation function for 1st, 2nd, 3rd, and 4th quarter of the spectrum */ + idx0 = lpcStartLine[LOFILT]; + i = lpcStopLine - lpcStartLine[LOFILT]; + idx1 = idx0 + i / 4; + idx2 = idx0 + i / 2; + idx3 = idx0 + i * 3 / 4; + idx4 = lpcStopLine; + } + else { + FDK_ASSERT(acfSplit[LOFILT]==1); + FDK_ASSERT(acfSplit[HIFILT]==3); + i = (lpcStopLine - lpcStartLine[HIFILT]) / 3; + idx0 = lpcStartLine[LOFILT]; + idx1 = lpcStartLine[HIFILT]; + idx2 = idx1 + i; + idx3 = idx2 + i; + idx4 = lpcStopLine; + } + + /* copy spectrum to temporal buffer and scale up as much as possible */ + INT sc1 = FDKaacEnc_ScaleUpSpectrum(pSpectrum, spectrum, idx0, idx1); + INT sc2 = FDKaacEnc_ScaleUpSpectrum(pSpectrum, spectrum, idx1, idx2); + INT sc3 = FDKaacEnc_ScaleUpSpectrum(pSpectrum, spectrum, idx2, idx3); + INT sc4 = FDKaacEnc_ScaleUpSpectrum(pSpectrum, spectrum, idx3, idx4); + + /* get scaling values for summation */ + INT nsc1, nsc2, nsc3, nsc4; + for (nsc1=1; (1<dataRaw.Short.subBlockInfo[subBlockNumber] + : &tnsData->dataRaw.Long.subBlockInfo; + + tnsData->filtersMerged = FALSE; + tsbi->tnsActive = FALSE; + tsbi->predictionGain = 1000; + tnsInfo->numOfFilters[subBlockNumber] = 0; + tnsInfo->coefRes[subBlockNumber] = tC->coefRes; + for (i = 0; i < tC->maxOrder; i++) { + tnsInfo->coef[subBlockNumber][HIFILT][i] = tnsInfo->coef[subBlockNumber][LOFILT][i] = 0; + } + + tnsInfo->length[subBlockNumber][HIFILT] = tnsInfo->length[subBlockNumber][LOFILT] = 0; + tnsInfo->order [subBlockNumber][HIFILT] = tnsInfo->order [subBlockNumber][LOFILT] = 0; + + if ( (tC->tnsActive) && (tC->maxOrder>0) ) + { + int sumSqrCoef; + + FDKaacEnc_MergedAutoCorrelation( + spectrum, + tC->acfWindow, + tC->lpcStartLine, + tC->lpcStopLine, + tC->maxOrder, + tC->confTab.acfSplit, + rxx1, + rxx2); + + /* compute higher TNS filter in lattice (ParCor) form with LeRoux-Gueguen algorithm */ + tsbi->predictionGain = FDKaacEnc_AutoToParcor(rxx2, parcor_tmp, tC->confTab.tnsLimitOrder[HIFILT]); + + /* non-linear quantization of TNS lattice coefficients with given resolution */ + FDKaacEnc_Parcor2Index( + parcor_tmp, + tnsInfo->coef[subBlockNumber][HIFILT], + tC->confTab.tnsLimitOrder[HIFILT], + tC->coefRes); + + /* reduce filter order by truncating trailing zeros, compute sum(abs(coefs)) */ + for (i = tC->confTab.tnsLimitOrder[HIFILT] - 1; i >= 0; i--) { + if (tnsInfo->coef[subBlockNumber][HIFILT][i] != 0) { + break; + } + } + + tnsInfo->order[subBlockNumber][HIFILT] = i + 1; + + sumSqrCoef = 0; + for (; i >= 0; i--) { + sumSqrCoef += tnsInfo->coef[subBlockNumber][HIFILT][i] * tnsInfo->coef[subBlockNumber][HIFILT][i]; + } + + tnsInfo->direction[subBlockNumber][HIFILT] = tC->confTab.tnsFilterDirection[HIFILT]; + tnsInfo->length[subBlockNumber][HIFILT] = sfbCnt - tC->lpcStartBand[HIFILT]; + + /* disable TNS if predictionGain is less than 3dB or sumSqrCoef is too small */ + if ((tsbi->predictionGain > tC->confTab.threshOn[HIFILT]) || (sumSqrCoef > (tC->confTab.tnsLimitOrder[HIFILT]/2 + 2))) + { + tsbi->tnsActive = TRUE; + tnsInfo->numOfFilters[subBlockNumber]++; + + /* compute second filter for lower quarter; only allowed for long windows! */ + if ( (blockType != SHORT_WINDOW) && + (tC->confTab.filterEnabled[LOFILT]) && (tC->confTab.seperateFiltersAllowed) ) + { + /* compute second filter for lower frequencies */ + + /* compute TNS filter in lattice (ParCor) form with LeRoux-Gueguen algorithm */ + INT predGain = FDKaacEnc_AutoToParcor(rxx1, parcor_tmp, tC->confTab.tnsLimitOrder[LOFILT]); + + /* non-linear quantization of TNS lattice coefficients with given resolution */ + FDKaacEnc_Parcor2Index( + parcor_tmp, + tnsInfo->coef[subBlockNumber][LOFILT], + tC->confTab.tnsLimitOrder[LOFILT], + tC->coefRes); + + /* reduce filter order by truncating trailing zeros, compute sum(abs(coefs)) */ + for (i = tC->confTab.tnsLimitOrder[LOFILT] - 1; i >= 0; i--) { + if (tnsInfo->coef[subBlockNumber][LOFILT][i] != 0) { + break; + } + } + tnsInfo->order[subBlockNumber][LOFILT] = i + 1; + + sumSqrCoef = 0; + for (; i >= 0; i--) { + sumSqrCoef += tnsInfo->coef[subBlockNumber][LOFILT][i] * tnsInfo->coef[subBlockNumber][LOFILT][i]; + } + + tnsInfo->direction[subBlockNumber][LOFILT] = tC->confTab.tnsFilterDirection[LOFILT]; + tnsInfo->length[subBlockNumber][LOFILT] = tC->lpcStartBand[HIFILT] - tC->lpcStartBand[LOFILT]; + + /* filter lower quarter if gain is high enough, but not if it's too high */ + if ( ( (predGain > tC->confTab.threshOn[LOFILT]) && (predGain < (16000 * tC->confTab.tnsLimitOrder[LOFILT])) ) + || ( (sumSqrCoef > 9) && (sumSqrCoef < 22 * tC->confTab.tnsLimitOrder[LOFILT]) ) ) + { + /* compare lower to upper filter; if they are very similar, merge them */ + sumSqrCoef = 0; + for (i = 0; i < tC->confTab.tnsLimitOrder[LOFILT]; i++) { + sumSqrCoef += FDKabs(tnsInfo->coef[subBlockNumber][HIFILT][i] - tnsInfo->coef[subBlockNumber][LOFILT][i]); + } + if ( (sumSqrCoef < 2) && + (tnsInfo->direction[subBlockNumber][LOFILT] == tnsInfo->direction[subBlockNumber][HIFILT]) ) + { + tnsData->filtersMerged = TRUE; + tnsInfo->length[subBlockNumber][HIFILT] = sfbCnt - tC->lpcStartBand[LOFILT]; + for (; i < tnsInfo->order[subBlockNumber][HIFILT]; i++) { + if (FDKabs(tnsInfo->coef[subBlockNumber][HIFILT][i]) > 1) { + break; + } + } + for (i--; i >= 0; i--) { + if (tnsInfo->coef[subBlockNumber][HIFILT][i] != 0) { + break; + } + } + if (i < tnsInfo->order[subBlockNumber][HIFILT]) { + tnsInfo->order[subBlockNumber][HIFILT] = i + 1; + } + } + else { + tnsInfo->numOfFilters[subBlockNumber]++; + } + } /* filter lower part */ + } /* second filter allowed */ + } /* if predictionGain > 1437 ... */ + } /* maxOrder > 0 && tnsActive */ + + return 0; + +} + + +/***************************************************************************/ +/*! + \brief FDKaacLdEnc_TnsSync + + synchronize TNS parameters when TNS gain difference small (relative) + + \param pointer to TNS data structure (destination) + \param pointer to TNS data structure (source) + \param pointer to TNS config structure + \param number of sub-block + \param block type + + \return void +****************************************************************************/ +void FDKaacEnc_TnsSync( + TNS_DATA *tnsDataDest, + const TNS_DATA *tnsDataSrc, + TNS_INFO *tnsInfoDest, + TNS_INFO *tnsInfoSrc, + const INT blockTypeDest, + const INT blockTypeSrc, + const TNS_CONFIG *tC + ) +{ + int i, w, absDiff, nWindows; + TNS_SUBBLOCK_INFO *sbInfoDest; + const TNS_SUBBLOCK_INFO *sbInfoSrc; + + /* if one channel contains short blocks and the other not, do not synchronize */ + if ( (blockTypeSrc == SHORT_WINDOW && blockTypeDest != SHORT_WINDOW) || + (blockTypeDest == SHORT_WINDOW && blockTypeSrc != SHORT_WINDOW) ) + { + return; + } + + if (blockTypeDest != SHORT_WINDOW) { + sbInfoDest = &tnsDataDest->dataRaw.Long.subBlockInfo; + sbInfoSrc = &tnsDataSrc->dataRaw.Long.subBlockInfo; + nWindows = 1; + } else { + sbInfoDest = &tnsDataDest->dataRaw.Short.subBlockInfo[0]; + sbInfoSrc = &tnsDataSrc->dataRaw.Short.subBlockInfo[0]; + nWindows = 8; + } + + for (w=0; wtnsActive || pSbInfoSrcW->tnsActive) { + for (i = 0; i < tC->maxOrder; i++) { + absDiff = FDKabs(tnsInfoDest->coef[w][HIFILT][i] - tnsInfoSrc->coef[w][HIFILT][i]); + absDiffSum += absDiff; + /* if coefficients diverge too much between channels, do not synchronize */ + if ((absDiff > 1) || (absDiffSum > 2)) { + doSync = 0; + break; + } + } + + if (doSync) { + /* if no significant difference was detected, synchronize coefficient sets */ + if (pSbInfoSrcW->tnsActive) { + /* no dest filter, or more dest than source filters: use one dest filter */ + if ((!pSbInfoDestW->tnsActive) || + ((pSbInfoDestW->tnsActive) && (tnsInfoDest->numOfFilters[w] > tnsInfoSrc->numOfFilters[w]))) + { + pSbInfoDestW->tnsActive = tnsInfoDest->numOfFilters[w] = 1; + } + tnsDataDest->filtersMerged = tnsDataSrc->filtersMerged; + tnsInfoDest->order [w][HIFILT] = tnsInfoSrc->order [w][HIFILT]; + tnsInfoDest->length [w][HIFILT] = tnsInfoSrc->length [w][HIFILT]; + tnsInfoDest->direction [w][HIFILT] = tnsInfoSrc->direction [w][HIFILT]; + tnsInfoDest->coefCompress[w][HIFILT] = tnsInfoSrc->coefCompress[w][HIFILT]; + + for (i = 0; i < tC->maxOrder; i++) { + tnsInfoDest->coef[w][HIFILT][i] = tnsInfoSrc->coef[w][HIFILT][i]; + } + } + else + pSbInfoDestW->tnsActive = tnsInfoDest->numOfFilters[w] = 0; + } + } + + } +} + +/***************************************************************************/ +/*! + \brief FDKaacEnc_TnsEncode + + perform TNS encoding + + \param pointer to TNS info structure + \param pointer to TNS data structure + \param number of sfbs + \param pointer to TNS config structure + \param low-pass line + \param pointer to spectrum + \param number of sub-block + \param block type + + \return ERROR STATUS +****************************************************************************/ +INT FDKaacEnc_TnsEncode( + TNS_INFO* tnsInfo, + TNS_DATA* tnsData, + const INT numOfSfb, + const TNS_CONFIG *tC, + const INT lowPassLine, + FIXP_DBL* spectrum, + const INT subBlockNumber, + const INT blockType + ) +{ + INT i, startLine, stopLine; + + if ( ( (blockType == SHORT_WINDOW) && (!tnsData->dataRaw.Short.subBlockInfo[subBlockNumber].tnsActive) ) + || ( (blockType != SHORT_WINDOW) && (!tnsData->dataRaw.Long.subBlockInfo.tnsActive) ) ) + { + return 1; + } + + startLine = (tnsData->filtersMerged) ? tC->lpcStartLine[LOFILT] : tC->lpcStartLine[HIFILT]; + stopLine = tC->lpcStopLine; + + for (i=0; inumOfFilters[subBlockNumber]; i++) { + + INT lpcGainFactor; + FIXP_DBL LpcCoeff[TNS_MAX_ORDER]; + FIXP_DBL workBuffer[TNS_MAX_ORDER]; + FIXP_DBL parcor_tmp[TNS_MAX_ORDER]; + + FDKaacEnc_Index2Parcor( + tnsInfo->coef[subBlockNumber][i], + parcor_tmp, + tnsInfo->order[subBlockNumber][i], + tC->coefRes); + + lpcGainFactor = FDKaacEnc_ParcorToLpc( + parcor_tmp, + LpcCoeff, + tnsInfo->order[subBlockNumber][i], + workBuffer); + + FDKaacEnc_AnalysisFilter( + &spectrum[startLine], + stopLine - startLine, + LpcCoeff, + tnsInfo->order[subBlockNumber][i], + lpcGainFactor); + + /* update for second filter */ + startLine = tC->lpcStartLine[LOFILT]; + stopLine = tC->lpcStartLine[HIFILT]; + } + + return(0); + +} + +static void FDKaacEnc_CalcGaussWindow( + FIXP_DBL *win, + const int winSize, + const INT samplingRate, + const INT transformResolution, + const FIXP_DBL timeResolution, + const INT timeResolution_e + ) +{ + #define PI_SCALE (2) + #define PI_FIX FL2FXCONST_DBL(3.1416f/(float)(1<> (DFRACT_BITS-1)); + tmp = (FIXP_DBL)((LONG)workBuffer[0]^sign); + + if(input[0]=0; j--) { + FIXP_DBL accu1 = fMult(tmp, input[j]); + FIXP_DBL accu2 = fMult(tmp, workBuffer[j]); + workBuffer[j] += accu1; + input[j] += accu2; + } + + workBuffer++; + } + + tmp = fMult((FIXP_DBL)((LONG)TNS_PREDGAIN_SCALE<<21), fDivNorm(autoCorr_0, input[0], &scale)); + predictionGain = (LONG)scaleValue(tmp,scale-21); + + return (predictionGain); +} + + +static INT FDKaacEnc_Search3(FIXP_DBL parcor) +{ + INT i, index=0; + + for(i=0;i<8;i++){ + if(parcor > FDKaacEnc_tnsCoeff3Borders[i]) + index=i; + } + return(index-4); +} + +static INT FDKaacEnc_Search4(FIXP_DBL parcor) +{ + INT i, index=0; + + for(i=0;i<16;i++){ + if(parcor > FDKaacEnc_tnsCoeff4Borders[i]) + index=i; + } + return(index-8); +} + + +/***************************************************************************** + + functionname: FDKaacEnc_Parcor2Index + +*****************************************************************************/ +static void FDKaacEnc_Parcor2Index( + const FIXP_DBL *parcor, + INT *RESTRICT index, + const INT order, + const INT bitsPerCoeff + ) +{ + INT i; + for(i=0; i, + ptr. to work buffer (required size: order) + output: LPC coefficients + +*****************************************************************************/ +static INT FDKaacEnc_ParcorToLpc( + const FIXP_DBL *reflCoeff, + FIXP_DBL *RESTRICT LpcCoeff, + const INT numOfCoeff, + FIXP_DBL *RESTRICT workBuffer + ) +{ + INT i, j; + INT shiftval, par2LpcShiftVal = 6; /* 6 should be enough, bec. max(numOfCoeff) = 20 */ + FIXP_DBL maxVal = FL2FXCONST_DBL(0.0f); + + LpcCoeff[0] = reflCoeff[0] >> par2LpcShiftVal; + for(i=1; i> par2LpcShiftVal; + } + + /* normalize LpcCoeff and calc shiftfactor */ + for(i=0; i=par2LpcShiftVal) ? par2LpcShiftVal : shiftval; + + for(i=0; i0) { + + INT idx = 0; + + /* keep filter coefficients twice and save memory copy operation in + modulo state buffer */ +#if defined(ARCH_PREFER_MULT_32x16) + FIXP_SGL coeff[2*TNS_MAX_ORDER]; + const FIXP_SGL *pCoeff; + for(i=0;i=0); + signal[j] = (tmp< 12 */ + /* for Short: length TRANS_FAC*TNS_MAX_ORDER (only 5 for short LC) is required -> 8*5=40 */ + /* Currently TRANS_FAC*TNS_MAX_ORDER = 8*12 = 96 (for LC) is used (per channel)! Memory could be saved here! */ + INT coef[TRANS_FAC][MAX_NUM_OF_FILTERS][TNS_MAX_ORDER]; +}TNS_INFO; + +INT FDKaacEnc_FreqToBandWithRounding( + const INT freq, + const INT fs, + const INT numOfBands, + const INT *bandStartOffset + ); + +#endif /* _TNS_H */ diff --git a/libAACenc/src/adj_thr.cpp b/libAACenc/src/adj_thr.cpp new file mode 100644 index 0000000..d9d89f2 --- /dev/null +++ b/libAACenc/src/adj_thr.cpp @@ -0,0 +1,2262 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Werner + contents/description: Threshold compensation + +******************************************************************************/ + +#include "common_fix.h" + +#include "adj_thr_data.h" +#include "adj_thr.h" +#include "qc_data.h" +#include "sf_estim.h" +#include "aacEnc_ram.h" + + + + +#define INV_INT_TAB_SIZE (8) +static const FIXP_DBL invInt[INV_INT_TAB_SIZE] = +{ + 0x7fffffff, 0x7fffffff, 0x40000000, 0x2aaaaaaa, 0x20000000, 0x19999999, 0x15555555, 0x12492492 +}; + + +#define INV_SQRT4_TAB_SIZE (8) +static const FIXP_DBL invSqrt4[INV_SQRT4_TAB_SIZE] = +{ + 0x7fffffff, 0x7fffffff, 0x6ba27e65, 0x61424bb5, 0x5a827999, 0x55994845, 0x51c8e33c, 0x4eb160d1 +}; + + +/*static const INT invRedExp = 4;*/ +static const FIXP_DBL SnrLdMin1 = (FIXP_DBL)0xfcad0ddf; /*FL2FXCONST_DBL(FDKlog(0.316)/FDKlog(2.0)/LD_DATA_SCALING);*/ +static const FIXP_DBL SnrLdMin2 = (FIXP_DBL)0x0351e1a2; /*FL2FXCONST_DBL(FDKlog(3.16) /FDKlog(2.0)/LD_DATA_SCALING);*/ +static const FIXP_DBL SnrLdFac = (FIXP_DBL)0xff5b2c3e; /*FL2FXCONST_DBL(FDKlog(0.8) /FDKlog(2.0)/LD_DATA_SCALING);*/ + +static const FIXP_DBL SnrLdMin3 = (FIXP_DBL)0xfe000000; /*FL2FXCONST_DBL(FDKlog(0.5) /FDKlog(2.0)/LD_DATA_SCALING);*/ +static const FIXP_DBL SnrLdMin4 = (FIXP_DBL)0x02000000; /*FL2FXCONST_DBL(FDKlog(2.0) /FDKlog(2.0)/LD_DATA_SCALING);*/ +static const FIXP_DBL SnrLdMin5 = (FIXP_DBL)0xfc000000; /*FL2FXCONST_DBL(FDKlog(0.25) /FDKlog(2.0)/LD_DATA_SCALING);*/ + + +/* values for avoid hole flag */ +enum _avoid_hole_state { + NO_AH =0, + AH_INACTIVE =1, + AH_ACTIVE =2 +}; + + +/* Q format definitions */ +#define Q_BITFAC (24) /* Q scaling used in FDKaacEnc_bitresCalcBitFac() calculation */ +#define Q_AVGBITS (17) /* scale bit values */ + +static INT FDKaacEnc_bits2pe2( + const INT bits, + const FIXP_DBL factor_m, + const INT factor_e + ) +{ + return (INT)(fMult(factor_m, (FIXP_DBL)(bits<> (Q_AVGBITS-factor_e)); +} + +/***************************************************************************** +functionname: FDKaacEnc_calcThreshExp +description: loudness calculation (threshold to the power of redExp) +*****************************************************************************/ +static void FDKaacEnc_calcThreshExp(FIXP_DBL thrExp[(2)][MAX_GROUPED_SFB], + QC_OUT_CHANNEL* qcOutChannel[(2)], + PSY_OUT_CHANNEL* psyOutChannel[(2)], + const INT nChannels) +{ + INT ch, sfb, sfbGrp; + FIXP_DBL thrExpLdData; + + for (ch=0; chsfbCnt;sfbGrp+= psyOutChannel[ch]->sfbPerGroup) { + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + thrExpLdData = psyOutChannel[ch]->sfbThresholdLdData[sfbGrp+sfb]>>2 ; + thrExp[ch][sfbGrp+sfb] = CalcInvLdData(thrExpLdData); + } + } + } +} + + +/***************************************************************************** + functionname: FDKaacEnc_adaptMinSnr + description: reduce minSnr requirements for bands with relative low energies +*****************************************************************************/ +static void FDKaacEnc_adaptMinSnr(QC_OUT_CHANNEL *qcOutChannel[(2)], + PSY_OUT_CHANNEL *psyOutChannel[(2)], + MINSNR_ADAPT_PARAM *msaParam, + const INT nChannels) +{ + INT ch, sfb, sfbGrp, nSfb; + FIXP_DBL avgEnLD64, dbRatio, minSnrRed; + FIXP_DBL minSnrLimitLD64 = FL2FXCONST_DBL(-0.00503012648262f); /* ld64(0.8f) */ + FIXP_DBL nSfbLD64; + FIXP_DBL accu; + + for (ch=0; chsfbCnt; sfbGrp+=psyOutChannel[ch]->sfbPerGroup) { + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + accu += psyOutChannel[ch]->sfbEnergy[sfbGrp+sfb]>>6; + nSfb++; + } + } + + if ((accu == FL2FXCONST_DBL(0.0f)) || (nSfb == 0)) { + avgEnLD64 = FL2FXCONST_DBL(-1.0f); + } + else { + nSfbLD64 = CalcLdInt(nSfb); + avgEnLD64 = CalcLdData(accu); + avgEnLD64 = avgEnLD64 + FL2FXCONST_DBL(0.09375f) - nSfbLD64; /* 0.09375f: compensate shift with 6 */ + } + + /* reduce minSnr requirement by minSnr^minSnrRed dependent on avgEn/sfbEn */ + for (sfbGrp=0; sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutChannel[ch]->sfbPerGroup) { + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + if ( (msaParam->startRatio + qcOutChannel[ch]->sfbEnergyLdData[sfbGrp+sfb]) < avgEnLD64 ) { + dbRatio = fMult((avgEnLD64 - qcOutChannel[ch]->sfbEnergyLdData[sfbGrp+sfb]),FL2FXCONST_DBL(0.3010299956f)); /* scaled by (1.0f/(10.0f*64.0f)) */ + minSnrRed = msaParam->redOffs + fMult(msaParam->redRatioFac,dbRatio); /* scaled by 1.0f/64.0f*/ + minSnrRed = fixMax(minSnrRed, msaParam->maxRed); /* scaled by 1.0f/64.0f*/ + qcOutChannel[ch]->sfbMinSnrLdData[sfbGrp+sfb] = (fMult(qcOutChannel[ch]->sfbMinSnrLdData[sfbGrp+sfb],minSnrRed)) << 6; + qcOutChannel[ch]->sfbMinSnrLdData[sfbGrp+sfb] = fixMin(minSnrLimitLD64, qcOutChannel[ch]->sfbMinSnrLdData[sfbGrp+sfb]); + } + } + } + } +} + + +/***************************************************************************** +functionname: FDKaacEnc_initAvoidHoleFlag +description: determine bands where avoid hole is not necessary resp. possible +*****************************************************************************/ +static void FDKaacEnc_initAvoidHoleFlag(QC_OUT_CHANNEL *qcOutChannel[(2)], + PSY_OUT_CHANNEL *psyOutChannel[(2)], + UCHAR ahFlag[(2)][MAX_GROUPED_SFB], + struct TOOLSINFO *toolsInfo, + const INT nChannels, + const PE_DATA *peData, + AH_PARAM *ahParam) +{ + INT ch, sfb, sfbGrp; + FIXP_DBL sfbEn, sfbEnm1; + FIXP_DBL sfbEnLdData; + FIXP_DBL avgEnLdData; + + /* decrease spread energy by 3dB for long blocks, resp. 2dB for shorts + (avoid more holes in long blocks) */ + for (ch=0; chlastWindowSequence != SHORT_WINDOW) { + for (sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt;sfbGrp+= psyOutChannel[ch]->sfbPerGroup) + for (sfb=0; sfbmaxSfbPerGroup; sfb++) + qcOutChan->sfbSpreadEnergy[sfbGrp+sfb] >>= 1 ; + } + else { + for (sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt;sfbGrp+= psyOutChannel[ch]->sfbPerGroup) + for (sfb=0; sfbmaxSfbPerGroup; sfb++) + qcOutChan->sfbSpreadEnergy[sfbGrp+sfb] = + fMult(FL2FXCONST_DBL(0.63f), + qcOutChan->sfbSpreadEnergy[sfbGrp+sfb]) ; + } + } + + /* increase minSnr for local peaks, decrease it for valleys */ + if (ahParam->modifyMinSnr) { + for(ch=0; chsfbCnt;sfbGrp+= psyOutChannel[ch]->sfbPerGroup){ + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + FIXP_DBL sfbEnp1, avgEn; + if (sfb > 0) + sfbEnm1 = qcOutChan->sfbEnergy[sfbGrp+sfb-1]; + else + sfbEnm1 = qcOutChan->sfbEnergy[sfbGrp+sfb]; + + if (sfb < psyOutChannel[ch]->maxSfbPerGroup-1) + sfbEnp1 = qcOutChan->sfbEnergy[sfbGrp+sfb+1]; + else + sfbEnp1 = qcOutChan->sfbEnergy[sfbGrp+sfb]; + + avgEn = (sfbEnm1>>1) + (sfbEnp1>>1); + avgEnLdData = CalcLdData(avgEn); + sfbEn = qcOutChan->sfbEnergy[sfbGrp+sfb]; + sfbEnLdData = qcOutChan->sfbEnergyLdData[sfbGrp+sfb]; + /* peak ? */ + if (sfbEn > avgEn) { + FIXP_DBL tmpMinSnrLdData; + if (psyOutChannel[ch]->lastWindowSequence==LONG_WINDOW) + tmpMinSnrLdData = fixMax( SnrLdFac + (FIXP_DBL)(avgEnLdData - sfbEnLdData), (FIXP_DBL)SnrLdMin1 ) ; + else + tmpMinSnrLdData = fixMax( SnrLdFac + (FIXP_DBL)(avgEnLdData - sfbEnLdData), (FIXP_DBL)SnrLdMin3 ) ; + + qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] = + fixMin(qcOutChan->sfbMinSnrLdData[sfbGrp+sfb], tmpMinSnrLdData); + } + /* valley ? */ + if ( ((sfbEnLdData+(FIXP_DBL)SnrLdMin4) < (FIXP_DBL)avgEnLdData) && (sfbEn > FL2FXCONST_DBL(0.0)) ) { + FIXP_DBL tmpMinSnrLdData = avgEnLdData - sfbEnLdData -(FIXP_DBL)SnrLdMin4 + qcOutChan->sfbMinSnrLdData[sfbGrp+sfb]; + tmpMinSnrLdData = fixMin((FIXP_DBL)SnrLdFac, tmpMinSnrLdData); + qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] = fixMin(tmpMinSnrLdData, + (FIXP_DBL)(qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] + SnrLdMin2 )); + } + } + } + } + } + + /* stereo: adapt the minimum requirements sfbMinSnr of mid and + side channels to avoid spending unnoticable bits */ + if (nChannels == 2) { + QC_OUT_CHANNEL* qcOutChanM = qcOutChannel[0]; + QC_OUT_CHANNEL* qcOutChanS = qcOutChannel[1]; + PSY_OUT_CHANNEL* psyOutChanM = psyOutChannel[0]; + for(sfbGrp = 0;sfbGrp < psyOutChanM->sfbCnt;sfbGrp+= psyOutChanM->sfbPerGroup){ + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + if (toolsInfo->msMask[sfbGrp+sfb]) { + FIXP_DBL maxSfbEnLd = fixMax(qcOutChanM->sfbEnergyLdData[sfbGrp+sfb],qcOutChanS->sfbEnergyLdData[sfbGrp+sfb]); + FIXP_DBL maxThrLd, sfbMinSnrTmpLd; + + if ( ((SnrLdMin5>>1) + (maxSfbEnLd>>1) + (qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb]>>1)) <= FL2FXCONST_DBL(-0.5f)) + maxThrLd = FL2FXCONST_DBL(-1.0f) ; + else + maxThrLd = SnrLdMin5 + maxSfbEnLd + qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb]; + + if (qcOutChanM->sfbEnergy[sfbGrp+sfb] > FL2FXCONST_DBL(0.0f)) + sfbMinSnrTmpLd = maxThrLd - qcOutChanM->sfbEnergyLdData[sfbGrp+sfb]; + else + sfbMinSnrTmpLd = FL2FXCONST_DBL(0.0f); + + qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb] = fixMax(qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb],sfbMinSnrTmpLd); + + if (qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb] <= FL2FXCONST_DBL(0.0f)) + qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb] = fixMin(qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb], (FIXP_DBL)SnrLdFac); + + if (qcOutChanS->sfbEnergy[sfbGrp+sfb] > FL2FXCONST_DBL(0.0f)) + sfbMinSnrTmpLd = maxThrLd - qcOutChanS->sfbEnergyLdData[sfbGrp+sfb]; + else + sfbMinSnrTmpLd = FL2FXCONST_DBL(0.0f); + + qcOutChanS->sfbMinSnrLdData[sfbGrp+sfb] = fixMax(qcOutChanS->sfbMinSnrLdData[sfbGrp+sfb],sfbMinSnrTmpLd); + + if (qcOutChanS->sfbMinSnrLdData[sfbGrp+sfb] <= FL2FXCONST_DBL(0.0f)) + qcOutChanS->sfbMinSnrLdData[sfbGrp+sfb] = fixMin(qcOutChanS->sfbMinSnrLdData[sfbGrp+sfb],(FIXP_DBL)SnrLdFac); + + if (qcOutChanM->sfbEnergy[sfbGrp+sfb]>qcOutChanM->sfbSpreadEnergy[sfbGrp+sfb]) + qcOutChanS->sfbSpreadEnergy[sfbGrp+sfb] = + fMult(qcOutChanS->sfbEnergy[sfbGrp+sfb], FL2FXCONST_DBL(0.9f)); + + if (qcOutChanS->sfbEnergy[sfbGrp+sfb]>qcOutChanS->sfbSpreadEnergy[sfbGrp+sfb]) + qcOutChanM->sfbSpreadEnergy[sfbGrp+sfb] = + fMult(qcOutChanM->sfbEnergy[sfbGrp+sfb], FL2FXCONST_DBL(0.9f)); + } + } + } + } + + /* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */ + for(ch=0; chsfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){ + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + if ((qcOutChan->sfbSpreadEnergy[sfbGrp+sfb] > qcOutChan->sfbEnergy[sfbGrp+sfb]) + || (qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] > FL2FXCONST_DBL(0.0f))) { + ahFlag[ch][sfbGrp+sfb] = NO_AH; + } + else { + ahFlag[ch][sfbGrp+sfb] = AH_INACTIVE; + } + } + } + } +} + + + +/** + * \brief Calculate constants that do not change during successive pe calculations. + * + * \param peData Pointer to structure containing PE data of current element. + * \param psyOutChannel Pointer to PSY_OUT_CHANNEL struct holding nChannels elements. + * \param qcOutChannel Pointer to QC_OUT_CHANNEL struct holding nChannels elements. + * \param nChannels Number of channels in element. + * \param peOffset Fixed PE offset defined while FDKaacEnc_AdjThrInit() depending on bitrate. + * + * \return void + */ +static +void FDKaacEnc_preparePe(PE_DATA *peData, + PSY_OUT_CHANNEL* psyOutChannel[(2)], + QC_OUT_CHANNEL* qcOutChannel[(2)], + const INT nChannels, + const INT peOffset) +{ + INT ch; + + for(ch=0; chpeChannelData[ch], + psyOutChan->sfbEnergyLdData, + psyOutChan->sfbThresholdLdData, + qcOutChannel[ch]->sfbFormFactorLdData, + psyOutChan->sfbOffsets, + psyOutChan->sfbCnt, + psyOutChan->sfbPerGroup, + psyOutChan->maxSfbPerGroup); + } + peData->offset = peOffset; +} + +/** + * \brief Calculate weighting factor for threshold adjustment. + * + * Calculate weighting factor to be applied at energies and thresholds in ld64 format. + * + * \param peData, Pointer to PE data in current element. + * \param psyOutChannel Pointer to PSY_OUT_CHANNEL struct holding nChannels elements. + * \param qcOutChannel Pointer to QC_OUT_CHANNEL struct holding nChannels elements. + * \param toolsInfo Pointer to tools info struct of current element. + * \param adjThrStateElement Pointer to ATS_ELEMENT holding enFacPatch states. + * \param nChannels Number of channels in element. + * \param usePatchTool Apply the weighting tool 0 (no) else (yes). + * + * \return void + */ +static +void FDKaacEnc_calcWeighting(PE_DATA *peData, + PSY_OUT_CHANNEL* psyOutChannel[(2)], + QC_OUT_CHANNEL* qcOutChannel[(2)], + struct TOOLSINFO *toolsInfo, + ATS_ELEMENT* adjThrStateElement, + const INT nChannels, + const INT usePatchTool) +{ + int ch, noShortWindowInFrame = TRUE; + INT exePatchM = 0; + + for (ch=0; chlastWindowSequence == SHORT_WINDOW) { + noShortWindowInFrame = FALSE; + } + FDKmemclear(qcOutChannel[ch]->sfbEnFacLd, MAX_GROUPED_SFB*sizeof(FIXP_DBL)); + } + + if (usePatchTool==0) { + return; /* tool is disabled */ + } + + for (ch=0; chsfbCnt; sfb++) { + + FIXP_DBL nrgFac12 = CalcInvLdData(psyOutChan->sfbEnergyLdData[sfb]>>1); /* nrg^(1/2) */ + FIXP_DBL nrgFac14 = CalcInvLdData(psyOutChan->sfbEnergyLdData[sfb]>>2); /* nrg^(1/4) */ + + /* maximal number of bands is 64, results scaling factor 6 */ + nLinesSum += peData->peChannelData[ch].sfbNLines[sfb]; /* relevant lines */ + nrgTotal += ( psyOutChan->sfbEnergy[sfb] >> 6 ); /* sum up nrg */ + nrgSum12 += ( nrgFac12 >> 6 ); /* sum up nrg^(2/4) */ + nrgSum14 += ( nrgFac14 >> 6 ); /* sum up nrg^(1/4) */ + nrgSum34 += ( fMult(nrgFac14, nrgFac12) >> 6 ); /* sum up nrg^(3/4) */ + } + + nrgTotal = CalcLdData(nrgTotal); /* get ld64 of total nrg */ + + nrgFacLd_14 = CalcLdData(nrgSum14) - nrgTotal; /* ld64(nrgSum14/nrgTotal) */ + nrgFacLd_12 = CalcLdData(nrgSum12) - nrgTotal; /* ld64(nrgSum12/nrgTotal) */ + nrgFacLd_34 = CalcLdData(nrgSum34) - nrgTotal; /* ld64(nrgSum34/nrgTotal) */ + + adjThrStateElement->chaosMeasureEnFac[ch] = FDKmax( FL2FXCONST_DBL(0.1875f), fDivNorm(nLinesSum,psyOutChan->sfbOffsets[psyOutChan->sfbCnt]) ); + + usePatch = (adjThrStateElement->chaosMeasureEnFac[ch] > FL2FXCONST_DBL(0.78125f)); + exePatch = ((usePatch) && (adjThrStateElement->lastEnFacPatch[ch])); + + for (sfb = 0; sfb < psyOutChan->sfbCnt; sfb++) { + INT sfbExePatch; + + /* for MS coupled SFBs, also execute patch in side channel if done in mid channel */ + if ((ch == 1) && (toolsInfo->msMask[sfb])) { + sfbExePatch = exePatchM; + } + else { + sfbExePatch = exePatch; + } + + if ( (sfbExePatch) && (psyOutChan->sfbEnergy[sfb]>FL2FXCONST_DBL(0.f)) ) + { + /* execute patch based on spectral flatness calculated above */ + if (adjThrStateElement->chaosMeasureEnFac[ch] > FL2FXCONST_DBL(0.8125f)) { + qcOutChannel[ch]->sfbEnFacLd[sfb] = ( (nrgFacLd_14 + (psyOutChan->sfbEnergyLdData[sfb]+(psyOutChan->sfbEnergyLdData[sfb]>>1)))>>1 ); /* sfbEnergy^(3/4) */ + } + else if (adjThrStateElement->chaosMeasureEnFac[ch] > FL2FXCONST_DBL(0.796875f)) { + qcOutChannel[ch]->sfbEnFacLd[sfb] = ( (nrgFacLd_12 + psyOutChan->sfbEnergyLdData[sfb])>>1 ); /* sfbEnergy^(2/4) */ + } + else { + qcOutChannel[ch]->sfbEnFacLd[sfb] = ( (nrgFacLd_34 + (psyOutChan->sfbEnergyLdData[sfb]>>1))>>1 ); /* sfbEnergy^(1/4) */ + } + qcOutChannel[ch]->sfbEnFacLd[sfb] = fixMin(qcOutChannel[ch]->sfbEnFacLd[sfb],(FIXP_DBL)0); + + } + } /* sfb loop */ + + adjThrStateElement->lastEnFacPatch[ch] = usePatch; + exePatchM = exePatch; + } + else { + /* !noShortWindowInFrame */ + adjThrStateElement->chaosMeasureEnFac[ch] = FL2FXCONST_DBL(0.75f); + adjThrStateElement->lastEnFacPatch[ch] = TRUE; /* allow use of sfbEnFac patch in upcoming frame */ + } + + } /* ch loop */ + +} + + + + +/***************************************************************************** +functionname: FDKaacEnc_calcPe +description: calculate pe for both channels +*****************************************************************************/ +static +void FDKaacEnc_calcPe(PSY_OUT_CHANNEL* psyOutChannel[(2)], + QC_OUT_CHANNEL* qcOutChannel[(2)], + PE_DATA *peData, + const INT nChannels) +{ + INT ch; + + peData->pe = peData->offset; + peData->constPart = 0; + peData->nActiveLines = 0; + for(ch=0; chpeChannelData[ch]; + FDKaacEnc_calcSfbPe(&peData->peChannelData[ch], + qcOutChannel[ch]->sfbWeightedEnergyLdData, + qcOutChannel[ch]->sfbThresholdLdData, + psyOutChannel[ch]->sfbCnt, + psyOutChannel[ch]->sfbPerGroup, + psyOutChannel[ch]->maxSfbPerGroup, + psyOutChannel[ch]->isBook, + psyOutChannel[ch]->isScale); + + peData->pe += peChanData->pe; + peData->constPart += peChanData->constPart; + peData->nActiveLines += peChanData->nActiveLines; + } +} + +void FDKaacEnc_peCalculation(PE_DATA *peData, + PSY_OUT_CHANNEL* psyOutChannel[(2)], + QC_OUT_CHANNEL* qcOutChannel[(2)], + struct TOOLSINFO *toolsInfo, + ATS_ELEMENT* adjThrStateElement, + const INT nChannels) +{ + /* constants that will not change during successive pe calculations */ + FDKaacEnc_preparePe(peData, psyOutChannel, qcOutChannel, nChannels, adjThrStateElement->peOffset); + + /* calculate weighting factor for threshold adjustment */ + FDKaacEnc_calcWeighting(peData, psyOutChannel, qcOutChannel, toolsInfo, adjThrStateElement, nChannels, 1); +{ + /* no weighting of threholds and energies for mlout */ + /* weight energies and thresholds */ + int ch; + for (ch=0; chsfbCnt; sfbGrp+=psyOutChannel[ch]->sfbPerGroup) { + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + pQcOutCh->sfbWeightedEnergyLdData[sfb+sfbGrp] = pQcOutCh->sfbEnergyLdData[sfb+sfbGrp] - pQcOutCh->sfbEnFacLd[sfb+sfbGrp]; + pQcOutCh->sfbThresholdLdData[sfb+sfbGrp] -= pQcOutCh->sfbEnFacLd[sfb+sfbGrp]; + } + } + } +} + + /* pe without reduction */ + FDKaacEnc_calcPe(psyOutChannel, qcOutChannel, peData, nChannels); +} + + + +/***************************************************************************** +functionname: FDKaacEnc_FDKaacEnc_calcPeNoAH +description: sum the pe data only for bands where avoid hole is inactive +*****************************************************************************/ +static void FDKaacEnc_FDKaacEnc_calcPeNoAH(INT *pe, + INT *constPart, + INT *nActiveLines, + PE_DATA *peData, + UCHAR ahFlag[(2)][MAX_GROUPED_SFB], + PSY_OUT_CHANNEL* psyOutChannel[(2)], + const INT nChannels) +{ + INT ch, sfb,sfbGrp; + + INT pe_tmp = peData->offset; + INT constPart_tmp = 0; + INT nActiveLines_tmp = 0; + for(ch=0; chpeChannelData[ch]; + for(sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt;sfbGrp+= psyOutChannel[ch]->sfbPerGroup){ + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + if(ahFlag[ch][sfbGrp+sfb] < AH_ACTIVE) { + pe_tmp += peChanData->sfbPe[sfbGrp+sfb]; + constPart_tmp += peChanData->sfbConstPart[sfbGrp+sfb]; + nActiveLines_tmp += peChanData->sfbNActiveLines[sfbGrp+sfb]; + } + } + } + } + /* correct scaled pe and constPart values */ + *pe = pe_tmp >> PE_CONSTPART_SHIFT; + *constPart = constPart_tmp >> PE_CONSTPART_SHIFT; + + *nActiveLines = nActiveLines_tmp; +} + + +/***************************************************************************** +functionname: FDKaacEnc_reduceThresholdsCBR +description: apply reduction formula +*****************************************************************************/ +static const FIXP_DBL limitThrReducedLdData = (FIXP_DBL)0x00008000; /*FL2FXCONST_DBL(FDKpow(2.0,-LD_DATA_SCALING/4.0));*/ + +static void FDKaacEnc_reduceThresholdsCBR(QC_OUT_CHANNEL* qcOutChannel[(2)], + PSY_OUT_CHANNEL* psyOutChannel[(2)], + UCHAR ahFlag[(2)][MAX_GROUPED_SFB], + FIXP_DBL thrExp[(2)][MAX_GROUPED_SFB], + const INT nChannels, + const FIXP_DBL redVal, + const SCHAR redValScaling) +{ + INT ch, sfb, sfbGrp; + FIXP_DBL sfbEnLdData, sfbThrLdData, sfbThrReducedLdData; + FIXP_DBL sfbThrExp; + + for(ch=0; chsfbCnt; sfbGrp+= psyOutChannel[ch]->sfbPerGroup){ + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + sfbEnLdData = qcOutChan->sfbWeightedEnergyLdData[sfbGrp+sfb]; + sfbThrLdData = qcOutChan->sfbThresholdLdData[sfbGrp+sfb]; + sfbThrExp = thrExp[ch][sfbGrp+sfb]; + if ((sfbEnLdData > sfbThrLdData) && (ahFlag[ch][sfbGrp+sfb] != AH_ACTIVE)) { + + /* threshold reduction formula: + float tmp = thrExp[ch][sfb]+redVal; + tmp *= tmp; + sfbThrReduced = tmp*tmp; + */ + int minScale = fixMin(CountLeadingBits(sfbThrExp), CountLeadingBits(redVal) - (DFRACT_BITS-1-redValScaling) )-1; + + /* 4*log( sfbThrExp + redVal ) */ + sfbThrReducedLdData = CalcLdData(fAbs(scaleValue(sfbThrExp, minScale) + scaleValue(redVal,(DFRACT_BITS-1-redValScaling)+minScale))) + - (FIXP_DBL)(minScale<<(DFRACT_BITS-1-LD_DATA_SHIFT)); + sfbThrReducedLdData <<= 2; + + /* avoid holes */ + if ( ((sfbThrReducedLdData - sfbEnLdData) > qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] ) + && (ahFlag[ch][sfbGrp+sfb] != NO_AH) ) + { + if (qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] > (FL2FXCONST_DBL(-1.0f) - sfbEnLdData) ){ + sfbThrReducedLdData = fixMax((qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] + sfbEnLdData), sfbThrLdData); + } + else sfbThrReducedLdData = sfbThrLdData; + ahFlag[ch][sfbGrp+sfb] = AH_ACTIVE; + } + + /* minimum of 29 dB Ratio for Thresholds */ + if ((sfbEnLdData+(FIXP_DBL)MAXVAL_DBL) > FL2FXCONST_DBL(9.6336206/LD_DATA_SCALING)){ + sfbThrReducedLdData = fixMax(sfbThrReducedLdData, (sfbEnLdData - FL2FXCONST_DBL(9.6336206/LD_DATA_SCALING))); + } + + qcOutChan->sfbThresholdLdData[sfbGrp+sfb] = sfbThrReducedLdData; + } + } + } + } +} + +/* similar to prepareSfbPe1() */ +static FIXP_DBL FDKaacEnc_calcChaosMeasure(PSY_OUT_CHANNEL *psyOutChannel, + const FIXP_DBL *sfbFormFactorLdData) +{ + #define SCALE_FORM_FAC (4) /* (SCALE_FORM_FAC+FORM_FAC_SHIFT) >= ld(FRAME_LENGTH)*/ + #define SCALE_NRGS (8) + #define SCALE_NLINES (16) + #define SCALE_NRGS_SQRT4 (2) /* 0.25 * SCALE_NRGS */ + #define SCALE_NLINES_P34 (12) /* 0.75 * SCALE_NLINES */ + + INT sfbGrp, sfb; + FIXP_DBL chaosMeasure; + INT frameNLines = 0; + FIXP_DBL frameFormFactor = FL2FXCONST_DBL(0.f); + FIXP_DBL frameEnergy = FL2FXCONST_DBL(0.f); + + for (sfbGrp=0; sfbGrpsfbCnt; sfbGrp+=psyOutChannel->sfbPerGroup) { + for (sfb=0; sfbmaxSfbPerGroup; sfb++){ + if (psyOutChannel->sfbEnergyLdData[sfbGrp+sfb] > psyOutChannel->sfbThresholdLdData[sfbGrp+sfb]) { + frameFormFactor += (CalcInvLdData(sfbFormFactorLdData[sfbGrp+sfb])>>SCALE_FORM_FAC); + frameNLines += (psyOutChannel->sfbOffsets[sfbGrp+sfb+1] - psyOutChannel->sfbOffsets[sfbGrp+sfb]); + frameEnergy += (psyOutChannel->sfbEnergy[sfbGrp+sfb]>>SCALE_NRGS); + } + } + } + + if(frameNLines > 0){ + + /* frameNActiveLines = frameFormFactor*2^FORM_FAC_SHIFT * ((frameEnergy *2^SCALE_NRGS)/frameNLines)^-0.25 + chaosMeasure = frameNActiveLines / frameNLines */ + chaosMeasure = + CalcInvLdData( (((CalcLdData(frameFormFactor)>>1) - + (CalcLdData(frameEnergy)>>(2+1))) - + (fMultDiv2(FL2FXCONST_DBL(0.75f),CalcLdData((FIXP_DBL)frameNLines<<(DFRACT_BITS-1-SCALE_NLINES))) - + (((FIXP_DBL)(SCALE_FORM_FAC-SCALE_NRGS_SQRT4+FORM_FAC_SHIFT-(SCALE_NLINES_P34))<<(DFRACT_BITS-1-LD_DATA_SHIFT))>>1)) + )<<1 ); + } else { + + /* assuming total chaos, if no sfb is above thresholds */ + chaosMeasure = FL2FXCONST_DBL(1.f); + } + + return chaosMeasure; +} + + +/* apply reduction formula for VBR-mode */ +static void FDKaacEnc_reduceThresholdsVBR(QC_OUT_CHANNEL* qcOutChannel[(2)], + PSY_OUT_CHANNEL* psyOutChannel[(2)], + UCHAR ahFlag[(2)][MAX_GROUPED_SFB], + FIXP_DBL thrExp[(2)][MAX_GROUPED_SFB], + const INT nChannels, + const FIXP_DBL vbrQualFactor, + FIXP_DBL* chaosMeasureOld) +{ + INT ch, sfbGrp, sfb; + FIXP_DBL chGroupEnergy[TRANS_FAC][2];/*energy for each group and channel*/ + FIXP_DBL chChaosMeasure[2]; + FIXP_DBL frameEnergy = FL2FXCONST_DBL(1e-10f); + FIXP_DBL chaosMeasure = FL2FXCONST_DBL(0.f); + FIXP_DBL sfbEnLdData, sfbThrLdData, sfbThrExp; + FIXP_DBL sfbThrReducedLdData; + FIXP_DBL chaosMeasureAvg; + INT groupCnt; /* loop counter */ + FIXP_DBL redVal[TRANS_FAC]; /* reduction values; in short-block case one redVal for each group */ + QC_OUT_CHANNEL *qcOutChan = NULL; + PSY_OUT_CHANNEL *psyOutChan = NULL; + +#define SCALE_GROUP_ENERGY (8) + +#define CONST_CHAOS_MEAS_AVG_FAC_0 (FL2FXCONST_DBL(0.25f)) +#define CONST_CHAOS_MEAS_AVG_FAC_1 (FL2FXCONST_DBL(1.f-0.25f)) + +#define MIN_LDTHRESH (FL2FXCONST_DBL(-0.515625f)) + + + for(ch=0; chsfbCnt; sfbGrp+=psyOutChan->sfbPerGroup, groupCnt++) { + chGroupEnergy[groupCnt][ch] = FL2FXCONST_DBL(0.f); + for (sfb=0; sfbmaxSfbPerGroup; sfb++){ + chGroupEnergy[groupCnt][ch] += (psyOutChan->sfbEnergy[sfbGrp+sfb]>>SCALE_GROUP_ENERGY); + } + chEnergy += chGroupEnergy[groupCnt][ch]; + } + frameEnergy += chEnergy; + + /* chaosMeasure */ + if (psyOutChannel[0]->lastWindowSequence == SHORT_WINDOW) { + chChaosMeasure[ch] = FL2FXCONST_DBL(0.5f); /* assume a constant chaos measure of 0.5f for short blocks */ + } else { + chChaosMeasure[ch] = FDKaacEnc_calcChaosMeasure(psyOutChannel[ch], qcOutChannel[ch]->sfbFormFactorLdData); + } + chaosMeasure += fMult(chChaosMeasure[ch], chEnergy); + } + + if(frameEnergy > chaosMeasure) { + INT scale = CntLeadingZeros(frameEnergy) - 1; + FIXP_DBL num = chaosMeasure<>2) + fMult(FL2FXCONST_DBL(0.7f/(4.f*0.3f)), (chaosMeasure - FL2FXCONST_DBL(0.2f)))); + chaosMeasure = (fixMin((FIXP_DBL)(FL2FXCONST_DBL(1.0f)>>2), fixMax((FIXP_DBL)(FL2FXCONST_DBL(0.1f)>>2), chaosMeasure)))<<2; + + /* calculation of reduction value */ + if (psyOutChannel[0]->lastWindowSequence == SHORT_WINDOW){ /* short-blocks */ + FDK_ASSERT(TRANS_FAC==8); + #define WIN_TYPE_SCALE (3) + + INT sfbGrp, groupCnt=0; + for (sfbGrp=0; sfbGrpsfbCnt; sfbGrp+=psyOutChan->sfbPerGroup,groupCnt++) { + + FIXP_DBL groupEnergy = FL2FXCONST_DBL(0.f); + + for(ch=0;chgroupLen[groupCnt]<=INV_INT_TAB_SIZE); + groupEnergy = fMult(groupEnergy,invInt[psyOutChannel[0]->groupLen[groupCnt]]); /* correction of group energy */ + groupEnergy = fixMin(groupEnergy, frameEnergy>>WIN_TYPE_SCALE); /* do not allow an higher redVal as calculated framewise */ + + groupEnergy>>=2; /* 2*WIN_TYPE_SCALE = 6 => 6+2 = 8 ==> 8/4 = int number */ + + redVal[groupCnt] = fMult(fMult(vbrQualFactor,chaosMeasure), + CalcInvLdData(CalcLdData(groupEnergy)>>2) ) + << (int)( ( 2 + (2*WIN_TYPE_SCALE) + SCALE_GROUP_ENERGY )>>2 ) ; + + } + } else { /* long-block */ + + redVal[0] = fMult( fMult(vbrQualFactor,chaosMeasure), + CalcInvLdData(CalcLdData(frameEnergy)>>2) ) + << (int)( SCALE_GROUP_ENERGY>>2 ) ; + } + + for(ch=0; chsfbCnt; sfbGrp+=psyOutChan->sfbPerGroup) { + for (sfb=0; sfbmaxSfbPerGroup; sfb++){ + + sfbEnLdData = (qcOutChan->sfbWeightedEnergyLdData[sfbGrp+sfb]); + sfbThrLdData = (qcOutChan->sfbThresholdLdData[sfbGrp+sfb]); + sfbThrExp = thrExp[ch][sfbGrp+sfb]; + + if ( (sfbThrLdData>=MIN_LDTHRESH) && (sfbEnLdData > sfbThrLdData) && (ahFlag[ch][sfbGrp+sfb] != AH_ACTIVE)) { + + /* Short-Window */ + if (psyOutChannel[ch]->lastWindowSequence == SHORT_WINDOW) { + const int groupNumber = (int) sfb/psyOutChan->sfbPerGroup; + + FDK_ASSERT(INV_SQRT4_TAB_SIZE>psyOutChan->groupLen[groupNumber]); + + sfbThrExp = fMult(sfbThrExp, fMult( FL2FXCONST_DBL(2.82f/4.f), invSqrt4[psyOutChan->groupLen[groupNumber]]))<<2 ; + + if ( sfbThrExp <= (limitThrReducedLdData-redVal[groupNumber]) ) { + sfbThrReducedLdData = FL2FXCONST_DBL(-1.0f); + } + else { + if ((FIXP_DBL)redVal[groupNumber] >= FL2FXCONST_DBL(1.0f)-sfbThrExp) + sfbThrReducedLdData = FL2FXCONST_DBL(0.0f); + else { + /* threshold reduction formula */ + sfbThrReducedLdData = CalcLdData(sfbThrExp + redVal[groupNumber]); + sfbThrReducedLdData <<= 2; + } + } + sfbThrReducedLdData += ( CalcLdInt(psyOutChan->groupLen[groupNumber]) - + ((FIXP_DBL)6<<(DFRACT_BITS-1-LD_DATA_SHIFT)) ); + } + + /* Long-Window */ + else { + if ((FIXP_DBL)redVal[0] >= FL2FXCONST_DBL(1.0f)-sfbThrExp) { + sfbThrReducedLdData = FL2FXCONST_DBL(0.0f); + } + else { + /* threshold reduction formula */ + sfbThrReducedLdData = CalcLdData(sfbThrExp + redVal[0]); + sfbThrReducedLdData <<= 2; + } + } + + /* avoid holes */ + if ( ((sfbThrReducedLdData - sfbEnLdData) > qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] ) + && (ahFlag[ch][sfbGrp+sfb] != NO_AH) ) + { + if (qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] > (FL2FXCONST_DBL(-1.0f) - sfbEnLdData) ){ + sfbThrReducedLdData = fixMax((qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] + sfbEnLdData), sfbThrLdData); + } + else sfbThrReducedLdData = sfbThrLdData; + ahFlag[ch][sfbGrp+sfb] = AH_ACTIVE; + } + + if (sfbThrReducedLdData FL2FXCONST_DBL(9.6336206/LD_DATA_SCALING)){ + sfbThrReducedLdData = fixMax(sfbThrReducedLdData, sfbEnLdData - FL2FXCONST_DBL(9.6336206/LD_DATA_SCALING)); + } + + sfbThrReducedLdData = fixMax(MIN_LDTHRESH,sfbThrReducedLdData); + + qcOutChan->sfbThresholdLdData[sfbGrp+sfb] = sfbThrReducedLdData; + } + } + } + } +} + + +/***************************************************************************** +functionname: FDKaacEnc_correctThresh +description: if pe difference deltaPe between desired pe and real pe is small enough, +the difference can be distributed among the scale factor bands. +New thresholds can be derived from this pe-difference +*****************************************************************************/ +static void FDKaacEnc_correctThresh(CHANNEL_MAPPING* cm, + QC_OUT_ELEMENT* qcElement[(6)], + PSY_OUT_ELEMENT* psyOutElement[(6)], + UCHAR ahFlag[(6)][(2)][MAX_GROUPED_SFB], + FIXP_DBL thrExp[(6)][(2)][MAX_GROUPED_SFB], + const FIXP_DBL redVal[(6)], + const SCHAR redValScaling[(6)], + const INT deltaPe, + const INT processElements, + const INT elementOffset) +{ + INT ch, sfb, sfbGrp; + QC_OUT_CHANNEL *qcOutChan; + PSY_OUT_CHANNEL *psyOutChan; + PE_CHANNEL_DATA *peChanData; + FIXP_DBL thrFactorLdData; + FIXP_DBL sfbEnLdData, sfbThrLdData, sfbThrReducedLdData; + FIXP_DBL *sfbPeFactorsLdData[(6)][(2)]; + FIXP_DBL sfbNActiveLinesLdData[(2)][MAX_GROUPED_SFB]; + INT normFactorInt; + FIXP_DBL normFactorLdData; + + INT nElements = elementOffset+processElements; + INT elementId; + + /* scratch is empty; use temporal memory from quantSpec in QC_OUT_CHANNEL */ + for(elementId=elementOffset;elementIdelInfo[elementId].nChannelsInEl; ch++) { + SHORT* ptr = qcElement[elementId]->qcOutChannel[ch]->quantSpec; + sfbPeFactorsLdData[elementId][ch] = (FIXP_DBL*)ptr; + } + } + + /* for each sfb calc relative factors for pe changes */ + normFactorInt = 0; + + for(elementId=elementOffset;elementIdelInfo[elementId].elType != ID_DSE) { + + for(ch=0; chelInfo[elementId].nChannelsInEl; ch++) { + + qcOutChan = qcElement[elementId]->qcOutChannel[ch]; + psyOutChan = psyOutElement[elementId]->psyOutChannel[ch]; + peChanData = &qcElement[elementId]->peData.peChannelData[ch]; + + for(sfbGrp = 0; sfbGrp < psyOutChan->sfbCnt; sfbGrp+= psyOutChan->sfbPerGroup){ + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + + if ( peChanData->sfbNActiveLines[sfbGrp+sfb] == 0 ) { + sfbNActiveLinesLdData[ch][sfbGrp+sfb] = FL2FXCONST_DBL(-1.0f); + } + else { + /* Both CalcLdInt and CalcLdData can be used! + * No offset has to be subtracted, because sfbNActiveLinesLdData + * is shorted while thrFactor calculation */ + sfbNActiveLinesLdData[ch][sfbGrp+sfb] = CalcLdInt(peChanData->sfbNActiveLines[sfbGrp+sfb]); + } + if ( ((ahFlag[elementId][ch][sfbGrp+sfb] < AH_ACTIVE) || (deltaPe > 0)) && + peChanData->sfbNActiveLines[sfbGrp+sfb] != 0 ) + { + if (thrExp[elementId][ch][sfbGrp+sfb] > -redVal[elementId]) { + + /* sfbPeFactors[ch][sfbGrp+sfb] = peChanData->sfbNActiveLines[sfbGrp+sfb] / + (thrExp[elementId][ch][sfbGrp+sfb] + redVal[elementId]); */ + + int minScale = fixMin(CountLeadingBits(thrExp[elementId][ch][sfbGrp+sfb]), CountLeadingBits(redVal[elementId]) - (DFRACT_BITS-1-redValScaling[elementId]) ) - 1; + + /* sumld = ld64( sfbThrExp + redVal ) */ + FIXP_DBL sumLd = CalcLdData(scaleValue(thrExp[elementId][ch][sfbGrp+sfb], minScale) + scaleValue(redVal[elementId], (DFRACT_BITS-1-redValScaling[elementId])+minScale)) + - (FIXP_DBL)(minScale<<(DFRACT_BITS-1-LD_DATA_SHIFT)); + + if (sumLd < FL2FXCONST_DBL(0.f)) { + sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = sfbNActiveLinesLdData[ch][sfbGrp+sfb] - sumLd; + } + else { + if ( sfbNActiveLinesLdData[ch][sfbGrp+sfb] > (FL2FXCONST_DBL(-1.f) + sumLd) ) { + sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = sfbNActiveLinesLdData[ch][sfbGrp+sfb] - sumLd; + } + else { + sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = sfbNActiveLinesLdData[ch][sfbGrp+sfb]; + } + } + + normFactorInt += (INT)CalcInvLdData(sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb]); + } + else sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = FL2FXCONST_DBL(1.0f); + } + else sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = FL2FXCONST_DBL(-1.0f); + } + } + } + } + } + + /* normFactorLdData = ld64(deltaPe/normFactorInt) */ + normFactorLdData = CalcLdData((FIXP_DBL)((deltaPe<0) ? (-deltaPe) : (deltaPe))) - CalcLdData((FIXP_DBL)normFactorInt); + + /* distribute the pe difference to the scalefactors + and calculate the according thresholds */ + for(elementId=elementOffset;elementIdelInfo[elementId].elType != ID_DSE) { + + for(ch=0; chelInfo[elementId].nChannelsInEl; ch++) { + qcOutChan = qcElement[elementId]->qcOutChannel[ch]; + psyOutChan = psyOutElement[elementId]->psyOutChannel[ch]; + peChanData = &qcElement[elementId]->peData.peChannelData[ch]; + + for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){ + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + + if (peChanData->sfbNActiveLines[sfbGrp+sfb] > 0) { + + /* pe difference for this sfb */ + if ( (sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb]==FL2FXCONST_DBL(-1.0f)) || + (deltaPe==0) ) + { + thrFactorLdData = FL2FXCONST_DBL(0.f); + } + else { + /* new threshold */ + FIXP_DBL tmp = CalcInvLdData(sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] + normFactorLdData - sfbNActiveLinesLdData[ch][sfbGrp+sfb] - FL2FXCONST_DBL((float)LD_DATA_SHIFT/LD_DATA_SCALING)); + + /* limit thrFactor to 60dB */ + tmp = (deltaPe<0) ? tmp : (-tmp); + thrFactorLdData = FDKmin(tmp, FL2FXCONST_DBL(20.f/LD_DATA_SCALING)); + } + + /* new threshold */ + sfbThrLdData = qcOutChan->sfbThresholdLdData[sfbGrp+sfb]; + sfbEnLdData = qcOutChan->sfbWeightedEnergyLdData[sfbGrp+sfb]; + + if (thrFactorLdData < FL2FXCONST_DBL(0.f)) { + if( sfbThrLdData > (FL2FXCONST_DBL(-1.f)-thrFactorLdData) ) { + sfbThrReducedLdData = sfbThrLdData + thrFactorLdData; + } + else { + sfbThrReducedLdData = FL2FXCONST_DBL(-1.f); + } + } + else{ + sfbThrReducedLdData = sfbThrLdData + thrFactorLdData; + } + + /* avoid hole */ + if ( (sfbThrReducedLdData - sfbEnLdData > qcOutChan->sfbMinSnrLdData[sfbGrp+sfb]) && + (ahFlag[elementId][ch][sfbGrp+sfb] == AH_INACTIVE) ) + { + /* sfbThrReduced = max(psyOutChan[ch]->sfbMinSnr[i] * sfbEn, sfbThr); */ + if ( sfbEnLdData > (sfbThrLdData-qcOutChan->sfbMinSnrLdData[sfbGrp+sfb]) ) { + sfbThrReducedLdData = qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] + sfbEnLdData; + } + else { + sfbThrReducedLdData = sfbThrLdData; + } + ahFlag[elementId][ch][sfbGrp+sfb] = AH_ACTIVE; + } + + qcOutChan->sfbThresholdLdData[sfbGrp+sfb] = sfbThrReducedLdData; + } + } + } + } + } + } +} + +/***************************************************************************** + functionname: FDKaacEnc_reduceMinSnr + description: if the desired pe can not be reached, reduce pe by + reducing minSnr +*****************************************************************************/ +void FDKaacEnc_reduceMinSnr(CHANNEL_MAPPING* cm, + QC_OUT_ELEMENT* qcElement[(6)], + PSY_OUT_ELEMENT* psyOutElement[(6)], + UCHAR ahFlag[(6)][(2)][MAX_GROUPED_SFB], + const INT desiredPe, + INT* redPeGlobal, + const INT processElements, + const INT elementOffset) + +{ + INT elementId; + INT nElements = elementOffset+processElements; + + INT newGlobalPe = *redPeGlobal; + + for(elementId=elementOffset;elementIdelInfo[elementId].elType != ID_DSE) { + INT ch; + INT maxSfbPerGroup[2]; + INT sfbCnt[2]; + INT sfbPerGroup[2]; + + for(ch=0; chelInfo[elementId].nChannelsInEl; ch++) { + maxSfbPerGroup[ch] = psyOutElement[elementId]->psyOutChannel[ch]->maxSfbPerGroup-1; + sfbCnt[ch] = psyOutElement[elementId]->psyOutChannel[ch]->sfbCnt; + sfbPerGroup[ch] = psyOutElement[elementId]->psyOutChannel[ch]->sfbPerGroup; + } + + PE_DATA *peData = &qcElement[elementId]->peData; + + do + { + for(ch=0; chelInfo[elementId].nChannelsInEl; ch++) { + + INT sfb, sfbGrp; + QC_OUT_CHANNEL *qcOutChan = qcElement[elementId]->qcOutChannel[ch]; + INT noReduction = 1; + + if (maxSfbPerGroup[ch]>=0) { /* sfb in next channel */ + INT deltaPe = 0; + sfb = maxSfbPerGroup[ch]--; + noReduction = 0; + + for (sfbGrp = 0; sfbGrp < sfbCnt[ch]; sfbGrp += sfbPerGroup[ch]) { + + if (ahFlag[elementId][ch][sfbGrp+sfb] != NO_AH && + qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] < SnrLdFac) + { + /* increase threshold to new minSnr of 1dB */ + qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] = SnrLdFac; + + /* sfbThrReduced = max(psyOutChan[ch]->sfbMinSnr[i] * sfbEn, sfbThr); */ + if ( qcOutChan->sfbWeightedEnergyLdData[sfbGrp+sfb] >= qcOutChan->sfbThresholdLdData[sfbGrp+sfb] - qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] ) { + + qcOutChan->sfbThresholdLdData[sfbGrp+sfb] = qcOutChan->sfbWeightedEnergyLdData[sfbGrp+sfb] + qcOutChan->sfbMinSnrLdData[sfbGrp+sfb]; + + /* calc new pe */ + /* C2 + C3*ld(1/0.8) = 1.5 */ + deltaPe -= (peData->peChannelData[ch].sfbPe[sfbGrp+sfb]>>PE_CONSTPART_SHIFT); + + /* sfbPe = 1.5 * sfbNLines */ + peData->peChannelData[ch].sfbPe[sfbGrp+sfb] = (3*peData->peChannelData[ch].sfbNLines[sfbGrp+sfb]) << (PE_CONSTPART_SHIFT-1); + deltaPe += (peData->peChannelData[ch].sfbPe[sfbGrp+sfb]>>PE_CONSTPART_SHIFT); + } + } + + } /* sfbGrp loop */ + + peData->pe += deltaPe; + peData->peChannelData[ch].pe += deltaPe; + newGlobalPe += deltaPe; + + /* stop if enough has been saved */ + if (peData->pe <= desiredPe) { + goto bail; + } + + } /* sfb > 0 */ + + if ( (ch==(cm->elInfo[elementId].nChannelsInEl-1)) && noReduction ) { + goto bail; + } + + } /* ch loop */ + + } while ( peData->pe > desiredPe); + + } /* != ID_DSE */ + } /* element loop */ + + +bail: + /* update global PE */ + *redPeGlobal = newGlobalPe; +} + + +/***************************************************************************** + functionname: FDKaacEnc_allowMoreHoles + description: if the desired pe can not be reached, some more scalefactor + bands have to be quantized to zero +*****************************************************************************/ +static void FDKaacEnc_allowMoreHoles(CHANNEL_MAPPING* cm, + QC_OUT_ELEMENT* qcElement[(6)], + PSY_OUT_ELEMENT* psyOutElement[(6)], + ATS_ELEMENT* AdjThrStateElement[(6)], + UCHAR ahFlag[(6)][(2)][MAX_GROUPED_SFB], + const INT desiredPe, + const INT currentPe, + const int processElements, + const int elementOffset) +{ + INT elementId; + INT nElements = elementOffset+processElements; + INT actPe = currentPe; + + if (actPe <= desiredPe) { + return; /* nothing to do */ + } + + for (elementId = elementOffset;elementIdelInfo[elementId].elType != ID_DSE) { + + INT ch, sfb, sfbGrp; + + PE_DATA *peData = &qcElement[elementId]->peData; + const INT nChannels = cm->elInfo[elementId].nChannelsInEl; + + QC_OUT_CHANNEL* qcOutChannel[(2)] = {NULL}; + PSY_OUT_CHANNEL* psyOutChannel[(2)] = {NULL}; + + for (ch=0; chqcOutChannel[ch]; + psyOutChannel[ch] = psyOutElement[elementId]->psyOutChannel[ch]; + + for(sfbGrp=0; sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+= psyOutChannel[ch]->sfbPerGroup) { + for (sfb=psyOutChannel[ch]->maxSfbPerGroup; sfbsfbPerGroup; sfb++) { + peData->peChannelData[ch].sfbPe[sfbGrp+sfb] = 0; + } + } + } + + /* for MS allow hole in the channel with less energy */ + if ( nChannels==2 && psyOutChannel[0]->lastWindowSequence==psyOutChannel[1]->lastWindowSequence ) { + + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + for(sfbGrp=0; sfbGrp < psyOutChannel[0]->sfbCnt; sfbGrp+=psyOutChannel[0]->sfbPerGroup) { + if (psyOutElement[elementId]->toolsInfo.msMask[sfbGrp+sfb]) { + FIXP_DBL EnergyLd_L = qcOutChannel[0]->sfbWeightedEnergyLdData[sfbGrp+sfb]; + FIXP_DBL EnergyLd_R = qcOutChannel[1]->sfbWeightedEnergyLdData[sfbGrp+sfb]; + + /* allow hole in side channel ? */ + if ( (ahFlag[elementId][1][sfbGrp+sfb] != NO_AH) && + (((FL2FXCONST_DBL(-0.02065512648f)>>1) + (qcOutChannel[0]->sfbMinSnrLdData[sfbGrp+sfb]>>1)) + > ((EnergyLd_R>>1) - (EnergyLd_L>>1))) ) + { + ahFlag[elementId][1][sfbGrp+sfb] = NO_AH; + qcOutChannel[1]->sfbThresholdLdData[sfbGrp+sfb] = FL2FXCONST_DBL(0.015625f) + EnergyLd_R; + actPe -= peData->peChannelData[1].sfbPe[sfbGrp+sfb]>>PE_CONSTPART_SHIFT; + } + /* allow hole in mid channel ? */ + else if ( (ahFlag[elementId][0][sfbGrp+sfb] != NO_AH) && + (((FL2FXCONST_DBL(-0.02065512648f)>>1) + (qcOutChannel[1]->sfbMinSnrLdData[sfbGrp+sfb]>>1)) + > ((EnergyLd_L>>1) - (EnergyLd_R>>1))) ) + { + ahFlag[elementId][0][sfbGrp+sfb] = NO_AH; + qcOutChannel[0]->sfbThresholdLdData[sfbGrp+sfb] = FL2FXCONST_DBL(0.015625f) + EnergyLd_L; + actPe -= peData->peChannelData[0].sfbPe[sfbGrp+sfb]>>PE_CONSTPART_SHIFT; + } /* if (ahFlag) */ + } /* if MS */ + } /* sfbGrp */ + if (actPe <= desiredPe) { + return; /* stop if enough has been saved */ + } + } /* sfb */ + } /* MS possible ? */ + + /* more holes necessary? subsequently erase bands + starting with low energies */ + INT startSfb[2]; + FIXP_DBL avgEnLD64,minEnLD64; + INT ahCnt; + FIXP_DBL ahCntLD64; + INT enIdx; + FIXP_DBL enLD64[4]; + FIXP_DBL avgEn; + + /* do not go below startSfb */ + for (ch=0; chlastWindowSequence != SHORT_WINDOW) + startSfb[ch] = AdjThrStateElement[elementId]->ahParam.startSfbL; + else + startSfb[ch] = AdjThrStateElement[elementId]->ahParam.startSfbS; + } + + /* calc avg and min energies of bands that avoid holes */ + avgEn = FL2FXCONST_DBL(0.0f); + minEnLD64 = FL2FXCONST_DBL(0.0f); + ahCnt = 0; + + for (ch=0; chmaxSfbPerGroup; sfb++) { + if ((ahFlag[elementId][ch][sfbGrp+sfb]!=NO_AH) && + (qcOutChannel[ch]->sfbWeightedEnergyLdData[sfbGrp+sfb] > qcOutChannel[ch]->sfbThresholdLdData[sfbGrp+sfb])){ + minEnLD64 = fixMin(minEnLD64,qcOutChannel[ch]->sfbEnergyLdData[sfbGrp+sfb]); + avgEn += qcOutChannel[ch]->sfbEnergy[sfbGrp+sfb] >> 6; + ahCnt++; + } + } + + sfbGrp += psyOutChannel[ch]->sfbPerGroup; + sfb=0; + + } while (sfbGrp < psyOutChannel[ch]->sfbCnt); + } + + if ( (avgEn == FL2FXCONST_DBL(0.0f)) || (ahCnt == 0) ) { + avgEnLD64 = FL2FXCONST_DBL(0.0f); + } + else { + avgEnLD64 = CalcLdData(avgEn); + ahCntLD64 = CalcLdInt(ahCnt); + avgEnLD64 = avgEnLD64 + FL2FXCONST_DBL(0.09375f) - ahCntLD64; /* compensate shift with 6 */ + } + + /* calc some energy borders between minEn and avgEn */ + /* for (enIdx=0; enIdx<4; enIdx++) */ + /* en[enIdx] = minEn * (float)FDKpow(avgEn/(minEn+FLT_MIN), (2*enIdx+1)/7.0f); */ + enLD64[0] = minEnLD64 + fMult((avgEnLD64-minEnLD64),FL2FXCONST_DBL(0.14285714285f)); + enLD64[1] = minEnLD64 + fMult((avgEnLD64-minEnLD64),FL2FXCONST_DBL(0.42857142857f)); + enLD64[2] = minEnLD64 + fMult((avgEnLD64-minEnLD64),FL2FXCONST_DBL(0.71428571428f)); + enLD64[3] = minEnLD64 + (avgEnLD64-minEnLD64); + + for (enIdx=0; enIdx<4; enIdx++) { + INT noReduction = 1; + + INT maxSfbPerGroup[2]; + INT sfbCnt[2]; + INT sfbPerGroup[2]; + + for(ch=0; chelInfo[elementId].nChannelsInEl; ch++) { + maxSfbPerGroup[ch] = psyOutElement[elementId]->psyOutChannel[ch]->maxSfbPerGroup-1; + sfbCnt[ch] = psyOutElement[elementId]->psyOutChannel[ch]->sfbCnt; + sfbPerGroup[ch] = psyOutElement[elementId]->psyOutChannel[ch]->sfbPerGroup; + } + + do { + + noReduction = 1; + + for(ch=0; chelInfo[elementId].nChannelsInEl; ch++) { + + INT sfb, sfbGrp; + + /* start with lowest energy border at highest sfb */ + if (maxSfbPerGroup[ch]>=startSfb[ch]) { /* sfb in next channel */ + sfb = maxSfbPerGroup[ch]--; + noReduction = 0; + + for (sfbGrp = 0; sfbGrp < sfbCnt[ch]; sfbGrp += sfbPerGroup[ch]) { + /* sfb energy below border ? */ + if (ahFlag[elementId][ch][sfbGrp+sfb] != NO_AH && qcOutChannel[ch]->sfbEnergyLdData[sfbGrp+sfb] < enLD64[enIdx]) { + /* allow hole */ + ahFlag[elementId][ch][sfbGrp+sfb] = NO_AH; + qcOutChannel[ch]->sfbThresholdLdData[sfbGrp+sfb] = FL2FXCONST_DBL(0.015625f) + qcOutChannel[ch]->sfbWeightedEnergyLdData[sfbGrp+sfb]; + actPe -= peData->peChannelData[ch].sfbPe[sfbGrp+sfb]>>PE_CONSTPART_SHIFT; + } + } /* sfbGrp */ + + if (actPe <= desiredPe) { + return; /* stop if enough has been saved */ + } + } /* sfb > 0 */ + } /* ch loop */ + + } while( (noReduction == 0) && (actPe > desiredPe) ); + + if (actPe <= desiredPe) { + return; /* stop if enough has been saved */ + } + + } /* enIdx loop */ + + } /* EOF DSE-suppression */ + } /* EOF for all elements... */ + +} + +/* reset avoid hole flags from AH_ACTIVE to AH_INACTIVE */ +static void FDKaacEnc_resetAHFlags( UCHAR ahFlag[(2)][MAX_GROUPED_SFB], + const int nChannels, + PSY_OUT_CHANNEL *psyOutChannel[(2)]) +{ + int ch, sfb, sfbGrp; + + for(ch=0; chsfbCnt; sfbGrp+=psyOutChannel[ch]->sfbPerGroup) { + for (sfb=0; sfbmaxSfbPerGroup; sfb++) { + if ( ahFlag[ch][sfbGrp+sfb] == AH_ACTIVE) { + ahFlag[ch][sfbGrp+sfb] = AH_INACTIVE; + } + } + } + } +} + + +static FIXP_DBL CalcRedValPower(FIXP_DBL num, + FIXP_DBL denum, + INT* scaling ) +{ + FIXP_DBL value = FL2FXCONST_DBL(0.f); + + if (num>=FL2FXCONST_DBL(0.f)) { + value = fDivNorm( num, denum, scaling); + } + else { + value = -fDivNorm( -num, denum, scaling); + } + value = f2Pow(value, *scaling, scaling); + *scaling = DFRACT_BITS-1-*scaling; + + return value; +} + + +/***************************************************************************** +functionname: FDKaacEnc_adaptThresholdsToPe +description: two guesses for the reduction value and one final correction of the thresholds +*****************************************************************************/ +static void FDKaacEnc_adaptThresholdsToPe(CHANNEL_MAPPING* cm, + ATS_ELEMENT* AdjThrStateElement[(6)], + QC_OUT_ELEMENT* qcElement[(6)], + PSY_OUT_ELEMENT* psyOutElement[(6)], + const INT desiredPe, + const INT processElements, + const INT elementOffset) +{ + FIXP_DBL redValue[(6)]; + SCHAR redValScaling[(6)]; + UCHAR pAhFlag[(6)][(2)][MAX_GROUPED_SFB]; + FIXP_DBL pThrExp[(6)][(2)][MAX_GROUPED_SFB]; + int iter; + + INT constPartGlobal, noRedPeGlobal, nActiveLinesGlobal, redPeGlobal; + constPartGlobal = noRedPeGlobal = nActiveLinesGlobal = redPeGlobal = 0; + + int elementId; + + int nElements = elementOffset+processElements; + if(nElements > cm->nElements) { + nElements = cm->nElements; + } + + /* ------------------------------------------------------- */ + /* Part I: Initialize data structures and variables... */ + /* ------------------------------------------------------- */ + for (elementId = elementOffset;elementIdelInfo[elementId].elType != ID_DSE) { + + INT nChannels = cm->elInfo[elementId].nChannelsInEl; + PE_DATA *peData = &qcElement[elementId]->peData; + + /* thresholds to the power of redExp */ + FDKaacEnc_calcThreshExp(pThrExp[elementId], qcElement[elementId]->qcOutChannel, psyOutElement[elementId]->psyOutChannel, nChannels); + + /* lower the minSnr requirements for low energies compared to the average + energy in this frame */ + FDKaacEnc_adaptMinSnr(qcElement[elementId]->qcOutChannel, psyOutElement[elementId]->psyOutChannel, &AdjThrStateElement[elementId]->minSnrAdaptParam, nChannels); + + /* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */ + FDKaacEnc_initAvoidHoleFlag(qcElement[elementId]->qcOutChannel, psyOutElement[elementId]->psyOutChannel, pAhFlag[elementId], &psyOutElement[elementId]->toolsInfo, nChannels, peData, &AdjThrStateElement[elementId]->ahParam); + + /* sum up */ + constPartGlobal += peData->constPart; + noRedPeGlobal += peData->pe; + nActiveLinesGlobal += fixMax((INT)peData->nActiveLines, 1); + + } /* EOF DSE-suppression */ + } /* EOF for all elements... */ + + /* ----------------------------------------------------------------------- */ + /* Part II: Calculate bit consumption of initial bit constraints setup */ + /* ----------------------------------------------------------------------- */ + for (elementId = elementOffset;elementIdelInfo[elementId].elType != ID_DSE) { + /* + redVal = ( 2 ^ ( (constPartGlobal-desiredPe) / (invRedExp*nActiveLinesGlobal) ) + - 2 ^ ( (constPartGlobal-noRedPeGlobal) / (invRedExp*nActiveLinesGlobal) ) ) + */ + + + INT nChannels = cm->elInfo[elementId].nChannelsInEl; + PE_DATA *peData = &qcElement[elementId]->peData; + + /* first guess of reduction value */ + int scale0=0, scale1=0; + FIXP_DBL tmp0 = CalcRedValPower( constPartGlobal-desiredPe, 4*nActiveLinesGlobal, &scale0 ); + FIXP_DBL tmp1 = CalcRedValPower( constPartGlobal-noRedPeGlobal, 4*nActiveLinesGlobal, &scale1 ); + + int scalMin = FDKmin(scale0, scale1)-1; + + redValue[elementId] = scaleValue(tmp0,(scalMin-scale0)) - scaleValue(tmp1,(scalMin-scale1)); + redValScaling[elementId] = scalMin; + + /* reduce thresholds */ + FDKaacEnc_reduceThresholdsCBR(qcElement[elementId]->qcOutChannel, psyOutElement[elementId]->psyOutChannel, pAhFlag[elementId], pThrExp[elementId], nChannels, redValue[elementId], redValScaling[elementId]); + + /* pe after first guess */ + FDKaacEnc_calcPe(psyOutElement[elementId]->psyOutChannel, qcElement[elementId]->qcOutChannel, peData, nChannels); + + redPeGlobal += peData->pe; + } /* EOF DSE-suppression */ + } /* EOF for all elements... */ + + /* -------------------------------------------------- */ + /* Part III: Iterate until bit constraints are met */ + /* -------------------------------------------------- */ + iter = 0; + while ((fixp_abs(redPeGlobal - desiredPe) > fMultI(FL2FXCONST_DBL(0.05f),desiredPe)) && (iter < 1)) { + + INT desiredPeNoAHGlobal; + INT redPeNoAHGlobal = 0; + INT constPartNoAHGlobal = 0; + INT nActiveLinesNoAHGlobal = 0; + + for (elementId = elementOffset;elementIdelInfo[elementId].elType != ID_DSE) { + + INT redPeNoAH, constPartNoAH, nActiveLinesNoAH; + INT nChannels = cm->elInfo[elementId].nChannelsInEl; + PE_DATA *peData = &qcElement[elementId]->peData; + + /* pe for bands where avoid hole is inactive */ + FDKaacEnc_FDKaacEnc_calcPeNoAH(&redPeNoAH, &constPartNoAH, &nActiveLinesNoAH, + peData, pAhFlag[elementId], psyOutElement[elementId]->psyOutChannel, nChannels); + + redPeNoAHGlobal += redPeNoAH; + constPartNoAHGlobal += constPartNoAH; + nActiveLinesNoAHGlobal += nActiveLinesNoAH; + } /* EOF DSE-suppression */ + } /* EOF for all elements... */ + + /* Calculate new redVal ... */ + if(desiredPe < redPeGlobal) { + + /* new desired pe without bands where avoid hole is active */ + desiredPeNoAHGlobal = desiredPe - (redPeGlobal - redPeNoAHGlobal); + + /* limit desiredPeNoAH to positive values, as the PE can not become negative */ + desiredPeNoAHGlobal = FDKmax(0,desiredPeNoAHGlobal); + + /* second guess (only if there are bands left where avoid hole is inactive)*/ + if (nActiveLinesNoAHGlobal > 0) { + for (elementId = elementOffset;elementIdelInfo[elementId].elType != ID_DSE) { + /* + redVal += ( 2 ^ ( (constPartNoAHGlobal-desiredPeNoAHGlobal) / (invRedExp*nActiveLinesNoAHGlobal) ) + - 2 ^ ( (constPartNoAHGlobal-redPeNoAHGlobal) / (invRedExp*nActiveLinesNoAHGlobal) ) ) + */ + int scale0 = 0; + int scale1 = 0; + + FIXP_DBL tmp0 = CalcRedValPower( constPartNoAHGlobal-desiredPeNoAHGlobal, 4*nActiveLinesNoAHGlobal, &scale0 ); + FIXP_DBL tmp1 = CalcRedValPower( constPartNoAHGlobal-redPeNoAHGlobal, 4*nActiveLinesNoAHGlobal, &scale1 ); + + int scalMin = FDKmin(scale0, scale1)-1; + + tmp0 = scaleValue(tmp0,(scalMin-scale0)) - scaleValue(tmp1,(scalMin-scale1)); + scale0 = scalMin; + + /* old reduction value */ + tmp1 = redValue[elementId]; + scale1 = redValScaling[elementId]; + + scalMin = fixMin(scale0,scale1)-1; + + /* sum up old and new reduction value */ + redValue[elementId] = scaleValue(tmp0,(scalMin-scale0)) + scaleValue(tmp1,(scalMin-scale1)); + redValScaling[elementId] = scalMin; + + } /* EOF DSE-suppression */ + } /* EOF for all elements... */ + } /* nActiveLinesNoAHGlobal > 0 */ + } + else { + /* desiredPe >= redPeGlobal */ + for (elementId = elementOffset;elementIdelInfo[elementId].elType != ID_DSE) { + + INT redVal_scale = 0; + FIXP_DBL tmp = fDivNorm((FIXP_DBL)redPeGlobal, (FIXP_DBL)desiredPe, &redVal_scale); + + /* redVal *= redPeGlobal/desiredPe; */ + redValue[elementId] = fMult(redValue[elementId], tmp); + redValScaling[elementId] -= redVal_scale; + + FDKaacEnc_resetAHFlags(pAhFlag[elementId], cm->elInfo[elementId].nChannelsInEl, psyOutElement[elementId]->psyOutChannel); + } /* EOF DSE-suppression */ + } /* EOF for all elements... */ + } + + redPeGlobal = 0; + /* Calculate new redVal's PE... */ + for (elementId = elementOffset;elementIdelInfo[elementId].elType != ID_DSE) { + + INT nChannels = cm->elInfo[elementId].nChannelsInEl; + PE_DATA *peData = &qcElement[elementId]->peData; + + /* reduce thresholds */ + FDKaacEnc_reduceThresholdsCBR(qcElement[elementId]->qcOutChannel, psyOutElement[elementId]->psyOutChannel, pAhFlag[elementId], pThrExp[elementId], nChannels, redValue[elementId], redValScaling[elementId]); + + /* pe after second guess */ + FDKaacEnc_calcPe(psyOutElement[elementId]->psyOutChannel, qcElement[elementId]->qcOutChannel, peData, nChannels); + redPeGlobal += peData->pe; + + } /* EOF DSE-suppression */ + } /* EOF for all elements... */ + + iter++; + } /* EOF while */ + + + /* ------------------------------------------------------- */ + /* Part IV: if still required, further reduce constraints */ + /* ------------------------------------------------------- */ + /* 1.0* 1.15* 1.20* + * desiredPe desiredPe desiredPe + * | | | + * ...XXXXXXXXXXXXXXXXXXXXXXXXXXX| | + * | | |XXXXXXXXXXX... + * | |XXXXXXXXXXX| + * --- A --- | --- B --- | --- C --- + * + * (X): redPeGlobal + * (A): FDKaacEnc_correctThresh() + * (B): FDKaacEnc_allowMoreHoles() + * (C): FDKaacEnc_reduceMinSnr() + */ + + /* correct thresholds to get closer to the desired pe */ + if ( redPeGlobal > desiredPe ) { + FDKaacEnc_correctThresh(cm, qcElement, psyOutElement, pAhFlag, pThrExp, redValue, redValScaling, + desiredPe - redPeGlobal, processElements, elementOffset); + + /* update PE */ + redPeGlobal = 0; + for(elementId=elementOffset;elementIdelInfo[elementId].elType != ID_DSE) { + + INT nChannels = cm->elInfo[elementId].nChannelsInEl; + PE_DATA *peData = &qcElement[elementId]->peData; + + /* pe after correctThresh */ + FDKaacEnc_calcPe(psyOutElement[elementId]->psyOutChannel, qcElement[elementId]->qcOutChannel, peData, nChannels); + redPeGlobal += peData->pe; + + } /* EOF DSE-suppression */ + } /* EOF for all elements... */ + } + + if ( redPeGlobal > desiredPe ) { + /* reduce pe by reducing minSnr requirements */ + FDKaacEnc_reduceMinSnr(cm, qcElement, psyOutElement, pAhFlag, + (fMultI(FL2FXCONST_DBL(0.15f),desiredPe) + desiredPe), + &redPeGlobal, processElements, elementOffset); + + /* reduce pe by allowing additional spectral holes */ + FDKaacEnc_allowMoreHoles(cm, qcElement, psyOutElement, AdjThrStateElement, pAhFlag, + desiredPe, redPeGlobal, processElements, elementOffset); + } + +} + + +/* similar to FDKaacEnc_adaptThresholdsToPe(), for VBR-mode */ +void FDKaacEnc_AdaptThresholdsVBR(QC_OUT_CHANNEL* qcOutChannel[(2)], + PSY_OUT_CHANNEL* psyOutChannel[(2)], + ATS_ELEMENT* AdjThrStateElement, + struct TOOLSINFO *toolsInfo, + PE_DATA *peData, + const INT nChannels) +{ + UCHAR pAhFlag[(2)][MAX_GROUPED_SFB]; + FIXP_DBL pThrExp[(2)][MAX_GROUPED_SFB]; + + /* thresholds to the power of redExp */ + FDKaacEnc_calcThreshExp(pThrExp, qcOutChannel, psyOutChannel, nChannels); + + /* lower the minSnr requirements for low energies compared to the average + energy in this frame */ + FDKaacEnc_adaptMinSnr(qcOutChannel, psyOutChannel, &AdjThrStateElement->minSnrAdaptParam, nChannels); + + /* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */ + FDKaacEnc_initAvoidHoleFlag(qcOutChannel, psyOutChannel, pAhFlag, toolsInfo, + nChannels, peData, &AdjThrStateElement->ahParam); + + /* reduce thresholds */ + FDKaacEnc_reduceThresholdsVBR(qcOutChannel, psyOutChannel, pAhFlag, pThrExp, nChannels, + AdjThrStateElement->vbrQualFactor, + &AdjThrStateElement->chaosMeasureOld); + +} + + +/***************************************************************************** + + functionname: FDKaacEnc_calcBitSave + description: Calculates percentage of bit save, see figure below + returns: + input: parameters and bitres-fullness + output: percentage of bit save + +*****************************************************************************/ +/* + bitsave + maxBitSave(%)| clipLow + |---\ + | \ + | \ + | \ + | \ + |--------\--------------> bitres + | \ + minBitSave(%)| \------------ + clipHigh maxBitres +*/ +static FIXP_DBL FDKaacEnc_calcBitSave(FIXP_DBL fillLevel, + const FIXP_DBL clipLow, + const FIXP_DBL clipHigh, + const FIXP_DBL minBitSave, + const FIXP_DBL maxBitSave, + const FIXP_DBL bitsave_slope) +{ + FIXP_DBL bitsave; + + fillLevel = fixMax(fillLevel, clipLow); + fillLevel = fixMin(fillLevel, clipHigh); + + bitsave = maxBitSave - fMult((fillLevel-clipLow), bitsave_slope); + + return (bitsave); +} + +/***************************************************************************** + + functionname: FDKaacEnc_calcBitSpend + description: Calculates percentage of bit spend, see figure below + returns: + input: parameters and bitres-fullness + output: percentage of bit spend + +*****************************************************************************/ +/* + bitspend clipHigh + maxBitSpend(%)| /-----------maxBitres + | / + | / + | / + | / + | / + |----/-----------------> bitres + | / + minBitSpend(%)|--/ + clipLow +*/ +static FIXP_DBL FDKaacEnc_calcBitSpend(FIXP_DBL fillLevel, + const FIXP_DBL clipLow, + const FIXP_DBL clipHigh, + const FIXP_DBL minBitSpend, + const FIXP_DBL maxBitSpend, + const FIXP_DBL bitspend_slope) +{ + FIXP_DBL bitspend; + + fillLevel = fixMax(fillLevel, clipLow); + fillLevel = fixMin(fillLevel, clipHigh); + + bitspend = minBitSpend + fMult(fillLevel-clipLow, bitspend_slope); + + return (bitspend); +} + + +/***************************************************************************** + + functionname: FDKaacEnc_adjustPeMinMax() + description: adjusts peMin and peMax parameters over time + returns: + input: current pe, peMin, peMax, bitres size + output: adjusted peMin/peMax + +*****************************************************************************/ +static void FDKaacEnc_adjustPeMinMax(const INT currPe, + INT *peMin, + INT *peMax) +{ + FIXP_DBL minFacHi = FL2FXCONST_DBL(0.3f), maxFacHi = (FIXP_DBL)MAXVAL_DBL, minFacLo = FL2FXCONST_DBL(0.14f), maxFacLo = FL2FXCONST_DBL(0.07f); + INT diff; + + INT minDiff_fix = fMultI(FL2FXCONST_DBL(0.1666666667f), currPe); + + if (currPe > *peMax) + { + diff = (currPe-*peMax) ; + *peMin += fMultI(minFacHi,diff); + *peMax += fMultI(maxFacHi,diff); + } + else if (currPe < *peMin) + { + diff = (*peMin-currPe) ; + *peMin -= fMultI(minFacLo,diff); + *peMax -= fMultI(maxFacLo,diff); + } + else + { + *peMin += fMultI(minFacHi, (currPe - *peMin)); + *peMax -= fMultI(maxFacLo, (*peMax - currPe)); + } + + if ((*peMax - *peMin) < minDiff_fix) + { + INT peMax_fix = *peMax, peMin_fix = *peMin; + FIXP_DBL partLo_fix, partHi_fix; + + partLo_fix = (FIXP_DBL)fixMax(0, currPe - peMin_fix); + partHi_fix = (FIXP_DBL)fixMax(0, peMax_fix - currPe); + + peMax_fix = (INT)(currPe + fMultI(fDivNorm(partHi_fix, (partLo_fix+partHi_fix)), minDiff_fix)); + peMin_fix = (INT)(currPe - fMultI(fDivNorm(partLo_fix, (partLo_fix+partHi_fix)), minDiff_fix)); + peMin_fix = fixMax(0, peMin_fix); + + *peMax = peMax_fix; + *peMin = peMin_fix; + } +} + + + +/***************************************************************************** + + functionname: BitresCalcBitFac + description: calculates factor of spending bits for one frame + 1.0 : take all frame dynpart bits + >1.0 : take all frame dynpart bits + bitres + <1.0 : put bits in bitreservoir + returns: BitFac + input: bitres-fullness, pe, blockType, parameter-settings + output: + +*****************************************************************************/ +/* + bitfac(%) pemax + bitspend(%) | /-----------maxBitres + | / + | / + | / + | / + | / + |----/-----------------> pe + | / + bitsave(%) |--/ + pemin +*/ + +static FIXP_DBL FDKaacEnc_bitresCalcBitFac(const INT bitresBits, + const INT maxBitresBits, + const INT pe, + const INT lastWindowSequence, + const INT avgBits, + const FIXP_DBL maxBitFac, + ADJ_THR_STATE *AdjThr, + ATS_ELEMENT *adjThrChan) +{ + BRES_PARAM *bresParam; + INT pex; + + INT qmin, qbr, qbres, qmbr; + FIXP_DBL bitSave, bitSpend; + + FIXP_DBL bitresFac_fix, tmp_cst, tmp_fix; + FIXP_DBL pe_pers, bits_ratio, maxBrVal; + FIXP_DBL bitsave_slope, bitspend_slope, maxBitFac_tmp; + FIXP_DBL fillLevel_fix = (FIXP_DBL)0x7fffffff; + FIXP_DBL UNITY = (FIXP_DBL)0x7fffffff; + FIXP_DBL POINT7 = (FIXP_DBL)0x5999999A; + + if (maxBitresBits > bitresBits) { + fillLevel_fix = fDivNorm(bitresBits, maxBitresBits); + } + + if (lastWindowSequence != SHORT_WINDOW) + { + bresParam = &(AdjThr->bresParamLong); + bitsave_slope = (FIXP_DBL)0x3BBBBBBC; + bitspend_slope = (FIXP_DBL)0x55555555; + } + else + { + bresParam = &(AdjThr->bresParamShort); + bitsave_slope = (FIXP_DBL)0x2E8BA2E9; + bitspend_slope = (FIXP_DBL)0x7fffffff; + } + + pex = fixMax(pe, adjThrChan->peMin); + pex = fixMin(pex, adjThrChan->peMax); + + bitSave = FDKaacEnc_calcBitSave(fillLevel_fix, + bresParam->clipSaveLow, bresParam->clipSaveHigh, + bresParam->minBitSave, bresParam->maxBitSave, bitsave_slope); + + bitSpend = FDKaacEnc_calcBitSpend(fillLevel_fix, + bresParam->clipSpendLow, bresParam->clipSpendHigh, + bresParam->minBitSpend, bresParam->maxBitSpend, bitspend_slope); + + pe_pers = fDivNorm(pex - adjThrChan->peMin, adjThrChan->peMax - adjThrChan->peMin); + tmp_fix = fMult(((FIXP_DBL)bitSpend + (FIXP_DBL)bitSave), pe_pers); + bitresFac_fix = (UNITY>>1) - ((FIXP_DBL)bitSave>>1) + (tmp_fix>>1); qbres = (DFRACT_BITS-2); + + /* (float)bitresBits/(float)avgBits */ + bits_ratio = fDivNorm(bitresBits, avgBits, &qbr); + qbr = DFRACT_BITS-1-qbr; + + /* Add 0.7 in q31 to bits_ratio in qbr */ + /* 0.7f + (float)bitresBits/(float)avgBits */ + qmin = fixMin(qbr, (DFRACT_BITS-1)); + bits_ratio = bits_ratio >> (qbr - qmin); + tmp_cst = POINT7 >> ((DFRACT_BITS-1) - qmin); + maxBrVal = (bits_ratio>>1) + (tmp_cst>>1); qmbr = qmin - 1; + + /* bitresFac_fix = fixMin(bitresFac_fix, 0.7 + bitresBits/avgBits); */ + bitresFac_fix = bitresFac_fix >> (qbres - qmbr); qbres = qmbr; + bitresFac_fix = fixMin(bitresFac_fix, maxBrVal); + + /* Compare with maxBitFac */ + qmin = fixMin(Q_BITFAC, qbres); + bitresFac_fix = bitresFac_fix >> (qbres - qmin); + maxBitFac_tmp = maxBitFac >> (Q_BITFAC - qmin); + if(maxBitFac_tmp < bitresFac_fix) + { + bitresFac_fix = maxBitFac; + } + else + { + if(qmin < Q_BITFAC) + { + bitresFac_fix = bitresFac_fix << (Q_BITFAC-qmin); + } + else + { + bitresFac_fix = bitresFac_fix >> (qmin-Q_BITFAC); + } + } + + FDKaacEnc_adjustPeMinMax(pe, &adjThrChan->peMin, &adjThrChan->peMax); + + return bitresFac_fix; +} + + +/***************************************************************************** +functionname: FDKaacEnc_AdjThrNew +description: allocate ADJ_THR_STATE +*****************************************************************************/ +INT FDKaacEnc_AdjThrNew(ADJ_THR_STATE** phAdjThr, + INT nElements) +{ + INT err = 0; + INT i; + ADJ_THR_STATE* hAdjThr = GetRam_aacEnc_AdjustThreshold(); + if (hAdjThr==NULL) { + err = 1; + goto bail; + } + + for (i=0; iadjThrStateElem[i] = GetRam_aacEnc_AdjThrStateElement(i); + if (hAdjThr->adjThrStateElem[i]==NULL) { + err = 1; + goto bail; + } + } + +bail: + *phAdjThr = hAdjThr; + return err; +} + + +/***************************************************************************** +functionname: FDKaacEnc_AdjThrInit +description: initialize ADJ_THR_STATE +*****************************************************************************/ +void FDKaacEnc_AdjThrInit(ADJ_THR_STATE *hAdjThr, + const INT meanPe, + ELEMENT_BITS *elBits[(6)], + INT nElements, + FIXP_DBL vbrQualFactor) +{ + INT i; + + FIXP_DBL POINT8 = FL2FXCONST_DBL(0.8f); + FIXP_DBL POINT6 = FL2FXCONST_DBL(0.6f); + + /* common for all elements: */ + /* parameters for bitres control */ + hAdjThr->bresParamLong.clipSaveLow = (FIXP_DBL)0x1999999a; /* FL2FXCONST_DBL(0.2f); */ + hAdjThr->bresParamLong.clipSaveHigh = (FIXP_DBL)0x7999999a; /* FL2FXCONST_DBL(0.95f); */ + hAdjThr->bresParamLong.minBitSave = (FIXP_DBL)0xf999999a; /* FL2FXCONST_DBL(-0.05f); */ + hAdjThr->bresParamLong.maxBitSave = (FIXP_DBL)0x26666666; /* FL2FXCONST_DBL(0.3f); */ + hAdjThr->bresParamLong.clipSpendLow = (FIXP_DBL)0x1999999a; /* FL2FXCONST_DBL(0.2f); */ + hAdjThr->bresParamLong.clipSpendHigh = (FIXP_DBL)0x7999999a; /* FL2FXCONST_DBL(0.95f); */ + hAdjThr->bresParamLong.minBitSpend = (FIXP_DBL)0xf3333333; /* FL2FXCONST_DBL(-0.10f); */ + hAdjThr->bresParamLong.maxBitSpend = (FIXP_DBL)0x33333333; /* FL2FXCONST_DBL(0.4f); */ + + hAdjThr->bresParamShort.clipSaveLow = (FIXP_DBL)0x199999a0; /* FL2FXCONST_DBL(0.2f); */ + hAdjThr->bresParamShort.clipSaveHigh = (FIXP_DBL)0x5fffffff; /* FL2FXCONST_DBL(0.75f); */ + hAdjThr->bresParamShort.minBitSave = (FIXP_DBL)0x00000000; /* FL2FXCONST_DBL(0.0f); */ + hAdjThr->bresParamShort.maxBitSave = (FIXP_DBL)0x199999a0; /* FL2FXCONST_DBL(0.2f); */ + hAdjThr->bresParamShort.clipSpendLow = (FIXP_DBL)0x199999a0; /* FL2FXCONST_DBL(0.2f); */ + hAdjThr->bresParamShort.clipSpendHigh = (FIXP_DBL)0x5fffffff; /* FL2FXCONST_DBL(0.75f); */ + hAdjThr->bresParamShort.minBitSpend = (FIXP_DBL)0xf9999998; /* FL2FXCONST_DBL(-0.05f); */ + hAdjThr->bresParamShort.maxBitSpend = (FIXP_DBL)0x40000000; /* FL2FXCONST_DBL(0.5f); */ + + /* specific for each element: */ + for (i=0; iadjThrStateElem[i]; + MINSNR_ADAPT_PARAM *msaParam = &atsElem->minSnrAdaptParam; + INT chBitrate = elBits[i]->chBitrateEl; + + /* parameters for bitres control */ + atsElem->peMin = fMultI(POINT8, meanPe) >> 1; + atsElem->peMax = fMultI(POINT6, meanPe); + + /* for use in FDKaacEnc_reduceThresholdsVBR */ + atsElem->chaosMeasureOld = FL2FXCONST_DBL(0.3f); + + /* additional pe offset to correct pe2bits for low bitrates */ + atsElem->peOffset = 0; + + /* vbr initialisation */ + atsElem->vbrQualFactor = vbrQualFactor; + if (chBitrate < 32000) + { + atsElem->peOffset = fixMax(50, 100-fMultI((FIXP_DBL)0x666667, chBitrate)); + } + + /* avoid hole parameters */ + if (chBitrate > 20000) { + atsElem->ahParam.modifyMinSnr = TRUE; + atsElem->ahParam.startSfbL = 15; + atsElem->ahParam.startSfbS = 3; + } + else { + atsElem->ahParam.modifyMinSnr = FALSE; + atsElem->ahParam.startSfbL = 0; + atsElem->ahParam.startSfbS = 0; + } + + /* minSnr adaptation */ + msaParam->maxRed = FL2FXCONST_DBL(0.00390625f); /* 0.25f/64.0f */ + /* start adaptation of minSnr for avgEn/sfbEn > startRatio */ + msaParam->startRatio = FL2FXCONST_DBL(0.05190512648f); /* ld64(10.0f) */ + /* maximum minSnr reduction to minSnr^maxRed is reached for + avgEn/sfbEn >= maxRatio */ + /* msaParam->maxRatio = 1000.0f; */ + /*msaParam->redRatioFac = ((float)1.0f - msaParam->maxRed) / ((float)10.0f*log10(msaParam->startRatio/msaParam->maxRatio)/log10(2.0f)*(float)0.3010299956f);*/ + msaParam->redRatioFac = FL2FXCONST_DBL(-0.375f); /* -0.0375f * 10.0f */ + /*msaParam->redOffs = (float)1.0f - msaParam->redRatioFac * (float)10.0f * log10(msaParam->startRatio)/log10(2.0f) * (float)0.3010299956f;*/ + msaParam->redOffs = FL2FXCONST_DBL(0.021484375); /* 1.375f/64.0f */ + + /* init pe correction */ + atsElem->peCorrectionFactor_m = FL2FXCONST_DBL(0.5f); /* 1.0 */ + atsElem->peCorrectionFactor_e = 1; + + atsElem->dynBitsLast = -1; + atsElem->peLast = 0; + + /* init bits to pe factor */ + atsElem->bits2PeFactor_m = FL2FXCONST_DBL(1.18f/(1<<(1))); + atsElem->bits2PeFactor_e = 1; + } +} + + +/***************************************************************************** + functionname: FDKaacEnc_FDKaacEnc_calcPeCorrection + description: calc desired pe +*****************************************************************************/ +static void FDKaacEnc_FDKaacEnc_calcPeCorrection( + FIXP_DBL *const correctionFac_m, + INT *const correctionFac_e, + const INT peAct, + const INT peLast, + const INT bitsLast, + const FIXP_DBL bits2PeFactor_m, + const INT bits2PeFactor_e + ) +{ + if ( (bitsLast > 0) && (peAct < 1.5f*peLast) && (peAct > 0.7f*peLast) && + (FDKaacEnc_bits2pe2(bitsLast, fMult(FL2FXCONST_DBL(1.2f/2.f), bits2PeFactor_m), bits2PeFactor_e+1) > peLast) && + (FDKaacEnc_bits2pe2(bitsLast, fMult(FL2FXCONST_DBL(0.65f), bits2PeFactor_m), bits2PeFactor_e ) < peLast) ) + { + FIXP_DBL corrFac = *correctionFac_m; + + int scaling = 0; + FIXP_DBL denum = (FIXP_DBL)FDKaacEnc_bits2pe2(bitsLast, bits2PeFactor_m, bits2PeFactor_e); + FIXP_DBL newFac = fDivNorm((FIXP_DBL)peLast, denum, &scaling); + + /* dead zone, newFac and corrFac are scaled by 0.5 */ + if ((FIXP_DBL)peLast <= denum) { /* ratio <= 1.f */ + newFac = fixMax(scaleValue(fixMin( fMult(FL2FXCONST_DBL(1.1f/2.f), newFac), scaleValue(FL2FXCONST_DBL( 1.f/2.f), -scaling)), scaling), FL2FXCONST_DBL(0.85f/2.f) ); + } + else { /* ratio < 1.f */ + newFac = fixMax( fixMin( scaleValue(fMult(FL2FXCONST_DBL(0.9f/2.f), newFac), scaling), FL2FXCONST_DBL(1.15f/2.f) ), FL2FXCONST_DBL( 1.f/2.f) ); + } + + if ( ((newFac > FL2FXCONST_DBL(1.f/2.f)) && (corrFac < FL2FXCONST_DBL(1.f/2.f))) + || ((newFac < FL2FXCONST_DBL(1.f/2.f)) && (corrFac > FL2FXCONST_DBL(1.f/2.f)))) + { + corrFac = FL2FXCONST_DBL(1.f/2.f); + } + + /* faster adaptation towards 1.0, slower in the other direction */ + if ( (corrFac < FL2FXCONST_DBL(1.f/2.f) && newFac < corrFac) + || (corrFac > FL2FXCONST_DBL(1.f/2.f) && newFac > corrFac) ) + { + corrFac = fMult(FL2FXCONST_DBL(0.85f), corrFac) + fMult(FL2FXCONST_DBL(0.15f), newFac); + } + else { + corrFac = fMult(FL2FXCONST_DBL(0.7f), corrFac) + fMult(FL2FXCONST_DBL(0.3f), newFac); + } + + corrFac = fixMax( fixMin( corrFac, FL2FXCONST_DBL(1.15f/2.f) ), FL2FXCONST_DBL(0.85/2.f) ); + + *correctionFac_m = corrFac; + *correctionFac_e = 1; + } + else { + *correctionFac_m = FL2FXCONST_DBL(1.f/2.f); + *correctionFac_e = 1; + } +} + + +void FDKaacEnc_DistributeBits(ADJ_THR_STATE *adjThrState, + ATS_ELEMENT *AdjThrStateElement, + PSY_OUT_CHANNEL *psyOutChannel[(2)], + PE_DATA *peData, + INT *grantedPe, + INT *grantedPeCorr, + const INT nChannels, + const INT commonWindow, + const INT grantedDynBits, + const INT bitresBits, + const INT maxBitresBits, + const FIXP_DBL maxBitFac, + const INT bitDistributenMode) +{ + FIXP_DBL bitFactor; + INT noRedPe = peData->pe; + + /* prefer short windows for calculation of bitFactor */ + INT curWindowSequence = LONG_WINDOW; + if (nChannels==2) { + if ((psyOutChannel[0]->lastWindowSequence == SHORT_WINDOW) || + (psyOutChannel[1]->lastWindowSequence == SHORT_WINDOW)) { + curWindowSequence = SHORT_WINDOW; + } + } + else { + curWindowSequence = psyOutChannel[0]->lastWindowSequence; + } + + if (grantedDynBits >= 1) { + if (bitDistributenMode!=0) { + *grantedPe = FDKaacEnc_bits2pe2(grantedDynBits, AdjThrStateElement->bits2PeFactor_m, AdjThrStateElement->bits2PeFactor_e); + } + else + { + /* factor dependend on current fill level and pe */ + bitFactor = FDKaacEnc_bitresCalcBitFac(bitresBits, maxBitresBits, noRedPe, + curWindowSequence, grantedDynBits, maxBitFac, + adjThrState, + AdjThrStateElement + ); + + /* desired pe for actual frame */ + /* Worst case max of grantedDynBits is = 1024 * 5.27 * 2 */ + *grantedPe = FDKaacEnc_bits2pe2(grantedDynBits, + fMult(bitFactor, AdjThrStateElement->bits2PeFactor_m), AdjThrStateElement->bits2PeFactor_e+(DFRACT_BITS-1-Q_BITFAC) + ); + } + } + else { + *grantedPe = 0; /* prevent divsion by 0 */ + } + + /* correction of pe value */ + { + FDKaacEnc_FDKaacEnc_calcPeCorrection( + &AdjThrStateElement->peCorrectionFactor_m, + &AdjThrStateElement->peCorrectionFactor_e, + fixMin(*grantedPe, noRedPe), + AdjThrStateElement->peLast, + AdjThrStateElement->dynBitsLast, + AdjThrStateElement->bits2PeFactor_m, + AdjThrStateElement->bits2PeFactor_e + ); + } + + *grantedPeCorr = (INT)(fMult((FIXP_DBL)(*grantedPe<peCorrectionFactor_m) >> (Q_AVGBITS-AdjThrStateElement->peCorrectionFactor_e)); + + /* update last pe */ + AdjThrStateElement->peLast = *grantedPe; + AdjThrStateElement->dynBitsLast = -1; + +} + +/***************************************************************************** +functionname: FDKaacEnc_AdjustThresholds +description: adjust thresholds +*****************************************************************************/ +void FDKaacEnc_AdjustThresholds(ATS_ELEMENT* AdjThrStateElement[(6)], + QC_OUT_ELEMENT* qcElement[(6)], + QC_OUT* qcOut, + PSY_OUT_ELEMENT* psyOutElement[(6)], + INT CBRbitrateMode, + CHANNEL_MAPPING* cm) +{ + int i; + if (CBRbitrateMode) + { + /* In case, no bits must be shifted between different elements, */ + /* an element-wise execution of the pe-dependent threshold- */ + /* adaption becomes necessary... */ + for (i=0; inElements; i++) + { + ELEMENT_INFO elInfo = cm->elInfo[i]; + + if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) || + (elInfo.elType == ID_LFE)) + { + /* qcElement[i]->grantedPe = 2000; */ /* Use this only for debugging */ + //if (totalGrantedPeCorr < totalNoRedPe) { + if (qcElement[i]->grantedPe < qcElement[i]->peData.pe) + { + /* calc threshold necessary for desired pe */ + FDKaacEnc_adaptThresholdsToPe(cm, + AdjThrStateElement, + qcElement, + psyOutElement, + qcElement[i]->grantedPeCorr, + 1, /* Process only 1 element */ + i); /* Process exactly THIS element */ + + } + + } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */ + + } /* -end- element loop */ + } + else { + for (i=0; inElements; i++) + { + ELEMENT_INFO elInfo = cm->elInfo[i]; + + if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) || + (elInfo.elType == ID_LFE)) + { + /* for VBR-mode */ + FDKaacEnc_AdaptThresholdsVBR(qcElement[i]->qcOutChannel, + psyOutElement[i]->psyOutChannel, + AdjThrStateElement[i], + &psyOutElement[i]->toolsInfo, + &qcElement[i]->peData, + cm->elInfo[i].nChannelsInEl); + } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */ + + } /* -end- element loop */ + + } + for (i=0; inElements; i++) { + int ch,sfb,sfbGrp; + /* no weighting of threholds and energies for mlout */ + /* weight energies and thresholds */ + for (ch=0; chelInfo[i].nChannelsInEl; ch++) { + QC_OUT_CHANNEL* pQcOutCh = qcElement[i]->qcOutChannel[ch]; + for (sfbGrp = 0;sfbGrp < psyOutElement[i]->psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutElement[i]->psyOutChannel[ch]->sfbPerGroup) { + for (sfb=0; sfbpsyOutChannel[ch]->maxSfbPerGroup; sfb++) { + pQcOutCh->sfbThresholdLdData[sfb+sfbGrp] += pQcOutCh->sfbEnFacLd[sfb+sfbGrp]; + } + } + } + } + +} + +void FDKaacEnc_AdjThrClose(ADJ_THR_STATE** phAdjThr) +{ + INT i; + ADJ_THR_STATE* hAdjThr = *phAdjThr; + + if (hAdjThr!=NULL) { + for (i=0; i<(6); i++) { + if (hAdjThr->adjThrStateElem[i]!=NULL) { + FreeRam_aacEnc_AdjThrStateElement(&hAdjThr->adjThrStateElem[i]); + } + } + FreeRam_aacEnc_AdjustThreshold(phAdjThr); + } +} + diff --git a/libAACenc/src/adj_thr.h b/libAACenc/src/adj_thr.h new file mode 100644 index 0000000..44db688 --- /dev/null +++ b/libAACenc/src/adj_thr.h @@ -0,0 +1,79 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Werner + contents/description: Threshold compensation + +******************************************************************************/ +#ifndef __ADJ_THR_H +#define __ADJ_THR_H + + +#include "adj_thr_data.h" +#include "qc_data.h" +#include "line_pe.h" +#include "interface.h" + + + +void FDKaacEnc_peCalculation(PE_DATA *peData, + PSY_OUT_CHANNEL* psyOutChannel[(2)], + QC_OUT_CHANNEL* qcOutChannel[(2)], + struct TOOLSINFO *toolsInfo, + ATS_ELEMENT* adjThrStateElement, + const INT nChannels); + +INT FDKaacEnc_AdjThrNew(ADJ_THR_STATE** phAdjThr, + INT nElements); + +void FDKaacEnc_AdjThrInit(ADJ_THR_STATE *hAdjThr, + const INT peMean, + ELEMENT_BITS* elBits[(6)], + INT nElements, + FIXP_DBL vbrQualFactor); + + +void FDKaacEnc_DistributeBits(ADJ_THR_STATE *adjThrState, + ATS_ELEMENT *AdjThrStateElement, + PSY_OUT_CHANNEL *psyOutChannel[(2)], + PE_DATA *peData, + INT *grantedPe, + INT *grantedPeCorr, + const INT nChannels, + const INT commonWindow, + const INT avgBits, + const INT bitresBits, + const INT maxBitresBits, + const FIXP_DBL maxBitFac, + const INT bitDistributenMode); + +void FDKaacEnc_AdjustThresholds(ATS_ELEMENT* AdjThrStateElement[(6)], + QC_OUT_ELEMENT* qcElement[(6)], + QC_OUT* qcOut, + PSY_OUT_ELEMENT* psyOutElement[(6)], + INT CBRbitrateMode, + CHANNEL_MAPPING* cm); + +void FDKaacEnc_AdjThrClose(ADJ_THR_STATE** hAdjThr); + +#endif diff --git a/libAACenc/src/adj_thr_data.h b/libAACenc/src/adj_thr_data.h new file mode 100644 index 0000000..6cb28cf --- /dev/null +++ b/libAACenc/src/adj_thr_data.h @@ -0,0 +1,88 @@ +/************************* Fast MPEG AAC Audio Encoder ********************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Schug / A. Groeschel + contents/description: threshold calculations + +******************************************************************************/ + +#ifndef __ADJ_THR_DATA_H +#define __ADJ_THR_DATA_H + + +#include "psy_const.h" + +typedef struct { + FIXP_DBL clipSaveLow, clipSaveHigh; + FIXP_DBL minBitSave, maxBitSave; + FIXP_DBL clipSpendLow, clipSpendHigh; + FIXP_DBL minBitSpend, maxBitSpend; +} BRES_PARAM; + +typedef struct { + INT modifyMinSnr; + INT startSfbL, startSfbS; +} AH_PARAM; + +typedef struct { + FIXP_DBL maxRed; + FIXP_DBL startRatio; + FIXP_DBL maxRatio; + FIXP_DBL redRatioFac; + FIXP_DBL redOffs; +} MINSNR_ADAPT_PARAM; + +typedef struct { + /* parameters for bitreservoir control */ + INT peMin, peMax; + /* constant offset to pe */ + INT peOffset; + /* constant PeFactor */ + FIXP_DBL bits2PeFactor_m; + INT bits2PeFactor_e; + /* avoid hole parameters */ + AH_PARAM ahParam; + /* values for correction of pe */ + /* paramters for adaptation of minSnr */ + MINSNR_ADAPT_PARAM minSnrAdaptParam; + INT peLast; + INT dynBitsLast; + FIXP_DBL peCorrectionFactor_m; + INT peCorrectionFactor_e; + + /* vbr encoding */ + FIXP_DBL vbrQualFactor; + FIXP_DBL chaosMeasureOld; + + /* threshold weighting */ + FIXP_DBL chaosMeasureEnFac[(2)]; + INT lastEnFacPatch[(2)]; + +} ATS_ELEMENT; + +typedef struct { + BRES_PARAM bresParamLong, bresParamShort; + ATS_ELEMENT* adjThrStateElem[(6)]; +} ADJ_THR_STATE; + +#endif diff --git a/libAACenc/src/band_nrg.cpp b/libAACenc/src/band_nrg.cpp new file mode 100644 index 0000000..8ae271b --- /dev/null +++ b/libAACenc/src/band_nrg.cpp @@ -0,0 +1,297 @@ +/***************************** MPEG-4 AAC Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: M. Werner + contents/description: Band/Line energy calculations + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "band_nrg.h" + + +/***************************************************************************** + functionname: FDKaacEnc_CalcSfbMaxScaleSpec + description: + input: + output: +*****************************************************************************/ +void +FDKaacEnc_CalcSfbMaxScaleSpec(const FIXP_DBL *RESTRICT mdctSpectrum, + const INT *RESTRICT bandOffset, + INT *RESTRICT sfbMaxScaleSpec, + const INT numBands) +{ + INT i,j; + FIXP_DBL maxSpc, tmp; + + for(i=0; i 0 */ + } +} + +/***************************************************************************** + functionname: FDKaacEnc_CheckBandEnergyOptim + description: + input: + output: +*****************************************************************************/ +FIXP_DBL +FDKaacEnc_CheckBandEnergyOptim(const FIXP_DBL *RESTRICT mdctSpectrum, + INT *RESTRICT sfbMaxScaleSpec, + const INT *RESTRICT bandOffset, + const INT numBands, + FIXP_DBL *RESTRICT bandEnergy, + FIXP_DBL *RESTRICT bandEnergyLdData, + INT minSpecShift) +{ + INT i, j, scale, nr = 0; + FIXP_DBL maxNrgLd = FL2FXCONST_DBL(-1.0f); + FIXP_DBL maxNrg = 0; + FIXP_DBL spec; + + for(i=0; i maxNrgLd) { + maxNrgLd = bandEnergyLdData[i]; + nr = i; + } + } + + /* return unscaled maxNrg*/ + scale = fixMax(0,sfbMaxScaleSpec[nr]-4); + scale = fixMax(2*(minSpecShift-scale),-(DFRACT_BITS-1)); + + maxNrg = scaleValue(bandEnergy[nr], scale); + + return maxNrg; +} + +/***************************************************************************** + functionname: FDKaacEnc_CalcBandEnergyOptimLong + description: + input: + output: +*****************************************************************************/ +INT +FDKaacEnc_CalcBandEnergyOptimLong(const FIXP_DBL *RESTRICT mdctSpectrum, + INT *RESTRICT sfbMaxScaleSpec, + const INT *RESTRICT bandOffset, + const INT numBands, + FIXP_DBL *RESTRICT bandEnergy, + FIXP_DBL *RESTRICT bandEnergyLdData) +{ + INT i, j, shiftBits = 0; + FIXP_DBL maxNrgLd = FL2FXCONST_DBL(0.0f); + + FIXP_DBL spec; + + for(i=0; i 7/2 = 4 (spc*spc) */ + FIXP_DBL tmp = FL2FXCONST_DBL(0.0); + /* don't use scaleValue() here, it increases workload quite sufficiently... */ + if (leadingBits>=0) { + for (j=bandOffset[i];j>shift; + tmp = fPow2AddDiv2(tmp, spec); + } + } + bandEnergy[i] = tmp<<1; + } + + /* calculate ld of bandNrg, subtract scaling */ + LdDataVector(bandEnergy, bandEnergyLdData, numBands); + for(i=numBands; i--!=0; ) { + FIXP_DBL scaleDiff = (sfbMaxScaleSpec[i]-4)*FL2FXCONST_DBL(2.0/64); + + bandEnergyLdData[i] = (bandEnergyLdData[i] >= ((FL2FXCONST_DBL(-1.f)>>1) + (scaleDiff>>1))) + ? bandEnergyLdData[i]-scaleDiff : FL2FXCONST_DBL(-1.f); + /* find maxNrgLd */ + maxNrgLd = fixMax(maxNrgLd, bandEnergyLdData[i]); + } + + if (maxNrgLd<=(FIXP_DBL)0) + { + for(i=numBands; i--!=0; ) + { + INT scale = fixMin((sfbMaxScaleSpec[i]-4)<<1,(DFRACT_BITS-1)); + bandEnergy[i] = scaleValue(bandEnergy[i], -scale); + } + return 0; + } + else + { /* scale down NRGs */ + while (maxNrgLd>FL2FXCONST_DBL(0.0f)) + { + maxNrgLd -= FL2FXCONST_DBL(2.0/64); + shiftBits++; + } + for(i=numBands; i--!=0; ) + { + INT scale = fixMin( ((sfbMaxScaleSpec[i]-4)+shiftBits)<<1, (DFRACT_BITS-1)); + bandEnergyLdData[i] -= shiftBits*FL2FXCONST_DBL(2.0/64); + bandEnergy[i] = scaleValue(bandEnergy[i], -scale); + } + return shiftBits; + } +} + + +/***************************************************************************** + functionname: FDKaacEnc_CalcBandEnergyOptimShort + description: + input: + output: +*****************************************************************************/ +void +FDKaacEnc_CalcBandEnergyOptimShort(const FIXP_DBL *RESTRICT mdctSpectrum, + INT *RESTRICT sfbMaxScaleSpec, + const INT *RESTRICT bandOffset, + const INT numBands, + FIXP_DBL *RESTRICT bandEnergy) +{ + INT i, j; + + for(i=0; i 7/2 = 4 (spc*spc) */ + FIXP_DBL tmp = FL2FXCONST_DBL(0.0); + for (j=bandOffset[i];j 7/2 = 4 (spc*spc) */ + scale = fixMin(scale,(DFRACT_BITS-1)); + bandEnergy[i] >>= scale; + } +} + + +/***************************************************************************** + functionname: FDKaacEnc_CalcBandNrgMSOpt + description: + input: + output: +*****************************************************************************/ +void FDKaacEnc_CalcBandNrgMSOpt(const FIXP_DBL *RESTRICT mdctSpectrumLeft, + const FIXP_DBL *RESTRICT mdctSpectrumRight, + INT *RESTRICT sfbMaxScaleSpecLeft, + INT *RESTRICT sfbMaxScaleSpecRight, + const INT *RESTRICT bandOffset, + const INT numBands, + FIXP_DBL *RESTRICT bandEnergyMid, + FIXP_DBL *RESTRICT bandEnergySide, + INT calcLdData, + FIXP_DBL *RESTRICT bandEnergyMidLdData, + FIXP_DBL *RESTRICT bandEnergySideLdData) +{ + INT i, j, minScale; + FIXP_DBL NrgMid, NrgSide, specm, specs; + + for (i=0; i 0) { + for (j=bandOffset[i];j>1; + FIXP_DBL specR = mdctSpectrumRight[j]>>1; + specm = specL + specR; + specs = specL - specR; + NrgMid = fPow2AddDiv2(NrgMid, specm); + NrgSide = fPow2AddDiv2(NrgSide, specs); + } + } + bandEnergyMid[i] = NrgMid<<1; + bandEnergySide[i] = NrgSide<<1; + } + + if(calcLdData) { + LdDataVector(bandEnergyMid, bandEnergyMidLdData, numBands); + LdDataVector(bandEnergySide, bandEnergySideLdData, numBands); + } + + for (i=0; i>= scale; + bandEnergySide[i] >>= scale; + } +} diff --git a/libAACenc/src/band_nrg.h b/libAACenc/src/band_nrg.h new file mode 100644 index 0000000..23a207b --- /dev/null +++ b/libAACenc/src/band_nrg.h @@ -0,0 +1,86 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Werner + Description: Band/Line energy calculation + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#ifndef _BAND_NRG_H +#define _BAND_NRG_H + +#include "common_fix.h" + + +void +FDKaacEnc_CalcSfbMaxScaleSpec( + const FIXP_DBL *mdctSpectrum, + const INT *bandOffset, + INT *sfbMaxScaleSpec, + const INT numBands + ); + +FIXP_DBL +FDKaacEnc_CheckBandEnergyOptim( + const FIXP_DBL *mdctSpectrum, + INT *sfbMaxScaleSpec, + const INT *bandOffset, + const INT numBands, + FIXP_DBL *bandEnergy, + FIXP_DBL *bandEnergyLdData, + INT minSpecShift + ); + +INT +FDKaacEnc_CalcBandEnergyOptimLong( + const FIXP_DBL *mdctSpectrum, + INT *sfbMaxScaleSpec, + const INT *bandOffset, + const INT numBands, + FIXP_DBL *bandEnergy, + FIXP_DBL *bandEnergyLdData + ); + +void +FDKaacEnc_CalcBandEnergyOptimShort( + const FIXP_DBL *mdctSpectrum, + INT *sfbMaxScaleSpec, + const INT *bandOffset, + const INT numBands, + FIXP_DBL *bandEnergy + ); + + +void FDKaacEnc_CalcBandNrgMSOpt( + const FIXP_DBL *RESTRICT mdctSpectrumLeft, + const FIXP_DBL *RESTRICT mdctSpectrumRight, + INT *RESTRICT sfbMaxScaleSpecLeft, + INT *RESTRICT sfbMaxScaleSpecRight, + const INT *RESTRICT bandOffset, + const INT numBands, + FIXP_DBL *RESTRICT bandEnergyMid, + FIXP_DBL *RESTRICT bandEnergySide, + INT calcLdData, + FIXP_DBL *RESTRICT bandEnergyMidLdData, + FIXP_DBL *RESTRICT bandEnergySideLdData); + +#endif diff --git a/libAACenc/src/bandwidth.cpp b/libAACenc/src/bandwidth.cpp new file mode 100644 index 0000000..51c3a33 --- /dev/null +++ b/libAACenc/src/bandwidth.cpp @@ -0,0 +1,316 @@ +/************************* Fast MPEG AAC Audio Encoder ********************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Schug / A. Groeschel + contents/description: bandwidth expert + +******************************************************************************/ + +#include "channel_map.h" +#include "bandwidth.h" +#include "aacEnc_ram.h" + +typedef struct{ + INT chanBitRate; + INT bandWidthMono; + INT bandWidth2AndMoreChan; + +} BANDWIDTH_TAB; + +static const BANDWIDTH_TAB bandWidthTable[] = { + {0, 3700, 5000}, + {12000, 5000, 6400}, + {20000, 6900, 9640}, + {28000, 9600, 13050}, + {40000, 12060, 14260}, + {56000, 13950, 15500}, + {72000, 14200, 16120}, + {96000, 17000, 17000}, + {576001,17000, 17000} +}; + + +static const BANDWIDTH_TAB bandWidthTable_LD_22050[] = { + { 8000, 2000, 2400}, + {12000, 2500, 2700}, + {16000, 3300, 3100}, + {24000, 6250, 7200}, + {32000, 9200, 10500}, + {40000, 16000, 16000}, + {48000, 16000, 16000}, + {360001, 16000, 16000} +}; + +static const BANDWIDTH_TAB bandWidthTable_LD_24000[] = { + { 8000, 2000, 2000}, + {12000, 2000, 2300}, + {16000, 2200, 2500}, + {24000, 5650, 6400}, + {32000, 11600, 12000}, + {40000, 12000, 16000}, + {48000, 16000, 16000}, + {64000, 16000, 16000}, + {360001, 16000, 16000} +}; + +static const BANDWIDTH_TAB bandWidthTable_LD_32000[] = { + { 8000, 2000, 2000}, + {12000, 2000, 2000}, + {24000, 4250, 5200}, + {32000, 8400, 9000}, + {40000, 9400, 11300}, + {48000, 11900, 13700}, + {64000, 14800, 16000}, + {76000, 16000, 16000}, + {360001, 16000, 16000} +}; + +static const BANDWIDTH_TAB bandWidthTable_LD_44100[] = { + { 8000, 2000, 2000}, + {24000, 2000, 2000}, + {32000, 4400, 5700}, + {40000, 7400, 8800}, + {48000, 9000, 10700}, + {56000, 11000, 12900}, + {64000, 14400, 15500}, + {80000, 16000, 16200}, + {96000, 16500, 16000}, + {128000, 16000, 16000}, + {360001, 16000, 16000} +}; + +static const BANDWIDTH_TAB bandWidthTable_LD_48000[] = { + { 8000, 2000, 2000}, + {24000, 2000, 2000}, + {32000, 4400, 5700}, + {40000, 7400, 8800}, + {48000, 9000, 10700}, + {56000, 11000, 12800}, + {64000, 14300, 15400}, + {80000, 16000, 16200}, + {96000, 16500, 16000}, + {128000, 16000, 16000}, + {360001, 16000, 16000} +}; + +typedef struct{ + AACENC_BITRATE_MODE bitrateMode; + int bandWidthMono; + int bandWidth2AndMoreChan; +} BANDWIDTH_TAB_VBR; + +static const BANDWIDTH_TAB_VBR bandWidthTableVBR[]= { + {AACENC_BR_MODE_CBR, 0, 0}, + {AACENC_BR_MODE_VBR_1, 13050, 13050}, + {AACENC_BR_MODE_VBR_2, 13050, 13050}, + {AACENC_BR_MODE_VBR_3, 14260, 14260}, + {AACENC_BR_MODE_VBR_4, 15500, 15500}, + {AACENC_BR_MODE_VBR_5, 48000, 48000}, + {AACENC_BR_MODE_SFR, 0, 0}, + {AACENC_BR_MODE_FF, 0, 0} + +}; + +static INT GetBandwidthEntry( + const INT frameLength, + const INT sampleRate, + const INT chanBitRate, + const INT entryNo) +{ + INT bandwidth = -1; + const BANDWIDTH_TAB *pBwTab = NULL; + INT bwTabSize = 0; + + switch (frameLength) { + case 960: + case 1024: + pBwTab = bandWidthTable; + bwTabSize = sizeof(bandWidthTable)/sizeof(BANDWIDTH_TAB); + break; + case 480: + case 512: + switch (sampleRate) { + case 8000: + case 11025: + case 12000: + case 16000: + case 22050: + pBwTab = bandWidthTable_LD_22050; + bwTabSize = sizeof(bandWidthTable_LD_22050)/sizeof(BANDWIDTH_TAB); + break; + case 24000: + pBwTab = bandWidthTable_LD_24000; + bwTabSize = sizeof(bandWidthTable_LD_24000)/sizeof(BANDWIDTH_TAB); + break; + case 32000: + pBwTab = bandWidthTable_LD_32000; + bwTabSize = sizeof(bandWidthTable_LD_32000)/sizeof(BANDWIDTH_TAB); + break; + case (44100): + pBwTab = bandWidthTable_LD_44100; + bwTabSize = sizeof(bandWidthTable_LD_44100)/sizeof(BANDWIDTH_TAB); + break; + case 48000: + case 64000: + case 88200: + case 96000: + pBwTab = bandWidthTable_LD_48000; + bwTabSize = sizeof(bandWidthTable_LD_48000)/sizeof(BANDWIDTH_TAB); + break; + } + break; + default: + pBwTab = NULL; + bwTabSize = 0; + } + + if (pBwTab!=NULL) { + int i; + for (i=0; i= pBwTab[i].chanBitRate && + chanBitRate < pBwTab[i+1].chanBitRate) + { + switch (frameLength) { + case 960: + case 1024: + bandwidth = (entryNo==0) + ? pBwTab[i].bandWidthMono + : pBwTab[i].bandWidth2AndMoreChan; + break; + case 480: + case 512: + { + INT q_res = 0; + INT startBw = (entryNo==0) ? pBwTab[i ].bandWidthMono : pBwTab[i ].bandWidth2AndMoreChan; + INT endBw = (entryNo==0) ? pBwTab[i+1].bandWidthMono : pBwTab[i+1].bandWidth2AndMoreChan; + INT startBr = pBwTab[i].chanBitRate; + INT endBr = pBwTab[i+1].chanBitRate; + + FIXP_DBL bwFac_fix = fDivNorm(chanBitRate-startBr, endBr-startBr, &q_res); + bandwidth = (INT)scaleValue(fMult(bwFac_fix, (FIXP_DBL)(endBw-startBw)),q_res) + startBw; + } + break; + default: + bandwidth = -1; + } + break; + } /* within bitrate range */ + } + } /* pBwTab!=NULL */ + + return bandwidth; +} + + +AAC_ENCODER_ERROR FDKaacEnc_DetermineBandWidth(INT* bandWidth, + INT proposedBandWidth, + INT bitrate, + AACENC_BITRATE_MODE bitrateMode, + INT sampleRate, + INT frameLength, + CHANNEL_MAPPING* cm, + CHANNEL_MODE encoderMode) +{ + AAC_ENCODER_ERROR ErrorStatus = AAC_ENC_OK; + //FIXP_DBL invBandWidthGain=FL2FXCONST_DBL(1.f); + INT chanBitRate = bitrate/cm->nChannels; + + /* vbr */ + switch(bitrateMode){ + case AACENC_BR_MODE_VBR_1: + case AACENC_BR_MODE_VBR_2: + case AACENC_BR_MODE_VBR_3: + case AACENC_BR_MODE_VBR_4: + case AACENC_BR_MODE_VBR_5: + if (proposedBandWidth != 0){ + /* use given bw */ + *bandWidth = proposedBandWidth; + } else { + /* take bw from table */ + switch(encoderMode){ + case MODE_1: + *bandWidth = bandWidthTableVBR[bitrateMode].bandWidthMono; + break; + case MODE_2: + case MODE_1_2: + case MODE_1_2_1: + case MODE_1_2_2: + case MODE_1_2_2_1: + case MODE_1_2_2_2_1: + *bandWidth = bandWidthTableVBR[bitrateMode].bandWidth2AndMoreChan; + break; + default: + return AAC_ENC_UNSUPPORTED_CHANNELCONFIG; + } + } + break; + case AACENC_BR_MODE_CBR: + case AACENC_BR_MODE_SFR: + case AACENC_BR_MODE_FF: + + /* bandwidth limiting */ + if (proposedBandWidth != 0) { + *bandWidth = FDKmin(proposedBandWidth, FDKmin(20000, sampleRate>>1)); + } + else { /* search reasonable bandwidth */ + + int entryNo = 0; + + switch(encoderMode){ + case MODE_1: /* mono */ + entryNo = 0; /* use mono bandwith settings */ + break; + + case MODE_2: /* stereo */ + case MODE_1_2: /* sce + cpe */ + case MODE_1_2_1: /* sce + cpe + sce */ + case MODE_1_2_2: /* sce + cpe + cpe */ + case MODE_1_2_2_1: /* (5.1) sce + cpe + cpe + lfe */ + case MODE_1_2_2_2_1: /* (7.1) sce + cpe + cpe + cpe + lfe */ + entryNo = 1; /* use stereo bandwith settings */ + break; + + default: + return AAC_ENC_UNSUPPORTED_CHANNELCONFIG; + } + + *bandWidth = GetBandwidthEntry( + frameLength, + sampleRate, + chanBitRate, + entryNo); + + if (*bandWidth==-1) { + ErrorStatus = AAC_ENC_INVALID_CHANNEL_BITRATE; + } + } + break; + default: + *bandWidth = 0; + return AAC_ENC_UNSUPPORTED_BITRATE_MODE; + } + + *bandWidth = FDKmin(*bandWidth, sampleRate/2); + + return ErrorStatus;; +} diff --git a/libAACenc/src/bandwidth.h b/libAACenc/src/bandwidth.h new file mode 100644 index 0000000..e58ab94 --- /dev/null +++ b/libAACenc/src/bandwidth.h @@ -0,0 +1,44 @@ +/************************* Fast MPEG AAC Audio Encoder ********************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Schug / A. Groeschel + contents/description: bandwidth expert + +******************************************************************************/ + +#ifndef _BANDWIDTH_H +#define _BANDWIDTH_H + + +#include "qc_data.h" + +AAC_ENCODER_ERROR FDKaacEnc_DetermineBandWidth(INT* bandWidth, + INT proposedBandwidth, + INT bitrate, + AACENC_BITRATE_MODE bitrateMode, + INT sampleRate, + INT frameLength, + CHANNEL_MAPPING* cm, + CHANNEL_MODE encoderMode); + +#endif /* BANDWIDTH_H */ diff --git a/libAACenc/src/bit_cnt.cpp b/libAACenc/src/bit_cnt.cpp new file mode 100644 index 0000000..f1a9b73 --- /dev/null +++ b/libAACenc/src/bit_cnt.cpp @@ -0,0 +1,1060 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Huffman Bitcounter & coder + +******************************************************************************/ + +#include "bit_cnt.h" + +#include "aacEnc_ram.h" + +#define HI_LTAB(a) (a>>16) +#define LO_LTAB(a) (a & 0xffff) + +/***************************************************************************** + + + functionname: FDKaacEnc_count1_2_3_4_5_6_7_8_9_10_11 + description: counts tables 1-11 + returns: + input: quantized spectrum + output: bitCount for tables 1-11 + +*****************************************************************************/ + +static void FDKaacEnc_count1_2_3_4_5_6_7_8_9_10_11(const SHORT *RESTRICT values, + const INT width, + INT *bitCount) +{ + + INT i; + INT bc1_2,bc3_4,bc5_6,bc7_8,bc9_10,bc11,sc; + INT t0,t1,t2,t3; + bc1_2=0; + bc3_4=0; + bc5_6=0; + bc7_8=0; + bc9_10=0; + bc11=0; + sc=0; + + for(i=0;i0)+(t1>0)+(t2>0)+(t3>0); + } + + bitCount[1]=HI_LTAB(bc1_2); + bitCount[2]=LO_LTAB(bc1_2); + bitCount[3]=HI_LTAB(bc3_4)+sc; + bitCount[4]=LO_LTAB(bc3_4)+sc; + bitCount[5]=HI_LTAB(bc5_6); + bitCount[6]=LO_LTAB(bc5_6); + bitCount[7]=HI_LTAB(bc7_8)+sc; + bitCount[8]=LO_LTAB(bc7_8)+sc; + bitCount[9]=HI_LTAB(bc9_10)+sc; + bitCount[10]=LO_LTAB(bc9_10)+sc; + bitCount[11]=bc11+sc; + +} + + +/***************************************************************************** + + functionname: FDKaacEnc_count3_4_5_6_7_8_9_10_11 + description: counts tables 3-11 + returns: + input: quantized spectrum + output: bitCount for tables 3-11 + +*****************************************************************************/ + +static void FDKaacEnc_count3_4_5_6_7_8_9_10_11(const SHORT *RESTRICT values, + const INT width, + INT *bitCount) +{ + + INT i; + INT bc3_4,bc5_6,bc7_8,bc9_10,bc11,sc; + INT t0,t1,t2,t3; + + bc3_4=0; + bc5_6=0; + bc7_8=0; + bc9_10=0; + bc11=0; + sc=0; + + for(i=0;i0)+(t1>0)+(t2>0)+(t3>0); + } + + bitCount[1]=INVALID_BITCOUNT; + bitCount[2]=INVALID_BITCOUNT; + bitCount[3]=HI_LTAB(bc3_4)+sc; + bitCount[4]=LO_LTAB(bc3_4)+sc; + bitCount[5]=HI_LTAB(bc5_6); + bitCount[6]=LO_LTAB(bc5_6); + bitCount[7]=HI_LTAB(bc7_8)+sc; + bitCount[8]=LO_LTAB(bc7_8)+sc; + bitCount[9]=HI_LTAB(bc9_10)+sc; + bitCount[10]=LO_LTAB(bc9_10)+sc; + bitCount[11]=bc11+sc; +} + + + +/***************************************************************************** + + functionname: FDKaacEnc_count5_6_7_8_9_10_11 + description: counts tables 5-11 + returns: + input: quantized spectrum + output: bitCount for tables 5-11 + +*****************************************************************************/ + + +static void FDKaacEnc_count5_6_7_8_9_10_11(const SHORT *RESTRICT values, + const INT width, + INT *bitCount) +{ + + INT i; + INT bc5_6,bc7_8,bc9_10,bc11,sc; + INT t0,t1; + bc5_6=0; + bc7_8=0; + bc9_10=0; + bc11=0; + sc=0; + + for(i=0;i0)+(t1>0); + } + bitCount[1]=INVALID_BITCOUNT; + bitCount[2]=INVALID_BITCOUNT; + bitCount[3]=INVALID_BITCOUNT; + bitCount[4]=INVALID_BITCOUNT; + bitCount[5]=HI_LTAB(bc5_6); + bitCount[6]=LO_LTAB(bc5_6); + bitCount[7]=HI_LTAB(bc7_8)+sc; + bitCount[8]=LO_LTAB(bc7_8)+sc; + bitCount[9]=HI_LTAB(bc9_10)+sc; + bitCount[10]=LO_LTAB(bc9_10)+sc; + bitCount[11]=bc11+sc; + +} + + +/***************************************************************************** + + functionname: FDKaacEnc_count7_8_9_10_11 + description: counts tables 7-11 + returns: + input: quantized spectrum + output: bitCount for tables 7-11 + +*****************************************************************************/ + +static void FDKaacEnc_count7_8_9_10_11(const SHORT *RESTRICT values, + const INT width, + INT *bitCount) +{ + + INT i; + INT bc7_8,bc9_10,bc11,sc; + INT t0,t1; + + bc7_8=0; + bc9_10=0; + bc11=0; + sc=0; + + for(i=0;i0)+(t1>0); + } + + bitCount[1]=INVALID_BITCOUNT; + bitCount[2]=INVALID_BITCOUNT; + bitCount[3]=INVALID_BITCOUNT; + bitCount[4]=INVALID_BITCOUNT; + bitCount[5]=INVALID_BITCOUNT; + bitCount[6]=INVALID_BITCOUNT; + bitCount[7]=HI_LTAB(bc7_8)+sc; + bitCount[8]=LO_LTAB(bc7_8)+sc; + bitCount[9]=HI_LTAB(bc9_10)+sc; + bitCount[10]=LO_LTAB(bc9_10)+sc; + bitCount[11]=bc11+sc; + +} + +/***************************************************************************** + + functionname: FDKaacEnc_count9_10_11 + description: counts tables 9-11 + returns: + input: quantized spectrum + output: bitCount for tables 9-11 + +*****************************************************************************/ + + + +static void FDKaacEnc_count9_10_11(const SHORT *RESTRICT values, + const INT width, + INT *bitCount) +{ + + INT i; + INT bc9_10,bc11,sc; + INT t0,t1; + + bc9_10=0; + bc11=0; + sc=0; + + for(i=0;i0)+(t1>0); + } + + bitCount[1]=INVALID_BITCOUNT; + bitCount[2]=INVALID_BITCOUNT; + bitCount[3]=INVALID_BITCOUNT; + bitCount[4]=INVALID_BITCOUNT; + bitCount[5]=INVALID_BITCOUNT; + bitCount[6]=INVALID_BITCOUNT; + bitCount[7]=INVALID_BITCOUNT; + bitCount[8]=INVALID_BITCOUNT; + bitCount[9]=HI_LTAB(bc9_10)+sc; + bitCount[10]=LO_LTAB(bc9_10)+sc; + bitCount[11]=bc11+sc; + +} + +/***************************************************************************** + + functionname: FDKaacEnc_count11 + description: counts table 11 + returns: + input: quantized spectrum + output: bitCount for table 11 + +*****************************************************************************/ + +static void FDKaacEnc_count11(const SHORT *RESTRICT values, + const INT width, + INT *bitCount) +{ + + INT i; + INT bc11,sc; + INT t0,t1; + + bc11=0; + sc=0; + for(i=0;i0)+(t1>0); + } + + bitCount[1]=INVALID_BITCOUNT; + bitCount[2]=INVALID_BITCOUNT; + bitCount[3]=INVALID_BITCOUNT; + bitCount[4]=INVALID_BITCOUNT; + bitCount[5]=INVALID_BITCOUNT; + bitCount[6]=INVALID_BITCOUNT; + bitCount[7]=INVALID_BITCOUNT; + bitCount[8]=INVALID_BITCOUNT; + bitCount[9]=INVALID_BITCOUNT; + bitCount[10]=INVALID_BITCOUNT; + bitCount[11]=bc11+sc; +} + +/***************************************************************************** + + functionname: FDKaacEnc_countEsc + description: counts table 11 (with Esc) + returns: + input: quantized spectrum + output: bitCount for tables 11 (with Esc) + +*****************************************************************************/ + +static void FDKaacEnc_countEsc(const SHORT *RESTRICT values, + const INT width, + INT *RESTRICT bitCount) +{ + + INT i; + INT bc11,ec,sc; + INT t0,t1,t00,t01; + + bc11=0; + sc=0; + ec=0; + for(i=0;i0)+(t1>0); + + t00 = fixMin(t0,16); + t01 = fixMin(t1,16); + bc11+= (INT) FDKaacEnc_huff_ltab11[t00][t01]; + + if(t0>=16){ + ec+=5; + while((t0>>=1) >= 16) + ec+=2; + } + + if(t1>=16){ + ec+=5; + while((t1>>=1) >= 16) + ec+=2; + } + } + + for (i=0; i<11; i++) + bitCount[i]=INVALID_BITCOUNT; + + bitCount[11]=bc11+sc+ec; +} + + +typedef void (*COUNT_FUNCTION)(const SHORT *RESTRICT values, + const INT width, + INT *RESTRICT bitCount); + +static const COUNT_FUNCTION countFuncTable[CODE_BOOK_ESC_LAV+1] = +{ + + FDKaacEnc_count1_2_3_4_5_6_7_8_9_10_11, /* 0 */ + FDKaacEnc_count1_2_3_4_5_6_7_8_9_10_11, /* 1 */ + FDKaacEnc_count3_4_5_6_7_8_9_10_11, /* 2 */ + FDKaacEnc_count5_6_7_8_9_10_11, /* 3 */ + FDKaacEnc_count5_6_7_8_9_10_11, /* 4 */ + FDKaacEnc_count7_8_9_10_11, /* 5 */ + FDKaacEnc_count7_8_9_10_11, /* 6 */ + FDKaacEnc_count7_8_9_10_11, /* 7 */ + FDKaacEnc_count9_10_11, /* 8 */ + FDKaacEnc_count9_10_11, /* 9 */ + FDKaacEnc_count9_10_11, /* 10 */ + FDKaacEnc_count9_10_11, /* 11 */ + FDKaacEnc_count9_10_11, /* 12 */ + FDKaacEnc_count11, /* 13 */ + FDKaacEnc_count11, /* 14 */ + FDKaacEnc_count11, /* 15 */ + FDKaacEnc_countEsc /* 16 */ +}; + + + +INT FDKaacEnc_bitCount(const SHORT *values, + const INT width, + INT maxVal, + INT *bitCount) +{ + + /* + check if we can use codebook 0 + */ + + if(maxVal == 0) + bitCount[0] = 0; + else + bitCount[0] = INVALID_BITCOUNT; + + maxVal = fixMin(maxVal,(INT)CODE_BOOK_ESC_LAV); + countFuncTable[maxVal](values,width,bitCount); + return(0); +} + + + + +/* + count difference between actual and zeroed lines +*/ +INT FDKaacEnc_countValues(SHORT *RESTRICT values, INT width, INT codeBook) +{ + + INT i,t0,t1,t2,t3,t00,t01; + INT codeLength; + INT signLength; + INT bitCnt=0; + + switch(codeBook){ + case CODE_BOOK_ZERO_NO: + break; + + case CODE_BOOK_1_NO: + for(i=0; i=16){ + INT n,p; + n=0; + p=t0; + while((p>>=1) >=16){ + bitCnt++; + n++; + } + bitCnt+=(n+5); + } + if(t1 >=16){ + INT n,p; + n=0; + p=t1; + while((p>>=1) >=16){ + bitCnt++; + n++; + } + bitCnt+=(n+5); + } + } + break; + + default: + break; + } + + return(bitCnt); +} + + + +INT FDKaacEnc_codeValues(SHORT *RESTRICT values, INT width, INT codeBook, HANDLE_FDK_BITSTREAM hBitstream) +{ + + INT i,t0,t1,t2,t3,t00,t01; + INT codeWord,codeLength; + INT sign,signLength; + + switch(codeBook){ + case CODE_BOOK_ZERO_NO: + break; + + case CODE_BOOK_1_NO: + for(i=0; i=16){ + INT n,p; + n=0; + p=t0; + while((p>>=1) >=16){ + FDKwriteBits(hBitstream,1,1); + n++; + } + FDKwriteBits(hBitstream,0,1); + FDKwriteBits(hBitstream,t0-(1<<(n+4)),n+4); + } + if(t1 >=16){ + INT n,p; + n=0; + p=t1; + while((p>>=1) >=16){ + FDKwriteBits(hBitstream,1,1); + n++; + } + FDKwriteBits(hBitstream,0,1); + FDKwriteBits(hBitstream,t1-(1<<(n+4)),n+4); + } + } + break; + + default: + break; + } + return(0); +} + +INT FDKaacEnc_codeScalefactorDelta(INT delta, HANDLE_FDK_BITSTREAM hBitstream) +{ + INT codeWord,codeLength; + + if(fixp_abs(delta) >CODE_BOOK_SCF_LAV) + return(1); + + codeWord = FDKaacEnc_huff_ctabscf[delta+CODE_BOOK_SCF_LAV]; + codeLength = (INT)FDKaacEnc_huff_ltabscf[delta+CODE_BOOK_SCF_LAV]; + FDKwriteBits(hBitstream,codeWord,codeLength); + return(0); +} + + + diff --git a/libAACenc/src/bit_cnt.h b/libAACenc/src/bit_cnt.h new file mode 100644 index 0000000..6baf7df --- /dev/null +++ b/libAACenc/src/bit_cnt.h @@ -0,0 +1,124 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Huffman Bitcounter & coder + +******************************************************************************/ +#ifndef __BITCOUNT_H +#define __BITCOUNT_H + + +#include "common_fix.h" +#include "FDK_bitstream.h" +#include "aacEnc_rom.h" + +#define INVALID_BITCOUNT (FDK_INT_MAX/4) + +/* + code book number table +*/ + +enum codeBookNo{ + CODE_BOOK_ZERO_NO= 0, + CODE_BOOK_1_NO= 1, + CODE_BOOK_2_NO= 2, + CODE_BOOK_3_NO= 3, + CODE_BOOK_4_NO= 4, + CODE_BOOK_5_NO= 5, + CODE_BOOK_6_NO= 6, + CODE_BOOK_7_NO= 7, + CODE_BOOK_8_NO= 8, + CODE_BOOK_9_NO= 9, + CODE_BOOK_10_NO= 10, + CODE_BOOK_ESC_NO= 11, + CODE_BOOK_RES_NO= 12, + CODE_BOOK_PNS_NO= 13, + CODE_BOOK_IS_OUT_OF_PHASE_NO= 14, + CODE_BOOK_IS_IN_PHASE_NO= 15 + +}; + +/* + code book index table +*/ + +enum codeBookNdx{ + CODE_BOOK_ZERO_NDX, + CODE_BOOK_1_NDX, + CODE_BOOK_2_NDX, + CODE_BOOK_3_NDX, + CODE_BOOK_4_NDX, + CODE_BOOK_5_NDX, + CODE_BOOK_6_NDX, + CODE_BOOK_7_NDX, + CODE_BOOK_8_NDX, + CODE_BOOK_9_NDX, + CODE_BOOK_10_NDX, + CODE_BOOK_ESC_NDX, + CODE_BOOK_RES_NDX, + CODE_BOOK_PNS_NDX, + CODE_BOOK_IS_OUT_OF_PHASE_NDX, + CODE_BOOK_IS_IN_PHASE_NDX, + NUMBER_OF_CODE_BOOKS +}; + +/* + code book lav table +*/ + +enum codeBookLav{ + CODE_BOOK_ZERO_LAV=0, + CODE_BOOK_1_LAV=1, + CODE_BOOK_2_LAV=1, + CODE_BOOK_3_LAV=2, + CODE_BOOK_4_LAV=2, + CODE_BOOK_5_LAV=4, + CODE_BOOK_6_LAV=4, + CODE_BOOK_7_LAV=7, + CODE_BOOK_8_LAV=7, + CODE_BOOK_9_LAV=12, + CODE_BOOK_10_LAV=12, + CODE_BOOK_ESC_LAV=16, + CODE_BOOK_SCF_LAV=60, + CODE_BOOK_PNS_LAV=60 + }; + +INT FDKaacEnc_bitCount(const SHORT *aQuantSpectrum, + const INT noOfSpecLines, + INT maxVal, + INT *bitCountLut); + +INT FDKaacEnc_countValues(SHORT *values, INT width, INT codeBook); + +INT FDKaacEnc_codeValues(SHORT *values, INT width, INT codeBook, HANDLE_FDK_BITSTREAM hBitstream); + +INT FDKaacEnc_codeScalefactorDelta(INT scalefactor, HANDLE_FDK_BITSTREAM hBitstream); + +inline INT FDKaacEnc_bitCountScalefactorDelta(const INT delta) +{ + FDK_ASSERT( (0 <= (delta+CODE_BOOK_SCF_LAV)) && ((delta+CODE_BOOK_SCF_LAV)<(int)(sizeof(FDKaacEnc_huff_ltabscf)/sizeof((FDKaacEnc_huff_ltabscf[0])))) ); + return((INT)FDKaacEnc_huff_ltabscf[delta+CODE_BOOK_SCF_LAV]); +} + +#endif diff --git a/libAACenc/src/bitenc.cpp b/libAACenc/src/bitenc.cpp new file mode 100644 index 0000000..d70f872 --- /dev/null +++ b/libAACenc/src/bitenc.cpp @@ -0,0 +1,1431 @@ + /******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Werner + contents/description: Bitstream encoder + +******************************************************************************/ + +#include "bitenc.h" +#include "bit_cnt.h" +#include "dyn_bits.h" +#include "qc_data.h" +#include "interface.h" +#include "aacEnc_ram.h" + + +#include "tpenc_lib.h" + +#include "FDK_tools_rom.h" /* needed for the bitstream syntax tables */ + +static const int globalGainOffset = 100; +static const int icsReservedBit = 0; +static const int noiseOffset = 90; + +/***************************************************************************** + + functionname: FDKaacEnc_encodeSpectralData + description: encode spectral data + returns: the number of written bits + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodeSpectralData(INT *sfbOffset, + SECTION_DATA *sectionData, + SHORT *quantSpectrum, + HANDLE_FDK_BITSTREAM hBitStream) +{ + INT i,sfb; + INT dbgVal = FDKgetValidBits(hBitStream); + + for(i=0;inoOfSections;i++) + { + if(sectionData->huffsection[i].codeBook != CODE_BOOK_PNS_NO) + { + /* huffencode spectral data for this huffsection */ + INT tmp = sectionData->huffsection[i].sfbStart+sectionData->huffsection[i].sfbCnt; + for(sfb=sectionData->huffsection[i].sfbStart; sfbhuffsection[i].codeBook, + hBitStream); + } + } + } + return(FDKgetValidBits(hBitStream)-dbgVal); +} + +/***************************************************************************** + + functionname:FDKaacEnc_encodeGlobalGain + description: encodes Global Gain (common scale factor) + returns: the number of static bits + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodeGlobalGain(INT globalGain, + INT scalefac, + HANDLE_FDK_BITSTREAM hBitStream, + INT mdctScale) +{ + if (hBitStream != NULL) { + FDKwriteBits(hBitStream,globalGain - scalefac + globalGainOffset-4*(LOG_NORM_PCM-mdctScale),8); + } + return (8); +} + + +/***************************************************************************** + + functionname:FDKaacEnc_encodeIcsInfo + description: encodes Ics Info + returns: the number of static bits + input: + output: + +*****************************************************************************/ + +static INT FDKaacEnc_encodeIcsInfo(INT blockType, + INT windowShape, + INT groupingMask, + INT maxSfbPerGroup, + HANDLE_FDK_BITSTREAM hBitStream, + UINT syntaxFlags) +{ + INT statBits; + + if (blockType == SHORT_WINDOW) { + statBits = 8 + TRANS_FAC - 1; + } else { + if (syntaxFlags & AC_ELD) { + statBits = 6; + } else + { + statBits = (!(syntaxFlags & AC_SCALABLE)) ? 11 : 10; + } + } + + if (hBitStream != NULL) { + + if (!(syntaxFlags & AC_ELD)){ + FDKwriteBits(hBitStream,icsReservedBit,1); + FDKwriteBits(hBitStream,blockType,2); + FDKwriteBits(hBitStream, (windowShape == LOL_WINDOW) ? KBD_WINDOW : windowShape,1); + } + + switch(blockType){ + case LONG_WINDOW: + case START_WINDOW: + case STOP_WINDOW: + FDKwriteBits(hBitStream,maxSfbPerGroup,6); + + if (!(syntaxFlags & (AC_SCALABLE|AC_ELD)) ) { /* If not scalable syntax then ... */ + /* No predictor data present */ + FDKwriteBits(hBitStream, 0, 1); + } + break; + + case SHORT_WINDOW: + FDKwriteBits(hBitStream,maxSfbPerGroup,4); + + /* Write grouping bits */ + FDKwriteBits(hBitStream,groupingMask,TRANS_FAC-1); + break; + } + } + + return (statBits); +} + +/***************************************************************************** + + functionname: FDKaacEnc_encodeSectionData + description: encode section data (common Huffman codebooks for adjacent + SFB's) + returns: none + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodeSectionData(SECTION_DATA *sectionData, + HANDLE_FDK_BITSTREAM hBitStream, + UINT useVCB11) +{ + if (hBitStream != NULL) { + INT sectEscapeVal=0,sectLenBits=0; + INT sectLen; + INT i; + INT dbgVal=FDKgetValidBits(hBitStream); + INT sectCbBits = 4; + + switch(sectionData->blockType) + { + case LONG_WINDOW: + case START_WINDOW: + case STOP_WINDOW: + sectEscapeVal = SECT_ESC_VAL_LONG; + sectLenBits = SECT_BITS_LONG; + break; + + case SHORT_WINDOW: + sectEscapeVal = SECT_ESC_VAL_SHORT; + sectLenBits = SECT_BITS_SHORT; + break; + } + + for(i=0;inoOfSections;i++) + { + INT codeBook = sectionData->huffsection[i].codeBook; + + FDKwriteBits(hBitStream,codeBook,sectCbBits); + + { + sectLen = sectionData->huffsection[i].sfbCnt; + + while(sectLen >= sectEscapeVal) + { + FDKwriteBits(hBitStream,sectEscapeVal,sectLenBits); + sectLen-=sectEscapeVal; + } + FDKwriteBits(hBitStream,sectLen,sectLenBits); + } + } + return(FDKgetValidBits(hBitStream)-dbgVal); + } + return (0); +} + +/***************************************************************************** + + functionname: FDKaacEnc_encodeScaleFactorData + description: encode DPCM coded scale factors + returns: none + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodeScaleFactorData(UINT *maxValueInSfb, + SECTION_DATA *sectionData, + INT *scalefac, + HANDLE_FDK_BITSTREAM hBitStream, + INT *RESTRICT noiseNrg, + const INT *isScale, + INT globalGain) +{ + if (hBitStream != NULL) { + INT i,j,lastValScf,deltaScf; + INT deltaPns; + INT lastValPns = 0; + INT noisePCMFlag = TRUE; + INT lastValIs; + + INT dbgVal = FDKgetValidBits(hBitStream); + + lastValScf=scalefac[sectionData->firstScf]; + lastValPns = globalGain-scalefac[sectionData->firstScf]+globalGainOffset-4*LOG_NORM_PCM-noiseOffset; + lastValIs = 0; + + for(i=0; inoOfSections; i++){ + if (sectionData->huffsection[i].codeBook != CODE_BOOK_ZERO_NO) { + + if ((sectionData->huffsection[i].codeBook == CODE_BOOK_IS_OUT_OF_PHASE_NO) || + (sectionData->huffsection[i].codeBook == CODE_BOOK_IS_IN_PHASE_NO)) + { + INT sfbStart = sectionData->huffsection[i].sfbStart; + INT tmp = sfbStart + sectionData->huffsection[i].sfbCnt; + for(j=sfbStart; jhuffsection[i].codeBook == CODE_BOOK_PNS_NO) { + INT sfbStart = sectionData->huffsection[i].sfbStart; + INT tmp = sfbStart + sectionData->huffsection[i].sfbCnt; + for(j=sfbStart; jhuffsection[i].sfbStart+sectionData->huffsection[i].sfbCnt; + for(j=sectionData->huffsection[i].sfbStart; jhuffsection[i].codeBook != CODE_BOOK_ZERO_NO */ + } /* section loop */ + + return(FDKgetValidBits(hBitStream)-dbgVal); + } /* if (hBitStream != NULL) */ + + return (0); +} + +/***************************************************************************** + + functionname:encodeMsInfo + description: encodes MS-Stereo Info + returns: the number of static bits + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodeMSInfo(INT sfbCnt, + INT grpSfb, + INT maxSfb, + INT msDigest, + INT *jsFlags, + HANDLE_FDK_BITSTREAM hBitStream) +{ + INT sfb, sfbOff, msBits = 0; + + if (hBitStream != NULL) + { + switch(msDigest) + { + case MS_NONE: + FDKwriteBits(hBitStream,SI_MS_MASK_NONE,2); + msBits += 2; + break; + + case MS_ALL: + FDKwriteBits(hBitStream,SI_MS_MASK_ALL,2); + msBits += 2; + break; + + case MS_SOME: + FDKwriteBits(hBitStream,SI_MS_MASK_SOME,2); + msBits += 2; + for(sfbOff = 0; sfbOff < sfbCnt; sfbOff+=grpSfb) + { + for(sfb=0; sfbnumOfFilters[i]!=0) { + tnsPresent=1; + break; + } + } + + if (tnsPresent==0) { + FDKwriteBits(hBitStream,0,1); + } else { + FDKwriteBits(hBitStream,1,1); + } + } + return (1); +} + +/***************************************************************************** + + functionname: FDKaacEnc_encodeTnsData + description: encode TNS data (filter order, coeffs, ..) + returns: the number of static bits + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodeTnsData(TNS_INFO *tnsInfo, + INT blockType, + HANDLE_FDK_BITSTREAM hBitStream) +{ + INT tnsBits = 0; + + if (tnsInfo!=NULL) { + + INT i,j,k; + INT tnsPresent = 0; + INT coefBits; + INT numOfWindows=(blockType==SHORT_WINDOW?TRANS_FAC:1); + + for (i=0; inumOfFilters[i]!=0) { + tnsPresent=1; + } + } + + if (hBitStream != NULL) + { + if (tnsPresent==1) { /* there is data to be written*/ + for (i=0; inumOfFilters[i],(blockType==SHORT_WINDOW?1:2)); + tnsBits += (blockType==SHORT_WINDOW?1:2); + if (tnsInfo->numOfFilters[i]) { + FDKwriteBits(hBitStream,(tnsInfo->coefRes[i]==4?1:0),1); + tnsBits += 1; + } + for (j=0; jnumOfFilters[i]; j++) { + FDKwriteBits(hBitStream,tnsInfo->length[i][j],(blockType==SHORT_WINDOW?4:6)); + tnsBits += (blockType==SHORT_WINDOW?4:6); + FDK_ASSERT(tnsInfo->order[i][j] <= 12); + FDKwriteBits(hBitStream,tnsInfo->order[i][j],(blockType==SHORT_WINDOW?3:5)); + tnsBits += (blockType==SHORT_WINDOW?3:5); + if (tnsInfo->order[i][j]){ + FDKwriteBits(hBitStream,tnsInfo->direction[i][j],1); + tnsBits +=1; /*direction*/ + if(tnsInfo->coefRes[i] == 4) { + coefBits = 3; + for(k=0; korder[i][j]; k++) { + if (tnsInfo->coef[i][j][k]> 3 || + tnsInfo->coef[i][j][k]< -4) { + coefBits = 4; + break; + } + } + } else { + coefBits = 2; + for(k=0; korder[i][j]; k++) { + if ( tnsInfo->coef[i][j][k]> 1 + || tnsInfo->coef[i][j][k]< -2) { + coefBits = 3; + break; + } + } + } + FDKwriteBits(hBitStream,-(coefBits - tnsInfo->coefRes[i]),1); /*coef_compres*/ + tnsBits +=1; /*coef_compression */ + for (k=0; korder[i][j]; k++ ) { + static const INT rmask[] = {0,1,3,7,15}; + FDKwriteBits(hBitStream,tnsInfo->coef[i][j][k] & rmask[coefBits],coefBits); + tnsBits += coefBits; + } + } + } + } + } + } + else { + if (tnsPresent != 0) { + for (i=0; inumOfFilters[i]) { + tnsBits += 1; + for (j=0; jnumOfFilters[i]; j++) { + tnsBits += (blockType==SHORT_WINDOW?4:6); + tnsBits += (blockType==SHORT_WINDOW?3:5); + if (tnsInfo->order[i][j]) { + tnsBits +=1; /*direction*/ + tnsBits +=1; /*coef_compression */ + if (tnsInfo->coefRes[i] == 4) { + coefBits=3; + for (k=0; korder[i][j]; k++) { + if (tnsInfo->coef[i][j][k]> 3 || tnsInfo->coef[i][j][k]< -4) { + coefBits = 4; + break; + } + } + } + else { + coefBits = 2; + for (k=0; korder[i][j]; k++) { + if (tnsInfo->coef[i][j][k]> 1 || tnsInfo->coef[i][j][k]< -2) { + coefBits = 3; + break; + } + } + } + for (k=0; korder[i][j]; k++) { + tnsBits += coefBits; + } + } + } + } + } + } + } + } /* (tnsInfo!=NULL) */ + + return (tnsBits); +} + +/***************************************************************************** + + functionname: FDKaacEnc_encodeGainControlData + description: unsupported + returns: none + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodeGainControlData(HANDLE_FDK_BITSTREAM hBitStream) +{ + if (hBitStream != NULL) { + FDKwriteBits(hBitStream,0,1); + } + return (1); +} + +/***************************************************************************** + + functionname: FDKaacEnc_encodePulseData + description: not supported yet (dummy) + returns: none + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_encodePulseData(HANDLE_FDK_BITSTREAM hBitStream) +{ + if (hBitStream != NULL) { + FDKwriteBits(hBitStream,0,1); + } + return (1); +} + + +/***************************************************************************** + + functionname: FDKaacEnc_writeExtensionPayload + description: write extension payload to bitstream + returns: number of written bits + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_writeExtensionPayload( HANDLE_FDK_BITSTREAM hBitStream, + EXT_PAYLOAD_TYPE extPayloadType, + const UCHAR *extPayloadData, + INT extPayloadBits + ) +{ + #define EXT_TYPE_BITS ( 4 ) + #define DATA_EL_VERSION_BITS ( 4 ) + #define FILL_NIBBLE_BITS ( 4 ) + + INT extBitsUsed = 0; + + if (extPayloadBits >= EXT_TYPE_BITS) + { + UCHAR fillByte = 0x00; /* for EXT_FIL and EXT_FILL_DATA */ + + if (hBitStream != NULL) { + FDKwriteBits(hBitStream, extPayloadType, EXT_TYPE_BITS); + } + extBitsUsed += EXT_TYPE_BITS; + + switch (extPayloadType) { + case EXT_DYNAMIC_RANGE: + /* case EXT_SAC_DATA: */ + case EXT_SBR_DATA: + case EXT_SBR_DATA_CRC: + if (hBitStream != NULL) { + int i, writeBits = extPayloadBits; + for (i=0; writeBits >= 8; i++) { + FDKwriteBits(hBitStream, extPayloadData[i], 8); + writeBits -= 8; + } + if (writeBits > 0) { + FDKwriteBits(hBitStream, extPayloadData[i]>>(8-writeBits), writeBits); + } + } + extBitsUsed += extPayloadBits; + break; + + case EXT_DATA_ELEMENT: + { + INT dataElementLength = (extPayloadBits+7)>>3; + INT cnt = dataElementLength; + int loopCounter = 1; + + while (dataElementLength >= 255) { + loopCounter++; + dataElementLength -= 255; + } + + if (hBitStream != NULL) { + int i; + FDKwriteBits(hBitStream, 0x00, DATA_EL_VERSION_BITS); /* data_element_version = ANC_DATA */ + + for (i=1; i= 8) { + FDKwriteBits(hBitStream, fillByte, 8); + writeBits -= 8; + } + } + extBitsUsed += FILL_NIBBLE_BITS + (extPayloadBits & ~0x7) - 8; + break; + } + } + + return (extBitsUsed); +} + + +/***************************************************************************** + + functionname: FDKaacEnc_writeDataStreamElement + description: write data stream elements like ancillary data ... + returns: the amount of used bits + input: + output: + +******************************************************************************/ +static INT FDKaacEnc_writeDataStreamElement( HANDLE_TRANSPORTENC hTpEnc, + INT elementInstanceTag, + INT dataPayloadBytes, + UCHAR *dataBuffer, + UINT alignAnchor ) +{ + #define DATA_BYTE_ALIGN_FLAG ( 0 ) + + #define EL_INSTANCE_TAG_BITS ( 4 ) + #define DATA_BYTE_ALIGN_FLAG_BITS ( 1 ) + #define DATA_LEN_COUNT_BITS ( 8 ) + #define DATA_LEN_ESC_COUNT_BITS ( 8 ) + + #define MAX_DATA_ALIGN_BITS ( 7 ) + #define MAX_DSE_DATA_BYTES ( 510 ) + + INT dseBitsUsed = 0; + + while (dataPayloadBytes > 0) + { + int esc_count = -1; + int cnt = 0; + INT crcReg = -1; + + dseBitsUsed += EL_ID_BITS + EL_INSTANCE_TAG_BITS + + DATA_BYTE_ALIGN_FLAG_BITS + DATA_LEN_COUNT_BITS; + + if (DATA_BYTE_ALIGN_FLAG) { + dseBitsUsed += MAX_DATA_ALIGN_BITS; + } + + cnt = fixMin(MAX_DSE_DATA_BYTES, dataPayloadBytes); + if ( cnt >= 255 ) { + esc_count = cnt - 255; + dseBitsUsed += DATA_LEN_ESC_COUNT_BITS; + } + + dataPayloadBytes -= cnt; + dseBitsUsed += cnt * 8; + + if (hTpEnc != NULL) { + HANDLE_FDK_BITSTREAM hBitStream = transportEnc_GetBitstream(hTpEnc); + int i; + + FDKwriteBits(hBitStream, ID_DSE, EL_ID_BITS); + + crcReg = transportEnc_CrcStartReg(hTpEnc, 0); + + FDKwriteBits(hBitStream, elementInstanceTag, EL_INSTANCE_TAG_BITS); + FDKwriteBits(hBitStream, DATA_BYTE_ALIGN_FLAG, DATA_BYTE_ALIGN_FLAG_BITS); + + /* write length field(s) */ + if ( esc_count >= 0 ) { + FDKwriteBits(hBitStream, 255, DATA_LEN_COUNT_BITS); + FDKwriteBits(hBitStream, esc_count, DATA_LEN_ESC_COUNT_BITS); + } else { + FDKwriteBits(hBitStream, cnt, DATA_LEN_COUNT_BITS); + } + + if (DATA_BYTE_ALIGN_FLAG) { + INT tmp = (INT)FDKgetValidBits(hBitStream); + FDKbyteAlign(hBitStream, alignAnchor); + /* count actual bits */ + dseBitsUsed += (INT)FDKgetValidBits(hBitStream) - tmp - MAX_DATA_ALIGN_BITS; + } + + /* write payload */ + for (i=0; inPayloadBits; + INT extBitsUsed = 0; + + if (hTpEnc != NULL) { + hBitStream = transportEnc_GetBitstream(hTpEnc); + } + + if (syntaxFlags & (AC_SCALABLE|AC_ER)) + { + if ( syntaxFlags & AC_DRM ) + { /* CAUTION: The caller has to assure that fill + data is written before the SBR payload. */ + UCHAR *extPayloadData = pExtension->pPayload; + + switch (pExtension->type) + { + case EXT_SBR_DATA: + case EXT_SBR_DATA_CRC: + /* SBR payload is written in reverse */ + if (hBitStream != NULL) { + int i, writeBits = payloadBits; + + FDKpushFor(hBitStream, payloadBits-1); /* Does a cache sync internally */ + + for (i=0; writeBits >= 8; i++) { + FDKwriteBitsBwd(hBitStream, extPayloadData[i], 8); + writeBits -= 8; + } + if (writeBits > 0) { + FDKwriteBitsBwd(hBitStream, extPayloadData[i]>>(8-writeBits), writeBits); + } + + FDKsyncCacheBwd (hBitStream); + FDKpushFor (hBitStream, payloadBits+1); + } + extBitsUsed += payloadBits; + break; + + case EXT_FILL_DATA: + case EXT_FIL: + default: + if (hBitStream != NULL) { + int writeBits = payloadBits; + while (writeBits >= 8) { + FDKwriteBits(hBitStream, 0x00, 8); + writeBits -= 8; + } + FDKwriteBits(hBitStream, 0x00, writeBits); + } + extBitsUsed += payloadBits; + break; + } + } + else { + if ( (syntaxFlags & AC_ELD) && ((pExtension->type==EXT_SBR_DATA) || (pExtension->type==EXT_SBR_DATA_CRC)) ) { + + if (hBitStream != NULL) { + int i, writeBits = payloadBits; + UCHAR *extPayloadData = pExtension->pPayload; + + for (i=0; writeBits >= 8; i++) { + FDKwriteBits(hBitStream, extPayloadData[i], 8); + writeBits -= 8; + } + if (writeBits > 0) { + FDKwriteBits(hBitStream, extPayloadData[i]>>(8-writeBits), writeBits); + } + } + extBitsUsed += payloadBits; + } + else + { + /* ER or scalable syntax -> write extension en bloc */ + extBitsUsed += FDKaacEnc_writeExtensionPayload( hBitStream, + pExtension->type, + pExtension->pPayload, + payloadBits ); + } + } + } + else { + /* We have normal GA bitstream payload (AOT 2,5,29) so pack + the data into a fill elements or DSEs */ + + if ( pExtension->type == EXT_DATA_ELEMENT ) + { + extBitsUsed += FDKaacEnc_writeDataStreamElement( hTpEnc, + elInstanceTag, + pExtension->nPayloadBits>>3, + pExtension->pPayload, + alignAnchor ); + } + else { + while (payloadBits >= (EL_ID_BITS + FILL_EL_COUNT_BITS)) { + INT cnt, esc_count=-1, alignBits=7; + + if ( (pExtension->type == EXT_FILL_DATA) || (pExtension->type == EXT_FIL) ) + { + payloadBits -= EL_ID_BITS + FILL_EL_COUNT_BITS; + if (payloadBits >= 15*8) { + payloadBits -= FILL_EL_ESC_COUNT_BITS; + esc_count = 0; /* write esc_count even if cnt becomes smaller 15 */ + } + alignBits = 0; + } + + cnt = fixMin(MAX_FILL_DATA_BYTES, (payloadBits+alignBits)>>3); + + if (cnt >= 15) { + esc_count = cnt - 15 + 1; + } + + if (hBitStream != NULL) { + /* write bitstream */ + FDKwriteBits(hBitStream, ID_FIL, EL_ID_BITS); + if (esc_count >= 0) { + FDKwriteBits(hBitStream, 15, FILL_EL_COUNT_BITS); + FDKwriteBits(hBitStream, esc_count, FILL_EL_ESC_COUNT_BITS); + } else { + FDKwriteBits(hBitStream, cnt, FILL_EL_COUNT_BITS); + } + } + + extBitsUsed += EL_ID_BITS + FILL_EL_COUNT_BITS + ((esc_count>=0) ? FILL_EL_ESC_COUNT_BITS : 0); + + cnt = fixMin(cnt*8, payloadBits); /* convert back to bits */ + extBitsUsed += FDKaacEnc_writeExtensionPayload( hBitStream, + pExtension->type, + pExtension->pPayload, + cnt ); + payloadBits -= cnt; + } + } + } + + return (extBitsUsed); +} + + +/***************************************************************************** + + functionname: FDKaacEnc_ByteAlignment + description: + returns: + input: + output: + +*****************************************************************************/ +static void FDKaacEnc_ByteAlignment(HANDLE_FDK_BITSTREAM hBitStream, int alignBits) +{ + FDKwriteBits(hBitStream, 0, alignBits); +} + +AAC_ENCODER_ERROR FDKaacEnc_ChannelElementWrite( HANDLE_TRANSPORTENC hTpEnc, + ELEMENT_INFO *pElInfo, + QC_OUT_CHANNEL *qcOutChannel[(2)], + PSY_OUT_ELEMENT *psyOutElement, + PSY_OUT_CHANNEL *psyOutChannel[(2)], + UINT syntaxFlags, + AUDIO_OBJECT_TYPE aot, + SCHAR epConfig, + INT *pBitDemand, + UCHAR minCnt + ) +{ + AAC_ENCODER_ERROR error = AAC_ENC_OK; + HANDLE_FDK_BITSTREAM hBitStream = NULL; + INT bitDemand = 0; + const element_list_t *list; + int i, ch, decision_bit; + INT crcReg1 = -1, crcReg2 = -1; + UCHAR numberOfChannels; + + if (hTpEnc != NULL) { + /* Get bitstream handle */ + hBitStream = transportEnc_GetBitstream(hTpEnc); + } + + if ( (pElInfo->elType==ID_SCE) || (pElInfo->elType==ID_LFE) ) { + numberOfChannels = 1; + } else { + numberOfChannels = 2; + } + + /* Get channel element sequence table */ + list = getBitstreamElementList(aot, epConfig, numberOfChannels, 0); + if (list == NULL) { + error = AAC_ENC_UNSUPPORTED_AOT; + goto bail; + } + + if (!(syntaxFlags & (AC_SCALABLE|AC_ER))) { + if (hBitStream != NULL) { + FDKwriteBits(hBitStream, pElInfo->elType, EL_ID_BITS); + } + bitDemand += EL_ID_BITS; + } + + /* Iterate through sequence table */ + i = 0; + ch = 0; + decision_bit = 0; + do { + /* some tmp values */ + SECTION_DATA *pChSectionData = NULL; + INT *pChScf = NULL; + UINT *pChMaxValueInSfb = NULL; + TNS_INFO *pTnsInfo = NULL; + INT chGlobalGain = 0; + INT chBlockType = 0; + INT chMaxSfbPerGrp = 0; + INT chSfbPerGrp = 0; + INT chSfbCnt = 0; + INT chFirstScf = 0; + + if (minCnt==0) { + if ( qcOutChannel!=NULL ) { + pChSectionData = &(qcOutChannel[ch]->sectionData); + pChScf = qcOutChannel[ch]->scf; + chGlobalGain = qcOutChannel[ch]->globalGain; + pChMaxValueInSfb = qcOutChannel[ch]->maxValueInSfb; + chBlockType = pChSectionData->blockType; + chMaxSfbPerGrp = pChSectionData->maxSfbPerGroup; + chSfbPerGrp = pChSectionData->sfbPerGroup; + chSfbCnt = pChSectionData->sfbCnt; + chFirstScf = pChScf[pChSectionData->firstScf]; + } + else { + /* get values from PSY */ + chSfbCnt = psyOutChannel[ch]->sfbCnt; + chSfbPerGrp = psyOutChannel[ch]->sfbPerGroup; + chMaxSfbPerGrp = psyOutChannel[ch]->maxSfbPerGroup; + } + pTnsInfo = &psyOutChannel[ch]->tnsInfo; + } /* minCnt==0 */ + + if ( qcOutChannel==NULL ) { + chBlockType = psyOutChannel[ch]->lastWindowSequence; + } + + switch (list->id[i]) + { + case element_instance_tag: + /* Write element instance tag */ + if (hBitStream != NULL) { + FDKwriteBits(hBitStream, pElInfo->instanceTag, 4); + } + bitDemand += 4; + break; + + case common_window: + /* Write common window flag */ + decision_bit = psyOutElement->commonWindow; + if (hBitStream != NULL) { + FDKwriteBits(hBitStream, psyOutElement->commonWindow, 1); + } + bitDemand += 1; + break; + + case ics_info: + /* Write individual channel info */ + bitDemand += FDKaacEnc_encodeIcsInfo( chBlockType, + psyOutChannel[ch]->windowShape, + psyOutChannel[ch]->groupingMask, + chMaxSfbPerGrp, + hBitStream, + syntaxFlags); + break; + + case ltp_data_present: + /* Write LTP data present flag */ + if (hBitStream != NULL) { + FDKwriteBits(hBitStream, 0, 1); + } + bitDemand += 1; + break; + + case ltp_data: + /* Predictor data not supported. + Nothing to do here. */ + break; + + case ms: + /* Write MS info */ + bitDemand += FDKaacEnc_encodeMSInfo( chSfbCnt, + chSfbPerGrp, + chMaxSfbPerGrp, + (minCnt==0) ? psyOutElement->toolsInfo.msDigest : MS_NONE, + psyOutElement->toolsInfo.msMask, + hBitStream); + break; + + case global_gain: + bitDemand += FDKaacEnc_encodeGlobalGain( chGlobalGain, + chFirstScf, + hBitStream, + psyOutChannel[ch]->mdctScale ); + break; + + case section_data: + { + INT siBits = FDKaacEnc_encodeSectionData(pChSectionData, hBitStream, (syntaxFlags & AC_ER_VCB11)?1:0); + if (hBitStream != NULL) { + if (siBits != qcOutChannel[ch]->sectionData.sideInfoBits) { + error = AAC_ENC_WRITE_SEC_ERROR; + } + } + bitDemand += siBits; + } + break; + + case scale_factor_data: + { + INT sfDataBits = FDKaacEnc_encodeScaleFactorData( pChMaxValueInSfb, + pChSectionData, + pChScf, + hBitStream, + psyOutChannel[ch]->noiseNrg, + psyOutChannel[ch]->isScale, + chGlobalGain ); + if ( (hBitStream != NULL) + && (sfDataBits != (qcOutChannel[ch]->sectionData.scalefacBits + qcOutChannel[ch]->sectionData.noiseNrgBits)) ) { + error = AAC_ENC_WRITE_SCAL_ERROR; + } + bitDemand += sfDataBits; + } + break; + + case esc2_rvlc: + if (syntaxFlags & AC_ER_RVLC) { + /* write RVLC data into bitstream (error sens. cat. 2) */ + error = AAC_ENC_UNSUPPORTED_AOT; + } + break; + + case pulse: + /* Write pulse data */ + bitDemand += FDKaacEnc_encodePulseData(hBitStream); + break; + + case tns_data_present: + /* Write TNS data present flag */ + bitDemand += FDKaacEnc_encodeTnsDataPresent(pTnsInfo, + chBlockType, + hBitStream); + break; + case tns_data: + /* Write TNS data */ + bitDemand += FDKaacEnc_encodeTnsData(pTnsInfo, + chBlockType, + hBitStream); + break; + + case gain_control_data: + /* Nothing to do here */ + break; + + case gain_control_data_present: + bitDemand += FDKaacEnc_encodeGainControlData(hBitStream); + break; + + + case esc1_hcr: + if (syntaxFlags & AC_ER_HCR) + { + error = AAC_ENC_UNKNOWN; + } + break; + + case spectral_data: + if (hBitStream != NULL) + { + INT spectralBits = 0; + + spectralBits = FDKaacEnc_encodeSpectralData( psyOutChannel[ch]->sfbOffsets, + pChSectionData, + qcOutChannel[ch]->quantSpec, + hBitStream ); + + if (spectralBits != qcOutChannel[ch]->sectionData.huffmanBits) { + return AAC_ENC_WRITE_SPEC_ERROR; + } + bitDemand += spectralBits; + } + break; + + /* Non data cases */ + case adtscrc_start_reg1: + if (hTpEnc != NULL) { + crcReg1 = transportEnc_CrcStartReg(hTpEnc, 192); + } + break; + case adtscrc_start_reg2: + if (hTpEnc != NULL) { + crcReg2 = transportEnc_CrcStartReg(hTpEnc, 128); + } + break; + case adtscrc_end_reg1: + case drmcrc_end_reg: + if (hTpEnc != NULL) { + transportEnc_CrcEndReg(hTpEnc, crcReg1); + } + break; + case adtscrc_end_reg2: + if (hTpEnc != NULL) { + transportEnc_CrcEndReg(hTpEnc, crcReg2); + } + break; + case drmcrc_start_reg: + if (hTpEnc != NULL) { + crcReg1 = transportEnc_CrcStartReg(hTpEnc, 0); + } + break; + case next_channel: + ch = (ch + 1) % numberOfChannels; + break; + case link_sequence: + list = list->next[decision_bit]; + i=-1; + break; + + default: + error = AAC_ENC_UNKNOWN; + break; + } + + if (error != AAC_ENC_OK) { + return error; + } + + i++; + + } while (list->id[i] != end_of_sequence); + +bail: + if (pBitDemand != NULL) { + *pBitDemand = bitDemand; + } + + return error; +} + + +//----------------------------------------------------------------------------------------------- + +AAC_ENCODER_ERROR FDKaacEnc_WriteBitstream(HANDLE_TRANSPORTENC hTpEnc, + CHANNEL_MAPPING *channelMapping, + QC_OUT *qcOut, + PSY_OUT* psyOut, + QC_STATE *qcKernel, + AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, + SCHAR epConfig + ) +{ + HANDLE_FDK_BITSTREAM hBs = transportEnc_GetBitstream(hTpEnc); + AAC_ENCODER_ERROR ErrorStatus = AAC_ENC_OK; + int i, n, doByteAlign = 1; + INT bitMarkUp; + INT frameBits; + /* Get first bit of raw data block. + In case of ADTS+PCE, AU would start at PCE. + This is okay because PCE assures alignment. */ + UINT alignAnchor = FDKgetValidBits(hBs); + + frameBits = bitMarkUp = alignAnchor; + + if ( syntaxFlags & AC_DAB ) + { /* Write PAD data as first element for DAB+ */ + for (n = 0; n < qcOut->nExtensions; n++) { + if ( (qcOut->extension[n].type == EXT_DATA_ELEMENT) + && (qcOut->extension[n].nPayloadBits > 0) + && (qcOut->extension[n].pPayload != NULL) ) + { + FDKaacEnc_writeExtensionData( hTpEnc, + &qcOut->extension[n], + 0, + alignAnchor, + syntaxFlags, + aot, + epConfig ); + + qcOut->extension[n].nPayloadBits = 0; + } + } + } + + /* Channel element loop */ + for (i=0; inElements; i++) { + + ELEMENT_INFO elInfo = channelMapping->elInfo[i]; + INT elementUsedBits = 0; + + switch (elInfo.elType) + { + case ID_SCE: /* single channel */ + case ID_CPE: /* channel pair */ + case ID_LFE: /* low freq effects channel */ + { + if ( AAC_ENC_OK != (ErrorStatus = FDKaacEnc_ChannelElementWrite( hTpEnc, + &elInfo, + qcOut->qcElement[i]->qcOutChannel, + psyOut->psyOutElement[i], + psyOut->psyOutElement[i]->psyOutChannel, + syntaxFlags, /* syntaxFlags (ER tools ...) */ + aot, /* aot: AOT_AAC_LC, AOT_SBR, AOT_PS */ + epConfig, /* epConfig -1, 0, 1 */ + NULL, + 0 )) ) + { + return ErrorStatus; + } + + if ( !(syntaxFlags & AC_ER) ) + { + /* Write associated extension payload */ + for (n = 0; n < qcOut->qcElement[i]->nExtensions; n++) { + FDKaacEnc_writeExtensionData( hTpEnc, + &qcOut->qcElement[i]->extension[n], + 0, + alignAnchor, + syntaxFlags, + aot, + epConfig ); + } + } + } + break; + + /* In FDK, DSE signalling explicit done in elDSE. See channel_map.cpp */ + default: + return AAC_ENC_INVALID_ELEMENTINFO_TYPE; + + } /* switch */ + + if(elInfo.elType != ID_DSE) { + elementUsedBits -= bitMarkUp; + bitMarkUp = FDKgetValidBits(hBs); + elementUsedBits += bitMarkUp; + frameBits += elementUsedBits; + } + + } /* for (i=0; inElements; i++) { + for (n = 0; n < qcOut->qcElement[i]->nExtensions; n++) { + + if ( (qcOut->qcElement[i]->extension[n].type==EXT_SBR_DATA) + || (qcOut->qcElement[i]->extension[n].type==EXT_SBR_DATA_CRC) ) + { + /* Write sbr extension payload */ + FDKaacEnc_writeExtensionData( hTpEnc, + &qcOut->qcElement[i]->extension[n], + 0, + alignAnchor, + syntaxFlags, + aot, + epConfig ); + + channelElementExtensionWritten[i][n] = 1; + } /* SBR */ + } /* n */ + } /* i */ + } /* AC_ELD */ + + for (i=0; inElements; i++) { + for (n = 0; n < qcOut->qcElement[i]->nExtensions; n++) { + + if (channelElementExtensionWritten[i][n]==0) + { + /* Write all ramaining extension payloads in element */ + FDKaacEnc_writeExtensionData( hTpEnc, + &qcOut->qcElement[i]->extension[n], + 0, + alignAnchor, + syntaxFlags, + aot, + epConfig ); + } + } /* n */ + } /* i */ + } /* if AC_ER */ + + /* Extend global extension payload table with fill bits */ + if ( syntaxFlags & AC_DRM ) + { + /* Exception for Drm */ + for (n = 0; n < qcOut->nExtensions; n++) { + if ( (qcOut->extension[n].type == EXT_SBR_DATA) + || (qcOut->extension[n].type == EXT_SBR_DATA_CRC) ) { + /* SBR data must be the last extension! */ + FDKmemcpy(&qcOut->extension[qcOut->nExtensions], &qcOut->extension[n], sizeof(QC_OUT_EXTENSION)); + break; + } + } + /* Do byte alignment after AAC (+ MPS) payload. + Assure that MPS has been written as channel assigned extension payload! */ + if (((FDKgetValidBits(hBs)-alignAnchor+(UINT)qcOut->totFillBits)&0x7)!=(UINT)qcOut->alignBits) { + return AAC_ENC_WRITTEN_BITS_ERROR; + } + FDKaacEnc_ByteAlignment(hBs, qcOut->alignBits); + doByteAlign = 0; + + } /* AC_DRM */ + + /* Add fill data / stuffing bits */ + n = qcOut->nExtensions; + qcOut->extension[n].type = EXT_FILL_DATA; + qcOut->extension[n].nPayloadBits = qcOut->totFillBits; + qcOut->nExtensions++; + + /* Write global extension payload and fill data */ + for (n = 0; (n < qcOut->nExtensions) && (n < (2+2)); n++) + { + FDKaacEnc_writeExtensionData( hTpEnc, + &qcOut->extension[n], + 0, + alignAnchor, + syntaxFlags, + aot, + epConfig ); + + /* For EXT_FIL or EXT_FILL_DATA we could do an additional sanity check here */ + } + + if (!(syntaxFlags & (AC_SCALABLE|AC_ER))) { + FDKwriteBits(hBs, ID_END, EL_ID_BITS); + } + + if (doByteAlign) { + /* Assure byte alignment*/ + if (((alignAnchor-FDKgetValidBits(hBs))&0x7)!=(UINT)qcOut->alignBits) { + return AAC_ENC_WRITTEN_BITS_ERROR; + } + + FDKaacEnc_ByteAlignment(hBs, qcOut->alignBits); + } + + frameBits -= bitMarkUp; + frameBits += FDKgetValidBits(hBs); + + transportEnc_EndAccessUnit(hTpEnc, &frameBits); + + if (frameBits != qcOut->totalBits + qcKernel->globHdrBits){ + return AAC_ENC_WRITTEN_BITS_ERROR; + } + + return ErrorStatus; +} + diff --git a/libAACenc/src/bitenc.h b/libAACenc/src/bitenc.h new file mode 100644 index 0000000..692a1a2 --- /dev/null +++ b/libAACenc/src/bitenc.h @@ -0,0 +1,120 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Werner + contents/description: Bitstream encoder + +******************************************************************************/ +#ifndef _BITENC_H +#define _BITENC_H + + +#include "qc_data.h" +#include "aacenc_tns.h" +#include "channel_map.h" +#include "interface.h" /* obsolete, when PSY_OUT is thrown out of the WritBS-call! */ +#include "FDK_audio.h" +#include "aacenc.h" + +#include "tpenc_lib.h" + +typedef enum{ + MAX_ENCODER_CHANNELS = 9, + MAX_BLOCK_TYPES = 4, + MAX_AAC_LAYERS = 9, + MAX_LAYERS = MAX_AAC_LAYERS , /* only one core layer if present */ + FIRST_LAY = 1 /* default layer number for AAC nonscalable */ +} _MAX_CONST; + +#define BUFFER_MX_HUFFCB_SIZE (32*sizeof(INT)) /* our FDK_bitbuffer needs size of power 2 */ + +#define EL_ID_BITS ( 3 ) + + +/** + * \brief Arbitrary order bitstream writer. This function can either assemble a bit stream + * and write into the bit buffer of hTpEnc or calculate the number of static bits (signal independent) + * TpEnc handle must be NULL in this case. Or also Calculate the minimum possible number of + * static bits which by disabling all tools e.g. MS, TNS and sbfCnt=0. The minCnt parameter + * has to be 1 in this latter case. + * \param hTpEnc Transport encoder handle. If NULL, the number of static bits will be returned into + * *pBitDemand. + * \param pElInfo + * \param qcOutChannel + * \param hReorderInfo + * \param psyOutElement + * \param psyOutChannel + * \param syntaxFlags Bit stream syntax flags as defined in FDK_audio.h (Audio Codec flags). + * \param aot + * \param epConfig + * \param pBitDemand Pointer to an int where the amount of bits is returned into. The returned value + * depends on if hTpEnc is NULL and minCnt. + * \param minCnt If non-zero the value returned into *pBitDemand is the absolute minimum required amount of + * static bits in order to write a valid bit stream. + * \return AAC_ENCODER_ERROR error code + */ +AAC_ENCODER_ERROR FDKaacEnc_ChannelElementWrite( HANDLE_TRANSPORTENC hTpEnc, + ELEMENT_INFO *pElInfo, + QC_OUT_CHANNEL *qcOutChannel[(2)], + PSY_OUT_ELEMENT *psyOutElement, + PSY_OUT_CHANNEL *psyOutChannel[(2)], + UINT syntaxFlags, + AUDIO_OBJECT_TYPE aot, + SCHAR epConfig, + INT *pBitDemand, + UCHAR minCnt + ); +/** + * \brief Write bit stream or account static bits + * \param hTpEnc transport encoder handle. If NULL, the function will + * not write any bit stream data but only count the amount + * of static (signal independent) bits + * \param channelMapping Channel mapping info + * \param qcOut + * \param psyOut + * \param qcKernel + * \param hBSE + * \param aot Audio Object Type being encoded + * \param syntaxFlags Flags indicating format specific detail + * \param epConfig Error protection config + */ +AAC_ENCODER_ERROR FDKaacEnc_WriteBitstream (HANDLE_TRANSPORTENC hTpEnc, + CHANNEL_MAPPING *channelMapping, + QC_OUT* qcOut, + PSY_OUT* psyOut, + QC_STATE* qcKernel, + AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, + SCHAR epConfig + ); + +INT FDKaacEnc_writeExtensionData( HANDLE_TRANSPORTENC hTpEnc, + QC_OUT_EXTENSION *pExtension, + INT elInstanceTag, + UINT alignAnchor, + UINT syntaxFlags, + AUDIO_OBJECT_TYPE aot, + SCHAR epConfig + ); + +#endif /* _BITENC_H */ diff --git a/libAACenc/src/block_switch.cpp b/libAACenc/src/block_switch.cpp new file mode 100644 index 0000000..e75536a --- /dev/null +++ b/libAACenc/src/block_switch.cpp @@ -0,0 +1,500 @@ +/***************************** MPEG-4 AAC Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Werner + Description: Block switching + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +/****************** Includes *****************************/ + +#include "block_switch.h" +#include "genericStds.h" + + +#define LOWOV_WINDOW _LOWOV_WINDOW + +/**************** internal function prototypes ***********/ + +static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT blSwWndIdx); + +static void FDKaacEnc_CalcWindowEnergy( BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl, + INT windowLen); + + +/****************** Constants *****************************/ +/* LONG START SHORT STOP LOWOV */ +static const INT blockType2windowShape[2][5] = { {SINE_WINDOW, KBD_WINDOW, WRONG_WINDOW, SINE_WINDOW, KBD_WINDOW}, /* LD */ + {KBD_WINDOW, SINE_WINDOW, SINE_WINDOW, KBD_WINDOW, WRONG_WINDOW} }; /* LC */ + +/* IIR high pass coeffs */ + +#ifndef SINETABLE_16BIT + +static const FIXP_DBL hiPassCoeff[BLOCK_SWITCHING_IIR_LEN]= +{ + FL2FXCONST_DBL(-0.5095),FL2FXCONST_DBL(0.7548) +}; + +static const FIXP_DBL accWindowNrgFac = FL2FXCONST_DBL(0.3f); /* factor for accumulating filtered window energies */ +static const FIXP_DBL oneMinusAccWindowNrgFac = FL2FXCONST_DBL(0.7f); +/* static const float attackRatio = 10.0; */ /* lower ratio limit for attacks */ +static const FIXP_DBL invAttackRatio = FL2FXCONST_DBL(0.1f); /* inverted lower ratio limit for attacks */ + +/* The next constants are scaled, because they are used for comparison with scaled values*/ +/* minimum energy for attacks */ +static const FIXP_DBL minAttackNrg = (FL2FXCONST_DBL(1e+6f*NORM_PCM_ENERGY)>>BLOCK_SWITCH_ENERGY_SHIFT); /* minimum energy for attacks */ + +#else + +static const FIXP_SGL hiPassCoeff[BLOCK_SWITCHING_IIR_LEN]= +{ + FL2FXCONST_SGL(-0.5095),FL2FXCONST_SGL(0.7548) +}; + +static const FIXP_DBL accWindowNrgFac = FL2FXCONST_DBL(0.3f); /* factor for accumulating filtered window energies */ +static const FIXP_SGL oneMinusAccWindowNrgFac = FL2FXCONST_SGL(0.7f); +/* static const float attackRatio = 10.0; */ /* lower ratio limit for attacks */ +static const FIXP_SGL invAttackRatio = FL2FXCONST_SGL(0.1f); /* inverted lower ratio limit for attacks */ +/* minimum energy for attacks */ +static const FIXP_DBL minAttackNrg = (FL2FXCONST_DBL(1e+6f*NORM_PCM_ENERGY)>>BLOCK_SWITCH_ENERGY_SHIFT); /* minimum energy for attacks */ + +#endif + +/**************** internal function prototypes ***********/ + +static INT FDKaacEnc_GetWindowIndex(INT blockSwWindowIndex); + +static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT shortWndIdx); + +static void FDKaacEnc_CalcWindowEnergy( BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl, + INT windowLen); + + + +/****************** Routines ****************************/ +void FDKaacEnc_InitBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, INT isLowDelay) +{ + /* note: the pointer to timeSignal can be zeroed here, because it is initialized for every call + to FDKaacEnc_BlockSwitching anew */ + FDKmemclear (blockSwitchingControl, sizeof(BLOCK_SWITCHING_CONTROL)); + + if (isLowDelay) + { + blockSwitchingControl->nBlockSwitchWindows = 4; + blockSwitchingControl->allowShortFrames = 0; + blockSwitchingControl->allowLookAhead = 0; + } + else + { + blockSwitchingControl->nBlockSwitchWindows = 8; + blockSwitchingControl->allowShortFrames = 1; + blockSwitchingControl->allowLookAhead = 1; + } + + blockSwitchingControl->noOfGroups = MAX_NO_OF_GROUPS; + + /* Initialize startvalue for blocktype */ + blockSwitchingControl->lastWindowSequence = LONG_WINDOW; + blockSwitchingControl->windowShape = blockType2windowShape[blockSwitchingControl->allowShortFrames][blockSwitchingControl->lastWindowSequence]; + +} + +static const INT suggestedGroupingTable[TRANS_FAC][MAX_NO_OF_GROUPS] = +{ + /* Attack in Window 0 */ {1, 3, 3, 1}, + /* Attack in Window 1 */ {1, 1, 3, 3}, + /* Attack in Window 2 */ {2, 1, 3, 2}, + /* Attack in Window 3 */ {3, 1, 3, 1}, + /* Attack in Window 4 */ {3, 1, 1, 3}, + /* Attack in Window 5 */ {3, 2, 1, 2}, + /* Attack in Window 6 */ {3, 3, 1, 1}, + /* Attack in Window 7 */ {3, 3, 1, 1} +}; + +/* change block type depending on current blocktype and whether there's an attack */ +/* assume no look-ahead */ +static const INT chgWndSq[2][N_BLOCKTYPES] = +{ + /* LONG WINDOW START_WINDOW SHORT_WINDOW STOP_WINDOW, LOWOV_WINDOW, WRONG_WINDOW */ + /*no attack*/ {LONG_WINDOW, STOP_WINDOW, WRONG_WINDOW, LONG_WINDOW, STOP_WINDOW , WRONG_WINDOW }, + /*attack */ {START_WINDOW, LOWOV_WINDOW, WRONG_WINDOW, START_WINDOW, LOWOV_WINDOW, WRONG_WINDOW } +}; + +/* change block type depending on current blocktype and whether there's an attack */ +/* assume look-ahead */ +static const INT chgWndSqLkAhd[2][2][N_BLOCKTYPES] = +{ + /*attack LONG WINDOW START_WINDOW SHORT_WINDOW STOP_WINDOW LOWOV_WINDOW, WRONG_WINDOW */ /* last attack */ + /*no attack*/ { {LONG_WINDOW, SHORT_WINDOW, STOP_WINDOW, LONG_WINDOW, WRONG_WINDOW, WRONG_WINDOW}, /* no attack */ + /*attack */ {START_WINDOW, SHORT_WINDOW, SHORT_WINDOW, START_WINDOW, WRONG_WINDOW, WRONG_WINDOW} }, /* no attack */ + /*no attack*/ { {LONG_WINDOW, SHORT_WINDOW, SHORT_WINDOW, LONG_WINDOW, WRONG_WINDOW, WRONG_WINDOW}, /* attack */ + /*attack */ {START_WINDOW, SHORT_WINDOW, SHORT_WINDOW, START_WINDOW, WRONG_WINDOW, WRONG_WINDOW} } /* attack */ +}; + +int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, const INT granuleLength, const int isLFE) +{ + UINT i; + FIXP_DBL enM1, enMax; + + UINT nBlockSwitchWindows = blockSwitchingControl->nBlockSwitchWindows; + + /* for LFE : only LONG window allowed */ + if (isLFE) { + + /* case LFE: */ + /* only long blocks, always use sine windows (MPEG2 AAC, MPEG4 AAC) */ + blockSwitchingControl->lastWindowSequence = LONG_WINDOW; + blockSwitchingControl->windowShape = SINE_WINDOW; + blockSwitchingControl->noOfGroups = 1; + blockSwitchingControl->groupLen[0] = 1; + + return(0); + }; + + /* Save current attack index as last attack index */ + blockSwitchingControl->lastattack = blockSwitchingControl->attack; + blockSwitchingControl->lastAttackIndex = blockSwitchingControl->attackIndex; + + /* Save current window energy as last window energy */ + FDKmemcpy(blockSwitchingControl->windowNrg[0], blockSwitchingControl->windowNrg[1], sizeof(blockSwitchingControl->windowNrg[0])); + FDKmemcpy(blockSwitchingControl->windowNrgF[0], blockSwitchingControl->windowNrgF[1], sizeof(blockSwitchingControl->windowNrgF[0])); + + if (blockSwitchingControl->allowShortFrames) + { + /* Calculate suggested grouping info for the last frame */ + + /* Reset grouping info */ + FDKmemclear (blockSwitchingControl->groupLen, sizeof(blockSwitchingControl->groupLen)); + + /* Set grouping info */ + blockSwitchingControl->noOfGroups = MAX_NO_OF_GROUPS; + + FDKmemcpy(blockSwitchingControl->groupLen, suggestedGroupingTable[blockSwitchingControl->lastAttackIndex], sizeof(blockSwitchingControl->groupLen)); + + if (blockSwitchingControl->attack == TRUE) + blockSwitchingControl->maxWindowNrg = FDKaacEnc_GetWindowEnergy(blockSwitchingControl->windowNrg[0], blockSwitchingControl->lastAttackIndex); + else + blockSwitchingControl->maxWindowNrg = FL2FXCONST_DBL(0.0); + + } + + + /* Calculate unfiltered and filtered energies in subwindows and combine to segments */ + FDKaacEnc_CalcWindowEnergy(blockSwitchingControl, granuleLength>>(nBlockSwitchWindows==4? 2:3 )); + + /* now calculate if there is an attack */ + + /* reset attack */ + blockSwitchingControl->attack = FALSE; + + /* look for attack */ + enMax = FL2FXCONST_DBL(0.0f); + enM1 = blockSwitchingControl->windowNrgF[0][nBlockSwitchWindows-1]; + + for (i=0; iaccWindowNrg); + blockSwitchingControl->accWindowNrg = fMultAdd(tmp, accWindowNrgFac, enM1) ; + + if (fMult(blockSwitchingControl->windowNrgF[1][i],invAttackRatio) > blockSwitchingControl->accWindowNrg ) { + blockSwitchingControl->attack = TRUE; + blockSwitchingControl->attackIndex = i; + } + enM1 = blockSwitchingControl->windowNrgF[1][i]; + enMax = fixMax(enMax, enM1); + } + + + if (enMax < minAttackNrg) blockSwitchingControl->attack = FALSE; + + /* Check if attack spreads over frame border */ + if((blockSwitchingControl->attack == FALSE) && (blockSwitchingControl->lastattack == TRUE)) { + /* if attack is in last window repeat SHORT_WINDOW */ + if ( ((blockSwitchingControl->windowNrgF[0][nBlockSwitchWindows-1]>>4) > fMult((FIXP_DBL)(10<<(DFRACT_BITS-1-4)), blockSwitchingControl->windowNrgF[1][1])) + && (blockSwitchingControl->lastAttackIndex == (INT)nBlockSwitchWindows-1) + ) + { + blockSwitchingControl->attack = TRUE; + blockSwitchingControl->attackIndex = 0; + } + } + + + if(blockSwitchingControl->allowLookAhead) + { + + + blockSwitchingControl->lastWindowSequence = + chgWndSqLkAhd[blockSwitchingControl->lastattack][blockSwitchingControl->attack][blockSwitchingControl->lastWindowSequence]; + } + else + { + /* Low Delay */ + blockSwitchingControl->lastWindowSequence = + chgWndSq[blockSwitchingControl->attack][blockSwitchingControl->lastWindowSequence]; + } + + + /* update window shape */ + blockSwitchingControl->windowShape = blockType2windowShape[blockSwitchingControl->allowShortFrames][blockSwitchingControl->lastWindowSequence]; + + return(0); +} + + + +static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT blSwWndIdx) +{ +/* For coherency, change FDKaacEnc_GetWindowEnergy() to calcluate the energy for a block switching analysis windows, + not for a short block. The same is done FDKaacEnc_CalcWindowEnergy(). The result of FDKaacEnc_GetWindowEnergy() + is used for a comparision of the max energy of left/right channel. */ + + return in[blSwWndIdx]; + +} + + +static void FDKaacEnc_CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl, INT windowLen) +{ + INT i; + UINT w; + + FIXP_SGL hiPassCoeff0 = hiPassCoeff[0]; + FIXP_SGL hiPassCoeff1 = hiPassCoeff[1]; + + INT_PCM *timeSignal = blockSwitchingControl->timeSignal; + + /* sum up scalarproduct of timesignal as windowed Energies */ + for (w=0; w < blockSwitchingControl->nBlockSwitchWindows; w++) { + + FIXP_DBL temp_windowNrg = FL2FXCONST_DBL(0.0f); + FIXP_DBL temp_windowNrgF = FL2FXCONST_DBL(0.0f); + FIXP_DBL temp_iirState0 = blockSwitchingControl->iirStates[0]; + FIXP_DBL temp_iirState1 = blockSwitchingControl->iirStates[1]; + + /* windowNrg = sum(timesample^2) */ + for(i=0;i> 1; +#else + tempUnfiltered = (FIXP_DBL) *timeSignal++ << (DFRACT_BITS-SAMPLE_BITS-1); +#endif + t1 = fMultDiv2(hiPassCoeff1, tempUnfiltered-temp_iirState0); + t2 = fMultDiv2(hiPassCoeff0, temp_iirState1); + tempFiltred = (t1 - t2) << 1; + + temp_iirState0 = tempUnfiltered; + temp_iirState1 = tempFiltred; + + /* subtract 2 from overallscaling (BLOCK_SWITCH_ENERGY_SHIFT) + * because tempUnfiltered was already scaled with 1 (is 2 after squaring) + * subtract 1 from overallscaling (BLOCK_SWITCH_ENERGY_SHIFT) + * because of fMultDiv2 is doing a scaling by one */ + temp_windowNrg += fPow2Div2(tempUnfiltered) >> (BLOCK_SWITCH_ENERGY_SHIFT - 1 - 2); + temp_windowNrgF += fPow2Div2(tempFiltred) >> (BLOCK_SWITCH_ENERGY_SHIFT - 1 - 2); + } + blockSwitchingControl->windowNrg[1][w] = temp_windowNrg; + blockSwitchingControl->windowNrgF[1][w] = temp_windowNrgF; + blockSwitchingControl->iirStates[0] = temp_iirState0; + blockSwitchingControl->iirStates[1] = temp_iirState1; + } +} + + +static const UCHAR synchronizedBlockTypeTable[5][5] = +{ + /* LONG_WINDOW START_WINDOW SHORT_WINDOW STOP_WINDOW LOWOV_WINDOW*/ + /* LONG_WINDOW */ {LONG_WINDOW, START_WINDOW, SHORT_WINDOW, STOP_WINDOW, LOWOV_WINDOW}, + /* START_WINDOW */ {START_WINDOW, START_WINDOW, SHORT_WINDOW, SHORT_WINDOW, LOWOV_WINDOW}, + /* SHORT_WINDOW */ {SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW, WRONG_WINDOW}, + /* STOP_WINDOW */ {STOP_WINDOW, SHORT_WINDOW, SHORT_WINDOW, STOP_WINDOW, LOWOV_WINDOW}, + /* LOWOV_WINDOW */ {LOWOV_WINDOW, LOWOV_WINDOW, WRONG_WINDOW, LOWOV_WINDOW, LOWOV_WINDOW}, +}; + +int FDKaacEnc_SyncBlockSwitching ( + BLOCK_SWITCHING_CONTROL *blockSwitchingControlLeft, + BLOCK_SWITCHING_CONTROL *blockSwitchingControlRight, + const INT nChannels, + const INT commonWindow ) +{ + UCHAR patchType = LONG_WINDOW; + + if( nChannels == 2 && commonWindow == TRUE) + { + /* could be better with a channel loop (need a handle to psy_data) */ + /* get suggested Block Types and synchronize */ + patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlLeft->lastWindowSequence]; + patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlRight->lastWindowSequence]; + + /* sanity check (no change from low overlap window to short winow and vice versa) */ + if (patchType == WRONG_WINDOW) + return -1; /* mixed up AAC-LC and AAC-LD */ + + /* Set synchronized Blocktype */ + blockSwitchingControlLeft->lastWindowSequence = patchType; + blockSwitchingControlRight->lastWindowSequence = patchType; + + /* update window shape */ + blockSwitchingControlLeft->windowShape = blockType2windowShape[blockSwitchingControlLeft->allowShortFrames][blockSwitchingControlLeft->lastWindowSequence]; + blockSwitchingControlRight->windowShape = blockType2windowShape[blockSwitchingControlLeft->allowShortFrames][blockSwitchingControlRight->lastWindowSequence]; + } + + if (blockSwitchingControlLeft->allowShortFrames) + { + int i; + + if( nChannels == 2 ) + { + if (commonWindow == TRUE) + { + /* Synchronize grouping info */ + int windowSequenceLeftOld = blockSwitchingControlLeft->lastWindowSequence; + int windowSequenceRightOld = blockSwitchingControlRight->lastWindowSequence; + + /* Long Blocks */ + if(patchType != SHORT_WINDOW) { + /* Set grouping info */ + blockSwitchingControlLeft->noOfGroups = 1; + blockSwitchingControlRight->noOfGroups = 1; + blockSwitchingControlLeft->groupLen[0] = 1; + blockSwitchingControlRight->groupLen[0] = 1; + + for (i = 1; i < MAX_NO_OF_GROUPS; i++) + { + blockSwitchingControlLeft->groupLen[i] = 0; + blockSwitchingControlRight->groupLen[i] = 0; + } + } + + /* Short Blocks */ + else { + /* in case all two channels were detected as short-blocks before syncing, use the grouping of channel with higher maxWindowNrg */ + if( (windowSequenceLeftOld == SHORT_WINDOW) && + (windowSequenceRightOld == SHORT_WINDOW) ) + { + if(blockSwitchingControlLeft->maxWindowNrg > blockSwitchingControlRight->maxWindowNrg) { + /* Left Channel wins */ + blockSwitchingControlRight->noOfGroups = blockSwitchingControlLeft->noOfGroups; + for (i = 0; i < MAX_NO_OF_GROUPS; i++){ + blockSwitchingControlRight->groupLen[i] = blockSwitchingControlLeft->groupLen[i]; + } + } + else { + /* Right Channel wins */ + blockSwitchingControlLeft->noOfGroups = blockSwitchingControlRight->noOfGroups; + for (i = 0; i < MAX_NO_OF_GROUPS; i++){ + blockSwitchingControlLeft->groupLen[i] = blockSwitchingControlRight->groupLen[i]; + } + } + } + else if ( (windowSequenceLeftOld == SHORT_WINDOW) && + (windowSequenceRightOld != SHORT_WINDOW) ) + { + /* else use grouping of short-block channel */ + blockSwitchingControlRight->noOfGroups = blockSwitchingControlLeft->noOfGroups; + for (i = 0; i < MAX_NO_OF_GROUPS; i++){ + blockSwitchingControlRight->groupLen[i] = blockSwitchingControlLeft->groupLen[i]; + } + } + else if ( (windowSequenceRightOld == SHORT_WINDOW) && + (windowSequenceLeftOld != SHORT_WINDOW) ) + { + blockSwitchingControlLeft->noOfGroups = blockSwitchingControlRight->noOfGroups; + for (i = 0; i < MAX_NO_OF_GROUPS; i++){ + blockSwitchingControlLeft->groupLen[i] = blockSwitchingControlRight->groupLen[i]; + } + } else { + /* syncing a start and stop window ... */ + /* use a standard grouping, + best grouping still to be determined! rtb 2006 06 07 */ + blockSwitchingControlLeft->noOfGroups = blockSwitchingControlRight->noOfGroups = 2; + blockSwitchingControlLeft->groupLen[0] = blockSwitchingControlRight->groupLen[0] = 4; + blockSwitchingControlLeft->groupLen[1] = blockSwitchingControlRight->groupLen[1] = 4; + } + } /* Short Blocks */ + } + else { + /* stereo, no common window */ + if (blockSwitchingControlLeft->lastWindowSequence!=SHORT_WINDOW){ + blockSwitchingControlLeft->noOfGroups = 1; + blockSwitchingControlLeft->groupLen[0] = 1; + for (i = 1; i < MAX_NO_OF_GROUPS; i++) + { + blockSwitchingControlLeft->groupLen[i] = 0; + } + } + if (blockSwitchingControlRight->lastWindowSequence!=SHORT_WINDOW){ + blockSwitchingControlRight->noOfGroups = 1; + blockSwitchingControlRight->groupLen[0] = 1; + for (i = 1; i < MAX_NO_OF_GROUPS; i++) + { + blockSwitchingControlRight->groupLen[i] = 0; + } + } + } /* common window */ + } else { + /* Mono */ + if (blockSwitchingControlLeft->lastWindowSequence!=SHORT_WINDOW){ + blockSwitchingControlLeft->noOfGroups = 1; + blockSwitchingControlLeft->groupLen[0] = 1; + + for (i = 1; i < MAX_NO_OF_GROUPS; i++) + { + blockSwitchingControlLeft->groupLen[i] = 0; + } + } + } + } /* allowShortFrames */ + +#ifdef BLOCK_SWITCH_DEBUG_INFO + FDKprintf("l:%d\tr:%d\n", blockSwitchingControlLeft->lastWindowSequence, blockSwitchingControlRight->lastWindowSequence); +#endif + + /* Translate LOWOV_WINDOW block type to a meaningful window shape. */ + if ( ! blockSwitchingControlLeft->allowShortFrames ) { + if ( blockSwitchingControlLeft->lastWindowSequence != LONG_WINDOW + && blockSwitchingControlLeft->lastWindowSequence != STOP_WINDOW ) + { + blockSwitchingControlLeft->lastWindowSequence = LONG_WINDOW; + blockSwitchingControlLeft->windowShape = LOL_WINDOW; + } + } + if (nChannels == 2) { + if ( ! blockSwitchingControlRight->allowShortFrames ) { + if ( blockSwitchingControlRight->lastWindowSequence != LONG_WINDOW + && blockSwitchingControlRight->lastWindowSequence != STOP_WINDOW ) + { + blockSwitchingControlRight->lastWindowSequence = LONG_WINDOW; + blockSwitchingControlRight->windowShape = LOL_WINDOW; + } + } + } + + return 0; +} + + diff --git a/libAACenc/src/block_switch.h b/libAACenc/src/block_switch.h new file mode 100644 index 0000000..f9eaa81 --- /dev/null +++ b/libAACenc/src/block_switch.h @@ -0,0 +1,85 @@ +/***************************** MPEG-4 AAC Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Werner + Description: Block switching + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef _BLOCK_SWITCH_H +#define _BLOCK_SWITCH_H + +#include "common_fix.h" + +#include "psy_const.h" + +/****************** Defines ******************************/ + #define BLOCK_SWITCH_WINDOWS 8 /* number of windows for energy calculation */ + +#define BLOCK_SWITCHING_IIR_LEN 2 /* Length of HighPass-IIR-Filter for Attack-Detection */ +#define BLOCK_SWITCH_ENERGY_SHIFT 7 /* should be logDualis(BLOCK_SWITCH_WINDOW_LEN) to avoid overflow in windowNrgs. */ + +#define LAST_WINDOW 0 +#define THIS_WINDOW 1 + + +/****************** Structures ***************************/ +typedef struct{ + INT_PCM *timeSignal; + INT lastWindowSequence; + INT windowShape; + INT lastWindowShape; + UINT nBlockSwitchWindows; /* number of windows for energy calculation */ + INT attack; + INT lastattack; + INT attackIndex; + INT lastAttackIndex; + INT allowShortFrames; /* for Low Delay, don't allow short frames */ + INT allowLookAhead; /* for Low Delay, don't do look-ahead */ + INT noOfGroups; + INT groupLen[MAX_NO_OF_GROUPS]; + FIXP_DBL maxWindowNrg; /* max energy in subwindows */ + + FIXP_DBL windowNrg[2][BLOCK_SWITCH_WINDOWS]; /* time signal energy in Subwindows (last and current) */ + FIXP_DBL windowNrgF[2][BLOCK_SWITCH_WINDOWS]; /* filtered time signal energy in segments (last and current) */ + FIXP_DBL accWindowNrg; /* recursively accumulated windowNrgF */ + + FIXP_DBL iirStates[BLOCK_SWITCHING_IIR_LEN]; /* filter delay-line */ + +} BLOCK_SWITCHING_CONTROL; + + + + + +void FDKaacEnc_InitBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, INT isLowDelay); + +int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, const INT granuleLength, const int isLFE); + +int FDKaacEnc_SyncBlockSwitching( + BLOCK_SWITCHING_CONTROL *blockSwitchingControlLeft, + BLOCK_SWITCHING_CONTROL *blockSwitchingControlRight, + const INT noOfChannels, + const INT commonWindow); + +#endif /* #ifndef _BLOCK_SWITCH_H */ diff --git a/libAACenc/src/channel_map.cpp b/libAACenc/src/channel_map.cpp new file mode 100644 index 0000000..0f1cb4f --- /dev/null +++ b/libAACenc/src/channel_map.cpp @@ -0,0 +1,499 @@ +/************************* Fast MPEG AAC Audio Encoder ********************** + + (C) Copyright Fraunhofer IIS (2000) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: A. Groeschel + contents/description: channel mapping functionality + +******************************************************************************/ + +#include "channel_map.h" +#include "bitenc.h" +#include "psy_const.h" +#include "qc_data.h" +#include "aacEnc_ram.h" + + +/* channel_assignment treats the relationship of Input file channels + to the encoder channels. + This is necessary because the usual order in RIFF files (.wav) + is different from the elements order in the coder given + by Table 8.1 (implicit speaker mapping) of the AAC standard. + + In mono and stereo case, this is trivial. + In mc case, it looks like this: + + Channel Input file coder chan +5ch: + front center 2 0 (SCE channel) + left center 0 1 (1st of 1st CPE) + right center 1 2 (2nd of 1st CPE) + left surround 3 3 (1st of 2nd CPE) + right surround 4 4 (2nd of 2nd CPE) + +5.1ch: + front center 2 0 (SCE channel) + left center 0 1 (1st of 1st CPE) + right center 1 2 (2nd of 1st CPE) + left surround 4 3 (1st of 2nd CPE) + right surround 5 4 (2nd of 2nd CPE) + LFE 3 5 (LFE) +*/ + +typedef struct { + + CHANNEL_MODE encoderMode; + INT channel_assignment[/*(6)*/12]; + +} CHANNEL_ASSIGNMENT_INFO_TAB; + + +static const CHANNEL_ASSIGNMENT_INFO_TAB assignmentInfoTabMpeg[] = +{ + { MODE_INVALID, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* invalid */ + { MODE_1, { 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* mono */ + { MODE_2, { 0, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* stereo */ + { MODE_1_2, { 0, 1, 2,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* 3ch */ + { MODE_1_2_1, { 0, 1, 2, 3,-1,-1,-1,-1,-1,-1,-1,-1} }, /* 4ch */ + { MODE_1_2_2, { 0, 1, 2, 3, 4,-1,-1,-1,-1,-1,-1,-1} }, /* 5ch */ + { MODE_1_2_2_1, { 0, 1, 2, 3, 4, 5,-1,-1,-1,-1,-1,-1} }, /* 5.1ch */ + { MODE_1_2_2_2_1, { 0, 1, 2, 3, 4, 5, 6, 7,-1,-1,-1,-1} }, /* 7.1ch */ +}; + +static const CHANNEL_ASSIGNMENT_INFO_TAB assignmentInfoTabWav[] = +{ + { MODE_INVALID, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* invalid */ + { MODE_1, { 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* mono */ + { MODE_2, { 0, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* stereo */ + { MODE_1_2, { 2, 0, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* 3ch */ + { MODE_1_2_1, { 2, 0, 1, 3,-1,-1,-1,-1,-1,-1,-1,-1} }, /* 4ch */ + { MODE_1_2_2, { 2, 0, 1, 3, 4,-1,-1,-1,-1,-1,-1,-1} }, /* 5ch */ + { MODE_1_2_2_1, { 2, 0, 1, 4, 5, 3,-1,-1,-1,-1,-1,-1} }, /* 5.1ch */ + { MODE_1_2_2_2_1, { 2, 0, 1, 6, 7, 4, 5, 3,-1,-1,-1,-1} }, /* 7.1ch */ +}; + +/* Channel mode configuration tab provides, + corresponding number of channels and elements +*/ +static const CHANNEL_MODE_CONFIG_TAB channelModeConfig[] = +{ + { MODE_1, 1, 1, 1 }, /* SCE */ + { MODE_2, 2, 2, 1 }, /* CPE */ + { MODE_1_2, 3, 3, 2 }, /* SCE,CPE */ + { MODE_1_2_1, 4, 4, 3 }, /* SCE,CPE,SCE */ + { MODE_1_2_2, 5, 5, 3 }, /* SCE,CPE,CPE */ + { MODE_1_2_2_1, 6, 5, 4 }, /* SCE,CPE,CPE,LFE */ + { MODE_1_2_2_2_1, 8, 7, 5 }, /* SCE,CPE,CPE,CPE,LFE */ +}; + +#define MAX_MODES (sizeof(assignmentInfoTabWav)/sizeof(CHANNEL_ASSIGNMENT_INFO_TAB)) + +const INT* FDKaacEnc_getChannelAssignment(CHANNEL_MODE encMode, CHANNEL_ORDER co) +{ + const CHANNEL_ASSIGNMENT_INFO_TAB *pTab; + int i; + + if (co == CH_ORDER_MPEG) + pTab = assignmentInfoTabMpeg; + else + pTab = assignmentInfoTabWav; + + for(i=MAX_MODES-1; i>0; i--) { + if (encMode== pTab[i].encoderMode) { + break; + } + } + return (pTab[i].channel_assignment); +} + +AAC_ENCODER_ERROR FDKaacEnc_DetermineEncoderMode(CHANNEL_MODE* mode, INT nChannels) +{ + INT i; + CHANNEL_MODE encMode = MODE_INVALID; + + if (*mode==MODE_UNKNOWN) { + for (i=0; i<(INT)sizeof(channelModeConfig)/(INT)sizeof(CHANNEL_MODE_CONFIG_TAB); i++) { + if (channelModeConfig[i].nChannels==nChannels) { + encMode = channelModeConfig[i].encMode; + break; + } + } + *mode = encMode; + } + else { + /* check if valid channel configuration */ + if (FDKaacEnc_GetChannelModeConfiguration(*mode)->nChannels==nChannels) { + encMode = *mode; + } + } + + if (encMode==MODE_INVALID) { + return AAC_ENC_UNSUPPORTED_CHANNELCONFIG; + } + + return AAC_ENC_OK; +} + +static INT FDKaacEnc_initElement (ELEMENT_INFO* elInfo, MP4_ELEMENT_ID elType, INT* cnt, CHANNEL_MODE mode, CHANNEL_ORDER co, INT* it_cnt, const FIXP_DBL relBits) { + + INT error=0; + INT counter =*cnt; + + const INT *assign = FDKaacEnc_getChannelAssignment(mode, co); + + elInfo->elType=elType; + elInfo->relativeBits = relBits; + + switch(elInfo->elType) { + case ID_SCE: case ID_LFE: case ID_CCE: + elInfo->nChannelsInEl=1; + elInfo->ChannelIndex[0]=assign[counter++]; + elInfo->instanceTag=it_cnt[elType]++; + + break; + case ID_CPE: + elInfo->nChannelsInEl=2; + elInfo->ChannelIndex[0]=assign[counter++]; + elInfo->ChannelIndex[1]=assign[counter++]; + elInfo->instanceTag=it_cnt[elType]++; + break; + case ID_DSE: + elInfo->nChannelsInEl=0; + elInfo->ChannelIndex[0]=0; + elInfo->ChannelIndex[1]=0; + elInfo->instanceTag=it_cnt[elType]++; + break; + default: error=1; + }; + *cnt = counter; + return error; + +} + +AAC_ENCODER_ERROR FDKaacEnc_InitChannelMapping(CHANNEL_MODE mode, CHANNEL_ORDER co, CHANNEL_MAPPING* cm) +{ + INT count=0; /* count through coder channels */ + INT it_cnt[ID_END+1]; + INT i; + + for (i=0; iencMode = channelModeConfig[i].encMode; + cm->nChannels = channelModeConfig[i].nChannels; + cm->nChannelsEff = channelModeConfig[i].nChannelsEff; + cm->nElements = channelModeConfig[i].nElements; + + break; + } + } + + /* init element info struct */ + switch(mode) { + case MODE_1: + /* (mono) sce */ + FDKaacEnc_initElement(&cm->elInfo[0], ID_SCE, &count, mode, co, it_cnt, (FIXP_DBL)MAXVAL_DBL); + break; + case MODE_2: + /* (stereo) cpe */ + FDKaacEnc_initElement(&cm->elInfo[0], ID_CPE, &count, mode, co, it_cnt, (FIXP_DBL)MAXVAL_DBL); + break; + + case MODE_1_2: + /* sce + cpe */ + FDKaacEnc_initElement(&cm->elInfo[0], ID_SCE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.4f)); + FDKaacEnc_initElement(&cm->elInfo[1], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.6f)); + break; + + case MODE_1_2_1: + /* sce + cpe + sce */ + FDKaacEnc_initElement(&cm->elInfo[0], ID_SCE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.3f)); + FDKaacEnc_initElement(&cm->elInfo[1], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.4f)); + FDKaacEnc_initElement(&cm->elInfo[2], ID_SCE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.3f)); + break; + + case MODE_1_2_2: + /* sce + cpe + cpe */ + FDKaacEnc_initElement(&cm->elInfo[0], ID_SCE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.26f)); + FDKaacEnc_initElement(&cm->elInfo[1], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.37f)); + FDKaacEnc_initElement(&cm->elInfo[2], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.37f)); + break; + + case MODE_1_2_2_1: + /* (5.1) sce + cpe + cpe + lfe */ + FDKaacEnc_initElement(&cm->elInfo[0], ID_SCE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.24f)); + FDKaacEnc_initElement(&cm->elInfo[1], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.35f)); + FDKaacEnc_initElement(&cm->elInfo[2], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.35f)); + FDKaacEnc_initElement(&cm->elInfo[3], ID_LFE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.06f)); + break; + + case MODE_1_2_2_2_1: + /* (7.1) sce + cpe + cpe + cpe + lfe */ + FDKaacEnc_initElement(&cm->elInfo[0], ID_SCE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.18f)); + FDKaacEnc_initElement(&cm->elInfo[1], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.26f)); + FDKaacEnc_initElement(&cm->elInfo[2], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.26f)); + FDKaacEnc_initElement(&cm->elInfo[3], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.26f)); + FDKaacEnc_initElement(&cm->elInfo[4], ID_LFE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.04f)); + break; + + default: + //*chMap=0; + return AAC_ENC_UNSUPPORTED_CHANNELCONFIG; + }; + + /* Prevent additional element and save memory for unused PSY_OUT_ELEMENT, + ATS_ELEMENT, QC_OUT_ELEMENT ... + DSE signalling is done via elDSE flag. + */ +// if (dseFlag == 1) { +// it_cnt[ID_DSE]++; /* increment DSE */ +// } +// cm->elDSE = it_cnt[ID_DSE]; /* save number of DSE elemts */ + + FDK_ASSERT(cm->nElements<=(6)); + + //*chMap = cm; + + return AAC_ENC_OK; +} + +AAC_ENCODER_ERROR FDKaacEnc_InitElementBits(QC_STATE *hQC, + CHANNEL_MAPPING *cm, + INT bitrateTot, + INT averageBitsTot, + INT maxChannelBits) +{ + int sc_brTot = CountLeadingBits(bitrateTot); + + switch(cm->encMode) { + case MODE_1: + hQC->elementBits[0]->chBitrateEl = bitrateTot; + + hQC->elementBits[0]->maxBitsEl = maxChannelBits; + + hQC->elementBits[0]->relativeBitsEl = cm->elInfo[0].relativeBits; + break; + + case MODE_2: + hQC->elementBits[0]->chBitrateEl = bitrateTot>>1; + + hQC->elementBits[0]->maxBitsEl = 2*maxChannelBits; + + hQC->elementBits[0]->relativeBitsEl = cm->elInfo[0].relativeBits; + break; + case MODE_1_2: { + hQC->elementBits[0]->relativeBitsEl = cm->elInfo[0].relativeBits; + hQC->elementBits[1]->relativeBitsEl = cm->elInfo[1].relativeBits; + FIXP_DBL sceRate = cm->elInfo[0].relativeBits; + FIXP_DBL cpeRate = cm->elInfo[1].relativeBits; + + hQC->elementBits[0]->chBitrateEl = fMult(sceRate, (FIXP_DBL)(bitrateTot<>sc_brTot; + hQC->elementBits[1]->chBitrateEl = fMult(cpeRate, (FIXP_DBL)(bitrateTot<>(sc_brTot+1); + + hQC->elementBits[0]->maxBitsEl = maxChannelBits; + hQC->elementBits[1]->maxBitsEl = 2*maxChannelBits; + break; + } + case MODE_1_2_1: { + /* sce + cpe + sce */ + hQC->elementBits[0]->relativeBitsEl = cm->elInfo[0].relativeBits; + hQC->elementBits[1]->relativeBitsEl = cm->elInfo[1].relativeBits; + hQC->elementBits[2]->relativeBitsEl = cm->elInfo[2].relativeBits; + FIXP_DBL sce1Rate = cm->elInfo[0].relativeBits; + FIXP_DBL cpeRate = cm->elInfo[1].relativeBits; + FIXP_DBL sce2Rate = cm->elInfo[2].relativeBits; + + hQC->elementBits[0]->chBitrateEl = fMult(sce1Rate, (FIXP_DBL)(bitrateTot<>sc_brTot; + hQC->elementBits[1]->chBitrateEl = fMult(cpeRate, (FIXP_DBL)(bitrateTot<>(sc_brTot+1); + hQC->elementBits[2]->chBitrateEl = fMult(sce2Rate, (FIXP_DBL)(bitrateTot<>sc_brTot; + + hQC->elementBits[0]->maxBitsEl = maxChannelBits; + hQC->elementBits[1]->maxBitsEl = 2*maxChannelBits; + hQC->elementBits[2]->maxBitsEl = maxChannelBits; + break; + } + case MODE_1_2_2: { + /* sce + cpe + cpe */ + hQC->elementBits[0]->relativeBitsEl = cm->elInfo[0].relativeBits; + hQC->elementBits[1]->relativeBitsEl = cm->elInfo[1].relativeBits; + hQC->elementBits[2]->relativeBitsEl = cm->elInfo[2].relativeBits; + FIXP_DBL sceRate = cm->elInfo[0].relativeBits; + FIXP_DBL cpe1Rate = cm->elInfo[1].relativeBits; + FIXP_DBL cpe2Rate = cm->elInfo[2].relativeBits; + + hQC->elementBits[0]->chBitrateEl = fMult(sceRate, (FIXP_DBL)(bitrateTot<>sc_brTot; + hQC->elementBits[1]->chBitrateEl = fMult(cpe1Rate, (FIXP_DBL)(bitrateTot<>(sc_brTot+1); + hQC->elementBits[2]->chBitrateEl = fMult(cpe2Rate, (FIXP_DBL)(bitrateTot<>(sc_brTot+1); + + hQC->elementBits[0]->maxBitsEl = maxChannelBits; + hQC->elementBits[1]->maxBitsEl = 2*maxChannelBits; + hQC->elementBits[2]->maxBitsEl = 2*maxChannelBits; + break; + } + + case MODE_1_2_2_1: { + /* (5.1) sce + cpe + cpe + lfe */ + hQC->elementBits[0]->relativeBitsEl = cm->elInfo[0].relativeBits; + hQC->elementBits[1]->relativeBitsEl = cm->elInfo[1].relativeBits; + hQC->elementBits[2]->relativeBitsEl = cm->elInfo[2].relativeBits; + hQC->elementBits[3]->relativeBitsEl = cm->elInfo[3].relativeBits; + FIXP_DBL sceRate = cm->elInfo[0].relativeBits; + FIXP_DBL cpe1Rate = cm->elInfo[1].relativeBits; + FIXP_DBL cpe2Rate = cm->elInfo[2].relativeBits; + FIXP_DBL lfeRate = cm->elInfo[3].relativeBits; + + int maxBitsTot = maxChannelBits * 5; /* LFE does not add to bit reservoir */ + int sc = CountLeadingBits(fixMax(maxChannelBits,averageBitsTot)); + int maxLfeBits = (int) FDKmax ( (INT)((fMult(lfeRate,(FIXP_DBL)(maxChannelBits<>sc)<<1), + (INT)((fMult(FL2FXCONST_DBL(1.1f/2.f),fMult(lfeRate,(FIXP_DBL)(averageBitsTot<>sc) ); + + maxChannelBits = (maxBitsTot - maxLfeBits); + sc = CountLeadingBits(maxChannelBits); + + maxChannelBits = fMult((FIXP_DBL)maxChannelBits<>sc; + + hQC->elementBits[0]->chBitrateEl = fMult(sceRate, (FIXP_DBL)(bitrateTot<>sc_brTot; + hQC->elementBits[1]->chBitrateEl = fMult(cpe1Rate, (FIXP_DBL)(bitrateTot<>(sc_brTot+1); + hQC->elementBits[2]->chBitrateEl = fMult(cpe2Rate, (FIXP_DBL)(bitrateTot<>(sc_brTot+1); + hQC->elementBits[3]->chBitrateEl = fMult(lfeRate, (FIXP_DBL)(bitrateTot<>sc_brTot; + + hQC->elementBits[0]->maxBitsEl = maxChannelBits; + hQC->elementBits[1]->maxBitsEl = 2*maxChannelBits; + hQC->elementBits[2]->maxBitsEl = 2*maxChannelBits; + hQC->elementBits[3]->maxBitsEl = maxLfeBits; + + break; + } + + case MODE_1_2_2_2_1:{ + /* (7.1) sce + cpe + cpe + cpe + lfe */ + hQC->elementBits[0]->relativeBitsEl = cm->elInfo[0].relativeBits; + hQC->elementBits[1]->relativeBitsEl = cm->elInfo[1].relativeBits; + hQC->elementBits[2]->relativeBitsEl = cm->elInfo[2].relativeBits; + hQC->elementBits[3]->relativeBitsEl = cm->elInfo[3].relativeBits; + hQC->elementBits[4]->relativeBitsEl = cm->elInfo[4].relativeBits; + FIXP_DBL sceRate = cm->elInfo[0].relativeBits; + FIXP_DBL cpe1Rate = cm->elInfo[1].relativeBits; + FIXP_DBL cpe2Rate = cm->elInfo[2].relativeBits; + FIXP_DBL cpe3Rate = cm->elInfo[3].relativeBits; + FIXP_DBL lfeRate = cm->elInfo[4].relativeBits; + + int maxBitsTot = maxChannelBits * 7; /* LFE does not add to bit reservoir */ + int sc = CountLeadingBits(fixMax(maxChannelBits,averageBitsTot)); + int maxLfeBits = (int) FDKmax ( (INT)((fMult(lfeRate,(FIXP_DBL)(maxChannelBits<>sc)<<1), + (INT)((fMult(FL2FXCONST_DBL(1.1f/2.f),fMult(lfeRate,(FIXP_DBL)(averageBitsTot<>sc) ); + + maxChannelBits = (maxBitsTot - maxLfeBits) / 7; + + hQC->elementBits[0]->chBitrateEl = fMult(sceRate, (FIXP_DBL)(bitrateTot<>sc_brTot; + hQC->elementBits[1]->chBitrateEl = fMult(cpe1Rate, (FIXP_DBL)(bitrateTot<>(sc_brTot+1); + hQC->elementBits[2]->chBitrateEl = fMult(cpe2Rate, (FIXP_DBL)(bitrateTot<>(sc_brTot+1); + hQC->elementBits[3]->chBitrateEl = fMult(cpe3Rate, (FIXP_DBL)(bitrateTot<>(sc_brTot+1); + hQC->elementBits[4]->chBitrateEl = fMult(lfeRate, (FIXP_DBL)(bitrateTot<>sc_brTot; + + hQC->elementBits[0]->maxBitsEl = maxChannelBits; + hQC->elementBits[1]->maxBitsEl = 2*maxChannelBits; + hQC->elementBits[2]->maxBitsEl = 2*maxChannelBits; + hQC->elementBits[3]->maxBitsEl = 2*maxChannelBits; + hQC->elementBits[4]->maxBitsEl = maxLfeBits; + break; + } + + default: + return AAC_ENC_UNSUPPORTED_CHANNELCONFIG; + } + + return AAC_ENC_OK; +} + +/********************************************************************************/ +/* */ +/* function: GetMonoStereoMODE(const CHANNEL_MODE mode) */ +/* */ +/* description: Determines encoder setting from channel mode. */ +/* Multichannel modes are mapped to mono or stereo modes */ +/* returns MODE_MONO in case of mono, */ +/* MODE_STEREO in case of stereo */ +/* MODE_INVALID in case of error */ +/* */ +/* input: CHANNEL_MODE mode: Encoder mode (see qc_data.h). */ +/* output: return: CM_STEREO_MODE monoStereoSetting */ +/* (MODE_INVALID: error, */ +/* MODE_MONO: mono */ +/* MODE_STEREO: stereo). */ +/* */ +/* misc: No memory is allocated. */ +/* */ +/********************************************************************************/ + +ELEMENT_MODE FDKaacEnc_GetMonoStereoMode(const CHANNEL_MODE mode){ + + ELEMENT_MODE monoStereoSetting = EL_MODE_INVALID; + + switch(mode){ + case MODE_1: /* mono setups */ + monoStereoSetting = EL_MODE_MONO; + break; + case MODE_2: /* stereo setups */ + case MODE_1_2: + case MODE_1_2_1: + case MODE_1_2_2: + case MODE_1_2_2_1: + case MODE_1_2_2_2_1: + monoStereoSetting = EL_MODE_STEREO; + break; + default: /* error */ + monoStereoSetting = EL_MODE_INVALID; + break; + } + + return monoStereoSetting; +} + +const CHANNEL_MODE_CONFIG_TAB* FDKaacEnc_GetChannelModeConfiguration(const CHANNEL_MODE mode) +{ + INT i; + const CHANNEL_MODE_CONFIG_TAB *cm_config = NULL; + + /* get channel mode config */ + for (i=0; i<(INT)sizeof(channelModeConfig)/(INT)sizeof(CHANNEL_MODE_CONFIG_TAB); i++) { + if (channelModeConfig[i].encMode==mode) + { + cm_config = &channelModeConfig[i]; + break; + } + } + return cm_config; +} + +/* +void FDKaacEnc_CloseChannelMapping (CHANNEL_MAPPING** phchMap) { + FreeRam_ChannelMapping(phchMap); +} +*/ + diff --git a/libAACenc/src/channel_map.h b/libAACenc/src/channel_map.h new file mode 100644 index 0000000..8b60656 --- /dev/null +++ b/libAACenc/src/channel_map.h @@ -0,0 +1,72 @@ +/************************* Fast MPEG AAC Audio Encoder ********************** + + (C) Copyright Fraunhofer IIS (2000) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: A. Groeschel + contents/description: channel mapping functionality + +******************************************************************************/ + +#ifndef _CHANNEL_MAP_H +#define _CHANNEL_MAP_H + + +#include "aacenc.h" +#include "psy_const.h" +#include "qc_data.h" + +typedef struct { + CHANNEL_MODE encMode; + INT nChannels; + INT nChannelsEff; + INT nElements; +} CHANNEL_MODE_CONFIG_TAB; + + +/* Element mode */ +typedef enum { + EL_MODE_INVALID = 0, + EL_MODE_MONO, + EL_MODE_STEREO +} ELEMENT_MODE; + + +AAC_ENCODER_ERROR FDKaacEnc_DetermineEncoderMode(CHANNEL_MODE* mode, + INT nChannels); + +AAC_ENCODER_ERROR FDKaacEnc_InitChannelMapping(CHANNEL_MODE mode, + CHANNEL_ORDER co, + CHANNEL_MAPPING* chMap); + +AAC_ENCODER_ERROR FDKaacEnc_InitElementBits(QC_STATE *hQC, + CHANNEL_MAPPING *cm, + INT bitrateTot, + INT averageBitsTot, + INT maxChannelBits); + +ELEMENT_MODE FDKaacEnc_GetMonoStereoMode(const CHANNEL_MODE mode); + +const CHANNEL_MODE_CONFIG_TAB* FDKaacEnc_GetChannelModeConfiguration(const CHANNEL_MODE mode); + +//void FDKaacEnc_CloseChannelMapping (CHANNEL_MAPPING** phchMap); + +#endif /* CHANNEL_MAP_H */ diff --git a/libAACenc/src/chaosmeasure.cpp b/libAACenc/src/chaosmeasure.cpp new file mode 100644 index 0000000..086a0b0 --- /dev/null +++ b/libAACenc/src/chaosmeasure.cpp @@ -0,0 +1,99 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1997) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Werner + contents/description: Chaos measure calculation + +******************************************************************************/ + +#include "chaosmeasure.h" + +/***************************************************************************** + functionname: FDKaacEnc_FDKaacEnc_CalculateChaosMeasurePeakFast + description: Eberlein method of chaos measure calculation by high-pass + filtering amplitude spectrum + A special case of FDKaacEnc_CalculateChaosMeasureTonalGeneric -- + highly optimized +*****************************************************************************/ +static void +FDKaacEnc_FDKaacEnc_CalculateChaosMeasurePeakFast( FIXP_DBL *RESTRICT paMDCTDataNM0, + INT numberOfLines, + FIXP_DBL *RESTRICT chaosMeasure ) +{ + INT i, j; + + /* calculate chaos measure by "peak filter" */ + for (i=0; i<2; i++) { + /* make even and odd pass through data */ + FIXP_DBL left,center; /* left, center tap of filter */ + + left = (FIXP_DBL)((LONG)paMDCTDataNM0[i]^((LONG)paMDCTDataNM0[i]>>(DFRACT_BITS-1))); + center = (FIXP_DBL)((LONG)paMDCTDataNM0[i+2]^((LONG)paMDCTDataNM0[i+2]>>(DFRACT_BITS-1))); + + for (j = i+2; j < numberOfLines - 2; j+=2) { + FIXP_DBL right = (FIXP_DBL)((LONG)paMDCTDataNM0[j+2]^((LONG)paMDCTDataNM0[j+2]>>(DFRACT_BITS-1))); + FIXP_DBL tmp = (left>>1)+(right>>1); + + if (tmp < center ) { + INT leadingBits = CntLeadingZeros(center)-1; + tmp = schur_div(tmp<codeBook == 11) || (huffsection->codeBook >= 16)) ) { + sideInfoBits = 5; + } + else { + sideInfoBits = sideInfoTab[huffsection->sfbCnt]; + } + + return (sideInfoBits); +} + +/* count bits using all possible tables */ +static void FDKaacEnc_buildBitLookUp( + const SHORT* const quantSpectrum, + const INT maxSfb, + const INT* const sfbOffset, + const UINT* const sfbMax, + INT bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1], + SECTION_INFO* const huffsection + ) +{ + INT i, sfbWidth; + + for (i = 0; i < maxSfb; i++) + { + huffsection[i].sfbCnt = 1; + huffsection[i].sfbStart = i; + huffsection[i].sectionBits = INVALID_BITCOUNT; + huffsection[i].codeBook = -1; + sfbWidth = sfbOffset[i + 1] - sfbOffset[i]; + FDKaacEnc_bitCount(quantSpectrum + sfbOffset[i], sfbWidth, sfbMax[i], bitLookUp[i]); + } +} + +/* essential helper functions */ +static INT FDKaacEnc_findBestBook( + const INT* const bc, + INT* const book, + const INT useVCB11 + ) +{ + INT minBits = INVALID_BITCOUNT, j; + + int end = CODE_BOOK_ESC_NDX; + + + for (j = 0; j <= end; j++) + { + if (bc[j] < minBits) + { + minBits = bc[j]; + *book = j; + } + } + return (minBits); +} + +static INT FDKaacEnc_findMinMergeBits( + const INT* const bc1, + const INT* const bc2, + const INT useVCB11 + ) +{ + INT minBits = INVALID_BITCOUNT, j; + + int end = CODE_BOOK_ESC_NDX; + + + for (j = 0; j <= end; j++) + { + if (bc1[j] + bc2[j] < minBits) + { + minBits = bc1[j] + bc2[j]; + } + } + return (minBits); +} + +static void FDKaacEnc_mergeBitLookUp( + INT* const bc1, + const INT* const bc2 + ) +{ + int j; + + for (j = 0; j <= CODE_BOOK_ESC_NDX; j++) + { + bc1[j] = fixMin(bc1[j] + bc2[j], INVALID_BITCOUNT); + } +} + +static INT FDKaacEnc_findMaxMerge( + const INT* const mergeGainLookUp, + const SECTION_INFO* const huffsection, + const INT maxSfb, + INT* const maxNdx + ) +{ + INT i, maxMergeGain = 0; + + for (i = 0; i + huffsection[i].sfbCnt < maxSfb; i += huffsection[i].sfbCnt) + { + if (mergeGainLookUp[i] > maxMergeGain) + { + maxMergeGain = mergeGainLookUp[i]; + *maxNdx = i; + } + } + return (maxMergeGain); +} + +static INT FDKaacEnc_CalcMergeGain( + const SECTION_INFO* const huffsection, + const INT bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1], + const SHORT* const sideInfoTab, + const INT ndx1, + const INT ndx2, + const INT useVCB11 + ) +{ + INT MergeGain, MergeBits, SplitBits; + + MergeBits = sideInfoTab[huffsection[ndx1].sfbCnt + huffsection[ndx2].sfbCnt] + FDKaacEnc_findMinMergeBits(bitLookUp[ndx1], bitLookUp[ndx2], useVCB11); + SplitBits = huffsection[ndx1].sectionBits + huffsection[ndx2].sectionBits; /* Bit amount for splitted huffsections */ + MergeGain = SplitBits - MergeBits; + + if ( (huffsection[ndx1].codeBook==CODE_BOOK_PNS_NO)||(huffsection[ndx2].codeBook==CODE_BOOK_PNS_NO) + || (huffsection[ndx1].codeBook==CODE_BOOK_IS_OUT_OF_PHASE_NO)||(huffsection[ndx2].codeBook==CODE_BOOK_IS_OUT_OF_PHASE_NO) + || (huffsection[ndx1].codeBook==CODE_BOOK_IS_IN_PHASE_NO)||(huffsection[ndx2].codeBook==CODE_BOOK_IS_IN_PHASE_NO) + ) + { + MergeGain = -1; + } + + return (MergeGain); +} + + +/* sectioning Stage 0:find minimum codbooks */ +static void FDKaacEnc_gmStage0( + SECTION_INFO* const RESTRICT huffsection, + const INT bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1], + const INT maxSfb, + const INT* const noiseNrg, + const INT* const isBook + ) +{ + INT i; + + for (i = 0; i < maxSfb; i++) + { + /* Side-Info bits will be calculated in Stage 1! */ + if (huffsection[i].sectionBits == INVALID_BITCOUNT) + { + /* intensity and pns codebooks are already allocated in bitcount.c */ + if(noiseNrg[i] != NO_NOISE_PNS){ + huffsection[i].codeBook=CODE_BOOK_PNS_NO; + huffsection[i].sectionBits = 0; + } + else if( isBook[i] ) { + huffsection[i].codeBook=isBook[i]; + huffsection[i].sectionBits = 0; + } + else { + huffsection[i].sectionBits = FDKaacEnc_findBestBook(bitLookUp[i], &(huffsection[i].codeBook), 0); /* useVCB11 must be 0!!! */ + } + } + } +} + +/* + sectioning Stage 1:merge all connected regions with the same code book and + calculate side info + */ +static void FDKaacEnc_gmStage1( + SECTION_INFO* const RESTRICT huffsection, + INT bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1], + const INT maxSfb, + const SHORT* const sideInfoTab, + const INT useVCB11 + ) +{ + INT mergeStart = 0, mergeEnd; + + do + { + for (mergeEnd = mergeStart + 1; mergeEnd < maxSfb; mergeEnd++) + { + if (huffsection[mergeStart].codeBook != huffsection[mergeEnd].codeBook) + break; + + + /* we can merge. update tables, side info bits will be updated outside of this loop */ + huffsection[mergeStart].sfbCnt++; + huffsection[mergeStart].sectionBits += huffsection[mergeEnd].sectionBits; + + /* update bit look up for all code books */ + FDKaacEnc_mergeBitLookUp(bitLookUp[mergeStart], bitLookUp[mergeEnd]); + } + + /* add side info info bits */ + huffsection[mergeStart].sectionBits += FDKaacEnc_getSideInfoBits(&huffsection[mergeStart], sideInfoTab, useVCB11); + huffsection[mergeEnd - 1].sfbStart = huffsection[mergeStart].sfbStart; /* speed up prev search */ + + mergeStart = mergeEnd; + + } while (mergeStart < maxSfb); +} + +/* + sectioning Stage 2:greedy merge algorithm, merge connected sections with + maximum bit gain until no more gain is possible + */ +static void +FDKaacEnc_gmStage2( + SECTION_INFO* const RESTRICT huffsection, + INT* const RESTRICT mergeGainLookUp, + INT bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1], + const INT maxSfb, + const SHORT* const sideInfoTab, + const INT useVCB11 + ) +{ + INT i; + + for (i = 0; i + huffsection[i].sfbCnt < maxSfb; i += huffsection[i].sfbCnt) + { + mergeGainLookUp[i] = FDKaacEnc_CalcMergeGain(huffsection, + bitLookUp, + sideInfoTab, + i, + i + huffsection[i].sfbCnt, + useVCB11); + } + + while (TRUE) + { + INT maxMergeGain, maxNdx = 0, maxNdxNext, maxNdxLast; + + maxMergeGain = FDKaacEnc_findMaxMerge(mergeGainLookUp, huffsection, maxSfb, &maxNdx); + + /* exit while loop if no more gain is possible */ + if (maxMergeGain <= 0) + break; + + maxNdxNext = maxNdx + huffsection[maxNdx].sfbCnt; + + /* merge sections with maximum bit gain */ + huffsection[maxNdx].sfbCnt += huffsection[maxNdxNext].sfbCnt; + huffsection[maxNdx].sectionBits += huffsection[maxNdxNext].sectionBits - maxMergeGain; + + /* update bit look up table for merged huffsection */ + FDKaacEnc_mergeBitLookUp(bitLookUp[maxNdx], bitLookUp[maxNdxNext]); + + /* update mergeLookUpTable */ + if (maxNdx != 0) + { + maxNdxLast = huffsection[maxNdx - 1].sfbStart; + mergeGainLookUp[maxNdxLast] = FDKaacEnc_CalcMergeGain(huffsection, + bitLookUp, + sideInfoTab, + maxNdxLast, + maxNdx, + useVCB11); + + } + maxNdxNext = maxNdx + huffsection[maxNdx].sfbCnt; + + huffsection[maxNdxNext - 1].sfbStart = huffsection[maxNdx].sfbStart; + + if (maxNdxNext < maxSfb) + mergeGainLookUp[maxNdx] = FDKaacEnc_CalcMergeGain(huffsection, + bitLookUp, + sideInfoTab, + maxNdx, + maxNdxNext, + useVCB11); + + } +} + +/* count bits used by the noiseless coder */ +static void FDKaacEnc_noiselessCounter( + SECTION_DATA* const RESTRICT sectionData, + INT mergeGainLookUp[MAX_SFB_LONG], + INT bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1], + const SHORT* const quantSpectrum, + const UINT* const maxValueInSfb, + const INT* const sfbOffset, + const INT blockType, + const INT* const noiseNrg, + const INT* const isBook, + const INT useVCB11 + ) +{ + INT grpNdx, i; + const SHORT *sideInfoTab = NULL; + SECTION_INFO *huffsection; + + /* use appropriate side info table */ + switch (blockType) + { + case LONG_WINDOW: + case START_WINDOW: + case STOP_WINDOW: + sideInfoTab = FDKaacEnc_sideInfoTabLong; + break; + case SHORT_WINDOW: + sideInfoTab = FDKaacEnc_sideInfoTabShort; + break; + } + + sectionData->noOfSections = 0; + sectionData->huffmanBits = 0; + sectionData->sideInfoBits = 0; + + + if (sectionData->maxSfbPerGroup == 0) + return; + + /* loop trough groups */ + for (grpNdx = 0; grpNdx < sectionData->sfbCnt; grpNdx += sectionData->sfbPerGroup) + { + huffsection = sectionData->huffsection + sectionData->noOfSections; + + /* count bits in this group */ + FDKaacEnc_buildBitLookUp(quantSpectrum, + sectionData->maxSfbPerGroup, + sfbOffset + grpNdx, + maxValueInSfb + grpNdx, + bitLookUp, + huffsection); + + /* 0.Stage :Find minimum Codebooks */ + FDKaacEnc_gmStage0(huffsection, bitLookUp, sectionData->maxSfbPerGroup, noiseNrg+grpNdx, isBook+grpNdx); + + /* 1.Stage :Merge all connected regions with the same code book */ + FDKaacEnc_gmStage1(huffsection, bitLookUp, sectionData->maxSfbPerGroup, sideInfoTab, useVCB11); + + + /* + 2.Stage + greedy merge algorithm, merge connected huffsections with maximum bit + gain until no more gain is possible + */ + + FDKaacEnc_gmStage2(huffsection, + mergeGainLookUp, + bitLookUp, + sectionData->maxSfbPerGroup, + sideInfoTab, + useVCB11); + + + + /* + compress output, calculate total huff and side bits + since we did not update the actual codebook in stage 2 + to save time, we must set it here for later use in bitenc + */ + + for (i = 0; i < sectionData->maxSfbPerGroup; i += huffsection[i].sfbCnt) + { + if ((huffsection[i].codeBook==CODE_BOOK_PNS_NO) || + (huffsection[i].codeBook==CODE_BOOK_IS_OUT_OF_PHASE_NO) || + (huffsection[i].codeBook==CODE_BOOK_IS_IN_PHASE_NO)) + { + huffsection[i].sectionBits=0; + } else { + /* the sections in the sectionData are now marked with the optimal code book */ + + FDKaacEnc_findBestBook(bitLookUp[i], &(huffsection[i].codeBook), useVCB11); + + sectionData->huffmanBits += huffsection[i].sectionBits - FDKaacEnc_getSideInfoBits(&huffsection[i], sideInfoTab, useVCB11); + } + + huffsection[i].sfbStart += grpNdx; + + /* sum up side info bits (section data bits) */ + sectionData->sideInfoBits += FDKaacEnc_getSideInfoBits(&huffsection[i], sideInfoTab, useVCB11); + sectionData->huffsection[sectionData->noOfSections++] = huffsection[i]; + } + } +} + + +/******************************************************************************* + + functionname: FDKaacEnc_scfCount + returns : --- + description : count bits used by scalefactors. + + not in all cases if maxValueInSfb[] == 0 we set deltaScf + to zero. only if the difference of the last and future + scalefacGain is not greater then CODE_BOOK_SCF_LAV (60). + + example: + ^ + scalefacGain | + | + | last 75 + | | + | | + | | + | | current 50 + | | | + | | | + | | | + | | | + | | | future 5 + | | | | + --- ... ---------------------------- ... ---------> + sfb + + + if maxValueInSfb[] of current is zero because of a + notfallstrategie, we do not save bits and transmit a + deltaScf of 25. otherwise the deltaScf between the last + scalfacGain (75) and the future scalefacGain (5) is 70. + +********************************************************************************/ +static void FDKaacEnc_scfCount( + const INT* const scalefacGain, + const UINT* const maxValueInSfb, + SECTION_DATA* const RESTRICT sectionData, + const INT* const isScale + ) +{ + INT i, j, k, m, n; + + INT lastValScf = 0; + INT deltaScf = 0; + INT found = 0; + INT scfSkipCounter = 0; + INT lastValIs = 0; + + sectionData->scalefacBits = 0; + + if (scalefacGain == NULL) + return; + + sectionData->firstScf = 0; + + for (i=0; inoOfSections; i++) + { + if (sectionData->huffsection[i].codeBook != CODE_BOOK_ZERO_NO) + { + sectionData->firstScf = sectionData->huffsection[i].sfbStart; + lastValScf = scalefacGain[sectionData->firstScf]; + break; + } + } + + for (i=0; inoOfSections; i++) + { + if ((sectionData->huffsection[i].codeBook == CODE_BOOK_IS_OUT_OF_PHASE_NO) || + (sectionData->huffsection[i].codeBook == CODE_BOOK_IS_IN_PHASE_NO)) + { + for (j = sectionData->huffsection[i].sfbStart; + j < sectionData->huffsection[i].sfbStart + sectionData->huffsection[i].sfbCnt; + j++) + { + INT deltaIs = isScale[j]-lastValIs; + lastValIs = isScale[j]; + sectionData->scalefacBits+=FDKaacEnc_bitCountScalefactorDelta(deltaIs); + } + } /* Intensity */ + else if ((sectionData->huffsection[i].codeBook != CODE_BOOK_ZERO_NO) && + (sectionData->huffsection[i].codeBook != CODE_BOOK_PNS_NO)) + { + INT tmp = sectionData->huffsection[i].sfbStart + sectionData->huffsection[i].sfbCnt; + for (j = sectionData->huffsection[i].sfbStart; jnoOfSections) && (found == 0); m++) + { + if ((sectionData->huffsection[m].codeBook != CODE_BOOK_ZERO_NO) && (sectionData->huffsection[m].codeBook != CODE_BOOK_PNS_NO)) + { + INT end = sectionData->huffsection[m].sfbStart + sectionData->huffsection[m].sfbCnt; + for (n = sectionData->huffsection[m].sfbStart; nscalefacBits += FDKaacEnc_bitCountScalefactorDelta(deltaScf); + } + } + } /* for (i=0; inoOfSections; i++) */ +} + +#ifdef PNS_PRECOUNT_ENABLE +/* + preCount bits used pns +*/ +/* estimate bits used by pns for correction of static bits */ +/* no codebook switch estimation, see AAC LD FASTENC */ +INT noisePreCount(const INT *noiseNrg, INT maxSfb) +{ + INT noisePCMFlag = TRUE; + INT lastValPns = 0, deltaPns; + int i, bits=0; + + for (i = 0; i < maxSfb; i++) { + if (noiseNrg[i] != NO_NOISE_PNS) { + + if (noisePCMFlag) { + bits+=PNS_PCM_BITS; + lastValPns = noiseNrg[i]; + noisePCMFlag = FALSE; + }else { + deltaPns = noiseNrg[i]-lastValPns; + lastValPns = noiseNrg[i]; + bits+=FDKaacEnc_bitCountScalefactorDelta(deltaPns); + } + } + } + return ( bits ); +} +#endif /* PNS_PRECOUNT_ENABLE */ + +/* count bits used by pns */ +static void FDKaacEnc_noiseCount( + SECTION_DATA* const RESTRICT sectionData, + const INT* const noiseNrg + ) +{ + INT noisePCMFlag = TRUE; + INT lastValPns = 0, deltaPns; + int i, j; + + sectionData->noiseNrgBits = 0; + + for (i = 0; i < sectionData->noOfSections; i++) { + if (sectionData->huffsection[i].codeBook == CODE_BOOK_PNS_NO) { + int sfbStart = sectionData->huffsection[i].sfbStart; + int sfbEnd = sfbStart + sectionData->huffsection[i].sfbCnt; + for (j=sfbStart; jnoiseNrgBits+=PNS_PCM_BITS; + lastValPns = noiseNrg[j]; + noisePCMFlag = FALSE; + } else { + deltaPns = noiseNrg[j]-lastValPns; + lastValPns = noiseNrg[j]; + sectionData->noiseNrgBits+=FDKaacEnc_bitCountScalefactorDelta(deltaPns); + } + } + } + } +} + +INT FDKaacEnc_dynBitCount( + BITCNTR_STATE* const hBC, + const SHORT* const quantSpectrum, + const UINT* const maxValueInSfb, + const INT* const scalefac, + const INT blockType, + const INT sfbCnt, + const INT maxSfbPerGroup, + const INT sfbPerGroup, + const INT* const sfbOffset, + SECTION_DATA* const RESTRICT sectionData, + const INT* const noiseNrg, + const INT* const isBook, + const INT* const isScale, + const UINT syntaxFlags + ) +{ + sectionData->blockType = blockType; + sectionData->sfbCnt = sfbCnt; + sectionData->sfbPerGroup = sfbPerGroup; + sectionData->noOfGroups = sfbCnt / sfbPerGroup; + sectionData->maxSfbPerGroup = maxSfbPerGroup; + + FDKaacEnc_noiselessCounter( + sectionData, + hBC->mergeGainLookUp, + (lookUpTable)hBC->bitLookUp, + quantSpectrum, + maxValueInSfb, + sfbOffset, + blockType, + noiseNrg, + isBook, + (syntaxFlags & AC_ER_VCB11)?1:0); + + FDKaacEnc_scfCount( + scalefac, + maxValueInSfb, + sectionData, + isScale); + + FDKaacEnc_noiseCount(sectionData, + noiseNrg); + + return (sectionData->huffmanBits + + sectionData->sideInfoBits + + sectionData->scalefacBits + + sectionData->noiseNrgBits); +} + +INT FDKaacEnc_BCNew(BITCNTR_STATE **phBC + ,UCHAR* dynamic_RAM + ) +{ + BITCNTR_STATE *hBC = GetRam_aacEnc_BitCntrState(); + + if (hBC) + { + *phBC = hBC; + hBC->bitLookUp = GetRam_aacEnc_BitLookUp(0,dynamic_RAM); + hBC->mergeGainLookUp = GetRam_aacEnc_MergeGainLookUp(0,dynamic_RAM); + if (hBC->bitLookUp == 0 || + hBC->mergeGainLookUp == 0) + { + return 1; + } + } + return (hBC == 0) ? 1 : 0; +} + +void FDKaacEnc_BCClose(BITCNTR_STATE **phBC) +{ + if (*phBC!=NULL) { + + FreeRam_aacEnc_BitCntrState(phBC); + } +} + + + diff --git a/libAACenc/src/dyn_bits.h b/libAACenc/src/dyn_bits.h new file mode 100644 index 0000000..b889ebe --- /dev/null +++ b/libAACenc/src/dyn_bits.h @@ -0,0 +1,104 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Noiseless coder module + +******************************************************************************/ +#ifndef __DYN_BITS_H +#define __DYN_BITS_H + +#include "common_fix.h" + +#include "psy_const.h" +#include "aacenc_tns.h" + +#define MAX_SECTIONS MAX_GROUPED_SFB +#define SECT_ESC_VAL_LONG 31 +#define SECT_ESC_VAL_SHORT 7 +#define CODE_BOOK_BITS 4 +#define SECT_BITS_LONG 5 +#define SECT_BITS_SHORT 3 +#define PNS_PCM_BITS 9 + +typedef struct +{ + INT codeBook; + INT sfbStart; + INT sfbCnt; + INT sectionBits; /* huff + si ! */ +} SECTION_INFO; + + +typedef struct +{ + INT blockType; + INT noOfGroups; + INT sfbCnt; + INT maxSfbPerGroup; + INT sfbPerGroup; + INT noOfSections; + SECTION_INFO huffsection[MAX_SECTIONS]; + INT sideInfoBits; /* sectioning bits */ + INT huffmanBits; /* huffman coded bits */ + INT scalefacBits; /* scalefac coded bits */ + INT noiseNrgBits; /* noiseEnergy coded bits */ + INT firstScf; /* first scf to be coded */ +} SECTION_DATA; + + +struct BITCNTR_STATE +{ + INT *bitLookUp; + INT *mergeGainLookUp; +}; + + +INT FDKaacEnc_BCNew(BITCNTR_STATE **phBC + ,UCHAR* dynamic_RAM + ); + +void FDKaacEnc_BCClose(BITCNTR_STATE **phBC); + +#if defined(PNS_PRECOUNT_ENABLE) +INT noisePreCount(const INT *noiseNrg, INT maxSfb); +#endif + +INT FDKaacEnc_dynBitCount( + BITCNTR_STATE* const hBC, + const SHORT* const quantSpectrum, + const UINT* const maxValueInSfb, + const INT* const scalefac, + const INT blockType, + const INT sfbCnt, + const INT maxSfbPerGroup, + const INT sfbPerGroup, + const INT* const sfbOffset, + SECTION_DATA* const RESTRICT sectionData, + const INT* const noiseNrg, + const INT* const isBook, + const INT* const isScale, + const UINT syntaxFlags + ); + +#endif diff --git a/libAACenc/src/grp_data.cpp b/libAACenc/src/grp_data.cpp new file mode 100644 index 0000000..8cd017b --- /dev/null +++ b/libAACenc/src/grp_data.cpp @@ -0,0 +1,206 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Short block grouping + +******************************************************************************/ +#include "psy_const.h" +#include "interface.h" + +/* +* this routine does not work in-place +*/ + +void +FDKaacEnc_groupShortData(FIXP_DBL *mdctSpectrum, /* in-out */ + SFB_THRESHOLD *sfbThreshold, /* in-out */ + SFB_ENERGY *sfbEnergy, /* in-out */ + SFB_ENERGY *sfbEnergyMS, /* in-out */ + SFB_ENERGY *sfbSpreadEnergy, + const INT sfbCnt, + const INT sfbActive, + const INT *sfbOffset, + const FIXP_DBL *sfbMinSnrLdData, + INT *groupedSfbOffset, /* out */ + INT *maxSfbPerGroup, /* out */ + FIXP_DBL *groupedSfbMinSnrLdData, + const INT noOfGroups, + const INT *groupLen, + const INT granuleLength) +{ + INT i,j; + INT line; /* counts through lines */ + INT sfb; /* counts through scalefactor bands */ + INT grp; /* counts through groups */ + INT wnd; /* counts through windows in a group */ + INT offset; /* needed in sfbOffset grouping */ + INT highestSfb; + + INT granuleLength_short = granuleLength/TRANS_FAC; + + /* for short blocks: regroup spectrum and */ + /* group energies and thresholds according to grouping */ + C_ALLOC_SCRATCH_START(tmpSpectrum, FIXP_DBL, (1024)); + + /* calculate maxSfbPerGroup */ + highestSfb = 0; + for (wnd = 0; wnd < TRANS_FAC; wnd++) + { + for (sfb = sfbActive-1; sfb >= highestSfb; sfb--) + { + for (line = sfbOffset[sfb+1]-1; line >= sfbOffset[sfb]; line--) + { + if ( mdctSpectrum[wnd*granuleLength_short+line] != FL2FXCONST_SPC(0.0) ) break; /* this band is not completely zero */ + } + if (line >= sfbOffset[sfb]) break; /* this band was not completely zero */ + } + highestSfb = fixMax(highestSfb, sfb); + } + highestSfb = highestSfb > 0 ? highestSfb : 0; + *maxSfbPerGroup = highestSfb+1; + + /* calculate groupedSfbOffset */ + i = 0; + offset = 0; + for (grp = 0; grp < noOfGroups; grp++) + { + for (sfb = 0; sfb < sfbActive+1; sfb++) + { + groupedSfbOffset[i++] = offset + sfbOffset[sfb] * groupLen[grp]; + } + i += sfbCnt-sfb; + offset += groupLen[grp] * granuleLength_short; + } + groupedSfbOffset[i++] = granuleLength; + + /* calculate groupedSfbMinSnr */ + i = 0; + for (grp = 0; grp < noOfGroups; grp++) + { + for (sfb = 0; sfb < sfbActive; sfb++) + { + groupedSfbMinSnrLdData[i++] = sfbMinSnrLdData[sfb]; + } + i += sfbCnt-sfb; + } + + /* sum up sfbThresholds */ + wnd = 0; + i = 0; + for (grp = 0; grp < noOfGroups; grp++) + { + for (sfb = 0; sfb < sfbActive; sfb++) + { + FIXP_DBL thresh = sfbThreshold->Short[wnd][sfb]; + for (j=1; jShort[wnd+j][sfb]; + } + sfbThreshold->Long[i++] = thresh; + } + i += sfbCnt-sfb; + wnd += groupLen[grp]; + } + + /* sum up sfbEnergies left/right */ + wnd = 0; + i = 0; + for (grp = 0; grp < noOfGroups; grp++) + { + for (sfb = 0; sfb < sfbActive; sfb++) + { + FIXP_DBL energy = sfbEnergy->Short[wnd][sfb]; + for (j=1; jShort[wnd+j][sfb]; + } + sfbEnergy->Long[i++] = energy; + } + i += sfbCnt-sfb; + wnd += groupLen[grp]; + } + + /* sum up sfbEnergies mid/side */ + wnd = 0; + i = 0; + for (grp = 0; grp < noOfGroups; grp++) + { + for (sfb = 0; sfb < sfbActive; sfb++) + { + FIXP_DBL energy = sfbEnergyMS->Short[wnd][sfb]; + for (j=1; jShort[wnd+j][sfb]; + } + sfbEnergyMS->Long[i++] = energy; + } + i += sfbCnt-sfb; + wnd += groupLen[grp]; + } + + /* sum up sfbSpreadEnergies */ + wnd = 0; + i = 0; + for (grp = 0; grp < noOfGroups; grp++) + { + for (sfb = 0; sfb < sfbActive; sfb++) + { + FIXP_DBL energy = sfbSpreadEnergy->Short[wnd][sfb]; + for (j=1; jShort[wnd+j][sfb]; + } + sfbSpreadEnergy->Long[i++] = energy; + } + i += sfbCnt-sfb; + wnd += groupLen[grp]; + } + + /* re-group spectrum */ + wnd = 0; + i = 0; + for (grp = 0; grp < noOfGroups; grp++) + { + for (sfb = 0; sfb < sfbActive; sfb++) + { + int width = sfbOffset[sfb+1]-sfbOffset[sfb]; + FIXP_DBL *pMdctSpectrum = &mdctSpectrum[sfbOffset[sfb]] + wnd*granuleLength_short; + for (j = 0; j < groupLen[grp]; j++) + { + FIXP_DBL *pTmp = pMdctSpectrum; + for (line = width; line > 0; line--) + { + tmpSpectrum[i++] = *pTmp++; + } + pMdctSpectrum += granuleLength_short; + } + } + i += (groupLen[grp]*(sfbOffset[sfbCnt]-sfbOffset[sfb])); + wnd += groupLen[grp]; + } + + FDKmemcpy(mdctSpectrum, tmpSpectrum, granuleLength*sizeof(FIXP_DBL)); + + C_ALLOC_SCRATCH_END(tmpSpectrum, FIXP_DBL, (1024)) +} diff --git a/libAACenc/src/grp_data.h b/libAACenc/src/grp_data.h new file mode 100644 index 0000000..b28cf8c --- /dev/null +++ b/libAACenc/src/grp_data.h @@ -0,0 +1,53 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Short block grouping + +******************************************************************************/ +#ifndef __GRP_DATA_H__ +#define __GRP_DATA_H__ + +#include "common_fix.h" + +#include "psy_data.h" + + +void +FDKaacEnc_groupShortData(FIXP_DBL *mdctSpectrum, /* in-out */ + SFB_THRESHOLD *sfbThreshold, /* in-out */ + SFB_ENERGY *sfbEnergy, /* in-out */ + SFB_ENERGY *sfbEnergyMS, /* in-out */ + SFB_ENERGY *sfbSpreadEnergy, + const INT sfbCnt, + const INT sfbActive, + const INT *sfbOffset, + const FIXP_DBL *sfbMinSnrLdData, + INT *groupedSfbOffset, /* out */ + INT *maxSfbPerGroup, + FIXP_DBL *groupedSfbMinSnrLdData, + const INT noOfGroups, + const INT *groupLen, + const INT granuleLength); + +#endif /* _INTERFACE_H */ diff --git a/libAACenc/src/intensity.cpp b/libAACenc/src/intensity.cpp new file mode 100644 index 0000000..b4d8637 --- /dev/null +++ b/libAACenc/src/intensity.cpp @@ -0,0 +1,691 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (2010) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + + Initial author: A. Horndasch (code originally from lwr) / Josef Hoepfl (FDK) + contents/description: intensity stereo processing + +******************************************************************************/ + +#include "intensity.h" +#include "interface.h" +#include "psy_configuration.h" +#include "psy_const.h" +#include "qc_main.h" +#include "bit_cnt.h" + +/* only set an IS seed it left/right channel correlation is above IS_CORR_THRESH */ +#define IS_CORR_THRESH FL2FXCONST_DBL(0.95f) + +/* when expanding the IS region to more SFBs only accept an error that is + * not more than IS_TOTAL_ERROR_THRESH overall and + * not more than IS_LOCAL_ERROR_THRESH for the current SFB */ +#define IS_TOTAL_ERROR_THRESH FL2FXCONST_DBL(0.04f) +#define IS_LOCAL_ERROR_THRESH FL2FXCONST_DBL(0.01f) + +/* the maximum allowed change of the intensity direction (unit: IS scale) - scaled with factor 0.25 - */ +#define IS_DIRECTION_DEVIATION_THRESH_SF 2 +#define IS_DIRECTION_DEVIATION_THRESH FL2FXCONST_DBL(2.0f/(1< no IS if the panning angle is not far from the middle, MS will do */ +/* this is equivalent to a scale of +/-1.02914634566 */ +#define IS_LEFT_RIGHT_RATIO_THRESH FL2FXCONST_DBL(0.7f) + +/* scalefactor of realScale */ +#define REAL_SCALE_SF 1 + +/* scalefactor overallLoudness */ +#define OVERALL_LOUDNESS_SF 6 + +/* scalefactor for sum over max samples per goup */ +#define MAX_SFB_PER_GROUP_SF 6 + +/* scalefactor for sum of mdct spectrum */ +#define MDCT_SPEC_SF 6 + + +typedef struct +{ + + FIXP_DBL corr_thresh; /*!< Only set an IS seed it left/right channel correlation is above corr_thresh */ + + FIXP_DBL total_error_thresh; /*!< When expanding the IS region to more SFBs only accept an error that is + not more than 'total_error_thresh' overall. */ + + FIXP_DBL local_error_thresh; /*!< When expanding the IS region to more SFBs only accept an error that is + not more than 'local_error_thresh' for the current SFB. */ + + FIXP_DBL direction_deviation_thresh; /*!< The maximum allowed change of the intensity direction (unit: IS scale) */ + + FIXP_DBL is_region_min_loudness; /*!< IS regions need to have a minimal percentage of the overall loudness, e.g. 0.06 == 6% */ + + INT min_is_sfbs; /*!< Only perform IS if 'min_is_sfbs' neighboring SFBs can be processed */ + + FIXP_DBL left_right_ratio_threshold; /*!< No IS if the panning angle is not far from the middle, MS will do */ + +} INTENSITY_PARAMETERS; + + +/***************************************************************************** + + functionname: calcSfbMaxScale + + description: Calc max value in scalefactor band + + input: *mdctSpectrum + l1 + l2 + + output: none + + returns: scalefactor + +*****************************************************************************/ +static INT +calcSfbMaxScale(const FIXP_DBL *mdctSpectrum, + const INT l1, + const INT l2) +{ + INT i; + INT sfbMaxScale; + FIXP_DBL maxSpc; + + maxSpc = FL2FXCONST_DBL(0.0); + for (i=l1; icorr_thresh = IS_CORR_THRESH; + isParams->total_error_thresh = IS_TOTAL_ERROR_THRESH; + isParams->local_error_thresh = IS_LOCAL_ERROR_THRESH; + isParams->direction_deviation_thresh = IS_DIRECTION_DEVIATION_THRESH; + isParams->is_region_min_loudness = IS_REGION_MIN_LOUDNESS; + isParams->min_is_sfbs = IS_MIN_SFBS; + isParams->left_right_ratio_threshold = IS_LEFT_RIGHT_RATIO_THRESH; +} + + +/***************************************************************************** + + functionname: FDKaacEnc_prepareIntensityDecision + + description: Prepares intensity decision + + input: sfbEnergyLeft + sfbEnergyRight + sfbEnergyLdDataLeft + sfbEnergyLdDataRight + mdctSpectrumLeft + sfbEnergyLdDataRight + isParams + + output: hrrErr scale: none + isMask scale: none + realScale scale: LD_DATA_SHIFT + REAL_SCALE_SF + normSfbLoudness scale: none + + returns: none + +*****************************************************************************/ +static void +FDKaacEnc_prepareIntensityDecision(const FIXP_DBL *sfbEnergyLeft, + const FIXP_DBL *sfbEnergyRight, + const FIXP_DBL *sfbEnergyLdDataLeft, + const FIXP_DBL *sfbEnergyLdDataRight, + const FIXP_DBL *mdctSpectrumLeft, + const FIXP_DBL *mdctSpectrumRight, + const INTENSITY_PARAMETERS *isParams, + FIXP_DBL *hrrErr, + INT *isMask, + FIXP_DBL *realScale, + FIXP_DBL *normSfbLoudness, + const INT sfbCnt, + const INT sfbPerGroup, + const INT maxSfbPerGroup, + const INT *sfbOffset) +{ + INT j,sfb,sfboffs; + INT grpCounter; + + /* temporary variables to compute loudness */ + FIXP_DBL overallLoudness[MAX_NO_OF_GROUPS]; + + /* temporary variables to compute correlation */ + FIXP_DBL channelCorr[MAX_GROUPED_SFB]; + FIXP_DBL ml, mr; + FIXP_DBL prod_lr; + FIXP_DBL square_l, square_r; + FIXP_DBL tmp_l, tmp_r; + FIXP_DBL inv_n; + + FDKmemclear(channelCorr, MAX_GROUPED_SFB*sizeof(FIXP_DBL)); + FDKmemclear(normSfbLoudness, MAX_GROUPED_SFB*sizeof(FIXP_DBL)); + FDKmemclear(overallLoudness, MAX_NO_OF_GROUPS*sizeof(FIXP_DBL)); + FDKmemclear(realScale, MAX_GROUPED_SFB*sizeof(FIXP_DBL)); + + for (grpCounter = 0, sfboffs = 0; sfboffs < sfbCnt; sfboffs += sfbPerGroup, grpCounter++) { + overallLoudness[grpCounter] = FL2FXCONST_DBL(0.0f); + for (sfb = 0; sfb < maxSfbPerGroup; sfb++) { + INT sL,sR,s; + FIXP_DBL isValue = sfbEnergyLdDataLeft[sfb+sfboffs]-sfbEnergyLdDataRight[sfb+sfboffs]; + + /* delimitate intensity scale value to representable range */ + realScale[sfb + sfboffs] = fixMin(FL2FXCONST_DBL(60.f/(1<<(REAL_SCALE_SF+LD_DATA_SHIFT))), fixMax(FL2FXCONST_DBL(-60.f/(1<<(REAL_SCALE_SF+LD_DATA_SHIFT))), isValue)); + + sL = fixMax(0,(CntLeadingZeros(sfbEnergyLeft[sfb + sfboffs])-1)); + sR = fixMax(0,(CntLeadingZeros(sfbEnergyRight[sfb + sfboffs])-1)); + s = (fixMin(sL,sR)>>2)<<2; + normSfbLoudness[sfb + sfboffs] = sqrtFixp(sqrtFixp(((sfbEnergyLeft[sfb + sfboffs]<> 1) + ((sfbEnergyRight[sfb + sfboffs]<> 1))) >> (s>>2); + + overallLoudness[grpCounter] += normSfbLoudness[sfb + sfboffs] >> OVERALL_LOUDNESS_SF; + /* don't do intensity if + * - panning angle is too close to the middle or + * - one channel is non-existent or + * - if it is dual mono */ + if( (sfbEnergyLeft[sfb + sfboffs] >= fMult(isParams->left_right_ratio_threshold,sfbEnergyRight[sfb + sfboffs])) + && (fMult(isParams->left_right_ratio_threshold,sfbEnergyLeft[sfb + sfboffs]) <= sfbEnergyRight[sfb + sfboffs]) ) { + + /* this will prevent post processing from considering this SFB for merging */ + hrrErr[sfb + sfboffs] = FL2FXCONST_DBL(1.0/8.0); + } + } + } + + for (grpCounter = 0, sfboffs = 0; sfboffs < sfbCnt; sfboffs += sfbPerGroup, grpCounter++) { + INT invOverallLoudnessSF; + FIXP_DBL invOverallLoudness; + + if (overallLoudness[grpCounter] == FL2FXCONST_DBL(0.0)) { + invOverallLoudness = FL2FXCONST_DBL(0.0); + invOverallLoudnessSF = 0; + } + else { + invOverallLoudness = fDivNorm((FIXP_DBL)MAXVAL_DBL, overallLoudness[grpCounter],&invOverallLoudnessSF); + invOverallLoudnessSF = invOverallLoudnessSF - OVERALL_LOUDNESS_SF + 1; /* +1: compensate fMultDiv2() in subsequent loop */ + } + invOverallLoudnessSF = fixMin(fixMax(invOverallLoudnessSF,-(DFRACT_BITS-1)),DFRACT_BITS-1); + + for (sfb = 0; sfb < maxSfbPerGroup; sfb++) { + FIXP_DBL tmp; + + tmp = fMultDiv2((normSfbLoudness[sfb + sfboffs]>>OVERALL_LOUDNESS_SF)<= 49); + /* max width of scalefactorband is 96; width's are always even */ + /* inv_n is scaled with factor 2 to compensate fMultDiv2() in subsequent loops */ + inv_n = GetInvInt((sfbOffset[sfb + sfboffs + 1] - sfbOffset[sfb + sfboffs])>>1); + + if (inv_n > FL2FXCONST_DBL(0.0f)) { + INT s,sL,sR; + + /* correlation := Pearson's product-moment coefficient */ + /* compute correlation between channels and check if it is over threshold */ + ml = FL2FXCONST_DBL(0.0f); + mr = FL2FXCONST_DBL(0.0f); + prod_lr = FL2FXCONST_DBL(0.0f); + square_l = FL2FXCONST_DBL(0.0f); + square_r = FL2FXCONST_DBL(0.0f); + + sL = calcSfbMaxScale(mdctSpectrumLeft,sfbOffset[sfb+sfboffs],sfbOffset[sfb+sfboffs+1]); + sR = calcSfbMaxScale(mdctSpectrumRight,sfbOffset[sfb+sfboffs],sfbOffset[sfb+sfboffs+1]); + s = fixMin(sL,sR); + + for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1]; j++) { + ml += fMultDiv2((mdctSpectrumLeft[j] << s),inv_n); // scaled with mdctScale - s + inv_n + mr += fMultDiv2((mdctSpectrumRight[j] << s),inv_n); // scaled with mdctScale - s + inv_n + } + ml = fMultDiv2(ml,inv_n); // scaled with mdctScale - s + inv_n + mr = fMultDiv2(mr,inv_n); // scaled with mdctScale - s + inv_n + + for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1]; j++) { + tmp_l = fMultDiv2((mdctSpectrumLeft[j] << s),inv_n) - ml; // scaled with mdctScale - s + inv_n + tmp_r = fMultDiv2((mdctSpectrumRight[j] << s),inv_n) - mr; // scaled with mdctScale - s + inv_n + + prod_lr += fMultDiv2(tmp_l,tmp_r); // scaled with 2*(mdctScale - s + inv_n) + 1 + square_l += fPow2Div2(tmp_l); // scaled with 2*(mdctScale - s + inv_n) + 1 + square_r += fPow2Div2(tmp_r); // scaled with 2*(mdctScale - s + inv_n) + 1 + } + prod_lr = prod_lr << 1; // scaled with 2*(mdctScale - s + inv_n) + square_l = square_l << 1; // scaled with 2*(mdctScale - s + inv_n) + square_r = square_r << 1; // scaled with 2*(mdctScale - s + inv_n) + + if (square_l > FL2FXCONST_DBL(0.0f) && square_r > FL2FXCONST_DBL(0.0f)) { + INT channelCorrSF = 0; + + /* local scaling of square_l and square_r is compensated after sqrt calculation */ + sL = fixMax(0,(CntLeadingZeros(square_l)-1)); + sR = fixMax(0,(CntLeadingZeros(square_r)-1)); + s = ((sL + sR)>>1)<<1; + sL = fixMin(sL,s); + sR = s-sL; + tmp = fMult(square_l< FL2FXCONST_DBL(0.0f)); + + /* numerator and denominator have the same scaling */ + if (prod_lr < FL2FXCONST_DBL(0.0f) ) { + channelCorr[sfb + sfboffs] = -(fDivNorm(-prod_lr,tmp,&channelCorrSF)); + + } + else { + channelCorr[sfb + sfboffs] = (fDivNorm( prod_lr,tmp,&channelCorrSF)); + } + channelCorrSF = fixMin(fixMax(( channelCorrSF + ((sL+sR)>>1)),-(DFRACT_BITS-1)),DFRACT_BITS-1); + + if (channelCorrSF < 0) { + channelCorr[sfb + sfboffs] = channelCorr[sfb + sfboffs] >> (-channelCorrSF); + } + else { + /* avoid overflows due to limited computational accuracy */ + if ( fAbs(channelCorr[sfb + sfboffs]) > (((FIXP_DBL)MAXVAL_DBL)>>channelCorrSF) ) { + if (channelCorr[sfb + sfboffs] < FL2FXCONST_DBL(0.0f)) + channelCorr[sfb + sfboffs] = -(FIXP_DBL) MAXVAL_DBL; + else + channelCorr[sfb + sfboffs] = (FIXP_DBL) MAXVAL_DBL; + } + else { + channelCorr[sfb + sfboffs] = channelCorr[sfb + sfboffs] << channelCorrSF; + } + } + } + } + + /* for post processing: hrrErr is the error in terms of (too little) correlation + * weighted with the loudness of the SFB; SFBs with small hrrErr can be merged */ + if (hrrErr[sfb + sfboffs] == FL2FXCONST_DBL(1.0/8.0)) { + continue; + } + + hrrErr[sfb + sfboffs] = fMultDiv2((FL2FXCONST_DBL(0.25f)-(channelCorr[sfb + sfboffs]>>2)),normSfbLoudness[sfb + sfboffs]); + + /* set IS mask/vector to 1, if correlation is high enough */ + if (fAbs(channelCorr[sfb + sfboffs]) >= isParams->corr_thresh) { + isMask[sfb + sfboffs] = 1; + } + } + } +} + + +/***************************************************************************** + + functionname: FDKaacEnc_finalizeIntensityDecision + + description: Finalizes intensity decision + + input: isParams scale: none + hrrErr scale: none + realIsScale scale: LD_DATA_SHIFT + REAL_SCALE_SF + normSfbLoudness scale: none + + output: isMask scale: none + + returns: none + +*****************************************************************************/ +static void +FDKaacEnc_finalizeIntensityDecision(const FIXP_DBL *hrrErr, + INT *isMask, + const FIXP_DBL *realIsScale, + const FIXP_DBL *normSfbLoudness, + const INTENSITY_PARAMETERS *isParams, + const INT sfbCnt, + const INT sfbPerGroup, + const INT maxSfbPerGroup) +{ + INT sfb,sfboffs, j; + INT startIsSfb = 0; + INT inIsBlock; + INT currentIsSfbCount; + FIXP_DBL overallHrrError; + FIXP_DBL isScaleLast = FL2FXCONST_DBL(0.0f); + FIXP_DBL isRegionLoudness; + + for (sfboffs = 0; sfboffs < sfbCnt; sfboffs += sfbPerGroup) { + inIsBlock = 0; + currentIsSfbCount = 0; + overallHrrError = FL2FXCONST_DBL(0.0f); + isRegionLoudness = FL2FXCONST_DBL(0.0f); + for (sfb = 0; sfb < maxSfbPerGroup; sfb++) { + if (isMask[sfboffs + sfb] == 1) { + if (currentIsSfbCount == 0) { + startIsSfb = sfboffs + sfb; + isScaleLast = realIsScale[sfboffs + sfb]; + } + inIsBlock = 1; + currentIsSfbCount++; + overallHrrError += hrrErr[sfboffs + sfb] >> (MAX_SFB_PER_GROUP_SF-3); + isRegionLoudness += normSfbLoudness[sfboffs + sfb] >> MAX_SFB_PER_GROUP_SF; + } + else { + /* based on correlation, IS should not be used + * -> use it anyway, if overall error is below threshold + * and if local error does not exceed threshold + * otherwise: check if there are enough IS SFBs + */ + if (inIsBlock) { + overallHrrError += hrrErr[sfboffs + sfb] >> (MAX_SFB_PER_GROUP_SF-3); + isRegionLoudness += normSfbLoudness[sfboffs + sfb] >> MAX_SFB_PER_GROUP_SF; + + if ( (hrrErr[sfboffs + sfb] < (isParams->local_error_thresh>>3)) && (overallHrrError < (isParams->total_error_thresh>>MAX_SFB_PER_GROUP_SF)) ) { + currentIsSfbCount++; + /* overwrite correlation based decision */ + isMask[sfboffs + sfb] = 1; + } else { + inIsBlock = 0; + } + } + } + /* check for large direction deviation */ + if (inIsBlock) { + if( fAbs(isScaleLast-realIsScale[sfboffs + sfb]) < (isParams->direction_deviation_thresh>>(REAL_SCALE_SF+LD_DATA_SHIFT-IS_DIRECTION_DEVIATION_THRESH_SF)) ) { + isScaleLast = realIsScale[sfboffs + sfb]; + } + else{ + isMask[sfboffs + sfb] = 0; + inIsBlock = 0; + currentIsSfbCount--; + } + } + + if (currentIsSfbCount > 0 && (!inIsBlock || sfb == maxSfbPerGroup - 1)) { + /* not enough SFBs -> do not use IS */ + if (currentIsSfbCount < isParams->min_is_sfbs || (isRegionLoudness < isParams->is_region_min_loudness>>MAX_SFB_PER_GROUP_SF)) { + for(j = startIsSfb; j <= sfboffs + sfb; j++) { + isMask[j] = 0; + } + } + currentIsSfbCount = 0; + overallHrrError = FL2FXCONST_DBL(0.0f); + isRegionLoudness = FL2FXCONST_DBL(0.0f); + } + } + } +} + + +/***************************************************************************** + + functionname: FDKaacEnc_IntensityStereoProcessing + + description: Intensity stereo processing tool + + input: sfbEnergyLeft + sfbEnergyRight + mdctSpectrumLeft + mdctSpectrumRight + sfbThresholdLeft + sfbThresholdRight + sfbSpreadEnLeft + sfbSpreadEnRight + sfbEnergyLdDataLeft + sfbEnergyLdDataRight + + output: isBook + isScale + pnsData->pnsFlag + msDigest zeroed from start to sfbCnt + msMask zeroed from start to sfbCnt + mdctSpectrumRight zeroed where isBook!=0 + sfbEnergyRight zeroed where isBook!=0 + sfbSpreadEnRight zeroed where isBook!=0 + sfbThresholdRight zeroed where isBook!=0 + sfbEnergyLdDataRight FL2FXCONST_DBL(-1.0) where isBook!=0 + sfbThresholdLdDataRight FL2FXCONST_DBL(-0.515625f) where isBook!=0 + + returns: none + +*****************************************************************************/ +void FDKaacEnc_IntensityStereoProcessing( + FIXP_DBL *sfbEnergyLeft, + FIXP_DBL *sfbEnergyRight, + FIXP_DBL *mdctSpectrumLeft, + FIXP_DBL *mdctSpectrumRight, + FIXP_DBL *sfbThresholdLeft, + FIXP_DBL *sfbThresholdRight, + FIXP_DBL *sfbThresholdLdDataRight, + FIXP_DBL *sfbSpreadEnLeft, + FIXP_DBL *sfbSpreadEnRight, + FIXP_DBL *sfbEnergyLdDataLeft, + FIXP_DBL *sfbEnergyLdDataRight, + INT *msDigest, + INT *msMask, + const INT sfbCnt, + const INT sfbPerGroup, + const INT maxSfbPerGroup, + const INT *sfbOffset, + const INT allowIS, + INT *isBook, + INT *isScale, + PNS_DATA *RESTRICT pnsData[2] + ) +{ + INT sfb,sfboffs, j; + FIXP_DBL scale; + FIXP_DBL lr; + FIXP_DBL hrrErr[MAX_GROUPED_SFB]; + FIXP_DBL normSfbLoudness[MAX_GROUPED_SFB]; + FIXP_DBL realIsScale[MAX_GROUPED_SFB]; + INTENSITY_PARAMETERS isParams; + INT isMask[MAX_GROUPED_SFB]; + + FDKmemclear((void*)isBook,sfbCnt*sizeof(INT)); + FDKmemclear((void*)isMask,sfbCnt*sizeof(INT)); + FDKmemclear((void*)realIsScale,sfbCnt*sizeof(FIXP_DBL)); + FDKmemclear((void*)isScale,sfbCnt*sizeof(INT)); + FDKmemclear((void*)hrrErr,sfbCnt*sizeof(FIXP_DBL)); + + if (!allowIS) + return; + + FDKaacEnc_initIsParams(&isParams); + + /* compute / set the following values per SFB: + * - left/right ratio between channels + * - normalized loudness + * + loudness == average of energy in channels to 0.25 + * + normalization: division by sum of all SFB loudnesses + * - isMask (is set to 0 if channels are the same or one is 0) + */ + FDKaacEnc_prepareIntensityDecision(sfbEnergyLeft, + sfbEnergyRight, + sfbEnergyLdDataLeft, + sfbEnergyLdDataRight, + mdctSpectrumLeft, + mdctSpectrumRight, + &isParams, + hrrErr, + isMask, + realIsScale, + normSfbLoudness, + sfbCnt, + sfbPerGroup, + maxSfbPerGroup, + sfbOffset); + + FDKaacEnc_finalizeIntensityDecision(hrrErr, + isMask, + realIsScale, + normSfbLoudness, + &isParams, + sfbCnt, + sfbPerGroup, + maxSfbPerGroup); + + for (sfb=0; sfb sfbThresholdRight[sfb+sfboffs]) ) { + continue; + } + /* NEW: if there is a big-enough IS region, switch off PNS */ + if (pnsData[0]) { + if(pnsData[0]->pnsFlag[sfb+sfboffs]) { + pnsData[0]->pnsFlag[sfb+sfboffs] = 0; + } + if(pnsData[1]->pnsFlag[sfb+sfboffs]) { + pnsData[1]->pnsFlag[sfb+sfboffs] = 0; + } + } + + inv_n = GetInvInt((sfbOffset[sfb + sfboffs + 1] - sfbOffset[sfb + sfboffs])>>1); // scaled with 2 to compensate fMultDiv2() in subsequent loop + sL = calcSfbMaxScale(mdctSpectrumLeft,sfbOffset[sfb+sfboffs],sfbOffset[sfb+sfboffs+1]); + sR = calcSfbMaxScale(mdctSpectrumRight,sfbOffset[sfb+sfboffs],sfbOffset[sfb+sfboffs+1]); + + lr = FL2FXCONST_DBL(0.0f); + for (j=sfbOffset[sfb+sfboffs]; j>1) - ((mdctSpectrumRight[j]<>1); + ed += fMultDiv2(d,d)>>(MDCT_SPEC_SF-1); + } + msMask[sfb+sfboffs] = 1; + tmp = fDivNorm(sfbEnergyLeft[sfb+sfboffs],ed,&s1); + s2 = (s1) + (2*s0) - 2 - MDCT_SPEC_SF; + if (s2 & 1) { + tmp = tmp>>1; + s2 = s2+1; + } + s2 = (s2>>1) + 1; // +1 compensate fMultDiv2() in subsequent loop + s2 = fixMin(fixMax(s2,-(DFRACT_BITS-1)),(DFRACT_BITS-1)); + scale = sqrtFixp(tmp); + if (s2 < 0) { + s2 = -s2; + for (j=sfbOffset[sfb+sfboffs]; j> s2; + mdctSpectrumRight[j] = FL2FXCONST_DBL(0.0f); + } + } + else { + for (j=sfbOffset[sfb+sfboffs]; j>1) + ((mdctSpectrumRight[j]<>1); + es += fMultDiv2(s,s)>>(MDCT_SPEC_SF-1); // scaled 2*(mdctScale - s0 + 1) + MDCT_SPEC_SF + } + msMask[sfb+sfboffs] = 0; + tmp = fDivNorm(sfbEnergyLeft[sfb+sfboffs],es,&s1); + s2 = (s1) + (2*s0) - 2 - MDCT_SPEC_SF; + if (s2 & 1) { + tmp = tmp>>1; + s2 = s2 + 1; + } + s2 = (s2>>1) + 1; // +1 compensate fMultDiv2() in subsequent loop + s2 = fixMin(fixMax(s2,-(DFRACT_BITS-1)),(DFRACT_BITS-1)); + scale = sqrtFixp(tmp); + if (s2 < 0) { + s2 = -s2; + for (j=sfbOffset[sfb+sfboffs]; j> s2; + mdctSpectrumRight[j] = FL2FXCONST_DBL(0.0f); + } + } + else { + for (j=sfbOffset[sfb+sfboffs]; j>1)-FL2FXCONST_DBL(0.5f/(1<<(REAL_SCALE_SF+LD_DATA_SHIFT+1))))>>(DFRACT_BITS-1-REAL_SCALE_SF-LD_DATA_SHIFT-1)) + 1; + } + else { + isScale[sfb+sfboffs] = (INT)(((realIsScale[sfb+sfboffs]>>1)+FL2FXCONST_DBL(0.5f/(1<<(REAL_SCALE_SF+LD_DATA_SHIFT+1))))>>(DFRACT_BITS-1-REAL_SCALE_SF-LD_DATA_SHIFT-1)); + } + + sfbEnergyRight[sfb+sfboffs] = FL2FXCONST_DBL(0.0f); + sfbEnergyLdDataRight[sfb+sfboffs] = FL2FXCONST_DBL(-1.0f); + sfbThresholdRight[sfb+sfboffs] = FL2FXCONST_DBL(0.0f); + sfbThresholdLdDataRight[sfb+sfboffs] = FL2FXCONST_DBL(-0.515625f); + sfbSpreadEnRight[sfb+sfboffs] = FL2FXCONST_DBL(0.0f); + + *msDigest = MS_SOME; + } + } +} + diff --git a/libAACenc/src/intensity.h b/libAACenc/src/intensity.h new file mode 100644 index 0000000..9165a22 --- /dev/null +++ b/libAACenc/src/intensity.h @@ -0,0 +1,61 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (2010) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + + Initial author: A. Horndasch (code originally from lwr and rtb) / Josef Höpfl (FDK) + contents/description: intensity stereo prototype + +******************************************************************************/ + +#ifndef _INTENSITY_H +#define _INTENSITY_H + +#include "aacenc_pns.h" + + +void FDKaacEnc_IntensityStereoProcessing( + FIXP_DBL *sfbEnergyLeft, + FIXP_DBL *sfbEnergyRight, + FIXP_DBL *mdctSpectrumLeft, + FIXP_DBL *mdctSpectrumRight, + FIXP_DBL *sfbThresholdLeft, + FIXP_DBL *sfbThresholdRight, + FIXP_DBL *sfbThresholdLdDataRight, + FIXP_DBL *sfbSpreadEnLeft, + FIXP_DBL *sfbSpreadEnRight, + FIXP_DBL *sfbEnergyLdDataLeft, + FIXP_DBL *sfbEnergyLdDataRight, + INT *msDigest, + INT *msMask, + const INT sfbCnt, + const INT sfbPerGroup, + const INT maxSfbPerGroup, + const INT *sfbOffset, + const INT allowIS, + INT *isBook, + INT *isScale, + PNS_DATA *RESTRICT pnsData[2] + ); + +#endif /* _INTENSITY_H */ + diff --git a/libAACenc/src/interface.h b/libAACenc/src/interface.h new file mode 100644 index 0000000..b6f747e --- /dev/null +++ b/libAACenc/src/interface.h @@ -0,0 +1,100 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Interface psychoaccoustic/quantizer + +******************************************************************************/ +#ifndef _INTERFACE_H +#define _INTERFACE_H + +#include "common_fix.h" + +#include "psy_data.h" +#include "aacenc_tns.h" + +enum +{ + MS_NONE = 0, + MS_SOME = 1, + MS_ALL = 2 +}; + +enum +{ + MS_ON = 1 +}; + +struct TOOLSINFO { + INT msDigest; /* 0 = no MS; 1 = some MS, 2 = all MS */ + INT msMask[MAX_GROUPED_SFB]; +}; + + +typedef struct { + INT sfbCnt; + INT sfbPerGroup; + INT maxSfbPerGroup; + INT lastWindowSequence; + INT windowShape; + INT groupingMask; + INT sfbOffsets[MAX_GROUPED_SFB+1]; + + INT mdctScale; /* number of transform shifts */ + INT groupLen[MAX_NO_OF_GROUPS]; + + TNS_INFO tnsInfo; + INT noiseNrg[MAX_GROUPED_SFB]; + INT isBook[MAX_GROUPED_SFB]; + INT isScale[MAX_GROUPED_SFB]; + + /* memory located in QC_OUT_CHANNEL */ + FIXP_DBL *mdctSpectrum; + FIXP_DBL *sfbEnergy; + FIXP_DBL *sfbSpreadEnergy; + FIXP_DBL *sfbThresholdLdData; + FIXP_DBL *sfbMinSnrLdData; + FIXP_DBL *sfbEnergyLdData; + + + }PSY_OUT_CHANNEL; + +typedef struct { + + /* information specific to each channel */ + PSY_OUT_CHANNEL* psyOutChannel[(2)]; + + /* information shared by both channels */ + INT commonWindow; + struct TOOLSINFO toolsInfo; + +} PSY_OUT_ELEMENT; + +typedef struct { + + PSY_OUT_ELEMENT* psyOutElement[(6)]; + PSY_OUT_CHANNEL* pPsyOutChannels[(6)]; + +}PSY_OUT; + +#endif /* _INTERFACE_H */ diff --git a/libAACenc/src/line_pe.cpp b/libAACenc/src/line_pe.cpp new file mode 100644 index 0000000..cf43a81 --- /dev/null +++ b/libAACenc/src/line_pe.cpp @@ -0,0 +1,145 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Werner + contents/description: Perceptual entropie module + +******************************************************************************/ + +#include "line_pe.h" +#include "sf_estim.h" +#include "bit_cnt.h" + +#include "genericStds.h" + +static const FIXP_DBL C1LdData = FL2FXCONST_DBL(3.0/LD_DATA_SCALING); /* C1 = 3.0 = log(8.0)/log(2) */ +static const FIXP_DBL C2LdData = FL2FXCONST_DBL(1.3219281/LD_DATA_SCALING); /* C2 = 1.3219281 = log(2.5)/log(2) */ +static const FIXP_DBL C3LdData = FL2FXCONST_DBL(0.5593573); /* 1-C2/C1 */ + + +/* constants that do not change during successive pe calculations */ +void FDKaacEnc_prepareSfbPe(PE_CHANNEL_DATA *peChanData, + const FIXP_DBL *sfbEnergyLdData, + const FIXP_DBL *sfbThresholdLdData, + const FIXP_DBL *sfbFormFactorLdData, + const INT *sfbOffset, + const INT sfbCnt, + const INT sfbPerGroup, + const INT maxSfbPerGroup) +{ + INT sfbGrp,sfb; + INT sfbWidth; + FIXP_DBL avgFormFactorLdData; + const FIXP_DBL formFacScaling = FL2FXCONST_DBL((float)FORM_FAC_SHIFT/LD_DATA_SCALING); + + for (sfbGrp = 0;sfbGrp < sfbCnt;sfbGrp+=sfbPerGroup) { + for (sfb=0; sfb (FIXP_DBL)sfbThresholdLdData[sfbGrp+sfb]) { + sfbWidth = sfbOffset[sfbGrp+sfb+1] - sfbOffset[sfbGrp+sfb]; + /* estimate number of active lines */ + avgFormFactorLdData = ((-sfbEnergyLdData[sfbGrp+sfb]>>1) + (CalcLdInt(sfbWidth)>>1))>>1; + peChanData->sfbNLines[sfbGrp+sfb] = + (INT)CalcInvLdData( (sfbFormFactorLdData[sfbGrp+sfb] + formFacScaling) + avgFormFactorLdData); + } + else { + peChanData->sfbNLines[sfbGrp+sfb] = 0; + } + } + } +} + +/* + formula for one sfb: + pe = n * ld(en/thr), if ld(en/thr) >= C1 + pe = n * (C2 + C3 * ld(en/thr)), if ld(en/thr) < C1 + n: estimated number of lines in sfb, + ld(x) = log(x)/log(2) + + constPart is sfbPe without the threshold part n*ld(thr) or n*C3*ld(thr) +*/ +void FDKaacEnc_calcSfbPe(PE_CHANNEL_DATA *RESTRICT peChanData, + const FIXP_DBL *RESTRICT sfbEnergyLdData, + const FIXP_DBL *RESTRICT sfbThresholdLdData, + const INT sfbCnt, + const INT sfbPerGroup, + const INT maxSfbPerGroup, + const INT *isBook, + const INT *isScale) +{ + INT sfbGrp,sfb; + INT nLines; + FIXP_DBL logDataRatio; + INT lastValIs = 0; + + peChanData->pe = 0; + peChanData->constPart = 0; + peChanData->nActiveLines = 0; + + for(sfbGrp = 0;sfbGrp < sfbCnt;sfbGrp+=sfbPerGroup){ + for (sfb=0; sfb (FIXP_DBL)sfbThresholdLdData[sfbGrp+sfb]) { + logDataRatio = (FIXP_DBL)(sfbEnergyLdData[sfbGrp+sfb] - sfbThresholdLdData[sfbGrp+sfb]); + nLines = peChanData->sfbNLines[sfbGrp+sfb]; + if (logDataRatio >= C1LdData) { + /* scale sfbPe and sfbConstPart with PE_CONSTPART_SHIFT */ + peChanData->sfbPe[sfbGrp+sfb] = fMultDiv2(logDataRatio, (FIXP_DBL)(nLines<<(LD_DATA_SHIFT+PE_CONSTPART_SHIFT+1))); + peChanData->sfbConstPart[sfbGrp+sfb] = + fMultDiv2(sfbEnergyLdData[sfbGrp+sfb], (FIXP_DBL)(nLines<<(LD_DATA_SHIFT+PE_CONSTPART_SHIFT+1))); ; + + } + else { + /* scale sfbPe and sfbConstPart with PE_CONSTPART_SHIFT */ + peChanData->sfbPe[sfbGrp+sfb] = + fMultDiv2(((FIXP_DBL)C2LdData + fMult(C3LdData,logDataRatio)), (FIXP_DBL)(nLines<<(LD_DATA_SHIFT+PE_CONSTPART_SHIFT+1))); + + peChanData->sfbConstPart[sfbGrp+sfb] = + fMultDiv2(((FIXP_DBL)C2LdData + fMult(C3LdData,sfbEnergyLdData[sfbGrp+sfb])), + (FIXP_DBL)(nLines<<(LD_DATA_SHIFT+PE_CONSTPART_SHIFT+1))) ; + + nLines = fMultI(C3LdData, nLines); + } + peChanData->sfbNActiveLines[sfbGrp+sfb] = nLines; + } + else if( isBook[sfb] ) { + /* provide for cost of scale factor for Intensity */ + INT delta = isScale[sfbGrp+sfb] - lastValIs; + lastValIs = isScale[sfbGrp+sfb]; + peChanData->sfbPe[sfbGrp+sfb] = FDKaacEnc_bitCountScalefactorDelta(delta)<sfbConstPart[sfbGrp+sfb] = 0; + peChanData->sfbNActiveLines[sfbGrp+sfb] = 0; + } + else { + peChanData->sfbPe[sfbGrp+sfb] = 0; + peChanData->sfbConstPart[sfbGrp+sfb] = 0; + peChanData->sfbNActiveLines[sfbGrp+sfb] = 0; + } + /* sum up peChanData values */ + peChanData->pe += peChanData->sfbPe[sfbGrp+sfb]; + peChanData->constPart += peChanData->sfbConstPart[sfbGrp+sfb]; + peChanData->nActiveLines += peChanData->sfbNActiveLines[sfbGrp+sfb]; + } + } + /* correct scaled pe and constPart values */ + peChanData->pe>>=PE_CONSTPART_SHIFT; + peChanData->constPart>>=PE_CONSTPART_SHIFT; +} diff --git a/libAACenc/src/line_pe.h b/libAACenc/src/line_pe.h new file mode 100644 index 0000000..418df27 --- /dev/null +++ b/libAACenc/src/line_pe.h @@ -0,0 +1,77 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Werner + contents/description: Perceptual entropie module + +******************************************************************************/ +#ifndef __LINE_PE_H +#define __LINE_PE_H + + +#include "common_fix.h" + +#include "psy_const.h" + +#define PE_CONSTPART_SHIFT FRACT_BITS + +typedef struct { + /* calculated by FDKaacEnc_prepareSfbPe */ + INT sfbNLines[MAX_GROUPED_SFB]; /* number of relevant lines in sfb */ + /* the rest is calculated by FDKaacEnc_calcSfbPe */ + INT sfbPe[MAX_GROUPED_SFB]; /* pe for each sfb */ + INT sfbConstPart[MAX_GROUPED_SFB]; /* constant part for each sfb */ + INT sfbNActiveLines[MAX_GROUPED_SFB]; /* number of active lines in sfb */ + INT pe; /* sum of sfbPe */ + INT constPart; /* sum of sfbConstPart */ + INT nActiveLines; /* sum of sfbNActiveLines */ +} PE_CHANNEL_DATA; + +typedef struct { + PE_CHANNEL_DATA peChannelData[(2)]; + INT pe; + INT constPart; + INT nActiveLines; + INT offset; +} PE_DATA; + + +void FDKaacEnc_prepareSfbPe(PE_CHANNEL_DATA *peChanData, + const FIXP_DBL *sfbEnergyLdData, + const FIXP_DBL *sfbThresholdLdData, + const FIXP_DBL *sfbFormFactorLdData, + const INT *sfbOffset, + const INT sfbCnt, + const INT sfbPerGroup, + const INT maxSfbPerGroup); + +void FDKaacEnc_calcSfbPe(PE_CHANNEL_DATA *RESTRICT peChanData, + const FIXP_DBL *RESTRICT sfbEnergyLdData, + const FIXP_DBL *RESTRICT sfbThresholdLdData, + const INT sfbCnt, + const INT sfbPerGroup, + const INT maxSfbPerGroup, + const INT *isBook, + const INT *isScale); + +#endif diff --git a/libAACenc/src/metadata_compressor.cpp b/libAACenc/src/metadata_compressor.cpp new file mode 100644 index 0000000..cfb55e9 --- /dev/null +++ b/libAACenc/src/metadata_compressor.cpp @@ -0,0 +1,965 @@ +/********************** Fraunhofer IIS FDK AAC Encoder lib ****************** + + (C) Copyright Fraunhofer IIS (2011) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Neusinger + Description: Compressor for AAC Metadata Generator + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + + +#include "metadata_compressor.h" +#include "channel_map.h" + + +#define LOG2 0.69314718056f /* natural logarithm of 2 */ +#define ILOG2 1.442695041f /* 1/LOG2 */ +#define FIXP_ILOG2_DIV2 (FL2FXCONST_DBL(ILOG2/2)) + +/*----------------- defines ----------------------*/ + +#define MAX_DRC_CHANNELS (8) /*!< Max number of audio input channels. */ +#define DOWNMIX_SHIFT (3) /*!< Max 8 channel. */ +#define WEIGHTING_FILTER_SHIFT (2) /*!< Scaling used in weighting filter. */ + +#define METADATA_INT_BITS 10 +#define METADATA_LINT_BITS 20 +#define METADATA_INT_SCALE (INT64(1)<<(METADATA_INT_BITS)) +#define METADATA_FRACT_BITS (DFRACT_BITS-1-METADATA_INT_BITS) +#define METADATA_FRACT_SCALE (INT64(1)<<(METADATA_FRACT_BITS)) + +/** + * Enum for channel assignment. + */ +enum { + L = 0, + R = 1, + C = 2, + LFE = 3, + LS = 4, + RS = 5, + S = 6, + LS2 = 7, + RS2 = 8 +}; + +/*--------------- structure definitions --------------------*/ + +/** + * Structure holds weighting filter filter states. + */ +struct WEIGHTING_STATES { + FIXP_DBL x1; + FIXP_DBL x2; + FIXP_DBL y1; + FIXP_DBL y2; +}; + +/** + * Dynamic Range Control compressor structure. + */ +struct DRC_COMP { + + FIXP_DBL maxBoostThr[2]; /*!< Max boost threshold. */ + FIXP_DBL boostThr[2]; /*!< Boost threshold. */ + FIXP_DBL earlyCutThr[2]; /*!< Early cut threshold. */ + FIXP_DBL cutThr[2]; /*!< Cut threshold. */ + FIXP_DBL maxCutThr[2]; /*!< Max cut threshold. */ + + FIXP_DBL boostFac[2]; /*!< Precalculated factor for boost compression. */ + FIXP_DBL earlyCutFac[2]; /*!< Precalculated factor for early cut compression. */ + FIXP_DBL cutFac[2]; /*!< Precalculated factor for cut compression. */ + + FIXP_DBL maxBoost[2]; /*!< Maximum boost. */ + FIXP_DBL maxCut[2]; /*!< Maximum cut. */ + FIXP_DBL maxEarlyCut[2]; /*!< Maximum early cut. */ + + FIXP_DBL fastAttack[2]; /*!< Fast attack coefficient. */ + FIXP_DBL fastDecay[2]; /*!< Fast release coefficient. */ + FIXP_DBL slowAttack[2]; /*!< Slow attack coefficient. */ + FIXP_DBL slowDecay[2]; /*!< Slow release coefficient. */ + UINT holdOff[2]; /*!< Hold time in blocks. */ + + FIXP_DBL attackThr[2]; /*!< Slow/fast attack threshold. */ + FIXP_DBL decayThr[2]; /*!< Slow/fast release threshold. */ + + DRC_PROFILE profile[2]; /*!< DRC profile. */ + INT blockLength; /*!< Block length in samples. */ + UINT sampleRate; /*!< Sample rate. */ + CHANNEL_MODE chanConfig; /*!< Channel configuration. */ + + UCHAR useWeighting; /*!< Use weighting filter. */ + + UINT channels; /*!< Number of channels. */ + UINT fullChannels; /*!< Number of full range channels. */ + INT channelIdx[9]; /*!< Offsets of interleaved channel samples (L, R, C, LFE, Ls, Rs, S, Ls2, Rs2). */ + + FIXP_DBL smoothLevel[2]; /*!< level smoothing states */ + FIXP_DBL smoothGain[2]; /*!< gain smoothing states */ + UINT holdCnt[2]; /*!< hold counter */ + + FIXP_DBL limGain[2]; /*!< limiter gain */ + FIXP_DBL limDecay; /*!< limiter decay (linear) */ + FIXP_DBL prevPeak[2]; /*!< max peak of previous block (stereo/mono)*/ + + WEIGHTING_STATES filter[MAX_DRC_CHANNELS]; /*!< array holds weighting filter states */ + +}; + +/*---------------- constants -----------------------*/ + +/** + * Profile tables. + */ +static const FIXP_DBL tabMaxBoostThr[] = { + (FIXP_DBL)(-43<limDecay = FL2FXCONST_DBL( ((0.006f / 256) * blockLength) / METADATA_INT_SCALE ); + + /* Save parameters. */ + drcComp->blockLength = blockLength; + drcComp->sampleRate = sampleRate; + drcComp->chanConfig = channelMode; + drcComp->useWeighting = useWeighting; + + if (FDK_DRC_Generator_setDrcProfile(drcComp, profileLine, profileRF)!=0) { /* expects initialized blockLength and sampleRate */ + return (-1); + } + + /* Set number of channels and channel offsets. */ + if (FDKaacEnc_InitChannelMapping(channelMode, channelOrder, &channelMapping)!=AAC_ENC_OK) { + return (-2); + } + + for (i = 0; i < 9; i++) drcComp->channelIdx[i] = -1; + + switch (channelMode) { + case MODE_1: /* mono */ + drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0]; + break; + case MODE_2: /* stereo */ + drcComp->channelIdx[L] = channelMapping.elInfo[0].ChannelIndex[0]; + drcComp->channelIdx[R] = channelMapping.elInfo[0].ChannelIndex[1]; + break; + case MODE_1_2: /* 3ch */ + drcComp->channelIdx[L] = channelMapping.elInfo[1].ChannelIndex[0]; + drcComp->channelIdx[R] = channelMapping.elInfo[1].ChannelIndex[1]; + drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0]; + break; + case MODE_1_2_1: /* 4ch */ + drcComp->channelIdx[L] = channelMapping.elInfo[1].ChannelIndex[0]; + drcComp->channelIdx[R] = channelMapping.elInfo[1].ChannelIndex[1]; + drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0]; + drcComp->channelIdx[S] = channelMapping.elInfo[2].ChannelIndex[0]; + break; + case MODE_1_2_2: /* 5ch */ + drcComp->channelIdx[L] = channelMapping.elInfo[1].ChannelIndex[0]; + drcComp->channelIdx[R] = channelMapping.elInfo[1].ChannelIndex[1]; + drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0]; + drcComp->channelIdx[LS] = channelMapping.elInfo[2].ChannelIndex[0]; + drcComp->channelIdx[RS] = channelMapping.elInfo[2].ChannelIndex[1]; + break; + case MODE_1_2_2_1: /* 5.1 ch */ + drcComp->channelIdx[L] = channelMapping.elInfo[1].ChannelIndex[0]; + drcComp->channelIdx[R] = channelMapping.elInfo[1].ChannelIndex[1]; + drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0]; + drcComp->channelIdx[LFE] = channelMapping.elInfo[3].ChannelIndex[0]; + drcComp->channelIdx[LS] = channelMapping.elInfo[2].ChannelIndex[0]; + drcComp->channelIdx[RS] = channelMapping.elInfo[2].ChannelIndex[1]; + break; + case MODE_1_2_2_2_1: /* 7.1 ch */ + drcComp->channelIdx[L] = channelMapping.elInfo[1].ChannelIndex[0]; + drcComp->channelIdx[R] = channelMapping.elInfo[1].ChannelIndex[1]; + drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0]; + drcComp->channelIdx[LFE] = channelMapping.elInfo[4].ChannelIndex[0]; + drcComp->channelIdx[LS] = channelMapping.elInfo[2].ChannelIndex[0]; + drcComp->channelIdx[RS] = channelMapping.elInfo[2].ChannelIndex[1]; + drcComp->channelIdx[LS2] = channelMapping.elInfo[3].ChannelIndex[0]; + drcComp->channelIdx[RS2] = channelMapping.elInfo[3].ChannelIndex[1]; + break; + case MODE_1_1: + case MODE_1_1_1_1: + case MODE_1_1_1_1_1_1: + case MODE_1_1_1_1_1_1_1_1: + case MODE_1_1_1_1_1_1_1_1_1_1_1_1: + case MODE_2_2: + case MODE_2_2_2: + case MODE_2_2_2_2: + case MODE_2_2_2_2_2_2: + default: + return (-1); + } + + drcComp->fullChannels = channelMapping.nChannelsEff; + drcComp->channels = channelMapping.nChannels; + + /* Init states. */ + drcComp->smoothLevel[0] = drcComp->smoothLevel[1] = (FIXP_DBL)(-135<smoothGain, sizeof(drcComp->smoothGain)); + FDKmemclear(drcComp->holdCnt, sizeof(drcComp->holdCnt)); + FDKmemclear(drcComp->limGain, sizeof(drcComp->limGain)); + FDKmemclear(drcComp->prevPeak, sizeof(drcComp->prevPeak)); + FDKmemclear(drcComp->filter, sizeof(drcComp->filter)); + + return (0); +} + + +INT FDK_DRC_Generator_setDrcProfile( + HDRC_COMP drcComp, + const DRC_PROFILE profileLine, + const DRC_PROFILE profileRF + ) +{ + int profileIdx, i; + + drcComp->profile[0] = profileLine; + drcComp->profile[1] = profileRF; + + for (i = 0; i < 2; i++) { + /* get profile index */ + switch (drcComp->profile[i]) { + case DRC_NONE: + case DRC_FILMSTANDARD: profileIdx = 0; break; + case DRC_FILMLIGHT: profileIdx = 1; break; + case DRC_MUSICSTANDARD: profileIdx = 2; break; + case DRC_MUSICLIGHT: profileIdx = 3; break; + case DRC_SPEECH: profileIdx = 4; break; + case DRC_DELAY_TEST: profileIdx = 5; break; + default: return (-1); + } + + /* get parameters for selected profile */ + if (profileIdx >= 0) { + drcComp->maxBoostThr[i] = tabMaxBoostThr[profileIdx]; + drcComp->boostThr[i] = tabBoostThr[profileIdx]; + drcComp->earlyCutThr[i] = tabEarlyCutThr[profileIdx]; + drcComp->cutThr[i] = tabCutThr[profileIdx]; + drcComp->maxCutThr[i] = tabMaxCutThr[profileIdx]; + + drcComp->boostFac[i] = tabBoostRatio[profileIdx]; + drcComp->earlyCutFac[i] = tabEarlyCutRatio[profileIdx]; + drcComp->cutFac[i] = tabCutRatio[profileIdx]; + + drcComp->maxBoost[i] = tabMaxBoost[profileIdx]; + drcComp->maxCut[i] = tabMaxCut[profileIdx]; + drcComp->maxEarlyCut[i] = - fMult((drcComp->cutThr[i] - drcComp->earlyCutThr[i]), drcComp->earlyCutFac[i]); /* no scaling after mult needed, earlyCutFac is in FIXP_DBL */ + + drcComp->fastAttack[i] = tc2Coeff(tabFastAttack[profileIdx], drcComp->sampleRate, drcComp->blockLength); + drcComp->fastDecay[i] = tc2Coeff(tabFastDecay[profileIdx], drcComp->sampleRate, drcComp->blockLength); + drcComp->slowAttack[i] = tc2Coeff(tabSlowAttack[profileIdx], drcComp->sampleRate, drcComp->blockLength); + drcComp->slowDecay[i] = tc2Coeff(tabSlowDecay[profileIdx], drcComp->sampleRate, drcComp->blockLength); + drcComp->holdOff[i] = tabHoldOff[profileIdx] * 256 / drcComp->blockLength; + + drcComp->attackThr[i] = tabAttackThr[profileIdx]; + drcComp->decayThr[i] = tabDecayThr[profileIdx]; + } + + drcComp->smoothGain[i] = FL2FXCONST_DBL(0.f); + } + return (0); +} + + +INT FDK_DRC_Generator_Calc( + HDRC_COMP drcComp, + const INT_PCM * const inSamples, + const INT dialnorm, + const INT drc_TargetRefLevel, + const INT comp_TargetRefLevel, + FIXP_DBL clev, + FIXP_DBL slev, + INT * const pDynrng, + INT * const pCompr + ) +{ + int i, c; + FIXP_DBL peak[2]; + + + /************************************************************************** + * compressor + **************************************************************************/ + if ((drcComp->profile[0] != DRC_NONE) || (drcComp->profile[1] != DRC_NONE)) { + /* Calc loudness level */ + FIXP_DBL level_b = FL2FXCONST_DBL(0.f); + int level_e = DFRACT_BITS-1; + + /* Increase energy time resolution with shorter processing blocks. 32 is an empiric value. */ + const int granuleLength = fixMin(32, drcComp->blockLength); + + if (drcComp->useWeighting) { + FIXP_DBL x1, x2, y, y1, y2; + /* sum of filter coefficients about 2.5 -> squared value is 6.25 + WEIGHTING_FILTER_SHIFT is 2 -> scaling about 16, therefore reduce granuleShift by 1. + */ + const int granuleShift = getShiftFactor(granuleLength)-1; + + for (c = 0; c < (int)drcComp->channels; c++) { + const INT_PCM* pSamples = &inSamples[c]; + + if (c == drcComp->channelIdx[LFE]) { + continue; /* skip LFE */ + } + + /* get filter states */ + x1 = drcComp->filter[c].x1; + x2 = drcComp->filter[c].x2; + y1 = drcComp->filter[c].y1; + y2 = drcComp->filter[c].y2; + + i = 0; + + do { + + int offset = i; + FIXP_DBL accu = FL2FXCONST_DBL(0.f); + + for (i=offset; i < fixMin(offset+granuleLength,drcComp->blockLength); i++) { + /* apply weighting filter */ + FIXP_DBL x = FX_PCM2FX_DBL((FIXP_PCM)pSamples[i*drcComp->channels]) >> WEIGHTING_FILTER_SHIFT; + + /* y = b0 * (x - x2) - a1 * y1 - a2 * y2; */ + y = fMult(b0,x-x2) - fMult(a1,y1) - fMult(a2,y2); + + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + + accu += fPow2Div2(y)>>(granuleShift-1); /* partial energy */ + } /* i */ + + fixpAdd(accu, granuleShift+2*WEIGHTING_FILTER_SHIFT, &level_b, &level_e); /* sup up partial energies */ + + } while ( i < drcComp->blockLength ); + + + /* save filter states */ + drcComp->filter[c].x1 = x1; + drcComp->filter[c].x2 = x2; + drcComp->filter[c].y1 = y1; + drcComp->filter[c].y2 = y2; + } /* c */ + } /* weighting */ + else { + const int granuleShift = getShiftFactor(granuleLength); + + for (c = 0; c < (int)drcComp->channels; c++) { + const INT_PCM* pSamples = &inSamples[c]; + + if ((int)c == drcComp->channelIdx[LFE]) { + continue; /* skip LFE */ + } + + i = 0; + + do { + int offset = i; + FIXP_DBL accu = FL2FXCONST_DBL(0.f); + + for (i=offset; i < fixMin(offset+granuleLength,drcComp->blockLength); i++) { + /* partial energy */ + accu += fPow2Div2((FIXP_PCM)pSamples[i*drcComp->channels])>>(granuleShift-1); + } /* i */ + + fixpAdd(accu, granuleShift, &level_b, &level_e); /* sup up partial energies */ + + } while ( i < drcComp->blockLength ); + } + } /* weighting */ + + /* + * Convert to dBFS, apply dialnorm + */ + /* level scaling */ + + /* descaled level in ld64 representation */ + FIXP_DBL ldLevel = CalcLdData(level_b) + (FIXP_DBL)((level_e-12)<<(DFRACT_BITS-1-LD_DATA_SHIFT)) - CalcLdData((FIXP_DBL)(drcComp->blockLength<<(DFRACT_BITS-1-12))); + + /* if (level < 1e-10) level = 1e-10f; */ + ldLevel = FDKmax(ldLevel, FL2FXCONST_DBL(-0.51905126482615036685473741085772f)); + + /* level = 10 * log(level)/log(10) + 3; + * = 10*log(2)/log(10) * ld(level) + 3; + * = 10 * 0.30102999566398119521373889472449 * ld(level) + 3 + * = 10 * (0.30102999566398119521373889472449 * ld(level) + 0.3) + * = 10 * (0.30102999566398119521373889472449 * ld64(level) + 0.3/64) * 64 + * + * additional scaling with METADATA_FRACT_BITS: + * = 10 * (0.30102999566398119521373889472449 * ld64(level) + 0.3/64) * 64 * 2^(METADATA_FRACT_BITS) + * = 10 * (0.30102999566398119521373889472449 * ld64(level) + 0.3/64) * 2^(METADATA_FRACT_BITS+LD_DATA_SHIFT) + * = 10*2^(METADATA_FRACT_BITS+LD_DATA_SHIFT) * ( 0.30102999566398119521373889472449 * ld64(level) + 0.3/64 ) + * */ + FIXP_DBL level = fMult((FIXP_DBL)(10<<(METADATA_FRACT_BITS+LD_DATA_SHIFT)), fMult( FL2FXCONST_DBL(0.30102999566398119521373889472449f), ldLevel) + (FIXP_DBL)(FL2FXCONST_DBL(0.3f)>>LD_DATA_SHIFT) ); + + /* level -= dialnorm + 31 */ /* this is fixed to Dolby-ReferenceLevel as compressor profiles are defined relative to this */ + level -= ((FIXP_DBL)(dialnorm<<(METADATA_FRACT_BITS-16)) + (FIXP_DBL)(31<profile[i] == DRC_NONE) { + /* no compression */ + drcComp->smoothGain[i] = FL2FXCONST_DBL(0.f); + } + else { + FIXP_DBL gain, alpha, lvl2smthlvl; + + /* calc static gain */ + if (level <= drcComp->maxBoostThr[i]) { + /* max boost */ + gain = drcComp->maxBoost[i]; + } + else if (level < drcComp->boostThr[i]) { + /* boost range */ + gain = fMult((level - drcComp->boostThr[i]),drcComp->boostFac[i]); + } + else if (level <= drcComp->earlyCutThr[i]) { + /* null band */ + gain = FL2FXCONST_DBL(0.f); + } + else if (level <= drcComp->cutThr[i]) { + /* early cut range */ + gain = fMult((level - drcComp->earlyCutThr[i]), drcComp->earlyCutFac[i]); + } + else if (level < drcComp->maxCutThr[i]) { + /* cut range */ + gain = fMult((level - drcComp->cutThr[i]), drcComp->cutFac[i]) - drcComp->maxEarlyCut[i]; + } + else { + /* max cut */ + gain = -drcComp->maxCut[i]; + } + + /* choose time constant */ + lvl2smthlvl = level - drcComp->smoothLevel[i]; + if (gain < drcComp->smoothGain[i]) { + /* attack */ + if (lvl2smthlvl > drcComp->attackThr[i]) { + /* fast attack */ + alpha = drcComp->fastAttack[i]; + } + else { + /* slow attack */ + alpha = drcComp->slowAttack[i]; + } + } + else { + /* release */ + if (lvl2smthlvl < -drcComp->decayThr[i]) { + /* fast release */ + alpha = drcComp->fastDecay[i]; + } + else { + /* slow release */ + alpha = drcComp->slowDecay[i]; + } + } + + /* smooth gain & level */ + if ((gain < drcComp->smoothGain[i]) || (drcComp->holdCnt[i] == 0)) { /* hold gain unless we have an attack or hold period is over */ + FIXP_DBL accu; + + /* drcComp->smoothLevel[i] = (1-alpha) * drcComp->smoothLevel[i] + alpha * level; */ + accu = fMult((FL2FXCONST_DBL(1.f)-alpha), drcComp->smoothLevel[i]); + accu += fMult(alpha,level); + drcComp->smoothLevel[i] = accu; + + /* drcComp->smoothGain[i] = (1-alpha) * drcComp->smoothGain[i] + alpha * gain; */ + accu = fMult((FL2FXCONST_DBL(1.f)-alpha), drcComp->smoothGain[i]); + accu += fMult(alpha,gain); + drcComp->smoothGain[i] = accu; + } + + /* hold counter */ + if (drcComp->holdCnt[i]) { + drcComp->holdCnt[i]--; + } + if (gain < drcComp->smoothGain[i]) { + drcComp->holdCnt[i] = drcComp->holdOff[i]; + } + } /* profile != DRC_NONE */ + } /* for i=1..2 */ + } else { + /* no compression */ + drcComp->smoothGain[0] = FL2FXCONST_DBL(0.f); + drcComp->smoothGain[1] = FL2FXCONST_DBL(0.f); + } + + /************************************************************************** + * limiter + **************************************************************************/ + + /* find peak level */ + peak[0] = peak[1] = FL2FXCONST_DBL(0.f); + for (i = 0; i < drcComp->blockLength; i++) { + FIXP_DBL tmp; + const INT_PCM* pSamples = &inSamples[i*drcComp->channels]; + INT_PCM maxSample = 0; + + /* single channels */ + for (c = 0; c < (int)drcComp->channels; c++) { + maxSample = FDKmax(maxSample, fAbs(pSamples[c])); + } + peak[0] = fixMax(peak[0], FX_PCM2FX_DBL(maxSample)>>DOWNMIX_SHIFT); + + /* Lt/Rt downmix */ + if (drcComp->fullChannels > 2) { + /* Lt */ + tmp = FL2FXCONST_DBL(0.f); + + if (drcComp->channelIdx[LS] >= 0) tmp -= fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[LS]])>>(DOWNMIX_SHIFT-1); /* Ls */ + if (drcComp->channelIdx[LS2] >= 0) tmp -= fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[LS2]])>>(DOWNMIX_SHIFT-1); /* Ls2 */ + if (drcComp->channelIdx[RS] >= 0) tmp -= fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[RS]])>>(DOWNMIX_SHIFT-1); /* Rs */ + if (drcComp->channelIdx[RS2] >= 0) tmp -= fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[RS2]])>>(DOWNMIX_SHIFT-1); /* Rs2 */ + if ((drcComp->channelIdx[LS] >= 0) && (drcComp->channelIdx[LS2] >= 0)) tmp = fMult(FL2FXCONST_DBL(0.707f), tmp); /* 7.1ch */ + if (drcComp->channelIdx[S] >= 0) tmp -= fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[S]])>>(DOWNMIX_SHIFT-1); /* S */ + if (drcComp->channelIdx[C] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[C]])>>(DOWNMIX_SHIFT-1); /* C */ + tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[L]])>>DOWNMIX_SHIFT); /* L */ + + peak[0] = fixMax(peak[0], fixp_abs(tmp)); + + /* Rt */ + tmp = FL2FXCONST_DBL(0.f); + if (drcComp->channelIdx[LS] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[LS]])>>(DOWNMIX_SHIFT-1); /* Ls */ + if (drcComp->channelIdx[LS2] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[LS2]])>>(DOWNMIX_SHIFT-1); /* Ls2 */ + if (drcComp->channelIdx[RS] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[RS]])>>(DOWNMIX_SHIFT-1); /* Rs */ + if (drcComp->channelIdx[RS2] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[RS2]])>>(DOWNMIX_SHIFT-1); /* Rs2 */ + if ((drcComp->channelIdx[RS] >= 0) && (drcComp->channelIdx[RS2] >= 0)) tmp = fMult(FL2FXCONST_DBL(0.707f), tmp); /* 7.1ch */ + if (drcComp->channelIdx[S] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[S]])>>(DOWNMIX_SHIFT-1); /* S */ + if (drcComp->channelIdx[C] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[C]])>>(DOWNMIX_SHIFT-1); /* C */ + tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[R]])>>DOWNMIX_SHIFT); /* R */ + + peak[0] = fixMax(peak[0], fixp_abs(tmp)); + } + + /* Lo/Ro downmix */ + if (drcComp->fullChannels > 2) { + /* Lo */ + tmp = FL2FXCONST_DBL(0.f); + if (drcComp->channelIdx[LS] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[LS]])>>(DOWNMIX_SHIFT-1); /* Ls */ + if (drcComp->channelIdx[LS2] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[LS2]])>>(DOWNMIX_SHIFT-1); /* Ls2 */ + if ((drcComp->channelIdx[LS] >= 0) && (drcComp->channelIdx[LS2] >= 0)) tmp = fMult(FL2FXCONST_DBL(0.707f), tmp); /* 7.1ch */ + if (drcComp->channelIdx[S] >= 0) tmp += fMultDiv2(slev, fMult(FL2FXCONST_DBL(0.7f), (FIXP_PCM)pSamples[drcComp->channelIdx[S]]))>>(DOWNMIX_SHIFT-1); /* S */ + if (drcComp->channelIdx[C] >= 0) tmp += fMultDiv2(clev, (FIXP_PCM)pSamples[drcComp->channelIdx[C]])>>(DOWNMIX_SHIFT-1); /* C */ + tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[L]])>>DOWNMIX_SHIFT); /* L */ + + peak[0] = fixMax(peak[0], fixp_abs(tmp)); + + /* Ro */ + tmp = FL2FXCONST_DBL(0.f); + if (drcComp->channelIdx[RS] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[RS]])>>(DOWNMIX_SHIFT-1); /* Rs */ + if (drcComp->channelIdx[RS2] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[RS2]])>>(DOWNMIX_SHIFT-1); /* Rs2 */ + if ((drcComp->channelIdx[RS] >= 0) && (drcComp->channelIdx[RS2] >= 0)) tmp = fMult(FL2FXCONST_DBL(0.707f), tmp); /* 7.1ch */ + if (drcComp->channelIdx[S] >= 0) tmp += fMultDiv2(slev, fMult(FL2FXCONST_DBL(0.7f), (FIXP_PCM)pSamples[drcComp->channelIdx[S]]))>>(DOWNMIX_SHIFT-1); /* S */ + if (drcComp->channelIdx[C] >= 0) tmp += fMultDiv2(clev, (FIXP_PCM)pSamples[drcComp->channelIdx[C]])>>(DOWNMIX_SHIFT-1); /* C */ + tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[R]])>>DOWNMIX_SHIFT); /* R */ + + peak[0] = fixMax(peak[0], fixp_abs(tmp)); + } + + peak[1] = fixMax(peak[0], peak[1]); + + /* Mono Downmix - for comp_val only */ + if (drcComp->fullChannels > 1) { + tmp = FL2FXCONST_DBL(0.f); + if (drcComp->channelIdx[LS] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[LS]])>>(DOWNMIX_SHIFT-1); /* Ls */ + if (drcComp->channelIdx[LS2] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[LS2]])>>(DOWNMIX_SHIFT-1); /* Ls2 */ + if (drcComp->channelIdx[RS] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[RS]])>>(DOWNMIX_SHIFT-1); /* Rs */ + if (drcComp->channelIdx[RS2] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[RS2]])>>(DOWNMIX_SHIFT-1); /* Rs2 */ + if ((drcComp->channelIdx[LS] >= 0) && (drcComp->channelIdx[LS2] >= 0)) tmp = fMult(FL2FXCONST_DBL(0.707f), tmp); /* 7.1ch */ + /*if ((drcComp->channelIdx[RS] >= 0) && (drcComp->channelIdx[RS2] >= 0)) tmp *=0.707f;*/ /* 7.1ch */ + if (drcComp->channelIdx[S] >= 0) tmp += fMultDiv2(slev, fMult(FL2FXCONST_DBL(0.7f), (FIXP_PCM)pSamples[drcComp->channelIdx[S]]))>>(DOWNMIX_SHIFT-1); /* S */ + if (drcComp->channelIdx[C] >= 0) tmp += fMultDiv2(clev, (FIXP_PCM)pSamples[drcComp->channelIdx[C]])>>(DOWNMIX_SHIFT-1); /* C */ + tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[L]])>>DOWNMIX_SHIFT); /* L */ + tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[R]])>>DOWNMIX_SHIFT); /* R */ + + peak[1] = fixMax(peak[1], fixp_abs(tmp)); + } + } + + for (i=0; i<2; i++) { + FIXP_DBL tmp = drcComp->prevPeak[i]; + drcComp->prevPeak[i] = peak[i]; + peak[i] = fixMax(peak[i], tmp); + + /* + * Convert to dBFS, apply dialnorm + */ + /* descaled peak in ld64 representation */ + FIXP_DBL ld_peak = CalcLdData(peak[i]) + (FIXP_DBL)((LONG)DOWNMIX_SHIFT<<(DFRACT_BITS-1-LD_DATA_SHIFT)); + + /* if (peak < 1e-6) level = 1e-6f; */ + ld_peak = FDKmax(ld_peak, FL2FXCONST_DBL(-0.31143075889569022011284244651463f)); + + /* peak[i] = 20 * log(peak[i])/log(10) + 0.2f + (drcComp->smoothGain[i]*2^METADATA_FRACT_BITS) + * peak[i] = 20 * log(2)/log(10) * ld(peak[i]) + 0.2f + (drcComp->smoothGain[i]*2^METADATA_FRACT_BITS) + * peak[i] = 10 * 2*0.30102999566398119521373889472449 * ld(peak[i]) + 0.2f + (drcComp->smoothGain[i]*2^METADATA_FRACT_BITS) + * + * additional scaling with METADATA_FRACT_BITS: + * peak[i] = (10 * 2*0.30102999566398119521373889472449 * ld64(peak[i]) * 64 + 0.2f + (drcComp->smoothGain[i]*2^METADATA_FRACT_BITS))*2^(-METADATA_FRACT_BITS) + * peak[i] = 10*2^(METADATA_FRACT_BITS+LD_DATA_SHIFT) * 2*0.30102999566398119521373889472449 * ld64(peak[i]) + * + 0.2f*2^(-METADATA_FRACT_BITS) + drcComp->smoothGain[i] + */ + peak[i] = fMult((FIXP_DBL)(10<<(METADATA_FRACT_BITS+LD_DATA_SHIFT)), fMult( FL2FX_DBL(2*0.30102999566398119521373889472449f), ld_peak)); + peak[i] += (FL2FX_DBL(0.2f)>>METADATA_INT_BITS); /* add a little bit headroom */ + peak[i] += drcComp->smoothGain[i]; + } + + /* peak -= dialnorm + 31; */ /* this is Dolby style only */ + peak[0] -= (FIXP_DBL)((dialnorm-drc_TargetRefLevel)<<(METADATA_FRACT_BITS-16)); /* peak[0] -= dialnorm - drc_TargetRefLevel */ + + /* peak += 11; */ /* this is Dolby style only */ /* RF mode output is 11dB higher */ + /*peak += comp_TargetRefLevel - drc_TargetRefLevel;*/ + peak[1] -= (FIXP_DBL)((dialnorm-comp_TargetRefLevel)<<(METADATA_FRACT_BITS-16)); /* peak[1] -= dialnorm - comp_TargetRefLevel */ + + /* limiter gain */ + drcComp->limGain[0] += drcComp->limDecay; /* linear limiter release */ + drcComp->limGain[0] = fixMin(drcComp->limGain[0], -peak[0]); + + drcComp->limGain[1] += 2*drcComp->limDecay; /* linear limiter release */ + drcComp->limGain[1] = fixMin(drcComp->limGain[1], -peak[1]); + + /*************************************************************************/ + + /* apply limiting, return DRC gains*/ + { + FIXP_DBL tmp; + + tmp = drcComp->smoothGain[0]; + if (drcComp->limGain[0] < FL2FXCONST_DBL(0.f)) { + tmp += drcComp->limGain[0]; + } + *pDynrng = (LONG) scaleValue(tmp, -(METADATA_FRACT_BITS-16)); + + tmp = drcComp->smoothGain[1]; + if (drcComp->limGain[1] < FL2FXCONST_DBL(0.f)) { + tmp += drcComp->limGain[1]; + } + *pCompr = (LONG) scaleValue(tmp, -(METADATA_FRACT_BITS-16)); + } + + return 0; +} + + +DRC_PROFILE FDK_DRC_Generator_getDrcProfile(const HDRC_COMP drcComp) +{ + return drcComp->profile[0]; +} + +DRC_PROFILE FDK_DRC_Generator_getCompProfile(const HDRC_COMP drcComp) +{ + return drcComp->profile[1]; +} + + diff --git a/libAACenc/src/metadata_compressor.h b/libAACenc/src/metadata_compressor.h new file mode 100644 index 0000000..1d53f81 --- /dev/null +++ b/libAACenc/src/metadata_compressor.h @@ -0,0 +1,190 @@ +/********************** Fraunhofer IIS FDK AAC Encoder lib ****************** + + (C) Copyright Fraunhofer IIS (2011) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Neusinger + Description: Compressor for AAC Metadata Generator + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef _METADATA_COMPRESSOR_H +#define _METADATA_COMPRESSOR_H + + +#include "FDK_audio.h" +#include "common_fix.h" + +#include "aacenc.h" + + +/** + * DRC compression profiles. + */ +typedef enum DRC_PROFILE { + DRC_NONE = 0, + DRC_FILMSTANDARD = 1, + DRC_FILMLIGHT = 2, + DRC_MUSICSTANDARD = 3, + DRC_MUSICLIGHT = 4, + DRC_SPEECH = 5, + DRC_DELAY_TEST = 6 + +} DRC_PROFILE; + + +/** + * DRC Compressor handle. + */ +typedef struct DRC_COMP DRC_COMP, *HDRC_COMP; + +/** + * \brief Open a DRC Compressor instance. + * + * Allocate memory for a compressor instance. + * + * \param phDrcComp A pointer to a compressor handle. Initialized on return. + * + * \return + * - 0, on succes. + * - unequal 0, on failure. + */ +INT FDK_DRC_Generator_Open( + HDRC_COMP *phDrcComp + ); + + +/** + * \brief Close the DRC Compressor instance. + * + * Deallocate instance and free whole memory. + * + * \param phDrcComp Pointer to the compressor handle to be deallocated. + * + * \return + * - 0, on succes. + * - unequal 0, on failure. + */ +INT FDK_DRC_Generator_Close( + HDRC_COMP *phDrcComp + ); + +/** + * \brief Configure DRC Compressor. + * + * \param drcComp Compressor handle. + * \param profileLine DRC profile for line mode. + * \param profileRF DRC profile for RF mode. + * \param blockLength Length of processing block in samples per channel. + * \param sampleRate Sampling rate in Hz. + * \param channelMode Channel configuration. + * \param channelOrder Channel order, MPEG or WAV. + * \param useWeighting Use weighting filter for loudness calculation + * + * \return + * - 0, on success, + * - unequal 0, on failure + */ +INT FDK_DRC_Generator_Initialize( + HDRC_COMP drcComp, + const DRC_PROFILE profileLine, + const DRC_PROFILE profileRF, + const INT blockLength, + const UINT sampleRate, + const CHANNEL_MODE channelMode, + const CHANNEL_ORDER channelOrder, + const UCHAR useWeighting + ); + +/** + * \brief Calculate DRC Compressor Gain. + * + * \param drcComp Compressor handle. + * \param inSamples Pointer to interleaved input audio samples. + * \param dialnorm Dialog Level in dB (typically -31...-1). + * \param drc_TargetRefLevel + * \param comp_TargetRefLevel + * \param clev Downmix center mix factor (typically 0.707, 0.595 or 0.5) + * \param slev Downmix surround mix factor (typically 0.707, 0.5, or 0) + * \param dynrng Pointer to variable receiving line mode DRC gain in dB + * \param compr Pointer to variable receiving RF mode DRC gain in dB + * + * \return + * - 0, on success, + * - unequal 0, on failure + */ +INT FDK_DRC_Generator_Calc( + HDRC_COMP drcComp, + const INT_PCM * const inSamples, + const INT dialnorm, + const INT drc_TargetRefLevel, + const INT comp_TargetRefLevel, + FIXP_DBL clev, + FIXP_DBL slev, + INT * const dynrng, + INT * const compr + ); + + +/** + * \brief Configure DRC Compressor Profile. + * + * \param drcComp Compressor handle. + * \param profileLine DRC profile for line mode. + * \param profileRF DRC profile for RF mode. + * + * \return + * - 0, on success, + * - unequal 0, on failure + */ +INT FDK_DRC_Generator_setDrcProfile( + HDRC_COMP drcComp, + const DRC_PROFILE profileLine, + const DRC_PROFILE profileRF + ); + + +/** + * \brief Get DRC profile for line mode. + * + * \param drcComp Compressor handle. + * + * \return Current Profile. + */ +DRC_PROFILE FDK_DRC_Generator_getDrcProfile( + const HDRC_COMP drcComp + ); + + +/** + * \brief Get DRC profile for RF mode. + * + * \param drcComp Compressor handle. + * + * \return Current Profile. + */ +DRC_PROFILE FDK_DRC_Generator_getCompProfile( + const HDRC_COMP drcComp + ); + + +#endif /* _METADATA_COMPRESSOR_H */ + diff --git a/libAACenc/src/metadata_main.cpp b/libAACenc/src/metadata_main.cpp new file mode 100644 index 0000000..f02ba3b --- /dev/null +++ b/libAACenc/src/metadata_main.cpp @@ -0,0 +1,809 @@ +/********************** Fraunhofer IIS FDK AAC Encoder lib ****************** + + (C) Copyright Fraunhofer IIS (2011) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): V. Bacigalupo + Description: Metadata Encoder library interface functions + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + + +#include "metadata_main.h" +#include "metadata_compressor.h" +#include "FDK_bitstream.h" +#include "FDK_audio.h" +#include "genericStds.h" + +/*----------------- defines ----------------------*/ +#define MAX_DRC_BANDS (1<<4) +#define MAX_DRC_CHANNELS (8) +#define MAX_DRC_FRAMELEN (2*1024) + +/*--------------- structure definitions --------------------*/ + +typedef struct AAC_METADATA +{ + /* MPEG: Dynamic Range Control */ + struct { + UCHAR prog_ref_level_present; + SCHAR prog_ref_level; + + UCHAR dyn_rng_sgn[MAX_DRC_BANDS]; + UCHAR dyn_rng_ctl[MAX_DRC_BANDS]; + + UCHAR drc_bands_present; + UCHAR drc_band_incr; + UCHAR drc_band_top[MAX_DRC_BANDS]; + UCHAR drc_interpolation_scheme; + AACENC_METADATA_DRC_PROFILE drc_profile; + INT drc_TargetRefLevel; /* used for Limiter */ + + /* excluded channels */ + UCHAR excluded_chns_present; + UCHAR exclude_mask[2]; /* MAX_NUMBER_CHANNELS/8 */ + } mpegDrc; + + /* ETSI: addtl ancillary data */ + struct { + /* Heavy Compression */ + UCHAR compression_on; /* flag, if compression value should be written */ + UCHAR compression_value; /* compression value */ + AACENC_METADATA_DRC_PROFILE comp_profile; + INT comp_TargetRefLevel; /* used for Limiter */ + INT timecode_coarse_status; + INT timecode_fine_status; + } etsiAncData; + + SCHAR centerMixLevel; /* center downmix level (0...7, according to table) */ + SCHAR surroundMixLevel; /* surround downmix level (0...7, according to table) */ + UCHAR WritePCEMixDwnIdx; /* flag */ + UCHAR DmxLvl_On; /* flag */ + + UCHAR dolbySurroundMode; + + UCHAR metadataMode; /* indicate meta data mode in current frame (delay line) */ + +} AAC_METADATA; + +struct FDK_METADATA_ENCODER +{ + INT metadataMode; + HDRC_COMP hDrcComp; + AACENC_MetaData submittedMetaData; + + INT nAudioDataDelay; + INT nMetaDataDelay; + INT nChannels; + + INT_PCM audioDelayBuffer[MAX_DRC_CHANNELS*MAX_DRC_FRAMELEN]; + int audioDelayIdx; + + AAC_METADATA metaDataBuffer[3]; + int metaDataDelayIdx; + + UCHAR drcInfoPayload[12]; + UCHAR drcDsePayload[8]; + + INT matrix_mixdown_idx; + AACENC_EXT_PAYLOAD exPayload[2]; + INT nExtensions; + + INT finalizeMetaData; /* Delay switch off by one frame and write default configuration to + finalize the metadata setup. */ +}; + + +/*---------------- constants -----------------------*/ +static const AACENC_MetaData defaultMetaDataSetup = { + AACENC_METADATA_DRC_NONE, + AACENC_METADATA_DRC_NONE, + -(31<<16), + -(31<<16), + 0, + -(31<<16), + 0, + 0, + 0, + 0, + 0 +}; + +static const FIXP_DBL dmxTable[8] = { + ((FIXP_DBL)MAXVAL_DBL), FL2FXCONST_DBL(0.841f), FL2FXCONST_DBL(0.707f), FL2FXCONST_DBL(0.596f), + FL2FXCONST_DBL(0.500f), FL2FXCONST_DBL(0.422f), FL2FXCONST_DBL(0.355f), FL2FXCONST_DBL(0.000f) +}; + +static const UCHAR surmix2matrix_mixdown_idx[8] = { + 0, 0, 0, 1, 1, 2, 2, 3 +}; + + +/*--------------- function declarations --------------------*/ +static FDK_METADATA_ERROR WriteMetadataPayload( + const HANDLE_FDK_METADATA_ENCODER hMetaData, + const AAC_METADATA * const pMetadata + ); + +static INT WriteDynamicRangeInfoPayload( + const AAC_METADATA* const pMetadata, + UCHAR* const pExtensionPayload + ); + +static INT WriteEtsiAncillaryDataPayload( + const AAC_METADATA* const pMetadata, + UCHAR* const pExtensionPayload + ); + +static FDK_METADATA_ERROR CompensateAudioDelay( + HANDLE_FDK_METADATA_ENCODER hMetaDataEnc, + INT_PCM * const pAudioSamples, + const INT nAudioSamples + ); + +static FDK_METADATA_ERROR LoadSubmittedMetadata( + const AACENC_MetaData * const hMetadata, + const INT nChannels, + const INT metadataMode, + AAC_METADATA * const pAacMetaData + ); + +static FDK_METADATA_ERROR ProcessCompressor( + AAC_METADATA *pMetadata, + HDRC_COMP hDrcComp, + const INT_PCM * const pSamples, + const INT nSamples + ); + +/*------------- function definitions ----------------*/ + +static DRC_PROFILE convertProfile(AACENC_METADATA_DRC_PROFILE aacProfile) +{ + DRC_PROFILE drcProfile = DRC_NONE; + + switch(aacProfile) { + case AACENC_METADATA_DRC_NONE: drcProfile = DRC_NONE; break; + case AACENC_METADATA_DRC_FILMSTANDARD: drcProfile = DRC_FILMSTANDARD; break; + case AACENC_METADATA_DRC_FILMLIGHT: drcProfile = DRC_FILMLIGHT; break; + case AACENC_METADATA_DRC_MUSICSTANDARD: drcProfile = DRC_MUSICSTANDARD; break; + case AACENC_METADATA_DRC_MUSICLIGHT: drcProfile = DRC_MUSICLIGHT; break; + case AACENC_METADATA_DRC_SPEECH: drcProfile = DRC_SPEECH; break; + default: drcProfile = DRC_NONE; break; + } + return drcProfile; +} + + +/* convert dialog normalization to program reference level */ +/* NOTE: this only is correct, if the decoder target level is set to -31dB for line mode / -20dB for RF mode */ +static UCHAR dialnorm2progreflvl(const INT d) +{ + return ((UCHAR)FDKmax(0, FDKmin((-d + (1<<13)) >> 14, 127))); +} + +/* convert program reference level to dialog normalization */ +static INT progreflvl2dialnorm(const UCHAR p) +{ + return -((INT)(p<<(16-2))); +} + +/* encode downmix levels to Downmixing_levels_MPEG4 */ +static SCHAR encodeDmxLvls(const SCHAR cmixlev, const SCHAR surmixlev) +{ + SCHAR dmxLvls = 0; + dmxLvls |= 0x80 | (cmixlev << 4); /* center_mix_level_on */ + dmxLvls |= 0x08 | surmixlev; /* surround_mix_level_on */ + + return dmxLvls; +} + +/* encode AAC DRC gain (ISO/IEC 14496-3:2005 4.5.2.7) */ +static void encodeDynrng(INT gain, UCHAR* const dyn_rng_ctl, UCHAR* const dyn_rng_sgn ) +{ + if(gain < 0) + { + *dyn_rng_sgn = 1; + gain = -gain; + } + else + { + *dyn_rng_sgn = 0; + } + gain = FDKmin(gain,(127<<14)); + + *dyn_rng_ctl = (UCHAR)((gain + (1<<13)) >> 14); +} + +/* decode AAC DRC gain (ISO/IEC 14496-3:2005 4.5.2.7) */ +static INT decodeDynrng(const UCHAR dyn_rng_ctl, const UCHAR dyn_rng_sgn) +{ + INT tmp = ((INT)dyn_rng_ctl << (16-2)); + if (dyn_rng_sgn) tmp = -tmp; + + return tmp; +} + +/* encode AAC compression value (ETSI TS 101 154 page 99) */ +static UCHAR encodeCompr(INT gain) +{ + UCHAR x, y; + INT tmp; + + /* tmp = (int)((48.164f - gain) / 6.0206f * 15 + 0.5f); */ + tmp = ((3156476 - gain) * 15 + 197283) / 394566; + + if (tmp >= 240) { + return 0xFF; + } + else if (tmp < 0) { + return 0; + } + else { + x = tmp / 15; + y = tmp % 15; + } + + return (x << 4) | y; +} + +/* decode AAC compression value (ETSI TS 101 154 page 99) */ +static INT decodeCompr(const UCHAR compr) +{ + INT gain; + SCHAR x = compr >> 4; /* 4 MSB of compr */ + UCHAR y = (compr & 0x0F); /* 4 LSB of compr */ + + /* gain = (INT)((48.164f - 6.0206f * x - 0.4014f * y) ); */ + gain = (INT)( scaleValue(((LONG)FL2FXCONST_DBL(6.0206f/128.f)*(8-x) - (LONG)FL2FXCONST_DBL(0.4014f/128.f)*y), -(DFRACT_BITS-1-7-16)) ); + + return gain; +} + + +FDK_METADATA_ERROR FDK_MetadataEnc_Open( + HANDLE_FDK_METADATA_ENCODER *phMetaData + ) +{ + FDK_METADATA_ERROR err = METADATA_OK; + HANDLE_FDK_METADATA_ENCODER hMetaData = NULL; + + if (phMetaData == NULL) { + err = METADATA_INVALID_HANDLE; + goto bail; + } + + /* allocate memory */ + hMetaData = (HANDLE_FDK_METADATA_ENCODER) FDKcalloc(1, sizeof(FDK_METADATA_ENCODER) ); + + if (hMetaData == NULL) { + err = METADATA_MEMORY_ERROR; + goto bail; + } + + FDKmemclear(hMetaData, sizeof(FDK_METADATA_ENCODER)); + + /* Allocate DRC Compressor. */ + if (FDK_DRC_Generator_Open(&hMetaData->hDrcComp)!=0) { + err = METADATA_MEMORY_ERROR; + goto bail; + } + + /* Return metadata instance */ + *phMetaData = hMetaData; + + return err; + +bail: + FDK_MetadataEnc_Close(&hMetaData); + return err; +} + +FDK_METADATA_ERROR FDK_MetadataEnc_Close( + HANDLE_FDK_METADATA_ENCODER *phMetaData + ) +{ + FDK_METADATA_ERROR err = METADATA_OK; + + if (phMetaData == NULL) { + err = METADATA_INVALID_HANDLE; + goto bail; + } + + if (*phMetaData != NULL) { + FDK_DRC_Generator_Close(&(*phMetaData)->hDrcComp); + FDKfree(*phMetaData); + *phMetaData = NULL; + } +bail: + return err; +} + +FDK_METADATA_ERROR FDK_MetadataEnc_Init( + HANDLE_FDK_METADATA_ENCODER hMetaData, + const INT resetStates, + const INT metadataMode, + const INT audioDelay, + const UINT frameLength, + const UINT sampleRate, + const UINT nChannels, + const CHANNEL_MODE channelMode, + const CHANNEL_ORDER channelOrder + ) +{ + FDK_METADATA_ERROR err = METADATA_OK; + int i, nFrames, delay; + + if (hMetaData==NULL) { + err = METADATA_INVALID_HANDLE; + goto bail; + } + + /* Determine values for delay compensation. */ + for (nFrames=0, delay=audioDelay-frameLength; delay>0; delay-=frameLength, nFrames++); + + if ( (hMetaData->nChannels>MAX_DRC_CHANNELS) || ((-delay)>MAX_DRC_FRAMELEN) ) { + err = METADATA_INIT_ERROR; + goto bail; + } + + /* Initialize with default setup. */ + FDKmemcpy(&hMetaData->submittedMetaData, &defaultMetaDataSetup, sizeof(AACENC_MetaData)); + + hMetaData->finalizeMetaData = 0; /* finalize meta data only while on/off switching, else disabled */ + + /* Reset delay lines. */ + if ( resetStates || (hMetaData->nAudioDataDelay!=-delay) || (hMetaData->nChannels!=(INT)nChannels) ) + { + FDKmemclear(hMetaData->audioDelayBuffer, sizeof(hMetaData->audioDelayBuffer)); + FDKmemclear(hMetaData->metaDataBuffer, sizeof(hMetaData->metaDataBuffer)); + hMetaData->audioDelayIdx = 0; + hMetaData->metaDataDelayIdx = 0; + } + else { + /* Enable meta data. */ + if ( (hMetaData->metadataMode==0) && (metadataMode!=0) ) { + /* disable meta data in all delay lines */ + for (i=0; i<(int)(sizeof(hMetaData->metaDataBuffer)/sizeof(AAC_METADATA)); i++) { + LoadSubmittedMetadata(&hMetaData->submittedMetaData, nChannels, 0, &hMetaData->metaDataBuffer[i]); + } + } + + /* Disable meta data.*/ + if ( (hMetaData->metadataMode!=0) && (metadataMode==0) ) { + hMetaData->finalizeMetaData = hMetaData->metadataMode; + } + } + + /* Initialize delay. */ + hMetaData->nAudioDataDelay = -delay; + hMetaData->nMetaDataDelay = nFrames; + hMetaData->nChannels = nChannels; + hMetaData->metadataMode = metadataMode; + + /* Initialize compressor. */ + if (metadataMode != 0) { + if ( FDK_DRC_Generator_Initialize( + hMetaData->hDrcComp, + DRC_NONE, + DRC_NONE, + frameLength, + sampleRate, + channelMode, + channelOrder, + 1) != 0) + { + err = METADATA_INIT_ERROR; + } + } +bail: + return err; +} + +static FDK_METADATA_ERROR ProcessCompressor( + AAC_METADATA *pMetadata, + HDRC_COMP hDrcComp, + const INT_PCM * const pSamples, + const INT nSamples + ) +{ + FDK_METADATA_ERROR err = METADATA_OK; + + INT dynrng, compr; + DRC_PROFILE profileDrc = convertProfile(pMetadata->mpegDrc.drc_profile); + DRC_PROFILE profileComp = convertProfile(pMetadata->etsiAncData.comp_profile); + + if ( (pMetadata==NULL) || (hDrcComp==NULL) ) { + err = METADATA_INVALID_HANDLE; + return err; + } + + /* first, check if profile is same as last frame + * otherwise, update setup */ + if ( (profileDrc != FDK_DRC_Generator_getDrcProfile(hDrcComp)) + || (profileComp != FDK_DRC_Generator_getCompProfile(hDrcComp)) ) + { + FDK_DRC_Generator_setDrcProfile(hDrcComp, profileDrc, profileComp); + } + + /* Sanity check */ + if (profileComp == DRC_NONE) { + pMetadata->etsiAncData.compression_value = 0x80; /* to ensure no external values will be written if not configured */ + } + + /* in case of embedding external values, copy this now (limiter may overwrite them) */ + dynrng = decodeDynrng(pMetadata->mpegDrc.dyn_rng_ctl[0], pMetadata->mpegDrc.dyn_rng_sgn[0]); + compr = decodeCompr(pMetadata->etsiAncData.compression_value); + + /* Call compressor */ + if (FDK_DRC_Generator_Calc(hDrcComp, + pSamples, + progreflvl2dialnorm(pMetadata->mpegDrc.prog_ref_level), + pMetadata->mpegDrc.drc_TargetRefLevel, + pMetadata->etsiAncData.comp_TargetRefLevel, + dmxTable[pMetadata->centerMixLevel], + dmxTable[pMetadata->surroundMixLevel], + &dynrng, + &compr) != 0) + { + err = METADATA_ENCODE_ERROR; + goto bail; + } + + /* Write DRC values */ + pMetadata->mpegDrc.drc_band_incr = 0; + encodeDynrng(dynrng, pMetadata->mpegDrc.dyn_rng_ctl, pMetadata->mpegDrc.dyn_rng_sgn); + pMetadata->etsiAncData.compression_value = encodeCompr(compr); + +bail: + return err; +} + +FDK_METADATA_ERROR FDK_MetadataEnc_Process( + HANDLE_FDK_METADATA_ENCODER hMetaDataEnc, + INT_PCM * const pAudioSamples, + const INT nAudioSamples, + const AACENC_MetaData * const pMetadata, + AACENC_EXT_PAYLOAD ** ppMetaDataExtPayload, + UINT * nMetaDataExtensions, + INT * matrix_mixdown_idx + ) +{ + FDK_METADATA_ERROR err = METADATA_OK; + int metaDataDelayWriteIdx, metaDataDelayReadIdx, metadataMode; + + /* Where to write new meta data info */ + metaDataDelayWriteIdx = hMetaDataEnc->metaDataDelayIdx; + + /* How to write the data */ + metadataMode = hMetaDataEnc->metadataMode; + + /* Compensate meta data delay. */ + hMetaDataEnc->metaDataDelayIdx++; + if (hMetaDataEnc->metaDataDelayIdx > hMetaDataEnc->nMetaDataDelay) hMetaDataEnc->metaDataDelayIdx = 0; + + /* Where to read pending meta data info from. */ + metaDataDelayReadIdx = hMetaDataEnc->metaDataDelayIdx; + + /* Submit new data if available. */ + if (pMetadata!=NULL) { + FDKmemcpy(&hMetaDataEnc->submittedMetaData, pMetadata, sizeof(AACENC_MetaData)); + } + + /* Write one additional frame with default configuration of meta data. Ensure defined behaviour on decoder side. */ + if ( (hMetaDataEnc->finalizeMetaData!=0) && (hMetaDataEnc->metadataMode==0)) { + FDKmemcpy(&hMetaDataEnc->submittedMetaData, &defaultMetaDataSetup, sizeof(AACENC_MetaData)); + metadataMode = hMetaDataEnc->finalizeMetaData; + hMetaDataEnc->finalizeMetaData = 0; + } + + /* Get last submitted data. */ + if ( (err = LoadSubmittedMetadata( + &hMetaDataEnc->submittedMetaData, + hMetaDataEnc->nChannels, + metadataMode, + &hMetaDataEnc->metaDataBuffer[metaDataDelayWriteIdx])) != METADATA_OK ) + { + goto bail; + } + + /* Calculate compressor if necessary and updata meta data info */ + if (hMetaDataEnc->metaDataBuffer[metaDataDelayWriteIdx].metadataMode != 0) { + if ( (err = ProcessCompressor( + &hMetaDataEnc->metaDataBuffer[metaDataDelayWriteIdx], + hMetaDataEnc->hDrcComp, + pAudioSamples, + nAudioSamples)) != METADATA_OK) + { + /* Get last submitted data again. */ + LoadSubmittedMetadata( + &hMetaDataEnc->submittedMetaData, + hMetaDataEnc->nChannels, + metadataMode, + &hMetaDataEnc->metaDataBuffer[metaDataDelayWriteIdx]); + } + } + + /* Convert Meta Data side info to bitstream data. */ + if ( (err = WriteMetadataPayload(hMetaDataEnc, &hMetaDataEnc->metaDataBuffer[metaDataDelayReadIdx])) != METADATA_OK ) { + goto bail; + } + + /* Assign meta data to output */ + *ppMetaDataExtPayload = hMetaDataEnc->exPayload; + *nMetaDataExtensions = hMetaDataEnc->nExtensions; + *matrix_mixdown_idx = hMetaDataEnc->matrix_mixdown_idx; + +bail: + /* Compensate audio delay, reset err status. */ + err = CompensateAudioDelay(hMetaDataEnc, pAudioSamples, nAudioSamples); + + return err; +} + + +static FDK_METADATA_ERROR CompensateAudioDelay( + HANDLE_FDK_METADATA_ENCODER hMetaDataEnc, + INT_PCM * const pAudioSamples, + const INT nAudioSamples + ) +{ + FDK_METADATA_ERROR err = METADATA_OK; + + if (hMetaDataEnc->nAudioDataDelay) { + int i, delaySamples = hMetaDataEnc->nAudioDataDelay*hMetaDataEnc->nChannels; + + for (i = 0; i < nAudioSamples; i++) { + INT_PCM tmp = pAudioSamples[i]; + pAudioSamples[i] = hMetaDataEnc->audioDelayBuffer[hMetaDataEnc->audioDelayIdx]; + hMetaDataEnc->audioDelayBuffer[hMetaDataEnc->audioDelayIdx] = tmp; + + hMetaDataEnc->audioDelayIdx++; + if (hMetaDataEnc->audioDelayIdx >= delaySamples) hMetaDataEnc->audioDelayIdx = 0; + } + } + + return err; +} + +/*----------------------------------------------------------------------------- + + functionname: WriteMetadataPayload + description: fills anc data and extension payload + returns: Error status + + ------------------------------------------------------------------------------*/ +static FDK_METADATA_ERROR WriteMetadataPayload( + const HANDLE_FDK_METADATA_ENCODER hMetaData, + const AAC_METADATA * const pMetadata + ) +{ + FDK_METADATA_ERROR err = METADATA_OK; + + if ( (hMetaData==NULL) || (pMetadata==NULL) ) { + err = METADATA_INVALID_HANDLE; + goto bail; + } + + hMetaData->nExtensions = 0; + hMetaData->matrix_mixdown_idx = -1; + + /* AAC-DRC */ + if (pMetadata->metadataMode != 0) + { + hMetaData->exPayload[hMetaData->nExtensions].pData = hMetaData->drcInfoPayload; + hMetaData->exPayload[hMetaData->nExtensions].dataType = EXT_DYNAMIC_RANGE; + hMetaData->exPayload[hMetaData->nExtensions].associatedChElement = -1; + + hMetaData->exPayload[hMetaData->nExtensions].dataSize = + WriteDynamicRangeInfoPayload(pMetadata, hMetaData->exPayload[hMetaData->nExtensions].pData); + + hMetaData->nExtensions++; + + /* Matrix Mixdown Coefficient in PCE */ + if (pMetadata->WritePCEMixDwnIdx) { + hMetaData->matrix_mixdown_idx = surmix2matrix_mixdown_idx[pMetadata->surroundMixLevel]; + } + + /* ETSI TS 101 154 (DVB) - MPEG4 ancillary_data() */ + if (pMetadata->metadataMode == 2) /* MP4_METADATA_MPEG_ETSI */ + { + hMetaData->exPayload[hMetaData->nExtensions].pData = hMetaData->drcDsePayload; + hMetaData->exPayload[hMetaData->nExtensions].dataType = EXT_DATA_ELEMENT; + hMetaData->exPayload[hMetaData->nExtensions].associatedChElement = -1; + + hMetaData->exPayload[hMetaData->nExtensions].dataSize = + WriteEtsiAncillaryDataPayload(pMetadata,hMetaData->exPayload[hMetaData->nExtensions].pData); + + hMetaData->nExtensions++; + } /* metadataMode == 2 */ + + } /* metadataMode != 0 */ + +bail: + return err; +} + +static INT WriteDynamicRangeInfoPayload( + const AAC_METADATA* const pMetadata, + UCHAR* const pExtensionPayload + ) +{ + const INT pce_tag_present = 0; /* yet fixed setting! */ + const INT prog_ref_lev_res_bits = 0; + INT i, drc_num_bands = 1; + + FDK_BITSTREAM bsWriter; + FDKinitBitStream(&bsWriter, pExtensionPayload, 16, 0, BS_WRITER); + + /* dynamic_range_info() */ + FDKwriteBits(&bsWriter, pce_tag_present, 1); /* pce_tag_present */ + if (pce_tag_present) { + FDKwriteBits(&bsWriter, 0x0, 4); /* pce_instance_tag */ + FDKwriteBits(&bsWriter, 0x0, 4); /* drc_tag_reserved_bits */ + } + + /* Exclude channels */ + FDKwriteBits(&bsWriter, (pMetadata->mpegDrc.excluded_chns_present) ? 1 : 0, 1); /* excluded_chns_present*/ + + /* Multiband DRC */ + FDKwriteBits(&bsWriter, (pMetadata->mpegDrc.drc_bands_present) ? 1 : 0, 1); /* drc_bands_present */ + if (pMetadata->mpegDrc.drc_bands_present) + { + FDKwriteBits(&bsWriter, pMetadata->mpegDrc.drc_band_incr, 4); /* drc_band_incr */ + FDKwriteBits(&bsWriter, pMetadata->mpegDrc.drc_interpolation_scheme, 4); /* drc_interpolation_scheme */ + drc_num_bands += pMetadata->mpegDrc.drc_band_incr; + for (i=0; impegDrc.drc_band_top[i], 8); /* drc_band_top */ + } + } + + /* Program Reference Level */ + FDKwriteBits(&bsWriter, pMetadata->mpegDrc.prog_ref_level_present, 1); /* prog_ref_level_present */ + if (pMetadata->mpegDrc.prog_ref_level_present) + { + FDKwriteBits(&bsWriter, pMetadata->mpegDrc.prog_ref_level, 7); /* prog_ref_level */ + FDKwriteBits(&bsWriter, prog_ref_lev_res_bits, 1); /* prog_ref_level_reserved_bits */ + } + + /* DRC Values */ + for (i=0; impegDrc.dyn_rng_sgn[i]) ? 1 : 0, 1); /* dyn_rng_sgn[ */ + FDKwriteBits(&bsWriter, pMetadata->mpegDrc.dyn_rng_ctl[i], 7); /* dyn_rng_ctl */ + } + + /* return number of valid bits in extension payload. */ + return FDKgetValidBits(&bsWriter); +} + +static INT WriteEtsiAncillaryDataPayload( + const AAC_METADATA* const pMetadata, + UCHAR* const pExtensionPayload + ) +{ + FDK_BITSTREAM bsWriter; + FDKinitBitStream(&bsWriter, pExtensionPayload, 16, 0, BS_WRITER); + + /* ancillary_data_sync */ + FDKwriteBits(&bsWriter, 0xBC, 8); + + /* bs_info */ + FDKwriteBits(&bsWriter, 0x3, 2); /* mpeg_audio_type */ + FDKwriteBits(&bsWriter, pMetadata->dolbySurroundMode, 2); /* dolby_surround_mode */ + FDKwriteBits(&bsWriter, 0x0, 4); /* reserved */ + + /* ancillary_data_status */ + FDKwriteBits(&bsWriter, 0, 3); /* 3 bit Reserved, set to "0" */ + FDKwriteBits(&bsWriter, (pMetadata->DmxLvl_On) ? 1 : 0, 1); /* downmixing_levels_MPEG4_status */ + FDKwriteBits(&bsWriter, 0, 1); /* Reserved, set to "0" */ + FDKwriteBits(&bsWriter, (pMetadata->etsiAncData.compression_on) ? 1 : 0, 1); /* audio_coding_mode_and_compression status */ + FDKwriteBits(&bsWriter, (pMetadata->etsiAncData.timecode_coarse_status) ? 1 : 0, 1); /* coarse_grain_timecode_status */ + FDKwriteBits(&bsWriter, (pMetadata->etsiAncData.timecode_fine_status) ? 1 : 0, 1); /* fine_grain_timecode_status */ + + /* downmixing_levels_MPEG4_status */ + if (pMetadata->DmxLvl_On) { + FDKwriteBits(&bsWriter, encodeDmxLvls(pMetadata->centerMixLevel, pMetadata->surroundMixLevel), 8); + } + + /* audio_coding_mode_and_compression_status */ + if (pMetadata->etsiAncData.compression_on) { + FDKwriteBits(&bsWriter, 0x01, 8); /* audio coding mode */ + FDKwriteBits(&bsWriter, pMetadata->etsiAncData.compression_value, 8); /* compression value */ + } + + /* grain-timecode coarse/fine */ + if (pMetadata->etsiAncData.timecode_coarse_status) { + FDKwriteBits(&bsWriter, 0x0, 16); /* not yet supported */ + } + + if (pMetadata->etsiAncData.timecode_fine_status) { + FDKwriteBits(&bsWriter, 0x0, 16); /* not yet supported */ + } + + return FDKgetValidBits(&bsWriter); +} + + +static FDK_METADATA_ERROR LoadSubmittedMetadata( + const AACENC_MetaData * const hMetadata, + const INT nChannels, + const INT metadataMode, + AAC_METADATA * const pAacMetaData + ) +{ + FDK_METADATA_ERROR err = METADATA_OK; + + if (pAacMetaData==NULL) { + err = METADATA_INVALID_HANDLE; + } + else { + /* init struct */ + FDKmemclear(pAacMetaData, sizeof(AAC_METADATA)); + + if (hMetadata!=NULL) { + /* convert data */ + pAacMetaData->mpegDrc.drc_profile = hMetadata->drc_profile; + pAacMetaData->etsiAncData.comp_profile = hMetadata->comp_profile; + pAacMetaData->mpegDrc.drc_TargetRefLevel = hMetadata->drc_TargetRefLevel; + pAacMetaData->etsiAncData.comp_TargetRefLevel= hMetadata->comp_TargetRefLevel; + pAacMetaData->mpegDrc.prog_ref_level_present = hMetadata->prog_ref_level_present; + pAacMetaData->mpegDrc.prog_ref_level = dialnorm2progreflvl(hMetadata->prog_ref_level); + + pAacMetaData->centerMixLevel = hMetadata->centerMixLevel; + pAacMetaData->surroundMixLevel = hMetadata->surroundMixLevel; + pAacMetaData->WritePCEMixDwnIdx = hMetadata->PCE_mixdown_idx_present; + pAacMetaData->DmxLvl_On = hMetadata->ETSI_DmxLvl_present; + + pAacMetaData->etsiAncData.compression_on = 1; + + + if (nChannels == 2) { + pAacMetaData->dolbySurroundMode = hMetadata->dolbySurroundMode; /* dolby_surround_mode */ + } else { + pAacMetaData->dolbySurroundMode = 0; + } + + pAacMetaData->etsiAncData.timecode_coarse_status = 0; /* not yet supported - attention: Update GetEstMetadataBytesPerFrame() if enable this! */ + pAacMetaData->etsiAncData.timecode_fine_status = 0; /* not yet supported - attention: Update GetEstMetadataBytesPerFrame() if enable this! */ + + pAacMetaData->metadataMode = metadataMode; + } + else { + pAacMetaData->metadataMode = 0; /* there is no configuration available */ + } + } + + return err; +} + +INT FDK_MetadataEnc_GetDelay( + HANDLE_FDK_METADATA_ENCODER hMetadataEnc + ) +{ + INT delay = 0; + + if (hMetadataEnc!=NULL) { + delay = hMetadataEnc->nAudioDataDelay; + } + + return delay; +} + + diff --git a/libAACenc/src/metadata_main.h b/libAACenc/src/metadata_main.h new file mode 100644 index 0000000..715a3cf --- /dev/null +++ b/libAACenc/src/metadata_main.h @@ -0,0 +1,161 @@ +/********************** Fraunhofer IIS FDK AAC Encoder lib ****************** + + (C) Copyright Fraunhofer IIS (2011) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): V. Bacigalupo + Description: Metadata Encoder library interface functions + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#ifndef _METADATA_MAIN_H +#define _METADATA_MAIN_H + + +/* Includes ******************************************************************/ +#include "aacenc_lib.h" +#include "aacenc.h" + + +/* Defines *******************************************************************/ + +/* Data Types ****************************************************************/ + +typedef enum { + METADATA_OK = 0x0000, /*!< No error happened. All fine. */ + METADATA_INVALID_HANDLE = 0x0020, /*!< Handle passed to function call was invalid. */ + METADATA_MEMORY_ERROR = 0x0021, /*!< Memory allocation failed. */ + METADATA_INIT_ERROR = 0x0040, /*!< General initialization error. */ + METADATA_ENCODE_ERROR = 0x0060 /*!< The encoding process was interrupted by an unexpected error. */ + +} FDK_METADATA_ERROR; + +/** + * Meta Data handle. + */ +typedef struct FDK_METADATA_ENCODER *HANDLE_FDK_METADATA_ENCODER; + + +/** + * \brief Open a Meta Data instance. + * + * \param phMetadataEnc A pointer to a Meta Data handle to be allocated. Initialized on return. + * + * \return + * - METADATA_OK, on succes. + * - METADATA_INVALID_HANDLE, METADATA_MEMORY_ERROR, on failure. + */ +FDK_METADATA_ERROR FDK_MetadataEnc_Open( + HANDLE_FDK_METADATA_ENCODER *phMetadataEnc + ); + + +/** + * \brief Initialize a Meta Data instance. + * + * \param hMetadataEnc Meta Data handle. + * \param resetStates Indication for full reset of all states. + * \param metadataMode Configures metat data output format (0,1,2). + * \param audioDelay Delay cause by the audio encoder. + * \param frameLength Number of samples to be processes within one frame. + * \param sampleRate Sampling rat in Hz of audio input signal. + * \param nChannels Number of audio input channels. + * \param channelMode Channel configuration which is used by the encoder. + * \param channelOrder Channel order of the input data. (WAV, MPEG) + * + * \return + * - METADATA_OK, on succes. + * - METADATA_INVALID_HANDLE, METADATA_INIT_ERROR, on failure. + */ +FDK_METADATA_ERROR FDK_MetadataEnc_Init( + HANDLE_FDK_METADATA_ENCODER hMetadataEnc, + const INT resetStates, + const INT metadataMode, + const INT audioDelay, + const UINT frameLength, + const UINT sampleRate, + const UINT nChannels, + const CHANNEL_MODE channelMode, + const CHANNEL_ORDER channelOrder + ); + + +/** + * \brief Calculate Meta Data processing. + * + * This function treats all step necessary for meta data processing. + * - Receive new meta data and make usable. + * - Calculate DRC compressor and extract meta data info. + * - Make meta data available for extern use. + * - Apply audio data and meta data delay compensation. + * + * \param hMetadataEnc Meta Data handle. + * \param pAudioSamples Pointer to audio input data. Existing function overwrites audio data with delayed audio samples. + * \param nAudioSamples Number of input audio samples to be prcessed. + * \param pMetadata Pointer to Metat Data input. + * \param ppMetaDataExtPayload Pointer to extension payload array. Filled on return. + * \param nMetaDataExtensions Pointer to variable to describe number of available extension payloads. Filled on return. + * \param matrix_mixdown_idx Pointer to variable for matrix mixdown coefficient. Filled on return. + * + * \return + * - METADATA_OK, on succes. + * - METADATA_INVALID_HANDLE, METADATA_ENCODE_ERROR, on failure. + */ +FDK_METADATA_ERROR FDK_MetadataEnc_Process( + HANDLE_FDK_METADATA_ENCODER hMetadataEnc, + INT_PCM * const pAudioSamples, + const INT nAudioSamples, + const AACENC_MetaData * const pMetadata, + AACENC_EXT_PAYLOAD ** ppMetaDataExtPayload, + UINT * nMetaDataExtensions, + INT * matrix_mixdown_idx + ); + + +/** + * \brief Close the Meta Data instance. + * + * Deallocate instance and free whole memory. + * + * \param phMetaData Pointer to the Meta Data handle to be deallocated. + * + * \return + * - METADATA_OK, on succes. + * - METADATA_INVALID_HANDLE, on failure. + */ +FDK_METADATA_ERROR FDK_MetadataEnc_Close( + HANDLE_FDK_METADATA_ENCODER *phMetaData + ); + + +/** + * \brief Get Meta Data Encoder delay. + * + * \param hMetadataEnc Meta Data Encoder handle. + * + * \return Delay caused by Meta Data module. + */ +INT FDK_MetadataEnc_GetDelay( + HANDLE_FDK_METADATA_ENCODER hMetadataEnc + ); + + +#endif /* _METADATA_MAIN_H */ + diff --git a/libAACenc/src/ms_stereo.cpp b/libAACenc/src/ms_stereo.cpp new file mode 100644 index 0000000..27cb184 --- /dev/null +++ b/libAACenc/src/ms_stereo.cpp @@ -0,0 +1,189 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: MS stereo processing + +******************************************************************************/ +#include "ms_stereo.h" + +#include "psy_const.h" + +/* static const float scaleMinThres = 1.0f; */ /* 0.75f for 3db boost */ + +void FDKaacEnc_MsStereoProcessing(PSY_DATA *RESTRICT psyData[(2)], + PSY_OUT_CHANNEL* psyOutChannel[2], + const INT *isBook, + INT *msDigest, /* output */ + INT *msMask, /* output */ + const INT sfbCnt, + const INT sfbPerGroup, + const INT maxSfbPerGroup, + const INT *sfbOffset) +{ + FIXP_DBL *sfbEnergyLeft = psyData[0]->sfbEnergy.Long; /* modified where msMask==1 */ + FIXP_DBL *sfbEnergyRight = psyData[1]->sfbEnergy.Long; /* modified where msMask==1 */ + const FIXP_DBL *sfbEnergyMid = psyData[0]->sfbEnergyMS.Long; + const FIXP_DBL *sfbEnergySide = psyData[1]->sfbEnergyMS.Long; + FIXP_DBL *sfbThresholdLeft = psyData[0]->sfbThreshold.Long; /* modified where msMask==1 */ + FIXP_DBL *sfbThresholdRight = psyData[1]->sfbThreshold.Long; /* modified where msMask==1 */ + + FIXP_DBL *sfbSpreadEnLeft = psyData[0]->sfbSpreadEnergy.Long; + FIXP_DBL *sfbSpreadEnRight = psyData[1]->sfbSpreadEnergy.Long; + + FIXP_DBL *sfbEnergyLeftLdData = psyOutChannel[0]->sfbEnergyLdData; /* modified where msMask==1 */ + FIXP_DBL *sfbEnergyRightLdData = psyOutChannel[1]->sfbEnergyLdData; /* modified where msMask==1 */ + FIXP_DBL *sfbEnergyMidLdData = psyData[0]->sfbEnergyMSLdData; + FIXP_DBL *sfbEnergySideLdData = psyData[1]->sfbEnergyMSLdData; + FIXP_DBL *sfbThresholdLeftLdData = psyOutChannel[0]->sfbThresholdLdData; /* modified where msMask==1 */ + FIXP_DBL *sfbThresholdRightLdData = psyOutChannel[1]->sfbThresholdLdData; /* modified where msMask==1 */ + + FIXP_DBL *mdctSpectrumLeft = psyData[0]->mdctSpectrum; /* modified where msMask==1 */ + FIXP_DBL *mdctSpectrumRight = psyData[1]->mdctSpectrum; /* modified where msMask==1 */ + + INT sfb,sfboffs, j; /* loop counters */ + FIXP_DBL pnlrLdData, pnmsLdData; + FIXP_DBL minThresholdLdData; + FIXP_DBL minThreshold; + INT useMS; + + INT msMaskTrueSomewhere = 0; /* to determine msDigest */ + INT numMsMaskFalse = 0; /* number of non-intensity bands where L/R coding is used */ + + for(sfb=0; sfb pnlr); +*/ + + /* we assume that scaleMinThres == 1.0f and we can drop it */ + minThresholdLdData = fixMin(sfbThresholdLeftLdData[sfb+sfboffs], sfbThresholdRightLdData[sfb+sfboffs]); + + /* pnlrLdData = sfbThresholdLeftLdData[sfb+sfboffs] - + max(sfbEnergyLeftLdData[sfb+sfboffs], sfbThresholdLeftLdData[sfb+sfboffs]) + + sfbThresholdRightLdData[sfb+sfboffs] - + max(sfbEnergyRightLdData[sfb+sfboffs], sfbThresholdRightLdData[sfb+sfboffs]); */ + tmp = fixMax(sfbEnergyLeftLdData[sfb+sfboffs], sfbThresholdLeftLdData[sfb+sfboffs]); + pnlrLdData = (sfbThresholdLeftLdData[sfb+sfboffs]>>1) - (tmp>>1); + pnlrLdData = pnlrLdData + (sfbThresholdRightLdData[sfb+sfboffs]>>1); + tmp = fixMax(sfbEnergyRightLdData[sfb+sfboffs], sfbThresholdRightLdData[sfb+sfboffs]); + pnlrLdData = pnlrLdData - (tmp>>1); + + /* pnmsLdData = minThresholdLdData - max(sfbEnergyMidLdData[sfb+sfboffs], minThresholdLdData) + + minThresholdLdData - max(sfbEnergySideLdData[sfb+sfboffs], minThresholdLdData); */ + tmp = fixMax(sfbEnergyMidLdData[sfb+sfboffs], minThresholdLdData); + pnmsLdData = minThresholdLdData - (tmp>>1); + tmp = fixMax(sfbEnergySideLdData[sfb+sfboffs], minThresholdLdData); + pnmsLdData = pnmsLdData - (tmp>>1); + useMS = (pnmsLdData > (pnlrLdData)); + + + if (useMS) { + msMask[sfb+sfboffs] = 1; + msMaskTrueSomewhere = 1; + for(j=sfbOffset[sfb+sfboffs]; j>1; + specR = mdctSpectrumRight[j]>>1; + mdctSpectrumLeft[j] = specL + specR; + mdctSpectrumRight[j] = specL - specR; + } + minThreshold = fixMin(sfbThresholdLeft[sfb+sfboffs], sfbThresholdRight[sfb+sfboffs]); + sfbThresholdLeft[sfb+sfboffs] = sfbThresholdRight[sfb+sfboffs] = minThreshold; + sfbThresholdLeftLdData[sfb+sfboffs] = sfbThresholdRightLdData[sfb+sfboffs] = minThresholdLdData; + sfbEnergyLeft[sfb+sfboffs] = sfbEnergyMid[sfb+sfboffs]; + sfbEnergyRight[sfb+sfboffs] = sfbEnergySide[sfb+sfboffs]; + sfbEnergyLeftLdData[sfb+sfboffs] = sfbEnergyMidLdData[sfb+sfboffs]; + sfbEnergyRightLdData[sfb+sfboffs] = sfbEnergySideLdData[sfb+sfboffs]; + + sfbSpreadEnLeft[sfb+sfboffs] = sfbSpreadEnRight[sfb+sfboffs] = + fixMin( sfbSpreadEnLeft[sfb+sfboffs], + sfbSpreadEnRight[sfb+sfboffs] ) >> 1; + + } + else { + msMask[sfb+sfboffs] = 0; + numMsMaskFalse++; + } /* useMS */ + } /* isBook */ + else { + /* keep mDigest from IS module */ + if (msMask[sfb+sfboffs]) { + msMaskTrueSomewhere = 1; + } + /* prohibit MS_MASK_ALL in combination with IS */ + numMsMaskFalse = 9; + } /* isBook */ + } /* sfboffs */ + } /* sfb */ + + + if(msMaskTrueSomewhere == 1) { + if ((numMsMaskFalse == 0) || ((numMsMaskFalse < maxSfbPerGroup) && (numMsMaskFalse < 9))) { + *msDigest = SI_MS_MASK_ALL; + /* loop through M/S bands; if msMask==0, set it to 1 and apply M/S */ + for (sfb = 0; sfb < sfbCnt; sfb += sfbPerGroup) { + for (sfboffs = 0; sfboffs < maxSfbPerGroup; sfboffs++) { + if (( (isBook == NULL) ? 1 : (isBook[sfb+sfboffs] == 0) ) && (msMask[sfb+sfboffs] == 0)) { + msMask[sfb+sfboffs] = 1; + /* apply M/S coding */ + for(j=sfbOffset[sfb+sfboffs]; j>1; + specR = mdctSpectrumRight[j]>>1; + mdctSpectrumLeft[j] = specL + specR; + mdctSpectrumRight[j] = specL - specR; + } + minThreshold = fixMin(sfbThresholdLeft[sfb+sfboffs], sfbThresholdRight[sfb+sfboffs]); + sfbThresholdLeft[sfb+sfboffs] = sfbThresholdRight[sfb+sfboffs] = minThreshold; + minThresholdLdData = fixMin(sfbThresholdLeftLdData[sfb+sfboffs], sfbThresholdRightLdData[sfb+sfboffs]); + sfbThresholdLeftLdData[sfb+sfboffs] = sfbThresholdRightLdData[sfb+sfboffs] = minThresholdLdData; + sfbEnergyLeft[sfb+sfboffs] = sfbEnergyMid[sfb+sfboffs]; + sfbEnergyRight[sfb+sfboffs] = sfbEnergySide[sfb+sfboffs]; + sfbEnergyLeftLdData[sfb+sfboffs] = sfbEnergyMidLdData[sfb+sfboffs]; + sfbEnergyRightLdData[sfb+sfboffs] = sfbEnergySideLdData[sfb+sfboffs]; + + sfbSpreadEnLeft[sfb+sfboffs] = sfbSpreadEnRight[sfb+sfboffs] = + fixMin( sfbSpreadEnLeft[sfb+sfboffs], + sfbSpreadEnRight[sfb+sfboffs] ) >> 1; + } + } + } + } else { + *msDigest = SI_MS_MASK_SOME; + } + } else { + *msDigest = SI_MS_MASK_NONE; + } +} diff --git a/libAACenc/src/ms_stereo.h b/libAACenc/src/ms_stereo.h new file mode 100644 index 0000000..1d74acb --- /dev/null +++ b/libAACenc/src/ms_stereo.h @@ -0,0 +1,44 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: MS stereo processing + +******************************************************************************/ +#ifndef __MS_STEREO_H__ +#define __MS_STEREO_H__ + + +#include "interface.h" + +void FDKaacEnc_MsStereoProcessing(PSY_DATA *RESTRICT psyData[(2)], + PSY_OUT_CHANNEL* psyOutChannel[2], + const INT *isBook, + INT *msDigest, /* output */ + INT *msMask, /* output */ + const INT sfbCnt, + const INT sfbPerGroup, + const INT maxSfbPerGroup, + const INT *sfbOffset); + +#endif diff --git a/libAACenc/src/noisedet.cpp b/libAACenc/src/noisedet.cpp new file mode 100644 index 0000000..2f21fb9 --- /dev/null +++ b/libAACenc/src/noisedet.cpp @@ -0,0 +1,170 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (2001) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + + Initial author: M. Lohwasser + contents/description: noisedet.c + Routines for Noise Detection + +******************************************************************************/ + +#include "noisedet.h" + +#include "aacenc_pns.h" +#include "pnsparam.h" + + +/***************************************************************************** + + functionname: FDKaacEnc_fuzzyIsSmaller + description: Fuzzy value calculation for "testVal is smaller than refVal" + returns: fuzzy value + input: test and ref Value, + low and high Lim + output: return fuzzy value + +*****************************************************************************/ +static FIXP_SGL FDKaacEnc_fuzzyIsSmaller( FIXP_DBL testVal, + FIXP_DBL refVal, + FIXP_DBL loLim, + FIXP_DBL hiLim ) +{ + if (refVal <= FL2FXCONST_DBL(0.0)) + return( FL2FXCONST_SGL(0.0f) ); + else if (testVal >= fMult((hiLim>>1)+(loLim>>1), refVal)) + return( FL2FXCONST_SGL(0.0f) ); + else return( (FIXP_SGL)MAXVAL_SGL ); +} + + + +/***************************************************************************** + + functionname: FDKaacEnc_noiseDetect + description: detect tonal sfb's; two tests + Powerdistribution: + sfb splittet in four regions, + compare the energy in all sections + PsychTonality: + compare tonality from chaosmeasure with reftonality + returns: + input: spectrum of one large mdct + number of sfb's + pointer to offset of sfb's + pointer to noiseFuzzyMeasure (modified) + noiseparams struct + pointer to sfb energies + pointer to tonality calculated in chaosmeasure + output: noiseFuzzy Measure + +*****************************************************************************/ + +void FDKaacEnc_noiseDetect(FIXP_DBL *RESTRICT mdctSpectrum, + INT *RESTRICT sfbMaxScaleSpec, + INT sfbActive, + const INT *RESTRICT sfbOffset, + FIXP_SGL *RESTRICT noiseFuzzyMeasure, + NOISEPARAMS *np, + FIXP_SGL *RESTRICT sfbtonality ) + +{ + int i, k, sfb, sfbWidth; + FIXP_SGL fuzzy, fuzzyTotal; + FIXP_DBL refVal, testVal; + +#define ALL_SFB_TONAL 0 +#define ALL_SFB_NONTONAL 0 + + /***** Start detection phase *****/ + /* Start noise detection for each band based on a number of checks */ + for (sfb=0; sfbstartSfb || sfbWidth < np->minSfbWidth) { + noiseFuzzyMeasure[sfb] = FL2FXCONST_SGL(0.0f); + continue; + } + + if ( (np->detectionAlgorithmFlags & USE_POWER_DISTRIBUTION) && (fuzzyTotal > FL2FXCONST_SGL(0.5f)) ) { + FIXP_DBL fhelp1, fhelp2, fhelp3, fhelp4, maxVal, minVal; + INT leadingBits = fixMax(0,(sfbMaxScaleSpec[sfb] - 3)); /* max sfbWidth = 96/4 ; 2^5=32 => 5/2 = 3 (spc*spc) */ + + /* check power distribution in four regions */ + fhelp1 = fhelp2 = fhelp3 = fhelp4 = FL2FXCONST_DBL(0.0f); + k = sfbWidth >>2; /* Width of a quarter band */ + + for (i=sfbOffset[sfb]; ipowDistPSDcurve[sfb]); + + fuzzy = FDKaacEnc_fuzzyIsSmaller(testVal, /* 1/2 * maxValue * PSDcurve */ + refVal, /* 1 * minValue */ + FL2FXCONST_DBL(0.495), /* 1/2 * loLim (0.99f/2) */ + FL2FXCONST_DBL(0.505)); /* 1/2 * hiLim (1.01f/2) */ + + fuzzyTotal = fixMin(fuzzyTotal, fuzzy); + } + + if ( (np->detectionAlgorithmFlags & USE_PSYCH_TONALITY) && (fuzzyTotal > FL2FXCONST_SGL(0.5f)) ) { + /* Detection with tonality-value of psych. acoustic (here: 1 is tonal!)*/ + + testVal = FX_SGL2FX_DBL(sfbtonality[sfb])>>1; /* 1/2 * sfbTonality */ + refVal = np->refTonality; + + fuzzy = FDKaacEnc_fuzzyIsSmaller(testVal, + refVal, + FL2FXCONST_DBL(0.45f), /* 1/2 * loLim (0.9f/2) */ + FL2FXCONST_DBL(0.55f)); /* 1/2 * hiLim (1.1f/2) */ + + fuzzyTotal = fixMin(fuzzyTotal, fuzzy); + } + + + /* Output of final result */ + noiseFuzzyMeasure[sfb] = fuzzyTotal; + } +} diff --git a/libAACenc/src/noisedet.h b/libAACenc/src/noisedet.h new file mode 100644 index 0000000..50b3371 --- /dev/null +++ b/libAACenc/src/noisedet.h @@ -0,0 +1,47 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (2001) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + + Initial author: M. Lohwasser + contents/description: noisedet.h + +******************************************************************************/ + +#ifndef __NOISEDET_H +#define __NOISEDET_H + +#include "common_fix.h" + +#include "pnsparam.h" +#include "psy_data.h" + + +void FDKaacEnc_noiseDetect( FIXP_DBL *mdctSpectrum, + INT *sfbMaxScaleSpec, + INT sfbActive, + const INT *sfbOffset, + FIXP_SGL noiseFuzzyMeasure[], + NOISEPARAMS *np, + FIXP_SGL *sfbtonality ); + +#endif diff --git a/libAACenc/src/pns_func.h b/libAACenc/src/pns_func.h new file mode 100644 index 0000000..320fe84 --- /dev/null +++ b/libAACenc/src/pns_func.h @@ -0,0 +1,89 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (2001) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + + Initial author: M. Lohwasser + contents/description: pns_func.h + +******************************************************************************/ + +#ifndef _PNS_FUNC_H +#define _PNS_FUNC_H + +#include "common_fix.h" + +#include "aacenc_pns.h" +#include "psy_data.h" + + + +AAC_ENCODER_ERROR FDKaacEnc_InitPnsConfiguration(PNS_CONFIG *pnsConf, + INT bitRate, + INT sampleRate, + INT usePns, + INT sfbCnt, + const INT *sfbOffset, + const INT numChan, + const INT isLC ); + +void FDKaacEnc_PnsDetect( PNS_CONFIG *pnsConf, + PNS_DATA *pnsData, + const INT lastWindowSequence, + const INT sfbActive, + const INT maxSfbPerGroup, + FIXP_DBL *sfbThresholdLdData, + const INT *sfbOffset, + FIXP_DBL *mdctSpectrum, + INT *sfbMaxScaleSpec, + FIXP_SGL *sfbtonality, + int tnsOrder, + INT tnsPredictionGain, + INT tnsActive, + FIXP_DBL *sfbEnergyLdData, + INT *noiseNrg ); + +void FDKaacEnc_CodePnsChannel( const INT sfbActive, + PNS_CONFIG *pnsConf, + INT *pnsFlag, + FIXP_DBL *sfbEnergy, + INT *noiseNrg, + FIXP_DBL *sfbThreshold ); + +void FDKaacEnc_PreProcessPnsChannelPair( const INT sfbActive, + FIXP_DBL *sfbEnergyLeft, + FIXP_DBL *sfbEnergyRight, + FIXP_DBL *sfbEnergyLeftLD, + FIXP_DBL *sfbEnergyRightLD, + FIXP_DBL *sfbEnergyMid, + PNS_CONFIG *pnsConfLeft, + PNS_DATA *pnsDataLeft, + PNS_DATA *pnsDataRight ); + +void FDKaacEnc_PostProcessPnsChannelPair( const INT sfbActive, + PNS_CONFIG *pnsConf, + PNS_DATA *pnsDataLeft, + PNS_DATA *pnsDataRight, + INT *msMask, + INT *msDigest ); + +#endif /* _PNS_FUNC_H */ diff --git a/libAACenc/src/pnsparam.cpp b/libAACenc/src/pnsparam.cpp new file mode 100644 index 0000000..0babc4a --- /dev/null +++ b/libAACenc/src/pnsparam.cpp @@ -0,0 +1,248 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (2001) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Lohwasser + contents/description: PNS parameters depending on bitrate and bandwidth + +******************************************************************************/ + +#include "pnsparam.h" +#include "psy_configuration.h" + +typedef struct { + SHORT startFreq; + /* Parameters for detection */ + FIXP_SGL refPower; + FIXP_SGL refTonality; + SHORT tnsGainThreshold; /* scaled by TNS_PREDGAIN_SCALE (=1000) */ + SHORT tnsPNSGainThreshold; /* scaled by TNS_PREDGAIN_SCALE (=1000) */ + FIXP_SGL gapFillThr; + SHORT minSfbWidth; + USHORT detectionAlgorithmFlags; +} PNS_INFO_TAB; + + +typedef struct { + ULONG brFrom; + ULONG brTo; + UCHAR S22050; + UCHAR S24000; + UCHAR S32000; + UCHAR S44100; + UCHAR S48000; +} AUTO_PNS_TAB; + +static const AUTO_PNS_TAB levelTable_mono[]= { + {0, 11999, 1, 1, 1, 1, 1,}, + {12000, 19999, 1, 1, 1, 1, 1,}, + {20000, 28999, 2, 1, 1, 1, 1,}, + {29000, 40999, 4, 4, 4, 2, 2,}, + {41000, 55999, 9, 9, 7, 7, 7,}, + {56000, 79999, 0, 0, 0, 9, 9,}, + {80000, 99999, 0, 0, 0, 0, 0,}, + {100000,999999, 0, 0, 0, 0, 0,}, +}; + +static const AUTO_PNS_TAB levelTable_stereo[]= { + {0, 11999, 1, 1, 1, 1, 1,}, + {12000, 19999, 3, 1, 1, 1, 1,}, + {20000, 28999, 3, 3, 3, 2, 2,}, + {29000, 40999, 7, 6, 6, 5, 5,}, + {41000, 55999, 9, 9, 7, 7, 7,}, + {56000, 79999, 0, 0, 0, 0, 0,}, + {80000, 99999, 0, 0, 0, 0, 0,}, + {100000,999999, 0, 0, 0, 0, 0,}, +}; + + +static const PNS_INFO_TAB pnsInfoTab[] = { +/*0 pns off */ +/*1*/ { 4000, FL2FXCONST_SGL(0.04), FL2FXCONST_SGL(0.06), 1150, 1200, FL2FXCONST_SGL(0.02), 8, + USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS /*| JUST_LONG_WINDOW*/ }, +/*2*/ { 4000, FL2FXCONST_SGL(0.04), FL2FXCONST_SGL(0.07), 1130, 1300, FL2FXCONST_SGL(0.05), 8, + USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS /*| JUST_LONG_WINDOW*/ }, +/*3*/ { 4100, FL2FXCONST_SGL(0.04), FL2FXCONST_SGL(0.07), 1100, 1400, FL2FXCONST_SGL(0.10), 8, + USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS /*| JUST_LONG_WINDOW*/ }, +/*4*/ { 4100, FL2FXCONST_SGL(0.03), FL2FXCONST_SGL(0.10), 1100, 1400, FL2FXCONST_SGL(0.15), 8, + USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS /*| JUST_LONG_WINDOW*/ }, +/*5*/ { 4300, FL2FXCONST_SGL(0.03), FL2FXCONST_SGL(0.10), 1100, 1400, FL2FXCONST_SGL(0.15), 8, + USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW }, +/*6*/ { 5000, FL2FXCONST_SGL(0.03), FL2FXCONST_SGL(0.10), 1100, 1400, FL2FXCONST_SGL(0.25), 8, + USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW }, +/*7*/ { 5500, FL2FXCONST_SGL(0.03), FL2FXCONST_SGL(0.12), 1100, 1400, FL2FXCONST_SGL(0.35), 8, + USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW }, +/*8*/ { 6000, FL2FXCONST_SGL(0.03), FL2FXCONST_SGL(0.12), 1080, 1400, FL2FXCONST_SGL(0.40), 8, + USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW }, +/*9*/ { 6000, FL2FXCONST_SGL(0.03), FL2FXCONST_SGL(0.14), 1070, 1400, FL2FXCONST_SGL(0.45), 8, + USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW }, +}; + +static const AUTO_PNS_TAB levelTable_lowComplexity[]= { + //{0, 23999, 1, 1, 1, 1, 1,}, + //{24000, 31999, 2, 2, 2, 2, 2,}, + {0, 27999, 0, 0, 0, 0, 0,}, + {28000, 31999, 2, 2, 2, 2, 2,}, + {32000, 47999, 3, 3, 3, 3, 3,}, + {48000, 48000, 4, 4, 4, 4, 4,}, + {48001, 999999, 0, 0, 0, 0, 0,}, +}; + +/* conversion of old LC tuning tables to new (LD enc) structure (only entries which are actually used were converted) */ +static const PNS_INFO_TAB pnsInfoTab_lowComplexity[] = { +/*0 pns off */ + /* DEFAULT parameter set */ +/*1*/ { 4100, FL2FXCONST_SGL(0.03), FL2FXCONST_SGL(0.16), 1100, 1400, FL2FXCONST_SGL(0.5), 16, + USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW }, +/*2*/ { 4100, FL2FXCONST_SGL(0.05), FL2FXCONST_SGL(0.10), 1410, 1400, FL2FXCONST_SGL(0.5), 16, + USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW }, +/*3*/ { 4100, FL2FXCONST_SGL(0.05), FL2FXCONST_SGL(0.10), 1100, 1400, FL2FXCONST_SGL(0.5), 16, + USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW }, + /* LOWSUBST -> PNS is used less often than with DEFAULT parameter set (for br: 48000 - 79999) */ +/*4*/ { 4100, FL2FXCONST_SGL(0.20), FL2FXCONST_SGL(0.10), 1410, 1400, FL2FXCONST_SGL(0.5), 16, + USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW }, +}; + +/**************************************************************************** + function to look up used pns level +****************************************************************************/ +int FDKaacEnc_lookUpPnsUse (int bitRate, int sampleRate, int numChan, const int isLC) { + + int hUsePns=0, size, i; + const AUTO_PNS_TAB *levelTable; + + if (isLC) { + levelTable = &levelTable_lowComplexity[0]; + size = sizeof(levelTable_lowComplexity); + } else + { /* (E)LD */ + levelTable = (numChan > 1) ? &levelTable_stereo[0] : &levelTable_mono[0]; + size = (numChan > 1) ? sizeof(levelTable_stereo) : sizeof(levelTable_mono); + } + + for(i = 0; i < (int) (size/sizeof(AUTO_PNS_TAB)); i++) { + if(((ULONG)bitRate >= levelTable[i].brFrom) && + ((ULONG)bitRate <= levelTable[i].brTo) ) + break; + } + + /* sanity check */ + if ((int)(sizeof(pnsInfoTab)/sizeof(PNS_INFO_TAB)) < i ) { + return (PNS_TABLE_ERROR); + } + + switch (sampleRate) { + case 22050: hUsePns = levelTable[i].S22050; break; + case 24000: hUsePns = levelTable[i].S24000; break; + case 32000: hUsePns = levelTable[i].S32000; break; + case 44100: hUsePns = levelTable[i].S44100; break; + case 48000: hUsePns = levelTable[i].S48000; break; + default: + if (isLC) { + hUsePns = levelTable[i].S48000; + } + break; + } + + return (hUsePns); +} + + +/***************************************************************************** + + functionname: FDKaacEnc_GetPnsParam + description: Gets PNS parameters depending on bitrate and bandwidth + returns: error status + input: Noiseparams struct, bitrate, sampling rate, + number of sfb's, pointer to sfb offset + output: PNS parameters + +*****************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_GetPnsParam(NOISEPARAMS *np, + INT bitRate, + INT sampleRate, + INT sfbCnt, + const INT *sfbOffset, + INT *usePns, + INT numChan, + const int isLC) + +{ + int i, hUsePns; + const PNS_INFO_TAB *pnsInfo; + + if (isLC) { + np->detectionAlgorithmFlags = IS_LOW_COMLEXITY; + pnsInfo = pnsInfoTab_lowComplexity; + } + else + { + np->detectionAlgorithmFlags = 0; + pnsInfo = pnsInfoTab; + } + + if (*usePns<=0) + return AAC_ENC_OK; + + /* new pns params */ + hUsePns = FDKaacEnc_lookUpPnsUse (bitRate, sampleRate, numChan, isLC); + if (hUsePns == 0) { + *usePns = 0; + return AAC_ENC_OK; + } + if (hUsePns == PNS_TABLE_ERROR) + return AAC_ENC_PNS_TABLE_ERROR; + + /* select correct row of tuning table */ + pnsInfo += hUsePns-1; + + np->startSfb = FDKaacEnc_FreqToBandWithRounding( pnsInfo->startFreq, + sampleRate, + sfbCnt, + sfbOffset ); + + np->detectionAlgorithmFlags |= pnsInfo->detectionAlgorithmFlags; + + np->refPower = FX_SGL2FX_DBL(pnsInfo->refPower); + np->refTonality = FX_SGL2FX_DBL(pnsInfo->refTonality); + np->tnsGainThreshold = pnsInfo->tnsGainThreshold; + np->tnsPNSGainThreshold = pnsInfo->tnsPNSGainThreshold; + np->minSfbWidth = pnsInfo->minSfbWidth; + + np->gapFillThr = (FIXP_SGL)pnsInfo->gapFillThr; + + /* assuming a constant dB/Hz slope in the signal's PSD curve, + the detection threshold needs to be corrected for the width of the band */ + for ( i = 0; i < (sfbCnt-1); i++) + { + INT qtmp, sfbWidth; + FIXP_DBL tmp; + + sfbWidth = sfbOffset[i+1]-sfbOffset[i]; + + tmp = fPow(np->refPower, 0, sfbWidth, DFRACT_BITS-1-5, &qtmp); + np->powDistPSDcurve[i] = (FIXP_SGL)((LONG)(scaleValue(tmp, qtmp) >> 16)); + } + np->powDistPSDcurve[sfbCnt] = np->powDistPSDcurve[sfbCnt-1]; + + return AAC_ENC_OK; +} diff --git a/libAACenc/src/pnsparam.h b/libAACenc/src/pnsparam.h new file mode 100644 index 0000000..7d947c6 --- /dev/null +++ b/libAACenc/src/pnsparam.h @@ -0,0 +1,78 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (2001) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + Initial author: M. Lohwasser + contents/description: PNS parameters depending on bitrate and bandwidth + +******************************************************************************/ + +#ifndef __PNSPARAM_H +#define __PNSPARAM_H + +#include "aacenc.h" +#include "common_fix.h" +#include "psy_const.h" + +#define NUM_PNSINFOTAB 4 +#define PNS_TABLE_ERROR -1 + +/* detection algorithm flags */ +#define USE_POWER_DISTRIBUTION (1<<0) +#define USE_PSYCH_TONALITY (1<<1) +#define USE_TNS_GAIN_THR (1<<2) +#define USE_TNS_PNS (1<<3) +#define JUST_LONG_WINDOW (1<<4) +/* additional algorithm flags */ +#define IS_LOW_COMLEXITY (1<<5) + +typedef struct +{ + /* PNS start band */ + short startSfb; + + /* detection algorithm flags */ + USHORT detectionAlgorithmFlags; + + /* Parameters for detection */ + FIXP_DBL refPower; + FIXP_DBL refTonality; + INT tnsGainThreshold; + INT tnsPNSGainThreshold; + INT minSfbWidth; + FIXP_SGL powDistPSDcurve[MAX_GROUPED_SFB]; + FIXP_SGL gapFillThr; +} NOISEPARAMS; + +int FDKaacEnc_lookUpPnsUse (int bitRate, int sampleRate, int numChan, const int isLC); + +/****** Definition of prototypes ******/ + +AAC_ENCODER_ERROR FDKaacEnc_GetPnsParam(NOISEPARAMS *np, + INT bitRate, + INT sampleRate, + INT sfbCnt, + const INT *sfbOffset, + INT *usePns, + INT numChan, + const INT isLC); + +#endif diff --git a/libAACenc/src/pre_echo_control.cpp b/libAACenc/src/pre_echo_control.cpp new file mode 100644 index 0000000..dd34e22 --- /dev/null +++ b/libAACenc/src/pre_echo_control.cpp @@ -0,0 +1,108 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: M.Werner + contents/description: Pre echo control + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "pre_echo_control.h" +#include "psy_configuration.h" + +void FDKaacEnc_InitPreEchoControl(FIXP_DBL *RESTRICT pbThresholdNm1, + INT *calcPreEcho, + INT numPb, + FIXP_DBL *RESTRICT sfbPcmQuantThreshold, + INT *mdctScalenm1) +{ + *mdctScalenm1 = PCM_QUANT_THR_SCALE>>1; + + FDKmemcpy(pbThresholdNm1, sfbPcmQuantThreshold, numPb*sizeof(FIXP_DBL)); + + *calcPreEcho = 1; +} + + +void FDKaacEnc_PreEchoControl(FIXP_DBL *RESTRICT pbThresholdNm1, + INT calcPreEcho, + INT numPb, + INT maxAllowedIncreaseFactor, + FIXP_SGL minRemainingThresholdFactor, + FIXP_DBL *RESTRICT pbThreshold, + INT mdctScale, + INT *mdctScalenm1) +{ + int i; + FIXP_DBL tmpThreshold1, tmpThreshold2; + int scaling; + + /* If lastWindowSequence in previous frame was start- or stop-window, + skip preechocontrol calculation */ + if (calcPreEcho==0) { + /* copy thresholds to internal memory */ + FDKmemcpy(pbThresholdNm1, pbThreshold, numPb*sizeof(FIXP_DBL)); + *mdctScalenm1 = mdctScale; + return; + } + + if ( mdctScale > *mdctScalenm1 ) { + /* if current thresholds are downscaled more than the ones from the last block */ + scaling = 2*(mdctScale-*mdctScalenm1); + for(i = 0; i < numPb; i++) { + + /* multiplication with return data type fract ist equivalent to int multiplication */ + FDK_ASSERT(scaling>=0); + tmpThreshold1 = maxAllowedIncreaseFactor * (pbThresholdNm1[i]>>scaling); + tmpThreshold2 = fMult(minRemainingThresholdFactor, pbThreshold[i]); + + FIXP_DBL tmp = pbThreshold[i]; + + /* copy thresholds to internal memory */ + pbThresholdNm1[i] = tmp; + + tmp = fixMin(tmp, tmpThreshold1); + pbThreshold[i] = fixMax(tmp, tmpThreshold2); + } + } + else { + /* if thresholds of last block are more downscaled than the current ones */ + scaling = 2*(*mdctScalenm1-mdctScale); + for(i = 0; i < numPb; i++) { + + /* multiplication with return data type fract ist equivalent to int multiplication */ + tmpThreshold1 = (maxAllowedIncreaseFactor>>1) * pbThresholdNm1[i]; + tmpThreshold2 = fMult(minRemainingThresholdFactor, pbThreshold[i]); + + /* copy thresholds to internal memory */ + pbThresholdNm1[i] = pbThreshold[i]; + + FDK_ASSERT(scaling>=0); + if((pbThreshold[i]>>(scaling+1)) > tmpThreshold1) { + pbThreshold[i] = tmpThreshold1<<(scaling+1); + } + pbThreshold[i] = fixMax(pbThreshold[i], tmpThreshold2); + } + } + + *mdctScalenm1 = mdctScale; +} diff --git a/libAACenc/src/pre_echo_control.h b/libAACenc/src/pre_echo_control.h new file mode 100644 index 0000000..ded5057 --- /dev/null +++ b/libAACenc/src/pre_echo_control.h @@ -0,0 +1,51 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Pre echo control + +******************************************************************************/ +#ifndef __PRE_ECHO_CONTROL_H +#define __PRE_ECHO_CONTROL_H + +#include "common_fix.h" + + +void FDKaacEnc_InitPreEchoControl(FIXP_DBL *pbThresholdnm1, + INT *calcPreEcho, + INT numPb, + FIXP_DBL *sfbPcmQuantThreshold, + INT *mdctScalenm1); + + +void FDKaacEnc_PreEchoControl(FIXP_DBL *pbThresholdNm1, + INT calcPreEcho, + INT numPb, + INT maxAllowedIncreaseFactor, + FIXP_SGL minRemainingThresholdFactor, + FIXP_DBL *pbThreshold, + INT mdctScale, + INT *mdctScalenm1); + +#endif + diff --git a/libAACenc/src/psy_configuration.cpp b/libAACenc/src/psy_configuration.cpp new file mode 100644 index 0000000..731abf4 --- /dev/null +++ b/libAACenc/src/psy_configuration.cpp @@ -0,0 +1,594 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Psychoaccoustic configuration + +******************************************************************************/ + +#include "psy_configuration.h" +#include "adj_thr.h" +#include "aacEnc_rom.h" + +#include "genericStds.h" + +#include "FDK_trigFcts.h" + +typedef struct{ + LONG sampleRate; + const SFB_PARAM_LONG *paramLong; + const SFB_PARAM_SHORT *paramShort; +}SFB_INFO_TAB; + + +static const SFB_INFO_TAB sfbInfoTab[] = { + {8000, &p_FDKaacEnc_8000_long_1024, &p_FDKaacEnc_8000_short_128}, + {11025, &p_FDKaacEnc_11025_long_1024, &p_FDKaacEnc_11025_short_128}, + {12000, &p_FDKaacEnc_12000_long_1024, &p_FDKaacEnc_12000_short_128}, + {16000, &p_FDKaacEnc_16000_long_1024, &p_FDKaacEnc_16000_short_128}, + {22050, &p_FDKaacEnc_22050_long_1024, &p_FDKaacEnc_22050_short_128}, + {24000, &p_FDKaacEnc_24000_long_1024, &p_FDKaacEnc_24000_short_128}, + {32000, &p_FDKaacEnc_32000_long_1024, &p_FDKaacEnc_32000_short_128}, + {44100, &p_FDKaacEnc_44100_long_1024, &p_FDKaacEnc_44100_short_128}, + {48000, &p_FDKaacEnc_48000_long_1024, &p_FDKaacEnc_48000_short_128}, + {64000, &p_FDKaacEnc_64000_long_1024, &p_FDKaacEnc_64000_short_128}, + {88200, &p_FDKaacEnc_88200_long_1024, &p_FDKaacEnc_88200_short_128}, + {96000, &p_FDKaacEnc_96000_long_1024, &p_FDKaacEnc_96000_short_128} + +}; + +/* 22050 and 24000 Hz */ +static const SFB_PARAM_LONG p_22050_long_512 = { + 31, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 8, 8, 8, 12, 12, 12, 16, 20, 24, + 28, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32} +}; + +/* 32000 Hz */ +static const SFB_PARAM_LONG p_32000_long_512 = { + 37, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 8, 8, 8, 8, 8, 12, + 12, 12, 12, 16, 16, 16, 20, 24, 24, 28, + 32, 32, 32, 32, 32, 32, 32} +}; + +/* 44100 Hz */ +static const SFB_PARAM_LONG p_44100_long_512 = { + 36, + {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, + 12, 12, 12, 12, 16, 20, 24, 28, 32, 32, + 32, 32, 32, 32, 32, 52} +}; + +static const SFB_INFO_TAB sfbInfoTabLD512[] = { + { 8000, &p_22050_long_512, NULL}, + {11025, &p_22050_long_512, NULL}, + {12000, &p_22050_long_512, NULL}, + {16000, &p_22050_long_512, NULL}, + {22050, &p_22050_long_512, NULL}, + {24000, &p_22050_long_512, NULL}, + {32000, &p_32000_long_512, NULL}, + {44100, &p_44100_long_512, NULL}, + {48000, &p_44100_long_512, NULL}, + {64000, &p_44100_long_512, NULL}, + {88200, &p_44100_long_512, NULL}, + {96000, &p_44100_long_512, NULL}, + +}; + + +/* 22050 and 24000 Hz */ +static const SFB_PARAM_LONG p_22050_long_480 = { + 30, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 8, 8, 8, 12, 12, 12, 16, 20, 24, + 28, 32, 32, 32, 32, 32, 32, 32, 32, 32} +}; + +/* 32000 Hz */ +static const SFB_PARAM_LONG p_32000_long_480 = { + 37, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, + 8, 8, 12, 12, 12, 16, 16, 20, 24, 32, + 32, 32, 32, 32, 32, 32, 32} +}; + +/* 44100 Hz */ +static const SFB_PARAM_LONG p_44100_long_480 = { + 35, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 8, 8, 8, 8, 8, 12, + 12, 12, 12, 12, 16, 16, 24, 28, 32, 32, + 32, 32, 32, 32, 48} +}; + +static const SFB_INFO_TAB sfbInfoTabLD480[] = { + { 8000, &p_22050_long_480, NULL}, + {11025, &p_22050_long_480, NULL}, + {12000, &p_22050_long_480, NULL}, + {16000, &p_22050_long_480, NULL}, + {22050, &p_22050_long_480, NULL}, + {24000, &p_22050_long_480, NULL}, + {32000, &p_32000_long_480, NULL}, + {44100, &p_44100_long_480, NULL}, + {48000, &p_44100_long_480, NULL}, + {64000, &p_44100_long_480, NULL}, + {88200, &p_44100_long_480, NULL}, + {96000, &p_44100_long_480, NULL}, + +}; + +/* Fixed point precision definitions */ +#define Q_BARCVAL (25) + +static AAC_ENCODER_ERROR FDKaacEnc_initSfbTable(LONG sampleRate, INT blockType, INT granuleLength, INT *sfbOffset, INT *sfbCnt) +{ + INT i, specStartOffset = 0; + const UCHAR* sfbWidth = NULL; + const SFB_INFO_TAB *sfbInfo = NULL; + int size; + + /* + select table + */ + switch(granuleLength) { + case 1024: + case 960: + sfbInfo = sfbInfoTab; + size = (INT)(sizeof(sfbInfoTab)/sizeof(SFB_INFO_TAB)); + break; + case 512: + sfbInfo = sfbInfoTabLD512; + size = sizeof(sfbInfoTabLD512); + break; + case 480: + sfbInfo = sfbInfoTabLD480; + size = sizeof(sfbInfoTabLD480); + break; + default: + return AAC_ENC_INVALID_FRAME_LENGTH; + } + + for(i = 0; i < size; i++){ + if(sfbInfo[i].sampleRate == sampleRate){ + switch(blockType){ + case LONG_WINDOW: + case START_WINDOW: + case STOP_WINDOW: + sfbWidth = sfbInfo[i].paramLong->sfbWidth; + *sfbCnt = sfbInfo[i].paramLong->sfbCnt; + break; + case SHORT_WINDOW: + sfbWidth = sfbInfo[i].paramShort->sfbWidth; + *sfbCnt = sfbInfo[i].paramShort->sfbCnt; + granuleLength /= TRANS_FAC; + break; + } + break; + } + } + if (i == size) { + return AAC_ENC_UNSUPPORTED_SAMPLINGRATE; + } + + /* + calc sfb offsets + */ + for(i = 0; i < *sfbCnt; i++){ + sfbOffset[i] = specStartOffset; + specStartOffset += sfbWidth[i]; + if (specStartOffset >= granuleLength) { + i++; + break; + } + } + *sfbCnt = fixMin(i,*sfbCnt); + sfbOffset[*sfbCnt] = fixMin(specStartOffset,granuleLength); + + return AAC_ENC_OK; +} + + +/***************************************************************************** + + functionname: FDKaacEnc_BarcLineValue + description: Calculates barc value for one frequency line + returns: barc value of line + input: number of lines in transform, index of line to check, Fs + output: + +*****************************************************************************/ +static FIXP_DBL FDKaacEnc_BarcLineValue(INT noOfLines, INT fftLine, LONG samplingFreq) +{ + + FIXP_DBL FOURBY3EM4 = (FIXP_DBL)0x45e7b273; /* 4.0/3 * 0.0001 in q43 */ + FIXP_DBL PZZZ76 = (FIXP_DBL)0x639d5e4a; /* 0.00076 in q41 */ + FIXP_DBL ONE3P3 = (FIXP_DBL)0x35333333; /* 13.3 in q26 */ + FIXP_DBL THREEP5 = (FIXP_DBL)0x1c000000; /* 3.5 in q27 */ + FIXP_DBL INV480 = (FIXP_DBL)0x44444444; // 1/480 in q39 + + FIXP_DBL center_freq, x1, x2; + FIXP_DBL bvalFFTLine, atan1, atan2; + + /* Theoritical maximum of center_freq (samp_freq*0.5) is 96khz * 0.5 = 48000 */ + /* Theoritical maximum of x1 is 1.3333333e-4f * center_freq = 6.4, can keep in q28 */ + /* Theoritical maximum of x2 is 0.00076f * center_freq = 36.48, can keep in q25 */ + + center_freq = fftLine * samplingFreq; /* q11 or q8 */ + + switch (noOfLines) { + case 1024: + center_freq = center_freq << 2; /* q13 */ + break; + case 128: + center_freq = center_freq << 5; /* q13 */ + break; + case 512: + center_freq = (fftLine * samplingFreq) << 3; // q13 + break; + case 480: + center_freq = fMult(center_freq, INV480) << 4; // q13 + break; + default: + center_freq = (FIXP_DBL)0; + } + + x1 = fMult(center_freq, FOURBY3EM4); /* q13 * q43 - (DFRACT_BITS-1) = q25 */ + x2 = fMult(center_freq, PZZZ76) << 2; /* q13 * q41 - (DFRACT_BITS-1) + 2 = q25 */ + + atan1 = fixp_atan(x1); + atan2 = fixp_atan(x2); + + /* q25 (q26 * q30 - (DFRACT_BITS-1)) + q25 (q27 * q30 * q30) */ + bvalFFTLine = fMult(ONE3P3, atan2) + fMult(THREEP5, fMult(atan1, atan1)); + return(bvalFFTLine); + +} + +/* + do not consider energies below a certain input signal level, + i.e. of -96dB or 1 bit at 16 bit PCM resolution, + might need to be configurable to e.g. 24 bit PCM Input or a lower + resolution for low bit rates +*/ +static void FDKaacEnc_InitMinPCMResolution(int numPb, + int *pbOffset, + FIXP_DBL *sfbPCMquantThreshold) +{ + /* PCM_QUANT_NOISE = FDKpow(10.0f, - 20.f / 10.0f) * ABS_LOW * NORM_PCM_ENERGY * FDKpow(2,PCM_QUANT_THR_SCALE) */ + #define PCM_QUANT_NOISE ((FIXP_DBL)0x00547062) + + for( int i = 0; i < numPb; i++ ) { + sfbPCMquantThreshold[i] = (pbOffset[i+1] - pbOffset[i]) * PCM_QUANT_NOISE; + } +} + +static FIXP_DBL getMaskFactor( + const FIXP_DBL dbVal_fix, + const INT dbVal_e, + const FIXP_DBL ten_fix, + const INT ten_e + ) +{ + INT q_msk; + FIXP_DBL mask_factor; + + mask_factor = fPow(ten_fix, DFRACT_BITS-1-ten_e, -dbVal_fix, DFRACT_BITS-1-dbVal_e, &q_msk); + q_msk = fixMin(DFRACT_BITS-1,fixMax(-(DFRACT_BITS-1),q_msk)); + + if ( (q_msk>0) && (mask_factor>(FIXP_DBL)MAXVAL_DBL>>q_msk) ) { + mask_factor = (FIXP_DBL)MAXVAL_DBL; + } + else { + mask_factor = scaleValue(mask_factor, q_msk); + } + + return (mask_factor); +} + +static void FDKaacEnc_initSpreading(INT numPb, + FIXP_DBL *pbBarcValue, + FIXP_DBL *pbMaskLoFactor, + FIXP_DBL *pbMaskHiFactor, + FIXP_DBL *pbMaskLoFactorSprEn, + FIXP_DBL *pbMaskHiFactorSprEn, + const LONG bitrate, + const INT blockType) + +{ + INT i; + FIXP_DBL MASKLOWSPREN, MASKHIGHSPREN; + + FIXP_DBL MASKHIGH = (FIXP_DBL)0x30000000; /* 1.5 in q29 */ + FIXP_DBL MASKLOW = (FIXP_DBL)0x60000000; /* 3.0 in q29 */ + FIXP_DBL MASKLOWSPRENLONG = (FIXP_DBL)0x60000000; /* 3.0 in q29 */ + FIXP_DBL MASKHIGHSPRENLONG = (FIXP_DBL)0x40000000; /* 2.0 in q29 */ + FIXP_DBL MASKHIGHSPRENLONGLOWBR = (FIXP_DBL)0x30000000; /* 1.5 in q29 */ + FIXP_DBL MASKLOWSPRENSHORT = (FIXP_DBL)0x40000000; /* 2.0 in q29 */ + FIXP_DBL MASKHIGHSPRENSHORT = (FIXP_DBL)0x30000000; /* 1.5 in q29 */ + FIXP_DBL TEN = (FIXP_DBL)0x50000000; /* 10.0 in q27 */ + + if (blockType != SHORT_WINDOW) + { + MASKLOWSPREN = MASKLOWSPRENLONG; + MASKHIGHSPREN = (bitrate>20000)?MASKHIGHSPRENLONG:MASKHIGHSPRENLONGLOWBR; + } + else + { + MASKLOWSPREN = MASKLOWSPRENSHORT; + MASKHIGHSPREN = MASKHIGHSPRENSHORT; + } + + for(i=0; i 0) + { + pbMaskHiFactor[i] = getMaskFactor( + fMult(MASKHIGH, (pbBarcValue[i] - pbBarcValue[i-1])), 23, + TEN, 27); + + pbMaskLoFactor[i-1] = getMaskFactor( + fMult(MASKLOW, (pbBarcValue[i] - pbBarcValue[i-1])), 23, + TEN, 27); + + pbMaskHiFactorSprEn[i] = getMaskFactor( + fMult(MASKHIGHSPREN, (pbBarcValue[i] - pbBarcValue[i-1])), 23, + TEN, 27); + + pbMaskLoFactorSprEn[i-1] = getMaskFactor( + fMult(MASKLOWSPREN, (pbBarcValue[i] - pbBarcValue[i-1])), 23, + TEN, 27); + } + else + { + pbMaskHiFactor[i] = (FIXP_DBL)0; + pbMaskLoFactor[numPb-1] = (FIXP_DBL)0; + pbMaskHiFactorSprEn[i] = (FIXP_DBL)0; + pbMaskLoFactorSprEn[numPb-1] = (FIXP_DBL)0; + } + } +} + +static void FDKaacEnc_initBarcValues(INT numPb, + INT *pbOffset, + INT numLines, + INT samplingFrequency, + FIXP_DBL *pbBval) +{ + INT i; + FIXP_DBL MAX_BARC = (FIXP_DBL)0x30000000; /* 24.0 in q25 */ + + for(i=0; i> 1) + (v2 >> 1); + pbBval[i] = fixMin(cur_bark, MAX_BARC); + } +} + +static void FDKaacEnc_initMinSnr(const LONG bitrate, + const LONG samplerate, + const INT numLines, + const INT *sfbOffset, + const INT sfbActive, + const INT blockType, + FIXP_DBL *sfbMinSnrLdData) +{ + INT sfb; + + /* Fix conversion variables */ + INT qbfac, qperwin, qdiv, qpeprt_const, qpeprt; + INT qtmp, qsnr, sfbWidth; + + FIXP_DBL MAX_BARC = (FIXP_DBL)0x30000000; /* 24.0 in q25 */ + FIXP_DBL MAX_BARCP1 = (FIXP_DBL)0x32000000; /* 25.0 in q25 */ + FIXP_DBL BITS2PEFAC = (FIXP_DBL)0x4b851eb8; /* 1.18 in q30 */ + FIXP_DBL PERS2P4 = (FIXP_DBL)0x624dd2f2; /* 0.024 in q36 */ + FIXP_DBL ONEP5 = (FIXP_DBL)0x60000000; /* 1.5 in q30 */ + FIXP_DBL MAX_SNR = (FIXP_DBL)0x33333333; /* 0.8 in q30 */ + FIXP_DBL MIN_SNR = (FIXP_DBL)0x003126e9; /* 0.003 in q30 */ + + FIXP_DBL barcFactor, pePerWindow, pePart, barcWidth; + FIXP_DBL pePart_const, tmp, snr, one_qsnr, one_point5; + + /* relative number of active barks */ + barcFactor = fDivNorm(fixMin(FDKaacEnc_BarcLineValue(numLines, sfbOffset[sfbActive], samplerate), MAX_BARC), + MAX_BARCP1, &qbfac); + + qbfac = DFRACT_BITS-1-qbfac; + + pePerWindow = fDivNorm(bitrate, samplerate, &qperwin); + qperwin = DFRACT_BITS-1-qperwin; + pePerWindow = fMult(pePerWindow, BITS2PEFAC); qperwin = qperwin + 30 - (DFRACT_BITS-1); + pePerWindow = fMult(pePerWindow, PERS2P4); qperwin = qperwin + 36 - (DFRACT_BITS-1); + + switch (numLines) { + case 1024: + qperwin = qperwin - 10; + break; + case 128: + qperwin = qperwin - 7; + break; + case 512: + qperwin = qperwin - 9; + break; + case 480: + qperwin = qperwin - 9; + pePerWindow = fMult(pePerWindow, FL2FXCONST_DBL(480.f/512.f)); + break; + } + + /* for short blocks it is assumed that more bits are available */ + if (blockType == SHORT_WINDOW) + { + pePerWindow = fMult(pePerWindow, ONEP5); + qperwin = qperwin + 30 - (DFRACT_BITS-1); + } + pePart_const = fDivNorm(pePerWindow, barcFactor, &qdiv); qpeprt_const = qperwin - qbfac + DFRACT_BITS-1-qdiv; + + for (sfb = 0; sfb < sfbActive; sfb++) + { + barcWidth = FDKaacEnc_BarcLineValue(numLines, sfbOffset[sfb+1], samplerate) - + FDKaacEnc_BarcLineValue(numLines, sfbOffset[sfb], samplerate); + + /* adapt to sfb bands */ + pePart = fMult(pePart_const, barcWidth); qpeprt = qpeprt_const + 25 - (DFRACT_BITS-1); + + /* pe -> snr calculation */ + sfbWidth = (sfbOffset[sfb+1] - sfbOffset[sfb]); + pePart = fDivNorm(pePart, sfbWidth, &qdiv); qpeprt += DFRACT_BITS-1-qdiv; + + tmp = f2Pow(pePart, DFRACT_BITS-1-qpeprt, &qtmp); + qtmp = DFRACT_BITS-1-qtmp; + + /* Subtract 1.5 */ + qsnr = fixMin(qtmp, 30); + tmp = tmp >> (qtmp - qsnr); + + if((30+1-qsnr) > (DFRACT_BITS-1)) + one_point5 = (FIXP_DBL)0; + else + one_point5 = (FIXP_DBL)(ONEP5 >> (30+1-qsnr)); + + snr = (tmp>>1) - (one_point5); qsnr -= 1; + + /* max(snr, 1.0) */ + if(qsnr > 0) + one_qsnr = (FIXP_DBL)(1 << qsnr); + else + one_qsnr = (FIXP_DBL)0; + + snr = fixMax(one_qsnr, snr); + + /* 1/snr */ + snr = fDivNorm(one_qsnr, snr, &qsnr); + qsnr = DFRACT_BITS-1-qsnr; + snr = (qsnr > 30)? (snr>>(qsnr-30)):snr; + + /* upper limit is -1 dB */ + snr = (snr > MAX_SNR) ? MAX_SNR : snr; + + /* lower limit is -25 dB */ + snr = (snr < MIN_SNR) ? MIN_SNR : snr; + snr = snr << 1; + + sfbMinSnrLdData[sfb] = CalcLdData(snr); + } +} + +AAC_ENCODER_ERROR FDKaacEnc_InitPsyConfiguration(INT bitrate, + INT samplerate, + INT bandwidth, + INT blocktype, + INT granuleLength, + INT useIS, + PSY_CONFIGURATION *psyConf, + FB_TYPE filterbank) +{ + AAC_ENCODER_ERROR ErrorStatus; + INT sfb; + FIXP_DBL sfbBarcVal[MAX_SFB]; + const INT frameLengthLong = granuleLength; + const INT frameLengthShort = granuleLength/TRANS_FAC; + + FDKmemclear(psyConf, sizeof(PSY_CONFIGURATION)); + psyConf->granuleLength = granuleLength; + psyConf->filterbank = filterbank; + + psyConf->allowIS = (useIS) && ( (bitrate/bandwidth) < 5 ); + + /* init sfb table */ + ErrorStatus = FDKaacEnc_initSfbTable(samplerate,blocktype,granuleLength,psyConf->sfbOffset,&psyConf->sfbCnt); + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + + /* calculate barc values for each pb */ + FDKaacEnc_initBarcValues(psyConf->sfbCnt, + psyConf->sfbOffset, + psyConf->sfbOffset[psyConf->sfbCnt], + samplerate, + sfbBarcVal); + + FDKaacEnc_InitMinPCMResolution(psyConf->sfbCnt, + psyConf->sfbOffset, + psyConf->sfbPcmQuantThreshold); + + /* calculate spreading function */ + FDKaacEnc_initSpreading(psyConf->sfbCnt, + sfbBarcVal, + psyConf->sfbMaskLowFactor, + psyConf->sfbMaskHighFactor, + psyConf->sfbMaskLowFactorSprEn, + psyConf->sfbMaskHighFactorSprEn, + bitrate, + blocktype); + + /* init ratio */ + + psyConf->maxAllowedIncreaseFactor = 2; /* integer */ + psyConf->minRemainingThresholdFactor = (FIXP_SGL)0x0148; /* FL2FXCONST_SGL(0.01f); */ /* fract */ + + psyConf->clipEnergy = (FIXP_DBL)0x773593ff; /* FL2FXCONST_DBL(1.0e9*NORM_PCM_ENERGY); */ + + if (blocktype!=SHORT_WINDOW) { + psyConf->lowpassLine = (INT)((2*bandwidth*frameLengthLong)/samplerate); + psyConf->lowpassLineLFE = LFE_LOWPASS_LINE; + } + else { + psyConf->lowpassLine = (INT)((2*bandwidth*frameLengthShort)/samplerate); + psyConf->lowpassLineLFE = 0; /* LFE only in lonf blocks */ + /* psyConf->clipEnergy /= (TRANS_FAC * TRANS_FAC); */ + psyConf->clipEnergy >>= 6; + } + + for (sfb = 0; sfb < psyConf->sfbCnt; sfb++){ + if (psyConf->sfbOffset[sfb] >= psyConf->lowpassLine) + break; + } + psyConf->sfbActive = sfb; + + for (sfb = 0; sfb < psyConf->sfbCnt; sfb++){ + if (psyConf->sfbOffset[sfb] >= psyConf->lowpassLineLFE) + break; + } + psyConf->sfbActiveLFE = sfb; + + /* calculate minSnr */ + FDKaacEnc_initMinSnr(bitrate, + samplerate, + psyConf->sfbOffset[psyConf->sfbCnt], + psyConf->sfbOffset, + psyConf->sfbActive, + blocktype, + psyConf->sfbMinSnrLdData); + + return AAC_ENC_OK; +} + diff --git a/libAACenc/src/psy_configuration.h b/libAACenc/src/psy_configuration.h new file mode 100644 index 0000000..aa60500 --- /dev/null +++ b/libAACenc/src/psy_configuration.h @@ -0,0 +1,102 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Psychoaccoustic configuration + +******************************************************************************/ +#ifndef _PSY_CONFIGURATION_H +#define _PSY_CONFIGURATION_H + + +#include "aacenc.h" +#include "common_fix.h" + +#include "psy_const.h" +#include "aacenc_tns.h" +#include "aacenc_pns.h" + +#define THR_SHIFTBITS 4 +#define PCM_QUANT_THR_SCALE 16 + +#define C_RATIO (FIXP_DBL)0x02940a10 /* FL2FXCONST_DBL(0.001258925f) << THR_SHIFTBITS; */ /* pow(10.0f, -(29.0f/10.0f)) */ + +typedef struct{ + + INT sfbCnt; /* number of existing sf bands */ + INT sfbActive; /* number of sf bands containing energy after lowpass */ + INT sfbActiveLFE; + INT sfbOffset[MAX_SFB+1]; + + INT filterbank; /* LC, LD or ELD */ + + FIXP_DBL sfbPcmQuantThreshold[MAX_SFB]; + + INT maxAllowedIncreaseFactor; /* preecho control */ + FIXP_SGL minRemainingThresholdFactor; + + INT lowpassLine; + INT lowpassLineLFE; + FIXP_DBL clipEnergy; /* for level dependend tmn */ + + FIXP_DBL sfbMaskLowFactor[MAX_SFB]; + FIXP_DBL sfbMaskHighFactor[MAX_SFB]; + + FIXP_DBL sfbMaskLowFactorSprEn[MAX_SFB]; + FIXP_DBL sfbMaskHighFactorSprEn[MAX_SFB]; + + FIXP_DBL sfbMinSnrLdData[MAX_SFB]; /* minimum snr (formerly known as bmax) */ + + TNS_CONFIG tnsConf; + PNS_CONFIG pnsConf; + + INT granuleLength; + INT allowIS; + +}PSY_CONFIGURATION; + + +typedef struct{ + UCHAR sfbCnt; /* Number of scalefactor bands */ + UCHAR sfbWidth[MAX_SFB_LONG]; /* Width of scalefactor bands for long blocks */ +}SFB_PARAM_LONG; + +typedef struct{ + UCHAR sfbCnt; /* Number of scalefactor bands */ + UCHAR sfbWidth[MAX_SFB_SHORT]; /* Width of scalefactor bands for short blocks */ +}SFB_PARAM_SHORT; + + +AAC_ENCODER_ERROR FDKaacEnc_InitPsyConfiguration(INT bitrate, + INT samplerate, + INT bandwidth, + INT blocktype, + INT granuleLength, + INT useIS, + PSY_CONFIGURATION *psyConf, + FB_TYPE filterbank); + +#endif /* _PSY_CONFIGURATION_H */ + + + diff --git a/libAACenc/src/psy_const.h b/libAACenc/src/psy_const.h new file mode 100644 index 0000000..d9d59d9 --- /dev/null +++ b/libAACenc/src/psy_const.h @@ -0,0 +1,99 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Global psychoaccoustic constants + +******************************************************************************/ +#ifndef _PSYCONST_H +#define _PSYCONST_H + + +#define TRUE 1 +#define FALSE 0 + + #define TRANS_FAC 8 /* encoder short long ratio */ + +#define FRAME_MAXLEN_SHORT ((1024)/TRANS_FAC) +#define FRAME_LEN_SHORT_128 ((1024)/TRANS_FAC) +#define FRAME_LEN_SHORT_120 (FRAME_LEN_LONG_960/TRANS_FAC) + +/* Filterbank type*/ +enum FB_TYPE { + FB_LC = 0, + FB_LD = 1, + FB_ELD = 2 +}; + +/* Block types */ +#define N_BLOCKTYPES 6 +enum +{ + LONG_WINDOW = 0, + START_WINDOW, + SHORT_WINDOW, + STOP_WINDOW, + _LOWOV_WINDOW, /* Do not use this block type out side of block_switch.cpp */ + WRONG_WINDOW +}; + +/* Window shapes */ +enum +{ + SINE_WINDOW = 0, + KBD_WINDOW = 1, + LOL_WINDOW = 2 /* Low OverLap window shape for AAC-LD */ +}; + +/* + MS stuff +*/ +enum +{ + SI_MS_MASK_NONE = 0, + SI_MS_MASK_SOME = 1, + SI_MS_MASK_ALL = 2 +}; + + + #define MAX_NO_OF_GROUPS 4 + #define MAX_SFB_LONG 51 /* 51 for a memory optimized implementation, maybe 64 for convenient debugging */ + #define MAX_SFB_SHORT 15 /* 15 for a memory optimized implementation, maybe 16 for convenient debugging */ + +#define MAX_SFB (MAX_SFB_SHORT > MAX_SFB_LONG ? MAX_SFB_SHORT : MAX_SFB_LONG) /* = 51 */ +#define MAX_GROUPED_SFB (MAX_NO_OF_GROUPS*MAX_SFB_SHORT > MAX_SFB_LONG ? \ + MAX_NO_OF_GROUPS*MAX_SFB_SHORT : MAX_SFB_LONG) /* = 60 */ + +#define MAX_INPUT_BUFFER_SIZE (2*(1024)) /* 2048 */ + + +#define PCM_LEVEL 1.0f +#define NORM_PCM (PCM_LEVEL/32768.0f) +#define NORM_PCM_ENERGY (NORM_PCM*NORM_PCM) +#define LOG_NORM_PCM -15 + +#define TNS_PREDGAIN_SCALE (1000) + +#define LFE_LOWPASS_LINE 12 + +#endif /* _PSYCONST_H */ diff --git a/libAACenc/src/psy_data.h b/libAACenc/src/psy_data.h new file mode 100644 index 0000000..af3cde8 --- /dev/null +++ b/libAACenc/src/psy_data.h @@ -0,0 +1,89 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Psychoaccoustic data + +******************************************************************************/ +#ifndef _PSY_DATA_H +#define _PSY_DATA_H + + +#include "block_switch.h" + +/* Be careful with MAX_SFB_LONG as length of the .Long arrays. + * sfbEnergy.Long and sfbEnergyMS.Long and sfbThreshold.Long are used as a temporary storage for the regrouped + * short energies and thresholds between FDKaacEnc_groupShortData() and BuildInterface() in FDKaacEnc_psyMain(). + * The space required for this is MAX_GROUPED_SFB ( = MAX_NO_OF_GROUPS*MAX_SFB_SHORT ). + * However, this is not important if unions are used (which is not possible with pfloat). */ + +typedef shouldBeUnion{ + FIXP_DBL Long[MAX_GROUPED_SFB]; + FIXP_DBL Short[TRANS_FAC][MAX_SFB_SHORT]; +}SFB_THRESHOLD; + +typedef shouldBeUnion{ + FIXP_DBL Long[MAX_GROUPED_SFB]; + FIXP_DBL Short[TRANS_FAC][MAX_SFB_SHORT]; +}SFB_ENERGY; + +typedef shouldBeUnion{ + FIXP_DBL Long[MAX_GROUPED_SFB]; + FIXP_DBL Short[TRANS_FAC][MAX_SFB_SHORT]; +}SFB_LD_ENERGY; + +typedef shouldBeUnion{ + INT Long[MAX_GROUPED_SFB]; + INT Short[TRANS_FAC][MAX_SFB_SHORT]; +}SFB_MAX_SCALE; + + +typedef struct{ + INT_PCM* psyInputBuffer; + FIXP_DBL RESTRICT overlapAddBuffer[1024]; + + BLOCK_SWITCHING_CONTROL blockSwitchingControl; /* block switching */ + FIXP_DBL sfbThresholdnm1[MAX_SFB]; /* FDKaacEnc_PreEchoControl */ + INT mdctScalenm1; /* scale of last block's mdct (FDKaacEnc_PreEchoControl) */ + INT calcPreEcho; + INT isLFE; +}PSY_STATIC; + + +typedef struct{ + FIXP_DBL *mdctSpectrum; + SFB_THRESHOLD sfbThreshold; /* adapt */ + SFB_ENERGY sfbEnergy; /* sfb energies */ + SFB_LD_ENERGY sfbEnergyLdData; /* sfb energies in ldData format */ + SFB_MAX_SCALE sfbMaxScaleSpec; + SFB_ENERGY sfbEnergyMS; /* mid/side sfb energies */ + FIXP_DBL sfbEnergyMSLdData[MAX_GROUPED_SFB]; /* mid/side sfb energies in ldData format */ + SFB_ENERGY sfbSpreadEnergy; + INT mdctScale; /* exponent of data in mdctSpectrum */ + INT groupedSfbOffset[MAX_GROUPED_SFB+1]; + INT sfbActive; + INT lowpassLine; +}PSY_DATA; + + +#endif /* _PSY_DATA_H */ diff --git a/libAACenc/src/psy_main.cpp b/libAACenc/src/psy_main.cpp new file mode 100644 index 0000000..bfc8b3b --- /dev/null +++ b/libAACenc/src/psy_main.cpp @@ -0,0 +1,1338 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Psychoaccoustic major function block + +******************************************************************************/ + +#include "psy_const.h" + +#include "block_switch.h" +#include "transform.h" +#include "spreading.h" +#include "pre_echo_control.h" +#include "band_nrg.h" +#include "psy_configuration.h" +#include "psy_data.h" +#include "ms_stereo.h" +#include "interface.h" +#include "psy_main.h" +#include "grp_data.h" +#include "tns_func.h" +#include "pns_func.h" +#include "tonality.h" +#include "aacEnc_ram.h" +#include "intensity.h" + + +#ifdef PSY_MAIN_DEBUG_INFO +FDKFILE *fSpectrumOut; +#endif + +/* blending to reduce gibbs artifacts */ +#define FADE_OUT_LEN 6 +static const FIXP_DBL fadeOutFactor[FADE_OUT_LEN] = {1840644096, 1533870080, 1227096064, 920322048, 613548032, 306774016}; + +/* forward definitions */ + + +static inline int isLowDelay( AUDIO_OBJECT_TYPE aot ) +{ + return (aot==AOT_ER_AAC_LD || aot==AOT_ER_AAC_ELD); +} + +/***************************************************************************** + + functionname: FDKaacEnc_PsyNew + description: allocates memory for psychoacoustic + returns: an error code + input: pointer to a psych handle + +*****************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_PsyNew(PSY_INTERNAL **phpsy, + const INT nElements, + const INT nChannels + ,UCHAR *dynamic_RAM + ) +{ + AAC_ENCODER_ERROR ErrorStatus; + PSY_INTERNAL *hPsy; + INT i; + + hPsy = GetRam_aacEnc_PsyInternal(); + *phpsy = hPsy; + if (hPsy == NULL) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto bail; + } + + for (i=0; ipsyElement[i] = GetRam_aacEnc_PsyElement(i); + if (hPsy->psyElement[i] == NULL) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto bail; + } + } + + for (i=0; ipStaticChannels[i] = GetRam_aacEnc_PsyStatic(i); + if (hPsy->pStaticChannels[i]==NULL) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto bail; + } + /* AUDIO INPUT BUFFER */ + hPsy->pStaticChannels[i]->psyInputBuffer = GetRam_aacEnc_PsyInputBuffer(i); + if (hPsy->pStaticChannels[i]->psyInputBuffer==NULL) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto bail; + } + } + + /* reusable psych memory */ + hPsy->psyDynamic = GetRam_aacEnc_PsyDynamic(0, dynamic_RAM); + + return AAC_ENC_OK; + +bail: + FDKaacEnc_PsyClose(phpsy, NULL); + + return ErrorStatus; +} + +/***************************************************************************** + + functionname: FDKaacEnc_PsyOutNew + description: allocates memory for psyOut struc + returns: an error code + input: pointer to a psych handle + +*****************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_PsyOutNew(PSY_OUT **phpsyOut, + const INT nElements, + const INT nChannels, + const INT nSubFrames + ,UCHAR *dynamic_RAM + ) +{ + AAC_ENCODER_ERROR ErrorStatus; + int n, i; + int elInc = 0, chInc = 0; + + for (n=0; npPsyOutChannels[i] = GetRam_aacEnc_PsyOutChannel(chInc++); + } + + for (i=0; ipsyOutElement[i] = GetRam_aacEnc_PsyOutElements(elInc++); + if (phpsyOut[n]->psyOutElement[i] == NULL) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto bail; + } + } + } /* nSubFrames */ + + return AAC_ENC_OK; + +bail: + FDKaacEnc_PsyClose(NULL, phpsyOut); + return ErrorStatus; +} + + +AAC_ENCODER_ERROR FDKaacEnc_psyInitStates(PSY_INTERNAL *hPsy, + PSY_STATIC* psyStatic, + AUDIO_OBJECT_TYPE audioObjectType) +{ + /* init input buffer */ + FDKmemclear(psyStatic->psyInputBuffer, MAX_INPUT_BUFFER_SIZE*sizeof(INT_PCM)); + + FDKaacEnc_InitBlockSwitching(&psyStatic->blockSwitchingControl, + isLowDelay(audioObjectType) + ); + + return AAC_ENC_OK; +} + + +AAC_ENCODER_ERROR FDKaacEnc_psyInit(PSY_INTERNAL *hPsy, + PSY_OUT **phpsyOut, + const INT nSubFrames, + const INT nMaxChannels, + const AUDIO_OBJECT_TYPE audioObjectType, + CHANNEL_MAPPING *cm) +{ + AAC_ENCODER_ERROR ErrorStatus = AAC_ENC_OK; + int i, ch, n, chInc = 0, resetChannels = 3; + + if ( (nMaxChannels>2) && (cm->nChannels==2) ) { + chInc = 1; + FDKaacEnc_psyInitStates(hPsy, hPsy->pStaticChannels[0], audioObjectType); + } + + if ( (nMaxChannels==2) ) { + resetChannels = 0; + } + + for (i=0; inElements; i++) { + for (ch=0; chelInfo[i].nChannelsInEl; ch++) { + if (cm->elInfo[i].elType!=ID_LFE) { + hPsy->psyElement[i]->psyStatic[ch] = hPsy->pStaticChannels[chInc]; + if (chInc>=resetChannels) { + FDKaacEnc_psyInitStates(hPsy, hPsy->psyElement[i]->psyStatic[ch], audioObjectType); + } + hPsy->psyElement[i]->psyStatic[ch]->isLFE = 0; + } + else { + hPsy->psyElement[i]->psyStatic[ch] = hPsy->pStaticChannels[nMaxChannels-1]; + hPsy->psyElement[i]->psyStatic[ch]->isLFE = 1; + } + chInc++; + } + } + + for (n=0; nnElements; i++) { + for (ch=0; chelInfo[i].nChannelsInEl; ch++) { + phpsyOut[n]->psyOutElement[i]->psyOutChannel[ch] = phpsyOut[n]->pPsyOutChannels[chInc++]; + } + } + } + + return ErrorStatus; +} + + +/***************************************************************************** + + functionname: FDKaacEnc_psyMainInit + description: initializes psychoacoustic + returns: an error code + +*****************************************************************************/ + +AAC_ENCODER_ERROR FDKaacEnc_psyMainInit(PSY_INTERNAL *hPsy, + AUDIO_OBJECT_TYPE audioObjectType, + CHANNEL_MAPPING *cm, + INT sampleRate, + INT granuleLength, + INT bitRate, + INT tnsMask, + INT bandwidth, + INT usePns, + INT useIS, + UINT syntaxFlags, + ULONG initFlags) +{ + AAC_ENCODER_ERROR ErrorStatus; + int i, ch; + int channelsEff = cm->nChannelsEff; + int tnsChannels = 0; + FB_TYPE filterBank; + +#ifdef PSY_MAIN_DEBUG_INFO + fSpectrumOut = FDKfopen("psy_main_spectrum2.raw", "wb"); +#endif + + switch(FDKaacEnc_GetMonoStereoMode(cm->encMode)) { + /* ... and map to tnsChannels */ + case EL_MODE_MONO: tnsChannels = 1; break; + case EL_MODE_STEREO: tnsChannels = 2; break; + default: tnsChannels = 0; + } + + switch (audioObjectType) + { + default: filterBank = FB_LC; break; + case AOT_ER_AAC_LD: filterBank = FB_LD; break; + case AOT_ER_AAC_ELD: filterBank = FB_ELD; break; + } + + hPsy->granuleLength = granuleLength; + + ErrorStatus = FDKaacEnc_InitPsyConfiguration(bitRate/channelsEff, sampleRate, bandwidth, LONG_WINDOW, hPsy->granuleLength, useIS, &(hPsy->psyConf[0]), filterBank); + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + + ErrorStatus = FDKaacEnc_InitTnsConfiguration( + (bitRate*tnsChannels)/channelsEff, + sampleRate, + tnsChannels, + LONG_WINDOW, + hPsy->granuleLength, + (syntaxFlags&AC_SBR_PRESENT)?1:0, + &(hPsy->psyConf[0].tnsConf), + &hPsy->psyConf[0], + (INT)(tnsMask&2), + (INT)(tnsMask&8) ); + + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + + if (granuleLength > 512) { + ErrorStatus = FDKaacEnc_InitPsyConfiguration(bitRate/channelsEff, sampleRate, bandwidth, SHORT_WINDOW, hPsy->granuleLength, useIS, &hPsy->psyConf[1], filterBank); + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + + ErrorStatus = FDKaacEnc_InitTnsConfiguration( + (bitRate*tnsChannels)/channelsEff, + sampleRate, + tnsChannels, + SHORT_WINDOW, + hPsy->granuleLength, + (syntaxFlags&AC_SBR_PRESENT)?1:0, + &hPsy->psyConf[1].tnsConf, + &hPsy->psyConf[1], + (INT)(tnsMask&1), + (INT)(tnsMask&4) ); + + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + + } + + + for (i=0; inElements; i++) { + for (ch=0; chelInfo[i].nChannelsInEl; ch++) { + if (initFlags) { + /* reset states */ + FDKaacEnc_psyInitStates(hPsy, hPsy->psyElement[i]->psyStatic[ch], audioObjectType); + } + + FDKaacEnc_InitPreEchoControl(hPsy->psyElement[i]->psyStatic[ch]->sfbThresholdnm1, + &hPsy->psyElement[i]->psyStatic[ch]->calcPreEcho, + hPsy->psyConf[0].sfbCnt, + hPsy->psyConf[0].sfbPcmQuantThreshold, + &hPsy->psyElement[i]->psyStatic[ch]->mdctScalenm1); + } + } + + ErrorStatus = FDKaacEnc_InitPnsConfiguration(&hPsy->psyConf[0].pnsConf, + bitRate/channelsEff, + sampleRate, + usePns, + hPsy->psyConf[0].sfbCnt, + hPsy->psyConf[0].sfbOffset, + cm->elInfo[0].nChannelsInEl, + (hPsy->psyConf[0].filterbank == FB_LC)); + if (ErrorStatus != AAC_ENC_OK) + return ErrorStatus; + + ErrorStatus = FDKaacEnc_InitPnsConfiguration(&hPsy->psyConf[1].pnsConf, + bitRate/channelsEff, + sampleRate, + usePns, + hPsy->psyConf[1].sfbCnt, + hPsy->psyConf[1].sfbOffset, + cm->elInfo[1].nChannelsInEl, + (hPsy->psyConf[1].filterbank == FB_LC)); + return ErrorStatus; +} + + +static +void FDKaacEnc_deinterleaveInputBuffer(INT_PCM *pOutputSamples, + INT_PCM *pInputSamples, + INT nSamples, + INT nChannels) +{ + INT k; + /* deinterlave input samples and write to output buffer */ + for (k=0; kpsyOutChannel; + FIXP_SGL sfbTonality[(2)][MAX_SFB_LONG]; + + PSY_STATIC **RESTRICT psyStatic = psyElement->psyStatic; + + PSY_DATA *RESTRICT psyData[(2)]; + TNS_DATA *RESTRICT tnsData[(2)]; + PNS_DATA *RESTRICT pnsData[(2)]; + + INT zeroSpec = TRUE; /* means all spectral lines are zero */ + + INT blockSwitchingOffset; + + PSY_CONFIGURATION *RESTRICT hThisPsyConf[(2)]; + INT windowLength[(2)]; + INT nWindows[(2)]; + INT wOffset; + + INT maxSfb[(2)]; + INT *pSfbMaxScaleSpec[(2)]; + FIXP_DBL *pSfbEnergy[(2)]; + FIXP_DBL *pSfbSpreadEnergy[(2)]; + FIXP_DBL *pSfbEnergyLdData[(2)]; + FIXP_DBL *pSfbEnergyMS[(2)]; + FIXP_DBL *pSfbThreshold[(2)]; + + INT isShortWindow[(2)]; + + + if (hPsyConfLong->filterbank == FB_LC) { + blockSwitchingOffset = psyConf->granuleLength + (9*psyConf->granuleLength/(2*TRANS_FAC)); + } else { + blockSwitchingOffset = psyConf->granuleLength; + } + + for(ch = 0; ch < channels; ch++) + { + psyData[ch] = &psyDynamic->psyData[ch]; + tnsData[ch] = &psyDynamic->tnsData[ch]; + pnsData[ch] = &psyDynamic->pnsData[ch]; + + psyData[ch]->mdctSpectrum = psyOutChannel[ch]->mdctSpectrum; + } + + /* block switching */ + if (hPsyConfLong->filterbank != FB_ELD) + { + int err; + + for(ch = 0; ch < channels; ch++) + { + C_ALLOC_SCRATCH_START(timeSignal, INT_PCM, (1024)); + psyStatic[ch]->blockSwitchingControl.timeSignal = timeSignal; + + /* deinterleave input data and use for block switching */ + FDKaacEnc_deinterleaveInputBuffer( psyStatic[ch]->blockSwitchingControl.timeSignal, + &pInput[chIdx[ch]], + psyConf->granuleLength, + totalChannels); + + + FDKaacEnc_BlockSwitching (&psyStatic[ch]->blockSwitchingControl, + psyConf->granuleLength + ,psyStatic[ch]->isLFE + ); + + + /* fill up internal input buffer, to 2xframelength samples */ + FDKmemcpy(psyStatic[ch]->psyInputBuffer+blockSwitchingOffset, + psyStatic[ch]->blockSwitchingControl.timeSignal, + (2*psyConf->granuleLength-blockSwitchingOffset)*sizeof(INT_PCM)); + + C_ALLOC_SCRATCH_END(timeSignal, INT_PCM, (1024)); + } + + /* synch left and right block type */ + err = FDKaacEnc_SyncBlockSwitching(&psyStatic[0]->blockSwitchingControl, + &psyStatic[1]->blockSwitchingControl, + channels, + commonWindow); + + if (err) { + return AAC_ENC_UNSUPPORTED_AOT; /* mixed up LC and LD */ + } + + } + else { + for(ch = 0; ch < channels; ch++) + { + /* deinterleave input data and use for block switching */ + FDKaacEnc_deinterleaveInputBuffer( psyStatic[ch]->psyInputBuffer + blockSwitchingOffset, + &pInput[chIdx[ch]], + psyConf->granuleLength, + totalChannels); + } + } + + for(ch = 0; ch < channels; ch++) + isShortWindow[ch]=(psyStatic[ch]->blockSwitchingControl.lastWindowSequence == SHORT_WINDOW); + + /* set parameters according to window length */ + for(ch = 0; ch < channels; ch++) + { + if(isShortWindow[ch]) { + hThisPsyConf[ch] = hPsyConfShort; + windowLength[ch] = psyConf->granuleLength/TRANS_FAC; + nWindows[ch] = TRANS_FAC; + maxSfb[ch] = MAX_SFB_SHORT; + + pSfbMaxScaleSpec[ch] = psyData[ch]->sfbMaxScaleSpec.Short[0]; + pSfbEnergy[ch] = psyData[ch]->sfbEnergy.Short[0]; + pSfbSpreadEnergy[ch] = psyData[ch]->sfbSpreadEnergy.Short[0]; + pSfbEnergyLdData[ch] = psyData[ch]->sfbEnergyLdData.Short[0]; + pSfbEnergyMS[ch] = psyData[ch]->sfbEnergyMS.Short[0]; + pSfbThreshold[ch] = psyData[ch]->sfbThreshold.Short[0]; + + } else + { + hThisPsyConf[ch] = hPsyConfLong; + windowLength[ch] = psyConf->granuleLength; + nWindows[ch] = 1; + maxSfb[ch] = MAX_GROUPED_SFB; + + pSfbMaxScaleSpec[ch] = psyData[ch]->sfbMaxScaleSpec.Long; + pSfbEnergy[ch] = psyData[ch]->sfbEnergy.Long; + pSfbSpreadEnergy[ch] = psyData[ch]->sfbSpreadEnergy.Long; + pSfbEnergyLdData[ch] = psyData[ch]->sfbEnergyLdData.Long; + pSfbEnergyMS[ch] = psyData[ch]->sfbEnergyMS.Long; + pSfbThreshold[ch] = psyData[ch]->sfbThreshold.Long; + } + } + + /* Transform and get mdctScaling for all channels and windows. */ + for(ch = 0; ch < channels; ch++) + { + /* update number of active bands */ + if (psyStatic[ch]->isLFE) { + psyData[ch]->sfbActive = hThisPsyConf[ch]->sfbActiveLFE; + psyData[ch]->lowpassLine = hThisPsyConf[ch]->lowpassLineLFE; + } else + { + psyData[ch]->sfbActive = hThisPsyConf[ch]->sfbActive; + psyData[ch]->lowpassLine = hThisPsyConf[ch]->lowpassLine; + } + + for(w = 0; w < nWindows[ch]; w++) { + + wOffset = w*windowLength[ch]; + + FDKaacEnc_Transform_Real( psyStatic[ch]->psyInputBuffer + wOffset, + psyData[ch]->mdctSpectrum+wOffset, + psyStatic[ch]->blockSwitchingControl.lastWindowSequence, + psyStatic[ch]->blockSwitchingControl.windowShape, + &psyStatic[ch]->blockSwitchingControl.lastWindowShape, + psyConf->granuleLength, + &mdctSpectrum_e, + hThisPsyConf[ch]->filterbank + ,psyStatic[ch]->overlapAddBuffer + ); + + /* Low pass / highest sfb */ + FDKmemclear(&psyData[ch]->mdctSpectrum[psyData[ch]->lowpassLine+wOffset], + (windowLength[ch]-psyData[ch]->lowpassLine)*sizeof(FIXP_DBL)); + + if (hPsyConfLong->filterbank != FB_LC) { + /* Do blending to reduce gibbs artifacts */ + for (int i=0; imdctSpectrum[psyData[ch]->lowpassLine+wOffset - FADE_OUT_LEN + i] = fMult(psyData[ch]->mdctSpectrum[psyData[ch]->lowpassLine+wOffset - FADE_OUT_LEN + i], fadeOutFactor[i]); + } + } + + + /* Check for zero spectrum. These loops will usually terminate very, very early. */ + for(line=0; (linelowpassLine) && (zeroSpec==TRUE); line++) { + if (psyData[ch]->mdctSpectrum[line+wOffset] != (FIXP_DBL)0) { + zeroSpec = FALSE; + break; + } + } + + } /* w loop */ + + psyData[ch]->mdctScale = mdctSpectrum_e; + + /* rotate internal time samples */ + FDKmemmove(psyStatic[ch]->psyInputBuffer, + psyStatic[ch]->psyInputBuffer+psyConf->granuleLength, + psyConf->granuleLength*sizeof(INT_PCM)); + + + /* ... and get remaining samples from input buffer */ + FDKaacEnc_deinterleaveInputBuffer( psyStatic[ch]->psyInputBuffer+psyConf->granuleLength, + &pInput[ (2*psyConf->granuleLength-blockSwitchingOffset)*totalChannels + chIdx[ch] ], + blockSwitchingOffset-psyConf->granuleLength, + totalChannels); + + } /* ch */ + + /* Do some rescaling to get maximum possible accuracy for energies */ + if ( zeroSpec == FALSE) { + + /* Calc possible spectrum leftshift for each sfb (1 means: 1 bit left shift is possible without overflow) */ + INT minSpecShift = MAX_SHIFT_DBL; + INT nrgShift = MAX_SHIFT_DBL; + INT finalShift = MAX_SHIFT_DBL; + FIXP_DBL currNrg = 0; + FIXP_DBL maxNrg = 0; + + for(ch = 0; ch < channels; ch++) { + for(w = 0; w < nWindows[ch]; w++) { + wOffset = w*windowLength[ch]; + FDKaacEnc_CalcSfbMaxScaleSpec(psyData[ch]->mdctSpectrum+wOffset, + hThisPsyConf[ch]->sfbOffset, + pSfbMaxScaleSpec[ch]+w*maxSfb[ch], + psyData[ch]->sfbActive); + + for (sfb = 0; sfbsfbActive; sfb++) + minSpecShift = fixMin(minSpecShift, (pSfbMaxScaleSpec[ch]+w*maxSfb[ch])[sfb]); + } + + } + + /* Calc possible energy leftshift for each sfb (1 means: 1 bit left shift is possible without overflow) */ + for(ch = 0; ch < channels; ch++) { + for(w = 0; w < nWindows[ch]; w++) { + wOffset = w*windowLength[ch]; + currNrg = FDKaacEnc_CheckBandEnergyOptim(psyData[ch]->mdctSpectrum+wOffset, + pSfbMaxScaleSpec[ch]+w*maxSfb[ch], + hThisPsyConf[ch]->sfbOffset, + psyData[ch]->sfbActive, + pSfbEnergy[ch]+w*maxSfb[ch], + pSfbEnergyLdData[ch]+w*maxSfb[ch], + minSpecShift-4); + + maxNrg = fixMax(maxNrg, currNrg); + } + } + + if ( maxNrg != (FIXP_DBL)0 ) { + nrgShift = (CountLeadingBits(maxNrg)>>1) + (minSpecShift-4); + } + + /* 2check: Hasn't this decision to be made for both channels? */ + /* For short windows 1 additional bit headroom is necessary to prevent overflows when summing up energies in FDKaacEnc_groupShortData() */ + if(isShortWindow[0]) nrgShift--; + + /* both spectrum and energies mustn't overflow */ + finalShift = fixMin(minSpecShift, nrgShift); + + /* do not shift more than 3 bits more to the left than signal without blockfloating point + * would be to avoid overflow of scaled PCM quantization thresholds */ + if (finalShift > psyData[0]->mdctScale + 3 ) + finalShift = psyData[0]->mdctScale + 3; + + FDK_ASSERT(finalShift >= 0); /* right shift is not allowed */ + + /* correct sfbEnergy and sfbEnergyLdData with new finalShift */ + FIXP_DBL ldShift = finalShift * FL2FXCONST_DBL(2.0/64); + for(ch = 0; ch < channels; ch++) { + for(w = 0; w < nWindows[ch]; w++) { + for(sfb=0; sfbsfbActive; sfb++) { + INT scale = fixMax(0, (pSfbMaxScaleSpec[ch]+w*maxSfb[ch])[sfb]-4); + scale = fixMin((scale-finalShift)<<1, DFRACT_BITS-1); + if (scale >= 0) (pSfbEnergy[ch]+w*maxSfb[ch])[sfb] >>= (scale); + else (pSfbEnergy[ch]+w*maxSfb[ch])[sfb] <<= (-scale); + (pSfbThreshold[ch]+w*maxSfb[ch])[sfb] = fMult((pSfbEnergy[ch]+w*maxSfb[ch])[sfb], C_RATIO); + (pSfbEnergyLdData[ch]+w*maxSfb[ch])[sfb] += ldShift; + } + } + } + + if ( finalShift != 0 ) { + for (ch = 0; ch < channels; ch++) { + for(w = 0; w < nWindows[ch]; w++) { + wOffset = w*windowLength[ch]; + for(line=0; linelowpassLine; line++) { + psyData[ch]->mdctSpectrum[line+wOffset] <<= finalShift; + } + /* update sfbMaxScaleSpec */ + for (sfb = 0; sfbsfbActive; sfb++) + (pSfbMaxScaleSpec[ch]+w*maxSfb[ch])[sfb] -= finalShift; + } + /* update mdctScale */ + psyData[ch]->mdctScale -= finalShift; + } + } + + } else { + /* all spectral lines are zero */ + for (ch = 0; ch < channels; ch++) { + psyData[ch]->mdctScale = 0; /* otherwise mdctScale would be for example 7 and PCM quantization thresholds would be shifted + * 14 bits to the right causing some of them to become 0 (which causes problems later) */ + /* clear sfbMaxScaleSpec */ + for(w = 0; w < nWindows[ch]; w++) { + for (sfb = 0; sfbsfbActive; sfb++) { + (pSfbMaxScaleSpec[ch]+w*maxSfb[ch])[sfb] = 0; + (pSfbEnergy[ch]+w*maxSfb[ch])[sfb] = (FIXP_DBL)0; + (pSfbEnergyLdData[ch]+w*maxSfb[ch])[sfb] = FL2FXCONST_DBL(-1.0f); + (pSfbThreshold[ch]+w*maxSfb[ch])[sfb] = (FIXP_DBL)0; + } + } + } + } + + /* Advance psychoacoustics: Tonality and TNS */ + if (psyStatic[0]->isLFE) { + tnsData[0]->dataRaw.Long.subBlockInfo.tnsActive = 0; + } + else + { + + for(ch = 0; ch < channels; ch++) { + if (!isShortWindow[ch]) { + /* tonality */ + FDKaacEnc_CalculateFullTonality( psyData[ch]->mdctSpectrum, + pSfbMaxScaleSpec[ch], + pSfbEnergyLdData[ch], + sfbTonality[ch], + psyData[ch]->sfbActive, + hThisPsyConf[ch]->sfbOffset, + hThisPsyConf[ch]->pnsConf.usePns); + } + } + + if (hPsyConfLong->tnsConf.tnsActive || hPsyConfShort->tnsConf.tnsActive) { + INT tnsActive[TRANS_FAC]; + INT nrgScaling[2] = {0,0}; + INT tnsSpecShift = 0; + + for(ch = 0; ch < channels; ch++) { + for(w = 0; w < nWindows[ch]; w++) { + + wOffset = w*windowLength[ch]; + /* TNS */ + FDKaacEnc_TnsDetect( + tnsData[ch], + &hThisPsyConf[ch]->tnsConf, + &psyOutChannel[ch]->tnsInfo, + hThisPsyConf[ch]->sfbCnt, + psyData[ch]->mdctSpectrum+wOffset, + w, + psyStatic[ch]->blockSwitchingControl.lastWindowSequence + ); + } + } + + if (channels == 2) { + FDKaacEnc_TnsSync( + tnsData[1], + tnsData[0], + &psyOutChannel[1]->tnsInfo, + &psyOutChannel[0]->tnsInfo, + + psyStatic[1]->blockSwitchingControl.lastWindowSequence, + psyStatic[0]->blockSwitchingControl.lastWindowSequence, + &hThisPsyConf[1]->tnsConf); + } + + FDK_ASSERT(commonWindow=1); /* all checks for TNS do only work for common windows (which is always set)*/ + for(w = 0; w < nWindows[0]; w++) + { + if (isShortWindow[0]) + tnsActive[w] = tnsData[0]->dataRaw.Short.subBlockInfo[w].tnsActive || + ((channels == 2) ? tnsData[1]->dataRaw.Short.subBlockInfo[w].tnsActive : 0); + else + tnsActive[w] = tnsData[0]->dataRaw.Long.subBlockInfo.tnsActive || + ((channels == 2) ? tnsData[1]->dataRaw.Long.subBlockInfo.tnsActive : 0); + } + + for(ch = 0; ch < channels; ch++) { + if (tnsActive[0] && !isShortWindow[ch]) { + /* Scale down spectrum if tns is active in one of the two channels with same lastWindowSequence */ + /* first part of threshold calculation; it's not necessary to update sfbMaxScaleSpec */ + INT shift = 1; + for(sfb=0; sfblowpassLine; sfb++) { + psyData[ch]->mdctSpectrum[sfb] = psyData[ch]->mdctSpectrum[sfb] >> shift; + } + + /* update thresholds */ + for (sfb=0; sfbsfbActive; sfb++) { + pSfbThreshold[ch][sfb] >>= (2*shift); + } + + psyData[ch]->mdctScale += shift; /* update mdctScale */ + + /* calc sfbEnergies after tnsEncode again ! */ + + } + } + + for(ch = 0; ch < channels; ch++) { + for(w = 0; w < nWindows[ch]; w++) + { + wOffset = w*windowLength[ch]; + FDKaacEnc_TnsEncode( + &psyOutChannel[ch]->tnsInfo, + tnsData[ch], + hThisPsyConf[ch]->sfbCnt, + &hThisPsyConf[ch]->tnsConf, + hThisPsyConf[ch]->sfbOffset[psyData[ch]->sfbActive],/*hThisPsyConf[ch]->lowpassLine*/ /* filter stops before that line ! */ + psyData[ch]->mdctSpectrum+wOffset, + w, + psyStatic[ch]->blockSwitchingControl.lastWindowSequence); + + if(tnsActive[w]) { + /* Calc sfb-bandwise mdct-energies for left and right channel again, */ + /* if tns active in current channel or in one channel with same lastWindowSequence left and right */ + FDKaacEnc_CalcSfbMaxScaleSpec(psyData[ch]->mdctSpectrum+wOffset, + hThisPsyConf[ch]->sfbOffset, + pSfbMaxScaleSpec[ch]+w*maxSfb[ch], + psyData[ch]->sfbActive); + } + } + } + + for(ch = 0; ch < channels; ch++) { + for(w = 0; w < nWindows[ch]; w++) { + + if (tnsActive[w]) { + + if (isShortWindow[ch]) { + FDKaacEnc_CalcBandEnergyOptimShort(psyData[ch]->mdctSpectrum+w*windowLength[ch], + pSfbMaxScaleSpec[ch]+w*maxSfb[ch], + hThisPsyConf[ch]->sfbOffset, + psyData[ch]->sfbActive, + pSfbEnergy[ch]+w*maxSfb[ch]); + } + else { + nrgScaling[ch] = /* with tns, energy calculation can overflow; -> scaling */ + FDKaacEnc_CalcBandEnergyOptimLong(psyData[ch]->mdctSpectrum, + pSfbMaxScaleSpec[ch], + hThisPsyConf[ch]->sfbOffset, + psyData[ch]->sfbActive, + pSfbEnergy[ch], + pSfbEnergyLdData[ch]); + tnsSpecShift = fixMax(tnsSpecShift, nrgScaling[ch]); /* nrgScaling is set only if nrg would have an overflow */ + } + } /* if tnsActive */ + } + } /* end channel loop */ + + /* adapt scaling to prevent nrg overflow, only for long blocks */ + for(ch = 0; ch < channels; ch++) { + if ( (tnsSpecShift!=0) && !isShortWindow[ch] ) { + /* scale down spectrum, nrg's and thresholds, if there was an overflow in sfbNrg calculation after tns */ + for(line=0; linelowpassLine; line++) { + psyData[ch]->mdctSpectrum[line] >>= tnsSpecShift; + } + INT scale = (tnsSpecShift-nrgScaling[ch])<<1; + for(sfb=0; sfbsfbActive; sfb++) { + pSfbEnergyLdData[ch][sfb] -= scale*FL2FXCONST_DBL(1.0/LD_DATA_SCALING); + pSfbEnergy[ch][sfb] >>= scale; + pSfbThreshold[ch][sfb] >>= (tnsSpecShift<<1); + } + psyData[ch]->mdctScale += tnsSpecShift; /* update mdctScale; not necessary to update sfbMaxScaleSpec */ + + } + } /* end channel loop */ + + } /* TNS active */ + } /* !isLFE */ + + + + + +#ifdef PSY_MAIN_DEBUG_INFO + for(ch = 0; ch < channels; ch++) { + FDKfwrite(psyData[ch]->mdctSpectrum, sizeof(FIXP_DBL), psyConf->granuleLength, fSpectrumOut); + } +#endif + + /* Advance thresholds */ + for(ch = 0; ch < channels; ch++) { + INT headroom; + + FIXP_DBL clipEnergy; + INT energyShift = psyData[ch]->mdctScale*2 ; + INT clipNrgShift = energyShift - THR_SHIFTBITS ; + + if(isShortWindow[ch]) + headroom = 6; + else + headroom = 0; + + if (clipNrgShift >= 0) + clipEnergy = hThisPsyConf[ch]->clipEnergy >> clipNrgShift ; + else if (clipNrgShift>=-headroom) + clipEnergy = hThisPsyConf[ch]->clipEnergy << -clipNrgShift ; + else + clipEnergy = (FIXP_DBL)MAXVAL_DBL ; + + for(w = 0; w < nWindows[ch]; w++) + { + INT i; + /* limit threshold to avoid clipping */ + for (i=0; isfbActive; i++) { + *(pSfbThreshold[ch]+w*maxSfb[ch]+i) = fixMin(*(pSfbThreshold[ch]+w*maxSfb[ch]+i), clipEnergy); + } + + /* spreading */ + FDKaacEnc_SpreadingMax(psyData[ch]->sfbActive, + hThisPsyConf[ch]->sfbMaskLowFactor, + hThisPsyConf[ch]->sfbMaskHighFactor, + pSfbThreshold[ch]+w*maxSfb[ch]); + + + /* PCM quantization threshold */ + energyShift += PCM_QUANT_THR_SCALE; + if (energyShift>=0) { + energyShift = fixMin(DFRACT_BITS-1,energyShift); + for (i=0; isfbActive;i++) { + *(pSfbThreshold[ch]+w*maxSfb[ch]+i) = fixMax(*(pSfbThreshold[ch]+w*maxSfb[ch]+i) >> THR_SHIFTBITS, + (hThisPsyConf[ch]->sfbPcmQuantThreshold[i] >> energyShift)); + } + } else { + energyShift = fixMin(DFRACT_BITS-1,-energyShift); + for (i=0; isfbActive;i++) { + *(pSfbThreshold[ch]+w*maxSfb[ch]+i) = fixMax(*(pSfbThreshold[ch]+w*maxSfb[ch]+i) >> THR_SHIFTBITS, + (hThisPsyConf[ch]->sfbPcmQuantThreshold[i] << energyShift)); + } + } + + if (!psyStatic[ch]->isLFE) + { + /* preecho control */ + if(psyStatic[ch]->blockSwitchingControl.lastWindowSequence == STOP_WINDOW) { + /* prevent FDKaacEnc_PreEchoControl from comparing stop + thresholds with short thresholds */ + for (i=0; isfbActive;i++) { + psyStatic[ch]->sfbThresholdnm1[i] = (FIXP_DBL)MAXVAL_DBL; + } + + psyStatic[ch]->mdctScalenm1 = 0; + psyStatic[ch]->calcPreEcho = 0; + } + + FDKaacEnc_PreEchoControl( psyStatic[ch]->sfbThresholdnm1, + psyStatic[ch]->calcPreEcho, + psyData[ch]->sfbActive, + hThisPsyConf[ch]->maxAllowedIncreaseFactor, + hThisPsyConf[ch]->minRemainingThresholdFactor, + pSfbThreshold[ch]+w*maxSfb[ch], + psyData[ch]->mdctScale, + &psyStatic[ch]->mdctScalenm1); + + psyStatic[ch]->calcPreEcho = 1; + + if(psyStatic[ch]->blockSwitchingControl.lastWindowSequence == START_WINDOW) + { + /* prevent FDKaacEnc_PreEchoControl in next frame to compare start + thresholds with short thresholds */ + for (i=0; isfbActive;i++) { + psyStatic[ch]->sfbThresholdnm1[i] = (FIXP_DBL)MAXVAL_DBL; + } + + psyStatic[ch]->mdctScalenm1 = 0; + psyStatic[ch]->calcPreEcho = 0; + } + + } + + /* spread energy to avoid hole detection */ + FDKmemcpy(pSfbSpreadEnergy[ch]+w*maxSfb[ch], pSfbEnergy[ch]+w*maxSfb[ch], psyData[ch]->sfbActive*sizeof(FIXP_DBL)); + + FDKaacEnc_SpreadingMax(psyData[ch]->sfbActive, + hThisPsyConf[ch]->sfbMaskLowFactorSprEn, + hThisPsyConf[ch]->sfbMaskHighFactorSprEn, + pSfbSpreadEnergy[ch]+w*maxSfb[ch]); + } + } + + /* Calc bandwise energies for mid and side channel. Do it only if 2 channels exist */ + if (channels==2) { + for(w = 0; w < nWindows[1]; w++) { + wOffset = w*windowLength[1]; + FDKaacEnc_CalcBandNrgMSOpt(psyData[0]->mdctSpectrum+wOffset, + psyData[1]->mdctSpectrum+wOffset, + pSfbMaxScaleSpec[0]+w*maxSfb[0], + pSfbMaxScaleSpec[1]+w*maxSfb[1], + hThisPsyConf[1]->sfbOffset, + psyData[0]->sfbActive, + pSfbEnergyMS[0]+w*maxSfb[0], + pSfbEnergyMS[1]+w*maxSfb[1], + (psyStatic[1]->blockSwitchingControl.lastWindowSequence != SHORT_WINDOW), + psyData[0]->sfbEnergyMSLdData, + psyData[1]->sfbEnergyMSLdData); + } + } + + /* group short data (maxSfb[ch] for short blocks is determined here) */ + for(ch=0;chblockSwitchingControl.noOfGroups * hPsyConfShort->sfbCnt; + /* At this point, energies and thresholds are copied/regrouped from the ".Short" to the ".Long" arrays */ + FDKaacEnc_groupShortData( psyData[ch]->mdctSpectrum, + &psyData[ch]->sfbThreshold, + &psyData[ch]->sfbEnergy, + &psyData[ch]->sfbEnergyMS, + &psyData[ch]->sfbSpreadEnergy, + hPsyConfShort->sfbCnt, + psyData[ch]->sfbActive, + hPsyConfShort->sfbOffset, + hPsyConfShort->sfbMinSnrLdData, + psyData[ch]->groupedSfbOffset, + &maxSfbPerGroup[ch], + psyOutChannel[ch]->sfbMinSnrLdData, + psyStatic[ch]->blockSwitchingControl.noOfGroups, + psyStatic[ch]->blockSwitchingControl.groupLen, + psyConf[1].granuleLength); + + + /* calculate ldData arrays (short values are in .Long-arrays after FDKaacEnc_groupShortData) */ + for (sfbGrp = 0; sfbGrp < noSfb; sfbGrp += hPsyConfShort->sfbCnt) { + LdDataVector(&psyData[ch]->sfbEnergy.Long[sfbGrp], &psyOutChannel[ch]->sfbEnergyLdData[sfbGrp], psyData[ch]->sfbActive); + } + + /* calc sfbThrld and set Values smaller 2^-31 to 2^-33*/ + for (sfbGrp = 0; sfbGrp < noSfb; sfbGrp += hPsyConfShort->sfbCnt) { + LdDataVector(&psyData[ch]->sfbThreshold.Long[sfbGrp], &psyOutChannel[ch]->sfbThresholdLdData[sfbGrp], psyData[ch]->sfbActive); + for (sfb=0;sfbsfbActive;sfb++) { + psyOutChannel[ch]->sfbThresholdLdData[sfbGrp+sfb] = + fixMax(psyOutChannel[ch]->sfbThresholdLdData[sfbGrp+sfb], FL2FXCONST_DBL(-0.515625f)); + } + } + + if ( channels==2 ) { + for (sfbGrp = 0; sfbGrp < noSfb; sfbGrp += hPsyConfShort->sfbCnt) { + LdDataVector(&psyData[ch]->sfbEnergyMS.Long[sfbGrp], &psyData[ch]->sfbEnergyMSLdData[sfbGrp], psyData[ch]->sfbActive); + } + } + + FDKmemcpy(psyOutChannel[ch]->sfbOffsets, psyData[ch]->groupedSfbOffset, (MAX_GROUPED_SFB+1)*sizeof(INT)); + + } else { + /* maxSfb[ch] for long blocks */ + for (sfb = psyData[ch]->sfbActive-1; sfb >= 0; sfb--) { + for (line = hPsyConfLong->sfbOffset[sfb+1]-1; line >= hPsyConfLong->sfbOffset[sfb]; line--) { + if (psyData[ch]->mdctSpectrum[line] != FL2FXCONST_SGL(0.0f)) break; + } + if (line > hPsyConfLong->sfbOffset[sfb]) break; + } + maxSfbPerGroup[ch] = sfb + 1; + /* ensure at least one section in ICS; workaround for existing decoder crc implementation */ + maxSfbPerGroup[ch] = fixMax(fixMin(5,psyData[ch]->sfbActive),maxSfbPerGroup[ch]); + + /* sfbNrgLdData is calculated in FDKaacEnc_advancePsychLong, copy in psyOut structure */ + FDKmemcpy(psyOutChannel[ch]->sfbEnergyLdData, psyData[ch]->sfbEnergyLdData.Long, psyData[ch]->sfbActive*sizeof(FIXP_DBL)); + + FDKmemcpy(psyOutChannel[ch]->sfbOffsets, hPsyConfLong->sfbOffset, (MAX_GROUPED_SFB+1)*sizeof(INT)); + + /* sfbMinSnrLdData modified in adjust threshold, copy necessary */ + FDKmemcpy(psyOutChannel[ch]->sfbMinSnrLdData, hPsyConfLong->sfbMinSnrLdData, psyData[ch]->sfbActive*sizeof(FIXP_DBL)); + + /* sfbEnergyMSLdData ist already calculated in FDKaacEnc_CalcBandNrgMSOpt; only in long case */ + + /* calc sfbThrld and set Values smaller 2^-31 to 2^-33*/ + LdDataVector(psyData[ch]->sfbThreshold.Long, psyOutChannel[ch]->sfbThresholdLdData, psyData[ch]->sfbActive); + for (i=0;isfbActive;i++) { + psyOutChannel[ch]->sfbThresholdLdData[i] = + fixMax(psyOutChannel[ch]->sfbThresholdLdData[i], FL2FXCONST_DBL(-0.515625f)); + } + + + } + + + } + + + /* + Intensity parameter intialization. + */ + for(ch=0;chisBook, MAX_GROUPED_SFB*sizeof(INT)); + FDKmemclear(psyOutChannel[ch]->isScale, MAX_GROUPED_SFB*sizeof(INT)); + } + + for(ch=0;chisLFE) + { + /* PNS Decision */ + FDKaacEnc_PnsDetect( &(psyConf[0].pnsConf), + pnsData[ch], + psyStatic[ch]->blockSwitchingControl.lastWindowSequence, + psyData[ch]->sfbActive, + maxSfbPerGroup[ch], /* count of Sfb which are not zero. */ + psyOutChannel[ch]->sfbThresholdLdData, + psyConf[win].sfbOffset, + psyData[ch]->mdctSpectrum, + psyData[ch]->sfbMaxScaleSpec.Long, + sfbTonality[ch], + psyOutChannel[ch]->tnsInfo.order[0][0], + tnsData[ch]->dataRaw.Long.subBlockInfo.predictionGain, + tnsData[ch]->dataRaw.Long.subBlockInfo.tnsActive, + psyOutChannel[ch]->sfbEnergyLdData, + psyOutChannel[ch]->noiseNrg ); + } /* !isLFE */ + } + + /* + stereo Processing + */ + if(channels == 2) + { + psyOutElement->toolsInfo.msDigest = MS_NONE; + psyOutElement->commonWindow = commonWindow; + if (psyOutElement->commonWindow) + maxSfbPerGroup[0] = maxSfbPerGroup[1] = + fixMax(maxSfbPerGroup[0], maxSfbPerGroup[1]); + + if(psyStatic[0]->blockSwitchingControl.lastWindowSequence != SHORT_WINDOW) + { + /* PNS preprocessing depending on ms processing: PNS not in Short Window! */ + FDKaacEnc_PreProcessPnsChannelPair( + psyData[0]->sfbActive, + (&psyData[0]->sfbEnergy)->Long, + (&psyData[1]->sfbEnergy)->Long, + psyOutChannel[0]->sfbEnergyLdData, + psyOutChannel[1]->sfbEnergyLdData, + psyData[0]->sfbEnergyMS.Long, + &(psyConf[0].pnsConf), + pnsData[0], + pnsData[1]); + + FDKaacEnc_IntensityStereoProcessing( + psyData[0]->sfbEnergy.Long, + psyData[1]->sfbEnergy.Long, + psyData[0]->mdctSpectrum, + psyData[1]->mdctSpectrum, + psyData[0]->sfbThreshold.Long, + psyData[1]->sfbThreshold.Long, + psyOutChannel[1]->sfbThresholdLdData, + psyData[0]->sfbSpreadEnergy.Long, + psyData[1]->sfbSpreadEnergy.Long, + psyOutChannel[0]->sfbEnergyLdData, + psyOutChannel[1]->sfbEnergyLdData, + &psyOutElement->toolsInfo.msDigest, + psyOutElement->toolsInfo.msMask, + psyConf[0].sfbCnt, + psyConf[0].sfbCnt, + maxSfbPerGroup[0], + psyConf[0].sfbOffset, + psyConf[0].allowIS && commonWindow, + psyOutChannel[1]->isBook, + psyOutChannel[1]->isScale, + pnsData); + + FDKaacEnc_MsStereoProcessing( + psyData, + psyOutChannel, + psyOutChannel[1]->isBook, + &psyOutElement->toolsInfo.msDigest, + psyOutElement->toolsInfo.msMask, + psyData[0]->sfbActive, + psyData[0]->sfbActive, + maxSfbPerGroup[0], + psyOutChannel[0]->sfbOffsets); + + /* PNS postprocessing */ + FDKaacEnc_PostProcessPnsChannelPair(psyData[0]->sfbActive, + &(psyConf[0].pnsConf), + pnsData[0], + pnsData[1], + psyOutElement->toolsInfo.msMask, + &psyOutElement->toolsInfo.msDigest); + + } else { + FDKaacEnc_IntensityStereoProcessing( + psyData[0]->sfbEnergy.Long, + psyData[1]->sfbEnergy.Long, + psyData[0]->mdctSpectrum, + psyData[1]->mdctSpectrum, + psyData[0]->sfbThreshold.Long, + psyData[1]->sfbThreshold.Long, + psyOutChannel[1]->sfbThresholdLdData, + psyData[0]->sfbSpreadEnergy.Long, + psyData[1]->sfbSpreadEnergy.Long, + psyOutChannel[0]->sfbEnergyLdData, + psyOutChannel[1]->sfbEnergyLdData, + &psyOutElement->toolsInfo.msDigest, + psyOutElement->toolsInfo.msMask, + psyStatic[0]->blockSwitchingControl.noOfGroups*hPsyConfShort->sfbCnt, + psyConf[1].sfbCnt, + maxSfbPerGroup[0], + psyData[0]->groupedSfbOffset, + psyConf[0].allowIS && commonWindow, + psyOutChannel[1]->isBook, + psyOutChannel[1]->isScale, + pnsData); + + /* it's OK to pass the ".Long" arrays here. They contain grouped short data since FDKaacEnc_groupShortData() */ + FDKaacEnc_MsStereoProcessing( psyData, + psyOutChannel, + psyOutChannel[1]->isBook, + &psyOutElement->toolsInfo.msDigest, + psyOutElement->toolsInfo.msMask, + psyStatic[0]->blockSwitchingControl.noOfGroups*hPsyConfShort->sfbCnt, + hPsyConfShort->sfbCnt, + maxSfbPerGroup[0], + psyOutChannel[0]->sfbOffsets); + } + } + + /* + PNS Coding + */ + for(ch=0;chisLFE) { + /* no PNS coding */ + for(sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) { + psyOutChannel[ch]->noiseNrg[sfb] = NO_NOISE_PNS; + } + } else + { + FDKaacEnc_CodePnsChannel(psyData[ch]->sfbActive, + &(psyConf[ch].pnsConf), + pnsData[ch]->pnsFlag, + psyData[ch]->sfbEnergyLdData.Long, + psyOutChannel[ch]->noiseNrg, /* this is the energy that will be written to the bitstream */ + psyOutChannel[ch]->sfbThresholdLdData); + } + } + + /* + build output + */ + for(ch=0;chmaxSfbPerGroup = maxSfbPerGroup[ch]; + psyOutChannel[ch]->mdctScale = psyData[ch]->mdctScale; + + if(isShortWindow[ch]==0) { + + psyOutChannel[ch]->sfbCnt = hPsyConfLong->sfbActive; + psyOutChannel[ch]->sfbPerGroup = hPsyConfLong->sfbActive; + psyOutChannel[ch]->lastWindowSequence = psyStatic[ch]->blockSwitchingControl.lastWindowSequence; + psyOutChannel[ch]->windowShape = psyStatic[ch]->blockSwitchingControl.windowShape; + } + else { + INT sfbCnt = psyStatic[ch]->blockSwitchingControl.noOfGroups*hPsyConfShort->sfbCnt; + + psyOutChannel[ch]->sfbCnt = sfbCnt; + psyOutChannel[ch]->sfbPerGroup = hPsyConfShort->sfbCnt; + psyOutChannel[ch]->lastWindowSequence = SHORT_WINDOW; + psyOutChannel[ch]->windowShape = SINE_WINDOW; + } + + /* generate grouping mask */ + mask = 0; + for (grp = 0; grp < psyStatic[ch]->blockSwitchingControl.noOfGroups; grp++) + { + mask <<= 1; + for (j=1; jblockSwitchingControl.groupLen[grp]; j++) { + mask = (mask<<1) | 1 ; + } + } + psyOutChannel[ch]->groupingMask = mask; + + /* build interface */ + FDKmemcpy(psyOutChannel[ch]->groupLen,psyStatic[ch]->blockSwitchingControl.groupLen,MAX_NO_OF_GROUPS*sizeof(INT)); + FDKmemcpy(psyOutChannel[ch]->sfbEnergy,(&psyData[ch]->sfbEnergy)->Long, MAX_GROUPED_SFB*sizeof(FIXP_DBL)); + FDKmemcpy(psyOutChannel[ch]->sfbSpreadEnergy,(&psyData[ch]->sfbSpreadEnergy)->Long, MAX_GROUPED_SFB*sizeof(FIXP_DBL)); +// FDKmemcpy(psyOutChannel[ch]->mdctSpectrum, psyData[ch]->mdctSpectrum, (1024)*sizeof(FIXP_DBL)); + } + + return AAC_ENC_OK; +} + + +void FDKaacEnc_PsyClose(PSY_INTERNAL **phPsyInternal, + PSY_OUT **phPsyOut) +{ + int n, i; + +#ifdef PSY_MAIN_DEBUG_INFO + if(fSpectrumOut!=NULL) + FDKfclose(fSpectrumOut); +#endif + + if(phPsyInternal!=NULL) { + PSY_INTERNAL *hPsyInternal = *phPsyInternal; + + if (hPsyInternal) + { + for (i=0; i<(6); i++) { + if (hPsyInternal->pStaticChannels[i]) { + if (hPsyInternal->pStaticChannels[i]->psyInputBuffer) + FreeRam_aacEnc_PsyInputBuffer(&hPsyInternal->pStaticChannels[i]->psyInputBuffer); /* AUDIO INPUT BUFFER */ + + FreeRam_aacEnc_PsyStatic(&hPsyInternal->pStaticChannels[i]); /* PSY_STATIC */ + } + } + + for (i=0; i<(6); i++) { + if (hPsyInternal->psyElement[i]) + FreeRam_aacEnc_PsyElement(&hPsyInternal->psyElement[i]); /* PSY_ELEMENT */ + } + + + FreeRam_aacEnc_PsyInternal(phPsyInternal); + } + } + + if (phPsyOut!=NULL) { + for (n=0; n<(1); n++) { + if (phPsyOut[n]) + { + for (i=0; i<(6); i++) { + if (phPsyOut[n]->pPsyOutChannels[i]) + FreeRam_aacEnc_PsyOutChannel(&phPsyOut[n]->pPsyOutChannels[i]); /* PSY_OUT_CHANNEL */ + } + + for (i=0; i<(6); i++) { + if (phPsyOut[n]->psyOutElement[i]) + FreeRam_aacEnc_PsyOutElements(&phPsyOut[n]->psyOutElement[i]); /* PSY_OUT_ELEMENTS */ + } + + FreeRam_aacEnc_PsyOut(&phPsyOut[n]); + } + } + } +} diff --git a/libAACenc/src/psy_main.h b/libAACenc/src/psy_main.h new file mode 100644 index 0000000..cb8819c --- /dev/null +++ b/libAACenc/src/psy_main.h @@ -0,0 +1,111 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Psychoaccoustic major function block + +******************************************************************************/ +#ifndef _PSYMAIN_H +#define _PSYMAIN_H + + +#include "psy_configuration.h" +#include "qc_data.h" +#include "aacenc_pns.h" + +/* + psych internal +*/ +typedef struct { + + PSY_STATIC* psyStatic[(2)]; + +}PSY_ELEMENT; + +typedef struct { + + PSY_DATA psyData[(2)]; + TNS_DATA tnsData[(2)]; + PNS_DATA pnsData[(2)]; + +}PSY_DYNAMIC; + + +typedef struct { + + PSY_CONFIGURATION psyConf[2]; /* LONG / SHORT */ + PSY_ELEMENT* psyElement[(6)]; + PSY_STATIC* pStaticChannels[(6)]; + PSY_DYNAMIC* psyDynamic; + INT granuleLength; + +}PSY_INTERNAL; + + +AAC_ENCODER_ERROR FDKaacEnc_PsyNew(PSY_INTERNAL **phpsy, + const INT nElements, + const INT nChannels + ,UCHAR *dynamic_RAM + ); + +AAC_ENCODER_ERROR FDKaacEnc_PsyOutNew(PSY_OUT **phpsyOut, + const INT nElements, + const INT nChannels, + const INT nSubFrames + ,UCHAR *dynamic_RAM + ); + +AAC_ENCODER_ERROR FDKaacEnc_psyInit(PSY_INTERNAL *hPsy, + PSY_OUT **phpsyOut, + const INT nSubFrames, + const INT nMaxChannels, + const AUDIO_OBJECT_TYPE audioObjectType, + CHANNEL_MAPPING *cm); + +AAC_ENCODER_ERROR FDKaacEnc_psyMainInit(PSY_INTERNAL *hPsy, + AUDIO_OBJECT_TYPE audioObjectType, + CHANNEL_MAPPING *cm, + INT sampleRate, + INT granuleLength, + INT bitRate, + INT tnsMask, + INT bandwidth, + INT usePns, + INT useIS, + UINT syntaxFlags, + ULONG initFlags); + +AAC_ENCODER_ERROR FDKaacEnc_psyMain(INT channels, + PSY_ELEMENT *psyElement, + PSY_DYNAMIC *psyDynamic, + PSY_CONFIGURATION *psyConf, + PSY_OUT_ELEMENT *psyOutElement, + INT_PCM *pInput, + INT *chIdx, + INT totalChannels + ); + +void FDKaacEnc_PsyClose(PSY_INTERNAL **phPsyInternal, + PSY_OUT **phPsyOut); + +#endif /* _PSYMAIN_H */ diff --git a/libAACenc/src/qc_data.h b/libAACenc/src/qc_data.h new file mode 100644 index 0000000..bbcffde --- /dev/null +++ b/libAACenc/src/qc_data.h @@ -0,0 +1,214 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Werner + contents/description: Quantizing & coding data + +******************************************************************************/ +#ifndef _QC_DATA_H +#define _QC_DATA_H + + +#include "psy_const.h" +#include "dyn_bits.h" +#include "adj_thr_data.h" +#include "line_pe.h" +#include "FDK_audio.h" +#include "interface.h" + + +typedef enum { + QCDATA_BR_MODE_INVALID = -1, + QCDATA_BR_MODE_CBR = 0, + QCDATA_BR_MODE_VBR_1 = 1, /* 32 kbps/channel */ + QCDATA_BR_MODE_VBR_2 = 2, /* 40 kbps/channel */ + QCDATA_BR_MODE_VBR_3 = 3, /* 48 kbps/channel */ + QCDATA_BR_MODE_VBR_4 = 4, /* 64 kbps/channel */ + QCDATA_BR_MODE_VBR_5 = 5, /* 96 kbps/channel */ + QCDATA_BR_MODE_FF = 6, /* Fixed frame mode. */ + QCDATA_BR_MODE_SFR = 7 /* Superframe mode. */ + + +} QCDATA_BR_MODE; + +typedef struct { + MP4_ELEMENT_ID elType; + INT instanceTag; + INT nChannelsInEl; + INT ChannelIndex[2]; + FIXP_DBL relativeBits; +} ELEMENT_INFO; + +typedef struct { + CHANNEL_MODE encMode; + INT nChannels; + INT nChannelsEff; + INT nElements; + ELEMENT_INFO elInfo[(6)]; +// INT elDSE; /* DSE element signalling */ +} CHANNEL_MAPPING; + +typedef struct { + INT paddingRest; +} PADDING; + + +/* Quantizing & coding stage */ + +struct QC_INIT{ + CHANNEL_MAPPING* channelMapping; + INT sceCpe; /* not used yet */ + INT maxBits; /* maximum number of bits in reservoir */ + INT averageBits; /* average number of bits we should use */ + INT bitRes; + INT staticBits; /* Bits per frame consumed by transport layers. */ + QCDATA_BR_MODE bitrateMode; + INT meanPe; + INT chBitrate; + INT invQuant; + INT maxIterations; /* Maximum number of allowed iterations before FDKaacEnc_crashRecovery() is applied. */ + FIXP_DBL maxBitFac; + INT bitrate; + INT nSubFrames; /* helper variable */ + INT minBits; /* minimal number of bits in one frame*/ + + PADDING padding; +}; + +typedef struct +{ + FIXP_DBL mdctSpectrum[(1024)]; + + SHORT quantSpec[(1024)]; + + UINT maxValueInSfb[MAX_GROUPED_SFB]; + INT scf[MAX_GROUPED_SFB]; + INT globalGain; + SECTION_DATA sectionData; + + FIXP_DBL sfbFormFactorLdData[MAX_GROUPED_SFB]; + + FIXP_DBL sfbThresholdLdData[MAX_GROUPED_SFB]; + FIXP_DBL sfbMinSnrLdData[MAX_GROUPED_SFB]; + FIXP_DBL sfbEnergyLdData[MAX_GROUPED_SFB]; + FIXP_DBL sfbEnergy[MAX_GROUPED_SFB]; + FIXP_DBL sfbWeightedEnergyLdData[MAX_GROUPED_SFB]; + + FIXP_DBL sfbEnFacLd[MAX_GROUPED_SFB]; + + FIXP_DBL sfbSpreadEnergy[MAX_GROUPED_SFB]; + +} QC_OUT_CHANNEL; + + +typedef struct +{ + EXT_PAYLOAD_TYPE type; /* type of the extension payload */ + INT nPayloadBits; /* size of the payload */ + UCHAR *pPayload; /* pointer to payload */ + +} QC_OUT_EXTENSION; + + +typedef struct +{ + INT staticBitsUsed; /* for verification purposes */ + INT dynBitsUsed; /* for verification purposes */ + + INT extBitsUsed; /* bit consumption of extended fill elements */ + INT nExtensions; /* number of extension payloads for this element */ + QC_OUT_EXTENSION extension[(1)]; /* reffering extension payload */ + + INT grantedDynBits; + + INT grantedPe; + INT grantedPeCorr; + + PE_DATA peData; + + QC_OUT_CHANNEL *qcOutChannel[(2)]; + + +} QC_OUT_ELEMENT; + +typedef struct +{ + QC_OUT_ELEMENT *qcElement[(6)]; + QC_OUT_CHANNEL *pQcOutChannels[(6)]; + QC_OUT_EXTENSION extension[(2+2)]; /* global extension payload */ + INT nExtensions; /* number of extension payloads for this AU */ + INT maxDynBits; /* maximal allowed dynamic bits in frame */ + INT grantedDynBits; /* granted dynamic bits in frame */ + INT totFillBits; /* fill bits */ + INT elementExtBits; /* element associated extension payload bits, e.g. sbr, drc ... */ + INT globalExtBits; /* frame/au associated extension payload bits (anc data ...) */ + INT staticBits; /* aac side info bits */ + + INT totalNoRedPe; + INT totalGrantedPeCorr; + + INT usedDynBits; /* number of dynamic bits in use */ + INT alignBits; /* AU alignment bits */ + INT totalBits; /* sum of static, dyn, sbr, fill, align and dse bits */ + +} QC_OUT; + +typedef struct { + INT chBitrateEl; /* channel bitrate in element (totalbitrate*el_relativeBits/el_channels) */ + INT maxBitsEl; /* used in crash recovery */ + INT bitResLevelEl; /* update bitreservoir level in each call of FDKaacEnc_QCMain */ + INT maxBitResBitsEl; /* nEffChannels*6144 - averageBitsInFrame */ + FIXP_DBL relativeBitsEl; /* Bits relative to total Bits*/ +} ELEMENT_BITS; + +typedef struct +{ + /* this is basically struct QC_INIT */ + + INT globHdrBits; + INT maxBitsPerFrame; /* maximal allowed bits per frame, 6144*nChannelsEff */ + INT minBitsPerFrame; /* minimal allowd bits per fram, superframing - DRM */ + INT nElements; + QCDATA_BR_MODE bitrateMode; + INT bitDistributenMode; /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir */ + INT bitResTot; + INT bitResTotMax; + INT maxIterations; /* Maximum number of allowed iterations before FDKaacEnc_crashRecovery() is applied. */ + INT invQuant; + + FIXP_DBL vbrQualFactor; + FIXP_DBL maxBitFac; + + PADDING padding; + + ELEMENT_BITS *elementBits[(6)]; + BITCNTR_STATE *hBitCounter; + ADJ_THR_STATE *hAdjThr; + +} QC_STATE; + +#endif /* _QC_DATA_H */ + + + + diff --git a/libAACenc/src/qc_main.cpp b/libAACenc/src/qc_main.cpp new file mode 100644 index 0000000..df9c4c4 --- /dev/null +++ b/libAACenc/src/qc_main.cpp @@ -0,0 +1,1551 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Werner + contents/description: Quantizing & coding + +******************************************************************************/ + +#include "qc_main.h" +#include "quantize.h" +#include "interface.h" +#include "adj_thr.h" +#include "sf_estim.h" +#include "bit_cnt.h" +#include "dyn_bits.h" +#include "channel_map.h" +#include "aacEnc_ram.h" + +#include "genericStds.h" + + +typedef struct { + QCDATA_BR_MODE bitrateMode; + LONG vbrQualFactor; +} TAB_VBR_QUAL_FACTOR; + +static const TAB_VBR_QUAL_FACTOR tableVbrQualFactor[] = { + {QCDATA_BR_MODE_CBR, FL2FXCONST_DBL(0.00f)}, + {QCDATA_BR_MODE_VBR_1, FL2FXCONST_DBL(0.160f)}, /* 32 kbps mono AAC-LC + SBR + PS */ + {QCDATA_BR_MODE_VBR_2, FL2FXCONST_DBL(0.148f)}, /* 64 kbps stereo AAC-LC + SBR */ + {QCDATA_BR_MODE_VBR_3, FL2FXCONST_DBL(0.135f)}, /* 80 - 96 kbps stereo AAC-LC */ + {QCDATA_BR_MODE_VBR_4, FL2FXCONST_DBL(0.111f)}, /* 128 kbps stereo AAC-LC */ + {QCDATA_BR_MODE_VBR_5, FL2FXCONST_DBL(0.070f)}, /* 192 kbps stereo AAC-LC */ + {QCDATA_BR_MODE_SFR, FL2FXCONST_DBL(0.00f)}, + {QCDATA_BR_MODE_FF, FL2FXCONST_DBL(0.00f)} +}; + +static INT isConstantBitrateMode( + const QCDATA_BR_MODE bitrateMode + ) +{ + return ( ((bitrateMode==QCDATA_BR_MODE_CBR) || (bitrateMode==QCDATA_BR_MODE_SFR) || (bitrateMode==QCDATA_BR_MODE_FF)) ? 1 : 0 ); +} + + + +typedef enum{ + FRAME_LEN_BYTES_MODULO = 1, + FRAME_LEN_BYTES_INT = 2 +}FRAME_LEN_RESULT_MODE; + +/* forward declarations */ + +static INT FDKaacEnc_calcMaxValueInSfb(INT sfbCnt, + INT maxSfbPerGroup, + INT sfbPerGroup, + INT *RESTRICT sfbOffset, + SHORT *RESTRICT quantSpectrum, + UINT *RESTRICT maxValue); + +static void FDKaacEnc_crashRecovery(INT nChannels, + PSY_OUT_ELEMENT* psyOutElement, + QC_OUT* qcOut, + QC_OUT_ELEMENT *qcElement, + INT bitsToSave, + AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, + SCHAR epConfig); + +static +AAC_ENCODER_ERROR FDKaacEnc_reduceBitConsumption(int* iterations, + const int maxIterations, + int gainAdjustment, + int* chConstraintsFulfilled, + int* calculateQuant, + int nChannels, + PSY_OUT_ELEMENT* psyOutElement, + QC_OUT* qcOut, + QC_OUT_ELEMENT* qcOutElement, + ELEMENT_BITS* elBits, + AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, + SCHAR epConfig); + + +void FDKaacEnc_QCClose (QC_STATE **phQCstate, QC_OUT **phQC); + +/***************************************************************************** + + functionname: FDKaacEnc_calcFrameLen + description: + returns: + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_calcFrameLen(INT bitRate, + INT sampleRate, + INT granuleLength, + FRAME_LEN_RESULT_MODE mode) +{ + + INT result; + + result = ((granuleLength)>>3)*(bitRate); + + switch(mode) { + case FRAME_LEN_BYTES_MODULO: + result %= sampleRate; + break; + case FRAME_LEN_BYTES_INT: + result /= sampleRate; + break; + } + return(result); +} + +/***************************************************************************** + + functionname:FDKaacEnc_framePadding + description: Calculates if padding is needed for actual frame + returns: + input: + output: + +*****************************************************************************/ +static INT FDKaacEnc_framePadding(INT bitRate, + INT sampleRate, + INT granuleLength, + INT *paddingRest) +{ + INT paddingOn; + INT difference; + + paddingOn = 0; + + difference = FDKaacEnc_calcFrameLen( bitRate, + sampleRate, + granuleLength, + FRAME_LEN_BYTES_MODULO ); + *paddingRest-=difference; + + if (*paddingRest <= 0 ) { + paddingOn = 1; + *paddingRest += sampleRate; + } + + return( paddingOn ); +} + + +/********************************************************************************* + + functionname: FDKaacEnc_QCOutNew + description: + return: + +**********************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_QCOutNew(QC_OUT **phQC, + const INT nElements, + const INT nChannels, + const INT nSubFrames + ,UCHAR *dynamic_RAM + ) +{ + AAC_ENCODER_ERROR ErrorStatus; + int n, i; + int elInc = 0, chInc = 0; + + for (n=0; npQcOutChannels[i] = GetRam_aacEnc_QCchannel(chInc, dynamic_RAM); + if ( phQC[n]->pQcOutChannels[i] == NULL + ) + { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto QCOutNew_bail; + } + chInc++; + } /* nChannels */ + + for (i=0; iqcElement[i] = GetRam_aacEnc_QCelement(elInc); + if (phQC[n]->qcElement[i] == NULL) + { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto QCOutNew_bail; + } + elInc++; + } /* nElements */ + + } /* nSubFrames */ + + + return AAC_ENC_OK; + +QCOutNew_bail: + return ErrorStatus; +} + +/********************************************************************************* + + functionname: FDKaacEnc_QCOutInit + description: + return: + +**********************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_QCOutInit(QC_OUT *phQC[(1)], + const INT nSubFrames, + const CHANNEL_MAPPING *cm) +{ + INT n,i,ch; + + for (n=0; nnElements; i++) { + for (ch=0; chelInfo[i].nChannelsInEl; ch++) { + phQC[n]->qcElement[i]->qcOutChannel[ch] = phQC[n]->pQcOutChannels[chInc]; + chInc++; + } /* chInEl */ + } /* nElements */ + } /* nSubFrames */ + + return AAC_ENC_OK; +} + +/********************************************************************************* + + functionname: FDKaacEnc_QCNew + description: + return: + +**********************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_QCNew(QC_STATE **phQC, + INT nElements + ,UCHAR* dynamic_RAM + ) +{ + AAC_ENCODER_ERROR ErrorStatus; + int i; + + QC_STATE* hQC = GetRam_aacEnc_QCstate(); + *phQC = hQC; + if (hQC == NULL) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto QCNew_bail; + } + + if (FDKaacEnc_AdjThrNew(&hQC->hAdjThr, nElements)) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto QCNew_bail; + } + + if (FDKaacEnc_BCNew(&(hQC->hBitCounter), dynamic_RAM)) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto QCNew_bail; + } + + for (i=0; ielementBits[i] = GetRam_aacEnc_ElementBits(i); + if (hQC->elementBits[i] == NULL) { + ErrorStatus = AAC_ENC_NO_MEMORY; + goto QCNew_bail; + } + } + + return AAC_ENC_OK; + +QCNew_bail: + FDKaacEnc_QCClose(phQC, NULL); + return ErrorStatus; +} + +/********************************************************************************* + + functionname: FDKaacEnc_QCInit + description: + return: + +**********************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_QCInit(QC_STATE *hQC, + struct QC_INIT *init) +{ + hQC->maxBitsPerFrame = init->maxBits; + hQC->minBitsPerFrame = init->minBits; + hQC->nElements = init->channelMapping->nElements; + hQC->bitResTotMax = init->bitRes; + hQC->bitResTot = init->bitRes; + hQC->maxBitFac = init->maxBitFac; + hQC->bitrateMode = init->bitrateMode; + hQC->invQuant = init->invQuant; + hQC->maxIterations = init->maxIterations; + + if ( isConstantBitrateMode(hQC->bitrateMode) ) { + INT bitresPerChannel = (hQC->bitResTotMax / init->channelMapping->nChannelsEff); + /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir */ + hQC->bitDistributenMode = (bitresPerChannel>50) ? 0 : (bitresPerChannel>0) ? 1 : 2; + } + else { + hQC->bitDistributenMode = 0; /* full bitreservoir */ + } + + + hQC->padding.paddingRest = init->padding.paddingRest; + + hQC->globHdrBits = init->staticBits; /* Bit overhead due to transport */ + + FDKaacEnc_InitElementBits(hQC, + init->channelMapping, + init->bitrate, + (init->averageBits/init->nSubFrames) - hQC->globHdrBits, + hQC->maxBitsPerFrame/init->channelMapping->nChannelsEff); + + switch(hQC->bitrateMode){ + case QCDATA_BR_MODE_CBR: + case QCDATA_BR_MODE_VBR_1: + case QCDATA_BR_MODE_VBR_2: + case QCDATA_BR_MODE_VBR_3: + case QCDATA_BR_MODE_VBR_4: + case QCDATA_BR_MODE_VBR_5: + case QCDATA_BR_MODE_SFR: + case QCDATA_BR_MODE_FF: + if((int)hQC->bitrateMode < (int)(sizeof(tableVbrQualFactor)/sizeof(TAB_VBR_QUAL_FACTOR))){ + hQC->vbrQualFactor = (FIXP_DBL)tableVbrQualFactor[hQC->bitrateMode].vbrQualFactor; + } else { + hQC->vbrQualFactor = FL2FXCONST_DBL(0.f); /* default setting */ + } + break; + case QCDATA_BR_MODE_INVALID: + default: + hQC->vbrQualFactor = FL2FXCONST_DBL(0.f); + break; + } + + FDKaacEnc_AdjThrInit(hQC->hAdjThr, + init->meanPe, + hQC->elementBits, /* or channelBitrates, was: channelBitrate */ + init->channelMapping->nElements, + hQC->vbrQualFactor); + + return AAC_ENC_OK; +} + + + +/********************************************************************************* + + functionname: FDKaacEnc_QCMainPrepare + description: + return: + +**********************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_QCMainPrepare(ELEMENT_INFO *elInfo, + ATS_ELEMENT* RESTRICT adjThrStateElement, + PSY_OUT_ELEMENT* RESTRICT psyOutElement, + QC_OUT_ELEMENT* RESTRICT qcOutElement, + AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, + SCHAR epConfig + ) +{ + AAC_ENCODER_ERROR ErrorStatus = AAC_ENC_OK; + INT nChannels = elInfo->nChannelsInEl; + + PSY_OUT_CHANNEL** RESTRICT psyOutChannel = psyOutElement->psyOutChannel; /* may be modified in-place */ + + FDKaacEnc_CalcFormFactor(qcOutElement->qcOutChannel, psyOutChannel, nChannels); + + /* prepare and calculate PE without reduction */ + FDKaacEnc_peCalculation(&qcOutElement->peData, psyOutChannel, qcOutElement->qcOutChannel, &psyOutElement->toolsInfo, adjThrStateElement, nChannels); + + ErrorStatus = FDKaacEnc_ChannelElementWrite( NULL, elInfo, NULL, + psyOutElement, + psyOutElement->psyOutChannel, + syntaxFlags, + aot, + epConfig, + &qcOutElement->staticBitsUsed, + 0 ); + + return ErrorStatus; +} + +/********************************************************************************* + + functionname: FDKaacEnc_AdjustBitrate + description: adjusts framelength via padding on a frame to frame basis, + to achieve a bitrate that demands a non byte aligned + framelength + return: errorcode + +**********************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_AdjustBitrate(QC_STATE *RESTRICT hQC, + CHANNEL_MAPPING *RESTRICT cm, + INT *avgTotalBits, + INT bitRate, /* total bitrate */ + INT sampleRate, /* output sampling rate */ + INT granuleLength) /* frame length */ +{ + INT paddingOn; + INT frameLen; + + /* Do we need an extra padding byte? */ + paddingOn = FDKaacEnc_framePadding(bitRate, + sampleRate, + granuleLength, + &hQC->padding.paddingRest); + + frameLen = paddingOn + FDKaacEnc_calcFrameLen(bitRate, + sampleRate, + granuleLength, + FRAME_LEN_BYTES_INT); + + *avgTotalBits = frameLen<<3; + + return AAC_ENC_OK; +} + +static AAC_ENCODER_ERROR FDKaacEnc_distributeElementDynBits(QC_STATE* hQC, + QC_OUT_ELEMENT* qcElement[(6)], + CHANNEL_MAPPING* cm, + INT codeBits) +{ + + INT i, firstEl = cm->nElements-1; + INT totalBits = 0; + + for (i=(cm->nElements-1); i>=0; i--) { + if ((cm->elInfo[i].elType == ID_SCE) || (cm->elInfo[i].elType == ID_CPE) || + (cm->elInfo[i].elType == ID_LFE)) + { + qcElement[i]->grantedDynBits = (INT)fMult(hQC->elementBits[i]->relativeBitsEl, (FIXP_DBL)codeBits); + totalBits += qcElement[i]->grantedDynBits; + firstEl = i; + } + } + qcElement[firstEl]->grantedDynBits += codeBits - totalBits; + + return AAC_ENC_OK; +} + +/** + * \brief Verify whether minBitsPerFrame criterion can be satisfied. + * + * This function evaluates the bit consumption only if minBitsPerFrame parameter is not 0. + * In hyperframing mode the difference between grantedDynBits and usedDynBits of all sub frames + * results the number of fillbits to be written. + * This bits can be distrubitued in superframe to reach minBitsPerFrame bit consumption in single AU's. + * The return value denotes if enough desired fill bits are available to achieve minBitsPerFrame in all frames. + * This check can only be used within superframes. + * + * \param qcOut Pointer to coding data struct. + * \param minBitsPerFrame Minimal number of bits to be consumed in each frame. + * \param nSubFrames Number of frames in superframe + * + * \return + * - 1: all fine + * - 0: criterion not fulfilled + */ +static int checkMinFrameBitsDemand( + QC_OUT** qcOut, + const INT minBitsPerFrame, + const INT nSubFrames + ) +{ + int result = 1; /* all fine*/ + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/********************************************************************************* + + functionname: FDKaacEnc_getMinimalStaticBitdemand + description: calculate minmal size of static bits by reduction , + to zero spectrum and deactivating tns and MS + return: number of static bits + +**********************************************************************************/ +static int FDKaacEnc_getMinimalStaticBitdemand(CHANNEL_MAPPING* cm, + PSY_OUT** psyOut) +{ + AUDIO_OBJECT_TYPE aot = AOT_AAC_LC; + UINT syntaxFlags = 0; + SCHAR epConfig = -1; + int i, bitcount = 0; + + for (i=0; inElements; i++) { + ELEMENT_INFO elInfo = cm->elInfo[i]; + + if ( (elInfo.elType == ID_SCE) + || (elInfo.elType == ID_CPE) + || (elInfo.elType == ID_LFE) ) + { + INT minElBits = 0; + + FDKaacEnc_ChannelElementWrite( NULL, &elInfo, NULL, + psyOut[0]->psyOutElement[i], + psyOut[0]->psyOutElement[i]->psyOutChannel, + syntaxFlags, + aot, + epConfig, + &minElBits, + 1 ); + bitcount += minElBits; + } + } + + return bitcount; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static AAC_ENCODER_ERROR FDKaacEnc_prepareBitDistribution(QC_STATE* hQC, + PSY_OUT** psyOut, + QC_OUT** qcOut, + CHANNEL_MAPPING* cm, + QC_OUT_ELEMENT* qcElement[(1)][(6)], + INT avgTotalBits, + INT *totalAvailableBits, + INT *avgTotalDynBits) +{ + int i; + /* get maximal allowed dynamic bits */ + qcOut[0]->grantedDynBits = (fixMin(hQC->maxBitsPerFrame, avgTotalBits) - hQC->globHdrBits)&~7; + qcOut[0]->grantedDynBits -= (qcOut[0]->globalExtBits + qcOut[0]->staticBits + qcOut[0]->elementExtBits); + qcOut[0]->maxDynBits = ((hQC->maxBitsPerFrame)&~7) - (qcOut[0]->globalExtBits + qcOut[0]->staticBits + qcOut[0]->elementExtBits); + /* assure that enough bits are available */ + if ((qcOut[0]->grantedDynBits+hQC->bitResTot) < 0) { + /* crash recovery allows to reduce static bits to a minimum */ + if ( (qcOut[0]->grantedDynBits+hQC->bitResTot) < (FDKaacEnc_getMinimalStaticBitdemand(cm, psyOut)-qcOut[0]->staticBits) ) + return AAC_ENC_BITRES_TOO_LOW; + } + + /* distribute dynamic bits to each element */ + FDKaacEnc_distributeElementDynBits(hQC, + qcElement[0], + cm, + qcOut[0]->grantedDynBits); + + *avgTotalDynBits = 0; /*frameDynBits;*/ + + *totalAvailableBits = avgTotalBits; + + /* sum up corrected granted PE */ + qcOut[0]->totalGrantedPeCorr = 0; + + for (i=0; inElements; i++) + { + ELEMENT_INFO elInfo = cm->elInfo[i]; + int nChannels = elInfo.nChannelsInEl; + + if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) || + (elInfo.elType == ID_LFE)) + { + /* for ( all sub frames ) ... */ + FDKaacEnc_DistributeBits(hQC->hAdjThr, + hQC->hAdjThr->adjThrStateElem[i], + psyOut[0]->psyOutElement[i]->psyOutChannel, + &qcElement[0][i]->peData, + &qcElement[0][i]->grantedPe, + &qcElement[0][i]->grantedPeCorr, + nChannels, + psyOut[0]->psyOutElement[i]->commonWindow, + qcElement[0][i]->grantedDynBits, + hQC->elementBits[i]->bitResLevelEl, + hQC->elementBits[i]->maxBitResBitsEl, + hQC->maxBitFac, + hQC->bitDistributenMode); + + *totalAvailableBits += hQC->elementBits[i]->bitResLevelEl; + /* get total corrected granted PE */ + qcOut[0]->totalGrantedPeCorr += qcElement[0][i]->grantedPeCorr; + } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */ + + } /* -end- element loop */ + + *totalAvailableBits = FDKmin(hQC->maxBitsPerFrame, (*totalAvailableBits)); + + return AAC_ENC_OK; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static AAC_ENCODER_ERROR FDKaacEnc_updateUsedDynBits(INT* sumDynBitsConsumed, + QC_OUT_ELEMENT* qcElement[(6)], + CHANNEL_MAPPING* cm) +{ + INT i; + + *sumDynBitsConsumed = 0; + + for (i=0; inElements; i++) + { + ELEMENT_INFO elInfo = cm->elInfo[i]; + + if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) || + (elInfo.elType == ID_LFE)) + { + /* sum up bits consumed */ + *sumDynBitsConsumed += qcElement[i]->dynBitsUsed; + } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */ + + } /* -end- element loop */ + + return AAC_ENC_OK; +} + + +static INT FDKaacEnc_getTotalConsumedDynBits(QC_OUT** qcOut, + INT nSubFrames) +{ + INT c, totalBits=0; + + /* sum up bit consumption for all sub frames */ + for (c=0; cusedDynBits==-1) return -1; + totalBits += qcOut[c]->usedDynBits; + } + + return totalBits; + +} + +static INT FDKaacEnc_getTotalConsumedBits(QC_OUT** qcOut, + QC_OUT_ELEMENT* qcElement[(1)][(6)], + CHANNEL_MAPPING* cm, + INT globHdrBits, + INT nSubFrames) +{ + int c, i; + int totalUsedBits = 0; + + for (c = 0 ; c < nSubFrames ; c++ ) + { + int dataBits = 0; + for (i=0; inElements; i++) + { + if ((cm->elInfo[i].elType == ID_SCE) || (cm->elInfo[i].elType == ID_CPE) || + (cm->elInfo[i].elType == ID_LFE)) + { + dataBits += qcElement[c][i]->dynBitsUsed + qcElement[c][i]->staticBitsUsed + qcElement[c][i]->extBitsUsed; + } + } + dataBits += qcOut[c]->globalExtBits; + + totalUsedBits += (8 - (dataBits) % 8) % 8; + totalUsedBits += dataBits + globHdrBits; /* header bits for every frame */ + } + return totalUsedBits; +} + +static AAC_ENCODER_ERROR FDKaacEnc_BitResRedistribution( + QC_STATE *const hQC, + const CHANNEL_MAPPING *const cm, + const INT avgTotalBits + ) +{ + /* check bitreservoir fill level */ + if (hQC->bitResTot < 0) { + return AAC_ENC_BITRES_TOO_LOW; + } + else if (hQC->bitResTot > hQC->bitResTotMax) { + return AAC_ENC_BITRES_TOO_HIGH; + } + else { + INT i, firstEl = cm->nElements-1; + INT totalBits = 0, totalBits_max = 0; + + int totalBitreservoir = FDKmin(hQC->bitResTot, (hQC->maxBitsPerFrame-avgTotalBits)); + int totalBitreservoirMax = FDKmin(hQC->bitResTotMax, (hQC->maxBitsPerFrame-avgTotalBits)); + + int sc_bitResTot = CountLeadingBits(totalBitreservoir); + int sc_bitResTotMax = CountLeadingBits(totalBitreservoirMax); + + for (i=(cm->nElements-1); i>=0; i--) { + if ((cm->elInfo[i].elType == ID_SCE) || (cm->elInfo[i].elType == ID_CPE) || + (cm->elInfo[i].elType == ID_LFE)) + { + hQC->elementBits[i]->bitResLevelEl = (INT)fMult(hQC->elementBits[i]->relativeBitsEl, (FIXP_DBL)(totalBitreservoir<>sc_bitResTot; + totalBits += hQC->elementBits[i]->bitResLevelEl; + + hQC->elementBits[i]->maxBitResBitsEl = (INT)fMult(hQC->elementBits[i]->relativeBitsEl, (FIXP_DBL)(totalBitreservoirMax<>sc_bitResTotMax; + totalBits_max += hQC->elementBits[i]->maxBitResBitsEl; + + firstEl = i; + } + } + hQC->elementBits[firstEl]->bitResLevelEl += totalBitreservoir - totalBits; + hQC->elementBits[firstEl]->maxBitResBitsEl += totalBitreservoirMax - totalBits_max; + } + + return AAC_ENC_OK; +} + + +AAC_ENCODER_ERROR FDKaacEnc_QCMain(QC_STATE* RESTRICT hQC, + PSY_OUT** psyOut, + QC_OUT** qcOut, + INT avgTotalBits, + CHANNEL_MAPPING* cm + ,AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, + SCHAR epConfig + ) +{ + int i, c; + AAC_ENCODER_ERROR ErrorStatus = AAC_ENC_OK; + INT avgTotalDynBits = 0; /* maximal allowd dynamic bits for all frames */ + INT totalAvailableBits = 0; + INT nSubFrames = 1; + + /*-------------------------------------------- */ + /* redistribute total bitreservoir to elements */ + ErrorStatus = FDKaacEnc_BitResRedistribution(hQC, cm, avgTotalBits); + if (ErrorStatus != AAC_ENC_OK) { + return ErrorStatus; + } + + /*-------------------------------------------- */ + /* fastenc needs one time threshold simulation, + in case of multiple frames, one more guess has to be calculated */ + + /*-------------------------------------------- */ + /* helper pointer */ + QC_OUT_ELEMENT* qcElement[(1)][(6)]; + + /* work on a copy of qcChannel and qcElement */ + for (i=0; inElements; i++) + { + ELEMENT_INFO elInfo = cm->elInfo[i]; + + if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) || + (elInfo.elType == ID_LFE)) + { + /* for ( all sub frames ) ... */ + for (c = 0 ; c < nSubFrames ; c++ ) + { + { + qcElement[c][i] = qcOut[c]->qcElement[i]; + } + } + } + } + + /*-------------------------------------------- */ + /*-------------------------------------------- */ + if ( isConstantBitrateMode(hQC->bitrateMode) ) + { + /* calc granted dynamic bits for sub frame and + distribute it to each element */ + ErrorStatus = FDKaacEnc_prepareBitDistribution( + hQC, + psyOut, + qcOut, + cm, + qcElement, + avgTotalBits, + &totalAvailableBits, + &avgTotalDynBits); + + if (ErrorStatus != AAC_ENC_OK) { + return ErrorStatus; + } + } + else { + qcOut[0]->grantedDynBits = ((hQC->maxBitsPerFrame - (hQC->globHdrBits))&~7) + - (qcOut[0]->globalExtBits + qcOut[0]->staticBits + qcOut[0]->elementExtBits); + qcOut[0]->maxDynBits = qcOut[0]->grantedDynBits; + + totalAvailableBits = hQC->maxBitsPerFrame; + avgTotalDynBits = 0; + } + +#ifdef PNS_PRECOUNT_ENABLE + /* Calculate estimated pns bits and substract them from grantedDynBits to get a more accurate number of available bits. */ + if (syntaxFlags & (AC_LD|AC_ELD)) + { + int estimatedPnsBits = 0, ch; + + for (ch=0; chnChannels; ch++) { + qcOut[0]->pQcOutChannels[ch]->sectionData.noiseNrgBits = noisePreCount(psyOut[0]->pPsyOutChannels[ch]->noiseNrg, psyOut[0]->pPsyOutChannels[ch]->maxSfbPerGroup); + estimatedPnsBits += qcOut[0]->pQcOutChannels[ch]->sectionData.noiseNrgBits; + } + qcOut[0]->grantedDynBits -= estimatedPnsBits; + } +#endif + + /* for ( all sub frames ) ... */ + for (c = 0 ; c < nSubFrames ; c++ ) + { + /* for CBR and VBR mode */ + FDKaacEnc_AdjustThresholds(hQC->hAdjThr->adjThrStateElem, + qcElement[c], + qcOut[c], + psyOut[c]->psyOutElement, + isConstantBitrateMode(hQC->bitrateMode), + cm); + + } /* -end- sub frame counter */ + + /*-------------------------------------------- */ + INT iterations[(1)][(6)]; + INT chConstraintsFulfilled[(1)][(6)][(2)]; + INT calculateQuant[(1)][(6)][(2)]; + INT constraintsFulfilled[(1)][(6)]; + /*-------------------------------------------- */ + + + /* for ( all sub frames ) ... */ + for (c = 0 ; c < nSubFrames ; c++ ) + { + for (i=0; inElements; i++) + { + ELEMENT_INFO elInfo = cm->elInfo[i]; + INT ch, nChannels = elInfo.nChannelsInEl; + + if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) || + (elInfo.elType == ID_LFE)) + { + /* Turn thresholds into scalefactors, optimize bit consumption and verify conformance */ + FDKaacEnc_EstimateScaleFactors(psyOut[c]->psyOutElement[i]->psyOutChannel, + qcElement[c][i]->qcOutChannel, + hQC->invQuant, + cm->elInfo[i].nChannelsInEl); + + + /*-------------------------------------------- */ + constraintsFulfilled[c][i] = 1; + iterations[c][i] = 0 ; + + for (ch = 0; ch < nChannels; ch++) + { + chConstraintsFulfilled[c][i][ch] = 1; + calculateQuant[c][i][ch] = 1; + } + + /*-------------------------------------------- */ + + } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */ + + } /* -end- element loop */ + + qcOut[c]->usedDynBits = -1; + + } /* -end- sub frame counter */ + + + + INT quantizationDone = 0; + INT sumDynBitsConsumedTotal = 0; + INT decreaseBitConsumption = -1; /* no direction yet! */ + + /*-------------------------------------------- */ + /* -start- Quantization loop ... */ + /*-------------------------------------------- */ + do /* until max allowed bits per frame and maxDynBits!=-1*/ + { + quantizationDone = 0; + + c = 0; /* get frame to process */ + + for (i=0; inElements; i++) + { + ELEMENT_INFO elInfo = cm->elInfo[i]; + INT ch, nChannels = elInfo.nChannelsInEl; + + if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) || + (elInfo.elType == ID_LFE)) + { + do /* until spectral values < MAX_QUANT */ + { + /*-------------------------------------------- */ + if (!constraintsFulfilled[c][i]) + { + FDKaacEnc_reduceBitConsumption(&iterations[c][i], + hQC->maxIterations, + (decreaseBitConsumption) ? 1 : -1, + chConstraintsFulfilled[c][i], + calculateQuant[c][i], + nChannels, + psyOut[c]->psyOutElement[i], + qcOut[c], + qcElement[c][i], + hQC->elementBits[i], + aot, + syntaxFlags, + epConfig); + } + + /*-------------------------------------------- */ + /*-------------------------------------------- */ + constraintsFulfilled[c][i] = 1 ; + + /*-------------------------------------------- */ + /* quantize spectrum (per each channel) */ + for (ch = 0; ch < nChannels; ch++) + { + /*-------------------------------------------- */ + chConstraintsFulfilled[c][i][ch] = 1; + + /*-------------------------------------------- */ + + if (calculateQuant[c][i][ch]) + { + QC_OUT_CHANNEL* qcOutCh = qcElement[c][i]->qcOutChannel[ch]; + PSY_OUT_CHANNEL* psyOutCh = psyOut[c]->psyOutElement[i]->psyOutChannel[ch]; + + calculateQuant[c][i][ch] = 0; /* calculate quantization only if necessary */ + + /*-------------------------------------------- */ + FDKaacEnc_QuantizeSpectrum(psyOutCh->sfbCnt, + psyOutCh->maxSfbPerGroup, + psyOutCh->sfbPerGroup, + psyOutCh->sfbOffsets, + qcOutCh->mdctSpectrum, + qcOutCh->globalGain, + qcOutCh->scf, + qcOutCh->quantSpec) ; + + /*-------------------------------------------- */ + if (FDKaacEnc_calcMaxValueInSfb(psyOutCh->sfbCnt, + psyOutCh->maxSfbPerGroup, + psyOutCh->sfbPerGroup, + psyOutCh->sfbOffsets, + qcOutCh->quantSpec, + qcOutCh->maxValueInSfb) > MAX_QUANT) + { + chConstraintsFulfilled[c][i][ch] = 0; + constraintsFulfilled[c][i] = 0 ; + /* if quanizted value out of range; increase global gain! */ + decreaseBitConsumption = 1; + } + + /*-------------------------------------------- */ + + } /* if calculateQuant[c][i][ch] */ + + } /* channel loop */ + + /*-------------------------------------------- */ + /* quantize spectrum (per each channel) */ + + /*-------------------------------------------- */ + + } while (!constraintsFulfilled[c][i]) ; /* does not regard bit consumption */ + + + /*-------------------------------------------- */ + /*-------------------------------------------- */ + qcElement[c][i]->dynBitsUsed = 0 ; /* reset dynamic bits */ + + /* quantization valid in current channel! */ + for (ch = 0; ch < nChannels; ch++) + { + QC_OUT_CHANNEL* qcOutCh = qcElement[c][i]->qcOutChannel[ch]; + PSY_OUT_CHANNEL *psyOutCh = psyOut[c]->psyOutElement[i]->psyOutChannel[ch]; + + /* count dynamic bits */ + INT chDynBits = FDKaacEnc_dynBitCount(hQC->hBitCounter, + qcOutCh->quantSpec, + qcOutCh->maxValueInSfb, + qcOutCh->scf, + psyOutCh->lastWindowSequence, + psyOutCh->sfbCnt, + psyOutCh->maxSfbPerGroup, + psyOutCh->sfbPerGroup, + psyOutCh->sfbOffsets, + &qcOutCh->sectionData, + psyOutCh->noiseNrg, + psyOutCh->isBook, + psyOutCh->isScale, + syntaxFlags) ; + + /* sum up dynamic channel bits */ + qcElement[c][i]->dynBitsUsed += chDynBits; + } + + /* save dynBitsUsed for correction of bits2pe relation */ + if(hQC->hAdjThr->adjThrStateElem[i]->dynBitsLast==-1) { + hQC->hAdjThr->adjThrStateElem[i]->dynBitsLast = qcElement[c][i]->dynBitsUsed; + } + } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */ + + } /* -end- element loop */ + + /* update dynBits of current subFrame */ + FDKaacEnc_updateUsedDynBits(&qcOut[c]->usedDynBits, + qcElement[c], + cm); + + /* get total consumed bits, dyn bits in all sub frames have to be valid */ + sumDynBitsConsumedTotal = FDKaacEnc_getTotalConsumedDynBits(qcOut, nSubFrames); + + if (sumDynBitsConsumedTotal==-1) + { + quantizationDone = 0; /* bit consumption not valid in all sub frames */ + } + else + { + int sumBitsConsumedTotal = FDKaacEnc_getTotalConsumedBits(qcOut, qcElement, cm, hQC->globHdrBits, nSubFrames); + + /* in all frames are valid dynamic bits */ + if (sumBitsConsumedTotal < totalAvailableBits && (decreaseBitConsumption==1) && checkMinFrameBitsDemand(qcOut,hQC->minBitsPerFrame,nSubFrames) + /*()*/ ) + { + quantizationDone = 1; /* exit bit adjustment */ + } + if (sumBitsConsumedTotal > totalAvailableBits && (decreaseBitConsumption==0) ) +// /*()*/ ) + { + quantizationDone = 0; /* reset! */ + break; + } + } + + + /*-------------------------------------------- */ + + int emergencyIterations = 1; + int dynBitsOvershoot = 0; + + for (c = 0 ; c < nSubFrames ; c++ ) + { + for (i=0; inElements; i++) + { + ELEMENT_INFO elInfo = cm->elInfo[i]; + + if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) || + (elInfo.elType == ID_LFE)) + { + /* iteration limitation */ + emergencyIterations &= ((iterations[c][i] < hQC->maxIterations) ? 0 : 1); + } + } + /* detection if used dyn bits exceeds the maximal allowed criterion */ + dynBitsOvershoot |= ((qcOut[c]->usedDynBits > qcOut[c]->maxDynBits) ? 1 : 0); + } + + if (quantizationDone==0 || dynBitsOvershoot) + { + + int sumBitsConsumedTotal = FDKaacEnc_getTotalConsumedBits(qcOut, qcElement, cm, hQC->globHdrBits, nSubFrames); + + if ( (sumDynBitsConsumedTotal >= avgTotalDynBits) || (sumDynBitsConsumedTotal==0) ) { + quantizationDone = 1; + } + if (emergencyIterations && (sumBitsConsumedTotal < totalAvailableBits)) { + quantizationDone = 1; + } + if ((sumBitsConsumedTotal > totalAvailableBits) || !checkMinFrameBitsDemand(qcOut,hQC->minBitsPerFrame,nSubFrames)) { + quantizationDone = 0; + } + if ((sumBitsConsumedTotal < totalAvailableBits) && checkMinFrameBitsDemand(qcOut,hQC->minBitsPerFrame,nSubFrames)) { + decreaseBitConsumption = 0; + } + else { + decreaseBitConsumption = 1; + } + + if (dynBitsOvershoot) { + quantizationDone = 0; + decreaseBitConsumption = 1; + } + + /* reset constraints fullfilled flags */ + FDKmemclear(constraintsFulfilled, sizeof(constraintsFulfilled)); + FDKmemclear(chConstraintsFulfilled, sizeof(chConstraintsFulfilled)); + + + }/* quantizationDone */ + + } while (!quantizationDone) ; + + /*-------------------------------------------- */ + /* ... -end- Quantization loop */ + /*-------------------------------------------- */ + + /*-------------------------------------------- */ + /*-------------------------------------------- */ + + return AAC_ENC_OK; +} + + +static AAC_ENCODER_ERROR FDKaacEnc_reduceBitConsumption(int* iterations, + const int maxIterations, + int gainAdjustment, + int* chConstraintsFulfilled, + int* calculateQuant, + int nChannels, + PSY_OUT_ELEMENT* psyOutElement, + QC_OUT* qcOut, + QC_OUT_ELEMENT* qcOutElement, + ELEMENT_BITS* elBits, + AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, + SCHAR epConfig) +{ + int ch; + + /** SOLVING PROBLEM **/ + if ((*iterations)++ >= maxIterations) + { + if (qcOutElement->dynBitsUsed==0) { + } + /* crash recovery */ + else { + INT bitsToSave = 0; + if ( (bitsToSave = fixMax((qcOutElement->dynBitsUsed + 8) - (elBits->bitResLevelEl + qcOutElement->grantedDynBits), + (qcOutElement->dynBitsUsed + qcOutElement->staticBitsUsed + 8) - (elBits->maxBitsEl))) > 0 ) + { + FDKaacEnc_crashRecovery(nChannels, + psyOutElement, + qcOut, + qcOutElement, + bitsToSave, + aot, + syntaxFlags, + epConfig) ; + } + else + { + for (ch = 0; ch < nChannels; ch++) + { + qcOutElement->qcOutChannel[ch]->globalGain += 1; + } + } + for (ch = 0; ch < nChannels; ch++) + { + calculateQuant[ch] = 1; + } + } + } + else /* iterations >= maxIterations */ + { + /* increase gain (+ next iteration) */ + for (ch = 0; ch < nChannels; ch++) + { + if(!chConstraintsFulfilled[ch]) + { + qcOutElement->qcOutChannel[ch]->globalGain += gainAdjustment ; + calculateQuant[ch] = 1; /* global gain has changed, recalculate quantization in next iteration! */ + } + } + } + + return AAC_ENC_OK; +} + +AAC_ENCODER_ERROR FDKaacEnc_updateFillBits(CHANNEL_MAPPING* cm, + QC_STATE* qcKernel, + ELEMENT_BITS* RESTRICT elBits[(6)], + QC_OUT** qcOut) +{ + switch (qcKernel->bitrateMode) { + case QCDATA_BR_MODE_SFR: + break; + + case QCDATA_BR_MODE_FF: + break; + + case QCDATA_BR_MODE_VBR_1: + case QCDATA_BR_MODE_VBR_2: + case QCDATA_BR_MODE_VBR_3: + case QCDATA_BR_MODE_VBR_4: + case QCDATA_BR_MODE_VBR_5: + qcOut[0]->totFillBits = (qcOut[0]->grantedDynBits - qcOut[0]->usedDynBits)&7; /* precalculate alignment bits */ + break; + + case QCDATA_BR_MODE_CBR: + case QCDATA_BR_MODE_INVALID: + default: + INT bitResSpace = qcKernel->bitResTotMax - qcKernel->bitResTot ; + /* processing fill-bits */ + INT deltaBitRes = qcOut[0]->grantedDynBits - qcOut[0]->usedDynBits ; + qcOut[0]->totFillBits = fixMax((deltaBitRes&7), (deltaBitRes - (fixMax(0,bitResSpace-7)&~7))); + break; + } /* switch (qcKernel->bitrateMode) */ + + return AAC_ENC_OK; +} + + + + +/********************************************************************************* + + functionname: FDKaacEnc_calcMaxValueInSfb + description: + return: + +**********************************************************************************/ + +static INT FDKaacEnc_calcMaxValueInSfb(INT sfbCnt, + INT maxSfbPerGroup, + INT sfbPerGroup, + INT *RESTRICT sfbOffset, + SHORT *RESTRICT quantSpectrum, + UINT *RESTRICT maxValue) +{ + INT sfbOffs,sfb; + INT maxValueAll = 0; + + for (sfbOffs=0;sfbOffsbitrateMode) { + case QCDATA_BR_MODE_FF: + case QCDATA_BR_MODE_VBR_1: + case QCDATA_BR_MODE_VBR_2: + case QCDATA_BR_MODE_VBR_3: + case QCDATA_BR_MODE_VBR_4: + case QCDATA_BR_MODE_VBR_5: + /* variable bitrate */ + qcKernel->bitResTot = FDKmin(qcKernel->maxBitsPerFrame, qcKernel->bitResTotMax); + break; + + case QCDATA_BR_MODE_CBR: + case QCDATA_BR_MODE_SFR: + case QCDATA_BR_MODE_INVALID: + default: + int c = 0; + /* constant bitrate */ + { + qcKernel->bitResTot += qcOut[c]->grantedDynBits - (qcOut[c]->usedDynBits + qcOut[c]->totFillBits + qcOut[c]->alignBits); + } + break; + } +} + +/********************************************************************************* + + functionname: FDKaacEnc_FinalizeBitConsumption + description: + return: + +**********************************************************************************/ +AAC_ENCODER_ERROR FDKaacEnc_FinalizeBitConsumption(CHANNEL_MAPPING *cm, + QC_STATE *qcKernel, + QC_OUT *qcOut, + QC_OUT_ELEMENT** qcElement, + HANDLE_TRANSPORTENC hTpEnc, + AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, + SCHAR epConfig) +{ + QC_OUT_EXTENSION fillExtPayload; + INT totFillBits, alignBits; + + { + int exactTpBits; + int max_iter = 3; + + /* Get total consumed bits in AU */ + qcOut->totalBits = qcOut->staticBits + qcOut->usedDynBits + qcOut->totFillBits + + qcOut->elementExtBits + qcOut->globalExtBits; + + /* Now we can get the exact transport bit amount, and hopefully it is equal to the estimated value */ + exactTpBits = transportEnc_GetStaticBits(hTpEnc, qcOut->totalBits); + + while (exactTpBits != qcKernel->globHdrBits && (max_iter-- > 0)) + { + INT diffBits = qcKernel->globHdrBits-exactTpBits; + if (diffBits >= 0) { + /* move bits from header to payload */ + qcOut->totFillBits += diffBits; + qcOut->totalBits += diffBits; + qcOut->grantedDynBits += diffBits; + } + else { + /* get missing bits from bitreservoir */ + qcKernel->bitResTot += diffBits; + } + qcKernel->globHdrBits = exactTpBits; + exactTpBits = transportEnc_GetStaticBits(hTpEnc, qcOut->totalBits); + } + FDK_ASSERT(exactTpBits == qcKernel->globHdrBits); + } + + /* Save total fill bits and distribut to alignment and fill bits */ + totFillBits = qcOut->totFillBits; + + /* fake a fill extension payload */ + FDKmemclear(&fillExtPayload, sizeof(QC_OUT_EXTENSION)); + + fillExtPayload.type = EXT_FILL_DATA; + fillExtPayload.nPayloadBits = totFillBits; + + /* ask bitstream encoder how many of that bits can be written in a fill extension data entity */ + qcOut->totFillBits = FDKaacEnc_writeExtensionData( NULL, + &fillExtPayload, + 0, 0, + syntaxFlags, + aot, + epConfig ); + + /* now distribute extra fillbits and alignbits */ + alignBits = 7 - (qcOut->staticBits + qcOut->usedDynBits + qcOut->elementExtBits + + qcOut->totFillBits + qcOut->globalExtBits -1)%8; + + /* Maybe we could remove this */ + if( ((alignBits + qcOut->totFillBits - totFillBits)==8) && (qcOut->totFillBits>8) ) + qcOut->totFillBits -= 8; + + qcOut->totalBits = qcOut->staticBits + qcOut->usedDynBits + qcOut->totFillBits + + alignBits + qcOut->elementExtBits + qcOut->globalExtBits; + + if ( (qcOut->totalBits>qcKernel->maxBitsPerFrame) || (qcOut->totalBitsminBitsPerFrame) ) { + return AAC_ENC_QUANT_ERROR; + } + + qcOut->alignBits = alignBits; + + return AAC_ENC_OK; +} + + + +/********************************************************************************* + + functionname: FDKaacEnc_crashRecovery + description: fulfills constraints by means of brute force... + => bits are saved by cancelling out spectral lines!! + (beginning at the highest frequencies) + return: errorcode + +**********************************************************************************/ + +static void FDKaacEnc_crashRecovery(INT nChannels, + PSY_OUT_ELEMENT* psyOutElement, + QC_OUT* qcOut, + QC_OUT_ELEMENT *qcElement, + INT bitsToSave, + AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, + SCHAR epConfig) +{ + INT ch ; + INT savedBits = 0 ; + INT sfb, sfbGrp ; + INT bitsPerScf[(2)][MAX_GROUPED_SFB] ; + INT sectionToScf[(2)][MAX_GROUPED_SFB] ; + INT *sfbOffset ; + INT sect, statBitsNew ; + QC_OUT_CHANNEL **qcChannel = qcElement->qcOutChannel; + PSY_OUT_CHANNEL **psyChannel = psyOutElement->psyOutChannel; + + /* create a table which converts frq-bins to bit-demand... [bitsPerScf] */ + /* ...and another one which holds the corresponding sections [sectionToScf] */ + for (ch = 0; ch < nChannels; ch++) + { + sfbOffset = psyChannel[ch]->sfbOffsets ; + + for (sect = 0; sect < qcChannel[ch]->sectionData.noOfSections; sect++) + { + INT sfb ; + INT codeBook = qcChannel[ch]->sectionData.huffsection[sect].codeBook ; + + for (sfb = qcChannel[ch]->sectionData.huffsection[sect].sfbStart; + sfb < qcChannel[ch]->sectionData.huffsection[sect].sfbStart + + qcChannel[ch]->sectionData.huffsection[sect].sfbCnt; + sfb++) + { + bitsPerScf[ch][sfb] = 0; + if ( (codeBook != CODE_BOOK_PNS_NO) /*&& + (sfb < (qcChannel[ch]->sectionData.noOfGroups*qcChannel[ch]->sectionData.maxSfbPerGroup))*/ ) + { + INT sfbStartLine = sfbOffset[sfb] ; + INT noOfLines = sfbOffset[sfb+1] - sfbStartLine ; + bitsPerScf[ch][sfb] = FDKaacEnc_countValues(&(qcChannel[ch]->quantSpec[sfbStartLine]), noOfLines, codeBook) ; + } + sectionToScf[ch][sfb] = sect ; + } + + } + } + + /* LOWER [maxSfb] IN BOTH CHANNELS!! */ + /* Attention: in case of stereo: maxSfbL == maxSfbR, GroupingL == GroupingR ; */ + + for (sfb = qcChannel[0]->sectionData.maxSfbPerGroup-1; sfb >= 0; sfb--) + { + for (sfbGrp = 0; sfbGrp < psyChannel[0]->sfbCnt; sfbGrp += psyChannel[0]->sfbPerGroup) + { + for (ch = 0; ch < nChannels; ch++) + { + int sect = sectionToScf[ch][sfbGrp+sfb]; + qcChannel[ch]->sectionData.huffsection[sect].sfbCnt-- ; + savedBits += bitsPerScf[ch][sfbGrp+sfb] ; + + if (qcChannel[ch]->sectionData.huffsection[sect].sfbCnt == 0) { + savedBits += (psyChannel[ch]->lastWindowSequence!=SHORT_WINDOW) ? FDKaacEnc_sideInfoTabLong[0] + : FDKaacEnc_sideInfoTabShort[0]; + } + } + } + + /* ...have enough bits been saved? */ + if (savedBits >= bitsToSave) + break ; + + } /* sfb loop */ + + /* if not enough bits saved, + clean whole spectrum and remove side info overhead */ + if (sfb == -1) { + sfb = 0 ; + } + + for (ch = 0; ch < nChannels; ch++) + { + qcChannel[ch]->sectionData.maxSfbPerGroup = sfb ; + psyChannel[ch]->maxSfbPerGroup = sfb ; + /* when no spectrum is coded save tools info in bitstream */ + if(sfb==0) { + FDKmemclear(&psyChannel[ch]->tnsInfo, sizeof(TNS_INFO)); + FDKmemclear(&psyOutElement->toolsInfo, sizeof(TOOLSINFO)); + } + } + /* dynamic bits will be updated in iteration loop */ + + { /* if stop sfb has changed save bits in side info, e.g. MS or TNS coding */ + ELEMENT_INFO elInfo; + + FDKmemclear(&elInfo, sizeof(ELEMENT_INFO)); + elInfo.nChannelsInEl = nChannels; + elInfo.elType = (nChannels == 2) ? ID_CPE : ID_SCE; + + FDKaacEnc_ChannelElementWrite( NULL, &elInfo, NULL, + psyOutElement, + psyChannel, + syntaxFlags, + aot, + epConfig, + &statBitsNew, + 0 ); + } + + savedBits = qcElement->staticBitsUsed - statBitsNew; + + /* update static and dynamic bits */ + qcElement->staticBitsUsed -= savedBits; + qcElement->grantedDynBits += savedBits; + + qcOut->staticBits -= savedBits; + qcOut->grantedDynBits += savedBits; + qcOut->maxDynBits += savedBits; + + +} + + + +void FDKaacEnc_QCClose (QC_STATE **phQCstate, QC_OUT **phQC) +{ + int n, i; + + if (phQC!=NULL) { + + for (n=0;n<(1);n++) { + if (phQC[n] != NULL) { + QC_OUT *hQC = phQC[n]; + for (i=0; i<(6); i++) { + } + + for (i=0; i<(6); i++) { + if (hQC->qcElement[i]) + FreeRam_aacEnc_QCelement(&hQC->qcElement[i]); + } + + FreeRam_aacEnc_QCout(&phQC[n]); + } + } + } + + if (phQCstate!=NULL) { + if (*phQCstate != NULL) { + QC_STATE *hQCstate = *phQCstate; + + if (hQCstate->hAdjThr != NULL) + FDKaacEnc_AdjThrClose(&hQCstate->hAdjThr); + + if (hQCstate->hBitCounter != NULL) + FDKaacEnc_BCClose(&hQCstate->hBitCounter); + + for (i=0; i<(6); i++) { + if (hQCstate->elementBits[i]!=NULL) { + FreeRam_aacEnc_ElementBits(&hQCstate->elementBits[i]); + } + } + FreeRam_aacEnc_QCstate(phQCstate); + } + } +} + diff --git a/libAACenc/src/qc_main.h b/libAACenc/src/qc_main.h new file mode 100644 index 0000000..1335a22 --- /dev/null +++ b/libAACenc/src/qc_main.h @@ -0,0 +1,108 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Werner + contents/description: Quantizing & coding + +******************************************************************************/ +#ifndef _QC_MAIN_H +#define _QC_MAIN_H + + +#include "aacenc.h" +#include "qc_data.h" +#include "interface.h" +#include "psy_main.h" +#include "tpenc_lib.h" + +/* Quantizing & coding stage */ + +AAC_ENCODER_ERROR FDKaacEnc_QCOutNew(QC_OUT **phQC, + const INT nElements, + const INT nChannels, + const INT nSubFrames + ,UCHAR *dynamic_RAM + ); + +AAC_ENCODER_ERROR FDKaacEnc_QCOutInit(QC_OUT *phQC[(1)], + const INT nSubFrames, + const CHANNEL_MAPPING *cm); + +AAC_ENCODER_ERROR FDKaacEnc_QCNew(QC_STATE **phQC, + INT nElements + ,UCHAR* dynamic_RAM + ); + +AAC_ENCODER_ERROR FDKaacEnc_QCInit(QC_STATE *hQC, struct QC_INIT *init); + +AAC_ENCODER_ERROR FDKaacEnc_QCMainPrepare( + ELEMENT_INFO *elInfo, + ATS_ELEMENT* RESTRICT adjThrStateElement, + PSY_OUT_ELEMENT* RESTRICT psyOutElement, + QC_OUT_ELEMENT* RESTRICT qcOutElement, /* returns error code */ + AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, + SCHAR epConfig + ); + + +AAC_ENCODER_ERROR FDKaacEnc_QCMain(QC_STATE* RESTRICT hQC, + PSY_OUT** psyOut, + QC_OUT** qcOut, + INT avgTotalBits, + CHANNEL_MAPPING* cm + ,AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, + SCHAR epConfig + ); + +AAC_ENCODER_ERROR FDKaacEnc_updateFillBits(CHANNEL_MAPPING* cm, + QC_STATE* qcKernel, + ELEMENT_BITS* RESTRICT elBits[(6)], + QC_OUT** qcOut); + + +void FDKaacEnc_updateBitres( CHANNEL_MAPPING *cm, + QC_STATE *qcKernel, + QC_OUT **qcOut); + +AAC_ENCODER_ERROR FDKaacEnc_FinalizeBitConsumption( CHANNEL_MAPPING *cm, + QC_STATE *hQC, + QC_OUT *qcOut, + QC_OUT_ELEMENT** qcElement, + HANDLE_TRANSPORTENC hTpEnc, + AUDIO_OBJECT_TYPE aot, + UINT syntaxFlags, + SCHAR epConfig + ); + +AAC_ENCODER_ERROR FDKaacEnc_AdjustBitrate(QC_STATE *RESTRICT hQC, + CHANNEL_MAPPING *RESTRICT cm, + INT *avgTotalBits, + INT bitRate, + INT sampleRate, + INT granuleLength); + +void FDKaacEnc_QCClose (QC_STATE **phQCstate, QC_OUT **phQC); + +#endif /* _QC_MAIN_H */ diff --git a/libAACenc/src/quantize.cpp b/libAACenc/src/quantize.cpp new file mode 100644 index 0000000..b8eb5de --- /dev/null +++ b/libAACenc/src/quantize.cpp @@ -0,0 +1,323 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Quantization + +******************************************************************************/ + +#include "quantize.h" + +#include "aacEnc_rom.h" + +/***************************************************************************** + + functionname: FDKaacEnc_quantizeLines + description: quantizes spectrum lines + returns: + input: global gain, number of lines to process, spectral data + output: quantized spectrum + +*****************************************************************************/ +static void FDKaacEnc_quantizeLines(INT gain, + INT noOfLines, + FIXP_DBL *mdctSpectrum, + SHORT *quaSpectrum) +{ + int line; + FIXP_DBL k = FL2FXCONST_DBL(-0.0946f + 0.5f)>>16; + FIXP_QTD quantizer = FDKaacEnc_quantTableQ[(-gain)&3]; + INT quantizershift = ((-gain)>>2)+1; + + + for (line = 0; line < noOfLines; line++) + { + FIXP_DBL accu = fMultDiv2(mdctSpectrum[line],quantizer); + + if (accu < FL2FXCONST_DBL(0.0f)) + { + accu=-accu; + /* normalize */ + INT accuShift = CntLeadingZeros(accu) - 1; /* CountLeadingBits() is not necessary here since test value is always > 0 */ + accu <<= accuShift; + INT tabIndex = (INT)(accu>>(DFRACT_BITS-2-MANT_DIGITS))&(~MANT_SIZE); + INT totalShift = quantizershift-accuShift+1; + accu = fMultDiv2(FDKaacEnc_mTab_3_4[tabIndex],FDKaacEnc_quantTableE[totalShift&3]); + totalShift = (16-4)-(3*(totalShift>>2)); + FDK_ASSERT(totalShift >=0); /* MAX_QUANT_VIOLATION */ + accu>>=totalShift; + quaSpectrum[line] = (SHORT)(-((LONG)(k + accu) >> (DFRACT_BITS-1-16))); + } + else if(accu > FL2FXCONST_DBL(0.0f)) + { + /* normalize */ + INT accuShift = CntLeadingZeros(accu) - 1; /* CountLeadingBits() is not necessary here since test value is always > 0 */ + accu <<= accuShift; + INT tabIndex = (INT)(accu>>(DFRACT_BITS-2-MANT_DIGITS))&(~MANT_SIZE); + INT totalShift = quantizershift-accuShift+1; + accu = fMultDiv2(FDKaacEnc_mTab_3_4[tabIndex],FDKaacEnc_quantTableE[totalShift&3]); + totalShift = (16-4)-(3*(totalShift>>2)); + FDK_ASSERT(totalShift >=0); /* MAX_QUANT_VIOLATION */ + accu>>=totalShift; + quaSpectrum[line] = (SHORT)((LONG)(k + accu) >> (DFRACT_BITS-1-16)); + } + else + quaSpectrum[line]=0; + } +} + + +/***************************************************************************** + + functionname:iFDKaacEnc_quantizeLines + description: iquantizes spectrum lines + mdctSpectrum = iquaSpectrum^4/3 *2^(0.25*gain) + input: global gain, number of lines to process,quantized spectrum + output: spectral data + +*****************************************************************************/ +static void FDKaacEnc_invQuantizeLines(INT gain, + INT noOfLines, + SHORT *quantSpectrum, + FIXP_DBL *mdctSpectrum) + +{ + INT iquantizermod; + INT iquantizershift; + INT line; + + iquantizermod = gain&3; + iquantizershift = gain>>2; + + for (line = 0; line < noOfLines; line++) { + + if(quantSpectrum[line] < 0) { + FIXP_DBL accu; + INT ex,specExp,tabIndex; + FIXP_DBL s,t; + + accu = (FIXP_DBL) -quantSpectrum[line]; + + ex = CountLeadingBits(accu); + accu <<= ex; + specExp = (DFRACT_BITS-1) - ex; + + FDK_ASSERT(specExp < 14); /* this fails if abs(value) > 8191 */ + + tabIndex = (INT)(accu>>(DFRACT_BITS-2-MANT_DIGITS))&(~MANT_SIZE); + + /* calculate "mantissa" ^4/3 */ + s = FDKaacEnc_mTab_4_3Elc[tabIndex]; + + /* get approperiate exponent multiplier for specExp^3/4 combined with scfMod */ + t = FDKaacEnc_specExpMantTableCombElc[iquantizermod][specExp]; + + /* multiply "mantissa" ^4/3 with exponent multiplier */ + accu = fMult(s,t); + + /* get approperiate exponent shifter */ + specExp = FDKaacEnc_specExpTableComb[iquantizermod][specExp]-1; /* -1 to avoid overflows in accu */ + + if ((-iquantizershift-specExp) < 0) + accu <<= -(-iquantizershift-specExp); + else + accu >>= -iquantizershift-specExp; + + mdctSpectrum[line] = -accu; + } + else if (quantSpectrum[line] > 0) { + FIXP_DBL accu; + INT ex,specExp,tabIndex; + FIXP_DBL s,t; + + accu = (FIXP_DBL)(INT)quantSpectrum[line]; + + ex = CountLeadingBits(accu); + accu <<= ex; + specExp = (DFRACT_BITS-1) - ex; + + FDK_ASSERT(specExp < 14); /* this fails if abs(value) > 8191 */ + + tabIndex = (INT)(accu>>(DFRACT_BITS-2-MANT_DIGITS))&(~MANT_SIZE); + + /* calculate "mantissa" ^4/3 */ + s = FDKaacEnc_mTab_4_3Elc[tabIndex]; + + /* get approperiate exponent multiplier for specExp^3/4 combined with scfMod */ + t = FDKaacEnc_specExpMantTableCombElc[iquantizermod][specExp]; + + /* multiply "mantissa" ^4/3 with exponent multiplier */ + accu = fMult(s,t); + + /* get approperiate exponent shifter */ + specExp = FDKaacEnc_specExpTableComb[iquantizermod][specExp]-1; /* -1 to avoid overflows in accu */ + + if (( -iquantizershift-specExp) < 0) + accu <<= -(-iquantizershift-specExp); + else + accu >>= -iquantizershift-specExp; + + mdctSpectrum[line] = accu; + } + else { + mdctSpectrum[line] = FL2FXCONST_DBL(0.0f); + } + } +} + +/***************************************************************************** + + functionname: FDKaacEnc_QuantizeSpectrum + description: quantizes the entire spectrum + returns: + input: number of scalefactor bands to be quantized, ... + output: quantized spectrum + +*****************************************************************************/ +void FDKaacEnc_QuantizeSpectrum(INT sfbCnt, + INT maxSfbPerGroup, + INT sfbPerGroup, + INT *sfbOffset, + FIXP_DBL *mdctSpectrum, + INT globalGain, + INT *scalefactors, + SHORT *quantizedSpectrum) +{ + INT sfbOffs,sfb; + + /* in FDKaacEnc_quantizeLines quaSpectrum is calculated with: + spec^(3/4) * 2^(-3/16*QSS) * 2^(3/4*scale) + k + simplify scaling calculation and reduce QSS before: + spec^(3/4) * 2^(-3/16*(QSS - 4*scale)) */ + + for(sfbOffs=0;sfbOffs>1)); + + scale = CountLeadingBits(diff); + diff = scaleValue(diff, scale); + diff = fPow2(diff); + scale = fixMin(2*(scale-1), DFRACT_BITS-1); + + diff = scaleValue(diff, -scale); + + xfsf = xfsf + diff; + } + + xfsf = CalcLdData(xfsf); + + return xfsf; +} + +/***************************************************************************** + + functionname: FDKaacEnc_calcSfbQuantEnergyAndDist + description: calculates energy and distortion of quantized values + returns: + input: gain, number of lines to process, quantized spectral data, + spectral data + output: energy, distortion + +*****************************************************************************/ +void FDKaacEnc_calcSfbQuantEnergyAndDist(FIXP_DBL *mdctSpectrum, + SHORT *quantSpectrum, + INT noOfLines, + INT gain, + FIXP_DBL *en, + FIXP_DBL *dist) +{ + INT i,scale; + FIXP_DBL invQuantSpec; + FIXP_DBL diff; + + *en = FL2FXCONST_DBL(0.0f); + *dist = FL2FXCONST_DBL(0.0f); + + for (i=0; i>1)); + + scale = CountLeadingBits(diff); + diff = scaleValue(diff, scale); + diff = fPow2(diff); + + scale = fixMin(2*(scale-1), DFRACT_BITS-1); + + diff = scaleValue(diff, -scale); + + *dist += diff; + } + + *en = CalcLdData(*en)+FL2FXCONST_DBL(0.03125f); + *dist = CalcLdData(*dist); +} + diff --git a/libAACenc/src/quantize.h b/libAACenc/src/quantize.h new file mode 100644 index 0000000..8568ef7 --- /dev/null +++ b/libAACenc/src/quantize.h @@ -0,0 +1,56 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Quantization + +******************************************************************************/ +#ifndef _QUANTIZE_H_ +#define _QUANTIZE_H_ + +#include "common_fix.h" + +/* quantizing */ + +#define MAX_QUANT 8191 + +void FDKaacEnc_QuantizeSpectrum(INT sfbCnt, + INT maxSfbPerGroup, + INT sfbPerGroup, + INT *sfbOffset, FIXP_DBL *mdctSpectrum, + INT globalGain, INT *scalefactors, + SHORT *quantizedSpectrum); + +FIXP_DBL FDKaacEnc_calcSfbDist(FIXP_DBL *mdctSpectrum, + SHORT *quantSpectrum, + INT noOfLines, + INT gain); + +void FDKaacEnc_calcSfbQuantEnergyAndDist(FIXP_DBL *mdctSpectrum, + SHORT *quantSpectrum, + INT noOfLines, + INT gain, + FIXP_DBL *en, + FIXP_DBL *dist); + +#endif /* _QUANTIZE_H_ */ diff --git a/libAACenc/src/sf_estim.cpp b/libAACenc/src/sf_estim.cpp new file mode 100644 index 0000000..59b20ed --- /dev/null +++ b/libAACenc/src/sf_estim.cpp @@ -0,0 +1,1243 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Werner + contents/description: Scale factor estimation + +******************************************************************************/ + +#include "sf_estim.h" +#include "aacEnc_rom.h" +#include "quantize.h" +#include "bit_cnt.h" + + + + +#define AS_PE_FAC_SHIFT 7 +#define DIST_FAC_SHIFT 3 +#define AS_PE_FAC_FLOAT (float)(1 << AS_PE_FAC_SHIFT) +static const INT MAX_SCF_DELTA = 60; + + +static const FIXP_DBL PE_C1 = FL2FXCONST_DBL(3.0f/AS_PE_FAC_FLOAT); /* (log(8.0)/log(2)) >> AS_PE_FAC_SHIFT */ +static const FIXP_DBL PE_C2 = FL2FXCONST_DBL(1.3219281f/AS_PE_FAC_FLOAT); /* (log(2.5)/log(2)) >> AS_PE_FAC_SHIFT */ +static const FIXP_DBL PE_C3 = FL2FXCONST_DBL(0.5593573f); /* 1-C2/C1 */ + + +/* + Function; FDKaacEnc_FDKaacEnc_CalcFormFactorChannel + + Description: Calculates the formfactor + + sf: scale factor of the mdct spectrum + sfbFormFactorLdData is scaled with the factor 1/(((2^sf)^0.5) * (2^FORM_FAC_SHIFT)) +*/ +static void +FDKaacEnc_FDKaacEnc_CalcFormFactorChannel(FIXP_DBL *RESTRICT sfbFormFactorLdData, + PSY_OUT_CHANNEL *RESTRICT psyOutChan) +{ + INT j, sfb, sfbGrp; + FIXP_DBL formFactor; + + int tmp0 = psyOutChan->sfbCnt; + int tmp1 = psyOutChan->maxSfbPerGroup; + int step = psyOutChan->sfbPerGroup; + for(sfbGrp = 0; sfbGrp < tmp0; sfbGrp += step) { + for (sfb = 0; sfb < tmp1; sfb++) { + formFactor = FL2FXCONST_DBL(0.0f); + /* calc sum of sqrt(spec) */ + for(j=psyOutChan->sfbOffsets[sfbGrp+sfb]; jsfbOffsets[sfbGrp+sfb+1]; j++ ) { + formFactor += sqrtFixp(fixp_abs(psyOutChan->mdctSpectrum[j]))>>FORM_FAC_SHIFT; + } + sfbFormFactorLdData[sfbGrp+sfb] = CalcLdData(formFactor); + } + /* set sfbFormFactor for sfbs with zero spec to zero. Just for debugging. */ + for ( ; sfb < psyOutChan->sfbPerGroup; sfb++) { + sfbFormFactorLdData[sfbGrp+sfb] = FL2FXCONST_DBL(-1.0f); + } + } +} + +/* + Function: FDKaacEnc_CalcFormFactor + + Description: Calls FDKaacEnc_FDKaacEnc_CalcFormFactorChannel() for each channel +*/ + +void +FDKaacEnc_CalcFormFactor(QC_OUT_CHANNEL *qcOutChannel[(2)], + PSY_OUT_CHANNEL *psyOutChannel[(2)], + const INT nChannels) +{ + INT j; + for (j=0; jsfbFormFactorLdData, psyOutChannel[j]); + } +} + +/* + Function: FDKaacEnc_calcSfbRelevantLines + + Description: Calculates sfbNRelevantLines + + sfbNRelevantLines is scaled with the factor 1/((2^FORM_FAC_SHIFT) * 2.0) +*/ +static void +FDKaacEnc_calcSfbRelevantLines( const FIXP_DBL *const sfbFormFactorLdData, + const FIXP_DBL *const sfbEnergyLdData, + const FIXP_DBL *const sfbThresholdLdData, + const INT *const sfbOffsets, + const INT sfbCnt, + const INT sfbPerGroup, + const INT maxSfbPerGroup, + FIXP_DBL *sfbNRelevantLines) +{ + INT sfbOffs, sfb; + FIXP_DBL sfbWidthLdData; + FIXP_DBL asPeFacLdData = FL2FXCONST_DBL(0.109375); /* AS_PE_FAC_SHIFT*ld64(2) */ + FIXP_DBL accu; + + /* sfbNRelevantLines[i] = 2^( (sfbFormFactorLdData[i] - 0.25 * (sfbEnergyLdData[i] - ld64(sfbWidth[i]/(2^7)) - AS_PE_FAC_SHIFT*ld64(2)) * 64); */ + + FDKmemclear(sfbNRelevantLines, sfbCnt * sizeof(FIXP_DBL)); + + for (sfbOffs=0; sfbOffs (FIXP_DBL)sfbThresholdLdData[sfbOffs+sfb]) { + INT sfbWidth = sfbOffsets[sfbOffs+sfb+1] - sfbOffsets[sfbOffs+sfb]; + + /* avgFormFactorLdData = sqrtFixp(sqrtFixp(sfbEnergyLdData[sfbOffs+sfb]/sfbWidth)); */ + /* sfbNRelevantLines[sfbOffs+sfb] = sfbFormFactor[sfbOffs+sfb] / avgFormFactorLdData; */ + sfbWidthLdData = (FIXP_DBL)(sfbWidth << (DFRACT_BITS-1-AS_PE_FAC_SHIFT)); + sfbWidthLdData = CalcLdData(sfbWidthLdData); + + accu = sfbEnergyLdData[sfbOffs+sfb] - sfbWidthLdData - asPeFacLdData; + accu = sfbFormFactorLdData[sfbOffs+sfb] - (accu >> 2); + + sfbNRelevantLines[sfbOffs+sfb] = CalcInvLdData(accu) >> 1; + } + } + } +} + +/* + Function: FDKaacEnc_countSingleScfBits + + Description: + + scfBitsFract is scaled by 1/(2^(2*AS_PE_FAC_SHIFT)) +*/ +static FIXP_DBL FDKaacEnc_countSingleScfBits(INT scf, INT scfLeft, INT scfRight) +{ + FIXP_DBL scfBitsFract; + + scfBitsFract = (FIXP_DBL) ( FDKaacEnc_bitCountScalefactorDelta(scfLeft-scf) + + FDKaacEnc_bitCountScalefactorDelta(scf-scfRight) ); + + scfBitsFract = scfBitsFract << (DFRACT_BITS-1-(2*AS_PE_FAC_SHIFT)); + + return scfBitsFract; /* output scaled by 1/(2^(2*AS_PE_FAC)) */ +} + +/* + Function: FDKaacEnc_calcSingleSpecPe + + specPe is scaled by 1/(2^(2*AS_PE_FAC_SHIFT)) +*/ +static FIXP_DBL FDKaacEnc_calcSingleSpecPe(INT scf, FIXP_DBL sfbConstPePart, FIXP_DBL nLines) +{ + FIXP_DBL specPe = FL2FXCONST_DBL(0.0f); + FIXP_DBL ldRatio; + FIXP_DBL scfFract; + + scfFract = (FIXP_DBL)(scf << (DFRACT_BITS-1-AS_PE_FAC_SHIFT)); + + ldRatio = sfbConstPePart - fMult(FL2FXCONST_DBL(0.375f),scfFract); + + if (ldRatio >= PE_C1) { + specPe = fMult(FL2FXCONST_DBL(0.7f),fMult(nLines,ldRatio)); + } + else { + specPe = fMult(FL2FXCONST_DBL(0.7f),fMult(nLines,(PE_C2 + fMult(PE_C3,ldRatio)))); + } + + return specPe; /* output scaled by 1/(2^(2*AS_PE_FAC)) */ +} + +/* + Function: FDKaacEnc_countScfBitsDiff + + scfBitsDiff is scaled by 1/(2^(2*AS_PE_FAC_SHIFT)) +*/ +static FIXP_DBL FDKaacEnc_countScfBitsDiff(INT *scfOld, + INT *scfNew, + INT sfbCnt, + INT startSfb, + INT stopSfb) +{ + FIXP_DBL scfBitsFract; + INT scfBitsDiff = 0; + INT sfb = 0, sfbLast; + INT sfbPrev, sfbNext; + + /* search for first relevant sfb */ + sfbLast = startSfb; + while ((sfbLast=0) && (scfOld[sfbPrev]==FDK_INT_MIN)) + sfbPrev--; + if (sfbPrev>=0) + scfBitsDiff += FDKaacEnc_bitCountScalefactorDelta(scfNew[sfbPrev]-scfNew[sfbLast]) - + FDKaacEnc_bitCountScalefactorDelta(scfOld[sfbPrev]-scfOld[sfbLast]); + /* now loop through all sfbs and count diffs of relevant sfbs */ + for (sfb=sfbLast+1; sfbsfbEnergy[sfb] * 6.75f / sfbFormFactor[sfb]) * LOG2_1; */ + /* 0.02152255861f = log(6.75)/log(2)/AS_PE_FAC_FLOAT; LOG2_1 is 1.0 for log2 */ + /* 0.09375f = log(64.0)/log(2.0)/64.0 = scale of sfbFormFactorLdData */ + if (sfbConstPePart[sfb] == (FIXP_DBL)FDK_INT_MIN) + sfbConstPePart[sfb] = ((psyOutChan->sfbEnergyLdData[sfb] - sfbFormFactorLdData[sfb] - FL2FXCONST_DBL(0.09375f)) >> 1) + FL2FXCONST_DBL(0.02152255861f); + + scfFract = (FIXP_DBL) (scfOld[sfb] << (DFRACT_BITS-1-AS_PE_FAC_SHIFT)); + ldRatioOld = sfbConstPePart[sfb] - fMult(FL2FXCONST_DBL(0.375f),scfFract); + + scfFract = (FIXP_DBL) (scfNew[sfb] << (DFRACT_BITS-1-AS_PE_FAC_SHIFT)); + ldRatioNew = sfbConstPePart[sfb] - fMult(FL2FXCONST_DBL(0.375f),scfFract); + + if (ldRatioOld >= PE_C1) + pOld = ldRatioOld; + else + pOld = PE_C2 + fMult(PE_C3,ldRatioOld); + + if (ldRatioNew >= PE_C1) + pNew = ldRatioNew; + else + pNew = PE_C2 + fMult(PE_C3,ldRatioNew); + + specPeDiff += fMult(FL2FXCONST_DBL(0.7f),fMult(sfbNRelevantLines[sfb],(pNew - pOld))); + } + } + + return specPeDiff; +} + +/* + Function: FDKaacEnc_improveScf + + Description: Calculate the distortion by quantization and inverse quantization of the spectrum with + various scalefactors. The scalefactor which provides the best results will be used. +*/ +static INT FDKaacEnc_improveScf(FIXP_DBL *spec, + SHORT *quantSpec, + SHORT *quantSpecTmp, + INT sfbWidth, + FIXP_DBL threshLdData, + INT scf, + INT minScf, + FIXP_DBL *distLdData, + INT *minScfCalculated + ) +{ + FIXP_DBL sfbDistLdData; + INT scfBest = scf; + INT k; + FIXP_DBL distFactorLdData = FL2FXCONST_DBL(-0.0050301265); /* ld64(1/1.25) */ + + /* calc real distortion */ + sfbDistLdData = FDKaacEnc_calcSfbDist(spec, + quantSpec, + sfbWidth, + scf); + *minScfCalculated = scf; + /* nmr > 1.25 -> try to improve nmr */ + if (sfbDistLdData > (threshLdData-distFactorLdData)) { + INT scfEstimated = scf; + FIXP_DBL sfbDistBestLdData = sfbDistLdData; + INT cnt; + /* improve by bigger scf ? */ + cnt = 0; + + while ((sfbDistLdData > (threshLdData-distFactorLdData)) && (cnt++ < 3)) { + scf++; + sfbDistLdData = FDKaacEnc_calcSfbDist(spec, + quantSpecTmp, + sfbWidth, + scf); + + if (sfbDistLdData < sfbDistBestLdData) { + scfBest = scf; + sfbDistBestLdData = sfbDistLdData; + for (k=0; k (threshLdData-distFactorLdData)) && (cnt++ < 1) && (scf > minScf)) { + scf--; + sfbDistLdData = FDKaacEnc_calcSfbDist(spec, + quantSpecTmp, + sfbWidth, + scf); + + if (sfbDistLdData < sfbDistBestLdData) { + scfBest = scf; + sfbDistBestLdData = sfbDistLdData; + for (k=0; k try to find bigger scf to use less bits */ + FIXP_DBL sfbDistBestLdData = sfbDistLdData; + FIXP_DBL sfbDistAllowedLdData = fixMin(sfbDistLdData-distFactorLdData,threshLdData); + int cnt; + for (cnt=0; cnt<3; cnt++) { + scf++; + sfbDistLdData = FDKaacEnc_calcSfbDist(spec, + quantSpecTmp, + sfbWidth, + scf); + + if (sfbDistLdData < sfbDistAllowedLdData) { + *minScfCalculated = scfBest+1; + scfBest = scf; + sfbDistBestLdData = sfbDistLdData; + for (k=0; ksfbActive); */ + /* setINT(FDK_INT_MAX, prevScfNext, psyOutChan->sfbActive); */ + /* setFLOAT(FLT_MAX, deltaPeLast, psyOutChan->sfbActive); */ + + for (i=0; isfbCnt; i++) { + prevScfLast[i] = FDK_INT_MAX; + prevScfNext[i] = FDK_INT_MAX; + deltaPeLast[i] = (FIXP_DBL)FDK_INT_MAX; + } + + sfbLast = -1; + sfbAct = -1; + sfbNext = -1; + scfLast = 0; + scfNext = 0; + scfMin = FDK_INT_MAX; + scfMax = FDK_INT_MAX; + do { + /* search for new relevant sfb */ + sfbNext++; + while ((sfbNext < psyOutChan->sfbCnt) && (scf[sfbNext] == FDK_INT_MIN)) + sfbNext++; + if ((sfbLast>=0) && (sfbAct>=0) && (sfbNextsfbCnt)) { + /* relevant scfs to the left and to the right */ + scfAct = scf[sfbAct]; + scfLast = scf + sfbLast; + scfNext = scf + sfbNext; + scfMin = fixMin(*scfLast, *scfNext); + scfMax = fixMax(*scfLast, *scfNext); + } + else if ((sfbLast==-1) && (sfbAct>=0) && (sfbNextsfbCnt)) { + /* first relevant scf */ + scfAct = scf[sfbAct]; + scfLast = &scfAct; + scfNext = scf + sfbNext; + scfMin = *scfNext; + scfMax = *scfNext; + } + else if ((sfbLast>=0) && (sfbAct>=0) && (sfbNext==psyOutChan->sfbCnt)) { + /* last relevant scf */ + scfAct = scf[sfbAct]; + scfLast = scf + sfbLast; + scfNext = &scfAct; + scfMin = *scfLast; + scfMax = *scfLast; + } + if (sfbAct>=0) + scfMin = fixMax(scfMin, minScf[sfbAct]); + + if ((sfbAct >= 0) && + (sfbLast>=0 || sfbNextsfbCnt) && + (scfAct > scfMin) && + (scfAct <= scfMin+MAX_SCF_DELTA) && + (scfAct >= scfMax-MAX_SCF_DELTA) && + (*scfLast != prevScfLast[sfbAct] || + *scfNext != prevScfNext[sfbAct] || + deltaPe < deltaPeLast[sfbAct])) { + /* bigger than neighbouring scf found, try to use smaller scf */ + success = 0; + + sfbWidth = psyOutChan->sfbOffsets[sfbAct+1] - psyOutChan->sfbOffsets[sfbAct]; + sfbOffs = psyOutChan->sfbOffsets[sfbAct]; + + /* estimate required bits for actual scf */ + enLdData = qcOutChannel->sfbEnergyLdData[sfbAct]; + + /* sfbConstPePart[sfbAct] = (float)log(6.75f*en/sfbFormFactor[sfbAct]) * LOG2_1; */ + /* 0.02152255861f = log(6.75)/log(2)/AS_PE_FAC_FLOAT; LOG2_1 is 1.0 for log2 */ + /* 0.09375f = log(64.0)/log(2.0)/64.0 = scale of sfbFormFactorLdData */ + if (sfbConstPePart[sfbAct] == (FIXP_DBL)FDK_INT_MIN) { + sfbConstPePart[sfbAct] = ((enLdData - sfbFormFactorLdData[sfbAct] - FL2FXCONST_DBL(0.09375f)) >> 1) + FL2FXCONST_DBL(0.02152255861f); + } + + sfbPeOld = FDKaacEnc_calcSingleSpecPe(scfAct,sfbConstPePart[sfbAct],sfbNRelevantLines[sfbAct]) + +FDKaacEnc_countSingleScfBits(scfAct, *scfLast, *scfNext); + + deltaPeNew = deltaPe; + updateMinScfCalculated = 1; + + do { + /* estimate required bits for smaller scf */ + scfAct--; + /* check only if the same check was not done before */ + if (scfAct < minScfCalculated[sfbAct] && scfAct>=scfMax-MAX_SCF_DELTA){ + /* estimate required bits for new scf */ + sfbPeNew = FDKaacEnc_calcSingleSpecPe(scfAct,sfbConstPePart[sfbAct],sfbNRelevantLines[sfbAct]) + +FDKaacEnc_countSingleScfBits(scfAct,*scfLast, *scfNext); + + /* use new scf if no increase in pe and + quantization error is smaller */ + deltaPeTmp = deltaPe + sfbPeNew - sfbPeOld; + /* 0.0006103515625f = 10.0f/(2^(2*AS_PE_FAC_SHIFT)) */ + if (deltaPeTmp < FL2FXCONST_DBL(0.0006103515625f)) { + /* distortion of new scf */ + sfbDistNew = FDKaacEnc_calcSfbDist(qcOutChannel->mdctSpectrum+sfbOffs, + quantSpecTmp+sfbOffs, + sfbWidth, + scfAct); + + if (sfbDistNew < sfbDist[sfbAct]) { + /* success, replace scf by new one */ + scf[sfbAct] = scfAct; + sfbDist[sfbAct] = sfbDistNew; + + for (k=0; k scfMin); + + deltaPe = deltaPeNew; + + /* save parameters to avoid multiple computations of the same sfb */ + prevScfLast[sfbAct] = *scfLast; + prevScfNext[sfbAct] = *scfNext; + deltaPeLast[sfbAct] = deltaPe; + } + + if (success && restartOnSuccess) { + /* start again at first sfb */ + sfbLast = -1; + sfbAct = -1; + sfbNext = -1; + scfLast = 0; + scfNext = 0; + scfMin = FDK_INT_MAX; + scfMax = FDK_INT_MAX; + success = 0; + } + else { + /* shift sfbs for next band */ + sfbLast = sfbAct; + sfbAct = sfbNext; + } + } while (sfbNext < psyOutChan->sfbCnt); +} + +/* + Function: FDKaacEnc_assimilateMultipleScf + +*/ +static void FDKaacEnc_assimilateMultipleScf(PSY_OUT_CHANNEL *psyOutChan, + QC_OUT_CHANNEL *qcOutChannel, + SHORT *quantSpec, + SHORT *quantSpecTmp, + INT *scf, + INT *minScf, + FIXP_DBL *sfbDist, + FIXP_DBL *sfbConstPePart, + FIXP_DBL *sfbFormFactorLdData, + FIXP_DBL *sfbNRelevantLines) +{ + INT sfb, startSfb, stopSfb; + INT scfTmp[MAX_GROUPED_SFB], scfMin, scfMax, scfAct; + INT possibleRegionFound; + INT sfbWidth, sfbOffs, i, k; + FIXP_DBL sfbDistNew[MAX_GROUPED_SFB], distOldSum, distNewSum; + INT deltaScfBits; + FIXP_DBL deltaSpecPe; + FIXP_DBL deltaPe = FL2FXCONST_DBL(0.0f); + FIXP_DBL deltaPeNew; + INT sfbCnt = psyOutChan->sfbCnt; + + /* calc min and max scalfactors */ + scfMin = FDK_INT_MAX; + scfMax = FDK_INT_MIN; + for (sfb=0; sfb scfAct)) + sfb++; + stopSfb = sfb; + + /* check if in all sfb of a valid region scfAct >= minScf[sfb] */ + possibleRegionFound = 0; + if (startSfb < sfbCnt) { + possibleRegionFound = 1; + for (sfb=startSfb; sfb> DIST_FAC_SHIFT; + + sfbWidth = psyOutChan->sfbOffsets[sfb+1] - psyOutChan->sfbOffsets[sfb]; + sfbOffs = psyOutChan->sfbOffsets[sfb]; + + sfbDistNew[sfb] = FDKaacEnc_calcSfbDist(qcOutChannel->mdctSpectrum+sfbOffs, + quantSpecTmp+sfbOffs, + sfbWidth, + scfAct); + + if (sfbDistNew[sfb] >qcOutChannel->sfbThresholdLdData[sfb]) { + /* no improvement, skip further dist. calculations */ + distNewSum = distOldSum << 1; + break; + } + distNewSum += CalcInvLdData(sfbDistNew[sfb]) >> DIST_FAC_SHIFT; + } + } + /* distortion smaller ? -> use new scalefactors */ + if (distNewSum < distOldSum) { + deltaPe = deltaPeNew; + for (sfb=startSfb; sfbsfbOffsets[sfb+1] - + psyOutChan->sfbOffsets[sfb]; + sfbOffs = psyOutChan->sfbOffsets[sfb]; + scf[sfb] = scfAct; + sfbDist[sfb] = sfbDistNew[sfb]; + + for (k=0; k scfMin); + } +} + +/* + Function: FDKaacEnc_FDKaacEnc_assimilateMultipleScf2 + +*/ +static void FDKaacEnc_FDKaacEnc_assimilateMultipleScf2(PSY_OUT_CHANNEL *psyOutChan, + QC_OUT_CHANNEL *qcOutChannel, + SHORT *quantSpec, + SHORT *quantSpecTmp, + INT *scf, + INT *minScf, + FIXP_DBL *sfbDist, + FIXP_DBL *sfbConstPePart, + FIXP_DBL *sfbFormFactorLdData, + FIXP_DBL *sfbNRelevantLines) +{ + INT sfb, startSfb, stopSfb; + INT scfTmp[MAX_GROUPED_SFB], scfAct, scfNew; + INT scfPrev, scfNext, scfPrevNextMin, scfPrevNextMax, scfLo, scfHi; + INT scfMin, scfMax; + INT *sfbOffs = psyOutChan->sfbOffsets; + FIXP_DBL sfbDistNew[MAX_GROUPED_SFB], sfbDistMax[MAX_GROUPED_SFB]; + FIXP_DBL distOldSum, distNewSum; + INT deltaScfBits; + FIXP_DBL deltaSpecPe; + FIXP_DBL deltaPe = FL2FXCONST_DBL(0.0f); + FIXP_DBL deltaPeNew = FL2FXCONST_DBL(0.0f); + INT sfbCnt = psyOutChan->sfbCnt; + INT bSuccess, bCheckScf; + INT i,k; + + /* calc min and max scalfactors */ + scfMin = FDK_INT_MAX; + scfMax = FDK_INT_MIN; + for (sfb=0; sfb= scfAct) + scfLo = fixMin(scfAct, scfPrevNextMin); + else + scfLo = scfPrevNextMax; + + if (startSfb < sfbCnt && scfHi-scfLo <= MAX_SCF_DELTA) { /* region found */ + /* 1. try to save bits by coarser quantization */ + if (scfHi > scf[startSfb]) { + /* calculate the allowed distortion */ + for (sfb=startSfb; sfbsfbThreshold[sfb]*sfbDist[sfb]*sfbDist[sfb],1.0f/3.0f); */ + /* sfbDistMax[sfb] = fixMax(sfbDistMax[sfb],qcOutChannel->sfbEnergy[sfb]*FL2FXCONST_DBL(1.e-3f)); */ + /* -0.15571537944 = ld64(1.e-3f)*/ + sfbDistMax[sfb] = fMult(FL2FXCONST_DBL(1.0f/3.0f),qcOutChannel->sfbThresholdLdData[sfb])+fMult(FL2FXCONST_DBL(1.0f/3.0f),sfbDist[sfb])+fMult(FL2FXCONST_DBL(1.0f/3.0f),sfbDist[sfb]); + sfbDistMax[sfb] = fixMax(sfbDistMax[sfb],qcOutChannel->sfbEnergyLdData[sfb]-FL2FXCONST_DBL(0.15571537944)); + sfbDistMax[sfb] = fixMin(sfbDistMax[sfb],qcOutChannel->sfbThresholdLdData[sfb]); + } + } + + /* loop over all possible scf values for this region */ + bCheckScf = 1; + for (scfNew=scf[startSfb]+1; scfNew<=scfHi; scfNew++) { + for (k=0; kmdctSpectrum+sfbOffs[sfb], + quantSpecTmp+sfbOffs[sfb], + sfbOffs[sfb+1]-sfbOffs[sfb], + scfNew); + + if (sfbDistNew[sfb] > sfbDistMax[sfb]) { + /* no improvement, skip further dist. calculations */ + bSuccess = 0; + if (sfbDistNew[sfb] == qcOutChannel->sfbEnergyLdData[sfb]) { + /* if whole sfb is already quantized to 0, further + checks with even coarser quant. are useless*/ + bCheckScf = 0; + } + break; + } + } + } + if (bCheckScf==0) /* further calculations useless ? */ + break; + /* distortion small enough ? -> use new scalefactors */ + if (bSuccess) { + deltaPe = deltaPeNew; + for (sfb=startSfb; sfb= minScf[sfb] */ + for (sfb=startSfb; sfb> DIST_FAC_SHIFT; + + sfbDistNew[sfb] = FDKaacEnc_calcSfbDist(qcOutChannel->mdctSpectrum+sfbOffs[sfb], + quantSpecTmp+sfbOffs[sfb], + sfbOffs[sfb+1]-sfbOffs[sfb], + scfNew); + + if (sfbDistNew[sfb] > qcOutChannel->sfbThresholdLdData[sfb]) { + /* no improvement, skip further dist. calculations */ + distNewSum = distOldSum << 1; + break; + } + distNewSum += CalcInvLdData(sfbDistNew[sfb]) >> DIST_FAC_SHIFT; + } + } + /* distortion smaller ? -> use new scalefactors */ + if (distNewSum < fMult(FL2FXCONST_DBL(0.8f),distOldSum)) { + deltaPe = deltaPeNew; + for (sfb=startSfb; sfbmdctSpectrum+sfbOffs[sfb], + quantSpec+sfbOffs[sfb], + sfbOffs[sfb+1]-sfbOffs[sfb], scfNew, + &sfbEnQ, &sfbDistNew[sfb]); + + distOldSum += CalcInvLdData(sfbDist[sfb]) >> DIST_FAC_SHIFT; + distNewSum += CalcInvLdData(sfbDistNew[sfb]) >> DIST_FAC_SHIFT; + + /* 0.00259488556167 = ld64(1.122f) */ + /* -0.00778722686652 = ld64(0.7079f) */ + if ((sfbDistNew[sfb] > (sfbDist[sfb]+FL2FXCONST_DBL(0.00259488556167f))) || (sfbEnQ < (qcOutChannel->sfbEnergyLdData[sfb] - FL2FXCONST_DBL(0.00778722686652f)))){ + bSuccess = 0; + break; + } + } + } + /* distortion smaller ? -> use new scalefactors */ + if (distNewSum < distOldSum && bSuccess) { + deltaPe = deltaPeNew; + for (sfb=startSfb; sfb C1/2^8 */ + + + + if (invQuant>0) { + FDKmemclear(quantSpec, (1024)*sizeof(SHORT)); + } + + /* scfs without energy or with thresh>energy are marked with FDK_INT_MIN */ + for(i=0; isfbCnt; i++) { + scf[i] = FDK_INT_MIN; + } + + for (i=0; isfbCnt; sfbOffs+=psyOutChannel->sfbPerGroup) { + for(sfb=0; sfbmaxSfbPerGroup; sfb++) { + + threshLdData = qcOutChannel->sfbThresholdLdData[sfbOffs+sfb]; + energyLdData = qcOutChannel->sfbEnergyLdData[sfbOffs+sfb]; + + sfbDistLdData[sfbOffs+sfb] = energyLdData; + + + if (energyLdData > threshLdData) { + FIXP_DBL tmp; + + /* energyPart = (float)log10(sfbFormFactor[sfbOffs+sfb]); */ + /* 0.09375f = log(64.0)/log(2.0)/64.0 = scale of sfbFormFactorLdData */ + energyPartLdData = sfbFormFactorLdData[sfbOffs+sfb] + FL2FXCONST_DBL(0.09375f); + + /* influence of allowed distortion */ + /* thresholdPart = (float)log10(6.75*thresh+FLT_MIN); */ + thresholdPartLdData = threshConstLdData + threshLdData; + + /* scf calc */ + /* scfFloat = 8.8585f * (thresholdPart - energyPart); */ + scfFract = thresholdPartLdData - energyPartLdData; + /* conversion from log2 to log10 */ + scfFract = fMult(convConst,scfFract); + /* (8.8585f * scfFract)/8 = 8/8 * scfFract + 0.8585 * scfFract/8 */ + scfFract = scfFract + fMult(FL2FXCONST_DBL(0.8585f),scfFract >> 3); + + /* integer scalefactor */ + /* scfInt = (int)floor(scfFloat); */ + scfInt = (INT)(scfFract>>((DFRACT_BITS-1)-3-LD_DATA_SHIFT)); /* 3 bits => scfFract/8.0; 6 bits => ld64 */ + + /* maximum of spectrum */ + maxSpec = FL2FXCONST_DBL(0.0f); + + for(j=psyOutChannel->sfbOffsets[sfbOffs+sfb]; jsfbOffsets[sfbOffs+sfb+1]; j++ ){ + absSpec = fixp_abs(qcOutChannel->mdctSpectrum[j]); + maxSpec = (absSpec > maxSpec) ? absSpec : maxSpec; + } + + /* lower scf limit to avoid quantized values bigger than MAX_QUANT */ + /* C1 = -69.33295f, C2 = 5.77078f = 4/log(2) */ + /* minSfMaxQuant[sfbOffs+sfb] = (int)ceil(C1 + C2*log(maxSpec)); */ + /* C1/2^8 + 4/log(2.0)*log(maxSpec)/2^8 => C1/2^8 + log(maxSpec)/log(2.0)*4/2^8 => C1/2^8 + log(maxSpec)/log(2.0)/64.0 */ + + //minSfMaxQuant[sfbOffs+sfb] = ((INT) ((c1Const + CalcLdData(maxSpec)) >> ((DFRACT_BITS-1)-8))) + 1; + tmp = CalcLdData(maxSpec); + if (c1Const>FL2FXCONST_DBL(-1.f)-tmp) { + minSfMaxQuant[sfbOffs+sfb] = ((INT) ((c1Const + tmp) >> ((DFRACT_BITS-1)-8))) + 1; + } + else { + minSfMaxQuant[sfbOffs+sfb] = ((INT) (FL2FXCONST_DBL(-1.f) >> ((DFRACT_BITS-1)-8))) + 1; + } + + scfInt = fixMax(scfInt, minSfMaxQuant[sfbOffs+sfb]); + + + /* find better scalefactor with analysis by synthesis */ + if (invQuant>0) { + scfInt = FDKaacEnc_improveScf(qcOutChannel->mdctSpectrum+psyOutChannel->sfbOffsets[sfbOffs+sfb], + quantSpec+psyOutChannel->sfbOffsets[sfbOffs+sfb], + quantSpecTmp+psyOutChannel->sfbOffsets[sfbOffs+sfb], + psyOutChannel->sfbOffsets[sfbOffs+sfb+1]-psyOutChannel->sfbOffsets[sfbOffs+sfb], + threshLdData, scfInt, minSfMaxQuant[sfbOffs+sfb], + &sfbDistLdData[sfbOffs+sfb], &minScfCalculated[sfbOffs+sfb] + ); + } + scf[sfbOffs+sfb] = scfInt; + } + } + } + + + if (invQuant>1) { + /* try to decrease scf differences */ + FIXP_DBL sfbConstPePart[MAX_GROUPED_SFB]; + FIXP_DBL sfbNRelevantLines[MAX_GROUPED_SFB]; + + for (i=0; isfbCnt; i++) + sfbConstPePart[i] = (FIXP_DBL)FDK_INT_MIN; + + FDKaacEnc_calcSfbRelevantLines( sfbFormFactorLdData, + qcOutChannel->sfbEnergyLdData, + qcOutChannel->sfbThresholdLdData, + psyOutChannel->sfbOffsets, + psyOutChannel->sfbCnt, + psyOutChannel->sfbPerGroup, + psyOutChannel->maxSfbPerGroup, + sfbNRelevantLines); + + + FDKaacEnc_assimilateSingleScf(psyOutChannel, qcOutChannel, quantSpec, quantSpecTmp, scf, + minSfMaxQuant, sfbDistLdData, sfbConstPePart, + sfbFormFactorLdData, sfbNRelevantLines, minScfCalculated, 1); + + + FDKaacEnc_assimilateMultipleScf(psyOutChannel, qcOutChannel, quantSpec, quantSpecTmp, scf, + minSfMaxQuant, sfbDistLdData, sfbConstPePart, + sfbFormFactorLdData, sfbNRelevantLines); + + + FDKaacEnc_FDKaacEnc_assimilateMultipleScf2(psyOutChannel, qcOutChannel, quantSpec, quantSpecTmp, scf, + minSfMaxQuant, sfbDistLdData, sfbConstPePart, + sfbFormFactorLdData, sfbNRelevantLines); + + } + + + /* get min scalefac */ + minSf = FDK_INT_MAX; + for (sfbOffs=0; sfbOffssfbCnt; sfbOffs+=psyOutChannel->sfbPerGroup) { + for (sfb = 0; sfb < psyOutChannel->maxSfbPerGroup; sfb++) { + if (scf[sfbOffs+sfb]!=FDK_INT_MIN) + minSf = fixMin(minSf,scf[sfbOffs+sfb]); + } + } + + /* limit scf delta */ + for (sfbOffs=0; sfbOffssfbCnt; sfbOffs+=psyOutChannel->sfbPerGroup) { + for (sfb = 0; sfb < psyOutChannel->maxSfbPerGroup; sfb++) { + if ((scf[sfbOffs+sfb] != FDK_INT_MIN) && (minSf+MAX_SCF_DELTA) < scf[sfbOffs+sfb]) { + scf[sfbOffs+sfb] = minSf + MAX_SCF_DELTA; + if (invQuant > 0) { /* changed bands need to be quantized again */ + sfbDistLdData[sfbOffs+sfb] = + FDKaacEnc_calcSfbDist(qcOutChannel->mdctSpectrum+psyOutChannel->sfbOffsets[sfbOffs+sfb], + quantSpec+psyOutChannel->sfbOffsets[sfbOffs+sfb], + psyOutChannel->sfbOffsets[sfbOffs+sfb+1]-psyOutChannel->sfbOffsets[sfbOffs+sfb], + scf[sfbOffs+sfb] + ); + } + } + } + } + + + /* get max scalefac for global gain */ + maxSf = FDK_INT_MIN; + for (sfbOffs=0; sfbOffssfbCnt; sfbOffs+=psyOutChannel->sfbPerGroup) { + for (sfb = 0; sfb < psyOutChannel->maxSfbPerGroup; sfb++) { + maxSf = fixMax(maxSf,scf[sfbOffs+sfb]); + } + } + + /* calc loop scalefactors, if spec is not all zero (i.e. maxSf == -99) */ + if( maxSf > FDK_INT_MIN ) { + *globalGain = maxSf; + for (sfbOffs=0; sfbOffssfbCnt; sfbOffs+=psyOutChannel->sfbPerGroup) { + for (sfb = 0; sfb < psyOutChannel->maxSfbPerGroup; sfb++) { + if( scf[sfbOffs+sfb] == FDK_INT_MIN ) { + scf[sfbOffs+sfb] = 0; + /* set band explicitely to zero */ + for(j=psyOutChannel->sfbOffsets[sfbOffs+sfb]; jsfbOffsets[sfbOffs+sfb+1]; j++ ) { + qcOutChannel->mdctSpectrum[j] = FL2FXCONST_DBL(0.0f); + } + } + else { + scf[sfbOffs+sfb] = maxSf - scf[sfbOffs+sfb]; + } + } + } + } + else{ + *globalGain = 0; + /* set spectrum explicitely to zero */ + for (sfbOffs=0; sfbOffssfbCnt; sfbOffs+=psyOutChannel->sfbPerGroup) { + for (sfb = 0; sfb < psyOutChannel->maxSfbPerGroup; sfb++) { + scf[sfbOffs+sfb] = 0; + /* set band explicitely to zero */ + for(j=psyOutChannel->sfbOffsets[sfbOffs+sfb]; jsfbOffsets[sfbOffs+sfb+1]; j++ ) { + qcOutChannel->mdctSpectrum[j] = FL2FXCONST_DBL(0.0f); + } + } + } + } + + /* free quantSpecTmp from scratch */ + C_ALLOC_SCRATCH_END(quantSpecTmp, SHORT, (1024)); + + +} + +void +FDKaacEnc_EstimateScaleFactors(PSY_OUT_CHANNEL *psyOutChannel[], + QC_OUT_CHANNEL* qcOutChannel[], + const int invQuant, + const int nChannels) +{ + int ch; + + for (ch = 0; ch < nChannels; ch++) + { + FDKaacEnc_FDKaacEnc_EstimateScaleFactorsChannel(qcOutChannel[ch], + psyOutChannel[ch], + qcOutChannel[ch]->scf, + &qcOutChannel[ch]->globalGain, + qcOutChannel[ch]->sfbFormFactorLdData + ,invQuant, + qcOutChannel[ch]->quantSpec + ); + } + +} + diff --git a/libAACenc/src/sf_estim.h b/libAACenc/src/sf_estim.h new file mode 100644 index 0000000..8b486af --- /dev/null +++ b/libAACenc/src/sf_estim.h @@ -0,0 +1,54 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Werner + contents/description: Scale factor estimation + +******************************************************************************/ +#ifndef _SF_ESTIM_H +#define _SF_ESTIM_H + +#include "common_fix.h" + + +#include "psy_const.h" +#include "qc_data.h" +#include "interface.h" + +#define FORM_FAC_SHIFT 6 + + +void +FDKaacEnc_CalcFormFactor(QC_OUT_CHANNEL *qcOutChannel[(2)], + PSY_OUT_CHANNEL *psyOutChannel[(2)], + const INT nChannels); + +void +FDKaacEnc_EstimateScaleFactors(PSY_OUT_CHANNEL *psyOutChannel[], + QC_OUT_CHANNEL* qcOutChannel[], + const int invQuant, + const int nChannels); + + + +#endif diff --git a/libAACenc/src/spreading.cpp b/libAACenc/src/spreading.cpp new file mode 100644 index 0000000..fc2f2f6 --- /dev/null +++ b/libAACenc/src/spreading.cpp @@ -0,0 +1,52 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Spreading of energy + +******************************************************************************/ + +#include "spreading.h" + +void FDKaacEnc_SpreadingMax(const INT pbCnt, + const FIXP_DBL *RESTRICT maskLowFactor, + const FIXP_DBL *RESTRICT maskHighFactor, + FIXP_DBL *RESTRICT pbSpreadEnergy) +{ + int i; + FIXP_DBL delay; + + /* slope to higher frequencies */ + delay = pbSpreadEnergy[0]; + for (i=1; i=0; i--) { + delay = fixMax(pbSpreadEnergy[i], fMult(maskLowFactor[i],delay)); + pbSpreadEnergy[i] = delay; + } +} diff --git a/libAACenc/src/spreading.h b/libAACenc/src/spreading.h new file mode 100644 index 0000000..dcb0923 --- /dev/null +++ b/libAACenc/src/spreading.h @@ -0,0 +1,40 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: Spreading of energy and weighted tonality + +******************************************************************************/ + +#ifndef _SPREADING_H +#define _SPREADING_H + +#include "common_fix.h" + + +void FDKaacEnc_SpreadingMax(const INT pbCnt, + const FIXP_DBL *RESTRICT maskLowFactor, + const FIXP_DBL *RESTRICT maskHighFactor, + FIXP_DBL *RESTRICT pbSpreadEnergy); + +#endif /* #ifndef _SPREADING_H */ diff --git a/libAACenc/src/tns_func.h b/libAACenc/src/tns_func.h new file mode 100644 index 0000000..ac619f6 --- /dev/null +++ b/libAACenc/src/tns_func.h @@ -0,0 +1,81 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: Alex Goeschel + contents/description: Temporal noise shaping + +******************************************************************************/ +#ifndef _TNS_FUNC_H +#define _TNS_FUNC_H + +#include "common_fix.h" + +#include "psy_configuration.h" + +AAC_ENCODER_ERROR FDKaacEnc_InitTnsConfiguration(INT bitrate, + INT samplerate, + INT channels, + INT blocktype, + INT granuleLength, + INT ldSbrPresent, + TNS_CONFIG *tnsConfig, + PSY_CONFIGURATION *psyConfig, + INT active, + INT useTnsPeak ); + +INT FDKaacEnc_TnsDetect( + TNS_DATA *tnsData, + const TNS_CONFIG *tC, + TNS_INFO* tnsInfo, + INT sfbCnt, + FIXP_DBL *spectrum, + INT subBlockNumber, + INT blockType + ); + + + +void FDKaacEnc_TnsSync( + TNS_DATA *tnsDataDest, + const TNS_DATA *tnsDataSrc, + TNS_INFO *tnsInfoDest, + TNS_INFO *tnsInfoSrc, + const INT blockTypeDest, + const INT blockTypeSrc, + const TNS_CONFIG *tC + ); + +INT FDKaacEnc_TnsEncode( + TNS_INFO* tnsInfo, + TNS_DATA* tnsData, + const INT numOfSfb, + const TNS_CONFIG *tC, + const INT lowPassLine, + FIXP_DBL* spectrum, + const INT subBlockNumber, + const INT blockType + ); + + + +#endif /* _TNS_FUNC_H */ diff --git a/libAACenc/src/tns_param.cpp b/libAACenc/src/tns_param.cpp new file mode 100644 index 0000000..36a62e8 --- /dev/null +++ b/libAACenc/src/tns_param.cpp @@ -0,0 +1,31 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M.Werner + contents/description: TNS parameters + +******************************************************************************/ + +#include "tns_param.h" + + diff --git a/libAACenc/src/tns_param.h b/libAACenc/src/tns_param.h new file mode 100644 index 0000000..d9a11e5 --- /dev/null +++ b/libAACenc/src/tns_param.h @@ -0,0 +1,33 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) copyright Fraunhofer-IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: Alex Goeschel + contents/description: Temporal noise shaping + +******************************************************************************/ +#ifndef _TNS_PARAM_H +#define _TNS_PARAM_H + + + +#endif /* _TNS_PARAM_H */ diff --git a/libAACenc/src/tonality.cpp b/libAACenc/src/tonality.cpp new file mode 100644 index 0000000..54b4b6e --- /dev/null +++ b/libAACenc/src/tonality.cpp @@ -0,0 +1,147 @@ +/******************************** MPEG Audio Encoder ************************** + + (c) copyright Fraunhofer IIS (1996) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + author: M. Werner + contents/description: Convert chaos measure to the tonality index + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "tonality.h" +#include "chaosmeasure.h" + +/*static const FIXP_SGL maxtone = FL2FXCONST_SGL(0.5);*/ +/*static const FIXP_SGL mintone = FL2FXCONST_SGL(0.05);*/ +/*static const float convtone = 2.0f;*/ /* 1.0/mintone */ + +/* -1.0/log(maxtone/mintone) */ +static const FIXP_DBL normlog = (FIXP_DBL)0xd977d949; /*FL2FXCONST_DBL(-0.4342944819f * FDKlog(2.0)/FDKlog(2.7182818)); */ + +static void FDKaacEnc_CalcSfbTonality(FIXP_DBL *RESTRICT spectrum, + INT *RESTRICT sfbMaxScaleSpec, + FIXP_DBL *RESTRICT chaosMeasure, + FIXP_SGL *RESTRICT sfbTonality, + INT sfbCnt, + const INT *RESTRICT sfbOffset, + FIXP_DBL *RESTRICT sfbEnergyLD64 ); + + +void FDKaacEnc_CalculateFullTonality(FIXP_DBL *RESTRICT spectrum, + INT *RESTRICT sfbMaxScaleSpec, + FIXP_DBL *RESTRICT sfbEnergyLD64, + FIXP_SGL *RESTRICT sfbTonality, + INT sfbCnt, + const INT *sfbOffset, + INT usePns) +{ + INT j; +#if defined(ARCH_PREFER_MULT_32x16) + FIXP_SGL alpha_0 = FL2FXCONST_SGL(0.25f); /* used in smooth ChaosMeasure */ + FIXP_SGL alpha_1 = FL2FXCONST_SGL(1.0f-0.25f); /* used in smooth ChaosMeasure */ +#else + FIXP_DBL alpha_0 = FL2FXCONST_DBL(0.25f); /* used in smooth ChaosMeasure */ + FIXP_DBL alpha_1 = FL2FXCONST_DBL(1.0f-0.25f); /* used in smooth ChaosMeasure */ +#endif + INT numberOfLines = sfbOffset[sfbCnt]; + + if (!usePns) + return; + + C_ALLOC_SCRATCH_START(chaosMeasurePerLine, FIXP_DBL, (1024)); + /* calculate chaos measure */ + FDKaacEnc_CalculateChaosMeasure(spectrum, + numberOfLines, + chaosMeasurePerLine); + + /* smooth ChaosMeasure */ + for (j=1;j 7/2 = 4 (spc*spc) */ + + FIXP_DBL chaosMeasureSfb = FL2FXCONST_DBL(0.0); + + /* calc chaosMeasurePerSfb */ + for (j=(sfbOffset[i+1]-sfbOffset[i])-1; j>=0; j--) { + FIXP_DBL tmp = (*spectrum++)< FL2FXCONST_DBL(-0.0519051) ) /* > ld(0.05)+ld(2) */ + { + if (chaosMeasureSfbLD64 <= FL2FXCONST_DBL(0.0) ) + sfbTonality[i] = FX_DBL2FX_SGL(fMultDiv2( chaosMeasureSfbLD64 , normlog ) << 7); + else + sfbTonality[i] = FL2FXCONST_SGL(0.0); + } + else + sfbTonality[i] = (FIXP_SGL)MAXVAL_SGL; + } + else + sfbTonality[i] = (FIXP_SGL)MAXVAL_SGL; + } +} diff --git a/libAACenc/src/tonality.h b/libAACenc/src/tonality.h new file mode 100644 index 0000000..8c6e4ed --- /dev/null +++ b/libAACenc/src/tonality.h @@ -0,0 +1,46 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) copyright Fraunhofer - IIS (1996) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + author: M. Lohwasser + contents/description: Calculate tonality index + +******************************************************************************/ + +#ifndef __TONALITY_H +#define __TONALITY_H + +#include "common_fix.h" + + +#include "chaosmeasure.h" + + +void FDKaacEnc_CalculateFullTonality( FIXP_DBL *RESTRICT spectrum, + INT *RESTRICT sfbMaxScaleSpec, + FIXP_DBL *RESTRICT sfbEnergyLD64, + FIXP_SGL *RESTRICT sfbTonality, + INT sfbCnt, + const INT *sfbOffset, + INT usePns); + +#endif diff --git a/libAACenc/src/transform.cpp b/libAACenc/src/transform.cpp new file mode 100644 index 0000000..99b8a6b --- /dev/null +++ b/libAACenc/src/transform.cpp @@ -0,0 +1,203 @@ +/***************************************************************************** + + (C) copyright Fraunhofer IIS (2001) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Description: FDKaacLdEnc_MdctTransform480: + The module FDKaacLdEnc_MdctTransform will perform the MDCT. + The MDCT supports the sine window and + + the zero padded window. The algorithm of the MDCT + can be divided in Windowing, PreModulation, Fft and + PostModulation. + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "transform.h" + +#include "dct.h" +#include "psy_const.h" +#include "aacEnc_rom.h" +#include "FDK_tools_rom.h" + +INT FDKaacEnc_Transform_Real (const INT_PCM * pTimeData, + FIXP_DBL *RESTRICT mdctData, + const INT blockType, + const INT windowShape, + INT *prevWindowShape, + const INT frameLength, + INT *mdctData_e, + INT filterType + ,FIXP_DBL * RESTRICT overlapAddBuffer + ) +{ + const INT_PCM * RESTRICT timeData; + + INT i; + /* tl: transform length + fl: left window slope length + nl: left window slope offset + fr: right window slope length + nr: right window slope offset + See FDK_tools/doc/intern/mdct.tex for more detail. */ + int tl, fl, nl, fr, nr; + + const FIXP_WTP * RESTRICT pLeftWindowPart; + const FIXP_WTP * RESTRICT pRightWindowPart; + + /* + * MDCT scale: + * + 1: fMultDiv2() in windowing. + * + 1: Because of factor 1/2 in Princen-Bradley compliant windowed TDAC. + */ + *mdctData_e = 1+1; + + tl = frameLength; + timeData = pTimeData; + + switch( blockType ) { + case LONG_WINDOW: + { + int offset = (windowShape == LOL_WINDOW) ? ((frameLength * 3)>>2) : 0; + fl = frameLength - offset; + fr = frameLength - offset; + } + break; + case STOP_WINDOW: + fl = frameLength >> 3; + fr = frameLength; + break; + case START_WINDOW: /* or StopStartSequence */ + fl = frameLength; + fr = frameLength >> 3; + break; + case SHORT_WINDOW: + fl = fr = frameLength >> 3; + tl >>= 3; + timeData = pTimeData + 3*fl + (fl/2); + break; + default: + FDK_ASSERT(0); + return -1; + break; + } + + /* Taken from FDK_tools/src/mdct.cpp Derive NR and NL */ + nr = (tl - fr)>>1; + nl = (tl - fl)>>1; + + pLeftWindowPart = FDKgetWindowSlope(fl, *prevWindowShape); + pRightWindowPart = FDKgetWindowSlope(fr, windowShape); + + /* windowing */ + if (filterType != FB_ELD) + { + /* Left window slope offset */ + for (i=0; i> ( 1 ); +#else + mdctData[(tl/2)+i] = - (FIXP_DBL) timeData[tl-i-1] << (DFRACT_BITS - SAMPLE_BITS - 1); +#endif + } + /* Left window slope */ + for (i=0; i> (1); +#else + mdctData[(tl/2)-1-i] = - (FIXP_DBL) timeData[tl+i] << (DFRACT_BITS - SAMPLE_BITS - 1); +#endif + } + /* Right window slope */ + for (i=0; i> (-WTS1)); + outval += (fMultDiv2((FIXP_PCM)timeData[L+N*3/4+i], pWindowELD[N+N/2+i]) >> (-WTS1) ); + outval += (fMultDiv2(overlapAddBuffer[N/2+i], pWindowELD[2*N+i])>> (-WTS2-1)); + + overlapAddBuffer[N/2+i] = overlapAddBuffer[i]; + + overlapAddBuffer[i] = z0; + mdctData[i] = overlapAddBuffer[N/2+i] + (fMultDiv2(overlapAddBuffer[N+N/2-1-i], pWindowELD[2*N+N/2+i]) >> (-WTS2-1)); + + mdctData[N-1-i] = outval; + overlapAddBuffer[N+N/2-1-i] = outval; + } + + for(i=N/4;i> (-WTS1)) ; + outval += (fMultDiv2(overlapAddBuffer[N/2+i], pWindowELD[2*N+i]) >> (-WTS2-1)); + + overlapAddBuffer[N/2+i] = overlapAddBuffer[i] + (fMult((FIXP_PCM)timeData[L-N/4+i], pWindowELD[N/2+i])<< (WTS0-1) ); + + overlapAddBuffer[i] = z0; + mdctData[i] = overlapAddBuffer[N/2+i] + (fMultDiv2(overlapAddBuffer[N+N/2-1-i], pWindowELD[2*N+N/2+i]) >> (-WTS2-1)); + + mdctData[N-1-i] = outval; + overlapAddBuffer[N+N/2-1-i] = outval; + } + } + + dct_IV(mdctData, tl, mdctData_e); + + *prevWindowShape = windowShape; + + return 0; +} + diff --git a/libAACenc/src/transform.h b/libAACenc/src/transform.h new file mode 100644 index 0000000..6be93b5 --- /dev/null +++ b/libAACenc/src/transform.h @@ -0,0 +1,60 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: M. Werner + contents/description: MDCT Transform + +******************************************************************************/ +#ifndef _TRANSFORM_H +#define _TRANSFORM_H + +#include "common_fix.h" + +#define WTS0 1 +#define WTS1 0 +#define WTS2 -2 + +/** + * \brief: Performe MDCT transform of time domain data. + * \param timeData pointer to time domain input signal. + * \param mdctData pointer to store frequency domain output data. + * \param blockType index indicating the type of block. Either + * LONG_WINDOW, START_WINDOW, SHORT_WINDOW or STOP_WINDOW. + * \param windowShape index indicating the window slope type to be used. + * Values allowed are either SINE_WINDOW or KBD_WINDOW. + * \param frameLength length of the block. Either 1024 or 960. + * \param mdctData_e pointer to an INT where the exponent of the frequency + * domain output data is stored into. + * \return 0 in case of success, non-zero in case of error (inconsistent parameters). + */ +INT FDKaacEnc_Transform_Real (const INT_PCM *timeData, + FIXP_DBL *RESTRICT mdctData, + const INT blockType, + const INT windowShape, + INT *prevWindowShape, + const INT frameLength, + INT *mdctData_e, + INT filterType + ,FIXP_DBL * RESTRICT overlapAddBuffer + ); +#endif diff --git a/libFDK/Android.mk b/libFDK/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/libFDK/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/libFDK/include/FDK_archdef.h b/libFDK/include/FDK_archdef.h new file mode 100644 index 0000000..eecc990 --- /dev/null +++ b/libFDK/include/FDK_archdef.h @@ -0,0 +1,184 @@ +/*************************** Fraunhofer IIS FDK Tools *********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef __ARCH_H__ +#define __ARCH_H__ + +/* Performance / Quality profile selector */ + #define FDK_HIGH_PERFORMANCE + +/* Unify some few toolchain specific defines to avoid having large "or" macro contraptions all over the source code. */ + +/* Take action against VisualStudio 2005 crosscompile problems. */ + +/* Use single macro (the GCC built in macro) for architecture identification independent of the particular toolchain */ +#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || (defined(_MSC_VER) && defined(_M_IX86)) || defined (__x86_64__) +#define __x86__ +#endif + +#if (defined(_M_ARM) || defined(__CC_ARM)) && !defined(__arm__) || defined(__TI_TMS470_V5__) && !defined(__arm__) +#define __arm__ +#endif + + + +/* Define __ARM_ARCH_5TE__ if armv5te features are supported */ +#if (__TARGET_ARCH_ARM == 5) || defined(__TARGET_FEATURE_DSPMUL) || (_M_ARM == 5) || defined(__ARM_ARCH_5TEJ__) || defined(__TI_TMS470_V5__) || defined(__ARM_ARCH_7EM__) +#define __ARM_ARCH_5TE__ +#endif + +/* Define __ARM_ARCH_6__ if the armv6 intructions are being supported. */ +#if (__TARGET_ARCH_ARM == 6) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6ZK__) +#define __ARM_ARCH_5TE__ +#define __ARM_ARCH_6__ +#endif + +/* Define __ARM_ARCH_7_A__ if the armv7 intructions are being supported. */ +#if defined(__TARGET_ARCH_7_R) || defined(__ARM_ARCH_7R__) +#define __ARM_ARCH_5TE__ +#define __ARM_ARCH_6__ +#define __ARM_ARCH_7_R__ +#endif + +/* Define __ARM_ARCH_7_A__ if the armv7 intructions are being supported. */ +#if defined(__TARGET_ARCH_7_A) || defined(__ARM_ARCH_7A__) +#define __ARM_ARCH_5TE__ +#define __ARM_ARCH_6__ +#define __ARM_ARCH_7_A__ +#endif + +/* Define __ARM_ARCH_7M__ if the ARMv7-M instructions are being supported, e.g. Cortex-M3. */ +#if defined(__TARGET_ARCH_7_M) || defined(__ARM_ARCH_7_M__) +#define __ARM_ARCH_7M__ +#endif + +/* Define __ARM_ARCH_7EM__ if the ARMv7-ME instructions are being supported, e.g. Cortex-M4. */ +#if defined(__TARGET_ARCH_7E_M) || defined(__ARM_ARCH_7E_M__) +#define __ARM_ARCH_7EM__ +#endif + +/* Detect and unify macros for neon feature. */ +#if defined(__TARGET_FEATURE_NEON) && !defined(__ARM_NEON__) +#define __ARM_NEON__ +#endif + +#ifdef _M_ARM +#include "cmnintrin.h" +#include "armintr.h" +#endif + + + +/* Define preferred Multiplication type */ +#if defined(FDK_HIGH_PERFORMANCE) && !defined(FDK_HIGH_QUALITY) /* FDK_HIGH_PERFORMANCE */ + +#if defined(__mips__) || defined(__powerpc__) || defined(__sh__) +#define ARCH_PREFER_MULT_16x16 +#undef SINETABLE_16BIT +#undef POW2COEFF_16BIT +#undef LDCOEFF_16BIT +#undef WINDOWTABLE_16BIT + +#elif defined(__arm__) && defined(__ARM_ARCH_5TE__) /* cppp replaced: elif */ /* cppp replaced: elif */ +#define ARCH_PREFER_MULT_32x16 +#define SINETABLE_16BIT +#define POW2COEFF_16BIT +#define LDCOEFF_16BIT +#define WINDOWTABLE_16BIT + +#elif defined(__arm__) && defined(__ARM_ARCH_7M__) +#define ARCH_PREFER_MULT_32x16 +#define SINETABLE_16BIT +#define POW2COEFF_16BIT +#define LDCOEFF_16BIT +#define WINDOWTABLE_16BIT + +#elif defined(__arm__) && defined(__ARM_ARCH_7EM__) +#define ARCH_PREFER_MULT_32x32 +#define ARCH_PREFER_MULT_32x16 +#define SINETABLE_16BIT +#define POW2COEFF_16BIT +#define LDCOEFF_16BIT +#define WINDOWTABLE_16BIT + +#elif defined(__arm__) && !defined(__ARM_ARCH_5TE__) +#define ARCH_PREFER_MULT_16x16 +#undef SINETABLE_16BIT +#undef WINDOWTABLE_16BIT +#undef POW2COEFF_16BIT +#undef LDCOEFF_16BIT + +#elif defined(__x86__) /* cppp replaced: elif */ +#define ARCH_PREFER_MULT_32x16 +#define SINETABLE_16BIT +#define WINDOWTABLE_16BIT +#define POW2COEFF_16BIT +#define LDCOEFF_16BIT + +#else + + #error >>>> Please set architecture characterization defines for your platform (FDK_HIGH_PERFORMANCE)! <<<< + +#endif /* Architecture switches */ + +#else /* neither FDK_HIGH_QUALITY or FDK_HIGH_PERFORMANCE */ + +#error Either set FDK_HIGH_QUALITY or FDK_HIGH_PERFORMANCE, but not both nor none of them. + +#endif /* End of quality/complexity tradeoff */ + +#define FDKTOOLS_PACKED_TABLES + + +#ifdef SINETABLE_16BIT + #define FIXP_STB FIXP_SGL /* STB sinus Tab used in transformation */ + #define FIXP_STP FIXP_SPK + #define STC(a) (FX_DBL2FXCONST_SGL(a)) +#else + #define FIXP_STB FIXP_DBL + #define FIXP_STP FIXP_DPK + #define STC(a) ((FIXP_DBL)(LONG)(a)) +#endif /* defined(SINETABLE_16BIT) */ + +#define STCP(cos,sin) { { STC(cos), STC(sin) } } + + +#ifdef WINDOWTABLE_16BIT + #define FIXP_WTB FIXP_SGL /* single FIXP_SGL values */ + #define FIXP_WTP FIXP_SPK /* packed FIXP_SGL values */ + #define WTC(a) FX_DBL2FXCONST_SGL(a) +#else /* SINETABLE_16BIT */ + #define FIXP_WTB FIXP_DBL + #define FIXP_WTP FIXP_DPK + #define WTC(a) (FIXP_DBL)(a) +#endif /* SINETABLE_16BIT */ + +#define WTCP(a,b) { { WTC(a), WTC(b) } } + + +#endif /* __ARCH_H__ */ diff --git a/libFDK/include/FDK_bitbuffer.h b/libFDK/include/FDK_bitbuffer.h new file mode 100644 index 0000000..3b6afd7 --- /dev/null +++ b/libFDK/include/FDK_bitbuffer.h @@ -0,0 +1,104 @@ +/*************************** Fraunhofer IIS FDK Tools *********************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Lohwasser + Description: common bitbuffer read/write routines + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef __FDK_BITBUFFER_H__ +#define __FDK_BITBUFFER_H__ + + + +#include "machine_type.h" + +typedef struct +{ + UINT ValidBits; + UINT ReadOffset; + UINT WriteOffset; + UINT BitCnt; + UINT BitNdx; + + UCHAR *Buffer; + UINT bufSize; + UINT bufBits; +} FDK_BITBUF; + +typedef FDK_BITBUF *HANDLE_FDK_BITBUF; + +#ifdef __cplusplus +extern "C" +{ +#endif + +extern const UINT BitMask [32+1]; + +/** The BitBuffer Functions are called straight from FDK_bitstream Interface. + For Functions functional survey look there. +*/ + +void FDK_CreateBitBuffer (HANDLE_FDK_BITBUF *hBitBuffer, UCHAR *pBuffer, UINT bufSize) ; + +void FDK_InitBitBuffer (HANDLE_FDK_BITBUF hBitBuffer, UCHAR *pBuffer, + UINT bufSize, UINT validBits) ; + +void FDK_ResetBitBuffer (HANDLE_FDK_BITBUF hBitBuffer) ; + +void FDK_DeleteBitBuffer (HANDLE_FDK_BITBUF hBitBuffer) ; + +INT FDK_get (HANDLE_FDK_BITBUF hBitBuffer, const UINT numberOfBits) ; + +INT FDK_get32 (HANDLE_FDK_BITBUF hBitBuffer) ; + +void FDK_put (HANDLE_FDK_BITBUF hBitBuffer, UINT value, const UINT numberOfBits) ; + +INT FDK_getBwd (HANDLE_FDK_BITBUF hBitBuffer, const UINT numberOfBits); +void FDK_putBwd (HANDLE_FDK_BITBUF hBitBuffer, UINT value, const UINT numberOfBits) ; + +void FDK_pushBack (HANDLE_FDK_BITBUF hBitBuffer, const UINT numberOfBits, UCHAR config) ; +void FDK_pushForward (HANDLE_FDK_BITBUF hBitBuffer, const UINT numberOfBits, UCHAR config) ; + +void FDK_byteAlign (HANDLE_FDK_BITBUF hBitBuffer, UCHAR config) ; + +UINT FDK_getValidBits (HANDLE_FDK_BITBUF hBitBuffer) ; +INT FDK_getFreeBits (HANDLE_FDK_BITBUF hBitBuffer) ; + +void FDK_setBitCnt (HANDLE_FDK_BITBUF hBitBuffer, const UINT value) ; +INT FDK_getBitCnt (HANDLE_FDK_BITBUF hBitBuffer) ; + +void FDK_Feed (HANDLE_FDK_BITBUF hBitBuffer, UCHAR inputBuffer [], + const UINT bufferSize, UINT *bytesValid) ; + +void FDK_Copy (HANDLE_FDK_BITBUF hBitBufDst, HANDLE_FDK_BITBUF hBitBufSrc, UINT *bytesValid) ; + +void FDK_Fetch (HANDLE_FDK_BITBUF hBitBuffer, UCHAR outBuf[], UINT *writeBytes); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/libFDK/include/FDK_bitstream.h b/libFDK/include/FDK_bitstream.h new file mode 100644 index 0000000..81c4e93 --- /dev/null +++ b/libFDK/include/FDK_bitstream.h @@ -0,0 +1,556 @@ +/*************************** Fraunhofer IIS FDK Tools *********************** + + (C) Copyright Fraunhofer IIS (2009) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Lohwasser + Description: bitstream interface to bitbuffer routines + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef __FDK_BITSTREAM_H__ +#define __FDK_BITSTREAM_H__ + + + +#include "FDK_bitbuffer.h" +#include "machine_type.h" + +#include "genericStds.h" + +#define CACHE_BITS 32 + +typedef enum { + BS_READER, + BS_WRITER +} FDK_BS_CFG; + + +typedef struct +{ + UINT CacheWord ; + UINT BitsInCache ; + FDK_BITBUF hBitBuf; + UINT ConfigCache ; +} FDK_BITSTREAM; + +typedef FDK_BITSTREAM* HANDLE_FDK_BITSTREAM; + +/** + * \brief CreateBitStream Function. + * + * Create and initialize bitstream with extern allocated buffer. + * + * \param pBuffer Pointer to BitBuffer array. + * \param bufSize Length of BitBuffer array. (awaits size 2^n) + * \param config Initialize BitStream as Reader or Writer. + */ +FDK_INLINE +HANDLE_FDK_BITSTREAM FDKcreateBitStream (UCHAR *pBuffer, + UINT bufSize, + FDK_BS_CFG config = BS_READER) +{ + HANDLE_FDK_BITSTREAM hBitStream = (HANDLE_FDK_BITSTREAM) FDKcalloc(1, sizeof(FDK_BITSTREAM)); + FDK_InitBitBuffer(&hBitStream->hBitBuf, pBuffer, bufSize, 0) ; + + /* init cache */ + hBitStream->CacheWord = hBitStream->BitsInCache = 0 ; + hBitStream->ConfigCache = config ; + + return hBitStream ; +} + + +/** + * \brief Initialize BistreamBuffer. BitBuffer can point to filled BitBuffer array . + * + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \param pBuffer Pointer to BitBuffer array. + * \param bufSize Length of BitBuffer array. (awaits size 2^n) + * \param validBits Number of valid BitBuffer filled Bits. + * \param config Initialize BitStream as Reader or Writer. + * \return void + */ +FDK_INLINE +void FDKinitBitStream (HANDLE_FDK_BITSTREAM hBitStream, + UCHAR *pBuffer, + UINT bufSize, + UINT validBits, + FDK_BS_CFG config = BS_READER) +{ + FDK_InitBitBuffer(&hBitStream->hBitBuf, pBuffer, bufSize, validBits) ; + + /* init cache */ + hBitStream->CacheWord = hBitStream->BitsInCache = 0 ; + hBitStream->ConfigCache = config ; +} + + +/** + * \brief ResetBitbuffer Function. Reset states in BitBuffer and Cache. + * + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \param config Initialize BitStream as Reader or Writer. + * \return void + */ +FDK_INLINE void FDKresetBitbuffer( HANDLE_FDK_BITSTREAM hBitStream, FDK_BS_CFG config = BS_READER) +{ + FDK_ResetBitBuffer( &hBitStream->hBitBuf ) ; + + /* init cache */ + hBitStream->CacheWord = hBitStream->BitsInCache = 0 ; + hBitStream->ConfigCache = config ; +} + + +/** DeleteBitStream. + + Deletes the in Create Bitstream allocated BitStream and BitBuffer. +*/ +FDK_INLINE void FDKdeleteBitStream (HANDLE_FDK_BITSTREAM hBitStream) +{ + FDK_DeleteBitBuffer(&hBitStream->hBitBuf) ; + FDKfree(hBitStream) ; +} + + +/** + * \brief ReadBits Function (forward). This function returns a number of sequential + * bits from the input bitstream. + * + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \param numberOfBits The number of bits to be retrieved. + * \return the requested bits, right aligned + * \return + */ +#define OPTIMIZE_FDKREADBITS + +FDK_INLINE UINT FDKreadBits(HANDLE_FDK_BITSTREAM hBitStream, + const UINT numberOfBits) +{ +#ifdef noOPTIMIZE_FDKREADBITS + INT missingBits = numberOfBits - hBitStream->BitsInCache; + if (missingBits > 0) + { + UINT bits = hBitStream->CacheWord << missingBits; + hBitStream->CacheWord = FDK_get32 (&hBitStream->hBitBuf) ; + hBitStream->BitsInCache = CACHE_BITS - missingBits; + return ( bits | (hBitStream->CacheWord >> hBitStream->BitsInCache)) & BitMask[numberOfBits]; + } + + hBitStream->BitsInCache -= numberOfBits; + return ( hBitStream->CacheWord >> hBitStream->BitsInCache) & BitMask[numberOfBits]; + +#else + const UINT validMask = BitMask [numberOfBits] ; + + if (hBitStream->BitsInCache <= numberOfBits) + { + const INT freeBits = (CACHE_BITS-1) - hBitStream->BitsInCache ; + + hBitStream->CacheWord = (hBitStream->CacheWord << freeBits) | FDK_get (&hBitStream->hBitBuf,freeBits) ; + hBitStream->BitsInCache += freeBits ; + } + + hBitStream->BitsInCache -= numberOfBits ; + + return (hBitStream->CacheWord >> hBitStream->BitsInCache) & validMask ; +#endif +} + +FDK_INLINE UINT FDKreadBit(HANDLE_FDK_BITSTREAM hBitStream) +{ +#ifdef OPTIMIZE_FDKREADBITS + if (!hBitStream->BitsInCache) + { + hBitStream->CacheWord = FDK_get32 (&hBitStream->hBitBuf); + hBitStream->BitsInCache = CACHE_BITS; + } + hBitStream->BitsInCache--; + + return (hBitStream->CacheWord >> hBitStream->BitsInCache) & 1; +#else + return FDKreadBits(hBitStream,1); +#endif +} + +/** + * \brief Read2Bits Function (forward). This function 2 sequential + * bits from the input bitstream. It is the optimized version + of FDKreadBits() for readign 2 bits. + * + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \return the requested bits, right aligned + * \return + */ +inline UINT FDKread2Bits(HANDLE_FDK_BITSTREAM hBitStream) +{ + UINT BitsInCache = hBitStream->BitsInCache; + if (BitsInCache < 2) /* Comparison changed from 'less-equal' to 'less' */ + { + const INT freeBits = (CACHE_BITS-1) - BitsInCache ; + + hBitStream->CacheWord = (hBitStream->CacheWord << freeBits) | FDK_get (&hBitStream->hBitBuf,freeBits) ; + BitsInCache += freeBits; + } + hBitStream->BitsInCache = BitsInCache - 2; + return (hBitStream->CacheWord >> hBitStream->BitsInCache) & 0x3; +} + +/** + * \brief ReadBits Function (backward). This function returns a number of sequential bits + * from the input bitstream. + * + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \param numberOfBits The number of bits to be retrieved. + * \return the requested bits, right aligned + */ +FDK_INLINE UINT FDKreadBitsBwd(HANDLE_FDK_BITSTREAM hBitStream, + const UINT numberOfBits) +{ + const UINT validMask = BitMask [numberOfBits] ; + + if (hBitStream->BitsInCache <= numberOfBits) + { + const INT freeBits = (CACHE_BITS-1) - hBitStream->BitsInCache ; + + hBitStream->CacheWord = (hBitStream->CacheWord << freeBits) | FDK_getBwd (&hBitStream->hBitBuf,freeBits) ; + hBitStream->BitsInCache += freeBits ; + } + + hBitStream->BitsInCache -= numberOfBits ; + + return (hBitStream->CacheWord >> hBitStream->BitsInCache) & validMask ; +} + + +/** + * \brief return a number of bits from the bitBuffer. + * You have to know what you do! Cache has to be synchronized before using this + * function. + * + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \param numBits The number of bits to be retrieved. + * \return the requested bits, right aligned + */ +FDK_INLINE UINT FDKgetBits (HANDLE_FDK_BITSTREAM hBitStream, UINT numBits) +{ + return FDK_get (&hBitStream->hBitBuf, numBits) ; +} + + +/** + * \brief WriteBits Function. This function writes numberOfBits of value into bitstream. + * + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \param value Variable holds data to be written. + * \param numberOfBits The number of bits to be written. + * \return number of bits written + */ +FDK_INLINE UCHAR FDKwriteBits(HANDLE_FDK_BITSTREAM hBitStream, UINT value, + const UINT numberOfBits) +{ + const UINT validMask = BitMask [numberOfBits] ; + + if ((hBitStream->BitsInCache+numberOfBits) < CACHE_BITS) + { + hBitStream->BitsInCache += numberOfBits ; + hBitStream->CacheWord = (hBitStream->CacheWord << numberOfBits) | (value & validMask); + } + else + { + FDK_put(&hBitStream->hBitBuf, hBitStream->CacheWord, hBitStream->BitsInCache) ; + hBitStream->BitsInCache = numberOfBits ; + hBitStream->CacheWord = (value & validMask) ; + } + + return numberOfBits; +} + + +/** + * \brief WriteBits Function (backward). This function writes numberOfBits of value into bitstream. + * + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \param value Variable holds data to be written. + * \param numberOfBits The number of bits to be written. + * \return number of bits written + */ +FDK_INLINE UCHAR FDKwriteBitsBwd(HANDLE_FDK_BITSTREAM hBitStream, UINT value, + const UINT numberOfBits) +{ + const UINT validMask = BitMask [numberOfBits] ; + + if ((hBitStream->BitsInCache+numberOfBits) <= CACHE_BITS) + { + hBitStream->BitsInCache += numberOfBits ; + hBitStream->CacheWord = (hBitStream->CacheWord << numberOfBits) | (value & validMask); + } + else + { + FDK_putBwd(&hBitStream->hBitBuf, hBitStream->CacheWord, hBitStream->BitsInCache) ; + hBitStream->BitsInCache = numberOfBits ; + hBitStream->CacheWord = (value & validMask) ; + } + + return numberOfBits; +} + + +/** + * \brief SyncCache Function. Clear cache after read forward. + * + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \return void + */ +FDK_INLINE void FDKsyncCache (HANDLE_FDK_BITSTREAM hBitStream) +{ + if (hBitStream->ConfigCache == BS_READER) + FDK_pushBack (&hBitStream->hBitBuf,hBitStream->BitsInCache,hBitStream->ConfigCache) ; + else /* BS_WRITER */ + FDK_put(&hBitStream->hBitBuf, hBitStream->CacheWord, hBitStream->BitsInCache) ; + + hBitStream->BitsInCache = 0 ; + hBitStream->CacheWord = 0 ; +} + + +/** + * \brief SyncCache Function. Clear cache after read backwards. + * + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \return void + */ +FDK_INLINE void FDKsyncCacheBwd (HANDLE_FDK_BITSTREAM hBitStream) +{ + if (hBitStream->ConfigCache == BS_READER) { + FDK_pushForward (&hBitStream->hBitBuf,hBitStream->BitsInCache,hBitStream->ConfigCache) ; + } else { /* BS_WRITER */ + FDK_putBwd (&hBitStream->hBitBuf, hBitStream->CacheWord, hBitStream->BitsInCache) ; + } + + hBitStream->BitsInCache = 0 ; + hBitStream->CacheWord = 0 ; +} + + +/** + * \brief Byte Alignment Function. + * This function performs the byte_alignment() syntactic function on the input stream, + * i.e. some bits will be discarded/padded so that the next bits to be read/written will + * be aligned on a byte boundary with respect to the bit position 0. + * + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \return void + */ +FDK_INLINE void FDKbyteAlign (HANDLE_FDK_BITSTREAM hBitStream) +{ + FDKsyncCache (hBitStream) ; + FDK_byteAlign (&hBitStream->hBitBuf, (UCHAR)hBitStream->ConfigCache) ; +} + + +/** + * \brief Byte Alignment Function with anchor + * This function performs the byte_alignment() syntactic function on the input stream, + * i.e. some bits will be discarded so that the next bits to be read/written would be aligned + * on a byte boundary with respect to the given alignment anchor. + * + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \param alignmentAnchor bit position to be considered as origin for byte alignment + * \return void + */ +FDK_INLINE void FDKbyteAlign (HANDLE_FDK_BITSTREAM hBitStream, UINT alignmentAnchor) +{ + FDKsyncCache (hBitStream) ; + if (hBitStream->ConfigCache == BS_READER) { + FDK_pushForward (&hBitStream->hBitBuf, + (8 - ((alignmentAnchor - FDK_getValidBits(&hBitStream->hBitBuf)) & 0x07)) & 0x07, + hBitStream->ConfigCache) ; + } + else { + FDK_put (&hBitStream->hBitBuf, + 0, + (8 - ((FDK_getValidBits(&hBitStream->hBitBuf)-alignmentAnchor) & 0x07)) & 0x07 ); + } +} + + +/** + * \brief Push Back(Cache) / For / BiDirectional Function. + * PushBackCache function ungets a number of bits erroneously read/written by the last Get() call. + * NB: The number of bits to be stuffed back into the stream may never exceed the + * number of bits returned by the immediately preceding Get() call. + * + * PushBack function ungets a number of bits (combines cache and bitbuffer indices) + * PushFor function gets a number of bits (combines cache and bitbuffer indices) + * PushBiDirectional gets/ungets number of bits as defined in PusBack/For function + * NB: The sign of bits is not known, so the function checks direction and calls + * appropriate function. (positive sign pushFor, negative sign pushBack ) + * + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \param numberOfBits The number of bits to be pushed back/for. + * \return void + */ +FDK_INLINE void FDKpushBackCache (HANDLE_FDK_BITSTREAM hBitStream, const UINT numberOfBits) +{ + FDK_ASSERT ((hBitStream->BitsInCache+numberOfBits)<=CACHE_BITS); + hBitStream->BitsInCache += numberOfBits ; +} + +FDK_INLINE void FDKpushBack (HANDLE_FDK_BITSTREAM hBitStream, const UINT numberOfBits) +{ + if ((hBitStream->BitsInCache+numberOfBits)ConfigCache == BS_READER) ) { + hBitStream->BitsInCache += numberOfBits ; + FDKsyncCache(hBitStream) ; /* sync cache to avoid invalid cache */ + } + else { + FDKsyncCache(hBitStream) ; + FDK_pushBack(&hBitStream->hBitBuf,numberOfBits,hBitStream->ConfigCache); + } +} + +FDK_INLINE void FDKpushFor (HANDLE_FDK_BITSTREAM hBitStream, const UINT numberOfBits) +{ + if ( (hBitStream->BitsInCache>numberOfBits) && (hBitStream->ConfigCache == BS_READER) ) { + hBitStream->BitsInCache -= numberOfBits; + } + else { + FDKsyncCache(hBitStream) ; + FDK_pushForward(&hBitStream->hBitBuf,numberOfBits,hBitStream->ConfigCache); + } +} + +FDK_INLINE void FDKpushBiDirectional (HANDLE_FDK_BITSTREAM hBitStream, const INT numberOfBits) +{ + if(numberOfBits>=0) FDKpushFor(hBitStream, numberOfBits) ; + else FDKpushBack(hBitStream, -numberOfBits) ; +} + + +/** + * \brief GetValidBits Function. Clear cache and return valid Bits from Bitbuffer. + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \return amount of valid bits that still can be read or were already written. + * + */ +FDK_INLINE UINT FDKgetValidBits (HANDLE_FDK_BITSTREAM hBitStream) +{ + FDKsyncCache(hBitStream) ; + return FDK_getValidBits(&hBitStream->hBitBuf) ; +} + + +/** + * \brief return amount of unused Bits from Bitbuffer. + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \return amount of free bits that still can be written into the bitstream + */ +FDK_INLINE INT FDKgetFreeBits (HANDLE_FDK_BITSTREAM hBitStream) +{ + return FDK_getFreeBits (&hBitStream->hBitBuf) ; +} + +/** + * \brief reset bitcounter in bitBuffer to zero. + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \return void + */ +FDK_INLINE void FDKresetBitCnt (HANDLE_FDK_BITSTREAM hBitStream) +{ + FDKsyncCache (hBitStream) ; + FDK_setBitCnt (&hBitStream->hBitBuf, 0) ; +} + +/** + * \brief set bitcoutner in bitBuffer to given value. + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \param value new value to be assigned to the bit counter + * \return void + */ +FDK_INLINE void FDKsetBitCnt (HANDLE_FDK_BITSTREAM hBitStream, UINT value) +{ + FDKsyncCache (hBitStream) ; + FDK_setBitCnt (&hBitStream->hBitBuf, value) ; +} + +/** + * \brief get bitcounter state from bitBuffer. + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \return current bit counter value + */ +FDK_INLINE INT FDKgetBitCnt (HANDLE_FDK_BITSTREAM hBitStream) +{ + FDKsyncCache(hBitStream) ; + return FDK_getBitCnt(&hBitStream->hBitBuf) ; +} + + +/** + * \brief Fill the BitBuffer with a number of input bytes from external source. + * The bytesValid variable returns the number of ramaining valid bytes in extern inputBuffer. + * + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \param inputBuffer Pointer to input buffer with bitstream data. + * \param bufferSize Total size of inputBuffer array. + * \param bytesValid Input: number of valid bytes in inputBuffer. Output: bytes still left unread in inputBuffer. + * \return void + */ +FDK_INLINE void FDKfeedBuffer (HANDLE_FDK_BITSTREAM hBitStream, const UCHAR inputBuffer [], const UINT bufferSize, UINT *bytesValid) +{ + FDKsyncCache (hBitStream) ; + FDK_Feed(&hBitStream->hBitBuf, (UCHAR*)inputBuffer, bufferSize, bytesValid ) ; +} + + +/** + * \brief fill destination BitBuffer with a number of bytes from source BitBuffer. The + * bytesValid variable returns the number of ramaining valid bytes in source BitBuffer. + * + * \param hBSDst HANDLE_FDK_BITSTREAM handle to write data into + * \param hBSSrc HANDLE_FDK_BITSTREAM handle to read data from + * \param bytesValid Input: number of valid bytes in inputBuffer. Output: bytes still left unread in inputBuffer. + * \return void + */ +FDK_INLINE void FDKcopyBuffer (HANDLE_FDK_BITSTREAM hBSDst, HANDLE_FDK_BITSTREAM hBSSrc, UINT *bytesValid) +{ + FDKsyncCache (hBSSrc) ; + FDK_Copy (&hBSDst->hBitBuf, &hBSSrc->hBitBuf, bytesValid) ; +} + + +/** + * \brief fill the outputBuffer with all valid bytes hold in BitBuffer. The WriteBytes + * variable returns the number of written Bytes. + * + * \param hBitStream HANDLE_FDK_BITSTREAM handle + * \param outputBuffer Pointer to output buffer. + * \param writeBytes Number of bytes write to output buffer. + * \return void + */ +FDK_INLINE void FDKfetchBuffer(HANDLE_FDK_BITSTREAM hBitStream, UCHAR *outputBuffer, UINT *writeBytes) +{ + FDKsyncCache (hBitStream) ; + FDK_Fetch(&hBitStream->hBitBuf, outputBuffer, writeBytes); +} + + +#endif diff --git a/libFDK/include/FDK_core.h b/libFDK/include/FDK_core.h new file mode 100644 index 0000000..ce77882 --- /dev/null +++ b/libFDK/include/FDK_core.h @@ -0,0 +1,47 @@ +/*************************** Fraunhofer IIS FDK Tools *********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: FDK tools versioning support + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef FDK_CORE_H +#define FDK_CORE_H + +#include "FDK_audio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Get FDK_tools library information. + * @return Return 0 on success and a negative errorcode on failure (see errorcodes.h). + */ +int FDK_toolsGetLibInfo(LIB_INFO *info); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libFDK/include/FDK_crc.h b/libFDK/include/FDK_crc.h new file mode 100644 index 0000000..29ae6c5 --- /dev/null +++ b/libFDK/include/FDK_crc.h @@ -0,0 +1,169 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) copyright Fraunhofer-IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: + contents/description: CRC calculation + +******************************************************************************/ + +#ifndef FDK_CRC_H +#define FDK_CRC_H + + + +#include "FDK_bitstream.h" + + +#define MAX_CRC_REGS 3 /*!< Maximal number of overlapping crc region in ADTS channel pair element is two. + Select three independent regions preventively. */ + +/** + * This structure describes single crc region used for crc calculation. + */ +typedef struct +{ + UCHAR isActive; + INT maxBits; + UINT bitBufCntBits; + UINT validBits; + +} CCrcRegData; + +/** + * CRC info structure. + */ +typedef struct +{ + CCrcRegData crcRegData[MAX_CRC_REGS]; /*!< Multiple crc region description. */ + const USHORT *pCrcLookup; /*!< Pointer to lookup table filled in FDK_crcInit(). */ + + USHORT crcPoly; /*!< CRC generator polynom. */ + USHORT crcMask; /*!< CRC mask. */ + USHORT startValue; /*!< CRC start value. */ + UCHAR crcLen; /*!< CRC length. */ + + UINT regStart; /*!< Start region marker for synchronization. */ + UINT regStop; /*!< Stop region marker for synchronization. */ + + USHORT crcValue; /*!< Crc value to be calculated. */ + +} FDK_CRCINFO; + +/** + * CRC info handle. + */ +typedef FDK_CRCINFO* HANDLE_FDK_CRCINFO; + + +/** + * \brief Initialize CRC structure. + * + * The function initializes existing crc info structure with denoted configuration. + * + * \param hCrcInfo Pointer to an outlying allocated crc info structure. + * \param crcPoly Configure crc polynom. + * \param crcStartValue Configure crc start value. + * \param crcLen Configure crc length. + * + * \return none + */ +void FDKcrcInit( + HANDLE_FDK_CRCINFO hCrcInfo, + const UINT crcPoly, + const UINT crcStartValue, + const UINT crcLen + ); + +/** + * \brief Reset CRC info structure. + * + * This function clears all intern states of the crc structure. + * + * \param hCrcInfo Pointer to crc info stucture. + * + * \return none + */ +void FDKcrcReset( + HANDLE_FDK_CRCINFO hCrcInfo + ); + + +/** + * \brief Start CRC region with maximum number of bits. + * + * This function marks position in bitstream to be used as start point for crc calculation. + * Bitstream range for crc calculation can be limited or kept dynamic depending on mBits parameter. + * The crc region has to be terminated with FDKcrcEndReg() in each case. + * + * \param hCrcInfo Pointer to crc info stucture. + * \param hBs Pointer to current bit buffer structure. + * \param mBits Number of bits in crc region to be calculated. + * - mBits > 0: Zero padding will be used for CRC calculation, if there + * are less than mBits bits available. + * - mBits < 0: No zero padding is done. + * - mBits = 0: The number of bits used in crc calculation is dynamically, + * depending on bitstream position between FDKcrcStartReg() and + * FDKcrcEndReg() call. + * + * \return ID for the created region, -1 in case of an error + */ +INT FDKcrcStartReg( + HANDLE_FDK_CRCINFO hCrcInfo, + const HANDLE_FDK_BITSTREAM hBs, + const INT mBits + ); + + +/** + * \brief Ends CRC region. + * + * This function terminates crc region specified with FDKcrcStartReg(). The number of bits in crc region depends + * on mBits parameter of FDKcrcStartReg(). + * This function calculates and updates crc in info structure. + * + * \param hCrcInfo Pointer to crc info stucture. + * \param hBs Pointer to current bit buffer structure. + * \param reg Crc region ID created in FDKcrcStartReg(). + * + * \return 0 on success + */ +INT FDKcrcEndReg( + HANDLE_FDK_CRCINFO hCrcInfo, + const HANDLE_FDK_BITSTREAM hBs, + const INT reg + ); + + +/** + * \brief This function returns crc value from info struct. + * + * \param hCrcInfo Pointer to crc info stucture. + * + * \return CRC value masked with crc length. + */ +USHORT FDKcrcGetCRC( + const HANDLE_FDK_CRCINFO hCrcInfo + ); + + +#endif /* FDK_CRC_H */ diff --git a/libFDK/include/FDK_tools_rom.h b/libFDK/include/FDK_tools_rom.h new file mode 100644 index 0000000..6425e49 --- /dev/null +++ b/libFDK/include/FDK_tools_rom.h @@ -0,0 +1,205 @@ +/*************************** Fraunhofer IIS FDK Tools *********************** + + (C) Copyright Fraunhofer IIS (2008) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Oliver Moser + Description: ROM tables used by FDK tools + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef __FDK_TOOLS_ROM_H__ +#define __FDK_TOOLS_ROM_H__ + +#include "common_fix.h" +#include "FDK_audio.h" + + +/* None radix2 rotation vectors */ +extern const FIXP_STB RotVectorReal60[60]; +extern const FIXP_STB RotVectorImag60[60]; +extern const FIXP_STB RotVectorReal240[240]; +extern const FIXP_STB RotVectorImag240[240]; +extern const FIXP_STB RotVectorReal480[480]; +extern const FIXP_STB RotVectorImag480[480]; + + +/* Regular sine tables */ +extern const FIXP_STP SineTable512[]; +extern const FIXP_STP SineTable480[]; + +/* AAC-LC windows */ +extern const FIXP_WTP SineWindow1024[]; +extern const FIXP_WTP KBDWindow1024[]; +extern const FIXP_WTP SineWindow128[]; +extern const FIXP_WTP KBDWindow128[]; + +extern const FIXP_WTP SineWindow960[]; +extern const FIXP_WTP KBDWindow960[]; +extern const FIXP_WTP SineWindow120[]; +extern const FIXP_WTP KBDWindow120[]; + +/* AAC-LD windows */ +extern const FIXP_WTP SineWindow512[]; +#define LowOverlapWindow512 SineWindow128 +extern const FIXP_WTP SineWindow480[]; +#define LowOverlapWindow480 SineWindow120 + + + +extern const FIXP_WTP SineWindow64[]; +extern const FIXP_WTP SineWindow32[]; + +/** + * \brief Helper table for window slope mapping. You should prefer the usage of the + * function FDKgetWindowSlope(), this table is only made public for some optimized + * access inside dct.cpp. + */ +extern const FIXP_WTP *const windowSlopes[2][3][9]; + +/** + * \brief Window slope access helper. Obtain a window of given length and shape. + * \param length Length of the window slope. + * \param shape Shape index of the window slope. 0: sine window, 1: Kaiser-Bessel. Any other + * value is applied a mask of 1 to, mapping it to either 0 or 1. + * \param Pointer to window slope or NULL if the requested window slope is not available. + */ +const FIXP_WTP * FDKgetWindowSlope(int length, int shape); + +extern const FIXP_WTP sin_twiddle_L64[]; + +/* + * Filter coefficient type definition + */ + +#if defined(ARCH_PREFER_MULT_16x16) || defined(ARCH_PREFER_MULT_32x16) + #define QMF_COEFF_16BIT +#endif + +#define QMF_FILTER_PROTOTYPE_SIZE 640 +#define QMF_NO_POLY 5 + +#ifdef QMF_COEFF_16BIT + #define FIXP_PFT FIXP_SGL + #define FIXP_QTW FIXP_SGL +#else + #define FIXP_PFT FIXP_DBL + #define FIXP_QTW FIXP_DBL +#endif + +#define QMF640_PFT_TABLE_SIZE (640/2 + QMF_NO_POLY) + +extern const FIXP_QTW qmf_phaseshift_cos32[32]; +extern const FIXP_QTW qmf_phaseshift_sin32[32]; +extern const FIXP_QTW qmf_phaseshift_cos64[64]; +extern const FIXP_QTW qmf_phaseshift_sin64[64]; + +extern const FIXP_PFT qmf_64[QMF640_PFT_TABLE_SIZE+QMF_NO_POLY]; + + + + + +#define QMF640_CLDFB_PFT_TABLE_SIZE (640) +#define QMF320_CLDFB_PFT_TABLE_SIZE (320) +#define QMF_CLDFB_PFT_SCALE 1 + +extern const FIXP_QTW qmf_phaseshift_cos32_cldfb[32]; +extern const FIXP_QTW qmf_phaseshift_sin32_cldfb[32]; +extern const FIXP_QTW qmf_phaseshift_cos64_cldfb[64]; +extern const FIXP_QTW qmf_phaseshift_sin64_cldfb[64]; + +extern const FIXP_PFT qmf_cldfb_640[QMF640_CLDFB_PFT_TABLE_SIZE]; +extern const FIXP_PFT qmf_cldfb_320[QMF320_CLDFB_PFT_TABLE_SIZE]; + + + + + +/* + * Raw Data Block list stuff. + */ +typedef enum { + element_instance_tag, + common_window, + global_gain, + ics_info, /* ics_reserved_bit, window_sequence, window_shape, max_sfb, scale_factor_grouping, predictor_data_present, ltp_data_present, ltp_data */ + max_sfb, + ms, /* ms_mask_present, ms_used */ + /*predictor_data_present,*/ /* part of ics_info */ + ltp_data_present, + ltp_data, + section_data, + scale_factor_data, + pulse, /* pulse_data_present, pulse_data */ + tns_data_present, + tns_data, + gain_control_data_present, + gain_control_data, + esc1_hcr, + esc2_rvlc, + spectral_data, + + scale_factor_data_usac, + core_mode, + common_tw, + lpd_channel_stream, + tw_data, + noise, + ac_spectral_data, + fac_data, + tns_active, /* introduced in MPEG-D usac CD */ + tns_data_present_usac, + common_max_sfb, + + + /* Non data list items */ + adtscrc_start_reg1, + adtscrc_start_reg2, + adtscrc_end_reg1, + adtscrc_end_reg2, + drmcrc_start_reg, + drmcrc_end_reg, + next_channel, + next_channel_loop, + link_sequence, + end_of_sequence +} rbd_id_t; + +struct element_list { + const rbd_id_t *id; + const struct element_list *next[2]; +}; + +typedef struct element_list element_list_t; +/** + * \brief get elementary stream pieces list for given parameters. + * \param aot audio object type + * \param epConfig the epConfig value from the current Audio Specific Config + * \param nChannels amount of channels contained in the current element. + * \param layer the layer of the current element. + * \return element_list_t parser guidance structure. + */ +const element_list_t * getBitstreamElementList(AUDIO_OBJECT_TYPE aot, SCHAR epConfig, UCHAR nChannels, UCHAR layer); + + +#endif + diff --git a/libFDK/include/FDK_trigFcts.h b/libFDK/include/FDK_trigFcts.h new file mode 100644 index 0000000..19ab0b8 --- /dev/null +++ b/libFDK/include/FDK_trigFcts.h @@ -0,0 +1,169 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Haricharan Lakshman, Manuel Jander + Description: Trigonometric functions fixed point fractional implementation. + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + + + +#include "common_fix.h" + +#include "FDK_tools_rom.h" + +/* Fixed point precision definitions */ +#define Q(format) ((FIXP_DBL)(((LONG)1) << (format))) + +#ifndef M_PI +#define M_PI (3.14159265358979323846f) +#endif + +/*! + * Inverse tangent function. + */ + +// --- fixp_atan() ---- +#define Q_ATANINP (25) // Input in q25, Output in q30 +#define Q_ATANOUT (30) +#define ATI_SF ((DFRACT_BITS-1)-Q_ATANINP) // 6 +#define ATI_SCALE ((float)(1<> shift; + + residual &= ( (1< (1< (1<<(LD-1))) { + FIXP_STP tmp; + /* Cosine/Sine simetry for angles greater than PI/4 */ + s = (1< (FIXP_DBL)(0)) ? (x) : -(x) ; } +#endif + +#if !defined(FUNCTION_fixabs_I) +inline INT fixabs_I(INT x) { return ((x) > (INT)(0)) ? (x) : -(x) ; } +#endif + +#if !defined(FUNCTION_fixabs_S) +inline FIXP_SGL fixabs_S(FIXP_SGL x) { return ((x) > (FIXP_SGL)(0)) ? (x) : -(x) ; } +#endif + +#endif /* __ABS_H__ */ diff --git a/libFDK/include/arm/clz_arm.h b/libFDK/include/arm/clz_arm.h new file mode 100644 index 0000000..d3c3e04 --- /dev/null +++ b/libFDK/include/arm/clz_arm.h @@ -0,0 +1,59 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: fixed point intrinsics + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#if defined(__arm__) + +#if defined(__GNUC__) && defined(__ARM_ARCH_5TE__) /* cppp replaced: elif */ + /* ARM gcc*/ + + #define FUNCTION_fixnormz_D + #define FUNCTION_fixnorm_D + + inline INT fixnormz_D(LONG value) + { + INT result; + asm("clz %0, %1 ": "=r"(result) : "r"(value) ); + return result; + } + + inline INT fixnorm_D(LONG value) + { + INT result; + if (value < 0) { + value = ~value; + } + if (value == 0) { + return 0; + } + result = fixnormz_D(value); + return result - 1; + } + +#endif /* arm toolchain */ + +#endif /* __arm__ */ + diff --git a/libFDK/include/arm/cplx_mul.h b/libFDK/include/arm/cplx_mul.h new file mode 100644 index 0000000..dba2a9f --- /dev/null +++ b/libFDK/include/arm/cplx_mul.h @@ -0,0 +1,153 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: fixed point intrinsics + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + + +#if defined(__arm__) && defined(__GNUC__) /* cppp replaced: elif */ + +#if defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_6__) + #define FUNCTION_cplxMultDiv2_32x16 + #define FUNCTION_cplxMultDiv2_32x16X2 + //#define FUNCTION_cplxMult_32x16 + //#define FUNCTION_cplxMult_32x16X2 +#endif + +#define FUNCTION_cplxMultDiv2_32x32X2 +//#define FUNCTION_cplxMult_32x32X2 + +#ifdef FUNCTION_cplxMultDiv2_32x16 +inline void cplxMultDiv2( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + const FIXP_DBL a_Re, + const FIXP_DBL a_Im, + const FIXP_SPK wpk ) +{ + LONG tmp1,tmp2; + const LONG w = wpk.w; + + asm("smulwt %0, %3, %4;\n" + "rsb %1,%0,#0;\n" + "smlawb %0, %2, %4, %1;\n" + "smulwt %1, %2, %4;\n" + "smlawb %1, %3, %4, %1;\n" + : "=&r"(tmp1), "=&r"(tmp2) + : "r"(a_Re), "r"(a_Im), "r"(w) + ); + + *c_Re = tmp1; + *c_Im = tmp2; +} +#endif /* FUNCTION_cplxMultDiv2_32x16 */ + +#ifdef FUNCTION_cplxMultDiv2_32x16X2 +inline void cplxMultDiv2( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + const FIXP_DBL a_Re, + const FIXP_DBL a_Im, + const FIXP_SGL b_Re, + const FIXP_SGL b_Im) +{ + LONG tmp1, tmp2; + + asm("smulwb %0, %3, %5;\n" /* %7 = -a_Im * b_Im */ + "rsb %1,%0,#0;\n" + "smlawb %0, %2, %4, %1;\n" /* tmp1 = a_Re * b_Re - a_Im * b_Im */ + "smulwb %1, %2, %5;\n" /* %7 = a_Re * b_Im */ + "smlawb %1, %3, %4, %1;\n" /* tmp2 = a_Im * b_Re + a_Re * b_Im */ + : "=&r"(tmp1), "=&r"(tmp2) + : "r"(a_Re), "r"(a_Im), "r"(b_Re), "r"(b_Im) + ); + + *c_Re = tmp1; + *c_Im = tmp2; +} +#endif /* FUNCTION_cplxMultDiv2_32x16X2 */ + +#ifdef FUNCTION_cplxMultAddDiv2_32x16X2 +inline void cplxMultAddDiv2( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + const FIXP_DBL a_Re, + const FIXP_DBL a_Im, + const FIXP_SGL b_Re, + const FIXP_SGL b_Im) +{ + LONG tmp1, tmp2; + + asm("smulwb %0, %3, %5;\n" + "rsb %1,%0,#0;\n" + "smlawb %0, %2, %4, %1;\n" + "smulwb %1, %2, %5;\n" + "smlawb %1, %3, %4, %1;\n" + : "=&r"(tmp1), "=&r"(tmp2) + : "r"(a_Re), "r"(a_Im), "r"(b_Re), "r"(b_Im) + ); + + *c_Re += tmp1; + *c_Im += tmp2; +} +#endif /* FUNCTION_cplxMultAddDiv2_32x16X2 */ + + +#ifdef FUNCTION_cplxMultDiv2_32x32X2 +inline void cplxMultDiv2( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + const FIXP_DBL a_Re, + const FIXP_DBL a_Im, + const FIXP_DBL b_Re, + const FIXP_DBL b_Im) +{ + LONG tmp1, tmp2; + +#ifdef __ARM_ARCH_6__ + asm( + "smmul %0, %2, %4;\n" /* tmp1 = a_Re * b_Re */ + "smmls %0, %3, %5, %0;\n" /* tmp1 -= a_Im * b_Im */ + "smmul %1, %2, %5;\n" /* tmp2 = a_Re * b_Im */ + "smmla %1, %3, %4, %1;\n" /* tmp2 += a_Im * b_Re */ + : "=&r"(tmp1), "=&r"(tmp2) + : "r"(a_Re), "r"(a_Im), "r"(b_Re), "r"(b_Im) + : "r0" + ); +#else + LONG discard; + asm( + "smull %2, %0, %7, %6;\n" /* tmp1 = -a_Im * b_Im */ + "smlal %2, %0, %3, %5;\n" /* tmp1 += a_Re * b_Re */ + "smull %2, %1, %3, %6;\n" /* tmp2 = a_Re * b_Im */ + "smlal %2, %1, %4, %5;\n" /* tmp2 += a_Im * b_Re */ + : "=&r"(tmp1), "=&r"(tmp2), "=&r"(discard) + : "r"(a_Re), "r"(a_Im), "r"(b_Re), "r"(b_Im), "r"(-a_Im) + ); + #endif + *c_Re = tmp1; + *c_Im = tmp2; +} +#endif /* FUNCTION_cplxMultDiv2_32x32X2 */ + + +#endif + diff --git a/libFDK/include/arm/fixmadd_arm.h b/libFDK/include/arm/fixmadd_arm.h new file mode 100644 index 0000000..15308f7 --- /dev/null +++ b/libFDK/include/arm/fixmadd_arm.h @@ -0,0 +1,97 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: fixed point intrinsics + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#if defined(__arm__) + + /* ############################################################################# */ + #if defined(__GNUC__) && defined(__arm__) && !defined(__SYMBIAN32__) /* cppp replaced: elif */ + /* ############################################################################# */ + /* ARM GNU GCC */ + + #define FUNCTION_fixmadddiv2_DD + + #ifdef __ARM_ARCH_6__ + inline FIXP_DBL fixmadddiv2_DD (FIXP_DBL x, const FIXP_DBL a, const FIXP_DBL b) { + INT result; + asm ("smmla %0, %1, %2, %3;\n" + : "=r" (result) + : "r" (a), "r" (b), "r"(x) ); + return result ; + } + #define FUNCTION_fixmsubdiv2_DD + inline FIXP_DBL fixmsubdiv2_DD (FIXP_DBL x, const FIXP_DBL a, const FIXP_DBL b) { + INT result; + asm ("smmls %0, %1, %2, %3;\n" + : "=r" (result) + : "r" (a), "r" (b), "r"(x) ); + return result ; + } + #else /* __ARM_ARCH_6__ */ + inline FIXP_DBL fixmadddiv2_DD (FIXP_DBL x, const FIXP_DBL a, const FIXP_DBL b) { + INT discard, result = x; + asm ("smlal %0, %1, %2, %3;\n" + : "=r" (discard), "+r" (result) + : "r" (a), "r" (b) ); + return result ; + } + #endif /* __ARM_ARCH_6__ */ + + #if defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_6__) + + #define FUNCTION_fixmadddiv2_DS + + inline FIXP_DBL fixmadddiv2_DS (FIXP_DBL x, const FIXP_DBL a, const FIXP_SGL b) { + INT result; + asm("smlawb %0, %1, %2, %3 " + : "=r" (result) + : "r" (a), "r" (b), "r" (x) ); + return result ; + } + + #endif /* defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_6__) */ + + #define FUNCTION_fixmadddiv2BitExact_DD + #define fixmadddiv2BitExact_DD(a, b, c) fixmadddiv2_DD(a, b, c) + + #define FUNCTION_fixmsubdiv2BitExact_DD + inline FIXP_DBL fixmsubdiv2BitExact_DD (FIXP_DBL x, const FIXP_DBL a, const FIXP_DBL b) { + return x - fixmuldiv2BitExact_DD(a, b); + } + + #define FUNCTION_fixmadddiv2BitExact_DS + #define fixmadddiv2BitExact_DS(a, b, c) fixmadddiv2_DS(a, b, c) + + #define FUNCTION_fixmsubdiv2BitExact_DS + inline FIXP_DBL fixmsubdiv2BitExact_DS (FIXP_DBL x, const FIXP_DBL a, const FIXP_SGL b) { + return x - fixmuldiv2BitExact_DS(a, b); + } + /* ############################################################################# */ + #endif /* toolchain */ + /* ############################################################################# */ + +#endif /* __arm__ */ + diff --git a/libFDK/include/arm/fixmul_arm.h b/libFDK/include/arm/fixmul_arm.h new file mode 100644 index 0000000..8cc448d --- /dev/null +++ b/libFDK/include/arm/fixmul_arm.h @@ -0,0 +1,79 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: fixed point intrinsics + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#if defined(__arm__) + +#if defined(__GNUC__) && defined(__arm__) /* cppp replaced: elif */ +/* ARM with GNU compiler */ + +#define FUNCTION_fixmuldiv2_DD + +#define FUNCTION_fixmuldiv2BitExact_DD +#define fixmuldiv2BitExact_DD(a,b) fixmuldiv2_DD(a,b) +#define FUNCTION_fixmulBitExact_DD +#define fixmulBitExact_DD(a,b) fixmul_DD(a,b) + +#define FUNCTION_fixmuldiv2BitExact_DS +#define fixmuldiv2BitExact_DS(a,b) fixmuldiv2_DS(a,b) + +#define FUNCTION_fixmulBitExact_DS +#define fixmulBitExact_DS(a,b) fixmul_DS(a,b) + +#if defined(__ARM_ARCH_6__) || defined(__TARGET_ARCH_7E_M) +inline INT fixmuldiv2_DD (const INT a, const INT b) +{ + INT result ; + __asm__ ("smmul %0, %1, %2" : "=r" (result) + : "r" (a), "r" (b)) ; + return result ; +} +#else +inline INT fixmuldiv2_DD (const INT a, const INT b) +{ + INT discard, result ; + __asm__ ("smull %0, %1, %2, %3" : "=&r" (discard), "=r" (result) + : "r" (a), "r" (b)) ; + return result ; +} +#endif + +#if defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_6__) +#define FUNCTION_fixmuldiv2_SD +inline INT fixmuldiv2_SD (const SHORT a, const INT b) +{ + INT result ; + __asm__ ("smulwb %0, %1, %2" + : "=r" (result) + : "r" (b), "r" (a)) ; + return result ; +} +#endif + +#endif /* defined(__GNUC__) && defined(__arm__) */ + +#endif /* __arm__ */ + diff --git a/libFDK/include/arm/scale.h b/libFDK/include/arm/scale.h new file mode 100644 index 0000000..11d18fb --- /dev/null +++ b/libFDK/include/arm/scale.h @@ -0,0 +1,90 @@ +/******************************** Fraunhofer IIS *************************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id: + Author(s): + Description: ARM scaling operations + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#if defined(__GNUC__) /* GCC Compiler */ /* cppp replaced: elif */ + +#if defined(__ARM_ARCH_6__) + +inline static INT shiftRightSat(INT src, int scale) +{ + INT result; + asm( + "ssat %0,%2,%0;\n" + + : "=&r"(result) + : "r"(src>>scale), "M"(SAMPLE_BITS) + ); + + return result; +} + + #define SATURATE_INT_PCM_RIGHT_SHIFT(src, scale) shiftRightSat(src, scale) + +inline static INT shiftLeftSat(INT src, int scale) +{ + INT result; + asm( + "ssat %0,%2,%0;\n" + + : "=&r"(result) + : "r"(src<= 0) + *value <<= newscale; + else + *value >>= -newscale; +} + + + #define SATURATE_RIGHT_SHIFT(src, scale, dBits) \ + ( (((LONG)(src) ^ ((LONG)(src) >> (DFRACT_BITS-1)))>>(scale)) > (LONG)(((1U)<<((dBits)-1))-1)) \ + ? ((LONG)(src) >> (DFRACT_BITS-1)) ^ (LONG)(((1U)<<((dBits)-1))-1) \ + : ((LONG)(src) >> (scale)) + + #define SATURATE_LEFT_SHIFT(src, scale, dBits) \ + ( ((LONG)(src) ^ ((LONG)(src) >> (DFRACT_BITS-1))) > ((LONG)(((1U)<<((dBits)-1))-1) >> (scale)) ) \ + ? ((LONG)(src) >> (DFRACT_BITS-1)) ^ (LONG)(((1U)<<((dBits)-1))-1) \ + : ((LONG)(src) << (scale)) + diff --git a/libFDK/include/arm/scramble.h b/libFDK/include/arm/scramble.h new file mode 100644 index 0000000..9143155 --- /dev/null +++ b/libFDK/include/arm/scramble.h @@ -0,0 +1,98 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: bitreversal of input data + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + + + +#if defined(FUNCTION_scramble) +#if defined(__GNUC__) /* cppp replaced: elif */ + +#define FUNCTION_scramble + +#if defined(__ARM_ARCH_5TE__) +#define USE_LDRD_STRD /* LDRD requires 8 byte data alignment. */ +#endif + +inline void scramble(FIXP_DBL x [], INT n) { + FDK_ASSERT(!(((INT)x)&(ALIGNMENT_DEFAULT-1))); + asm("mov r2, #1;\n" /* r2(m) = 1; */ + "sub r3, %1, #1;\n" /* r3 = n-1; */ + "mov r4, #0;\n" /* r4(j) = 0; */ + +"scramble_m_loop%=:\n" /* { */ + "mov r5, %1;\n" /* r5(k) = 1; */ + +"scramble_k_loop%=:\n" /* { */ + "mov r5, r5, lsr #1;\n" /* k >>= 1; */ + "eor r4, r4, r5;\n" /* j ^=k; */ + "ands r10, r4, r5;\n" /* r10 = r4 & r5; */ + "beq scramble_k_loop%=;\n" /* } while (r10 == 0); */ + + "cmp r4, r2;\n" /* if (r4 < r2) break; */ + "bcc scramble_m_loop_end%=;\n" + +#ifdef USE_LDRD_STRD + "mov r5, r2, lsl #3;\n" /* m(r5) = r2*4*2 */ + "ldrd r10, [%0, r5];\n" /* r10 = x[r5], x7 = x[r5+1] */ + "mov r6, r4, lsl #3;\n" /* j(r6) = r4*4*2 */ + "ldrd r8, [%0, r6];\n" /* r8 = x[r6], r9 = x[r6+1]; */ + "strd r10, [%0, r6];\n" /* x[r6,r6+1] = r10,r11; */ + "strd r8, [%0, r5];\n" /* x[r5,r5+1] = r8,r9; */ +#else + "mov r5, r2, lsl #3;\n" /* m(r5) = r2*4*2 */ + "ldr r10, [%0, r5];\n" + "mov r6, r4, lsl #3;\n" /* j(r6) = r4*4*2 */ + "ldr r11, [%0, r6];\n" + + "str r10, [%0, r6];\n" + "str r11, [%0, r5];\n" + + "add r5, r5, #4;" + "ldr r10, [%0, r5];\n" + "add r6, r6, #4;" + "ldr r11, [%0, r6];\n" + "str r10, [%0, r6];\n" + "str r11, [%0, r5];\n" +#endif +"scramble_m_loop_end%=:\n" + "add r2, r2, #1;\n" /* r2++; */ + "cmp r2, r3;\n" + "bcc scramble_m_loop%=;\n" /* } while (r2(m) < r3(n-1)); */ + : + : "r"(x), "r"(n) +#ifdef USE_LDRD_STRD + : "r2","r3", "r4","r5", "r10","r11", "r8","r9", "r6" ); +#else + : "r2","r3", "r4","r5", "r10","r11", "r6" ); +#endif +} +#else +/* Force C implementation if no assembler version available. */ +#undef FUNCTION_scramble +#endif /* Toolchain selection. */ + +#endif /* defined(FUNCTION_scramble) */ diff --git a/libFDK/include/autocorr2nd.h b/libFDK/include/autocorr2nd.h new file mode 100644 index 0000000..896fc17 --- /dev/null +++ b/libFDK/include/autocorr2nd.h @@ -0,0 +1,66 @@ +/*************************** Fraunhofer IIS FDK Tools *********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Lohwasser + Description: fixed point abs definitions + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef _AUTOCORR_2ND_H +#define _AUTOCORR_2ND_H + + + +#include "common_fix.h" + +typedef struct { + FIXP_DBL r00r; + FIXP_DBL r11r; + FIXP_DBL r22r; + FIXP_DBL r01r; + FIXP_DBL r02r; + FIXP_DBL r12r; + FIXP_DBL r01i; + FIXP_DBL r02i; + FIXP_DBL r12i; + FIXP_DBL det; + int det_scale; +} ACORR_COEFS; + +#define LPC_ORDER 2 + + +INT +autoCorr2nd_real (ACORR_COEFS *ac, /*!< Pointer to autocorrelation coeffs */ + const FIXP_DBL *reBuffer, /*!< Pointer to to real part of spectrum */ + const int len /*!< Number of qmf slots */ + ); +INT +autoCorr2nd_cplx (ACORR_COEFS *ac, /*!< Pointer to autocorrelation coeffs */ + const FIXP_DBL *reBuffer, /*!< Pointer to to real part of spectrum */ + const FIXP_DBL *imBuffer, /*!< Pointer to imag part of spectrum */ + const int len /*!< Number of qmf slots */ + ); + + +#endif /* _AUTOCORR_2ND_H */ diff --git a/libFDK/include/clz.h b/libFDK/include/clz.h new file mode 100644 index 0000000..42c1c53 --- /dev/null +++ b/libFDK/include/clz.h @@ -0,0 +1,127 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Marc Gayer + Description: fixed point intrinsics + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#if !defined(__CLZ_H__) +#define __CLZ_H__ + +#include "FDK_archdef.h" +#include "machine_type.h" + +#if defined(__arm__) +#include "arm/clz_arm.h" + +#elif defined(__mips__) /* cppp replaced: elif */ +#include "mips/clz_mips.h" + +#endif /* all cores */ + + +/************************************************************************* + ************************************************************************* + Software fallbacks for missing functions. +************************************************************************** +**************************************************************************/ + +#if !defined(FUNCTION_fixnormz_S) +#ifdef FUNCTION_fixnormz_D +inline INT fixnormz_S (SHORT a) +{ + return fixnormz_D((INT)(a)); +} +#else +inline INT fixnormz_S (SHORT a) +{ + int leadingBits = 0; + a = ~a; + while(a & 0x8000) { + leadingBits++; + a <<= 1; + } + + return (leadingBits); +} +#endif +#endif + +#if !defined(FUNCTION_fixnormz_D) +inline INT fixnormz_D (LONG a) +{ + INT leadingBits = 0; + a = ~a; + while(a & 0x80000000) { + leadingBits++; + a <<= 1; + } + + return (leadingBits); +} +#endif + + +/***************************************************************************** + + functionname: fixnorm_D + description: Count leading ones or zeros of operand val for dfract/LONG INT values. + Return this value minus 1. Return 0 if operand==0. +*****************************************************************************/ +#if !defined(FUNCTION_fixnorm_S) +#ifdef FUNCTION_fixnorm_D +inline INT fixnorm_S(FIXP_SGL val) +{ + return fixnorm_D((INT)(val)); +} +#else +inline INT fixnorm_S(FIXP_SGL val) +{ + INT leadingBits = 0; + if ( val != (FIXP_SGL)0 ) { + if ( val < (FIXP_SGL)0 ) { + val = ~val; + } + leadingBits = fixnormz_S(val) - 1; + } + return (leadingBits); +} +#endif +#endif + +#if !defined(FUNCTION_fixnorm_D) +inline INT fixnorm_D(FIXP_DBL val) +{ + INT leadingBits = 0; + if ( val != (FIXP_DBL)0 ) { + if ( val < (FIXP_DBL)0 ) { + val = ~val; + } + leadingBits = fixnormz_D(val) - 1; + } + return (leadingBits); +} +#endif + +#endif /* __CLZ_H__ */ diff --git a/libFDK/include/common_fix.h b/libFDK/include/common_fix.h new file mode 100644 index 0000000..c5cbd8a --- /dev/null +++ b/libFDK/include/common_fix.h @@ -0,0 +1,324 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2002) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Lohwasser, M. Gayer + Description: Flexible fixpoint library configuration + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef _COMMON_FIX_H +#define _COMMON_FIX_H + +#include "FDK_archdef.h" +#include "machine_type.h" + +/* ***** Start of former fix.h ****** */ + +/* Configure fractional or integer arithmetic */ + #define FIX_FRACT 0 /* Define this to "1" to use fractional arithmetic simulation in class fract instead of integer arithmetic */ + /* 1 for debug with extra runtime overflow checking. */ + +/* Truncate -1.0 to -1.0 + 1/(D)FRACT_FIX_SCALE */ +//#define FRACT_TRUNC_MINUSONE + +/* Define bit sizes of integer fixpoint fractional data types */ +#define FRACT_BITS 16 /* single precision */ +#define DFRACT_BITS 32 /* double precision */ +#define ACCU_BITS 40 /* double precision plus overflow */ + +/* Fixpoint equivalent type fot PCM audio time domain data. */ +#if defined(SAMPLE_BITS) +#if (SAMPLE_BITS == DFRACT_BITS) + #define FIXP_PCM FIXP_DBL + #define FX_PCM2FX_DBL(x) ((FIXP_DBL)(x)) + #define FX_DBL2FX_PCM(x) ((INT_PCM)(x)) +#elif (SAMPLE_BITS == FRACT_BITS) + #define FIXP_PCM FIXP_SGL + #define FX_PCM2FX_DBL(x) FX_SGL2FX_DBL((FIXP_SGL)(x)) + #define FX_DBL2FX_PCM(x) FX_DBL2FX_SGL(x) +#else + #error SAMPLE_BITS different from FRACT_BITS or DFRACT_BITS not implemented! +#endif +#endif + +/* ****** End of former fix.h ****** */ + +#define SGL_MASK ((1UL<> (DFRACT_BITS-FRACT_BITS-1)) + 1) > (((LONG)1< 0) ) ? \ + (FIXP_SGL)(SHORT)(((LONG)1<<(FRACT_BITS-1))-1):(FIXP_SGL)(SHORT)((((val) >> (DFRACT_BITS-FRACT_BITS-1)) + 1) >> 1) ) + + + +#define shouldBeUnion union /* unions are possible */ + + typedef SHORT FIXP_SGL; + typedef LONG FIXP_DBL; + +/* macros for compile-time conversion of constant float values to fixedpoint */ +#define FL2FXCONST_SPC FL2FXCONST_DBL + +#ifdef FRACT_TRUNC_MINUSONE +#define MINVAL_DBL_CONST MINVAL_DBL+1 +#define MINVAL_SGL_CONST MINVAL_SGL+1 +#else +#define MINVAL_DBL_CONST MINVAL_DBL +#define MINVAL_SGL_CONST MINVAL_SGL +#endif + +#define FL2FXCONST_SGL(val) \ +(FIXP_SGL)( ( (val) >= 0) ? \ +((( (double)(val) * (FRACT_FIX_SCALE) + 0.5 ) >= (double)(MAXVAL_SGL) ) ? (SHORT)(MAXVAL_SGL) : (SHORT)( (double)(val) * (double)(FRACT_FIX_SCALE) + 0.5)) : \ +((( (double)(val) * (FRACT_FIX_SCALE) - 0.5) <= (double)(MINVAL_SGL_CONST) ) ? (SHORT)(MINVAL_SGL_CONST) : (SHORT)( (double)(val) * (double)(FRACT_FIX_SCALE) - 0.5)) ) + +#define FL2FXCONST_DBL(val) \ +(FIXP_DBL)( ( (val) >= 0) ? \ +((( (double)(val) * (DFRACT_FIX_SCALE) + 0.5 ) >= (double)(MAXVAL_DBL) ) ? (LONG)(MAXVAL_DBL) : (LONG)( (double)(val) * (double)(DFRACT_FIX_SCALE) + 0.5)) : \ +((( (double)(val) * (DFRACT_FIX_SCALE) - 0.5) <= (double)(MINVAL_DBL_CONST) ) ? (LONG)(MINVAL_DBL_CONST) : (LONG)( (double)(val) * (double)(DFRACT_FIX_SCALE) - 0.5)) ) + +/* macros for runtime conversion of float values to integer fixedpoint. NO OVERFLOW CHECK!!! */ +#define FL2FX_SPC FL2FX_DBL +#define FL2FX_SGL(val) ( (val)>0.0f ? (SHORT)( (val)*(float)(FRACT_FIX_SCALE)+0.5f ) : (SHORT)( (val)*(float)(FRACT_FIX_SCALE)-0.5f ) ) +#define FL2FX_DBL(val) ( (val)>0.0f ? (LONG)( (val)*(float)(DFRACT_FIX_SCALE)+0.5f ) : (LONG)( (val)*(float)(DFRACT_FIX_SCALE)-0.5f ) ) + +/* macros for runtime conversion of fixedpoint values to other fixedpoint. NO ROUNDING!!! */ +#define FX_ACC2FX_SGL(val) ((FIXP_SGL)((val)>>(ACCU_BITS-FRACT_BITS))) +#define FX_ACC2FX_DBL(val) ((FIXP_DBL)((val)>>(ACCU_BITS-DFRACT_BITS))) +#define FX_SGL2FX_ACC(val) ((FIXP_ACC)((LONG)(val)<<(ACCU_BITS-FRACT_BITS))) +#define FX_SGL2FX_DBL(val) ((FIXP_DBL)((LONG)(val)<<(DFRACT_BITS-FRACT_BITS))) +#define FX_DBL2FX_SGL(val) ((FIXP_SGL)((val)>>(DFRACT_BITS-FRACT_BITS))) + +/* ############################################################# */ + +/* macros for runtime conversion of integer fixedpoint values to float. */ +/* This is just for temporary use and should not be required in a final version! */ + +/* #define FX_DBL2FL(val) ((float)(pow(2.,-31.)*(float)val)) */ /* version #1 */ +#define FX_DBL2FL(val) ((float)((double)(val)/(double)DFRACT_FIX_SCALE)) /* version #2 - identical to class dfract cast from dfract to float */ + +/* ############################################################# */ +#include "fixmul.h" + +FDK_INLINE LONG fMult(SHORT a, SHORT b) { return fixmul_SS(a, b); } +FDK_INLINE LONG fMult(SHORT a, LONG b) { return fixmul_SD(a, b); } +FDK_INLINE LONG fMult(LONG a, SHORT b) { return fixmul_DS(a, b); } +FDK_INLINE LONG fMult(LONG a, LONG b) { return fixmul_DD(a, b); } +FDK_INLINE LONG fPow2(LONG a) { return fixpow2_D(a); } +FDK_INLINE LONG fPow2(SHORT a) { return fixpow2_S(a); } + +FDK_INLINE INT fMultI(LONG a, SHORT b) { return ( (INT)(((1<<(FRACT_BITS-2)) + + fixmuldiv2_DD(a,((INT)b<>(FRACT_BITS-1)) ); } + +FDK_INLINE INT fMultIfloor(LONG a, INT b) { return ( (INT)((1 + + fixmuldiv2_DD(a,(b<> (FRACT_BITS-1)) ); } + +FDK_INLINE INT fMultIceil(LONG a, INT b) { return ( (INT)(((INT)0x7fff + + fixmuldiv2_DD(a,(b<> (FRACT_BITS-1)) ); } + +FDK_INLINE LONG fMultDiv2(SHORT a, SHORT b) { return fixmuldiv2_SS(a, b); } +FDK_INLINE LONG fMultDiv2(SHORT a, LONG b) { return fixmuldiv2_SD(a, b); } +FDK_INLINE LONG fMultDiv2(LONG a, SHORT b) { return fixmuldiv2_DS(a, b); } +FDK_INLINE LONG fMultDiv2(LONG a, LONG b) { return fixmuldiv2_DD(a, b); } +FDK_INLINE LONG fPow2Div2(LONG a) { return fixpow2div2_D(a); } +FDK_INLINE LONG fPow2Div2(SHORT a) { return fixpow2div2_S(a); } + +FDK_INLINE LONG fMultDiv2BitExact(LONG a, LONG b) { return fixmuldiv2BitExact_DD(a, b); } +FDK_INLINE LONG fMultDiv2BitExact(SHORT a, LONG b) { return fixmuldiv2BitExact_SD(a, b); } +FDK_INLINE LONG fMultDiv2BitExact(LONG a, SHORT b) { return fixmuldiv2BitExact_DS(a, b); } +FDK_INLINE LONG fMultBitExact(LONG a, LONG b) { return fixmulBitExact_DD(a, b); } +FDK_INLINE LONG fMultBitExact(SHORT a, LONG b) { return fixmulBitExact_SD(a, b); } +FDK_INLINE LONG fMultBitExact(LONG a, SHORT b) { return fixmulBitExact_DS(a, b); } + +/* ******************************************************************************** */ +#include "abs.h" + +FDK_INLINE FIXP_DBL fAbs(FIXP_DBL x) + { return fixabs_D(x); } +FDK_INLINE FIXP_SGL fAbs(FIXP_SGL x) + { return fixabs_S(x); } + +/* workaround for TI C6x compiler but not for TI ARM9E compiler */ +#if (!defined(__TI_COMPILER_VERSION__) || defined(__TI_TMS470_V5__)) && !defined(__x86_64__) +FDK_INLINE INT fAbs(INT x) + { return fixabs_I(x); } +#endif + +/* ******************************************************************************** */ + +#include "clz.h" + +FDK_INLINE INT fNormz(FIXP_DBL x) + { return fixnormz_D(x); } +FDK_INLINE INT fNormz(FIXP_SGL x) + { return fixnormz_S(x); } +FDK_INLINE INT fNorm(FIXP_DBL x) + { return fixnorm_D(x); } +FDK_INLINE INT fNorm(FIXP_SGL x) + { return fixnorm_S(x); } + + +/* ******************************************************************************** */ +/* ******************************************************************************** */ +/* ******************************************************************************** */ + +#include "clz.h" +#define fixp_abs(x) fAbs(x) +#define fixMin(a,b) fMin(a,b) +#define fixMax(a,b) fMax(a,b) +#define CntLeadingZeros(x) fixnormz_D(x) +#define CountLeadingBits(x) fixnorm_D(x) + +#include "fixmadd.h" + +/* y = (x+0.5*a*b) */ +FDK_INLINE FIXP_DBL fMultAddDiv2(FIXP_DBL x, FIXP_DBL a, FIXP_DBL b) + { return fixmadddiv2_DD(x, a, b); } +FDK_INLINE FIXP_DBL fMultAddDiv2(FIXP_DBL x, FIXP_SGL a, FIXP_DBL b) + { return fixmadddiv2_SD(x, a, b); } +FDK_INLINE FIXP_DBL fMultAddDiv2(FIXP_DBL x, FIXP_DBL a, FIXP_SGL b) + { return fixmadddiv2_DS(x, a, b); } +FDK_INLINE FIXP_DBL fMultAddDiv2(FIXP_DBL x, FIXP_SGL a, FIXP_SGL b) + { return fixmadddiv2_SS(x, a, b); } + +FDK_INLINE FIXP_DBL fPow2AddDiv2(FIXP_DBL x, FIXP_DBL a) + { return fixpadddiv2_D(x, a); } +FDK_INLINE FIXP_DBL fPow2AddDiv2(FIXP_DBL x, FIXP_SGL a) + { return fixpadddiv2_S(x, a); } + + +/* y = 2*(x+0.5*a*b) = (2x+a*b) */ +FDK_INLINE FIXP_DBL fMultAdd(FIXP_DBL x, FIXP_DBL a, FIXP_DBL b) + { return fixmadd_DD(x, a, b); } +inline FIXP_DBL fMultAdd(FIXP_DBL x, FIXP_SGL a, FIXP_DBL b) + { return fixmadd_SD(x, a, b); } +inline FIXP_DBL fMultAdd(FIXP_DBL x, FIXP_DBL a, FIXP_SGL b) + { return fixmadd_DS(x, a, b); } +inline FIXP_DBL fMultAdd(FIXP_DBL x, FIXP_SGL a, FIXP_SGL b) + { return fixmadd_SS(x, a, b); } + +inline FIXP_DBL fPow2Add(FIXP_DBL x, FIXP_DBL a) + { return fixpadd_D(x, a); } +inline FIXP_DBL fPow2Add(FIXP_DBL x, FIXP_SGL a) + { return fixpadd_S(x, a); } + + +/* y = (x-0.5*a*b) */ +inline FIXP_DBL fMultSubDiv2(FIXP_DBL x, FIXP_DBL a, FIXP_DBL b) + { return fixmsubdiv2_DD(x, a, b); } +inline FIXP_DBL fMultSubDiv2(FIXP_DBL x, FIXP_SGL a, FIXP_DBL b) + { return fixmsubdiv2_SD(x, a, b); } +inline FIXP_DBL fMultSubDiv2(FIXP_DBL x, FIXP_DBL a, FIXP_SGL b) + { return fixmsubdiv2_DS(x, a, b); } +inline FIXP_DBL fMultSubDiv2(FIXP_DBL x, FIXP_SGL a, FIXP_SGL b) + { return fixmsubdiv2_SS(x, a, b); } + +/* y = 2*(x-0.5*a*b) = (2*x-a*b) */ +FDK_INLINE FIXP_DBL fMultSub(FIXP_DBL x, FIXP_DBL a, FIXP_DBL b) + { return fixmsub_DD(x, a, b); } +inline FIXP_DBL fMultSub(FIXP_DBL x, FIXP_SGL a, FIXP_DBL b) + { return fixmsub_SD(x, a, b); } +inline FIXP_DBL fMultSub(FIXP_DBL x, FIXP_DBL a, FIXP_SGL b) + { return fixmsub_DS(x, a, b); } +inline FIXP_DBL fMultSub(FIXP_DBL x, FIXP_SGL a, FIXP_SGL b) + { return fixmsub_SS(x, a, b); } + +FDK_INLINE FIXP_DBL fMultAddDiv2BitExact(FIXP_DBL x, FIXP_DBL a, FIXP_DBL b) + { return fixmadddiv2BitExact_DD(x, a, b); } +FDK_INLINE FIXP_DBL fMultAddDiv2BitExact(FIXP_DBL x, FIXP_SGL a, FIXP_DBL b) + { return fixmadddiv2BitExact_SD(x, a, b); } +FDK_INLINE FIXP_DBL fMultAddDiv2BitExact(FIXP_DBL x, FIXP_DBL a, FIXP_SGL b) + { return fixmadddiv2BitExact_DS(x, a, b); } +FDK_INLINE FIXP_DBL fMultSubDiv2BitExact(FIXP_DBL x, FIXP_DBL a, FIXP_DBL b) + { return fixmsubdiv2BitExact_DD(x, a, b); } +FDK_INLINE FIXP_DBL fMultSubDiv2BitExact(FIXP_DBL x, FIXP_SGL a, FIXP_DBL b) + { return fixmsubdiv2BitExact_SD(x, a, b); } +FDK_INLINE FIXP_DBL fMultSubDiv2BitExact(FIXP_DBL x, FIXP_DBL a, FIXP_SGL b) + { return fixmsubdiv2BitExact_DS(x, a, b); } + +#include "fixminmax.h" + +FDK_INLINE FIXP_DBL fMin(FIXP_DBL a, FIXP_DBL b) + { return fixmin_D(a,b); } +FDK_INLINE FIXP_DBL fMax(FIXP_DBL a, FIXP_DBL b) + { return fixmax_D(a,b); } + +FDK_INLINE FIXP_SGL fMin(FIXP_SGL a, FIXP_SGL b) + { return fixmin_S(a,b); } +FDK_INLINE FIXP_SGL fMax(FIXP_SGL a, FIXP_SGL b) + { return fixmax_S(a,b); } + +/* workaround for TI C6x compiler but not for TI ARM9E */ +#if ((!defined(__TI_COMPILER_VERSION__) || defined(__TI_TMS470_V5__)) && !defined(__x86_64__)) || (FIX_FRACT == 1) +FDK_INLINE INT fMax(INT a, INT b) + { return fixmax_I(a,b); } +FDK_INLINE INT fMin(INT a, INT b) + { return fixmin_I(a,b); } +#endif + +inline UINT fMax(UINT a, UINT b) + { return fixmax_UI(a,b); } +inline UINT fMin(UINT a, UINT b) + { return fixmin_UI(a,b); } + +/* Complex data types */ +typedef shouldBeUnion { + /* vector representation for arithmetic */ + struct { + FIXP_SGL re; + FIXP_SGL im; + } v; + /* word representation for memory move */ + LONG w; +} FIXP_SPK; + +typedef shouldBeUnion { + /* vector representation for arithmetic */ + struct { + FIXP_DBL re; + FIXP_DBL im; + } v; + /* word representation for memory move */ + INT64 w; +} FIXP_DPK; + +#include "fixmul.h" +#include "fixmadd.h" +#include "cplx_mul.h" +#include "scale.h" +#include "fixpoint_math.h" + +#endif diff --git a/libFDK/include/cplx_mul.h b/libFDK/include/cplx_mul.h new file mode 100644 index 0000000..42064d4 --- /dev/null +++ b/libFDK/include/cplx_mul.h @@ -0,0 +1,207 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: fixed point intrinsics + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "common_fix.h" + +#if !defined(__CPLX_Mult_H__) +#define __CPLX_Mult_H__ + +#if defined(__CC_ARM) || defined(__arm__) || defined(_M_ARM) /* cppp replaced: elif */ +#include "arm/cplx_mul.h" + +#elif defined(__GNUC__) && defined(__mips__) /* cppp replaced: elif */ +#include "mips/cplx_mul.h" + +#endif /* #if defined all cores: bfin, arm, etc. */ + +/* ############################################################################# */ + +/* Fallback generic implementations */ + +#if !defined(FUNCTION_cplxMultDiv2_32x16X2) +#define FUNCTION_cplxMultDiv2_32x16X2 + +inline void cplxMultDiv2( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + const FIXP_DBL a_Re, + const FIXP_DBL a_Im, + const FIXP_SGL b_Re, + const FIXP_SGL b_Im) +{ + *c_Re = fMultDiv2(a_Re,b_Re) - fMultDiv2(a_Im,b_Im); + *c_Im = fMultDiv2(a_Re,b_Im) + fMultDiv2(a_Im,b_Re); +} +#endif + +#if !defined(FUNCTION_cplxMultDiv2_32x16) +#define FUNCTION_cplxMultDiv2_32x16 + +inline void cplxMultDiv2( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + const FIXP_DBL a_Re, + const FIXP_DBL a_Im, + const FIXP_SPK w ) +{ + cplxMultDiv2(c_Re, c_Im, a_Re, a_Im, w.v.re, w.v.im); +} +#endif + +#if !defined(FUNCTION_cplxMultAddDiv2_32x16X2) +#define FUNCTION_cplxMultAddDiv2_32x16X2 + +inline void cplxMultAddDiv2( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + const FIXP_DBL a_Re, + const FIXP_DBL a_Im, + const FIXP_SGL b_Re, + const FIXP_SGL b_Im) +{ + *c_Re += fMultDiv2(a_Re,b_Re) - fMultDiv2(a_Im,b_Im); + *c_Im += fMultDiv2(a_Re,b_Im) + fMultDiv2(a_Im,b_Re); +} +#endif + +#if !defined(FUNCTION_cplxMultSubDiv2_32x16X2) +#define FUNCTION_cplxMultSubDiv2_32x16X2 + +inline void cplxMultSubDiv2( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + const FIXP_DBL a_Re, + const FIXP_DBL a_Im, + const FIXP_SGL b_Re, + const FIXP_SGL b_Im) +{ + *c_Re -= fMultDiv2(a_Re,b_Re) - fMultDiv2(a_Im,b_Im); + *c_Im -= fMultDiv2(a_Re,b_Im) + fMultDiv2(a_Im,b_Re); +} +#endif + +#if !defined(FUNCTION_cplxMultDiv2_32x32X2) +#define FUNCTION_cplxMultDiv2_32x32X2 + +inline void cplxMultDiv2( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + const FIXP_DBL a_Re, + const FIXP_DBL a_Im, + const FIXP_DBL b_Re, + const FIXP_DBL b_Im) +{ + *c_Re = fMultDiv2(a_Re,b_Re) - fMultDiv2(a_Im,b_Im); + *c_Im = fMultDiv2(a_Re,b_Im) + fMultDiv2(a_Im,b_Re); +} +#endif + +#if !defined(FUNCTION_cplxMultDiv2_32x32) +#define FUNCTION_cplxMultDiv2_32x32 + +inline void cplxMultDiv2( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + const FIXP_DBL a_Re, + const FIXP_DBL a_Im, + const FIXP_DPK w) +{ + cplxMultDiv2(c_Re, c_Im, a_Re, a_Im, w.v.re, w.v.im); +} +#endif + +#if !defined(FUNCTION_cplxMultSubDiv2_32x32X2) +#define FUNCTION_cplxMultSubDiv2_32x32X2 + +inline void cplxMultSubDiv2( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + const FIXP_DBL a_Re, + const FIXP_DBL a_Im, + const FIXP_DBL b_Re, + const FIXP_DBL b_Im) +{ + *c_Re -= fMultDiv2(a_Re,b_Re) - fMultDiv2(a_Im,b_Im); + *c_Im -= fMultDiv2(a_Re,b_Im) + fMultDiv2(a_Im,b_Re); +} +#endif + +/* ############################################################################# */ + +#if !defined(FUNCTION_cplxMult_32x16X2) +#define FUNCTION_cplxMult_32x16X2 + +inline void cplxMult( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + const FIXP_DBL a_Re, + const FIXP_DBL a_Im, + const FIXP_SGL b_Re, + const FIXP_SGL b_Im) +{ + *c_Re = fMult(a_Re,b_Re) - fMult(a_Im,b_Im); + *c_Im = fMult(a_Re,b_Im) + fMult(a_Im,b_Re); +} +#endif + +#if !defined(FUNCTION_cplxMult_32x16) +#define FUNCTION_cplxMult_32x16 + +inline void cplxMult( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + const FIXP_DBL a_Re, + const FIXP_DBL a_Im, + const FIXP_SPK w ) +{ + cplxMult(c_Re, c_Im, a_Re, a_Im, w.v.re, w.v.im); +} +#endif + +#if !defined(FUNCTION_cplxMult_32x32X2) +#define FUNCTION_cplxMult_32x32X2 + +inline void cplxMult( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + const FIXP_DBL a_Re, + const FIXP_DBL a_Im, + const FIXP_DBL b_Re, + const FIXP_DBL b_Im) +{ + *c_Re = fMult(a_Re,b_Re) - fMult(a_Im,b_Im); + *c_Im = fMult(a_Re,b_Im) + fMult(a_Im,b_Re); +} +#endif + +#if !defined(FUNCTION_cplxMult_32x32) +#define FUNCTION_cplxMult_32x32 +inline void cplxMult( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + const FIXP_DBL a_Re, + const FIXP_DBL a_Im, + const FIXP_DPK w) +{ + cplxMult(c_Re, c_Im, a_Re, a_Im, w.v.re, w.v.im); +} +#endif + +/* ############################################################################# */ + +#endif /* __CPLX_Mult_H__ */ + diff --git a/libFDK/include/dct.h b/libFDK/include/dct.h new file mode 100644 index 0000000..3ffacf5 --- /dev/null +++ b/libFDK/include/dct.h @@ -0,0 +1,85 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2009) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: Library functions to calculate standard DCTs. This will most + likely be replaced by hand-optimized functions for the specific + target processor. + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef __dct_H +#define __dct_H + + + +#include "common_fix.h" + +/** + * \brief Calculate DCT type II of given length. The DCT IV is + * calculated by a complex FFT, with some pre and post twiddeling. + * A factor of sqrt(2/(N-1)) is NOT applied. + * \param pDat pointer to input/output data (in place processing). + * \param size size of pDat. + * \param pDat_e pointer to an integer containing the exponent of the data + * referenced by pDat. The exponent is updated accordingly. + */ +void dct_II(FIXP_DBL *pDat, FIXP_DBL *tmp, int size, int *pDat_e); + +/** + * \brief Calculate DCT type III of given length. The DCT IV is + * calculated by a complex FFT, with some pre and post twiddeling. + * Note that the factor 0.5 for the sum term x[0] is 1.0 instead of 0.5. + * A factor of sqrt(2/N) is NOT applied. + * \param pDat pointer to input/output data (in place processing). + * \param size size of pDat. + * \param pDat_e pointer to an integer containing the exponent of the data + * referenced by pDat. The exponent is updated accordingly. + */ +void dct_III(FIXP_DBL *pDat, FIXP_DBL *tmp, int size, int *pDat_e); + +/** + * \brief Calculate DCT type IV of given length. The DCT IV is + * calculated by a complex FFT, with some pre and post twiddeling. + * A factor of sqrt(2/N) is NOT applied. + * \param pDat pointer to input/output data (in place processing). + * \param size size of pDat. + * \param pDat_e pointer to an integer containing the exponent of the data + * referenced by pDat. The exponent is updated accordingly. + */ +void dct_IV(FIXP_DBL *pDat,int size, int *pDat_e); + +/** + * \brief Calculate DST type IV of given length. The DST IV is + * calculated by a complex FFT, with some pre and post twiddeling. + * A factor of sqrt(2/N) is NOT applied. + * \param pDat pointer to input/output data (in place processing). + * \param size size of pDat. + * \param pDat_e pointer to an integer containing the exponent of the data + * referenced by pDat. The exponent is updated accordingly. + */ +void dst_IV(FIXP_DBL *pDat,int size, int *pDat_e); + + + +#endif diff --git a/libFDK/include/fft.h b/libFDK/include/fft.h new file mode 100644 index 0000000..95e7a05 --- /dev/null +++ b/libFDK/include/fft.h @@ -0,0 +1,191 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2001) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl, DSP Solutions + Description: Fix point FFT + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef __FFT_H__ +#define __FFT_H__ + +#include "common_fix.h" + +/** + * \brief Perform an inplace complex valued FFT of length 2^n + * + * \param length Length of the FFT to be calculated. + * \param pInput Input/Output data buffer. The input data must have at least 1 bit scale headroom. + * The values are interleaved, real/imag pairs. + * \param scalefactor Pointer to an INT, which contains the current scale of the input data, + * which is updated according to the FFT scale. + */ +void fft(int length, FIXP_DBL *pInput, INT *scalefactor); + +/** + * \brief Perform an inplace complex valued IFFT of length 2^n + * + * \param length Length of the FFT to be calculated. + * \param pInput Input/Output data buffer. The input data must have at least 1 bit scale headroom. + * The values are interleaved, real/imag pairs. + * \param scalefactor Pointer to an INT, which contains the current scale of the input data, + * which is updated according to the IFFT scale. + */ +void ifft(int length, FIXP_DBL *pInput, INT *scalefactor); + + +/* + * Frequently used and fixed short length FFTs. + */ + +LNK_SECTION_CODE_L1 +static void FORCEINLINE fft_4(FIXP_DBL *x) +{ + FIXP_DBL a00, a10, a20, a30, tmp0, tmp1; + + a00 = (x[0] + x[4])>>1; /* Re A + Re B */ + a10 = (x[2] + x[6])>>1; /* Re C + Re D */ + a20 = (x[1] + x[5])>>1; /* Im A + Im B */ + a30 = (x[3] + x[7])>>1; /* Im C + Im D */ + + x[0] = a00 + a10; /* Re A' = Re A + Re B + Re C + Re D */ + x[1] = a20 + a30; /* Im A' = Im A + Im B + Im C + Im D */ + + tmp0 = a00 - x[4]; /* Re A - Re B */ + tmp1 = a20 - x[5]; /* Im A - Im B */ + + x[4] = a00 - a10; /* Re C' = Re A + Re B - Re C - Re D */ + x[5] = a20 - a30; /* Im C' = Im A + Im B - Im C - Im D */ + + a10 = a10 - x[6]; /* Re C - Re D */ + a30 = a30 - x[7]; /* Im C - Im D */ + + x[2] = tmp0 + a30; /* Re B' = Re A - Re B + Im C - Im D */ + x[6] = tmp0 - a30; /* Re D' = Re A - Re B - Im C + Im D */ + x[3] = tmp1 - a10; /* Im B' = Im A - Im B - Re C + Re D */ + x[7] = tmp1 + a10; /* Im D' = Im A - Im B + Re C - Re D */ +} + +LNK_SECTION_CODE_L1 +static void FORCEINLINE fft_8(FIXP_DBL *x) +{ + #define W_PiFOURTH STC(0x5a82799a) + + FIXP_DBL a00, a10, a20, a30; + FIXP_DBL y[16]; + + a00 = (x[0] + x[8])>>1; + a10 = x[4] + x[12]; + a20 = (x[1] + x[9])>>1; + a30 = x[5] + x[13]; + + y[0] = a00 + (a10>>1); + y[4] = a00 - (a10>>1); + y[1] = a20 + (a30>>1); + y[5] = a20 - (a30>>1); + + a00 = a00 - x[8]; + a10 = (a10>>1) - x[12]; + a20 = a20 - x[9]; + a30 = (a30>>1) - x[13]; + + y[2] = a00 + a30; + y[6] = a00 - a30; + y[3] = a20 - a10; + y[7] = a20 + a10; + + a00 = (x[2] + x[10])>>1; + a10 = x[6] + x[14]; + a20 = (x[3] + x[11])>>1; + a30 = x[7] + x[15]; + + y[8] = a00 + (a10>>1); + y[12] = a00 - (a10>>1); + y[9] = a20 + (a30>>1); + y[13] = a20 - (a30>>1); + + a00 = a00 - x[10]; + a10 = (a10>>1) - x[14]; + a20 = a20 - x[11]; + a30 = (a30>>1) - x[15]; + + y[10] = a00 + a30; + y[14] = a00 - a30; + y[11] = a20 - a10; + y[15] = a20 + a10; + + FIXP_DBL vr, vi, ur, ui; + + ur = y[0]>>1; + ui = y[1]>>1; + vr = y[8]; + vi = y[9]; + x[0] = ur + (vr>>1); + x[1] = ui + (vi>>1); + x[8] = ur - (vr>>1); + x[9] = ui - (vi>>1); + + ur = y[4]>>1; + ui = y[5]>>1; + vi = y[12]; + vr = y[13]; + x[4] = ur + (vr>>1); + x[5] = ui - (vi>>1); + x[12] = ur - (vr>>1); + x[13] = ui + (vi>>1); + + ur = y[10]; + ui = y[11]; + vr = fMultDiv2(ui+ur,W_PiFOURTH); + vi = fMultDiv2(ui-ur,W_PiFOURTH); + ur = y[2]; + ui = y[3]; + x[2] = (ur>>1) + vr; + x[3] = (ui>>1) + vi; + x[10] = (ur>>1) - vr; + x[11] = (ui>>1) - vi; + + ur = y[14]; + ui = y[15]; + vr = fMultDiv2(ui-ur,W_PiFOURTH); + vi = fMultDiv2(ui+ur,W_PiFOURTH); + ur = y[6]; + ui = y[7]; + x[6] = (ur>>1) + vr; + x[7] = (ui>>1) - vi; + x[14] = (ur>>1) - vr; + x[15] = (ui>>1) + vi; +} + +/** + * \brief FFT of fixed length 16 + */ +inline void fft_16(FIXP_DBL *x); + +/** + * \brief FFT of fixed length 32 + */ +inline void fft_32(FIXP_DBL *x); + + +#endif diff --git a/libFDK/include/fft_rad2.h b/libFDK/include/fft_rad2.h new file mode 100644 index 0000000..07efc83 --- /dev/null +++ b/libFDK/include/fft_rad2.h @@ -0,0 +1,72 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2003) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Lohwasser, M. Gayer + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef _FFT_RAD2_H +#define _FFT_RAD2_H + + +#include "common_fix.h" + +/** + * \brief Performe an inplace complex valued FFT of 2^n length + * + * \param x Input/Output data buffer. The input data must have at least 1 bit scale headroom. + * The values are interleaved, real/imag pairs. + * \param ldn log2 of FFT length + * \param trigdata Pointer to a sinetable of a length of at least (2^ldn)/2 sine values. + * \param trigDataSize length of the sinetable "trigdata". + */ +void dit_fft(FIXP_DBL *x, const INT ldn, const FIXP_STP *trigdata, const INT trigDataSize) ; + +/** + * \brief Performe an inplace complex valued inverse FFT of 2^n length + * + * \param x Input/Output data buffer. The input data must have at least 1 bit scale headroom. + * The values are interleaved, real/imag pairs. + * \param ldn log2 of FFT length + * \param trigdata Pointer to a sinetable of a length of at least (2^ldn)/2 sine values. + * \param trigDataSize length of the sinetable "trigdata". + */ +void dit_ifft(FIXP_DBL *x, const INT ldn, const FIXP_STP *trigdata, const INT trigDataSize) ; + +/* Rest of the world. */ + +#define SCALEFACTOR2048 10 +#define SCALEFACTOR1024 9 +#define SCALEFACTOR512 8 +#define SCALEFACTOR256 7 +#define SCALEFACTOR128 6 +#define SCALEFACTOR64 5 +#define SCALEFACTOR32 4 +#define SCALEFACTOR16 3 +#define SCALEFACTOR8 2 +#define SCALEFACTOR4 1 +#define SCALEFACTOR2 1 + +#endif /* _FFT_RAD2_H */ + diff --git a/libFDK/include/fixmadd.h b/libFDK/include/fixmadd.h new file mode 100644 index 0000000..65591a7 --- /dev/null +++ b/libFDK/include/fixmadd.h @@ -0,0 +1,244 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2003) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Lohwasser, M. Gayer + Description: fixed point intrinsics + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#if !defined(__FIXMADD_H__) +#define __FIXMADD_H__ + +#include "FDK_archdef.h" +#include "machine_type.h" +#include "fixmul.h" + +#if defined(__arm__) +#include "arm/fixmadd_arm.h" + +#elif defined(__mips__) /* cppp replaced: elif */ +#include "mips/fixmadd_mips.h" + +#endif /* all cores */ + +/************************************************************************* + ************************************************************************* + Software fallbacks for missing functions. +************************************************************************** +**************************************************************************/ + +/* Divide by two versions. */ + +#if !defined(FUNCTION_fixmadddiv2_DD) +inline FIXP_DBL fixmadddiv2_DD (FIXP_DBL x, const FIXP_DBL a, const FIXP_DBL b) + { return (x + fMultDiv2 (a, b)); } +#endif + +#if !defined(FUNCTION_fixmadddiv2_SD) +inline FIXP_DBL fixmadddiv2_SD (FIXP_DBL x, const FIXP_SGL a, const FIXP_DBL b) { +#ifdef FUNCTION_fixmadddiv2_DS + return fixmadddiv2_DS(x, b, a); +#else + return fixmadddiv2_DD(x, FX_SGL2FX_DBL(a), b); +#endif +} +#endif + +#if !defined(FUNCTION_fixmadddiv2_DS) +inline FIXP_DBL fixmadddiv2_DS (FIXP_DBL x, const FIXP_DBL a, const FIXP_SGL b) { +#ifdef FUNCTION_fixmadddiv2_SD + return fixmadddiv2_SD(x, b, a); +#else + return fixmadddiv2_DD(x, a, FX_SGL2FX_DBL(b)); +#endif +} +#endif + +#if !defined(FUNCTION_fixmadddiv2_SS) +inline FIXP_DBL fixmadddiv2_SS (FIXP_DBL x, const FIXP_SGL a, const FIXP_SGL b) + { return x + fMultDiv2(a,b); } +#endif + +#if !defined(FUNCTION_fixmsubdiv2_DD) +inline FIXP_DBL fixmsubdiv2_DD (FIXP_DBL x, const FIXP_DBL a, const FIXP_DBL b) + { return (x - fMultDiv2 (a, b)); } +#endif + +#if !defined(FUNCTION_fixmsubdiv2_SD) +inline FIXP_DBL fixmsubdiv2_SD (FIXP_DBL x, const FIXP_SGL a, const FIXP_DBL b) { +#ifdef FUNCTION_fixmsubdiv2_DS + return fixmsubdiv2_DS(x, b, a); +#else + return fixmsubdiv2_DD(x, FX_SGL2FX_DBL(a), b); +#endif +} +#endif + +#if !defined(FUNCTION_fixmsubdiv2_DS) +inline FIXP_DBL fixmsubdiv2_DS (FIXP_DBL x, const FIXP_DBL a, const FIXP_SGL b) { +#ifdef FUNCTION_fixmsubdiv2_SD + return fixmsubdiv2_SD(x, b, a); +#else + return fixmsubdiv2_DD(x, a, FX_SGL2FX_DBL(b)); +#endif +} +#endif + +#if !defined(FUNCTION_fixmsubdiv2_SS) +inline FIXP_DBL fixmsubdiv2_SS (FIXP_DBL x, const FIXP_SGL a, const FIXP_SGL b) + { return x - fMultDiv2(a,b); } +#endif + + +#if !defined(FUNCTION_fixmadddiv2BitExact_DD) +#define FUNCTION_fixmadddiv2BitExact_DD +inline FIXP_DBL fixmadddiv2BitExact_DD (FIXP_DBL x, const FIXP_DBL a, const FIXP_DBL b) { + return x + fMultDiv2BitExact(a, b); +} +#endif +#if !defined(FUNCTION_fixmadddiv2BitExact_SD) +#define FUNCTION_fixmadddiv2BitExact_SD +inline FIXP_DBL fixmadddiv2BitExact_SD (FIXP_DBL x, const FIXP_SGL a, const FIXP_DBL b) { +#ifdef FUNCTION_fixmadddiv2BitExact_DS + return fixmadddiv2BitExact_DS(x, b, a); +#else + return x + fMultDiv2BitExact(a, b); +#endif +} +#endif +#if !defined(FUNCTION_fixmadddiv2BitExact_DS) +#define FUNCTION_fixmadddiv2BitExact_DS +inline FIXP_DBL fixmadddiv2BitExact_DS (FIXP_DBL x, const FIXP_DBL a, const FIXP_SGL b) { +#ifdef FUNCTION_fixmadddiv2BitExact_SD + return fixmadddiv2BitExact_SD(x, b, a); +#else + return x + fMultDiv2BitExact(a, b); +#endif +} +#endif + +#if !defined(FUNCTION_fixmsubdiv2BitExact_DD) +#define FUNCTION_fixmsubdiv2BitExact_DD +inline FIXP_DBL fixmsubdiv2BitExact_DD (FIXP_DBL x, const FIXP_DBL a, const FIXP_DBL b) { + return x - fMultDiv2BitExact(a, b); +} +#endif +#if !defined(FUNCTION_fixmsubdiv2BitExact_SD) +#define FUNCTION_fixmsubdiv2BitExact_SD +inline FIXP_DBL fixmsubdiv2BitExact_SD (FIXP_DBL x, const FIXP_SGL a, const FIXP_DBL b) { +#ifdef FUNCTION_fixmsubdiv2BitExact_DS + return fixmsubdiv2BitExact_DS(x, b, a); +#else + return x - fMultDiv2BitExact(a, b); +#endif +} +#endif +#if !defined(FUNCTION_fixmsubdiv2BitExact_DS) +#define FUNCTION_fixmsubdiv2BitExact_DS +inline FIXP_DBL fixmsubdiv2BitExact_DS (FIXP_DBL x, const FIXP_DBL a, const FIXP_SGL b) { +#ifdef FUNCTION_fixmsubdiv2BitExact_SD + return fixmsubdiv2BitExact_SD(x, b, a); +#else + return x - fMultDiv2BitExact(a, b); +#endif +} +#endif + +/* Normal versions */ + +#if !defined(FUNCTION_fixmadd_DD) +inline FIXP_DBL fixmadd_DD (FIXP_DBL x, const FIXP_DBL a, const FIXP_DBL b) + { return fixmadddiv2_DD(x,a,b)<<1; } +#endif +#if !defined(FUNCTION_fixmadd_SD) +inline FIXP_DBL fixmadd_SD (FIXP_DBL x, const FIXP_SGL a, const FIXP_DBL b) { +#ifdef FUNCTION_fixmadd_DS + return fixmadd_DS(x, b, a); +#else + return fixmadd_DD(x, FX_SGL2FX_DBL(a), b); +#endif +} +#endif +#if !defined(FUNCTION_fixmadd_DS) +inline FIXP_DBL fixmadd_DS (FIXP_DBL x, const FIXP_DBL a, const FIXP_SGL b) { +#ifdef FUNCTION_fixmadd_SD + return fixmadd_SD(x, b, a); +#else + return fixmadd_DD(x, a, FX_SGL2FX_DBL(b)); +#endif +} +#endif +#if !defined(FUNCTION_fixmadd_SS) +inline FIXP_DBL fixmadd_SS (FIXP_DBL x, const FIXP_SGL a, const FIXP_SGL b) + { return (x + fMultDiv2(a,b))<<1; } +#endif + +#if !defined(FUNCTION_fixmsub_DD) +inline FIXP_DBL fixmsub_DD (FIXP_DBL x, const FIXP_DBL a, const FIXP_DBL b) + { return fixmsubdiv2_DD(x,a,b)<<1; } +#endif +#if !defined(FUNCTION_fixmsub_SD) +inline FIXP_DBL fixmsub_SD (FIXP_DBL x, const FIXP_SGL a, const FIXP_DBL b) { +#ifdef FUNCTION_fixmsub_DS + return fixmsub_DS(x, b, a); +#else + return fixmsub_DD(x, FX_SGL2FX_DBL(a), b); +#endif +} +#endif +#if !defined(FUNCTION_fixmsub_DS) +inline FIXP_DBL fixmsub_DS (FIXP_DBL x, const FIXP_DBL a, const FIXP_SGL b) { +#ifdef FUNCTION_fixmsub_SD + return fixmsub_SD(x, b, a); +#else + return fixmsub_DD(x, a, FX_SGL2FX_DBL(b)); +#endif +} +#endif +#if !defined(FUNCTION_fixmsub_SS) +inline FIXP_DBL fixmsub_SS (FIXP_DBL x, const FIXP_SGL a, const FIXP_SGL b) + { return (x - fMultDiv2(a,b))<<1; } +#endif + +#if !defined(FUNCTION_fixpow2adddiv2_D) +inline INT fixpadddiv2_D (FIXP_DBL x, const FIXP_DBL a) + { return (x + fPow2Div2(a)); } +#endif +#if !defined(FUNCTION_fixpow2add_D) +inline INT fixpadd_D (FIXP_DBL x, const FIXP_DBL a) + { return (x + fPow2(a)); } +#endif + +#if !defined(FUNCTION_fixpow2adddiv2_S) +inline INT fixpadddiv2_S (FIXP_DBL x, const FIXP_SGL a) + { return (x + fPow2Div2(a)); } +#endif +#if !defined(FUNCTION_fixpow2add_S) +inline INT fixpadd_S (FIXP_DBL x, const FIXP_SGL a) + { return (x + fPow2(a)); } +#endif + + + +#endif // __FIXMADD_H__ + diff --git a/libFDK/include/fixminmax.h b/libFDK/include/fixminmax.h new file mode 100644 index 0000000..5bbd53b --- /dev/null +++ b/libFDK/include/fixminmax.h @@ -0,0 +1,58 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Lohwasser, M. Gayer + Description: min/max inline functions and defines + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef FIXMINMAX__H +#define FIXMINMAX__H + +#include "FDK_archdef.h" +#include "machine_type.h" + +/* Inline Function to determine the smaller/bigger value of two values with same type. */ + + +template inline T fixmin (T a, T b) +{ + return (a < b ? a : b); +} + +template inline T fixmax (T a, T b) +{ + return (a > b ? a : b); +} + +#define fixmax_D(a,b) fixmax(a,b) +#define fixmin_D(a,b) fixmin(a,b) +#define fixmax_S(a,b) fixmax(a,b) +#define fixmin_S(a,b) fixmin(a,b) +#define fixmax_I(a,b) fixmax(a,b) +#define fixmin_I(a,b) fixmin(a,b) +#define fixmax_UI(a,b) fixmax(a,b) +#define fixmin_UI(a,b) fixmin(a,b) + + +#endif diff --git a/libFDK/include/fixmul.h b/libFDK/include/fixmul.h new file mode 100644 index 0000000..f9f35e2 --- /dev/null +++ b/libFDK/include/fixmul.h @@ -0,0 +1,223 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Stefan Gewinner + Description: fixed point multiplication + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#if !defined(__FIXMUL_H__) +#define __FIXMUL_H__ + +#include "FDK_archdef.h" +#include "machine_type.h" + + +#if defined(__arm__) +#include "arm/fixmul_arm.h" + +#elif defined(__mips__) /* cppp replaced: elif */ +#include "mips/fixmul_mips.h" + +#elif defined(__x86__) /* cppp replaced: elif */ +#include "x86/fixmul_x86.h" + +#endif /* all cores */ + +/************************************************************************* + ************************************************************************* + Software fallbacks for missing functions +************************************************************************** +**************************************************************************/ + +#if !defined(FUNCTION_fixmuldiv2_DD) +#define FUNCTION_fixmuldiv2_DD +#if defined(_MSC_VER) || defined(__CC_ARM) || defined(__ANALOG_EXTENSIONS__) || defined(__TI_COMPILER_VERSION__) +#pragma message ("Extremely slow implementation of fixmuldiv2_DD !!") +#else +#warning Extremely slow implementation of fixmuldiv2_DD !! +#endif +inline LONG fixmuldiv2_DD (const LONG a, const LONG b) +{ + return (LONG) ((((INT64)a) * b) >> 32) ; +} +#endif + +#if !defined(FUNCTION_fixmuldiv2BitExact_DD) +#define FUNCTION_fixmuldiv2BitExact_DD +#if defined(_MSC_VER) || defined(__CC_ARM) || defined(__ANALOG_EXTENSIONS__) || defined(__TI_COMPILER_VERSION__) +#pragma message ("Extremely slow implementation of fixmuldiv2BitExact_DD !!") +#else +#warning Extremely slow implementation of fixmuldiv2BitExact_DD !! +#endif +inline LONG fixmuldiv2BitExact_DD (const LONG a, const LONG b) +{ + return (LONG) ((((INT64)a) * b) >> 32) ; +} +#endif + +#if !defined(FUNCTION_fixmul_DD) +#define FUNCTION_fixmul_DD +inline LONG fixmul_DD (const LONG a, const LONG b) + { return fixmuldiv2_DD (a, b) << 1 ; } +#endif + +#if !defined(FUNCTION_fixmulBitExact_DD) +#define FUNCTION_fixmulBitExact_DD +#if defined(_MSC_VER) || defined(__CC_ARM) || defined(__ANALOG_EXTENSIONS__) || defined(__TI_COMPILER_VERSION__) || defined(__XTENSA__) +#pragma message ("Extremely slow implementation of fixmulBitExact_DD !!") +#else +#warning Extremely slow implementation of fixmulBitExact_DD !! +#endif +inline LONG fixmulBitExact_DD (const LONG a, const LONG b) +{ + return ( (LONG) ((((INT64)a) * b) >> 32) ) << 1; +} +#endif + +#if !defined(FUNCTION_fixmuldiv2_SS) +#define FUNCTION_fixmuldiv2_SS +inline LONG fixmuldiv2_SS (const SHORT a, const SHORT b) + { return ((LONG)a*b); } +#endif + +#if !defined(FUNCTION_fixmul_SS) +#define FUNCTION_fixmul_SS +inline LONG fixmul_SS (const SHORT a, const SHORT b) + { return (a*b) <<1; } +#endif + +#if !defined(FUNCTION_fixmuldiv2_SD) +#define FUNCTION_fixmuldiv2_SD +inline LONG fixmuldiv2_SD (const SHORT a, const LONG b) +#ifdef FUNCTION_fixmuldiv2_DS + { return fixmuldiv2_DS(b, a); } +#else + { return fixmuldiv2_DD(FX_SGL2FX_DBL(a), b); } +#endif +#endif + +#if !defined(FUNCTION_fixmuldiv2_DS) +#define FUNCTION_fixmuldiv2_DS +inline LONG fixmuldiv2_DS (const LONG a, const SHORT b) +#ifdef FUNCTION_fixmuldiv2_SD + { return fixmuldiv2_SD(b, a); } +#else + { return fixmuldiv2_DD(a, FX_SGL2FX_DBL(b)); } +#endif +#endif + +#if !defined(FUNCTION_fixmuldiv2BitExact_SD) +#define FUNCTION_fixmuldiv2BitExact_SD +inline LONG fixmuldiv2BitExact_SD (const SHORT a, const LONG b) +#ifdef FUNCTION_fixmuldiv2BitExact_DS + { return fixmuldiv2BitExact_DS(b, a); } +#else + { return (LONG) ((((INT64)a) * b) >> 16) ; } +#endif +#endif + +#if !defined(FUNCTION_fixmuldiv2BitExact_DS) +#define FUNCTION_fixmuldiv2BitExact_DS +inline LONG fixmuldiv2BitExact_DS (const LONG a, const SHORT b) +#ifdef FUNCTION_fixmuldiv2BitExact_SD + { return fixmuldiv2BitExact_SD(b, a); } +#else + { return (LONG) ((((INT64)a) * b) >> 16) ; } +#endif +#endif + +#if !defined(FUNCTION_fixmul_SD) +#define FUNCTION_fixmul_SD +inline LONG fixmul_SD (const SHORT a, const LONG b) { +#ifdef FUNCTION_fixmul_DS + return fixmul_SD(b, a); +#else + return fixmuldiv2_SD (a, b) << 1 ; +#endif +} +#endif + +#if !defined(FUNCTION_fixmul_DS) +#define FUNCTION_fixmul_DS +inline LONG fixmul_DS (const LONG a, const SHORT b) { +#ifdef FUNCTION_fixmul_SD + return fixmul_SD(b, a); +#else + return fixmuldiv2_DS(a, b) << 1 ; +#endif +} +#endif + +#if !defined(FUNCTION_fixmulBitExact_SD) +#define FUNCTION_fixmulBitExact_SD +inline LONG fixmulBitExact_SD (const SHORT a, const LONG b) +#ifdef FUNCTION_fixmulBitExact_DS + { return fixmulBitExact_DS(b, a); } +#else + { return (LONG) (((((INT64)a) * b) >> 16) << 1); } +#endif +#endif + +#if !defined(FUNCTION_fixmulBitExact_DS) +#define FUNCTION_fixmulBitExact_DS +inline LONG fixmulBitExact_DS (const LONG a, const SHORT b) +#ifdef FUNCTION_fixmulBitExact_SD + { return fixmulBitExact_SD(b, a); } +#else + { return (LONG) (((((INT64)a) * b) >> 16) << 1); } +#endif +#endif + + +#if !defined(FUNCTION_fixpow2div2_D) +#ifdef ARCH_WA_16BITMULT +#error Fallback for fixpow2div2_D is not 16 bit safe ! +#endif +#define FUNCTION_fixpow2div2_D +inline LONG fixpow2div2_D (const LONG a) + { return fixmuldiv2_DD(a, a); } +#endif + +#if !defined(FUNCTION_fixpow2_D) +#ifdef ARCH_WA_16BITMULT +#error Fallback for fixpow2_D is not 16 bit safe ! +#endif +#define FUNCTION_fixpow2_D +inline LONG fixpow2_D (const LONG a) + { return fixpow2div2_D(a)<<1; } +#endif + +#if !defined(FUNCTION_fixpow2div2_S) +#define FUNCTION_fixpow2div2_S +inline LONG fixpow2div2_S (const SHORT a) + { return fixmuldiv2_SS(a, a); } +#endif + +#if !defined(FUNCTION_fixpow2_S) +#define FUNCTION_fixpow2_S +inline LONG fixpow2_S (const SHORT a) + { return fixpow2div2_S(a)<<1; } +#endif + + +#endif /* __FIXMUL_H__ */ diff --git a/libFDK/include/fixpoint_math.h b/libFDK/include/fixpoint_math.h new file mode 100644 index 0000000..0d0a059 --- /dev/null +++ b/libFDK/include/fixpoint_math.h @@ -0,0 +1,397 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Gayer + Description: Fixed point specific mathematical functions + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef __fixpoint_math_H +#define __fixpoint_math_H + + +#include "common_fix.h" + + +#define LD_DATA_SCALING (64.0f) +#define LD_DATA_SHIFT 6 /* pow(2, LD_DATA_SHIFT) = LD_DATA_SCALING */ +/*#define SIMULATE_MIPS_DIV */ /* schur_div() in C that simulates the inline asm schur_div() on MIPS */ + +/** + * \brief deprecated. Use fLog2() instead. + */ +FIXP_DBL CalcLdData(FIXP_DBL op); + +void LdDataVector(FIXP_DBL *srcVector, FIXP_DBL *destVector, INT number); + +FIXP_DBL CalcInvLdData(FIXP_DBL op); + + +void InitLdInt(); +FIXP_DBL CalcLdInt(INT i); + +extern const USHORT sqrt_tab[49]; + +inline FIXP_DBL sqrtFixp_lookup(FIXP_DBL x) +{ + UINT y = (INT)x; + UCHAR is_zero=(y==0); + INT zeros=fixnormz_D(y) & 0x1e; + y<<=zeros; + UINT idx=(y>>26)-16; + USHORT frac=(y>>10)&0xffff; + USHORT nfrac=0xffff^frac; + UINT t=nfrac*sqrt_tab[idx]+frac*sqrt_tab[idx+1]; + t=t>>(zeros>>1); + return(is_zero ? 0 : t); +} + +inline FIXP_DBL sqrtFixp_lookup(FIXP_DBL x, INT *x_e) +{ + UINT y = (INT)x; + INT e; + + if (x == (FIXP_DBL)0) { + return x; + } + + /* Normalize */ + e=fixnormz_D(y); + y<<=e; + e = *x_e - e + 2; + + /* Correct odd exponent. */ + if (e & 1) { + y >>= 1; + e ++; + } + /* Get square root */ + UINT idx=(y>>26)-16; + USHORT frac=(y>>10)&0xffff; + USHORT nfrac=0xffff^frac; + UINT t=nfrac*sqrt_tab[idx]+frac*sqrt_tab[idx+1]; + + /* Write back exponent */ + *x_e = e >> 1; + return (FIXP_DBL)(LONG)(t>>1); +} + + + +FIXP_DBL sqrtFixp(FIXP_DBL op); + +void InitInvSqrtTab(); + +FIXP_DBL invSqrtNorm2(FIXP_DBL op, INT *shift); + +/***************************************************************************** + + functionname: invFixp + description: delivers 1/(op) + +*****************************************************************************/ +inline FIXP_DBL invFixp(FIXP_DBL op) +{ + INT tmp_exp ; + FIXP_DBL tmp_inv = invSqrtNorm2(op, &tmp_exp) ; + FDK_ASSERT((31-(2*tmp_exp+1))>=0) ; + return ( fPow2Div2( (FIXP_DBL)tmp_inv ) >> (31-(2*tmp_exp+1)) ) ; +} + + + +#if defined(__mips__) && (__GNUC__==2) + +#define FUNCTION_schur_div +inline FIXP_DBL schur_div(FIXP_DBL num,FIXP_DBL denum, INT count) +{ + INT result, tmp ; + __asm__ ("srl %1, %2, 15\n" + "div %3, %1\n" : "=lo" (result) + : "%d" (tmp), "d" (denum) , "d" (num) + : "hi" ) ; + return result<<16 ; +} + +/*###########################################################################################*/ +#elif defined(__mips__) && (__GNUC__==3) + +#define FUNCTION_schur_div +inline FIXP_DBL schur_div(FIXP_DBL num,FIXP_DBL denum, INT count) +{ + INT result, tmp; + + __asm__ ("srl %[tmp], %[denum], 15\n" + "div %[result], %[num], %[tmp]\n" + : [tmp] "+r" (tmp), [result]"=r"(result) + : [denum]"r"(denum), [num]"r"(num) + : "hi", "lo"); + return result << (DFRACT_BITS-16); +} + +/*###########################################################################################*/ +#elif defined(SIMULATE_MIPS_DIV) + +#define FUNCTION_schur_div +inline FIXP_DBL schur_div(FIXP_DBL num, FIXP_DBL denum, INT count) +{ + FDK_ASSERT (count<=DFRACT_BITS-1); + FDK_ASSERT (num>=(FIXP_DBL)0); + FDK_ASSERT (denum>(FIXP_DBL)0); + FDK_ASSERT (num <= denum); + + INT tmp = denum >> (count-1); + INT result = 0; + + while (num > tmp) + { + num -= tmp; + result++; + } + + return result << (DFRACT_BITS-count); +} + +/*###########################################################################################*/ +#endif /* target architecture selector */ + +#if !defined(FUNCTION_schur_div) +/** + * \brief Divide two FIXP_DBL values with given precision. + * \param num dividend + * \param denum divisor + * \param count amount of significant bits of the result (starting to the MSB) + * \return num/divisor + */ +FIXP_DBL schur_div(FIXP_DBL num,FIXP_DBL denum, INT count); +#endif + + + +FIXP_DBL mul_dbl_sgl_rnd (const FIXP_DBL op1, + const FIXP_SGL op2); + +/** + * \brief multiply two values with normalization, thus max precision. + * Author: Robert Weidner + * + * \param f1 first factor + * \param f2 secod factor + * \param result_e pointer to an INT where the exponent of the result is stored into + * \return mantissa of the product f1*f2 + */ +FIXP_DBL fMultNorm( + FIXP_DBL f1, + FIXP_DBL f2, + INT *result_e + ); + +/** + * \brief Divide 2 FIXP_DBL values with normalization of input values. + * \param num numerator + * \param denum denomintator + * \return num/denum with exponent = 0 + */ +FIXP_DBL fDivNorm(FIXP_DBL num, FIXP_DBL denom, INT *result_e); + +/** + * \brief Divide 2 FIXP_DBL values with normalization of input values. + * \param num numerator + * \param denum denomintator + * \param result_e pointer to an INT where the exponent of the result is stored into + * \return num/denum with exponent = *result_e + */ +FIXP_DBL fDivNorm(FIXP_DBL num, FIXP_DBL denom); + +/** + * \brief Divide 2 FIXP_DBL values with normalization of input values. + * \param num numerator + * \param denum denomintator + * \return num/denum with exponent = 0 + */ +FIXP_DBL fDivNormHighPrec(FIXP_DBL L_num, FIXP_DBL L_denum, INT *result_e); + +/** + * \brief Calculate log(argument)/log(2) (logarithm with base 2). deprecated. Use fLog2() instead. + * \param arg mantissa of the argument + * \param arg_e exponent of the argument + * \param result_e pointer to an INT to store the exponent of the result + * \return the mantissa of the result. + * \param + */ +FIXP_DBL CalcLog2(FIXP_DBL arg, INT arg_e, INT *result_e); + +/** + * \brief return 2 ^ (exp * 2^exp_e) + * \param exp_m mantissa of the exponent to 2.0f + * \param exp_e exponent of the exponent to 2.0f + * \param result_e pointer to a INT where the exponent of the result will be stored into + * \return mantissa of the result + */ +FIXP_DBL f2Pow(const FIXP_DBL exp_m, const INT exp_e, INT *result_e); + +/** + * \brief return 2 ^ (exp_m * 2^exp_e). This version returns only the mantissa with implicit exponent of zero. + * \param exp_m mantissa of the exponent to 2.0f + * \param exp_e exponent of the exponent to 2.0f + * \return mantissa of the result + */ +FIXP_DBL f2Pow(const FIXP_DBL exp_m, const INT exp_e); + +/** + * \brief return x ^ (exp * 2^exp_e), where log2(x) = baseLd_m * 2^(baseLd_e). This saves + * the need to compute log2() of constant values (when x is a constant). + * \param ldx_m mantissa of log2() of x. + * \param ldx_e exponent of log2() of x. + * \param exp_m mantissa of the exponent to 2.0f + * \param exp_e exponent of the exponent to 2.0f + * \param result_e pointer to a INT where the exponent of the result will be stored into + * \return mantissa of the result + */ +FIXP_DBL fLdPow( + FIXP_DBL baseLd_m, + INT baseLd_e, + FIXP_DBL exp_m, INT exp_e, + INT *result_e + ); + +/** + * \brief return x ^ (exp * 2^exp_e), where log2(x) = baseLd_m * 2^(baseLd_e). This saves + * the need to compute log2() of constant values (when x is a constant). This version + * does not return an exponent, which is implicitly 0. + * \param ldx_m mantissa of log2() of x. + * \param ldx_e exponent of log2() of x. + * \param exp_m mantissa of the exponent to 2.0f + * \param exp_e exponent of the exponent to 2.0f + * \return mantissa of the result + */ +FIXP_DBL fLdPow( + FIXP_DBL baseLd_m, INT baseLd_e, + FIXP_DBL exp_m, INT exp_e + ); + +/** + * \brief return (base * 2^base_e) ^ (exp * 2^exp_e). Use fLdPow() instead whenever possible. + * \param base_m mantissa of the base. + * \param base_e exponent of the base. + * \param exp_m mantissa of power to be calculated of the base. + * \param exp_e exponent of power to be calculated of the base. + * \param result_e pointer to a INT where the exponent of the result will be stored into. + * \return mantissa of the result. + */ +FIXP_DBL fPow(FIXP_DBL base_m, INT base_e, FIXP_DBL exp_m, INT exp_e, INT *result_e); + +/** + * \brief return (base * 2^base_e) ^ N + * \param base mantissa of the base + * \param base_e exponent of the base + * \param power to be calculated of the base + * \param result_e pointer to a INT where the exponent of the result will be stored into + * \return mantissa of the result + */ +FIXP_DBL fPowInt(FIXP_DBL base_m, INT base_e, INT N, INT *result_e); + +/** + * \brief calculate logarithm of base 2 of x_m * 2^(x_e) + * \param x_m mantissa of the input value. + * \param x_e exponent of the input value. + * \param pointer to an INT where the exponent of the result is returned into. + * \return mantissa of the result. + */ +FIXP_DBL fLog2(FIXP_DBL x_m, INT x_e, INT *result_e); + +/** + * \brief calculate logarithm of base 2 of x_m * 2^(x_e) + * \param x_m mantissa of the input value. + * \param x_e exponent of the input value. + * \return mantissa of the result with implicit exponent of LD_DATA_SHIFT. + */ +FIXP_DBL fLog2(FIXP_DBL x_m, INT x_e); + +/** + * \brief Add with saturation of the result. + * \param a first summand + * \param b second summand + * \return saturated sum of a and b. + */ +inline FIXP_SGL fAddSaturate(const FIXP_SGL a, const FIXP_SGL b) +{ + LONG sum; + + sum = (LONG)(SHORT)a + (LONG)(SHORT)b; + sum = fMax(fMin((INT)sum, (INT)MAXVAL_SGL), (INT)MINVAL_SGL); + return (FIXP_SGL)(SHORT)sum; +} + +/** + * \brief Add with saturation of the result. + * \param a first summand + * \param b second summand + * \return saturated sum of a and b. + */ +inline FIXP_DBL fAddSaturate(const FIXP_DBL a, const FIXP_DBL b) +{ + LONG sum; + + sum = (LONG)(a>>1) + (LONG)(b>>1); + sum = fMax(fMin((INT)sum, (INT)(MAXVAL_DBL>>1)), (INT)(MINVAL_DBL>>1)); + return (FIXP_DBL)(LONG)(sum<<1); +} + +#define TEST_ROUNDING 0 + + +#if TEST_ROUNDING +void checkRound(); +void checkRound2(); +#endif + + +/***************************************************************************** + + array for 1/n, n=1..50 + +****************************************************************************/ + + extern const FIXP_DBL invCount[50]; + + LNK_SECTION_INITCODE + inline void InitInvInt(void) {} + + +/** + * \brief Calculate the value of 1/i where i is a integer value. It supports + * input values from 1 upto 50. + * \param intValue Integer input value. + * \param FIXP_DBL representation of 1/intValue + */ +inline FIXP_DBL GetInvInt(int intValue) +{ + FDK_ASSERT((intValue > 0) && (intValue < 50)); + FDK_ASSERT(intValue<50); + return invCount[intValue]; +} + + +#endif + diff --git a/libFDK/include/mdct.h b/libFDK/include/mdct.h new file mode 100644 index 0000000..f96ea06 --- /dev/null +++ b/libFDK/include/mdct.h @@ -0,0 +1,181 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2011) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander, Josef Hoepfl + Description: MDCT routines + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef __MDCT_H__ +#define __MDCT_H__ + + + +#include "common_fix.h" + +#define MDCT_OUT_HEADROOM 2 /* Output additional headroom */ +#define MDCT_OUTPUT_SCALE (DFRACT_BITS-SAMPLE_BITS-MDCT_OUT_HEADROOM) +/* Refer to "Output word length" in ISO/IEC 14496-3:2008(E) 23.2.3.6 */ +#define MDCT_OUTPUT_GAIN 16 + +#if (SAMPLE_BITS == DFRACT_BITS) +#define IMDCT_SCALE(x) (INT_PCM)SATURATE_LEFT_SHIFT(x, -MDCT_OUTPUT_SCALE, SAMPLE_BITS) +#else +#define IMDCT_SCALE(x) (INT_PCM)SATURATE_RIGHT_SHIFT(x, MDCT_OUTPUT_SCALE, SAMPLE_BITS) +#endif +#define IMDCT_SCALE_DBL(x) (FIXP_DBL)(x) + +/** + * \brief MDCT persistent data + */ +typedef struct { + union { + FIXP_DBL *freq; + FIXP_DBL *time; + } overlap; /**< Pointer to overlap memory */ + + const FIXP_WTP *prev_wrs; /**< pointer to previous right window slope */ + int prev_tl; /**< previous tranform length */ + int prev_nr; /**< previous right window offset */ + int prev_fr; /**< previous right window slope length */ + int ov_offset; /**< overlap time data fill level */ + int ov_size; /**< Overlap buffer size in words */ + +} mdct_t; + +typedef mdct_t* H_MDCT; + +/** + * \brief Initialize as valid MDCT handle + * + * \param hMdct handle of an allocated MDCT handle. + * \param overlap pointer to FIXP_DBL overlap buffer. + * \param overlapBufferSize size in FIXP_DBLs of the given overlap buffer. + * \return void + */ +void mdct_init( H_MDCT hMdct, + FIXP_DBL *overlap, + INT overlapBufferSize ); + +/** + * \brief perform MDCT transform (time domain to frequency domain) with given parameters. + * + * \param hMdct handle of an allocated MDCT handle. + * \param spectrum pointer to where the resulting MDCT spectrum will be stored into. + * \param scalefactor pointer to the input scale shift value. Updated accordingly on return. + * \param input pointer to input time domain signal + * \param tl transformation length. + * \param nr right window slope offset (amount of window coefficients assumed to be 1.0) + * \param fr right overlap window slope length + * \param wrs pointer to the right side overlap window coefficients. + * \return number of input samples processed. + */ +INT mdct_block( + H_MDCT hMdct, + FIXP_DBL *spectrum, + INT *scalefactor, + INT_PCM *input, + INT tl, + INT nr, + INT fr, + const FIXP_WTB *wrs ); + + +/** + * \brief add/multiply 2/N transform gain and MPEG4 part 3 defined output gain (see definition + * of MDCT_OUTPUT_GAIN) to given mantissa factor and exponent. + * \param pGain pointer to the mantissa of a gain factor to be applied to IMDCT data. + * \param pExponent pointer to the exponent of a gain factor to be applied to IMDCT data. + * \param tl length of the IMDCT where the gain *pGain * (2 ^ *pExponent) will be applied to. + */ +void imdct_gain( + FIXP_DBL *pGain, + int *pExponent, + int tl + ); + +/** + * \brief drain buffered output samples into given buffer. Changes the MDCT state. + */ +INT imdct_drain( + H_MDCT hMdct, + FIXP_DBL * pTimeData, + INT nrSamplesRoom + ); + + +/** + * \brief Copy overlap time domain data to given buffer. Does not change the MDCT state. + * \return number of actually copied samples (ov + nr). + */ +INT imdct_copy_ov_and_nr( + H_MDCT hMdct, + FIXP_DBL * pTimeData, + INT nrSamples + ); + +/** + * \brief Adapt MDCT parameters for non-matching window slopes. + * \param hMdct handle of an allocated MDCT handle. + * \param pfl pointer to left overlap window side length. + * \param pnl pointer to length of the left n part of the window. + * \param tl transform length. + * \param wls pointer to the left side overlap window coefficients. + * \param noOutSamples desired number of output samples. + */ +void imdct_adapt_parameters(H_MDCT hMdct, int *pfl, int *pnl, int tl, const FIXP_WTP *wls, int noOutSamples); + +/** + * \brief perform several inverse MDCT transforms (frequency domain to time domain) with given parameters. + * + * \param hMdct handle of an allocated MDCT handle. + * \param output pointer to where the output time domain signal will be stored into. + * \param stride the stride factor for accessing time domain samples in output. + * \param spectrum pointer to the input MDCT spectra. + * \param scalefactors scale shift values of the input spectrum. + * \param nSpec number of MDCT spectrums. + * \param noOutSamples desired number of output samples. + * \param tl transform length. + * \param wls pointer to the left side overlap window coefficients. + * \param fl left overlap window side length. + * \param wrs pointer to the right side overlap window coefficients of all individual IMDCTs. + * \param fr right overlap window side length of all individual IMDCTs. + * \param gain factor to apply to output samples (if != 0). + * \return number of output samples returned. + */ +INT imdct_block( + H_MDCT hMdct, + FIXP_DBL *output, + FIXP_DBL *spectrum, + const SHORT scalefactor[], + const INT nSpec, + const INT noOutSamples, + const INT tl, + const FIXP_WTP *wls, + INT fl, + const FIXP_WTP *wrs, + const INT fr, + FIXP_DBL gain ); + + +#endif /* __MDCT_H__ */ diff --git a/libFDK/include/mips/abs_mips.h b/libFDK/include/mips/abs_mips.h new file mode 100644 index 0000000..92729c5 --- /dev/null +++ b/libFDK/include/mips/abs_mips.h @@ -0,0 +1,44 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: fixed point intrinsics + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#if defined(__mips__) + +#if defined(__GNUC__) && defined(__mips__) + + #if defined(__mips_dsp) + #define FUNCTION_fixabs_D + #define FUNCTION_fixabs_I + #define FUNCTION_fixabs_S + inline FIXP_DBL fixabs_D(FIXP_DBL x) { return __builtin_mips_absq_s_w(x); } + inline FIXP_SGL fixabs_S(FIXP_SGL x) { return ((x) > (FIXP_SGL)(0)) ? (x) : -(x) ; } + inline INT fixabs_I(INT x) { return __builtin_mips_absq_s_w(x); } + #endif /* __mips_dsp */ + +#endif /* defined(__GNUC__) && defined(__mips__) */ + +#endif /*__mips__ */ + diff --git a/libFDK/include/mips/clz_mips.h b/libFDK/include/mips/clz_mips.h new file mode 100644 index 0000000..23e6949 --- /dev/null +++ b/libFDK/include/mips/clz_mips.h @@ -0,0 +1,55 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: fixed point intrinsics + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#if defined(__mips__) + +#if defined(__mips__) && (__GNUC__==2) && (mips>=32) + + #define FUNCTION_fixnormz_D + inline INT fixnormz_D(LONG value) + { + INT result; + __asm__ ("clz %0,%1" : "=d" (result) : "d" (value)); + + return result; + } + +#elif defined(__mips__) && (__GNUC__==3) && (__mips>=32) + + #define FUNCTION_fixnormz_D + INT inline fixnormz_D(LONG value) + { + INT result; + __asm__ ("clz %[result], %[value]" : [result] "=r" (result) : [value] "r" (value)) ; + + return result; + } + +#endif + +#endif /* __mips__ */ + diff --git a/libFDK/include/mips/cplx_mul.h b/libFDK/include/mips/cplx_mul.h new file mode 100644 index 0000000..f6f46cc --- /dev/null +++ b/libFDK/include/mips/cplx_mul.h @@ -0,0 +1,93 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: fixed point intrinsics + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + + +#if defined(__GNUC__) && defined(__mips__) + + +//#define FUNCTION_cplxMultDiv2_32x16 +//#define FUNCTION_cplxMultDiv2_32x16X2 +#define FUNCTION_cplxMultDiv2_32x32X2 +//#define FUNCTION_cplxMult_32x16 +//#define FUNCTION_cplxMult_32x16X2 +#define FUNCTION_cplxMult_32x32X2 + +#if defined(FUNCTION_cplxMultDiv2_32x32X2) +inline void cplxMultDiv2( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + FIXP_DBL a_Re, + FIXP_DBL a_Im, + FIXP_DBL b_Re, + FIXP_DBL b_Im) +{ + INT result; + + __asm__ ("mult %[a_Re], %[b_Re];\n" + "msub %[a_Im], %[b_Im];\n" + : "=hi"(result) + : [a_Re]"r"(a_Re), [b_Re]"r"(b_Re), [a_Im]"r"(a_Im), [b_Im]"r"(b_Im) + : "lo"); + + *c_Re = result; + + __asm__ ("mult %[a_Re], %[b_Im];\n" + "madd %[a_Im], %[b_Re];\n" + : "=hi"(result) + : [a_Re]"r"(a_Re), [b_Im]"r"(b_Im), [a_Im]"r"(a_Im), [b_Re]"r"(b_Re) + : "lo"); + *c_Im = result; +} +#endif + +#if defined(FUNCTION_cplxMult_32x32X2) +inline void cplxMult( FIXP_DBL *c_Re, + FIXP_DBL *c_Im, + FIXP_DBL a_Re, + FIXP_DBL a_Im, + FIXP_DBL b_Re, + FIXP_DBL b_Im) +{ + INT result; + __asm__ ("mult %[a_Re], %[b_Re];\n" + "msub %[a_Im], %[b_Im];\n" + : "=hi"(result) + : [a_Re]"r"(a_Re), [b_Re]"r"(b_Re), [a_Im]"r"(a_Im), [b_Im]"r"(b_Im) + : "lo"); + *c_Re = result<<1; + + __asm__ ("mult %[a_Re], %[b_Im];\n" + "madd %[a_Im], %[b_Re];\n" + : "=hi"(result) + : [a_Re]"r"(a_Re), [b_Im]"r"(b_Im), [a_Im]"r"(a_Im), [b_Re]"r"(b_Re) + : "lo"); + *c_Im = result<<1; +} +#endif + +#endif /* defined(__GNUC__) && defined(__mips__) */ + diff --git a/libFDK/include/mips/fixmadd_mips.h b/libFDK/include/mips/fixmadd_mips.h new file mode 100644 index 0000000..4d075ad --- /dev/null +++ b/libFDK/include/mips/fixmadd_mips.h @@ -0,0 +1,32 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: fixed point intrinsics + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#if defined(__mips__) + + +#endif /* __mips__ */ + diff --git a/libFDK/include/mips/fixmul_mips.h b/libFDK/include/mips/fixmul_mips.h new file mode 100644 index 0000000..067674c --- /dev/null +++ b/libFDK/include/mips/fixmul_mips.h @@ -0,0 +1,53 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: fixed point intrinsics + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#if defined(__mips__) + +#if (__GNUC__) && defined(__mips__) /* cppp replaced: elif */ +/* MIPS GCC based compiler */ + +#define FUNCTION_fixmuldiv2_DD + +#define FUNCTION_fixmuldiv2BitExact_DD +#define fixmuldiv2BitExact_DD(a,b) fixmuldiv2_DD(a,b) + +inline INT fixmuldiv2_DD (const INT a, const INT b) +{ + INT result ; + + asm ("mult %1,%2;\n" + : "=hi" (result) + : "d" (a), "r" (b) + : "lo"); + + return result ; +} + +#endif /* (__GNUC__) && defined(__mips__) */ + +#endif /* __mips__ */ + diff --git a/libFDK/include/mips/scale.h b/libFDK/include/mips/scale.h new file mode 100644 index 0000000..82b1833 --- /dev/null +++ b/libFDK/include/mips/scale.h @@ -0,0 +1,48 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2007) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef MIPS_SCALE_H +#define MIPS_SCALE_H + +#if defined(__mips_dsp) + +/*! +* +* \brief Scale input value by 2^{scale} and saturate output to 2^{dBits-1} +* \return scaled and saturated value +* +* This macro scales src value right or left and applies saturation to (2^dBits)-1 +* maxima output. +*/ +#define SATURATE_RIGHT_SHIFT(src, scale, dBits) \ + (__builtin_mips_shll_s_w((src)>>scale,(DFRACT_BITS-(dBits)))>>(DFRACT_BITS-(dBits))) + + +#endif /*__mips_dsp */ + +#endif /* MIPS_SCALE_H */ diff --git a/libFDK/include/mips/scramble.h b/libFDK/include/mips/scramble.h new file mode 100644 index 0000000..b93031a --- /dev/null +++ b/libFDK/include/mips/scramble.h @@ -0,0 +1,59 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2007) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef MIPS_SCRAMBLE_H +#define MIPS_SCRAMBLE_H + +#define FUNCTION_scramble + +#if defined(FUNCTION_scramble) +inline void scramble(FIXP_DBL *x, INT n) { + INT m,j; + int ldn=1; + do {ldn++;} while((1<> (16-ldn); + + if (j>m) + { + FIXP_DBL tmp; + tmp=x[2*m]; + x[2*m]=x[2*j]; + x[2*j]=tmp; + + tmp=x[2*m+1]; + x[2*m+1]=x[2*j+1]; + x[2*j+1]=tmp; + } + } +} +#endif + +#endif /* MIPS_SCRAMBLE_H */ diff --git a/libFDK/include/qmf.h b/libFDK/include/qmf.h new file mode 100644 index 0000000..89c1061 --- /dev/null +++ b/libFDK/include/qmf.h @@ -0,0 +1,188 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file qmf.h + \brief Complex qmf analysis/synthesis $Revision: 36871 $ + \author Markus Werner + +*/ +#ifndef __QMF_H +#define __QMF_H + + + +#include "common_fix.h" +#include "FDK_tools_rom.h" +#include "dct.h" + +/* + * Filter coefficient type definition + */ +#ifdef QMF_DATA_16BIT +#define FIXP_QMF FIXP_SGL +#define FX_DBL2FX_QMF FX_DBL2FX_SGL +#define FX_QMF2FX_DBL FX_SGL2FX_DBL +#define QFRACT_BITS FRACT_BITS +#else +#define FIXP_QMF FIXP_DBL +#define FX_DBL2FX_QMF +#define FX_QMF2FX_DBL +#define QFRACT_BITS DFRACT_BITS +#endif + +/* ARM neon optimized QMF analysis filter requires 32 bit input. + Implemented for RVCT only, currently disabled. See src/arm/qmf_arm.cpp:45 */ +#define FIXP_QAS FIXP_PCM +#define QAS_BITS SAMPLE_BITS + +#ifdef QMFSYN_STATES_16BIT +#define FIXP_QSS FIXP_SGL +#define QSS_BITS FRACT_BITS +#else +#define FIXP_QSS FIXP_DBL +#define QSS_BITS DFRACT_BITS +#endif + +/* Flags for QMF intialization */ +/* Low Power mode flag */ +#define QMF_FLAG_LP 1 +/* Filter is not symetric. This flag is set internally in the QMF initialization as required. */ +#define QMF_FLAG_NONSYMMETRIC 2 +/* Complex Low Delay Filter Bank (or std symmetric filter bank) */ +#define QMF_FLAG_CLDFB 4 +/* Flag indicating that the states should be kept. */ +#define QMF_FLAG_KEEP_STATES 8 +/* Complex Low Delay Filter Bank used in MPEG Surround Encoder */ +#define QMF_FLAG_MPSLDFB 16 +/* Complex Low Delay Filter Bank used in MPEG Surround Encoder allows a optimized calculation of the modulation in qmfForwardModulationHQ() */ +#define QMF_FLAG_MPSLDFB_OPTIMIZE_MODULATION 32 + + +typedef struct +{ + int lb_scale; /*!< Scale of low band area */ + int ov_lb_scale; /*!< Scale of adjusted overlap low band area */ + int hb_scale; /*!< Scale of high band area */ + int ov_hb_scale; /*!< Scale of adjusted overlap high band area */ +} QMF_SCALE_FACTOR; + +struct QMF_FILTER_BANK +{ + const FIXP_PFT *p_filter; /*!< Pointer to filter coefficients */ + + void *FilterStates; /*!< Pointer to buffer of filter states + FIXP_PCM in analyse and + FIXP_DBL in synthesis filter */ + int FilterSize; /*!< Size of prototype filter. */ + const FIXP_QTW *t_cos; /*!< Modulation tables. */ + const FIXP_QTW *t_sin; + int filterScale; /*!< filter scale */ + + int no_channels; /*!< Total number of channels (subbands) */ + int no_col; /*!< Number of time slots */ + int lsb; /*!< Top of low subbands */ + int usb; /*!< Top of high subbands */ + + int outScalefactor; /*!< Scale factor of output data (syn only) */ + FIXP_DBL outGain; /*!< Gain output data (syn only) (init with 0x80000000 to ignore) */ + + UINT flags; /*!< flags */ + UCHAR p_stride; /*!< Stride Factor of polyphase filters */ + +}; + +typedef struct QMF_FILTER_BANK *HANDLE_QMF_FILTER_BANK; + +void +qmfAnalysisFiltering( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */ + FIXP_QMF **qmfReal, /*!< Pointer to real subband slots */ + FIXP_QMF **qmfImag, /*!< Pointer to imag subband slots */ + QMF_SCALE_FACTOR *scaleFactor, /*!< Scale factors of QMF data */ + const INT_PCM *timeIn, /*!< Time signal */ + const int stride, /*!< Stride factor of audio data */ + FIXP_QMF *pWorkBuffer /*!< pointer to temporal working buffer */ + ); + +void +qmfSynthesisFiltering( HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */ + FIXP_QMF **QmfBufferReal, /*!< Pointer to real subband slots */ + FIXP_QMF **QmfBufferImag, /*!< Pointer to imag subband slots */ + const QMF_SCALE_FACTOR *scaleFactor, /*!< Scale factors of QMF data */ + const int ov_len, /*!< Length of band overlap */ + INT_PCM *timeOut, /*!< Time signal */ + const int stride, /*!< Stride factor of audio data */ + FIXP_QMF *pWorkBuffer /*!< pointer to temporal working buffer */ + ); + +int +qmfInitAnalysisFilterBank( HANDLE_QMF_FILTER_BANK h_Qmf, /*!< QMF Handle */ + FIXP_QAS *pFilterStates, /*!< Pointer to filter state buffer */ + int noCols, /*!< Number of time slots */ + int lsb, /*!< Number of lower bands */ + int usb, /*!< Number of upper bands */ + int no_channels, /*!< Number of critically sampled bands */ + int flags); /*!< Flags */ + +void +qmfAnalysisFilteringSlot( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank */ + FIXP_QMF *qmfReal, /*!< Low and High band, real */ + FIXP_QMF *qmfImag, /*!< Low and High band, imag */ + const INT_PCM *timeIn, /*!< Pointer to input */ + const int stride, /*!< stride factor of input */ + FIXP_QMF *pWorkBuffer /*!< pointer to temporal working buffer */ + ); + +int +qmfInitSynthesisFilterBank( HANDLE_QMF_FILTER_BANK h_Qmf, /*!< QMF Handle */ + FIXP_QSS *pFilterStates, /*!< Pointer to filter state buffer */ + int noCols, /*!< Number of time slots */ + int lsb, /*!< Number of lower bands */ + int usb, /*!< Number of upper bands */ + int no_channels, /*!< Number of critically sampled bands */ + int flags); /*!< Flags */ + +void qmfSynthesisFilteringSlot( HANDLE_QMF_FILTER_BANK synQmf, + const FIXP_QMF *realSlot, + const FIXP_QMF *imagSlot, + const int scaleFactorLowBand, + const int scaleFactorHighBand, + INT_PCM *timeOut, + const int stride, + FIXP_QMF *pWorkBuffer); + +void +qmfChangeOutScalefactor (HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */ + int outScalefactor /*!< New scaling factor for output data */ + ); + +void +qmfChangeOutGain (HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */ + FIXP_DBL outputGain /*!< New gain for output data */ + ); + + + +#endif /* __QMF_H */ diff --git a/libFDK/include/scale.h b/libFDK/include/scale.h new file mode 100644 index 0000000..72e7f03 --- /dev/null +++ b/libFDK/include/scale.h @@ -0,0 +1,180 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: Scaling operations + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef SCALE_H +#define SCALE_H + +#include "common_fix.h" +#include "genericStds.h" +#include "fixminmax.h" + + #define SCALE_INLINE inline + + +#if defined(__arm__) /* cppp replaced: elif */ +#include "arm/scale.h" + +#elif defined(__mips__) /* cppp replaced: elif */ +#include "mips/scale.h" + +#endif + + +#include "../src/scale.cpp" + +#ifndef FUNCTION_scaleValue +/*! + * + * \brief Multiply input by \f$ 2^{scalefactor} \f$ + * + * \return Scaled input + * + */ +#define FUNCTION_scaleValue +inline +FIXP_DBL scaleValue(const FIXP_DBL value, /*!< Value */ + INT scalefactor /*!< Scalefactor */ + ) +{ + if(scalefactor > 0) + return (value<>(-scalefactor)); +} +#endif + +#ifndef FUNCTION_scaleValueSaturate +/*! + * + * \brief Multiply input by \f$ 2^{scalefactor} \f$ + * \param value The value to be scaled. + * \param the shift amount + * \return \f$ value * 2^scalefactor \f$ + * + */ +#define FUNCTION_scaleValueSaturate +inline +FIXP_DBL scaleValueSaturate( + const FIXP_DBL value, + INT scalefactor + ) +{ + if(scalefactor > 0) { + if (fNorm(value) < scalefactor && value != (FIXP_DBL)0) { + return (FIXP_DBL)MAXVAL_DBL; + } else { + return (value<>(-scalefactor)); + } +} +#endif + +#ifndef FUNCTION_scaleValueInPlace +/*! + * + * \brief Multiply input by \f$ 2^{scalefactor} \f$ in place + * + * \return void + * + */ +#define FUNCTION_scaleValueInPlace +inline +void scaleValueInPlace( + FIXP_DBL *value, /*!< Value */ + INT scalefactor /*!< Scalefactor */ + ) +{ + INT newscale; + /* Note: The assignment inside the if conditional allows combining a load with the compare to zero (on ARM and maybe others) */ + if ((newscale = (scalefactor)) >= 0) { + *(value) <<= newscale; + } else { + *(value) >>= -newscale; + } +} +#endif + +/*! + * + * \brief Scale input value by 2^{scale} and saturate output to 2^{dBits-1} + * \return scaled and saturated value + * + * This macro scales src value right or left and applies saturation to (2^dBits)-1 + * maxima output. + */ + +#ifndef SATURATE_RIGHT_SHIFT + #define SATURATE_RIGHT_SHIFT(src, scale, dBits) \ + ( (((LONG)(src)>>(scale)) > (LONG)(((1U)<<((dBits)-1))-1)) ? (LONG)(((1U)<<((dBits)-1))-1) \ + : (((LONG)(src)>>(scale)) < ~((LONG)(((1U)<<((dBits)-1))-1))) ? ~((LONG)(((1U)<<((dBits)-1))-1)) \ + : ((LONG)(src) >> (scale)) ) +#endif + +#ifndef SATURATE_LEFT_SHIFT + #define SATURATE_LEFT_SHIFT(src, scale, dBits) \ + ( ((LONG)(src) > ((LONG)(((1U)<<((dBits)-1))-1)>>(scale))) ? (LONG)(((1U)<<((dBits)-1))-1) \ + : ((LONG)(src) < ~((LONG)(((1U)<<((dBits)-1))-1)>>(scale))) ? ~((LONG)(((1U)<<((dBits)-1))-1)) \ + : ((LONG)(src) << (scale)) ) +#endif + +#ifndef SATURATE_SHIFT +#define SATURATE_SHIFT(src, scale, dBits) \ + ( ((scale) < 0) \ + ? SATURATE_LEFT_SHIFT((src), -(scale), (dBits)) \ + : SATURATE_RIGHT_SHIFT((src), (scale), (dBits)) ) +#endif + +/* + * Alternative shift and saturate left, saturates to -0.99999 instead of -1.0000 + * to avoid problems when inverting the sign of the result. + */ +#ifndef SATURATE_LEFT_SHIFT_ALT +#define SATURATE_LEFT_SHIFT_ALT(src, scale, dBits) \ + ( ((LONG)(src) > ((LONG)(((1U)<<((dBits)-1))-1)>>(scale))) ? (LONG)(((1U)<<((dBits)-1))-1) \ + : ((LONG)(src) < ~((LONG)(((1U)<<((dBits)-1))-2)>>(scale))) ? ~((LONG)(((1U)<<((dBits)-1))-2)) \ + : ((LONG)(src) << (scale)) ) +#endif + +#ifndef SATURATE_RIGHT_SHIFT_ALT + #define SATURATE_RIGHT_SHIFT_ALT(src, scale, dBits) \ + ( (((LONG)(src)>>(scale)) > (LONG)(((1U)<<((dBits)-1))-1)) ? (LONG)(((1U)<<((dBits)-1))-1) \ + : (((LONG)(src)>>(scale)) < ~((LONG)(((1U)<<((dBits)-1))-2))) ? ~((LONG)(((1U)<<((dBits)-1))-2)) \ + : ((LONG)(src) >> (scale)) ) +#endif + +#ifndef SATURATE_INT_PCM_RIGHT_SHIFT +#define SATURATE_INT_PCM_RIGHT_SHIFT(src, scale) SATURATE_RIGHT_SHIFT(src, scale, SAMPLE_BITS) +#endif + +#ifndef SATURATE_INT_PCM_LEFT_SHIFT +#define SATURATE_INT_PCM_LEFT_SHIFT(src, scale) SATURATE_LEFT_SHIFT(src, scale, SAMPLE_BITS) +#endif + +#endif /* #ifndef SCALE_H */ diff --git a/libFDK/include/scramble.h b/libFDK/include/scramble.h new file mode 100644 index 0000000..3fc3b56 --- /dev/null +++ b/libFDK/include/scramble.h @@ -0,0 +1,103 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef SCRAMBLE_H +#define SCRAMBLE_H + +#include "common_fix.h" + +#if defined(__arm__) +#include "arm/scramble.h" + +#elif defined(__mips__) && defined(__mips_dsp) /* cppp replaced: elif */ +#include "mips/scramble.h" + +#endif + +/***************************************************************************** + + functionname: scramble + description: bitreversal of input data + returns: + input: + output: + +*****************************************************************************/ +#if !defined(FUNCTION_scramble_sgl) + +inline void scramble_sgl(FIXP_SGL *x, INT n) +{ + INT m,k,j; + + for (m=1,j=0; m>1; (!((j^=k)&k)); k>>=1);} + + if (j>m) + { + FIXP_SGL tmp; + tmp=x[2*m]; + x[2*m]=x[2*j]; + x[2*j]=tmp; + + tmp=x[2*m+1]; + x[2*m+1]=x[2*j+1]; + x[2*j+1]=tmp; + } + } +} +#endif + +#if !defined(FUNCTION_scramble) + +/* default scramble functionality */ +inline void scramble(FIXP_DBL *x, INT n) +{ + INT m,k,j; + FDK_ASSERT(!(((UINT64)x)&(ALIGNMENT_DEFAULT-1))); + + for (m=1,j=0; m>1; (!((j^=k)&k)); k>>=1);} + + if (j>m) + { + FIXP_DBL tmp; + tmp=x[2*m]; + x[2*m]=x[2*j]; + x[2*j]=tmp; + + tmp=x[2*m+1]; + x[2*m+1]=x[2*j+1]; + x[2*j+1]=tmp; + } + } +} +#endif /* !defined(FUNCTION_scramble) */ + +#endif /* SCRAMBLE_H */ diff --git a/libFDK/include/x86/abs_x86.h b/libFDK/include/x86/abs_x86.h new file mode 100644 index 0000000..682bc9f --- /dev/null +++ b/libFDK/include/x86/abs_x86.h @@ -0,0 +1,44 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: fixed point intrinsics + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#if defined(__x86__) + + #if defined(__x86_64__) + + inline INT fixabs_D(INT x) { return ((x) > (INT)(0)) ? (x) : -(x) ; } + inline INT fixabs_S(INT x) { return ((x) > (INT)(0)) ? (x) : -(x) ; } + + #define fixabs_I(x) fixabs_D(x) + + #define FUNCTION_fixabs_S + #define FUNCTION_fixabs_D + #define FUNCTION_fixabs_I + + #endif /* __x86_64__ */ + +#endif /*__x86__ */ + diff --git a/libFDK/include/x86/fixmul_x86.h b/libFDK/include/x86/fixmul_x86.h new file mode 100644 index 0000000..d391b40 --- /dev/null +++ b/libFDK/include/x86/fixmul_x86.h @@ -0,0 +1,115 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: fixed point intrinsics + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#if defined(__x86__) + +#if defined(_MSC_VER) && defined(_M_IX86) +/* Intel x86 */ + +#define FUNCTION_fixmul_DD +#define FUNCTION_fixmuldiv2_DD +#define FUNCTION_fixmuldiv2BitExact_DD +#define fixmuldiv2BitExact_DD(a,b) fixmuldiv2_DD(a,b) +#define FUNCTION_fixmulBitExact_DD +#define fixmulBitExact_DD(a,b) fixmul_DD(a,b) + +#define FUNCTION_fixmuldiv2BitExact_DS +#define fixmuldiv2BitExact_DS(a,b) fixmuldiv2_DS(a,b) + +#define FUNCTION_fixmulBitExact_DS +#define fixmulBitExact_DS(a,b) fixmul_DS(a,b) + +inline INT fixmul_DD (INT a, const INT b) +{ + __asm + { + mov eax, a + imul b + shl edx, 1 + mov a, edx + } + return a ; +} + + +inline INT fixmuldiv2_DD (INT a, const INT b) +{ + __asm + { + mov eax, a + imul b + mov a, edx + } + return a ; +} + +/* ############################################################################# */ +#elif (defined(__GNUC__)||defined(__gnu_linux__)) && defined(__x86__) + +#define FUNCTION_fixmul_DD +#define FUNCTION_fixmuldiv2_DD + +#define FUNCTION_fixmuldiv2BitExact_DD +#define fixmuldiv2BitExact_DD(a,b) fixmuldiv2_DD(a,b) + +#define FUNCTION_fixmulBitExact_DD +#define fixmulBitExact_DD(a,b) fixmul_DD(a,b) + +#define FUNCTION_fixmuldiv2BitExact_DS +#define fixmuldiv2BitExact_DS(a,b) fixmuldiv2_DS(a,b) + +#define FUNCTION_fixmulBitExact_DS +#define fixmulBitExact_DS(a,b) fixmul_DS(a,b) + +inline INT fixmul_DD (INT a, const INT b) +{ + INT result; + + asm( "imul %2;\n" + "shl $1, %0;\n" + : "=d"(result), "+a"(a) + : "r"(b) ); + + return result; +} + + +inline INT fixmuldiv2_DD (INT a, const INT b) +{ + INT result; + + asm ( "imul %2;" + : "=d"(result), "+a"(a) + : "r"(b) ); + + return result; +} + +#endif /* (defined(__GNUC__)||defined(__gnu_linux__)) && defined(__x86__) */ + +#endif /* __x86__ */ + diff --git a/libFDK/src/Android.mk b/libFDK/src/Android.mk new file mode 100644 index 0000000..64553d8 --- /dev/null +++ b/libFDK/src/Android.mk @@ -0,0 +1,30 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + autocorr2nd.cpp \ + dct.cpp \ + FDK_bitbuffer.cpp \ + FDK_core.cpp \ + FDK_crc.cpp \ + FDK_tools_rom.cpp \ + FDK_trigFcts.cpp \ + fft.cpp \ + fft_rad2.cpp \ + fixpoint_math.cpp \ + mdct.cpp \ + qmf.cpp \ + scale.cpp + +LOCAL_CFLAGS := -DANDROID + +LOCAL_CFLAGS += -Wno-sequence-point -Wno-extra + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../../libSYS/include \ + +LOCAL_MODULE:= libFDK + +include $(BUILD_STATIC_LIBRARY) diff --git a/libFDK/src/FDK_bitbuffer.cpp b/libFDK/src/FDK_bitbuffer.cpp new file mode 100644 index 0000000..75a0375 --- /dev/null +++ b/libFDK/src/FDK_bitbuffer.cpp @@ -0,0 +1,427 @@ +/*************************** Fraunhofer IIS FDK Tools *********************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Lohwasser + Description: common bitbuffer read/write routines + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "FDK_bitbuffer.h" + + + + +#include "genericStds.h" +#include "common_fix.h" +#include "fixminmax.h" + +const UINT BitMask [32+1] = +{ + 0x0, 0x1, 0x3, 0x7, + 0xf, 0x1f, 0x3f, 0x7f, + 0xff, 0x1ff, 0x3ff, 0x7ff, + 0xfff, 0x1fff, 0x3fff, 0x7fff, + 0xffff, 0x1ffff, 0x3ffff, 0x7ffff, + 0xfffff, 0x1fffff, 0x3fffff, 0x7fffff, + 0xffffff, 0x1ffffff, 0x3ffffff, 0x7ffffff, + 0xfffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, + 0xffffffff +}; + +const UINT *const RESTRICT pBitMask = BitMask; + +void FDK_CreateBitBuffer (HANDLE_FDK_BITBUF *hBitBuf, UCHAR *pBuffer, + UINT bufSize) +{ + //*hBitBuf = (HANDLE_FDK_BITBUF) FDKcalloc(sizeof(FDK_BITBUF),1); + + FDK_InitBitBuffer (*hBitBuf, pBuffer, bufSize, 0); + + FDKmemclear((*hBitBuf)->Buffer, bufSize*sizeof(UCHAR)); +} + +void FDK_DeleteBitBuffer (HANDLE_FDK_BITBUF hBitBuf) { /*FDKfree((HANDLE_FDK_BITBUF)hBitBuf) */; } + +void FDK_InitBitBuffer (HANDLE_FDK_BITBUF hBitBuf, UCHAR *pBuffer, + UINT bufSize, UINT validBits) +{ + hBitBuf->ValidBits = validBits ; + hBitBuf->ReadOffset = 0 ; + hBitBuf->WriteOffset = 0 ; + hBitBuf->BitCnt = 0 ; + hBitBuf->BitNdx = 0 ; + + hBitBuf->Buffer = pBuffer ; + hBitBuf->bufSize = bufSize ; + hBitBuf->bufBits = (bufSize << 3) ; +#if defined(FDK_DEBUG) || defined(DEBUG) + /*assure bufsize (2^n) */ + if (bufSize!=0) { + UINT x = 0, n=bufSize; + for (x=0; n>0; x++,n>>=1) {} + if ( bufSize != (1<<(x-1)) ) { + FDKprintfErr("Error: bufSizein FDK_InitBitBuffer() != (2^n), %d\n", bufSize); + } + } +#endif +} + +void FDK_ResetBitBuffer ( HANDLE_FDK_BITBUF hBitBuf ) +{ + hBitBuf->ValidBits = 0 ; + hBitBuf->ReadOffset = 0 ; + hBitBuf->WriteOffset = 0 ; + hBitBuf->BitCnt = 0 ; + hBitBuf->BitNdx = 0 ; +} + +INT FDK_get (HANDLE_FDK_BITBUF hBitBuf, const UINT numberOfBits) +{ + UINT byteOffset = hBitBuf->BitNdx >> 3 ; + UINT bitOffset = hBitBuf->BitNdx & 0x07 ; + + hBitBuf->BitNdx = (hBitBuf->BitNdx + numberOfBits) & (hBitBuf->bufBits - 1) ; + hBitBuf->BitCnt += numberOfBits ; + hBitBuf->ValidBits -= numberOfBits ; + + UINT byteMask = hBitBuf->bufSize - 1 ; + + UINT tx = (hBitBuf->Buffer [ byteOffset & byteMask] << 24) | + (hBitBuf->Buffer [(byteOffset+1) & byteMask] << 16) | + (hBitBuf->Buffer [(byteOffset+2) & byteMask] << 8) | + hBitBuf->Buffer [(byteOffset+3) & byteMask]; + + if (bitOffset) + { + tx <<= bitOffset; + tx |= hBitBuf->Buffer [(byteOffset+4) & byteMask] >> (8-bitOffset); + } + + return (tx >> (32 - numberOfBits)) ; +} + +/* 01-DEC_2009 A. Tritthart + New routine added that reads 32 bits in order to allow a simple update of the 32-bit cache. + Due to push-back features, the read operations are not byte-aligned, nor 32-bit aligned, + all bytes need to be shifted according to the current read bit position. + Usage: bitstream->cache = FDK_get32 (bitstream); +*/ + +INT FDK_get32 (HANDLE_FDK_BITBUF hBitBuf) +{ + UINT BitNdx = hBitBuf->BitNdx + 32; + if (BitNdx <= hBitBuf->bufBits) + { + hBitBuf->BitNdx = BitNdx; + hBitBuf->BitCnt += 32; + hBitBuf->ValidBits -= 32; + + UINT byteOffset = (BitNdx-1) >> 3; + UINT cache = (hBitBuf->Buffer[(byteOffset-3)] << 24) | + (hBitBuf->Buffer[(byteOffset-2)] << 16) | + (hBitBuf->Buffer[(byteOffset-1)] << 8) | + hBitBuf->Buffer[(byteOffset-0)]; + + if ( (BitNdx = (BitNdx&7)) != 0 ) { + cache = (cache >> (8-BitNdx)) | ((UINT)hBitBuf->Buffer [byteOffset-4] << (24+BitNdx)); + } + return (cache) ; + } + else + { + /* exotic path, used only at the end of the buffer, when wrapping around */ + int nBits = (INT)hBitBuf->bufBits-(INT)hBitBuf->BitNdx; + + UINT cache = FDK_get (hBitBuf,nBits)<< (32-nBits); + cache |= (FDK_get (hBitBuf,32-nBits)); + return (cache); + } +} + +INT FDK_getBwd (HANDLE_FDK_BITBUF hBitBuf, const UINT numberOfBits) +{ + UINT byteOffset = hBitBuf->BitNdx >> 3 ; + UINT bitOffset = hBitBuf->BitNdx & 0x07 ; + UINT byteMask = hBitBuf->bufSize - 1 ; + int i; + + hBitBuf->BitNdx = (hBitBuf->BitNdx - numberOfBits) & (hBitBuf->bufBits - 1) ; + hBitBuf->BitCnt -= numberOfBits ; + hBitBuf->ValidBits += numberOfBits ; + + UINT tx = hBitBuf->Buffer [(byteOffset-3) & byteMask] << 24 | + hBitBuf->Buffer [(byteOffset-2) & byteMask] << 16 | + hBitBuf->Buffer [(byteOffset-1) & byteMask] << 8 | + hBitBuf->Buffer [ byteOffset & byteMask] ; + UINT txa = 0x0; + + tx >>= (8 - bitOffset) ; + + if (bitOffset && numberOfBits > 24) + { + tx |= hBitBuf->Buffer [(byteOffset-4) & byteMask] << (24 + bitOffset) ; + } + + /* in place turn around */ + for (i = 0; i < 16; i++) { + UINT bitMaskR = 0x00000001 << i; + UINT bitMaskL = 0x80000000 >> i; + + txa |= (tx & bitMaskR) << (31 - (i<<1)); + txa |= (tx & bitMaskL) >> (31 - (i<<1)); + } + + return (txa >> (32 - numberOfBits)) ; +} + +void FDK_put (HANDLE_FDK_BITBUF hBitBuf, UINT value, const UINT numberOfBits) +{ + UINT byteOffset = hBitBuf->BitNdx >> 3 ; + UINT bitOffset = hBitBuf->BitNdx & 0x07 ; + + hBitBuf->BitNdx = (hBitBuf->BitNdx + numberOfBits) & (hBitBuf->bufBits - 1) ; + hBitBuf->BitCnt += numberOfBits ; + hBitBuf->ValidBits += numberOfBits ; + + UINT byteMask = hBitBuf->bufSize - 1 ; + + UINT tmp = value<<(32-numberOfBits)>>bitOffset; + UINT mask = ~BitMask[(32-bitOffset)] | (BitMask [(32-numberOfBits)] >> bitOffset) ; + + hBitBuf->Buffer [ byteOffset & byteMask] = (hBitBuf->Buffer [ byteOffset & byteMask]&(mask>>24)) | (UCHAR)(tmp>>24); + hBitBuf->Buffer [(byteOffset+1) & byteMask] = (hBitBuf->Buffer [(byteOffset+1) & byteMask]&(mask>>16)) | (UCHAR)(tmp>>16); + hBitBuf->Buffer [(byteOffset+2) & byteMask] = (hBitBuf->Buffer [(byteOffset+2) & byteMask]&(mask>>8)) | (UCHAR)(tmp>>8); + hBitBuf->Buffer [(byteOffset+3) & byteMask] = (hBitBuf->Buffer [(byteOffset+3) & byteMask]&(mask)) | (UCHAR)(tmp); + + if (bitOffset && numberOfBits > 24) + { + hBitBuf->Buffer [(byteOffset+4) & byteMask] = (UCHAR)(value<<(40-numberOfBits)>>bitOffset) | + ( hBitBuf->Buffer [(byteOffset+4) & byteMask] & BitMask[(40-numberOfBits-bitOffset)] ) ; + } +} + +void FDK_putBwd (HANDLE_FDK_BITBUF hBitBuf, UINT value, const UINT numberOfBits) +{ + UINT byteOffset = hBitBuf->BitNdx >> 3 ; + UINT bitOffset = 7 - (hBitBuf->BitNdx & 0x07) ; + UINT byteMask = hBitBuf->bufSize - 1 ; + + UINT mask = ~(BitMask[numberOfBits] << bitOffset) ; + UINT tmp = 0x0000; + int i; + + hBitBuf->BitNdx = (hBitBuf->BitNdx - numberOfBits) & (hBitBuf->bufBits - 1) ; + hBitBuf->BitCnt -= numberOfBits ; + hBitBuf->ValidBits -= numberOfBits ; + + /* in place turn around */ + for (i = 0; i < 16; i++) { + UINT bitMaskR = 0x00000001 << i; + UINT bitMaskL = 0x80000000 >> i; + + tmp |= (value & bitMaskR) << (31 - (i<<1)); + tmp |= (value & bitMaskL) >> (31 - (i<<1)); + } + value = tmp; + tmp = value>>(32-numberOfBits)<Buffer [ byteOffset & byteMask] = (hBitBuf->Buffer [ byteOffset & byteMask]&(mask)) | (UCHAR)(tmp); + hBitBuf->Buffer [(byteOffset-1) & byteMask] = (hBitBuf->Buffer [(byteOffset-1) & byteMask]&(mask>>8)) | (UCHAR)(tmp>>8); + hBitBuf->Buffer [(byteOffset-2) & byteMask] = (hBitBuf->Buffer [(byteOffset-2) & byteMask]&(mask>>16)) | (UCHAR)(tmp>>16); + hBitBuf->Buffer [(byteOffset-3) & byteMask] = (hBitBuf->Buffer [(byteOffset-3) & byteMask]&(mask>>24)) | (UCHAR)(tmp>>24); + + if ((bitOffset + numberOfBits) > 32) + { + hBitBuf->Buffer [(byteOffset-4) & byteMask] = (UCHAR)(value>>(64-numberOfBits-bitOffset)) | + ( hBitBuf->Buffer [(byteOffset-4) & byteMask] & ~(BitMask[bitOffset] >> (32-numberOfBits)) ) ; + } +} + + +void FDK_pushBack (HANDLE_FDK_BITBUF hBitBuf, const UINT numberOfBits, UCHAR config) +{ + hBitBuf->BitCnt -= numberOfBits ; + hBitBuf->ValidBits += (config==0) ? numberOfBits : (-(INT)numberOfBits) ; + hBitBuf->BitNdx = (hBitBuf->BitNdx - numberOfBits) & (hBitBuf->bufBits - 1) ; +} + +void FDK_pushForward (HANDLE_FDK_BITBUF hBitBuf, const UINT numberOfBits, UCHAR config) +{ + hBitBuf->BitCnt += numberOfBits ; + hBitBuf->ValidBits -= (config==0) ? numberOfBits : (-(INT)numberOfBits) ; + hBitBuf->BitNdx = (hBitBuf->BitNdx + numberOfBits) & (hBitBuf->bufBits - 1) ; +} + + +void FDK_byteAlign (HANDLE_FDK_BITBUF hBitBuf, UCHAR config) +{ + INT alignment = hBitBuf->BitCnt & 0x07 ; + + if (alignment) + { + if (config==0) + FDK_pushForward (hBitBuf, 8 - alignment, config) ; /* BS_READER */ + else + FDK_put (hBitBuf,0 , 8 - alignment) ; /* BS_WRITER */ + } + + hBitBuf->BitCnt = 0 ; +} + +UINT FDK_getValidBits (HANDLE_FDK_BITBUF hBitBuf) +{ + return hBitBuf->ValidBits; +} + +INT FDK_getFreeBits (HANDLE_FDK_BITBUF hBitBuf) +{ + return (hBitBuf->bufBits - hBitBuf->ValidBits) ; +} + +void FDK_setBitCnt (HANDLE_FDK_BITBUF hBitBuf, const UINT value) +{ + hBitBuf->BitCnt = value ; +} + +INT FDK_getBitCnt (HANDLE_FDK_BITBUF hBitBuf) +{ + return hBitBuf->BitCnt ; +} + +void FDK_Feed(HANDLE_FDK_BITBUF hBitBuf, + UCHAR *RESTRICT inputBuffer, + const UINT bufferSize, + UINT *bytesValid) +{ + inputBuffer = &inputBuffer [bufferSize - *bytesValid] ; + + UINT bTotal = 0 ; + + UINT bToRead = (hBitBuf->bufBits - hBitBuf->ValidBits) >> 3 ; + UINT noOfBytes = fMin(bToRead, *bytesValid); //(bToRead < *bytesValid) ? bToRead : *bytesValid ; + + while (noOfBytes > 0) + { + /* split read to buffer size */ + bToRead = hBitBuf->bufSize - hBitBuf->ReadOffset ; + bToRead = fMin(bToRead, noOfBytes); //(bToRead < noOfBytes) ? bToRead : noOfBytes ; + + /* copy 'bToRead' bytes from 'ptr' to inputbuffer */ + FDKmemcpy(&hBitBuf->Buffer[hBitBuf->ReadOffset], inputBuffer, bToRead*sizeof(UCHAR)); + + /* add noOfBits to number of valid bits in buffer */ + hBitBuf->ValidBits += bToRead << 3 ; + bTotal += bToRead ; + inputBuffer += bToRead ; + + hBitBuf->ReadOffset = (hBitBuf->ReadOffset + bToRead) & (hBitBuf->bufSize - 1) ; + noOfBytes -= bToRead ; + } + + *bytesValid -= bTotal ; +} + +void CopyAlignedBlock (HANDLE_FDK_BITBUF h_BitBufSrc, UCHAR *RESTRICT dstBuffer, UINT bToRead) +{ + UINT byteOffset = h_BitBufSrc->BitNdx >> 3 ; + const UINT byteMask = h_BitBufSrc->bufSize - 1 ; + + UCHAR *RESTRICT pBBB = h_BitBufSrc->Buffer; + for (UINT i = 0 ; i < bToRead ; i++) + { + dstBuffer[i] = pBBB[(byteOffset+i) & byteMask] ; + } + + bToRead <<= 3 ; + + h_BitBufSrc->BitNdx = (h_BitBufSrc->BitNdx + bToRead) & (h_BitBufSrc->bufBits - 1) ; + h_BitBufSrc->BitCnt += bToRead ; + h_BitBufSrc->ValidBits -= bToRead ; +} + +void FDK_Copy (HANDLE_FDK_BITBUF h_BitBufDst, HANDLE_FDK_BITBUF h_BitBufSrc, UINT *bytesValid) +{ + INT bTotal = 0; + + /* limit noOfBytes to valid bytes in src buffer and available bytes in dst buffer */ + UINT bToRead = h_BitBufSrc->ValidBits >> 3 ; + UINT noOfBytes = fMin(bToRead, *bytesValid); //(*bytesValid < bToRead) ? *bytesValid : bToRead ; + bToRead = FDK_getFreeBits(h_BitBufDst); + noOfBytes = fMin(bToRead, noOfBytes); //(bToRead < noOfBytes) ? bToRead : noOfBytes; + + while (noOfBytes > 0) + { + /* Split Read to buffer size */ + bToRead = h_BitBufDst->bufSize - h_BitBufDst->ReadOffset ; + bToRead = fMin(noOfBytes, bToRead); //(noOfBytes < bToRead) ? noOfBytes : bToRead ; + + /* copy 'bToRead' bytes from buffer to buffer */ + if (!(h_BitBufSrc->BitNdx & 0x07)) { + CopyAlignedBlock (h_BitBufSrc, h_BitBufDst->Buffer + h_BitBufDst->ReadOffset, bToRead) ; + } else { + for (UINT i = 0; i < bToRead; i++) + { + h_BitBufDst->Buffer [h_BitBufDst->ReadOffset + i] = (UCHAR)FDK_get(h_BitBufSrc,8); + } + } + + /* add noOfBits to number of valid bits in buffer */ + h_BitBufDst->ValidBits += bToRead << 3 ; + bTotal += bToRead; + + h_BitBufDst->ReadOffset = (h_BitBufDst->ReadOffset + bToRead) & (h_BitBufDst->bufSize-1); + noOfBytes -= bToRead; + } + + *bytesValid -=bTotal; +} + +void FDK_Fetch (HANDLE_FDK_BITBUF hBitBuf, UCHAR *outBuf, UINT *writeBytes) +{ + UCHAR *RESTRICT outputBuffer = outBuf; + UINT bTotal = 0 ; + + UINT bToWrite = (hBitBuf->ValidBits) >> 3 ; + UINT noOfBytes = fMin(bToWrite, *writeBytes); //(bToWrite < *writeBytes) ? bToWrite : *writeBytes ; + + while (noOfBytes > 0) + { + /* split write to buffer size */ + bToWrite = hBitBuf->bufSize - hBitBuf->WriteOffset ; + bToWrite = fMin(bToWrite, noOfBytes); //(bToWrite < noOfBytes) ? bToWrite : noOfBytes ; + + /* copy 'bToWrite' bytes from bitbuffer to outputbuffer */ + FDKmemcpy(outputBuffer, &hBitBuf->Buffer[hBitBuf->WriteOffset], bToWrite*sizeof(UCHAR)); + + /* sub noOfBits from number of valid bits in buffer */ + hBitBuf->ValidBits -= bToWrite << 3 ; + bTotal += bToWrite ; + outputBuffer += bToWrite ; + + hBitBuf->WriteOffset = (hBitBuf->WriteOffset + bToWrite) & (hBitBuf->bufSize - 1) ; + noOfBytes -= bToWrite ; + } + + *writeBytes = bTotal ; +} + diff --git a/libFDK/src/FDK_core.cpp b/libFDK/src/FDK_core.cpp new file mode 100644 index 0000000..3f5e8fb --- /dev/null +++ b/libFDK/src/FDK_core.cpp @@ -0,0 +1,66 @@ +/*************************** Fraunhofer IIS FDK Tools *********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: FDK tools versioning support + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "FDK_core.h" + +/* FDK tools library info */ +#define FDK_TOOLS_LIB_VL0 2 +#define FDK_TOOLS_LIB_VL1 2 +#define FDK_TOOLS_LIB_VL2 5 +#define FDK_TOOLS_LIB_TITLE "FDK Tools" +#define FDK_TOOLS_LIB_BUILD_DATE __DATE__ +#define FDK_TOOLS_LIB_BUILD_TIME __TIME__ + +int FDK_toolsGetLibInfo(LIB_INFO *info) +{ + UINT v; + int i; + + if (info == NULL) { + return -1; + } + + /* search for next free tab */ + i = FDKlibInfo_lookup(info, FDK_TOOLS); + if (i<0) return -1; + + info += i; + + v = LIB_VERSION(FDK_TOOLS_LIB_VL0, FDK_TOOLS_LIB_VL1, FDK_TOOLS_LIB_VL2); + + FDKsprintf(info->versionStr, "%d.%d.%d", ((v >> 24) & 0xff), ((v >> 16) & 0xff), ((v >> 8 ) & 0xff)); + + info->module_id = FDK_TOOLS; + info->version = v; + info->build_date = (char *)FDK_TOOLS_LIB_BUILD_DATE; + info->build_time = (char *)FDK_TOOLS_LIB_BUILD_TIME; + info->title = (char *)FDK_TOOLS_LIB_TITLE; + info->flags = 0; + + return 0; +} diff --git a/libFDK/src/FDK_crc.cpp b/libFDK/src/FDK_crc.cpp new file mode 100644 index 0000000..0049807 --- /dev/null +++ b/libFDK/src/FDK_crc.cpp @@ -0,0 +1,397 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: + contents/description: CRC calculation + +******************************************************************************/ + +#include "FDK_crc.h" + + + +/*---------------- constants -----------------------*/ + +/** + * \brief This table defines precalculated lookup tables for crc polynom x^16 + x^15 + x^2 + x^0. + */ +static const USHORT crcLookup_16_15_2_0[256] = +{ + 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011, + 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022, + 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072, + 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041, + 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2, + 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1, + 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1, + 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082, + 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192, + 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1, + 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1, + 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2, + 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151, + 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162, + 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132, + 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101, + 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312, + 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321, + 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371, + 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342, + 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1, + 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2, + 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2, + 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381, + 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291, + 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2, + 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2, + 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1, + 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252, + 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261, + 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231, + 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202 +}; + +/** + * \brief This table defines precalculated lookup tables for crc polynom x^16 + x^12 + x^5 + x^0. + */ +static const USHORT crcLookup_16_12_5_0[256] = +{ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + + +/*--------------- function declarations --------------------*/ + +static inline INT calcCrc_Bits( + USHORT * const pCrc, + USHORT crcMask, + USHORT crcPoly, + HANDLE_FDK_BITSTREAM hBs, + INT nBits + ); + +static inline INT calcCrc_Bytes( + USHORT * const pCrc, + const USHORT * pCrcLookup, + HANDLE_FDK_BITSTREAM hBs, + INT nBytes + ); + +static void crcCalc( + HANDLE_FDK_CRCINFO hCrcInfo, + HANDLE_FDK_BITSTREAM hBs, + const INT reg + ); + + +/*------------- function definitions ----------------*/ + +void FDKcrcInit( + HANDLE_FDK_CRCINFO hCrcInfo, + const UINT crcPoly, + const UINT crcStartValue, + const UINT crcLen + ) +{ + /* crc polynom example: + x^16 + x^15 + x^2 + x^0 (1) 1000 0000 0000 0101 -> 0x8005 + x^16 + x^12 + x^5 + x^0 (1) 0001 0000 0010 0001 -> 0x1021 + x^8 + x^4 + x^3 + x^2 + x^0 (1) 0001 1101 -> 0x001d */ + + hCrcInfo->crcLen = crcLen; + hCrcInfo->crcPoly = crcPoly; + hCrcInfo->startValue = crcStartValue; + hCrcInfo->crcMask = (crcLen) ? (1<<(crcLen-1)) : 0; + + FDKcrcReset(hCrcInfo); + + hCrcInfo->pCrcLookup = 0; + + if (hCrcInfo->crcLen==16) { + switch ( crcPoly ) { + case 0x8005: + hCrcInfo->pCrcLookup = crcLookup_16_15_2_0; + break; + case 0x1021: + hCrcInfo->pCrcLookup = crcLookup_16_12_5_0; + break; + case 0x001d: + default: + /* no lookup table */ + hCrcInfo->pCrcLookup = 0; + } + } + + +} + +void FDKcrcReset(HANDLE_FDK_CRCINFO hCrcInfo) +{ + int i; + + hCrcInfo->crcValue = hCrcInfo->startValue; + + for(i=0;icrcRegData[i].isActive = 0; + } + hCrcInfo->regStart = 0; + hCrcInfo->regStop = 0; +} + +INT FDKcrcStartReg( + HANDLE_FDK_CRCINFO hCrcInfo, + const HANDLE_FDK_BITSTREAM hBs, + const INT mBits + ) +{ + int reg = hCrcInfo->regStart; + + FDK_ASSERT(hCrcInfo->crcRegData[reg].isActive==0); + hCrcInfo->crcRegData[reg].isActive = 1; + hCrcInfo->crcRegData[reg].maxBits = mBits; + hCrcInfo->crcRegData[reg].validBits = FDKgetValidBits(hBs) ; + hCrcInfo->crcRegData[reg].bitBufCntBits = 0; + + hCrcInfo->regStart = (hCrcInfo->regStart+1)%MAX_CRC_REGS; + + return (reg); +} + +INT FDKcrcEndReg( + HANDLE_FDK_CRCINFO hCrcInfo, + const HANDLE_FDK_BITSTREAM hBs, + const INT reg + ) +{ + FDK_ASSERT((reg==(INT)hCrcInfo->regStop)&&(hCrcInfo->crcRegData[reg].isActive==1)); + + if (hBs->ConfigCache==BS_WRITER) { + hCrcInfo->crcRegData[reg].bitBufCntBits = FDKgetValidBits(hBs) - hCrcInfo->crcRegData[reg].validBits; + } + else { + hCrcInfo->crcRegData[reg].bitBufCntBits = hCrcInfo->crcRegData[reg].validBits - FDKgetValidBits(hBs); + } + + if (hCrcInfo->crcRegData[reg].maxBits == 0) { + hCrcInfo->crcRegData[reg].maxBits = hCrcInfo->crcRegData[reg].bitBufCntBits; + } + + crcCalc( hCrcInfo, hBs, reg); + + hCrcInfo->crcRegData[reg].isActive = 0; + hCrcInfo->regStop = (hCrcInfo->regStop+1)%MAX_CRC_REGS; + + return 0; +} + +USHORT FDKcrcGetCRC( + const HANDLE_FDK_CRCINFO hCrcInfo + ) +{ + return ( hCrcInfo->crcValue & (((hCrcInfo->crcMask-1)<<1)+1) ); +} + +/** + * \brief Calculate crc bits. + * + * Calculate crc starting at current bitstream postion over nBits. + * + * \param pCrc Pointer to an outlying allocated crc info structure. + * \param crcMask CrcMask in use. + * \param crcPoly Crc polynom in use. + * \param hBs Handle to current bit buffer structure. + * \param nBits Number of processing bits. + * + * \return Number of processed bits. + */ +static inline INT calcCrc_Bits( + USHORT * const pCrc, + USHORT crcMask, + USHORT crcPoly, + HANDLE_FDK_BITSTREAM hBs, + INT nBits + ) +{ + int i; + USHORT crc = *pCrc; /* get crc value */ + + if (hBs!=NULL) { + for (i = 0; (i < nBits); i++) { + USHORT tmp = FDKreadBits(hBs,1); // process single bit + tmp ^= ( (crc & crcMask) ? 1 : 0 ); + tmp *= crcPoly; + crc <<= 1; + crc ^= tmp; + } + } + else { + for (i = 0; (i < nBits); i++) { + USHORT tmp = 0; // process single bit + tmp ^= ( (crc & crcMask) ? 1 : 0 ); + tmp *= crcPoly; + crc <<= 1; + crc ^= tmp; + } + } + *pCrc = crc; /* update crc value */ + + return nBits; +} + +/** + * \brief Calculate crc bytes. + * + * Calculate crc starting at current bitstream postion over nBytes. + * + * \param pCrc Pointer to an outlying allocated crc info structure. + * \param pCrcLookup Pointer to lookup table used for fast crc calculation. + * \param hBs Handle to current bit buffer structure. + * \param nBits Number of processing bytes. + * + * \return Number of processed bits. + */ +static inline INT calcCrc_Bytes( + USHORT * const pCrc, + const USHORT * pCrcLookup, + HANDLE_FDK_BITSTREAM hBs, + INT nBytes + ) +{ + int i; + USHORT crc = *pCrc; /* get crc value */ + + if (hBs!=NULL) { + for (i=0; i>8)^((UCHAR)FDKreadBits(hBs,8)))&0xFF]; + } + } + else { + for (i=0; i>8)^((UCHAR)0))&0xFF]; + } + } + + *pCrc = crc; /* update crc value */ + + return (i); +} + +/** + * \brief Calculate crc. + * + * Calculate crc. Lenght depends on mBits parameter in FDKcrcStartReg() configuration. + * + * \param hCrcInfo Pointer to an outlying allocated crc info structure. + * \param hBs Pointer to current bit buffer structure. + * \param reg Crc region ID. + * + * \return Number of processed bits. + */ +static void crcCalc( + HANDLE_FDK_CRCINFO hCrcInfo, + HANDLE_FDK_BITSTREAM hBs, + const INT reg + ) +{ + USHORT crc = hCrcInfo->crcValue; + CCrcRegData *rD = &hCrcInfo->crcRegData[reg]; + FDK_BITSTREAM bsReader; + + if (hBs->ConfigCache==BS_READER) { + bsReader = *hBs; + FDKpushBiDirectional(&bsReader, -(INT)(rD->validBits-FDKgetValidBits(&bsReader))); + } + else { + FDKinitBitStream(&bsReader, hBs->hBitBuf.Buffer, hBs->hBitBuf.bufSize, hBs->hBitBuf.ValidBits, BS_READER); + FDKpushBiDirectional(&bsReader, rD->validBits); + } + + int bits, rBits; + rBits = (rD->maxBits>=0) ? rD->maxBits : -rD->maxBits; /* ramaining bits */ + if ((rD->maxBits>0) && (((INT)rD->bitBufCntBits>>3<<3)bitBufCntBits; + } + else { + bits = rBits; + } + + int words = bits >> 3; /* processing bytes */ + int mBits = bits & 0x7; /* modulo bits */ + + if(hCrcInfo->pCrcLookup) { + rBits -= (calcCrc_Bytes(&crc, hCrcInfo->pCrcLookup, &bsReader, words)<<3); + } + else { + rBits -= calcCrc_Bits(&crc, hCrcInfo->crcMask, hCrcInfo->crcPoly, &bsReader, words<<3 ); + } + + /* remaining valid bits*/ + if(mBits!=0) { + rBits -= calcCrc_Bits(&crc, hCrcInfo->crcMask, hCrcInfo->crcPoly, &bsReader, mBits ); + } + + if (rBits!=0) { + /* zero bytes */ + if ( (hCrcInfo->pCrcLookup) && (rBits>8) ) { + rBits -= (calcCrc_Bytes(&crc, hCrcInfo->pCrcLookup, NULL, rBits>>3)<<3); + } + /* remaining zero bits */ + if (rBits!=0) { + rBits -= calcCrc_Bits(&crc, hCrcInfo->crcMask, hCrcInfo->crcPoly, NULL, rBits ); + } + } + + hCrcInfo->crcValue = crc; +} + diff --git a/libFDK/src/FDK_tools_rom.cpp b/libFDK/src/FDK_tools_rom.cpp new file mode 100644 index 0000000..d3c768b --- /dev/null +++ b/libFDK/src/FDK_tools_rom.cpp @@ -0,0 +1,2358 @@ +/*************************** Fraunhofer IIS FDK Tools *********************** + + (C) Copyright Fraunhofer IIS (2008) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Oliver Moser + Description: ROM tables used by FDK tools + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "FDK_tools_rom.h" + + + + + + + + + + + +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_STP SineTable480[] = +{ + STCP(0x7fffffff, 0x00000000), STCP(0x7fffd315, 0x006b3b9b), STCP(0x7fff4c54, 0x00d676eb), STCP(0x7ffe6bbf, 0x0141b1a5), + STCP(0x7ffd3154, 0x01aceb7c), STCP(0x7ffb9d15, 0x02182427), STCP(0x7ff9af04, 0x02835b5a), STCP(0x7ff76721, 0x02ee90c8), + STCP(0x7ff4c56f, 0x0359c428), STCP(0x7ff1c9ef, 0x03c4f52f), STCP(0x7fee74a2, 0x0430238f), STCP(0x7feac58d, 0x049b4f00), + STCP(0x7fe6bcb0, 0x05067734), STCP(0x7fe25a0f, 0x05719be2), STCP(0x7fdd9dad, 0x05dcbcbe), STCP(0x7fd8878e, 0x0647d97c), + STCP(0x7fd317b4, 0x06b2f1d2), STCP(0x7fcd4e24, 0x071e0575), STCP(0x7fc72ae2, 0x07891418), STCP(0x7fc0adf2, 0x07f41d72), + STCP(0x7fb9d759, 0x085f2137), STCP(0x7fb2a71b, 0x08ca1f1b), STCP(0x7fab1d3d, 0x093516d4), STCP(0x7fa339c5, 0x09a00817), + STCP(0x7f9afcb9, 0x0a0af299), STCP(0x7f92661d, 0x0a75d60e), STCP(0x7f8975f9, 0x0ae0b22c), STCP(0x7f802c52, 0x0b4b86a8), + STCP(0x7f76892f, 0x0bb65336), STCP(0x7f6c8c96, 0x0c21178c), STCP(0x7f62368f, 0x0c8bd35e), STCP(0x7f578721, 0x0cf68662), + STCP(0x7f4c7e54, 0x0d61304e), STCP(0x7f411c2f, 0x0dcbd0d5), STCP(0x7f3560b9, 0x0e3667ad), STCP(0x7f294bfd, 0x0ea0f48c), + STCP(0x7f1cde01, 0x0f0b7727), STCP(0x7f1016ce, 0x0f75ef33), STCP(0x7f02f66f, 0x0fe05c64), STCP(0x7ef57cea, 0x104abe71), + STCP(0x7ee7aa4c, 0x10b5150f), STCP(0x7ed97e9c, 0x111f5ff4), STCP(0x7ecaf9e5, 0x11899ed3), STCP(0x7ebc1c31, 0x11f3d164), + STCP(0x7eace58a, 0x125df75b), STCP(0x7e9d55fc, 0x12c8106f), STCP(0x7e8d6d91, 0x13321c53), STCP(0x7e7d2c54, 0x139c1abf), + STCP(0x7e6c9251, 0x14060b68), STCP(0x7e5b9f93, 0x146fee03), STCP(0x7e4a5426, 0x14d9c245), STCP(0x7e38b017, 0x154387e6), + STCP(0x7e26b371, 0x15ad3e9a), STCP(0x7e145e42, 0x1616e618), STCP(0x7e01b096, 0x16807e15), STCP(0x7deeaa7a, 0x16ea0646), + STCP(0x7ddb4bfc, 0x17537e63), STCP(0x7dc79529, 0x17bce621), STCP(0x7db3860f, 0x18263d36), STCP(0x7d9f1ebd, 0x188f8357), + STCP(0x7d8a5f40, 0x18f8b83c), STCP(0x7d7547a7, 0x1961db9b), STCP(0x7d5fd801, 0x19caed29), STCP(0x7d4a105d, 0x1a33ec9c), + STCP(0x7d33f0ca, 0x1a9cd9ac), STCP(0x7d1d7958, 0x1b05b40f), STCP(0x7d06aa16, 0x1b6e7b7a), STCP(0x7cef8315, 0x1bd72fa4), + STCP(0x7cd80464, 0x1c3fd045), STCP(0x7cc02e15, 0x1ca85d12), STCP(0x7ca80038, 0x1d10d5c2), STCP(0x7c8f7ade, 0x1d793a0b), + STCP(0x7c769e18, 0x1de189a6), STCP(0x7c5d69f7, 0x1e49c447), STCP(0x7c43de8e, 0x1eb1e9a7), STCP(0x7c29fbee, 0x1f19f97b), + STCP(0x7c0fc22a, 0x1f81f37c), STCP(0x7bf53153, 0x1fe9d75f), STCP(0x7bda497d, 0x2051a4dd), STCP(0x7bbf0aba, 0x20b95bac), + STCP(0x7ba3751d, 0x2120fb83), STCP(0x7b8788ba, 0x2188841a), STCP(0x7b6b45a5, 0x21eff528), STCP(0x7b4eabf1, 0x22574e65), + STCP(0x7b31bbb2, 0x22be8f87), STCP(0x7b1474fd, 0x2325b847), STCP(0x7af6d7e6, 0x238cc85d), STCP(0x7ad8e482, 0x23f3bf7e), + STCP(0x7aba9ae6, 0x245a9d65), STCP(0x7a9bfb27, 0x24c161c7), STCP(0x7a7d055b, 0x25280c5e), STCP(0x7a5db997, 0x258e9ce0), + STCP(0x7a3e17f2, 0x25f51307), STCP(0x7a1e2082, 0x265b6e8a), STCP(0x79fdd35c, 0x26c1af22), STCP(0x79dd3098, 0x2727d486), + STCP(0x79bc384d, 0x278dde6e), STCP(0x799aea92, 0x27f3cc94), STCP(0x7979477d, 0x28599eb0), STCP(0x79574f28, 0x28bf547b), + STCP(0x793501a9, 0x2924edac), STCP(0x79125f19, 0x298a69fc), STCP(0x78ef678f, 0x29efc925), STCP(0x78cc1b26, 0x2a550adf), + STCP(0x78a879f4, 0x2aba2ee4), STCP(0x78848414, 0x2b1f34eb), STCP(0x7860399e, 0x2b841caf), STCP(0x783b9aad, 0x2be8e5e8), + STCP(0x7816a759, 0x2c4d9050), STCP(0x77f15fbc, 0x2cb21ba0), STCP(0x77cbc3f2, 0x2d168792), STCP(0x77a5d413, 0x2d7ad3de), + STCP(0x777f903c, 0x2ddf0040), STCP(0x7758f886, 0x2e430c6f), STCP(0x77320d0d, 0x2ea6f827), STCP(0x770acdec, 0x2f0ac320), + STCP(0x76e33b3f, 0x2f6e6d16), STCP(0x76bb5521, 0x2fd1f5c1), STCP(0x76931bae, 0x30355cdd), STCP(0x766a8f04, 0x3098a223), + STCP(0x7641af3d, 0x30fbc54d), STCP(0x76187c77, 0x315ec617), STCP(0x75eef6ce, 0x31c1a43b), STCP(0x75c51e61, 0x32245f72), + STCP(0x759af34c, 0x3286f779), STCP(0x757075ac, 0x32e96c09), STCP(0x7545a5a0, 0x334bbcde), STCP(0x751a8346, 0x33ade9b3), + STCP(0x74ef0ebc, 0x340ff242), STCP(0x74c34820, 0x3471d647), STCP(0x74972f92, 0x34d3957e), STCP(0x746ac52f, 0x35352fa1), + STCP(0x743e0918, 0x3596a46c), STCP(0x7410fb6b, 0x35f7f39c), STCP(0x73e39c49, 0x36591cea), STCP(0x73b5ebd1, 0x36ba2014), + STCP(0x7387ea23, 0x371afcd5), STCP(0x73599760, 0x377bb2e9), STCP(0x732af3a7, 0x37dc420c), STCP(0x72fbff1b, 0x383ca9fb), + STCP(0x72ccb9db, 0x389cea72), STCP(0x729d2409, 0x38fd032d), STCP(0x726d3dc6, 0x395cf3e9), STCP(0x723d0734, 0x39bcbc63), + STCP(0x720c8075, 0x3a1c5c57), STCP(0x71dba9ab, 0x3a7bd382), STCP(0x71aa82f7, 0x3adb21a1), STCP(0x71790c7e, 0x3b3a4672), + STCP(0x71474660, 0x3b9941b1), STCP(0x711530c2, 0x3bf8131c), STCP(0x70e2cbc6, 0x3c56ba70), STCP(0x70b01790, 0x3cb5376b), + STCP(0x707d1443, 0x3d1389cb), STCP(0x7049c203, 0x3d71b14d), STCP(0x701620f5, 0x3dcfadb0), STCP(0x6fe2313c, 0x3e2d7eb1), + STCP(0x6fadf2fc, 0x3e8b240e), STCP(0x6f79665b, 0x3ee89d86), STCP(0x6f448b7e, 0x3f45ead8), STCP(0x6f0f6289, 0x3fa30bc1), + STCP(0x6ed9eba1, 0x40000000), STCP(0x6ea426ed, 0x405cc754), STCP(0x6e6e1492, 0x40b9617d), STCP(0x6e37b4b6, 0x4115ce38), + STCP(0x6e010780, 0x41720d46), STCP(0x6dca0d14, 0x41ce1e65), STCP(0x6d92c59b, 0x422a0154), STCP(0x6d5b313b, 0x4285b5d4), + STCP(0x6d23501b, 0x42e13ba4), STCP(0x6ceb2261, 0x433c9283), STCP(0x6cb2a837, 0x4397ba32), STCP(0x6c79e1c2, 0x43f2b271), + STCP(0x6c40cf2c, 0x444d7aff), STCP(0x6c07709b, 0x44a8139e), STCP(0x6bcdc639, 0x45027c0c), STCP(0x6b93d02e, 0x455cb40c), + STCP(0x6b598ea3, 0x45b6bb5e), STCP(0x6b1f01c0, 0x461091c2), STCP(0x6ae429ae, 0x466a36f9), STCP(0x6aa90697, 0x46c3aac5), + STCP(0x6a6d98a4, 0x471cece7), STCP(0x6a31e000, 0x4775fd1f), STCP(0x69f5dcd3, 0x47cedb31), STCP(0x69b98f48, 0x482786dc), + STCP(0x697cf78a, 0x487fffe4), STCP(0x694015c3, 0x48d84609), STCP(0x6902ea1d, 0x4930590f), STCP(0x68c574c4, 0x498838b6), + STCP(0x6887b5e2, 0x49dfe4c2), STCP(0x6849ada3, 0x4a375cf5), STCP(0x680b5c33, 0x4a8ea111), STCP(0x67ccc1be, 0x4ae5b0da), + STCP(0x678dde6e, 0x4b3c8c12), STCP(0x674eb271, 0x4b93327c), STCP(0x670f3df3, 0x4be9a3db), STCP(0x66cf8120, 0x4c3fdff4), + STCP(0x668f7c25, 0x4c95e688), STCP(0x664f2f2e, 0x4cebb75c), STCP(0x660e9a6a, 0x4d415234), STCP(0x65cdbe05, 0x4d96b6d3), + STCP(0x658c9a2d, 0x4debe4fe), STCP(0x654b2f10, 0x4e40dc79), STCP(0x65097cdb, 0x4e959d08), STCP(0x64c783bd, 0x4eea2670), + STCP(0x648543e4, 0x4f3e7875), STCP(0x6442bd7e, 0x4f9292dc), STCP(0x63fff0ba, 0x4fe6756a), STCP(0x63bcddc7, 0x503a1fe5), + STCP(0x637984d4, 0x508d9211), STCP(0x6335e611, 0x50e0cbb4), STCP(0x62f201ac, 0x5133cc94), STCP(0x62add7d6, 0x51869476), + STCP(0x626968be, 0x51d92321), STCP(0x6224b495, 0x522b7859), STCP(0x61dfbb8a, 0x527d93e6), STCP(0x619a7dce, 0x52cf758f), + STCP(0x6154fb91, 0x53211d18), STCP(0x610f3505, 0x53728a4a), STCP(0x60c92a5a, 0x53c3bcea), STCP(0x6082dbc1, 0x5414b4c1), + STCP(0x603c496c, 0x54657194), STCP(0x5ff5738d, 0x54b5f32c), STCP(0x5fae5a55, 0x55063951), STCP(0x5f66fdf5, 0x555643c8), + STCP(0x5f1f5ea1, 0x55a6125c), STCP(0x5ed77c8a, 0x55f5a4d2), STCP(0x5e8f57e2, 0x5644faf4), STCP(0x5e46f0dd, 0x5694148b), + STCP(0x5dfe47ad, 0x56e2f15d), STCP(0x5db55c86, 0x57319135), STCP(0x5d6c2f99, 0x577ff3da), STCP(0x5d22c11c, 0x57ce1917), + STCP(0x5cd91140, 0x581c00b3), STCP(0x5c8f203b, 0x5869aa79), STCP(0x5c44ee40, 0x58b71632), STCP(0x5bfa7b82, 0x590443a7), + STCP(0x5bafc837, 0x595132a2), STCP(0x5b64d492, 0x599de2ee), STCP(0x5b19a0c8, 0x59ea5454), STCP(0x5ace2d0f, 0x5a36869f), + STCP(0x5a82799a, 0x5a82799a) +}; + + +RAM_ALIGN +LNK_SECTION_CONSTDATA +LNK_SECTION_CONSTDATA_L1 +const FIXP_STP SineTable512[] = +{ + STCP(0x7fffffff, 0x00000000), STCP(0x7fffd886, 0x006487e3), STCP(0x7fff6216, 0x00c90f88), STCP(0x7ffe9cb2, 0x012d96b1), + STCP(0x7ffd885a, 0x01921d20), STCP(0x7ffc250f, 0x01f6a297), STCP(0x7ffa72d1, 0x025b26d7), STCP(0x7ff871a2, 0x02bfa9a4), + STCP(0x7ff62182, 0x03242abf), STCP(0x7ff38274, 0x0388a9ea), STCP(0x7ff09478, 0x03ed26e6), STCP(0x7fed5791, 0x0451a177), + STCP(0x7fe9cbc0, 0x04b6195d), STCP(0x7fe5f108, 0x051a8e5c), STCP(0x7fe1c76b, 0x057f0035), STCP(0x7fdd4eec, 0x05e36ea9), + STCP(0x7fd8878e, 0x0647d97c), STCP(0x7fd37153, 0x06ac406f), STCP(0x7fce0c3e, 0x0710a345), STCP(0x7fc85854, 0x077501be), + STCP(0x7fc25596, 0x07d95b9e), STCP(0x7fbc040a, 0x083db0a7), STCP(0x7fb563b3, 0x08a2009a), STCP(0x7fae7495, 0x09064b3a), + STCP(0x7fa736b4, 0x096a9049), STCP(0x7f9faa15, 0x09cecf89), STCP(0x7f97cebd, 0x0a3308bd), STCP(0x7f8fa4b0, 0x0a973ba5), + STCP(0x7f872bf3, 0x0afb6805), STCP(0x7f7e648c, 0x0b5f8d9f), STCP(0x7f754e80, 0x0bc3ac35), STCP(0x7f6be9d4, 0x0c27c389), + STCP(0x7f62368f, 0x0c8bd35e), STCP(0x7f5834b7, 0x0cefdb76), STCP(0x7f4de451, 0x0d53db92), STCP(0x7f434563, 0x0db7d376), + STCP(0x7f3857f6, 0x0e1bc2e4), STCP(0x7f2d1c0e, 0x0e7fa99e), STCP(0x7f2191b4, 0x0ee38766), STCP(0x7f15b8ee, 0x0f475bff), + STCP(0x7f0991c4, 0x0fab272b), STCP(0x7efd1c3c, 0x100ee8ad), STCP(0x7ef05860, 0x1072a048), STCP(0x7ee34636, 0x10d64dbd), + STCP(0x7ed5e5c6, 0x1139f0cf), STCP(0x7ec8371a, 0x119d8941), STCP(0x7eba3a39, 0x120116d5), STCP(0x7eabef2c, 0x1264994e), + STCP(0x7e9d55fc, 0x12c8106f), STCP(0x7e8e6eb2, 0x132b7bf9), STCP(0x7e7f3957, 0x138edbb1), STCP(0x7e6fb5f4, 0x13f22f58), + STCP(0x7e5fe493, 0x145576b1), STCP(0x7e4fc53e, 0x14b8b17f), STCP(0x7e3f57ff, 0x151bdf86), STCP(0x7e2e9cdf, 0x157f0086), + STCP(0x7e1d93ea, 0x15e21445), STCP(0x7e0c3d29, 0x16451a83), STCP(0x7dfa98a8, 0x16a81305), STCP(0x7de8a670, 0x170afd8d), + STCP(0x7dd6668f, 0x176dd9de), STCP(0x7dc3d90d, 0x17d0a7bc), STCP(0x7db0fdf8, 0x183366e9), STCP(0x7d9dd55a, 0x18961728), + STCP(0x7d8a5f40, 0x18f8b83c), STCP(0x7d769bb5, 0x195b49ea), STCP(0x7d628ac6, 0x19bdcbf3), STCP(0x7d4e2c7f, 0x1a203e1b), + STCP(0x7d3980ec, 0x1a82a026), STCP(0x7d24881b, 0x1ae4f1d6), STCP(0x7d0f4218, 0x1b4732ef), STCP(0x7cf9aef0, 0x1ba96335), + STCP(0x7ce3ceb2, 0x1c0b826a), STCP(0x7ccda169, 0x1c6d9053), STCP(0x7cb72724, 0x1ccf8cb3), STCP(0x7ca05ff1, 0x1d31774d), + STCP(0x7c894bde, 0x1d934fe5), STCP(0x7c71eaf9, 0x1df5163f), STCP(0x7c5a3d50, 0x1e56ca1e), STCP(0x7c4242f2, 0x1eb86b46), + STCP(0x7c29fbee, 0x1f19f97b), STCP(0x7c116853, 0x1f7b7481), STCP(0x7bf88830, 0x1fdcdc1b), STCP(0x7bdf5b94, 0x203e300d), + STCP(0x7bc5e290, 0x209f701c), STCP(0x7bac1d31, 0x21009c0c), STCP(0x7b920b89, 0x2161b3a0), STCP(0x7b77ada8, 0x21c2b69c), + STCP(0x7b5d039e, 0x2223a4c5), STCP(0x7b420d7a, 0x22847de0), STCP(0x7b26cb4f, 0x22e541af), STCP(0x7b0b3d2c, 0x2345eff8), + STCP(0x7aef6323, 0x23a6887f), STCP(0x7ad33d45, 0x24070b08), STCP(0x7ab6cba4, 0x24677758), STCP(0x7a9a0e50, 0x24c7cd33), + STCP(0x7a7d055b, 0x25280c5e), STCP(0x7a5fb0d8, 0x2588349d), STCP(0x7a4210d8, 0x25e845b6), STCP(0x7a24256f, 0x26483f6c), + STCP(0x7a05eead, 0x26a82186), STCP(0x79e76ca7, 0x2707ebc7), STCP(0x79c89f6e, 0x27679df4), STCP(0x79a98715, 0x27c737d3), + STCP(0x798a23b1, 0x2826b928), STCP(0x796a7554, 0x288621b9), STCP(0x794a7c12, 0x28e5714b), STCP(0x792a37fe, 0x2944a7a2), + STCP(0x7909a92d, 0x29a3c485), STCP(0x78e8cfb2, 0x2a02c7b8), STCP(0x78c7aba2, 0x2a61b101), STCP(0x78a63d11, 0x2ac08026), + STCP(0x78848414, 0x2b1f34eb), STCP(0x786280bf, 0x2b7dcf17), STCP(0x78403329, 0x2bdc4e6f), STCP(0x781d9b65, 0x2c3ab2b9), + STCP(0x77fab989, 0x2c98fbba), STCP(0x77d78daa, 0x2cf72939), STCP(0x77b417df, 0x2d553afc), STCP(0x7790583e, 0x2db330c7), + STCP(0x776c4edb, 0x2e110a62), STCP(0x7747fbce, 0x2e6ec792), STCP(0x77235f2d, 0x2ecc681e), STCP(0x76fe790e, 0x2f29ebcc), + STCP(0x76d94989, 0x2f875262), STCP(0x76b3d0b4, 0x2fe49ba7), STCP(0x768e0ea6, 0x3041c761), STCP(0x76680376, 0x309ed556), + STCP(0x7641af3d, 0x30fbc54d), STCP(0x761b1211, 0x3158970e), STCP(0x75f42c0b, 0x31b54a5e), STCP(0x75ccfd42, 0x3211df04), + STCP(0x75a585cf, 0x326e54c7), STCP(0x757dc5ca, 0x32caab6f), STCP(0x7555bd4c, 0x3326e2c3), STCP(0x752d6c6c, 0x3382fa88), + STCP(0x7504d345, 0x33def287), STCP(0x74dbf1ef, 0x343aca87), STCP(0x74b2c884, 0x34968250), STCP(0x7489571c, 0x34f219a8), + STCP(0x745f9dd1, 0x354d9057), STCP(0x74359cbd, 0x35a8e625), STCP(0x740b53fb, 0x36041ad9), STCP(0x73e0c3a3, 0x365f2e3b), + STCP(0x73b5ebd1, 0x36ba2014), STCP(0x738acc9e, 0x3714f02a), STCP(0x735f6626, 0x376f9e46), STCP(0x7333b883, 0x37ca2a30), + STCP(0x7307c3d0, 0x382493b0), STCP(0x72db8828, 0x387eda8e), STCP(0x72af05a7, 0x38d8fe93), STCP(0x72823c67, 0x3932ff87), + STCP(0x72552c85, 0x398cdd32), STCP(0x7227d61c, 0x39e6975e), STCP(0x71fa3949, 0x3a402dd2), STCP(0x71cc5626, 0x3a99a057), + STCP(0x719e2cd2, 0x3af2eeb7), STCP(0x716fbd68, 0x3b4c18ba), STCP(0x71410805, 0x3ba51e29), STCP(0x71120cc5, 0x3bfdfecd), + STCP(0x70e2cbc6, 0x3c56ba70), STCP(0x70b34525, 0x3caf50da), STCP(0x708378ff, 0x3d07c1d6), STCP(0x70536771, 0x3d600d2c), + STCP(0x7023109a, 0x3db832a6), STCP(0x6ff27497, 0x3e10320d), STCP(0x6fc19385, 0x3e680b2c), STCP(0x6f906d84, 0x3ebfbdcd), + STCP(0x6f5f02b2, 0x3f1749b8), STCP(0x6f2d532c, 0x3f6eaeb8), STCP(0x6efb5f12, 0x3fc5ec98), STCP(0x6ec92683, 0x401d0321), + STCP(0x6e96a99d, 0x4073f21d), STCP(0x6e63e87f, 0x40cab958), STCP(0x6e30e34a, 0x4121589b), STCP(0x6dfd9a1c, 0x4177cfb1), + STCP(0x6dca0d14, 0x41ce1e65), STCP(0x6d963c54, 0x42244481), STCP(0x6d6227fa, 0x427a41d0), STCP(0x6d2dd027, 0x42d0161e), + STCP(0x6cf934fc, 0x4325c135), STCP(0x6cc45698, 0x437b42e1), STCP(0x6c8f351c, 0x43d09aed), STCP(0x6c59d0a9, 0x4425c923), + STCP(0x6c242960, 0x447acd50), STCP(0x6bee3f62, 0x44cfa740), STCP(0x6bb812d1, 0x452456bd), STCP(0x6b81a3cd, 0x4578db93), + STCP(0x6b4af279, 0x45cd358f), STCP(0x6b13fef5, 0x4621647d), STCP(0x6adcc964, 0x46756828), STCP(0x6aa551e9, 0x46c9405c), + STCP(0x6a6d98a4, 0x471cece7), STCP(0x6a359db9, 0x47706d93), STCP(0x69fd614a, 0x47c3c22f), STCP(0x69c4e37a, 0x4816ea86), + STCP(0x698c246c, 0x4869e665), STCP(0x69532442, 0x48bcb599), STCP(0x6919e320, 0x490f57ee), STCP(0x68e06129, 0x4961cd33), + STCP(0x68a69e81, 0x49b41533), STCP(0x686c9b4b, 0x4a062fbd), STCP(0x683257ab, 0x4a581c9e), STCP(0x67f7d3c5, 0x4aa9dba2), + STCP(0x67bd0fbd, 0x4afb6c98), STCP(0x67820bb7, 0x4b4ccf4d), STCP(0x6746c7d8, 0x4b9e0390), STCP(0x670b4444, 0x4bef092d), + STCP(0x66cf8120, 0x4c3fdff4), STCP(0x66937e91, 0x4c9087b1), STCP(0x66573cbb, 0x4ce10034), STCP(0x661abbc5, 0x4d31494b), + STCP(0x65ddfbd3, 0x4d8162c4), STCP(0x65a0fd0b, 0x4dd14c6e), STCP(0x6563bf92, 0x4e210617), STCP(0x6526438f, 0x4e708f8f), + STCP(0x64e88926, 0x4ebfe8a5), STCP(0x64aa907f, 0x4f0f1126), STCP(0x646c59bf, 0x4f5e08e3), STCP(0x642de50d, 0x4faccfab), + STCP(0x63ef3290, 0x4ffb654d), STCP(0x63b0426d, 0x5049c999), STCP(0x637114cc, 0x5097fc5e), STCP(0x6331a9d4, 0x50e5fd6d), + STCP(0x62f201ac, 0x5133cc94), STCP(0x62b21c7b, 0x518169a5), STCP(0x6271fa69, 0x51ced46e), STCP(0x62319b9d, 0x521c0cc2), + STCP(0x61f1003f, 0x5269126e), STCP(0x61b02876, 0x52b5e546), STCP(0x616f146c, 0x53028518), STCP(0x612dc447, 0x534ef1b5), + STCP(0x60ec3830, 0x539b2af0), STCP(0x60aa7050, 0x53e73097), STCP(0x60686ccf, 0x5433027d), STCP(0x60262dd6, 0x547ea073), + STCP(0x5fe3b38d, 0x54ca0a4b), STCP(0x5fa0fe1f, 0x55153fd4), STCP(0x5f5e0db3, 0x556040e2), STCP(0x5f1ae274, 0x55ab0d46), + STCP(0x5ed77c8a, 0x55f5a4d2), STCP(0x5e93dc1f, 0x56400758), STCP(0x5e50015d, 0x568a34a9), STCP(0x5e0bec6e, 0x56d42c99), + STCP(0x5dc79d7c, 0x571deefa), STCP(0x5d8314b1, 0x57677b9d), STCP(0x5d3e5237, 0x57b0d256), STCP(0x5cf95638, 0x57f9f2f8), + STCP(0x5cb420e0, 0x5842dd54), STCP(0x5c6eb258, 0x588b9140), STCP(0x5c290acc, 0x58d40e8c), STCP(0x5be32a67, 0x591c550e), + STCP(0x5b9d1154, 0x59646498), STCP(0x5b56bfbd, 0x59ac3cfd), STCP(0x5b1035cf, 0x59f3de12), STCP(0x5ac973b5, 0x5a3b47ab), + STCP(0x5a82799a, 0x5a82799a) +}; + + + + + + + + + + + + + + + + + + + + + +/* generate_fft_tables.m 4 15 */ +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_STB RotVectorReal60[] = +{ + STC(0x7f4c7e54), STC(0x7d33f0ca), STC(0x79bc384d), + STC(0x7d33f0ca), STC(0x74ef0ebc), STC(0x678dde6e), + STC(0x79bc384d), STC(0x678dde6e), STC(0x4b3c8c12), + STC(0x74ef0ebc), STC(0x55a6125c), STC(0x278dde6e), + STC(0x6ed9eba1), STC(0x40000000), STC(0x00000000), + STC(0x678dde6e), STC(0x278dde6e), STC(0xd8722191), + STC(0x5f1f5ea1), STC(0x0d61304e), STC(0xb4c373ed), + STC(0x55a6125c), STC(0xf29ecfb1), STC(0x98722191), + STC(0x4b3c8c12), STC(0xd8722191), STC(0x8643c7b2), + STC(0x40000000), STC(0xbfffffff), STC(0x80000000), + STC(0x340ff242), STC(0xaa59eda3), STC(0x8643c7b2), + STC(0x278dde6e), STC(0x98722191), STC(0x98722191), + STC(0x1a9cd9ac), STC(0x8b10f143), STC(0xb4c373ed), + STC(0x0d61304e), STC(0x82cc0f35), STC(0xd8722191), +}; +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_STB RotVectorImag60[] = +{ + STC(0x0d61304e), STC(0x1a9cd9ac), STC(0x278dde6e), + STC(0x1a9cd9ac), STC(0x340ff242), STC(0x4b3c8c12), + STC(0x278dde6e), STC(0x4b3c8c12), STC(0x678dde6e), + STC(0x340ff242), STC(0x5f1f5ea1), STC(0x79bc384d), + STC(0x40000000), STC(0x6ed9eba1), STC(0x7fffffff), + STC(0x4b3c8c12), STC(0x79bc384d), STC(0x79bc384d), + STC(0x55a6125c), STC(0x7f4c7e54), STC(0x678dde6e), + STC(0x5f1f5ea1), STC(0x7f4c7e54), STC(0x4b3c8c12), + STC(0x678dde6e), STC(0x79bc384d), STC(0x278dde6e), + STC(0x6ed9eba1), STC(0x6ed9eba1), STC(0x00000000), + STC(0x74ef0ebc), STC(0x5f1f5ea1), STC(0xd8722191), + STC(0x79bc384d), STC(0x4b3c8c12), STC(0xb4c373ed), + STC(0x7d33f0ca), STC(0x340ff242), STC(0x98722191), + STC(0x7f4c7e54), STC(0x1a9cd9ac), STC(0x8643c7b2), +}; + + + +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_STB RotVectorReal240[] = +{ + STC(0x7ff4c56f), STC(0x7fd317b4), STC(0x7f9afcb9), STC(0x7f4c7e54), STC(0x7ee7aa4c), STC(0x7e6c9251), STC(0x7ddb4bfc), STC(0x7d33f0ca), STC(0x7c769e18), STC(0x7ba3751d), STC(0x7aba9ae6), STC(0x79bc384d), STC(0x78a879f4), STC(0x777f903c), STC(0x7641af3d), + STC(0x7fd317b4), STC(0x7f4c7e54), STC(0x7e6c9251), STC(0x7d33f0ca), STC(0x7ba3751d), STC(0x79bc384d), STC(0x777f903c), STC(0x74ef0ebc), STC(0x720c8075), STC(0x6ed9eba1), STC(0x6b598ea3), STC(0x678dde6e), STC(0x637984d4), STC(0x5f1f5ea1), STC(0x5a82799a), + STC(0x7f9afcb9), STC(0x7e6c9251), STC(0x7c769e18), STC(0x79bc384d), STC(0x7641af3d), STC(0x720c8075), STC(0x6d23501b), STC(0x678dde6e), STC(0x6154fb91), STC(0x5a82799a), STC(0x53211d18), STC(0x4b3c8c12), STC(0x42e13ba4), STC(0x3a1c5c57), STC(0x30fbc54d), + STC(0x7f4c7e54), STC(0x7d33f0ca), STC(0x79bc384d), STC(0x74ef0ebc), STC(0x6ed9eba1), STC(0x678dde6e), STC(0x5f1f5ea1), STC(0x55a6125c), STC(0x4b3c8c12), STC(0x40000000), STC(0x340ff242), STC(0x278dde6e), STC(0x1a9cd9ac), STC(0x0d61304e), STC(0x00000000), + STC(0x7ee7aa4c), STC(0x7ba3751d), STC(0x7641af3d), STC(0x6ed9eba1), STC(0x658c9a2d), STC(0x5a82799a), STC(0x4debe4fe), STC(0x40000000), STC(0x30fbc54d), STC(0x2120fb83), STC(0x10b5150f), STC(0x00000000), STC(0xef4aeaf0), STC(0xdedf047c), STC(0xcf043ab2), + STC(0x7e6c9251), STC(0x79bc384d), STC(0x720c8075), STC(0x678dde6e), STC(0x5a82799a), STC(0x4b3c8c12), STC(0x3a1c5c57), STC(0x278dde6e), STC(0x14060b68), STC(0x00000000), STC(0xebf9f497), STC(0xd8722191), STC(0xc5e3a3a8), STC(0xb4c373ed), STC(0xa57d8665), + STC(0x7ddb4bfc), STC(0x777f903c), STC(0x6d23501b), STC(0x5f1f5ea1), STC(0x4debe4fe), STC(0x3a1c5c57), STC(0x245a9d65), STC(0x0d61304e), STC(0xf5f50d66), STC(0xdedf047c), STC(0xc8e5032a), STC(0xb4c373ed), STC(0xa326eebf), STC(0x94a6715c), STC(0x89be50c2), + STC(0x7d33f0ca), STC(0x74ef0ebc), STC(0x678dde6e), STC(0x55a6125c), STC(0x40000000), STC(0x278dde6e), STC(0x0d61304e), STC(0xf29ecfb1), STC(0xd8722191), STC(0xbfffffff), STC(0xaa59eda3), STC(0x98722191), STC(0x8b10f143), STC(0x82cc0f35), STC(0x80000000), + STC(0x7c769e18), STC(0x720c8075), STC(0x6154fb91), STC(0x4b3c8c12), STC(0x30fbc54d), STC(0x14060b68), STC(0xf5f50d66), STC(0xd8722191), STC(0xbd1ec45b), STC(0xa57d8665), STC(0x92dcafe4), STC(0x8643c7b2), STC(0x80650346), STC(0x81936dae), STC(0x89be50c2), + STC(0x7ba3751d), STC(0x6ed9eba1), STC(0x5a82799a), STC(0x40000000), STC(0x2120fb83), STC(0x00000000), STC(0xdedf047c), STC(0xbfffffff), STC(0xa57d8665), STC(0x9126145e), STC(0x845c8ae2), STC(0x80000000), STC(0x845c8ae2), STC(0x9126145e), STC(0xa57d8665), + STC(0x7aba9ae6), STC(0x6b598ea3), STC(0x53211d18), STC(0x340ff242), STC(0x10b5150f), STC(0xebf9f497), STC(0xc8e5032a), STC(0xaa59eda3), STC(0x92dcafe4), STC(0x845c8ae2), STC(0x800b3a90), STC(0x8643c7b2), STC(0x96830875), STC(0xaf726dee), STC(0xcf043ab2), + STC(0x79bc384d), STC(0x678dde6e), STC(0x4b3c8c12), STC(0x278dde6e), STC(0x00000000), STC(0xd8722191), STC(0xb4c373ed), STC(0x98722191), STC(0x8643c7b2), STC(0x80000000), STC(0x8643c7b2), STC(0x98722191), STC(0xb4c373ed), STC(0xd8722191), STC(0xffffffff), + STC(0x78a879f4), STC(0x637984d4), STC(0x42e13ba4), STC(0x1a9cd9ac), STC(0xef4aeaf0), STC(0xc5e3a3a8), STC(0xa326eebf), STC(0x8b10f143), STC(0x80650346), STC(0x845c8ae2), STC(0x96830875), STC(0xb4c373ed), STC(0xdba5629a), STC(0x06b2f1d2), STC(0x30fbc54d), + STC(0x777f903c), STC(0x5f1f5ea1), STC(0x3a1c5c57), STC(0x0d61304e), STC(0xdedf047c), STC(0xb4c373ed), STC(0x94a6715c), STC(0x82cc0f35), STC(0x81936dae), STC(0x9126145e), STC(0xaf726dee), STC(0xd8722191), STC(0x06b2f1d2), STC(0x340ff242), STC(0x5a82799a), +}; +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_STB RotVectorImag240[] = +{ + STC(0x0359c428), STC(0x06b2f1d2), STC(0x0a0af299), STC(0x0d61304e), STC(0x10b5150f), STC(0x14060b68), STC(0x17537e63), STC(0x1a9cd9ac), STC(0x1de189a6), STC(0x2120fb83), STC(0x245a9d65), STC(0x278dde6e), STC(0x2aba2ee4), STC(0x2ddf0040), STC(0x30fbc54d), + STC(0x06b2f1d2), STC(0x0d61304e), STC(0x14060b68), STC(0x1a9cd9ac), STC(0x2120fb83), STC(0x278dde6e), STC(0x2ddf0040), STC(0x340ff242), STC(0x3a1c5c57), STC(0x40000000), STC(0x45b6bb5e), STC(0x4b3c8c12), STC(0x508d9211), STC(0x55a6125c), STC(0x5a82799a), + STC(0x0a0af299), STC(0x14060b68), STC(0x1de189a6), STC(0x278dde6e), STC(0x30fbc54d), STC(0x3a1c5c57), STC(0x42e13ba4), STC(0x4b3c8c12), STC(0x53211d18), STC(0x5a82799a), STC(0x6154fb91), STC(0x678dde6e), STC(0x6d23501b), STC(0x720c8075), STC(0x7641af3d), + STC(0x0d61304e), STC(0x1a9cd9ac), STC(0x278dde6e), STC(0x340ff242), STC(0x40000000), STC(0x4b3c8c12), STC(0x55a6125c), STC(0x5f1f5ea1), STC(0x678dde6e), STC(0x6ed9eba1), STC(0x74ef0ebc), STC(0x79bc384d), STC(0x7d33f0ca), STC(0x7f4c7e54), STC(0x7fffffff), + STC(0x10b5150f), STC(0x2120fb83), STC(0x30fbc54d), STC(0x40000000), STC(0x4debe4fe), STC(0x5a82799a), STC(0x658c9a2d), STC(0x6ed9eba1), STC(0x7641af3d), STC(0x7ba3751d), STC(0x7ee7aa4c), STC(0x7fffffff), STC(0x7ee7aa4c), STC(0x7ba3751d), STC(0x7641af3d), + STC(0x14060b68), STC(0x278dde6e), STC(0x3a1c5c57), STC(0x4b3c8c12), STC(0x5a82799a), STC(0x678dde6e), STC(0x720c8075), STC(0x79bc384d), STC(0x7e6c9251), STC(0x7fffffff), STC(0x7e6c9251), STC(0x79bc384d), STC(0x720c8075), STC(0x678dde6e), STC(0x5a82799a), + STC(0x17537e63), STC(0x2ddf0040), STC(0x42e13ba4), STC(0x55a6125c), STC(0x658c9a2d), STC(0x720c8075), STC(0x7aba9ae6), STC(0x7f4c7e54), STC(0x7f9afcb9), STC(0x7ba3751d), STC(0x7387ea23), STC(0x678dde6e), STC(0x581c00b3), STC(0x45b6bb5e), STC(0x30fbc54d), + STC(0x1a9cd9ac), STC(0x340ff242), STC(0x4b3c8c12), STC(0x5f1f5ea1), STC(0x6ed9eba1), STC(0x79bc384d), STC(0x7f4c7e54), STC(0x7f4c7e54), STC(0x79bc384d), STC(0x6ed9eba1), STC(0x5f1f5ea1), STC(0x4b3c8c12), STC(0x340ff242), STC(0x1a9cd9ac), STC(0x00000000), + STC(0x1de189a6), STC(0x3a1c5c57), STC(0x53211d18), STC(0x678dde6e), STC(0x7641af3d), STC(0x7e6c9251), STC(0x7f9afcb9), STC(0x79bc384d), STC(0x6d23501b), STC(0x5a82799a), STC(0x42e13ba4), STC(0x278dde6e), STC(0x0a0af299), STC(0xebf9f497), STC(0xcf043ab2), + STC(0x2120fb83), STC(0x40000000), STC(0x5a82799a), STC(0x6ed9eba1), STC(0x7ba3751d), STC(0x7fffffff), STC(0x7ba3751d), STC(0x6ed9eba1), STC(0x5a82799a), STC(0x40000000), STC(0x2120fb83), STC(0x00000000), STC(0xdedf047c), STC(0xbfffffff), STC(0xa57d8665), + STC(0x245a9d65), STC(0x45b6bb5e), STC(0x6154fb91), STC(0x74ef0ebc), STC(0x7ee7aa4c), STC(0x7e6c9251), STC(0x7387ea23), STC(0x5f1f5ea1), STC(0x42e13ba4), STC(0x2120fb83), STC(0xfca63bd7), STC(0xd8722191), STC(0xb780001b), STC(0x9c867b2b), STC(0x89be50c2), + STC(0x278dde6e), STC(0x4b3c8c12), STC(0x678dde6e), STC(0x79bc384d), STC(0x7fffffff), STC(0x79bc384d), STC(0x678dde6e), STC(0x4b3c8c12), STC(0x278dde6e), STC(0x00000000), STC(0xd8722191), STC(0xb4c373ed), STC(0x98722191), STC(0x8643c7b2), STC(0x80000000), + STC(0x2aba2ee4), STC(0x508d9211), STC(0x6d23501b), STC(0x7d33f0ca), STC(0x7ee7aa4c), STC(0x720c8075), STC(0x581c00b3), STC(0x340ff242), STC(0x0a0af299), STC(0xdedf047c), STC(0xb780001b), STC(0x98722191), STC(0x85456519), STC(0x802ce84b), STC(0x89be50c2), + STC(0x2ddf0040), STC(0x55a6125c), STC(0x720c8075), STC(0x7f4c7e54), STC(0x7ba3751d), STC(0x678dde6e), STC(0x45b6bb5e), STC(0x1a9cd9ac), STC(0xebf9f497), STC(0xbfffffff), STC(0x9c867b2b), STC(0x8643c7b2), STC(0x802ce84b), STC(0x8b10f143), STC(0xa57d8665), +}; + +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_STB RotVectorReal480[] = +{ + STC(0x7ffd3154), STC(0x7ff4c56f), STC(0x7fe6bcb0), STC(0x7fd317b4), STC(0x7fb9d759), STC(0x7f9afcb9), STC(0x7f76892f), STC(0x7f4c7e54), STC(0x7f1cde01), STC(0x7ee7aa4c), STC(0x7eace58a), STC(0x7e6c9251), STC(0x7e26b371), STC(0x7ddb4bfc), STC(0x7d8a5f40), STC(0x7d33f0ca), STC(0x7cd80464), STC(0x7c769e18), STC(0x7c0fc22a), STC(0x7ba3751d), STC(0x7b31bbb2), STC(0x7aba9ae6), STC(0x7a3e17f2), STC(0x79bc384d), STC(0x793501a9), STC(0x78a879f4), STC(0x7816a759), STC(0x777f903c), STC(0x76e33b3f), STC(0x7641af3d), STC(0x759af34c), + STC(0x7ff4c56f), STC(0x7fd317b4), STC(0x7f9afcb9), STC(0x7f4c7e54), STC(0x7ee7aa4c), STC(0x7e6c9251), STC(0x7ddb4bfc), STC(0x7d33f0ca), STC(0x7c769e18), STC(0x7ba3751d), STC(0x7aba9ae6), STC(0x79bc384d), STC(0x78a879f4), STC(0x777f903c), STC(0x7641af3d), STC(0x74ef0ebc), STC(0x7387ea23), STC(0x720c8075), STC(0x707d1443), STC(0x6ed9eba1), STC(0x6d23501b), STC(0x6b598ea3), STC(0x697cf78a), STC(0x678dde6e), STC(0x658c9a2d), STC(0x637984d4), STC(0x6154fb91), STC(0x5f1f5ea1), STC(0x5cd91140), STC(0x5a82799a), STC(0x581c00b3), + STC(0x7fe6bcb0), STC(0x7f9afcb9), STC(0x7f1cde01), STC(0x7e6c9251), STC(0x7d8a5f40), STC(0x7c769e18), STC(0x7b31bbb2), STC(0x79bc384d), STC(0x7816a759), STC(0x7641af3d), STC(0x743e0918), STC(0x720c8075), STC(0x6fadf2fc), STC(0x6d23501b), STC(0x6a6d98a4), STC(0x678dde6e), STC(0x648543e4), STC(0x6154fb91), STC(0x5dfe47ad), STC(0x5a82799a), STC(0x56e2f15d), STC(0x53211d18), STC(0x4f3e7875), STC(0x4b3c8c12), STC(0x471cece7), STC(0x42e13ba4), STC(0x3e8b240e), STC(0x3a1c5c57), STC(0x3596a46c), STC(0x30fbc54d), STC(0x2c4d9050), + STC(0x7fd317b4), STC(0x7f4c7e54), STC(0x7e6c9251), STC(0x7d33f0ca), STC(0x7ba3751d), STC(0x79bc384d), STC(0x777f903c), STC(0x74ef0ebc), STC(0x720c8075), STC(0x6ed9eba1), STC(0x6b598ea3), STC(0x678dde6e), STC(0x637984d4), STC(0x5f1f5ea1), STC(0x5a82799a), STC(0x55a6125c), STC(0x508d9211), STC(0x4b3c8c12), STC(0x45b6bb5e), STC(0x40000000), STC(0x3a1c5c57), STC(0x340ff242), STC(0x2ddf0040), STC(0x278dde6e), STC(0x2120fb83), STC(0x1a9cd9ac), STC(0x14060b68), STC(0x0d61304e), STC(0x06b2f1d2), STC(0x00000000), STC(0xf94d0e2d), + STC(0x7fb9d759), STC(0x7ee7aa4c), STC(0x7d8a5f40), STC(0x7ba3751d), STC(0x793501a9), STC(0x7641af3d), STC(0x72ccb9db), STC(0x6ed9eba1), STC(0x6a6d98a4), STC(0x658c9a2d), STC(0x603c496c), STC(0x5a82799a), STC(0x54657194), STC(0x4debe4fe), STC(0x471cece7), STC(0x40000000), STC(0x389cea72), STC(0x30fbc54d), STC(0x2924edac), STC(0x2120fb83), STC(0x18f8b83c), STC(0x10b5150f), STC(0x085f2137), STC(0x00000000), STC(0xf7a0dec8), STC(0xef4aeaf0), STC(0xe70747c3), STC(0xdedf047c), STC(0xd6db1253), STC(0xcf043ab2), STC(0xc763158d), + STC(0x7f9afcb9), STC(0x7e6c9251), STC(0x7c769e18), STC(0x79bc384d), STC(0x7641af3d), STC(0x720c8075), STC(0x6d23501b), STC(0x678dde6e), STC(0x6154fb91), STC(0x5a82799a), STC(0x53211d18), STC(0x4b3c8c12), STC(0x42e13ba4), STC(0x3a1c5c57), STC(0x30fbc54d), STC(0x278dde6e), STC(0x1de189a6), STC(0x14060b68), STC(0x0a0af299), STC(0x00000000), STC(0xf5f50d66), STC(0xebf9f497), STC(0xe21e7659), STC(0xd8722191), STC(0xcf043ab2), STC(0xc5e3a3a8), STC(0xbd1ec45b), STC(0xb4c373ed), STC(0xacdee2e7), STC(0xa57d8665), STC(0x9eab046e), + STC(0x7f76892f), STC(0x7ddb4bfc), STC(0x7b31bbb2), STC(0x777f903c), STC(0x72ccb9db), STC(0x6d23501b), STC(0x668f7c25), STC(0x5f1f5ea1), STC(0x56e2f15d), STC(0x4debe4fe), STC(0x444d7aff), STC(0x3a1c5c57), STC(0x2f6e6d16), STC(0x245a9d65), STC(0x18f8b83c), STC(0x0d61304e), STC(0x01aceb7c), STC(0xf5f50d66), STC(0xea52c165), STC(0xdedf047c), STC(0xd3b26faf), STC(0xc8e5032a), STC(0xbe8df2b9), STC(0xb4c373ed), STC(0xab9a8e6b), STC(0xa326eebf), STC(0x9b7abc1b), STC(0x94a6715c), STC(0x8eb8b99f), STC(0x89be50c2), STC(0x85c1e80d), + STC(0x7f4c7e54), STC(0x7d33f0ca), STC(0x79bc384d), STC(0x74ef0ebc), STC(0x6ed9eba1), STC(0x678dde6e), STC(0x5f1f5ea1), STC(0x55a6125c), STC(0x4b3c8c12), STC(0x40000000), STC(0x340ff242), STC(0x278dde6e), STC(0x1a9cd9ac), STC(0x0d61304e), STC(0x00000000), STC(0xf29ecfb1), STC(0xe5632653), STC(0xd8722191), STC(0xcbf00dbd), STC(0xbfffffff), STC(0xb4c373ed), STC(0xaa59eda3), STC(0xa0e0a15e), STC(0x98722191), STC(0x9126145e), STC(0x8b10f143), STC(0x8643c7b2), STC(0x82cc0f35), STC(0x80b381ab), STC(0x80000000), STC(0x80b381ab), + STC(0x7f1cde01), STC(0x7c769e18), STC(0x7816a759), STC(0x720c8075), STC(0x6a6d98a4), STC(0x6154fb91), STC(0x56e2f15d), STC(0x4b3c8c12), STC(0x3e8b240e), STC(0x30fbc54d), STC(0x22be8f87), STC(0x14060b68), STC(0x05067734), STC(0xf5f50d66), STC(0xe70747c3), STC(0xd8722191), STC(0xca695b93), STC(0xbd1ec45b), STC(0xb0c1878a), STC(0xa57d8665), STC(0x9b7abc1b), STC(0x92dcafe4), STC(0x8bc1f6e7), STC(0x8643c7b2), STC(0x8275a0bf), STC(0x80650346), STC(0x8019434f), STC(0x81936dae), STC(0x84ce444d), STC(0x89be50c2), STC(0x90520d03), + STC(0x7ee7aa4c), STC(0x7ba3751d), STC(0x7641af3d), STC(0x6ed9eba1), STC(0x658c9a2d), STC(0x5a82799a), STC(0x4debe4fe), STC(0x40000000), STC(0x30fbc54d), STC(0x2120fb83), STC(0x10b5150f), STC(0x00000000), STC(0xef4aeaf0), STC(0xdedf047c), STC(0xcf043ab2), STC(0xbfffffff), STC(0xb2141b01), STC(0xa57d8665), STC(0x9a7365d2), STC(0x9126145e), STC(0x89be50c2), STC(0x845c8ae2), STC(0x811855b3), STC(0x80000000), STC(0x811855b3), STC(0x845c8ae2), STC(0x89be50c2), STC(0x9126145e), STC(0x9a7365d2), STC(0xa57d8665), STC(0xb2141b01), + STC(0x7eace58a), STC(0x7aba9ae6), STC(0x743e0918), STC(0x6b598ea3), STC(0x603c496c), STC(0x53211d18), STC(0x444d7aff), STC(0x340ff242), STC(0x22be8f87), STC(0x10b5150f), STC(0xfe531483), STC(0xebf9f497), STC(0xda0aecf8), STC(0xc8e5032a), STC(0xb8e31318), STC(0xaa59eda3), STC(0x9d969741), STC(0x92dcafe4), STC(0x8a650cb3), STC(0x845c8ae2), STC(0x80e321fe), STC(0x800b3a90), STC(0x81d94c8e), STC(0x8643c7b2), STC(0x8d334624), STC(0x96830875), STC(0xa201b852), STC(0xaf726dee), STC(0xbe8df2b9), STC(0xcf043ab2), STC(0xe07e0c83), + STC(0x7e6c9251), STC(0x79bc384d), STC(0x720c8075), STC(0x678dde6e), STC(0x5a82799a), STC(0x4b3c8c12), STC(0x3a1c5c57), STC(0x278dde6e), STC(0x14060b68), STC(0x00000000), STC(0xebf9f497), STC(0xd8722191), STC(0xc5e3a3a8), STC(0xb4c373ed), STC(0xa57d8665), STC(0x98722191), STC(0x8df37f8a), STC(0x8643c7b2), STC(0x81936dae), STC(0x80000000), STC(0x81936dae), STC(0x8643c7b2), STC(0x8df37f8a), STC(0x98722191), STC(0xa57d8665), STC(0xb4c373ed), STC(0xc5e3a3a8), STC(0xd8722191), STC(0xebf9f497), STC(0xffffffff), STC(0x14060b68), + STC(0x7e26b371), STC(0x78a879f4), STC(0x6fadf2fc), STC(0x637984d4), STC(0x54657194), STC(0x42e13ba4), STC(0x2f6e6d16), STC(0x1a9cd9ac), STC(0x05067734), STC(0xef4aeaf0), STC(0xda0aecf8), STC(0xc5e3a3a8), STC(0xb36a1977), STC(0xa326eebf), STC(0x9592675b), STC(0x8b10f143), STC(0x83f03dd5), STC(0x80650346), STC(0x808976d0), STC(0x845c8ae2), STC(0x8bc1f6e7), STC(0x96830875), STC(0xa45037c8), STC(0xb4c373ed), STC(0xc763158d), STC(0xdba5629a), STC(0xf0f488d8), STC(0x06b2f1d2), STC(0x1c3fd045), STC(0x30fbc54d), STC(0x444d7aff), + STC(0x7ddb4bfc), STC(0x777f903c), STC(0x6d23501b), STC(0x5f1f5ea1), STC(0x4debe4fe), STC(0x3a1c5c57), STC(0x245a9d65), STC(0x0d61304e), STC(0xf5f50d66), STC(0xdedf047c), STC(0xc8e5032a), STC(0xb4c373ed), STC(0xa326eebf), STC(0x94a6715c), STC(0x89be50c2), STC(0x82cc0f35), STC(0x800b3a90), STC(0x81936dae), STC(0x8757860b), STC(0x9126145e), STC(0x9eab046e), STC(0xaf726dee), STC(0xc2ec7634), STC(0xd8722191), STC(0xef4aeaf0), STC(0x06b2f1d2), STC(0x1de189a6), STC(0x340ff242), STC(0x487fffe4), STC(0x5a82799a), STC(0x697cf78a), +}; +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_STB RotVectorImag480[] = +{ + STC(0x01aceb7c), STC(0x0359c428), STC(0x05067734), STC(0x06b2f1d2), STC(0x085f2137), STC(0x0a0af299), STC(0x0bb65336), STC(0x0d61304e), STC(0x0f0b7727), STC(0x10b5150f), STC(0x125df75b), STC(0x14060b68), STC(0x15ad3e9a), STC(0x17537e63), STC(0x18f8b83c), STC(0x1a9cd9ac), STC(0x1c3fd045), STC(0x1de189a6), STC(0x1f81f37c), STC(0x2120fb83), STC(0x22be8f87), STC(0x245a9d65), STC(0x25f51307), STC(0x278dde6e), STC(0x2924edac), STC(0x2aba2ee4), STC(0x2c4d9050), STC(0x2ddf0040), STC(0x2f6e6d16), STC(0x30fbc54d), STC(0x3286f779), + STC(0x0359c428), STC(0x06b2f1d2), STC(0x0a0af299), STC(0x0d61304e), STC(0x10b5150f), STC(0x14060b68), STC(0x17537e63), STC(0x1a9cd9ac), STC(0x1de189a6), STC(0x2120fb83), STC(0x245a9d65), STC(0x278dde6e), STC(0x2aba2ee4), STC(0x2ddf0040), STC(0x30fbc54d), STC(0x340ff242), STC(0x371afcd5), STC(0x3a1c5c57), STC(0x3d1389cb), STC(0x40000000), STC(0x42e13ba4), STC(0x45b6bb5e), STC(0x487fffe4), STC(0x4b3c8c12), STC(0x4debe4fe), STC(0x508d9211), STC(0x53211d18), STC(0x55a6125c), STC(0x581c00b3), STC(0x5a82799a), STC(0x5cd91140), + STC(0x05067734), STC(0x0a0af299), STC(0x0f0b7727), STC(0x14060b68), STC(0x18f8b83c), STC(0x1de189a6), STC(0x22be8f87), STC(0x278dde6e), STC(0x2c4d9050), STC(0x30fbc54d), STC(0x3596a46c), STC(0x3a1c5c57), STC(0x3e8b240e), STC(0x42e13ba4), STC(0x471cece7), STC(0x4b3c8c12), STC(0x4f3e7875), STC(0x53211d18), STC(0x56e2f15d), STC(0x5a82799a), STC(0x5dfe47ad), STC(0x6154fb91), STC(0x648543e4), STC(0x678dde6e), STC(0x6a6d98a4), STC(0x6d23501b), STC(0x6fadf2fc), STC(0x720c8075), STC(0x743e0918), STC(0x7641af3d), STC(0x7816a759), + STC(0x06b2f1d2), STC(0x0d61304e), STC(0x14060b68), STC(0x1a9cd9ac), STC(0x2120fb83), STC(0x278dde6e), STC(0x2ddf0040), STC(0x340ff242), STC(0x3a1c5c57), STC(0x40000000), STC(0x45b6bb5e), STC(0x4b3c8c12), STC(0x508d9211), STC(0x55a6125c), STC(0x5a82799a), STC(0x5f1f5ea1), STC(0x637984d4), STC(0x678dde6e), STC(0x6b598ea3), STC(0x6ed9eba1), STC(0x720c8075), STC(0x74ef0ebc), STC(0x777f903c), STC(0x79bc384d), STC(0x7ba3751d), STC(0x7d33f0ca), STC(0x7e6c9251), STC(0x7f4c7e54), STC(0x7fd317b4), STC(0x7fffffff), STC(0x7fd317b4), + STC(0x085f2137), STC(0x10b5150f), STC(0x18f8b83c), STC(0x2120fb83), STC(0x2924edac), STC(0x30fbc54d), STC(0x389cea72), STC(0x40000000), STC(0x471cece7), STC(0x4debe4fe), STC(0x54657194), STC(0x5a82799a), STC(0x603c496c), STC(0x658c9a2d), STC(0x6a6d98a4), STC(0x6ed9eba1), STC(0x72ccb9db), STC(0x7641af3d), STC(0x793501a9), STC(0x7ba3751d), STC(0x7d8a5f40), STC(0x7ee7aa4c), STC(0x7fb9d759), STC(0x7fffffff), STC(0x7fb9d759), STC(0x7ee7aa4c), STC(0x7d8a5f40), STC(0x7ba3751d), STC(0x793501a9), STC(0x7641af3d), STC(0x72ccb9db), + STC(0x0a0af299), STC(0x14060b68), STC(0x1de189a6), STC(0x278dde6e), STC(0x30fbc54d), STC(0x3a1c5c57), STC(0x42e13ba4), STC(0x4b3c8c12), STC(0x53211d18), STC(0x5a82799a), STC(0x6154fb91), STC(0x678dde6e), STC(0x6d23501b), STC(0x720c8075), STC(0x7641af3d), STC(0x79bc384d), STC(0x7c769e18), STC(0x7e6c9251), STC(0x7f9afcb9), STC(0x7fffffff), STC(0x7f9afcb9), STC(0x7e6c9251), STC(0x7c769e18), STC(0x79bc384d), STC(0x7641af3d), STC(0x720c8075), STC(0x6d23501b), STC(0x678dde6e), STC(0x6154fb91), STC(0x5a82799a), STC(0x53211d18), + STC(0x0bb65336), STC(0x17537e63), STC(0x22be8f87), STC(0x2ddf0040), STC(0x389cea72), STC(0x42e13ba4), STC(0x4c95e688), STC(0x55a6125c), STC(0x5dfe47ad), STC(0x658c9a2d), STC(0x6c40cf2c), STC(0x720c8075), STC(0x76e33b3f), STC(0x7aba9ae6), STC(0x7d8a5f40), STC(0x7f4c7e54), STC(0x7ffd3154), STC(0x7f9afcb9), STC(0x7e26b371), STC(0x7ba3751d), STC(0x7816a759), STC(0x7387ea23), STC(0x6e010780), STC(0x678dde6e), STC(0x603c496c), STC(0x581c00b3), STC(0x4f3e7875), STC(0x45b6bb5e), STC(0x3b9941b1), STC(0x30fbc54d), STC(0x25f51307), + STC(0x0d61304e), STC(0x1a9cd9ac), STC(0x278dde6e), STC(0x340ff242), STC(0x40000000), STC(0x4b3c8c12), STC(0x55a6125c), STC(0x5f1f5ea1), STC(0x678dde6e), STC(0x6ed9eba1), STC(0x74ef0ebc), STC(0x79bc384d), STC(0x7d33f0ca), STC(0x7f4c7e54), STC(0x7fffffff), STC(0x7f4c7e54), STC(0x7d33f0ca), STC(0x79bc384d), STC(0x74ef0ebc), STC(0x6ed9eba1), STC(0x678dde6e), STC(0x5f1f5ea1), STC(0x55a6125c), STC(0x4b3c8c12), STC(0x40000000), STC(0x340ff242), STC(0x278dde6e), STC(0x1a9cd9ac), STC(0x0d61304e), STC(0x00000000), STC(0xf29ecfb1), + STC(0x0f0b7727), STC(0x1de189a6), STC(0x2c4d9050), STC(0x3a1c5c57), STC(0x471cece7), STC(0x53211d18), STC(0x5dfe47ad), STC(0x678dde6e), STC(0x6fadf2fc), STC(0x7641af3d), STC(0x7b31bbb2), STC(0x7e6c9251), STC(0x7fe6bcb0), STC(0x7f9afcb9), STC(0x7d8a5f40), STC(0x79bc384d), STC(0x743e0918), STC(0x6d23501b), STC(0x648543e4), STC(0x5a82799a), STC(0x4f3e7875), STC(0x42e13ba4), STC(0x3596a46c), STC(0x278dde6e), STC(0x18f8b83c), STC(0x0a0af299), STC(0xfaf988cb), STC(0xebf9f497), STC(0xdd417078), STC(0xcf043ab2), STC(0xc174dbf1), + STC(0x10b5150f), STC(0x2120fb83), STC(0x30fbc54d), STC(0x40000000), STC(0x4debe4fe), STC(0x5a82799a), STC(0x658c9a2d), STC(0x6ed9eba1), STC(0x7641af3d), STC(0x7ba3751d), STC(0x7ee7aa4c), STC(0x7fffffff), STC(0x7ee7aa4c), STC(0x7ba3751d), STC(0x7641af3d), STC(0x6ed9eba1), STC(0x658c9a2d), STC(0x5a82799a), STC(0x4debe4fe), STC(0x40000000), STC(0x30fbc54d), STC(0x2120fb83), STC(0x10b5150f), STC(0x00000000), STC(0xef4aeaf0), STC(0xdedf047c), STC(0xcf043ab2), STC(0xbfffffff), STC(0xb2141b01), STC(0xa57d8665), STC(0x9a7365d2), + STC(0x125df75b), STC(0x245a9d65), STC(0x3596a46c), STC(0x45b6bb5e), STC(0x54657194), STC(0x6154fb91), STC(0x6c40cf2c), STC(0x74ef0ebc), STC(0x7b31bbb2), STC(0x7ee7aa4c), STC(0x7ffd3154), STC(0x7e6c9251), STC(0x7a3e17f2), STC(0x7387ea23), STC(0x6a6d98a4), STC(0x5f1f5ea1), STC(0x51d92321), STC(0x42e13ba4), STC(0x3286f779), STC(0x2120fb83), STC(0x0f0b7727), STC(0xfca63bd7), STC(0xea52c165), STC(0xd8722191), STC(0xc763158d), STC(0xb780001b), STC(0xa91d0ea2), STC(0x9c867b2b), STC(0x91fef87f), STC(0x89be50c2), STC(0x83f03dd5), + STC(0x14060b68), STC(0x278dde6e), STC(0x3a1c5c57), STC(0x4b3c8c12), STC(0x5a82799a), STC(0x678dde6e), STC(0x720c8075), STC(0x79bc384d), STC(0x7e6c9251), STC(0x7fffffff), STC(0x7e6c9251), STC(0x79bc384d), STC(0x720c8075), STC(0x678dde6e), STC(0x5a82799a), STC(0x4b3c8c12), STC(0x3a1c5c57), STC(0x278dde6e), STC(0x14060b68), STC(0x00000000), STC(0xebf9f497), STC(0xd8722191), STC(0xc5e3a3a8), STC(0xb4c373ed), STC(0xa57d8665), STC(0x98722191), STC(0x8df37f8a), STC(0x8643c7b2), STC(0x81936dae), STC(0x80000000), STC(0x81936dae), + STC(0x15ad3e9a), STC(0x2aba2ee4), STC(0x3e8b240e), STC(0x508d9211), STC(0x603c496c), STC(0x6d23501b), STC(0x76e33b3f), STC(0x7d33f0ca), STC(0x7fe6bcb0), STC(0x7ee7aa4c), STC(0x7a3e17f2), STC(0x720c8075), STC(0x668f7c25), STC(0x581c00b3), STC(0x471cece7), STC(0x340ff242), STC(0x1f81f37c), STC(0x0a0af299), STC(0xf449acc9), STC(0xdedf047c), STC(0xca695b93), STC(0xb780001b), STC(0xa6aecd5d), STC(0x98722191), STC(0x8d334624), STC(0x85456519), STC(0x80e321fe), STC(0x802ce84b), STC(0x8327fb9b), STC(0x89be50c2), STC(0x93bf30d3), + STC(0x17537e63), STC(0x2ddf0040), STC(0x42e13ba4), STC(0x55a6125c), STC(0x658c9a2d), STC(0x720c8075), STC(0x7aba9ae6), STC(0x7f4c7e54), STC(0x7f9afcb9), STC(0x7ba3751d), STC(0x7387ea23), STC(0x678dde6e), STC(0x581c00b3), STC(0x45b6bb5e), STC(0x30fbc54d), STC(0x1a9cd9ac), STC(0x0359c428), STC(0xebf9f497), STC(0xd545d11b), STC(0xbfffffff), STC(0xacdee2e7), STC(0x9c867b2b), STC(0x8f82ebbc), STC(0x8643c7b2), STC(0x811855b3), STC(0x802ce84b), STC(0x838961e7), STC(0x8b10f143), STC(0x96830875), STC(0xa57d8665), STC(0xb780001b), +}; + + +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_WTP SineWindow1024[] = +{ + WTCP(0x7ffffd88, 0x001921fb), WTCP(0x7fffe9cb, 0x004b65ee), WTCP(0x7fffc251, 0x007da9d4), WTCP(0x7fff8719, 0x00afeda8), + WTCP(0x7fff3824, 0x00e23160), WTCP(0x7ffed572, 0x011474f6), WTCP(0x7ffe5f03, 0x0146b860), WTCP(0x7ffdd4d7, 0x0178fb99), + WTCP(0x7ffd36ee, 0x01ab3e97), WTCP(0x7ffc8549, 0x01dd8154), WTCP(0x7ffbbfe6, 0x020fc3c6), WTCP(0x7ffae6c7, 0x024205e8), + WTCP(0x7ff9f9ec, 0x027447b0), WTCP(0x7ff8f954, 0x02a68917), WTCP(0x7ff7e500, 0x02d8ca16), WTCP(0x7ff6bcf0, 0x030b0aa4), + WTCP(0x7ff58125, 0x033d4abb), WTCP(0x7ff4319d, 0x036f8a51), WTCP(0x7ff2ce5b, 0x03a1c960), WTCP(0x7ff1575d, 0x03d407df), + WTCP(0x7fefcca4, 0x040645c7), WTCP(0x7fee2e30, 0x04388310), WTCP(0x7fec7c02, 0x046abfb3), WTCP(0x7feab61a, 0x049cfba7), + WTCP(0x7fe8dc78, 0x04cf36e5), WTCP(0x7fe6ef1c, 0x05017165), WTCP(0x7fe4ee06, 0x0533ab20), WTCP(0x7fe2d938, 0x0565e40d), + WTCP(0x7fe0b0b1, 0x05981c26), WTCP(0x7fde7471, 0x05ca5361), WTCP(0x7fdc247a, 0x05fc89b8), WTCP(0x7fd9c0ca, 0x062ebf22), + WTCP(0x7fd74964, 0x0660f398), WTCP(0x7fd4be46, 0x06932713), WTCP(0x7fd21f72, 0x06c5598a), WTCP(0x7fcf6ce8, 0x06f78af6), + WTCP(0x7fcca6a7, 0x0729bb4e), WTCP(0x7fc9ccb2, 0x075bea8c), WTCP(0x7fc6df08, 0x078e18a7), WTCP(0x7fc3dda9, 0x07c04598), + WTCP(0x7fc0c896, 0x07f27157), WTCP(0x7fbd9fd0, 0x08249bdd), WTCP(0x7fba6357, 0x0856c520), WTCP(0x7fb7132b, 0x0888ed1b), + WTCP(0x7fb3af4e, 0x08bb13c5), WTCP(0x7fb037bf, 0x08ed3916), WTCP(0x7facac7f, 0x091f5d06), WTCP(0x7fa90d8e, 0x09517f8f), + WTCP(0x7fa55aee, 0x0983a0a7), WTCP(0x7fa1949e, 0x09b5c048), WTCP(0x7f9dbaa0, 0x09e7de6a), WTCP(0x7f99ccf4, 0x0a19fb04), + WTCP(0x7f95cb9a, 0x0a4c1610), WTCP(0x7f91b694, 0x0a7e2f85), WTCP(0x7f8d8de1, 0x0ab0475c), WTCP(0x7f895182, 0x0ae25d8d), + WTCP(0x7f850179, 0x0b147211), WTCP(0x7f809dc5, 0x0b4684df), WTCP(0x7f7c2668, 0x0b7895f0), WTCP(0x7f779b62, 0x0baaa53b), + WTCP(0x7f72fcb4, 0x0bdcb2bb), WTCP(0x7f6e4a5e, 0x0c0ebe66), WTCP(0x7f698461, 0x0c40c835), WTCP(0x7f64aabf, 0x0c72d020), + WTCP(0x7f5fbd77, 0x0ca4d620), WTCP(0x7f5abc8a, 0x0cd6da2d), WTCP(0x7f55a7fa, 0x0d08dc3f), WTCP(0x7f507fc7, 0x0d3adc4e), + WTCP(0x7f4b43f2, 0x0d6cda53), WTCP(0x7f45f47b, 0x0d9ed646), WTCP(0x7f409164, 0x0dd0d01f), WTCP(0x7f3b1aad, 0x0e02c7d7), + WTCP(0x7f359057, 0x0e34bd66), WTCP(0x7f2ff263, 0x0e66b0c3), WTCP(0x7f2a40d2, 0x0e98a1e9), WTCP(0x7f247ba5, 0x0eca90ce), + WTCP(0x7f1ea2dc, 0x0efc7d6b), WTCP(0x7f18b679, 0x0f2e67b8), WTCP(0x7f12b67c, 0x0f604faf), WTCP(0x7f0ca2e7, 0x0f923546), + WTCP(0x7f067bba, 0x0fc41876), WTCP(0x7f0040f6, 0x0ff5f938), WTCP(0x7ef9f29d, 0x1027d784), WTCP(0x7ef390ae, 0x1059b352), + WTCP(0x7eed1b2c, 0x108b8c9b), WTCP(0x7ee69217, 0x10bd6356), WTCP(0x7edff570, 0x10ef377d), WTCP(0x7ed94538, 0x11210907), + WTCP(0x7ed28171, 0x1152d7ed), WTCP(0x7ecbaa1a, 0x1184a427), WTCP(0x7ec4bf36, 0x11b66dad), WTCP(0x7ebdc0c6, 0x11e83478), + WTCP(0x7eb6aeca, 0x1219f880), WTCP(0x7eaf8943, 0x124bb9be), WTCP(0x7ea85033, 0x127d7829), WTCP(0x7ea1039b, 0x12af33ba), + WTCP(0x7e99a37c, 0x12e0ec6a), WTCP(0x7e922fd6, 0x1312a230), WTCP(0x7e8aa8ac, 0x13445505), WTCP(0x7e830dff, 0x137604e2), + WTCP(0x7e7b5fce, 0x13a7b1bf), WTCP(0x7e739e1d, 0x13d95b93), WTCP(0x7e6bc8eb, 0x140b0258), WTCP(0x7e63e03b, 0x143ca605), + WTCP(0x7e5be40c, 0x146e4694), WTCP(0x7e53d462, 0x149fe3fc), WTCP(0x7e4bb13c, 0x14d17e36), WTCP(0x7e437a9c, 0x1503153a), + WTCP(0x7e3b3083, 0x1534a901), WTCP(0x7e32d2f4, 0x15663982), WTCP(0x7e2a61ed, 0x1597c6b7), WTCP(0x7e21dd73, 0x15c95097), + WTCP(0x7e194584, 0x15fad71b), WTCP(0x7e109a24, 0x162c5a3b), WTCP(0x7e07db52, 0x165dd9f0), WTCP(0x7dff0911, 0x168f5632), + WTCP(0x7df62362, 0x16c0cef9), WTCP(0x7ded2a47, 0x16f2443e), WTCP(0x7de41dc0, 0x1723b5f9), WTCP(0x7ddafdce, 0x17552422), + WTCP(0x7dd1ca75, 0x17868eb3), WTCP(0x7dc883b4, 0x17b7f5a3), WTCP(0x7dbf298d, 0x17e958ea), WTCP(0x7db5bc02, 0x181ab881), + WTCP(0x7dac3b15, 0x184c1461), WTCP(0x7da2a6c6, 0x187d6c82), WTCP(0x7d98ff17, 0x18aec0db), WTCP(0x7d8f4409, 0x18e01167), + WTCP(0x7d85759f, 0x19115e1c), WTCP(0x7d7b93da, 0x1942a6f3), WTCP(0x7d719eba, 0x1973ebe6), WTCP(0x7d679642, 0x19a52ceb), + WTCP(0x7d5d7a74, 0x19d669fc), WTCP(0x7d534b50, 0x1a07a311), WTCP(0x7d4908d9, 0x1a38d823), WTCP(0x7d3eb30f, 0x1a6a0929), + WTCP(0x7d3449f5, 0x1a9b361d), WTCP(0x7d29cd8c, 0x1acc5ef6), WTCP(0x7d1f3dd6, 0x1afd83ad), WTCP(0x7d149ad5, 0x1b2ea43a), + WTCP(0x7d09e489, 0x1b5fc097), WTCP(0x7cff1af5, 0x1b90d8bb), WTCP(0x7cf43e1a, 0x1bc1ec9e), WTCP(0x7ce94dfb, 0x1bf2fc3a), + WTCP(0x7cde4a98, 0x1c240786), WTCP(0x7cd333f3, 0x1c550e7c), WTCP(0x7cc80a0f, 0x1c861113), WTCP(0x7cbcccec, 0x1cb70f43), + WTCP(0x7cb17c8d, 0x1ce80906), WTCP(0x7ca618f3, 0x1d18fe54), WTCP(0x7c9aa221, 0x1d49ef26), WTCP(0x7c8f1817, 0x1d7adb73), + WTCP(0x7c837ad8, 0x1dabc334), WTCP(0x7c77ca65, 0x1ddca662), WTCP(0x7c6c06c0, 0x1e0d84f5), WTCP(0x7c602fec, 0x1e3e5ee5), + WTCP(0x7c5445e9, 0x1e6f342c), WTCP(0x7c4848ba, 0x1ea004c1), WTCP(0x7c3c3860, 0x1ed0d09d), WTCP(0x7c3014de, 0x1f0197b8), + WTCP(0x7c23de35, 0x1f325a0b), WTCP(0x7c179467, 0x1f63178f), WTCP(0x7c0b3777, 0x1f93d03c), WTCP(0x7bfec765, 0x1fc4840a), + WTCP(0x7bf24434, 0x1ff532f2), WTCP(0x7be5ade6, 0x2025dcec), WTCP(0x7bd9047c, 0x205681f1), WTCP(0x7bcc47fa, 0x208721f9), + WTCP(0x7bbf7860, 0x20b7bcfe), WTCP(0x7bb295b0, 0x20e852f6), WTCP(0x7ba59fee, 0x2118e3dc), WTCP(0x7b989719, 0x21496fa7), + WTCP(0x7b8b7b36, 0x2179f64f), WTCP(0x7b7e4c45, 0x21aa77cf), WTCP(0x7b710a49, 0x21daf41d), WTCP(0x7b63b543, 0x220b6b32), + WTCP(0x7b564d36, 0x223bdd08), WTCP(0x7b48d225, 0x226c4996), WTCP(0x7b3b4410, 0x229cb0d5), WTCP(0x7b2da2fa, 0x22cd12bd), + WTCP(0x7b1feee5, 0x22fd6f48), WTCP(0x7b1227d3, 0x232dc66d), WTCP(0x7b044dc7, 0x235e1826), WTCP(0x7af660c2, 0x238e646a), + WTCP(0x7ae860c7, 0x23beab33), WTCP(0x7ada4dd8, 0x23eeec78), WTCP(0x7acc27f7, 0x241f2833), WTCP(0x7abdef25, 0x244f5e5c), + WTCP(0x7aafa367, 0x247f8eec), WTCP(0x7aa144bc, 0x24afb9da), WTCP(0x7a92d329, 0x24dfdf20), WTCP(0x7a844eae, 0x250ffeb7), + WTCP(0x7a75b74f, 0x25401896), WTCP(0x7a670d0d, 0x25702cb7), WTCP(0x7a584feb, 0x25a03b11), WTCP(0x7a497feb, 0x25d0439f), + WTCP(0x7a3a9d0f, 0x26004657), WTCP(0x7a2ba75a, 0x26304333), WTCP(0x7a1c9ece, 0x26603a2c), WTCP(0x7a0d836d, 0x26902b39), + WTCP(0x79fe5539, 0x26c01655), WTCP(0x79ef1436, 0x26effb76), WTCP(0x79dfc064, 0x271fda96), WTCP(0x79d059c8, 0x274fb3ae), + WTCP(0x79c0e062, 0x277f86b5), WTCP(0x79b15435, 0x27af53a6), WTCP(0x79a1b545, 0x27df1a77), WTCP(0x79920392, 0x280edb23), + WTCP(0x79823f20, 0x283e95a1), WTCP(0x797267f2, 0x286e49ea), WTCP(0x79627e08, 0x289df7f8), WTCP(0x79528167, 0x28cd9fc1), + WTCP(0x79427210, 0x28fd4140), WTCP(0x79325006, 0x292cdc6d), WTCP(0x79221b4b, 0x295c7140), WTCP(0x7911d3e2, 0x298bffb2), + WTCP(0x790179cd, 0x29bb87bc), WTCP(0x78f10d0f, 0x29eb0957), WTCP(0x78e08dab, 0x2a1a847b), WTCP(0x78cffba3, 0x2a49f920), + WTCP(0x78bf56f9, 0x2a796740), WTCP(0x78ae9fb0, 0x2aa8ced3), WTCP(0x789dd5cb, 0x2ad82fd2), WTCP(0x788cf94c, 0x2b078a36), + WTCP(0x787c0a36, 0x2b36ddf7), WTCP(0x786b088c, 0x2b662b0e), WTCP(0x7859f44f, 0x2b957173), WTCP(0x7848cd83, 0x2bc4b120), + WTCP(0x7837942b, 0x2bf3ea0d), WTCP(0x78264849, 0x2c231c33), WTCP(0x7814e9df, 0x2c52478a), WTCP(0x780378f1, 0x2c816c0c), + WTCP(0x77f1f581, 0x2cb089b1), WTCP(0x77e05f91, 0x2cdfa071), WTCP(0x77ceb725, 0x2d0eb046), WTCP(0x77bcfc3f, 0x2d3db928), + WTCP(0x77ab2ee2, 0x2d6cbb10), WTCP(0x77994f11, 0x2d9bb5f6), WTCP(0x77875cce, 0x2dcaa9d5), WTCP(0x7775581d, 0x2df996a3), + WTCP(0x776340ff, 0x2e287c5a), WTCP(0x77511778, 0x2e575af3), WTCP(0x773edb8b, 0x2e863267), WTCP(0x772c8d3a, 0x2eb502ae), + WTCP(0x771a2c88, 0x2ee3cbc1), WTCP(0x7707b979, 0x2f128d99), WTCP(0x76f5340e, 0x2f41482e), WTCP(0x76e29c4b, 0x2f6ffb7a), + WTCP(0x76cff232, 0x2f9ea775), WTCP(0x76bd35c7, 0x2fcd4c19), WTCP(0x76aa670d, 0x2ffbe95d), WTCP(0x76978605, 0x302a7f3a), + WTCP(0x768492b4, 0x30590dab), WTCP(0x76718d1c, 0x308794a6), WTCP(0x765e7540, 0x30b61426), WTCP(0x764b4b23, 0x30e48c22), + WTCP(0x76380ec8, 0x3112fc95), WTCP(0x7624c031, 0x31416576), WTCP(0x76115f63, 0x316fc6be), WTCP(0x75fdec60, 0x319e2067), + WTCP(0x75ea672a, 0x31cc7269), WTCP(0x75d6cfc5, 0x31fabcbd), WTCP(0x75c32634, 0x3228ff5c), WTCP(0x75af6a7b, 0x32573a3f), + WTCP(0x759b9c9b, 0x32856d5e), WTCP(0x7587bc98, 0x32b398b3), WTCP(0x7573ca75, 0x32e1bc36), WTCP(0x755fc635, 0x330fd7e1), + WTCP(0x754bafdc, 0x333debab), WTCP(0x7537876c, 0x336bf78f), WTCP(0x75234ce8, 0x3399fb85), WTCP(0x750f0054, 0x33c7f785), + WTCP(0x74faa1b3, 0x33f5eb89), WTCP(0x74e63108, 0x3423d78a), WTCP(0x74d1ae55, 0x3451bb81), WTCP(0x74bd199f, 0x347f9766), + WTCP(0x74a872e8, 0x34ad6b32), WTCP(0x7493ba34, 0x34db36df), WTCP(0x747eef85, 0x3508fa66), WTCP(0x746a12df, 0x3536b5be), + WTCP(0x74552446, 0x356468e2), WTCP(0x744023bc, 0x359213c9), WTCP(0x742b1144, 0x35bfb66e), WTCP(0x7415ece2, 0x35ed50c9), + WTCP(0x7400b69a, 0x361ae2d3), WTCP(0x73eb6e6e, 0x36486c86), WTCP(0x73d61461, 0x3675edd9), WTCP(0x73c0a878, 0x36a366c6), + WTCP(0x73ab2ab4, 0x36d0d746), WTCP(0x73959b1b, 0x36fe3f52), WTCP(0x737ff9ae, 0x372b9ee3), WTCP(0x736a4671, 0x3758f5f2), + WTCP(0x73548168, 0x37864477), WTCP(0x733eaa96, 0x37b38a6d), WTCP(0x7328c1ff, 0x37e0c7cc), WTCP(0x7312c7a5, 0x380dfc8d), + WTCP(0x72fcbb8c, 0x383b28a9), WTCP(0x72e69db7, 0x38684c19), WTCP(0x72d06e2b, 0x389566d6), WTCP(0x72ba2cea, 0x38c278d9), + WTCP(0x72a3d9f7, 0x38ef821c), WTCP(0x728d7557, 0x391c8297), WTCP(0x7276ff0d, 0x39497a43), WTCP(0x7260771b, 0x39766919), + WTCP(0x7249dd86, 0x39a34f13), WTCP(0x72333251, 0x39d02c2a), WTCP(0x721c7580, 0x39fd0056), WTCP(0x7205a716, 0x3a29cb91), + WTCP(0x71eec716, 0x3a568dd4), WTCP(0x71d7d585, 0x3a834717), WTCP(0x71c0d265, 0x3aaff755), WTCP(0x71a9bdba, 0x3adc9e86), + WTCP(0x71929789, 0x3b093ca3), WTCP(0x717b5fd3, 0x3b35d1a5), WTCP(0x7164169d, 0x3b625d86), WTCP(0x714cbbeb, 0x3b8ee03e), + WTCP(0x71354fc0, 0x3bbb59c7), WTCP(0x711dd220, 0x3be7ca1a), WTCP(0x7106430e, 0x3c143130), WTCP(0x70eea28e, 0x3c408f03), + WTCP(0x70d6f0a4, 0x3c6ce38a), WTCP(0x70bf2d53, 0x3c992ec0), WTCP(0x70a7589f, 0x3cc5709e), WTCP(0x708f728b, 0x3cf1a91c), + WTCP(0x70777b1c, 0x3d1dd835), WTCP(0x705f7255, 0x3d49fde1), WTCP(0x70475839, 0x3d761a19), WTCP(0x702f2ccd, 0x3da22cd7), + WTCP(0x7016f014, 0x3dce3614), WTCP(0x6ffea212, 0x3dfa35c8), WTCP(0x6fe642ca, 0x3e262bee), WTCP(0x6fcdd241, 0x3e52187f), + WTCP(0x6fb5507a, 0x3e7dfb73), WTCP(0x6f9cbd79, 0x3ea9d4c3), WTCP(0x6f841942, 0x3ed5a46b), WTCP(0x6f6b63d8, 0x3f016a61), + WTCP(0x6f529d40, 0x3f2d26a0), WTCP(0x6f39c57d, 0x3f58d921), WTCP(0x6f20dc92, 0x3f8481dd), WTCP(0x6f07e285, 0x3fb020ce), + WTCP(0x6eeed758, 0x3fdbb5ec), WTCP(0x6ed5bb10, 0x40074132), WTCP(0x6ebc8db0, 0x4032c297), WTCP(0x6ea34f3d, 0x405e3a16), + WTCP(0x6e89ffb9, 0x4089a7a8), WTCP(0x6e709f2a, 0x40b50b46), WTCP(0x6e572d93, 0x40e064ea), WTCP(0x6e3daaf8, 0x410bb48c), + WTCP(0x6e24175c, 0x4136fa27), WTCP(0x6e0a72c5, 0x416235b2), WTCP(0x6df0bd35, 0x418d6729), WTCP(0x6dd6f6b1, 0x41b88e84), + WTCP(0x6dbd1f3c, 0x41e3abbc), WTCP(0x6da336dc, 0x420ebecb), WTCP(0x6d893d93, 0x4239c7aa), WTCP(0x6d6f3365, 0x4264c653), + WTCP(0x6d551858, 0x428fbabe), WTCP(0x6d3aec6e, 0x42baa4e6), WTCP(0x6d20afac, 0x42e584c3), WTCP(0x6d066215, 0x43105a50), + WTCP(0x6cec03af, 0x433b2585), WTCP(0x6cd1947c, 0x4365e65b), WTCP(0x6cb71482, 0x43909ccd), WTCP(0x6c9c83c3, 0x43bb48d4), + WTCP(0x6c81e245, 0x43e5ea68), WTCP(0x6c67300b, 0x44108184), WTCP(0x6c4c6d1a, 0x443b0e21), WTCP(0x6c319975, 0x44659039), + WTCP(0x6c16b521, 0x449007c4), WTCP(0x6bfbc021, 0x44ba74bd), WTCP(0x6be0ba7b, 0x44e4d71c), WTCP(0x6bc5a431, 0x450f2edb), + WTCP(0x6baa7d49, 0x45397bf4), WTCP(0x6b8f45c7, 0x4563be60), WTCP(0x6b73fdae, 0x458df619), WTCP(0x6b58a503, 0x45b82318), + WTCP(0x6b3d3bcb, 0x45e24556), WTCP(0x6b21c208, 0x460c5cce), WTCP(0x6b0637c1, 0x46366978), WTCP(0x6aea9cf8, 0x46606b4e), + WTCP(0x6acef1b2, 0x468a624a), WTCP(0x6ab335f4, 0x46b44e65), WTCP(0x6a9769c1, 0x46de2f99), WTCP(0x6a7b8d1e, 0x470805df), + WTCP(0x6a5fa010, 0x4731d131), WTCP(0x6a43a29a, 0x475b9188), WTCP(0x6a2794c1, 0x478546de), WTCP(0x6a0b7689, 0x47aef12c), + WTCP(0x69ef47f6, 0x47d8906d), WTCP(0x69d3090e, 0x48022499), WTCP(0x69b6b9d3, 0x482badab), WTCP(0x699a5a4c, 0x48552b9b), + WTCP(0x697dea7b, 0x487e9e64), WTCP(0x69616a65, 0x48a805ff), WTCP(0x6944da10, 0x48d16265), WTCP(0x6928397e, 0x48fab391), + WTCP(0x690b88b5, 0x4923f97b), WTCP(0x68eec7b9, 0x494d341e), WTCP(0x68d1f68f, 0x49766373), WTCP(0x68b5153a, 0x499f8774), + WTCP(0x689823bf, 0x49c8a01b), WTCP(0x687b2224, 0x49f1ad61), WTCP(0x685e106c, 0x4a1aaf3f), WTCP(0x6840ee9b, 0x4a43a5b0), + WTCP(0x6823bcb7, 0x4a6c90ad), WTCP(0x68067ac3, 0x4a957030), WTCP(0x67e928c5, 0x4abe4433), WTCP(0x67cbc6c0, 0x4ae70caf), + WTCP(0x67ae54ba, 0x4b0fc99d), WTCP(0x6790d2b6, 0x4b387af9), WTCP(0x677340ba, 0x4b6120bb), WTCP(0x67559eca, 0x4b89badd), + WTCP(0x6737ecea, 0x4bb24958), WTCP(0x671a2b20, 0x4bdacc28), WTCP(0x66fc596f, 0x4c034345), WTCP(0x66de77dc, 0x4c2baea9), + WTCP(0x66c0866d, 0x4c540e4e), WTCP(0x66a28524, 0x4c7c622d), WTCP(0x66847408, 0x4ca4aa41), WTCP(0x6666531d, 0x4ccce684), + WTCP(0x66482267, 0x4cf516ee), WTCP(0x6629e1ec, 0x4d1d3b7a), WTCP(0x660b91af, 0x4d455422), WTCP(0x65ed31b5, 0x4d6d60df), + WTCP(0x65cec204, 0x4d9561ac), WTCP(0x65b0429f, 0x4dbd5682), WTCP(0x6591b38c, 0x4de53f5a), WTCP(0x657314cf, 0x4e0d1c30), + WTCP(0x6554666d, 0x4e34ecfc), WTCP(0x6535a86b, 0x4e5cb1b9), WTCP(0x6516dacd, 0x4e846a60), WTCP(0x64f7fd98, 0x4eac16eb), + WTCP(0x64d910d1, 0x4ed3b755), WTCP(0x64ba147d, 0x4efb4b96), WTCP(0x649b08a0, 0x4f22d3aa), WTCP(0x647bed3f, 0x4f4a4f89), + WTCP(0x645cc260, 0x4f71bf2e), WTCP(0x643d8806, 0x4f992293), WTCP(0x641e3e38, 0x4fc079b1), WTCP(0x63fee4f8, 0x4fe7c483), + WTCP(0x63df7c4d, 0x500f0302), WTCP(0x63c0043b, 0x50363529), WTCP(0x63a07cc7, 0x505d5af1), WTCP(0x6380e5f6, 0x50847454), + WTCP(0x63613fcd, 0x50ab814d), WTCP(0x63418a50, 0x50d281d5), WTCP(0x6321c585, 0x50f975e6), WTCP(0x6301f171, 0x51205d7b), + WTCP(0x62e20e17, 0x5147388c), WTCP(0x62c21b7e, 0x516e0715), WTCP(0x62a219aa, 0x5194c910), WTCP(0x628208a1, 0x51bb7e75), + WTCP(0x6261e866, 0x51e22740), WTCP(0x6241b8ff, 0x5208c36a), WTCP(0x62217a72, 0x522f52ee), WTCP(0x62012cc2, 0x5255d5c5), + WTCP(0x61e0cff5, 0x527c4bea), WTCP(0x61c06410, 0x52a2b556), WTCP(0x619fe918, 0x52c91204), WTCP(0x617f5f12, 0x52ef61ee), + WTCP(0x615ec603, 0x5315a50e), WTCP(0x613e1df0, 0x533bdb5d), WTCP(0x611d66de, 0x536204d7), WTCP(0x60fca0d2, 0x53882175), + WTCP(0x60dbcbd1, 0x53ae3131), WTCP(0x60bae7e1, 0x53d43406), WTCP(0x6099f505, 0x53fa29ed), WTCP(0x6078f344, 0x542012e1), + WTCP(0x6057e2a2, 0x5445eedb), WTCP(0x6036c325, 0x546bbdd7), WTCP(0x601594d1, 0x54917fce), WTCP(0x5ff457ad, 0x54b734ba), + WTCP(0x5fd30bbc, 0x54dcdc96), WTCP(0x5fb1b104, 0x5502775c), WTCP(0x5f90478a, 0x55280505), WTCP(0x5f6ecf53, 0x554d858d), + WTCP(0x5f4d4865, 0x5572f8ed), WTCP(0x5f2bb2c5, 0x55985f20), WTCP(0x5f0a0e77, 0x55bdb81f), WTCP(0x5ee85b82, 0x55e303e6), + WTCP(0x5ec699e9, 0x5608426e), WTCP(0x5ea4c9b3, 0x562d73b2), WTCP(0x5e82eae5, 0x565297ab), WTCP(0x5e60fd84, 0x5677ae54), + WTCP(0x5e3f0194, 0x569cb7a8), WTCP(0x5e1cf71c, 0x56c1b3a1), WTCP(0x5dfade20, 0x56e6a239), WTCP(0x5dd8b6a7, 0x570b8369), + WTCP(0x5db680b4, 0x5730572e), WTCP(0x5d943c4e, 0x57551d80), WTCP(0x5d71e979, 0x5779d65b), WTCP(0x5d4f883b, 0x579e81b8), + WTCP(0x5d2d189a, 0x57c31f92), WTCP(0x5d0a9a9a, 0x57e7afe4), WTCP(0x5ce80e41, 0x580c32a7), WTCP(0x5cc57394, 0x5830a7d6), + WTCP(0x5ca2ca99, 0x58550f6c), WTCP(0x5c801354, 0x58796962), WTCP(0x5c5d4dcc, 0x589db5b3), WTCP(0x5c3a7a05, 0x58c1f45b), + WTCP(0x5c179806, 0x58e62552), WTCP(0x5bf4a7d2, 0x590a4893), WTCP(0x5bd1a971, 0x592e5e19), WTCP(0x5bae9ce7, 0x595265df), + WTCP(0x5b8b8239, 0x59765fde), WTCP(0x5b68596d, 0x599a4c12), WTCP(0x5b452288, 0x59be2a74), WTCP(0x5b21dd90, 0x59e1faff), + WTCP(0x5afe8a8b, 0x5a05bdae), WTCP(0x5adb297d, 0x5a29727b), WTCP(0x5ab7ba6c, 0x5a4d1960), WTCP(0x5a943d5e, 0x5a70b258), +}; + +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_WTP KBDWindow1024[] = +{ + WTCP(0x7fffffa4, 0x0009962f), WTCP(0x7fffff39, 0x000e16fb), WTCP(0x7ffffebf, 0x0011ea65), WTCP(0x7ffffe34, 0x0015750e), + WTCP(0x7ffffd96, 0x0018dc74), WTCP(0x7ffffce5, 0x001c332e), WTCP(0x7ffffc1f, 0x001f83f5), WTCP(0x7ffffb43, 0x0022d59a), + WTCP(0x7ffffa4f, 0x00262cc2), WTCP(0x7ffff942, 0x00298cc4), WTCP(0x7ffff81a, 0x002cf81f), WTCP(0x7ffff6d6, 0x003070c4), + WTCP(0x7ffff573, 0x0033f840), WTCP(0x7ffff3f1, 0x00378fd9), WTCP(0x7ffff24d, 0x003b38a1), WTCP(0x7ffff085, 0x003ef381), + WTCP(0x7fffee98, 0x0042c147), WTCP(0x7fffec83, 0x0046a2a8), WTCP(0x7fffea44, 0x004a9847), WTCP(0x7fffe7d8, 0x004ea2b7), + WTCP(0x7fffe53f, 0x0052c283), WTCP(0x7fffe274, 0x0056f829), WTCP(0x7fffdf76, 0x005b4422), WTCP(0x7fffdc43, 0x005fa6dd), + WTCP(0x7fffd8d6, 0x006420c8), WTCP(0x7fffd52f, 0x0068b249), WTCP(0x7fffd149, 0x006d5bc4), WTCP(0x7fffcd22, 0x00721d9a), + WTCP(0x7fffc8b6, 0x0076f828), WTCP(0x7fffc404, 0x007bebca), WTCP(0x7fffbf06, 0x0080f8d9), WTCP(0x7fffb9bb, 0x00861fae), + WTCP(0x7fffb41e, 0x008b609e), WTCP(0x7fffae2c, 0x0090bbff), WTCP(0x7fffa7e1, 0x00963224), WTCP(0x7fffa13a, 0x009bc362), + WTCP(0x7fff9a32, 0x00a17009), WTCP(0x7fff92c5, 0x00a7386c), WTCP(0x7fff8af0, 0x00ad1cdc), WTCP(0x7fff82ad, 0x00b31da8), + WTCP(0x7fff79f9, 0x00b93b21), WTCP(0x7fff70cf, 0x00bf7596), WTCP(0x7fff672a, 0x00c5cd57), WTCP(0x7fff5d05, 0x00cc42b1), + WTCP(0x7fff525c, 0x00d2d5f3), WTCP(0x7fff4729, 0x00d9876c), WTCP(0x7fff3b66, 0x00e05769), WTCP(0x7fff2f10, 0x00e74638), + WTCP(0x7fff221f, 0x00ee5426), WTCP(0x7fff148e, 0x00f58182), WTCP(0x7fff0658, 0x00fcce97), WTCP(0x7ffef776, 0x01043bb3), + WTCP(0x7ffee7e2, 0x010bc923), WTCP(0x7ffed795, 0x01137733), WTCP(0x7ffec68a, 0x011b4631), WTCP(0x7ffeb4ba, 0x01233669), + WTCP(0x7ffea21d, 0x012b4827), WTCP(0x7ffe8eac, 0x01337bb8), WTCP(0x7ffe7a61, 0x013bd167), WTCP(0x7ffe6533, 0x01444982), + WTCP(0x7ffe4f1c, 0x014ce454), WTCP(0x7ffe3813, 0x0155a229), WTCP(0x7ffe2011, 0x015e834d), WTCP(0x7ffe070d, 0x0167880c), + WTCP(0x7ffdecff, 0x0170b0b2), WTCP(0x7ffdd1df, 0x0179fd8b), WTCP(0x7ffdb5a2, 0x01836ee1), WTCP(0x7ffd9842, 0x018d0500), + WTCP(0x7ffd79b3, 0x0196c035), WTCP(0x7ffd59ee, 0x01a0a0ca), WTCP(0x7ffd38e8, 0x01aaa70a), WTCP(0x7ffd1697, 0x01b4d341), + WTCP(0x7ffcf2f2, 0x01bf25b9), WTCP(0x7ffccdee, 0x01c99ebd), WTCP(0x7ffca780, 0x01d43e99), WTCP(0x7ffc7f9e, 0x01df0597), + WTCP(0x7ffc563d, 0x01e9f401), WTCP(0x7ffc2b51, 0x01f50a22), WTCP(0x7ffbfecf, 0x02004844), WTCP(0x7ffbd0ab, 0x020baeb1), + WTCP(0x7ffba0da, 0x02173db4), WTCP(0x7ffb6f4f, 0x0222f596), WTCP(0x7ffb3bfd, 0x022ed6a1), WTCP(0x7ffb06d8, 0x023ae11f), + WTCP(0x7ffacfd3, 0x02471558), WTCP(0x7ffa96e0, 0x02537397), WTCP(0x7ffa5bf2, 0x025ffc25), WTCP(0x7ffa1efc, 0x026caf4a), + WTCP(0x7ff9dfee, 0x02798d4f), WTCP(0x7ff99ebb, 0x0286967c), WTCP(0x7ff95b55, 0x0293cb1b), WTCP(0x7ff915ab, 0x02a12b72), + WTCP(0x7ff8cdaf, 0x02aeb7cb), WTCP(0x7ff88351, 0x02bc706d), WTCP(0x7ff83682, 0x02ca559f), WTCP(0x7ff7e731, 0x02d867a9), + WTCP(0x7ff7954e, 0x02e6a6d2), WTCP(0x7ff740c8, 0x02f51361), WTCP(0x7ff6e98e, 0x0303ad9c), WTCP(0x7ff68f8f, 0x031275ca), + WTCP(0x7ff632ba, 0x03216c30), WTCP(0x7ff5d2fb, 0x03309116), WTCP(0x7ff57042, 0x033fe4bf), WTCP(0x7ff50a7a, 0x034f6773), + WTCP(0x7ff4a192, 0x035f1975), WTCP(0x7ff43576, 0x036efb0a), WTCP(0x7ff3c612, 0x037f0c78), WTCP(0x7ff35353, 0x038f4e02), + WTCP(0x7ff2dd24, 0x039fbfeb), WTCP(0x7ff26370, 0x03b06279), WTCP(0x7ff1e623, 0x03c135ed), WTCP(0x7ff16527, 0x03d23a8b), + WTCP(0x7ff0e067, 0x03e37095), WTCP(0x7ff057cc, 0x03f4d84e), WTCP(0x7fefcb40, 0x040671f7), WTCP(0x7fef3aad, 0x04183dd3), + WTCP(0x7feea5fa, 0x042a3c22), WTCP(0x7fee0d11, 0x043c6d25), WTCP(0x7fed6fda, 0x044ed11d), WTCP(0x7fecce3d, 0x04616849), + WTCP(0x7fec2821, 0x047432eb), WTCP(0x7feb7d6c, 0x04873140), WTCP(0x7feace07, 0x049a6388), WTCP(0x7fea19d6, 0x04adca01), + WTCP(0x7fe960c0, 0x04c164ea), WTCP(0x7fe8a2aa, 0x04d53481), WTCP(0x7fe7df79, 0x04e93902), WTCP(0x7fe71712, 0x04fd72aa), + WTCP(0x7fe6495a, 0x0511e1b6), WTCP(0x7fe57634, 0x05268663), WTCP(0x7fe49d83, 0x053b60eb), WTCP(0x7fe3bf2b, 0x05507189), + WTCP(0x7fe2db0f, 0x0565b879), WTCP(0x7fe1f110, 0x057b35f4), WTCP(0x7fe10111, 0x0590ea35), WTCP(0x7fe00af3, 0x05a6d574), + WTCP(0x7fdf0e97, 0x05bcf7ea), WTCP(0x7fde0bdd, 0x05d351cf), WTCP(0x7fdd02a6, 0x05e9e35c), WTCP(0x7fdbf2d2, 0x0600acc8), + WTCP(0x7fdadc40, 0x0617ae48), WTCP(0x7fd9becf, 0x062ee814), WTCP(0x7fd89a5e, 0x06465a62), WTCP(0x7fd76eca, 0x065e0565), + WTCP(0x7fd63bf1, 0x0675e954), WTCP(0x7fd501b0, 0x068e0662), WTCP(0x7fd3bfe4, 0x06a65cc3), WTCP(0x7fd2766a, 0x06beecaa), + WTCP(0x7fd1251e, 0x06d7b648), WTCP(0x7fcfcbda, 0x06f0b9d1), WTCP(0x7fce6a7a, 0x0709f775), WTCP(0x7fcd00d8, 0x07236f65), + WTCP(0x7fcb8ecf, 0x073d21d2), WTCP(0x7fca1439, 0x07570eea), WTCP(0x7fc890ed, 0x077136dd), WTCP(0x7fc704c7, 0x078b99da), + WTCP(0x7fc56f9d, 0x07a6380d), WTCP(0x7fc3d147, 0x07c111a4), WTCP(0x7fc2299e, 0x07dc26cc), WTCP(0x7fc07878, 0x07f777b1), + WTCP(0x7fbebdac, 0x0813047d), WTCP(0x7fbcf90f, 0x082ecd5b), WTCP(0x7fbb2a78, 0x084ad276), WTCP(0x7fb951bc, 0x086713f7), + WTCP(0x7fb76eaf, 0x08839206), WTCP(0x7fb58126, 0x08a04ccb), WTCP(0x7fb388f4, 0x08bd446e), WTCP(0x7fb185ee, 0x08da7915), + WTCP(0x7faf77e5, 0x08f7eae7), WTCP(0x7fad5ead, 0x09159a09), WTCP(0x7fab3a17, 0x0933869f), WTCP(0x7fa909f6, 0x0951b0cd), + WTCP(0x7fa6ce1a, 0x097018b7), WTCP(0x7fa48653, 0x098ebe7f), WTCP(0x7fa23273, 0x09ada248), WTCP(0x7f9fd249, 0x09ccc431), + WTCP(0x7f9d65a4, 0x09ec245b), WTCP(0x7f9aec53, 0x0a0bc2e7), WTCP(0x7f986625, 0x0a2b9ff3), WTCP(0x7f95d2e7, 0x0a4bbb9e), + WTCP(0x7f933267, 0x0a6c1604), WTCP(0x7f908472, 0x0a8caf43), WTCP(0x7f8dc8d5, 0x0aad8776), WTCP(0x7f8aff5c, 0x0ace9eb9), + WTCP(0x7f8827d3, 0x0aeff526), WTCP(0x7f854204, 0x0b118ad8), WTCP(0x7f824dbb, 0x0b335fe6), WTCP(0x7f7f4ac3, 0x0b557469), + WTCP(0x7f7c38e4, 0x0b77c879), WTCP(0x7f7917e9, 0x0b9a5c2b), WTCP(0x7f75e79b, 0x0bbd2f97), WTCP(0x7f72a7c3, 0x0be042d0), + WTCP(0x7f6f5828, 0x0c0395ec), WTCP(0x7f6bf892, 0x0c2728fd), WTCP(0x7f6888c9, 0x0c4afc16), WTCP(0x7f650894, 0x0c6f0f4a), + WTCP(0x7f6177b9, 0x0c9362a8), WTCP(0x7f5dd5ff, 0x0cb7f642), WTCP(0x7f5a232a, 0x0cdcca26), WTCP(0x7f565f00, 0x0d01de63), + WTCP(0x7f528947, 0x0d273307), WTCP(0x7f4ea1c2, 0x0d4cc81f), WTCP(0x7f4aa835, 0x0d729db7), WTCP(0x7f469c65, 0x0d98b3da), + WTCP(0x7f427e13, 0x0dbf0a92), WTCP(0x7f3e4d04, 0x0de5a1e9), WTCP(0x7f3a08f9, 0x0e0c79e7), WTCP(0x7f35b1b4, 0x0e339295), + WTCP(0x7f3146f8, 0x0e5aebfa), WTCP(0x7f2cc884, 0x0e82861a), WTCP(0x7f28361b, 0x0eaa60fd), WTCP(0x7f238f7c, 0x0ed27ca5), + WTCP(0x7f1ed467, 0x0efad917), WTCP(0x7f1a049d, 0x0f237656), WTCP(0x7f151fdc, 0x0f4c5462), WTCP(0x7f1025e3, 0x0f75733d), + WTCP(0x7f0b1672, 0x0f9ed2e6), WTCP(0x7f05f146, 0x0fc8735e), WTCP(0x7f00b61d, 0x0ff254a1), WTCP(0x7efb64b4, 0x101c76ae), + WTCP(0x7ef5fcca, 0x1046d981), WTCP(0x7ef07e19, 0x10717d15), WTCP(0x7eeae860, 0x109c6165), WTCP(0x7ee53b5b, 0x10c7866a), + WTCP(0x7edf76c4, 0x10f2ec1e), WTCP(0x7ed99a58, 0x111e9279), WTCP(0x7ed3a5d1, 0x114a7971), WTCP(0x7ecd98eb, 0x1176a0fc), + WTCP(0x7ec77360, 0x11a30910), WTCP(0x7ec134eb, 0x11cfb1a1), WTCP(0x7ebadd44, 0x11fc9aa2), WTCP(0x7eb46c27, 0x1229c406), + WTCP(0x7eade14c, 0x12572dbf), WTCP(0x7ea73c6c, 0x1284d7bc), WTCP(0x7ea07d41, 0x12b2c1ed), WTCP(0x7e99a382, 0x12e0ec42), + WTCP(0x7e92aee7, 0x130f56a8), WTCP(0x7e8b9f2a, 0x133e010b), WTCP(0x7e847402, 0x136ceb59), WTCP(0x7e7d2d25, 0x139c157b), + WTCP(0x7e75ca4c, 0x13cb7f5d), WTCP(0x7e6e4b2d, 0x13fb28e6), WTCP(0x7e66af7f, 0x142b1200), WTCP(0x7e5ef6f8, 0x145b3a92), + WTCP(0x7e572150, 0x148ba281), WTCP(0x7e4f2e3b, 0x14bc49b4), WTCP(0x7e471d70, 0x14ed300f), WTCP(0x7e3eeea5, 0x151e5575), + WTCP(0x7e36a18e, 0x154fb9c9), WTCP(0x7e2e35e2, 0x15815ced), WTCP(0x7e25ab56, 0x15b33ec1), WTCP(0x7e1d019e, 0x15e55f25), + WTCP(0x7e14386e, 0x1617bdf9), WTCP(0x7e0b4f7d, 0x164a5b19), WTCP(0x7e02467e, 0x167d3662), WTCP(0x7df91d25, 0x16b04fb2), + WTCP(0x7defd327, 0x16e3a6e2), WTCP(0x7de66837, 0x17173bce), WTCP(0x7ddcdc0a, 0x174b0e4d), WTCP(0x7dd32e53, 0x177f1e39), + WTCP(0x7dc95ec6, 0x17b36b69), WTCP(0x7dbf6d17, 0x17e7f5b3), WTCP(0x7db558f9, 0x181cbcec), WTCP(0x7dab221f, 0x1851c0e9), + WTCP(0x7da0c83c, 0x1887017d), WTCP(0x7d964b05, 0x18bc7e7c), WTCP(0x7d8baa2b, 0x18f237b6), WTCP(0x7d80e563, 0x19282cfd), + WTCP(0x7d75fc5e, 0x195e5e20), WTCP(0x7d6aeed0, 0x1994caee), WTCP(0x7d5fbc6d, 0x19cb7335), WTCP(0x7d5464e6, 0x1a0256c2), + WTCP(0x7d48e7ef, 0x1a397561), WTCP(0x7d3d453b, 0x1a70cede), WTCP(0x7d317c7c, 0x1aa86301), WTCP(0x7d258d65, 0x1ae03195), + WTCP(0x7d1977aa, 0x1b183a63), WTCP(0x7d0d3afc, 0x1b507d30), WTCP(0x7d00d710, 0x1b88f9c5), WTCP(0x7cf44b97, 0x1bc1afe6), + WTCP(0x7ce79846, 0x1bfa9f58), WTCP(0x7cdabcce, 0x1c33c7e0), WTCP(0x7ccdb8e4, 0x1c6d293f), WTCP(0x7cc08c39, 0x1ca6c337), + WTCP(0x7cb33682, 0x1ce0958a), WTCP(0x7ca5b772, 0x1d1a9ff8), WTCP(0x7c980ebd, 0x1d54e240), WTCP(0x7c8a3c14, 0x1d8f5c21), + WTCP(0x7c7c3f2e, 0x1dca0d56), WTCP(0x7c6e17bc, 0x1e04f59f), WTCP(0x7c5fc573, 0x1e4014b4), WTCP(0x7c514807, 0x1e7b6a53), + WTCP(0x7c429f2c, 0x1eb6f633), WTCP(0x7c33ca96, 0x1ef2b80f), WTCP(0x7c24c9fa, 0x1f2eaf9e), WTCP(0x7c159d0d, 0x1f6adc98), + WTCP(0x7c064383, 0x1fa73eb2), WTCP(0x7bf6bd11, 0x1fe3d5a3), WTCP(0x7be7096c, 0x2020a11e), WTCP(0x7bd7284a, 0x205da0d8), + WTCP(0x7bc71960, 0x209ad483), WTCP(0x7bb6dc65, 0x20d83bd1), WTCP(0x7ba6710d, 0x2115d674), WTCP(0x7b95d710, 0x2153a41b), + WTCP(0x7b850e24, 0x2191a476), WTCP(0x7b7415ff, 0x21cfd734), WTCP(0x7b62ee59, 0x220e3c02), WTCP(0x7b5196e9, 0x224cd28d), + WTCP(0x7b400f67, 0x228b9a82), WTCP(0x7b2e578a, 0x22ca938a), WTCP(0x7b1c6f0b, 0x2309bd52), WTCP(0x7b0a55a1, 0x23491783), + WTCP(0x7af80b07, 0x2388a1c4), WTCP(0x7ae58ef5, 0x23c85bbf), WTCP(0x7ad2e124, 0x2408451a), WTCP(0x7ac0014e, 0x24485d7c), + WTCP(0x7aacef2e, 0x2488a48a), WTCP(0x7a99aa7e, 0x24c919e9), WTCP(0x7a8632f8, 0x2509bd3d), WTCP(0x7a728858, 0x254a8e29), + WTCP(0x7a5eaa5a, 0x258b8c50), WTCP(0x7a4a98b9, 0x25ccb753), WTCP(0x7a365333, 0x260e0ed3), WTCP(0x7a21d983, 0x264f9271), + WTCP(0x7a0d2b68, 0x269141cb), WTCP(0x79f8489e, 0x26d31c80), WTCP(0x79e330e4, 0x2715222f), WTCP(0x79cde3f8, 0x27575273), + WTCP(0x79b8619a, 0x2799acea), WTCP(0x79a2a989, 0x27dc3130), WTCP(0x798cbb85, 0x281ededf), WTCP(0x7976974e, 0x2861b591), + WTCP(0x79603ca5, 0x28a4b4e0), WTCP(0x7949ab4c, 0x28e7dc65), WTCP(0x7932e304, 0x292b2bb8), WTCP(0x791be390, 0x296ea270), + WTCP(0x7904acb3, 0x29b24024), WTCP(0x78ed3e30, 0x29f6046b), WTCP(0x78d597cc, 0x2a39eed8), WTCP(0x78bdb94a, 0x2a7dff02), + WTCP(0x78a5a270, 0x2ac2347c), WTCP(0x788d5304, 0x2b068eda), WTCP(0x7874cacb, 0x2b4b0dae), WTCP(0x785c098d, 0x2b8fb08a), + WTCP(0x78430f11, 0x2bd47700), WTCP(0x7829db1f, 0x2c1960a1), WTCP(0x78106d7f, 0x2c5e6cfd), WTCP(0x77f6c5fb, 0x2ca39ba3), + WTCP(0x77dce45c, 0x2ce8ec23), WTCP(0x77c2c86e, 0x2d2e5e0b), WTCP(0x77a871fa, 0x2d73f0e8), WTCP(0x778de0cd, 0x2db9a449), + WTCP(0x777314b2, 0x2dff77b8), WTCP(0x77580d78, 0x2e456ac4), WTCP(0x773ccaeb, 0x2e8b7cf6), WTCP(0x77214cdb, 0x2ed1addb), + WTCP(0x77059315, 0x2f17fcfb), WTCP(0x76e99d69, 0x2f5e69e2), WTCP(0x76cd6ba9, 0x2fa4f419), WTCP(0x76b0fda4, 0x2feb9b27), + WTCP(0x7694532e, 0x30325e96), WTCP(0x76776c17, 0x30793dee), WTCP(0x765a4834, 0x30c038b5), WTCP(0x763ce759, 0x31074e72), + WTCP(0x761f4959, 0x314e7eab), WTCP(0x76016e0b, 0x3195c8e6), WTCP(0x75e35545, 0x31dd2ca9), WTCP(0x75c4fedc, 0x3224a979), + WTCP(0x75a66aab, 0x326c3ed8), WTCP(0x75879887, 0x32b3ec4d), WTCP(0x7568884b, 0x32fbb159), WTCP(0x754939d1, 0x33438d81), + WTCP(0x7529acf4, 0x338b8045), WTCP(0x7509e18e, 0x33d3892a), WTCP(0x74e9d77d, 0x341ba7b1), WTCP(0x74c98e9e, 0x3463db5a), + WTCP(0x74a906cd, 0x34ac23a7), WTCP(0x74883fec, 0x34f48019), WTCP(0x746739d8, 0x353cf02f), WTCP(0x7445f472, 0x3585736a), + WTCP(0x74246f9c, 0x35ce0949), WTCP(0x7402ab37, 0x3616b14c), WTCP(0x73e0a727, 0x365f6af0), WTCP(0x73be6350, 0x36a835b5), + WTCP(0x739bdf95, 0x36f11118), WTCP(0x73791bdd, 0x3739fc98), WTCP(0x7356180e, 0x3782f7b2), WTCP(0x7332d410, 0x37cc01e3), + WTCP(0x730f4fc9, 0x38151aa8), WTCP(0x72eb8b24, 0x385e417e), WTCP(0x72c7860a, 0x38a775e1), WTCP(0x72a34066, 0x38f0b74d), + WTCP(0x727eba24, 0x393a053e), WTCP(0x7259f331, 0x39835f30), WTCP(0x7234eb79, 0x39ccc49e), WTCP(0x720fa2eb, 0x3a163503), + WTCP(0x71ea1977, 0x3a5fafda), WTCP(0x71c44f0c, 0x3aa9349e), WTCP(0x719e439d, 0x3af2c2ca), WTCP(0x7177f71a, 0x3b3c59d7), + WTCP(0x71516978, 0x3b85f940), WTCP(0x712a9aaa, 0x3bcfa07e), WTCP(0x71038aa4, 0x3c194f0d), WTCP(0x70dc395e, 0x3c630464), + WTCP(0x70b4a6cd, 0x3cacbfff), WTCP(0x708cd2e9, 0x3cf68155), WTCP(0x7064bdab, 0x3d4047e1), WTCP(0x703c670d, 0x3d8a131c), + WTCP(0x7013cf0a, 0x3dd3e27e), WTCP(0x6feaf59c, 0x3e1db580), WTCP(0x6fc1dac1, 0x3e678b9b), WTCP(0x6f987e76, 0x3eb16449), + WTCP(0x6f6ee0b9, 0x3efb3f01), WTCP(0x6f45018b, 0x3f451b3d), WTCP(0x6f1ae0eb, 0x3f8ef874), WTCP(0x6ef07edb, 0x3fd8d620), + WTCP(0x6ec5db5d, 0x4022b3b9), WTCP(0x6e9af675, 0x406c90b7), WTCP(0x6e6fd027, 0x40b66c93), WTCP(0x6e446879, 0x410046c5), + WTCP(0x6e18bf71, 0x414a1ec6), WTCP(0x6decd517, 0x4193f40d), WTCP(0x6dc0a972, 0x41ddc615), WTCP(0x6d943c8d, 0x42279455), + WTCP(0x6d678e71, 0x42715e45), WTCP(0x6d3a9f2a, 0x42bb235f), WTCP(0x6d0d6ec5, 0x4304e31a), WTCP(0x6cdffd4f, 0x434e9cf1), + WTCP(0x6cb24ad6, 0x4398505b), WTCP(0x6c84576b, 0x43e1fcd1), WTCP(0x6c56231c, 0x442ba1cd), WTCP(0x6c27adfd, 0x44753ec7), + WTCP(0x6bf8f81e, 0x44bed33a), WTCP(0x6bca0195, 0x45085e9d), WTCP(0x6b9aca75, 0x4551e06b), WTCP(0x6b6b52d5, 0x459b581e), + WTCP(0x6b3b9ac9, 0x45e4c52f), WTCP(0x6b0ba26b, 0x462e2717), WTCP(0x6adb69d3, 0x46777d52), WTCP(0x6aaaf11b, 0x46c0c75a), + WTCP(0x6a7a385c, 0x470a04a9), WTCP(0x6a493fb3, 0x475334b9), WTCP(0x6a18073d, 0x479c5707), WTCP(0x69e68f17, 0x47e56b0c), + WTCP(0x69b4d761, 0x482e7045), WTCP(0x6982e039, 0x4877662c), WTCP(0x6950a9c0, 0x48c04c3f), WTCP(0x691e341a, 0x490921f8), + WTCP(0x68eb7f67, 0x4951e6d5), WTCP(0x68b88bcd, 0x499a9a51), WTCP(0x68855970, 0x49e33beb), WTCP(0x6851e875, 0x4a2bcb1f), + WTCP(0x681e3905, 0x4a74476b), WTCP(0x67ea4b47, 0x4abcb04c), WTCP(0x67b61f63, 0x4b050541), WTCP(0x6781b585, 0x4b4d45c9), + WTCP(0x674d0dd6, 0x4b957162), WTCP(0x67182883, 0x4bdd878c), WTCP(0x66e305b8, 0x4c2587c6), WTCP(0x66ada5a5, 0x4c6d7190), + WTCP(0x66780878, 0x4cb5446a), WTCP(0x66422e60, 0x4cfcffd5), WTCP(0x660c1790, 0x4d44a353), WTCP(0x65d5c439, 0x4d8c2e64), + WTCP(0x659f348e, 0x4dd3a08c), WTCP(0x656868c3, 0x4e1af94b), WTCP(0x6531610d, 0x4e623825), WTCP(0x64fa1da3, 0x4ea95c9d), + WTCP(0x64c29ebb, 0x4ef06637), WTCP(0x648ae48d, 0x4f375477), WTCP(0x6452ef53, 0x4f7e26e1), WTCP(0x641abf46, 0x4fc4dcfb), + WTCP(0x63e254a2, 0x500b7649), WTCP(0x63a9afa2, 0x5051f253), WTCP(0x6370d083, 0x5098509f), WTCP(0x6337b784, 0x50de90b3), + WTCP(0x62fe64e3, 0x5124b218), WTCP(0x62c4d8e0, 0x516ab455), WTCP(0x628b13bc, 0x51b096f3), WTCP(0x625115b8, 0x51f6597b), + WTCP(0x6216df18, 0x523bfb78), WTCP(0x61dc701f, 0x52817c72), WTCP(0x61a1c912, 0x52c6dbf5), WTCP(0x6166ea36, 0x530c198d), + WTCP(0x612bd3d2, 0x535134c5), WTCP(0x60f0862d, 0x53962d2a), WTCP(0x60b50190, 0x53db024a), WTCP(0x60794644, 0x541fb3b1), + WTCP(0x603d5494, 0x546440ef), WTCP(0x60012cca, 0x54a8a992), WTCP(0x5fc4cf33, 0x54eced2b), WTCP(0x5f883c1c, 0x55310b48), + WTCP(0x5f4b73d2, 0x5575037c), WTCP(0x5f0e76a5, 0x55b8d558), WTCP(0x5ed144e5, 0x55fc806f), WTCP(0x5e93dee1, 0x56400452), + WTCP(0x5e5644ec, 0x56836096), WTCP(0x5e187757, 0x56c694cf), WTCP(0x5dda7677, 0x5709a092), WTCP(0x5d9c429f, 0x574c8374), + WTCP(0x5d5ddc24, 0x578f3d0d), WTCP(0x5d1f435d, 0x57d1ccf2), WTCP(0x5ce078a0, 0x581432bd), WTCP(0x5ca17c45, 0x58566e04), + WTCP(0x5c624ea4, 0x58987e63), WTCP(0x5c22f016, 0x58da6372), WTCP(0x5be360f6, 0x591c1ccc), WTCP(0x5ba3a19f, 0x595daa0d), + WTCP(0x5b63b26c, 0x599f0ad1), WTCP(0x5b2393ba, 0x59e03eb6), WTCP(0x5ae345e7, 0x5a214558), WTCP(0x5aa2c951, 0x5a621e56), +}; + +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_WTP SineWindow128[] = +{ + WTCP(0x7fff6216, 0x00c90f88), WTCP(0x7ffa72d1, 0x025b26d7), WTCP(0x7ff09478, 0x03ed26e6), WTCP(0x7fe1c76b, 0x057f0035), + WTCP(0x7fce0c3e, 0x0710a345), WTCP(0x7fb563b3, 0x08a2009a), WTCP(0x7f97cebd, 0x0a3308bd), WTCP(0x7f754e80, 0x0bc3ac35), + WTCP(0x7f4de451, 0x0d53db92), WTCP(0x7f2191b4, 0x0ee38766), WTCP(0x7ef05860, 0x1072a048), WTCP(0x7eba3a39, 0x120116d5), + WTCP(0x7e7f3957, 0x138edbb1), WTCP(0x7e3f57ff, 0x151bdf86), WTCP(0x7dfa98a8, 0x16a81305), WTCP(0x7db0fdf8, 0x183366e9), + WTCP(0x7d628ac6, 0x19bdcbf3), WTCP(0x7d0f4218, 0x1b4732ef), WTCP(0x7cb72724, 0x1ccf8cb3), WTCP(0x7c5a3d50, 0x1e56ca1e), + WTCP(0x7bf88830, 0x1fdcdc1b), WTCP(0x7b920b89, 0x2161b3a0), WTCP(0x7b26cb4f, 0x22e541af), WTCP(0x7ab6cba4, 0x24677758), + WTCP(0x7a4210d8, 0x25e845b6), WTCP(0x79c89f6e, 0x27679df4), WTCP(0x794a7c12, 0x28e5714b), WTCP(0x78c7aba2, 0x2a61b101), + WTCP(0x78403329, 0x2bdc4e6f), WTCP(0x77b417df, 0x2d553afc), WTCP(0x77235f2d, 0x2ecc681e), WTCP(0x768e0ea6, 0x3041c761), + WTCP(0x75f42c0b, 0x31b54a5e), WTCP(0x7555bd4c, 0x3326e2c3), WTCP(0x74b2c884, 0x34968250), WTCP(0x740b53fb, 0x36041ad9), + WTCP(0x735f6626, 0x376f9e46), WTCP(0x72af05a7, 0x38d8fe93), WTCP(0x71fa3949, 0x3a402dd2), WTCP(0x71410805, 0x3ba51e29), + WTCP(0x708378ff, 0x3d07c1d6), WTCP(0x6fc19385, 0x3e680b2c), WTCP(0x6efb5f12, 0x3fc5ec98), WTCP(0x6e30e34a, 0x4121589b), + WTCP(0x6d6227fa, 0x427a41d0), WTCP(0x6c8f351c, 0x43d09aed), WTCP(0x6bb812d1, 0x452456bd), WTCP(0x6adcc964, 0x46756828), + WTCP(0x69fd614a, 0x47c3c22f), WTCP(0x6919e320, 0x490f57ee), WTCP(0x683257ab, 0x4a581c9e), WTCP(0x6746c7d8, 0x4b9e0390), + WTCP(0x66573cbb, 0x4ce10034), WTCP(0x6563bf92, 0x4e210617), WTCP(0x646c59bf, 0x4f5e08e3), WTCP(0x637114cc, 0x5097fc5e), + WTCP(0x6271fa69, 0x51ced46e), WTCP(0x616f146c, 0x53028518), WTCP(0x60686ccf, 0x5433027d), WTCP(0x5f5e0db3, 0x556040e2), + WTCP(0x5e50015d, 0x568a34a9), WTCP(0x5d3e5237, 0x57b0d256), WTCP(0x5c290acc, 0x58d40e8c), WTCP(0x5b1035cf, 0x59f3de12), +}; + +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_WTP KBDWindow128[] = +{ + WTCP(0x7ffffffe, 0x00016f63), WTCP(0x7ffffff1, 0x0003e382), WTCP(0x7fffffc7, 0x00078f64), WTCP(0x7fffff5d, 0x000cc323), + WTCP(0x7ffffe76, 0x0013d9ed), WTCP(0x7ffffcaa, 0x001d3a9d), WTCP(0x7ffff953, 0x0029581f), WTCP(0x7ffff372, 0x0038b1bd), + WTCP(0x7fffe98b, 0x004bd34d), WTCP(0x7fffd975, 0x00635538), WTCP(0x7fffc024, 0x007fdc64), WTCP(0x7fff995b, 0x00a219f1), + WTCP(0x7fff5f5b, 0x00cacad0), WTCP(0x7fff0a75, 0x00fab72d), WTCP(0x7ffe9091, 0x0132b1af), WTCP(0x7ffde49e, 0x01739689), + WTCP(0x7ffcf5ef, 0x01be4a63), WTCP(0x7ffbaf84, 0x0213b910), WTCP(0x7ff9f73a, 0x0274d41e), WTCP(0x7ff7acf1, 0x02e2913a), + WTCP(0x7ff4a99a, 0x035de86c), WTCP(0x7ff0be3d, 0x03e7d233), WTCP(0x7febb2f1, 0x0481457c), WTCP(0x7fe545d4, 0x052b357c), + WTCP(0x7fdd2a02, 0x05e68f77), WTCP(0x7fd30695, 0x06b4386f), WTCP(0x7fc675b4, 0x07950acb), WTCP(0x7fb703be, 0x0889d3ef), + WTCP(0x7fa42e89, 0x099351e0), WTCP(0x7f8d64d8, 0x0ab230e0), WTCP(0x7f7205f8, 0x0be70923), WTCP(0x7f516195, 0x0d325c93), + WTCP(0x7f2ab7d0, 0x0e9494ae), WTCP(0x7efd3997, 0x100e0085), WTCP(0x7ec8094a, 0x119ed2ef), WTCP(0x7e8a3ba7, 0x134720d8), + WTCP(0x7e42d906, 0x1506dfdc), WTCP(0x7df0dee4, 0x16dde50b), WTCP(0x7d9341b4, 0x18cbe3f7), WTCP(0x7d28ef02, 0x1ad06e07), + WTCP(0x7cb0cfcc, 0x1ceaf215), WTCP(0x7c29cb20, 0x1f1abc4f), WTCP(0x7b92c8eb, 0x215ef677), WTCP(0x7aeab4ec, 0x23b6a867), + WTCP(0x7a3081d0, 0x2620b8ec), WTCP(0x79632c5a, 0x289beef5), WTCP(0x7881be95, 0x2b26f30b), WTCP(0x778b5304, 0x2dc0511f), + WTCP(0x767f17c0, 0x30667aa2), WTCP(0x755c5178, 0x3317c8dd), WTCP(0x74225e50, 0x35d27f98), WTCP(0x72d0b887, 0x3894cff3), + WTCP(0x7166f8e7, 0x3b5cdb7b), WTCP(0x6fe4d8e8, 0x3e28b770), WTCP(0x6e4a3491, 0x40f6702a), WTCP(0x6c970bfc, 0x43c40caa), + WTCP(0x6acb8483, 0x468f9231), WTCP(0x68e7e994, 0x495707f5), WTCP(0x66ecad1c, 0x4c187ac7), WTCP(0x64da6797, 0x4ed200c5), + WTCP(0x62b1d7b7, 0x5181bcea), WTCP(0x6073e1ae, 0x5425e28e), WTCP(0x5e218e16, 0x56bcb8c2), WTCP(0x5bbc0875, 0x59449d76), +}; + + + + + + + + +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_WTP SineWindow960[] = +{ + WTCP(0x7ffffd31, 0x001aceea), WTCP(0x7fffe6bc, 0x00506cb9), WTCP(0x7fffb9d1, 0x00860a79), WTCP(0x7fff7671, 0x00bba822), + WTCP(0x7fff1c9b, 0x00f145ab), WTCP(0x7ffeac50, 0x0126e309), WTCP(0x7ffe2590, 0x015c8033), WTCP(0x7ffd885a, 0x01921d20), + WTCP(0x7ffcd4b0, 0x01c7b9c6), WTCP(0x7ffc0a91, 0x01fd561d), WTCP(0x7ffb29fd, 0x0232f21a), WTCP(0x7ffa32f4, 0x02688db4), + WTCP(0x7ff92577, 0x029e28e2), WTCP(0x7ff80186, 0x02d3c39b), WTCP(0x7ff6c720, 0x03095dd5), WTCP(0x7ff57647, 0x033ef786), + WTCP(0x7ff40efa, 0x037490a5), WTCP(0x7ff2913a, 0x03aa292a), WTCP(0x7ff0fd07, 0x03dfc109), WTCP(0x7fef5260, 0x0415583b), + WTCP(0x7fed9148, 0x044aeeb5), WTCP(0x7febb9bd, 0x0480846e), WTCP(0x7fe9cbc0, 0x04b6195d), WTCP(0x7fe7c752, 0x04ebad79), + WTCP(0x7fe5ac72, 0x052140b7), WTCP(0x7fe37b22, 0x0556d30f), WTCP(0x7fe13361, 0x058c6478), WTCP(0x7fded530, 0x05c1f4e7), + WTCP(0x7fdc608f, 0x05f78453), WTCP(0x7fd9d57f, 0x062d12b4), WTCP(0x7fd73401, 0x06629ffe), WTCP(0x7fd47c14, 0x06982c2b), + WTCP(0x7fd1adb9, 0x06cdb72f), WTCP(0x7fcec8f1, 0x07034101), WTCP(0x7fcbcdbc, 0x0738c998), WTCP(0x7fc8bc1b, 0x076e50eb), + WTCP(0x7fc5940e, 0x07a3d6f0), WTCP(0x7fc25596, 0x07d95b9e), WTCP(0x7fbf00b3, 0x080edeec), WTCP(0x7fbb9567, 0x084460cf), + WTCP(0x7fb813b0, 0x0879e140), WTCP(0x7fb47b91, 0x08af6033), WTCP(0x7fb0cd0a, 0x08e4dda0), WTCP(0x7fad081b, 0x091a597e), + WTCP(0x7fa92cc5, 0x094fd3c3), WTCP(0x7fa53b09, 0x09854c66), WTCP(0x7fa132e8, 0x09bac35d), WTCP(0x7f9d1461, 0x09f0389f), + WTCP(0x7f98df77, 0x0a25ac23), WTCP(0x7f949429, 0x0a5b1dde), WTCP(0x7f903279, 0x0a908dc9), WTCP(0x7f8bba66, 0x0ac5fbd9), + WTCP(0x7f872bf3, 0x0afb6805), WTCP(0x7f82871f, 0x0b30d244), WTCP(0x7f7dcbec, 0x0b663a8c), WTCP(0x7f78fa5b, 0x0b9ba0d5), + WTCP(0x7f74126b, 0x0bd10513), WTCP(0x7f6f141f, 0x0c066740), WTCP(0x7f69ff76, 0x0c3bc74f), WTCP(0x7f64d473, 0x0c71253a), + WTCP(0x7f5f9315, 0x0ca680f5), WTCP(0x7f5a3b5e, 0x0cdbda79), WTCP(0x7f54cd4f, 0x0d1131ba), WTCP(0x7f4f48e8, 0x0d4686b1), + WTCP(0x7f49ae2a, 0x0d7bd954), WTCP(0x7f43fd18, 0x0db12999), WTCP(0x7f3e35b0, 0x0de67776), WTCP(0x7f3857f6, 0x0e1bc2e4), + WTCP(0x7f3263e9, 0x0e510bd8), WTCP(0x7f2c598a, 0x0e865248), WTCP(0x7f2638db, 0x0ebb962c), WTCP(0x7f2001dd, 0x0ef0d77b), + WTCP(0x7f19b491, 0x0f26162a), WTCP(0x7f1350f8, 0x0f5b5231), WTCP(0x7f0cd712, 0x0f908b86), WTCP(0x7f0646e2, 0x0fc5c220), + WTCP(0x7effa069, 0x0ffaf5f6), WTCP(0x7ef8e3a6, 0x103026fe), WTCP(0x7ef2109d, 0x1065552e), WTCP(0x7eeb274d, 0x109a807e), + WTCP(0x7ee427b9, 0x10cfa8e5), WTCP(0x7edd11e1, 0x1104ce58), WTCP(0x7ed5e5c6, 0x1139f0cf), WTCP(0x7ecea36b, 0x116f1040), + WTCP(0x7ec74acf, 0x11a42ca2), WTCP(0x7ebfdbf5, 0x11d945eb), WTCP(0x7eb856de, 0x120e5c13), WTCP(0x7eb0bb8a, 0x12436f10), + WTCP(0x7ea909fc, 0x12787ed8), WTCP(0x7ea14235, 0x12ad8b63), WTCP(0x7e996436, 0x12e294a7), WTCP(0x7e917000, 0x13179a9b), + WTCP(0x7e896595, 0x134c9d34), WTCP(0x7e8144f6, 0x13819c6c), WTCP(0x7e790e25, 0x13b69836), WTCP(0x7e70c124, 0x13eb908c), + WTCP(0x7e685df2, 0x14208563), WTCP(0x7e5fe493, 0x145576b1), WTCP(0x7e575508, 0x148a646e), WTCP(0x7e4eaf51, 0x14bf4e91), + WTCP(0x7e45f371, 0x14f43510), WTCP(0x7e3d2169, 0x152917e1), WTCP(0x7e34393b, 0x155df6fc), WTCP(0x7e2b3ae8, 0x1592d257), + WTCP(0x7e222672, 0x15c7a9ea), WTCP(0x7e18fbda, 0x15fc7daa), WTCP(0x7e0fbb22, 0x16314d8e), WTCP(0x7e06644c, 0x1666198d), + WTCP(0x7dfcf759, 0x169ae19f), WTCP(0x7df3744b, 0x16cfa5b9), WTCP(0x7de9db23, 0x170465d2), WTCP(0x7de02be4, 0x173921e2), + WTCP(0x7dd6668f, 0x176dd9de), WTCP(0x7dcc8b25, 0x17a28dbe), WTCP(0x7dc299a9, 0x17d73d79), WTCP(0x7db8921c, 0x180be904), + WTCP(0x7dae747f, 0x18409058), WTCP(0x7da440d6, 0x1875336a), WTCP(0x7d99f721, 0x18a9d231), WTCP(0x7d8f9762, 0x18de6ca5), + WTCP(0x7d85219c, 0x191302bc), WTCP(0x7d7a95cf, 0x1947946c), WTCP(0x7d6ff3fe, 0x197c21ad), WTCP(0x7d653c2b, 0x19b0aa75), + WTCP(0x7d5a6e57, 0x19e52ebb), WTCP(0x7d4f8a85, 0x1a19ae76), WTCP(0x7d4490b6, 0x1a4e299d), WTCP(0x7d3980ec, 0x1a82a026), + WTCP(0x7d2e5b2a, 0x1ab71208), WTCP(0x7d231f70, 0x1aeb7f3a), WTCP(0x7d17cdc2, 0x1b1fe7b3), WTCP(0x7d0c6621, 0x1b544b6a), + WTCP(0x7d00e88f, 0x1b88aa55), WTCP(0x7cf5550e, 0x1bbd046c), WTCP(0x7ce9aba1, 0x1bf159a4), WTCP(0x7cddec48, 0x1c25a9f6), + WTCP(0x7cd21707, 0x1c59f557), WTCP(0x7cc62bdf, 0x1c8e3bbe), WTCP(0x7cba2ad3, 0x1cc27d23), WTCP(0x7cae13e4, 0x1cf6b97c), + WTCP(0x7ca1e715, 0x1d2af0c1), WTCP(0x7c95a467, 0x1d5f22e7), WTCP(0x7c894bde, 0x1d934fe5), WTCP(0x7c7cdd7b, 0x1dc777b3), + WTCP(0x7c705940, 0x1dfb9a48), WTCP(0x7c63bf2f, 0x1e2fb79a), WTCP(0x7c570f4b, 0x1e63cfa0), WTCP(0x7c4a4996, 0x1e97e251), + WTCP(0x7c3d6e13, 0x1ecbefa4), WTCP(0x7c307cc2, 0x1efff78f), WTCP(0x7c2375a8, 0x1f33fa0a), WTCP(0x7c1658c5, 0x1f67f70b), + WTCP(0x7c09261d, 0x1f9bee8a), WTCP(0x7bfbddb1, 0x1fcfe07d), WTCP(0x7bee7f85, 0x2003ccdb), WTCP(0x7be10b99, 0x2037b39b), + WTCP(0x7bd381f1, 0x206b94b4), WTCP(0x7bc5e290, 0x209f701c), WTCP(0x7bb82d76, 0x20d345cc), WTCP(0x7baa62a8, 0x210715b8), + WTCP(0x7b9c8226, 0x213adfda), WTCP(0x7b8e8bf5, 0x216ea426), WTCP(0x7b808015, 0x21a26295), WTCP(0x7b725e8a, 0x21d61b1e), + WTCP(0x7b642756, 0x2209cdb6), WTCP(0x7b55da7c, 0x223d7a55), WTCP(0x7b4777fe, 0x227120f3), WTCP(0x7b38ffde, 0x22a4c185), + WTCP(0x7b2a721f, 0x22d85c04), WTCP(0x7b1bcec4, 0x230bf065), WTCP(0x7b0d15d0, 0x233f7ea0), WTCP(0x7afe4744, 0x237306ab), + WTCP(0x7aef6323, 0x23a6887f), WTCP(0x7ae06971, 0x23da0411), WTCP(0x7ad15a2f, 0x240d7958), WTCP(0x7ac23561, 0x2440e84d), + WTCP(0x7ab2fb09, 0x247450e4), WTCP(0x7aa3ab29, 0x24a7b317), WTCP(0x7a9445c5, 0x24db0edb), WTCP(0x7a84cade, 0x250e6427), + WTCP(0x7a753a79, 0x2541b2f3), WTCP(0x7a659496, 0x2574fb36), WTCP(0x7a55d93a, 0x25a83ce6), WTCP(0x7a460867, 0x25db77fa), + WTCP(0x7a362220, 0x260eac6a), WTCP(0x7a262668, 0x2641da2d), WTCP(0x7a161540, 0x26750139), WTCP(0x7a05eead, 0x26a82186), + WTCP(0x79f5b2b1, 0x26db3b0a), WTCP(0x79e5614f, 0x270e4dbd), WTCP(0x79d4fa89, 0x27415996), WTCP(0x79c47e63, 0x27745e8c), + WTCP(0x79b3ece0, 0x27a75c95), WTCP(0x79a34602, 0x27da53a9), WTCP(0x799289cc, 0x280d43bf), WTCP(0x7981b841, 0x28402cce), + WTCP(0x7970d165, 0x28730ecd), WTCP(0x795fd53a, 0x28a5e9b4), WTCP(0x794ec3c3, 0x28d8bd78), WTCP(0x793d9d03, 0x290b8a12), + WTCP(0x792c60fe, 0x293e4f78), WTCP(0x791b0fb5, 0x29710da1), WTCP(0x7909a92d, 0x29a3c485), WTCP(0x78f82d68, 0x29d6741b), + WTCP(0x78e69c69, 0x2a091c59), WTCP(0x78d4f634, 0x2a3bbd37), WTCP(0x78c33acb, 0x2a6e56ac), WTCP(0x78b16a32, 0x2aa0e8b0), + WTCP(0x789f846b, 0x2ad37338), WTCP(0x788d897b, 0x2b05f63d), WTCP(0x787b7963, 0x2b3871b5), WTCP(0x78695428, 0x2b6ae598), + WTCP(0x785719cc, 0x2b9d51dd), WTCP(0x7844ca53, 0x2bcfb67b), WTCP(0x783265c0, 0x2c021369), WTCP(0x781fec15, 0x2c34689e), + WTCP(0x780d5d57, 0x2c66b611), WTCP(0x77fab989, 0x2c98fbba), WTCP(0x77e800ad, 0x2ccb3990), WTCP(0x77d532c7, 0x2cfd6f8a), + WTCP(0x77c24fdb, 0x2d2f9d9f), WTCP(0x77af57eb, 0x2d61c3c7), WTCP(0x779c4afc, 0x2d93e1f8), WTCP(0x77892910, 0x2dc5f829), + WTCP(0x7775f22a, 0x2df80653), WTCP(0x7762a64f, 0x2e2a0c6c), WTCP(0x774f4581, 0x2e5c0a6b), WTCP(0x773bcfc4, 0x2e8e0048), + WTCP(0x7728451c, 0x2ebfedfa), WTCP(0x7714a58b, 0x2ef1d377), WTCP(0x7700f115, 0x2f23b0b9), WTCP(0x76ed27be, 0x2f5585b5), + WTCP(0x76d94989, 0x2f875262), WTCP(0x76c55679, 0x2fb916b9), WTCP(0x76b14e93, 0x2fead2b0), WTCP(0x769d31d9, 0x301c863f), + WTCP(0x76890050, 0x304e315d), WTCP(0x7674b9fa, 0x307fd401), WTCP(0x76605edb, 0x30b16e23), WTCP(0x764beef8, 0x30e2ffb9), + WTCP(0x76376a52, 0x311488bc), WTCP(0x7622d0ef, 0x31460922), WTCP(0x760e22d1, 0x317780e2), WTCP(0x75f95ffc, 0x31a8eff5), + WTCP(0x75e48874, 0x31da5651), WTCP(0x75cf9c3d, 0x320bb3ee), WTCP(0x75ba9b5a, 0x323d08c3), WTCP(0x75a585cf, 0x326e54c7), + WTCP(0x75905ba0, 0x329f97f3), WTCP(0x757b1ccf, 0x32d0d23c), WTCP(0x7565c962, 0x3302039b), WTCP(0x7550615c, 0x33332c06), + WTCP(0x753ae4c0, 0x33644b76), WTCP(0x75255392, 0x339561e1), WTCP(0x750fadd7, 0x33c66f40), WTCP(0x74f9f391, 0x33f77388), + WTCP(0x74e424c5, 0x34286eb3), WTCP(0x74ce4177, 0x345960b7), WTCP(0x74b849aa, 0x348a498b), WTCP(0x74a23d62, 0x34bb2927), + WTCP(0x748c1ca4, 0x34ebff83), WTCP(0x7475e772, 0x351ccc96), WTCP(0x745f9dd1, 0x354d9057), WTCP(0x74493fc5, 0x357e4abe), + WTCP(0x7432cd51, 0x35aefbc2), WTCP(0x741c467b, 0x35dfa35a), WTCP(0x7405ab45, 0x3610417f), WTCP(0x73eefbb3, 0x3640d627), + WTCP(0x73d837ca, 0x3671614b), WTCP(0x73c15f8d, 0x36a1e2e0), WTCP(0x73aa7301, 0x36d25ae0), WTCP(0x7393722a, 0x3702c942), + WTCP(0x737c5d0b, 0x37332dfd), WTCP(0x736533a9, 0x37638908), WTCP(0x734df607, 0x3793da5b), WTCP(0x7336a42b, 0x37c421ee), + WTCP(0x731f3e17, 0x37f45fb7), WTCP(0x7307c3d0, 0x382493b0), WTCP(0x72f0355a, 0x3854bdcf), WTCP(0x72d892ba, 0x3884de0b), + WTCP(0x72c0dbf3, 0x38b4f45d), WTCP(0x72a91109, 0x38e500bc), WTCP(0x72913201, 0x3915031f), WTCP(0x72793edf, 0x3944fb7e), + WTCP(0x726137a8, 0x3974e9d0), WTCP(0x72491c5e, 0x39a4ce0e), WTCP(0x7230ed07, 0x39d4a82f), WTCP(0x7218a9a7, 0x3a04782a), + WTCP(0x72005242, 0x3a343df7), WTCP(0x71e7e6dc, 0x3a63f98d), WTCP(0x71cf677a, 0x3a93aae5), WTCP(0x71b6d420, 0x3ac351f6), + WTCP(0x719e2cd2, 0x3af2eeb7), WTCP(0x71857195, 0x3b228120), WTCP(0x716ca26c, 0x3b52092a), WTCP(0x7153bf5d, 0x3b8186ca), + WTCP(0x713ac86b, 0x3bb0f9fa), WTCP(0x7121bd9c, 0x3be062b0), WTCP(0x71089ef2, 0x3c0fc0e6), WTCP(0x70ef6c74, 0x3c3f1491), + WTCP(0x70d62625, 0x3c6e5daa), WTCP(0x70bccc09, 0x3c9d9c28), WTCP(0x70a35e25, 0x3cccd004), WTCP(0x7089dc7e, 0x3cfbf935), + WTCP(0x70704718, 0x3d2b17b3), WTCP(0x70569df8, 0x3d5a2b75), WTCP(0x703ce122, 0x3d893474), WTCP(0x7023109a, 0x3db832a6), + WTCP(0x70092c65, 0x3de72604), WTCP(0x6fef3488, 0x3e160e85), WTCP(0x6fd52907, 0x3e44ec22), WTCP(0x6fbb09e7, 0x3e73bed2), + WTCP(0x6fa0d72c, 0x3ea2868c), WTCP(0x6f8690db, 0x3ed14349), WTCP(0x6f6c36f8, 0x3efff501), WTCP(0x6f51c989, 0x3f2e9bab), + WTCP(0x6f374891, 0x3f5d373e), WTCP(0x6f1cb416, 0x3f8bc7b4), WTCP(0x6f020c1c, 0x3fba4d03), WTCP(0x6ee750a8, 0x3fe8c724), + WTCP(0x6ecc81be, 0x4017360e), WTCP(0x6eb19f64, 0x404599b9), WTCP(0x6e96a99d, 0x4073f21d), WTCP(0x6e7ba06f, 0x40a23f32), + WTCP(0x6e6083de, 0x40d080f0), WTCP(0x6e4553ef, 0x40feb74f), WTCP(0x6e2a10a8, 0x412ce246), WTCP(0x6e0eba0c, 0x415b01ce), + WTCP(0x6df35020, 0x418915de), WTCP(0x6dd7d2ea, 0x41b71e6f), WTCP(0x6dbc426e, 0x41e51b77), WTCP(0x6da09eb1, 0x42130cf0), + WTCP(0x6d84e7b7, 0x4240f2d1), WTCP(0x6d691d87, 0x426ecd12), WTCP(0x6d4d4023, 0x429c9bab), WTCP(0x6d314f93, 0x42ca5e94), + WTCP(0x6d154bd9, 0x42f815c5), WTCP(0x6cf934fc, 0x4325c135), WTCP(0x6cdd0b00, 0x435360de), WTCP(0x6cc0cdea, 0x4380f4b7), + WTCP(0x6ca47dbf, 0x43ae7cb7), WTCP(0x6c881a84, 0x43dbf8d7), WTCP(0x6c6ba43e, 0x44096910), WTCP(0x6c4f1af2, 0x4436cd58), + WTCP(0x6c327ea6, 0x446425a8), WTCP(0x6c15cf5d, 0x449171f8), WTCP(0x6bf90d1d, 0x44beb240), WTCP(0x6bdc37eb, 0x44ebe679), + WTCP(0x6bbf4fcd, 0x45190e99), WTCP(0x6ba254c7, 0x45462a9a), WTCP(0x6b8546de, 0x45733a73), WTCP(0x6b682617, 0x45a03e1d), + WTCP(0x6b4af279, 0x45cd358f), WTCP(0x6b2dac06, 0x45fa20c2), WTCP(0x6b1052c6, 0x4626ffae), WTCP(0x6af2e6bc, 0x4653d24b), + WTCP(0x6ad567ef, 0x46809891), WTCP(0x6ab7d663, 0x46ad5278), WTCP(0x6a9a321d, 0x46d9fff8), WTCP(0x6a7c7b23, 0x4706a10a), + WTCP(0x6a5eb17a, 0x473335a5), WTCP(0x6a40d527, 0x475fbdc3), WTCP(0x6a22e630, 0x478c395a), WTCP(0x6a04e499, 0x47b8a864), + WTCP(0x69e6d067, 0x47e50ad8), WTCP(0x69c8a9a1, 0x481160ae), WTCP(0x69aa704c, 0x483da9e0), WTCP(0x698c246c, 0x4869e665), + WTCP(0x696dc607, 0x48961635), WTCP(0x694f5523, 0x48c23949), WTCP(0x6930d1c4, 0x48ee4f98), WTCP(0x69123bf1, 0x491a591c), + WTCP(0x68f393ae, 0x494655cc), WTCP(0x68d4d900, 0x497245a1), WTCP(0x68b60bee, 0x499e2892), WTCP(0x68972c7d, 0x49c9fe99), + WTCP(0x68783ab1, 0x49f5c7ae), WTCP(0x68593691, 0x4a2183c8), WTCP(0x683a2022, 0x4a4d32e1), WTCP(0x681af76a, 0x4a78d4f0), + WTCP(0x67fbbc6d, 0x4aa469ee), WTCP(0x67dc6f31, 0x4acff1d3), WTCP(0x67bd0fbd, 0x4afb6c98), WTCP(0x679d9e14, 0x4b26da35), + WTCP(0x677e1a3e, 0x4b523aa2), WTCP(0x675e843e, 0x4b7d8dd8), WTCP(0x673edc1c, 0x4ba8d3cf), WTCP(0x671f21dc, 0x4bd40c80), + WTCP(0x66ff5584, 0x4bff37e2), WTCP(0x66df771a, 0x4c2a55ef), WTCP(0x66bf86a3, 0x4c55669f), WTCP(0x669f8425, 0x4c8069ea), + WTCP(0x667f6fa5, 0x4cab5fc9), WTCP(0x665f4929, 0x4cd64834), WTCP(0x663f10b7, 0x4d012324), WTCP(0x661ec654, 0x4d2bf091), + WTCP(0x65fe6a06, 0x4d56b073), WTCP(0x65ddfbd3, 0x4d8162c4), WTCP(0x65bd7bc0, 0x4dac077b), WTCP(0x659ce9d4, 0x4dd69e92), + WTCP(0x657c4613, 0x4e012800), WTCP(0x655b9083, 0x4e2ba3be), WTCP(0x653ac92b, 0x4e5611c5), WTCP(0x6519f010, 0x4e80720e), + WTCP(0x64f90538, 0x4eaac490), WTCP(0x64d808a8, 0x4ed50945), WTCP(0x64b6fa66, 0x4eff4025), WTCP(0x6495da79, 0x4f296928), + WTCP(0x6474a8e5, 0x4f538448), WTCP(0x645365b2, 0x4f7d917c), WTCP(0x643210e4, 0x4fa790be), WTCP(0x6410aa81, 0x4fd18206), + WTCP(0x63ef3290, 0x4ffb654d), WTCP(0x63cda916, 0x50253a8b), WTCP(0x63ac0e19, 0x504f01ba), WTCP(0x638a619e, 0x5078bad1), + WTCP(0x6368a3ad, 0x50a265c9), WTCP(0x6346d44b, 0x50cc029c), WTCP(0x6324f37d, 0x50f59141), WTCP(0x6303014a, 0x511f11b2), + WTCP(0x62e0fdb8, 0x514883e7), WTCP(0x62bee8cc, 0x5171e7d9), WTCP(0x629cc28c, 0x519b3d80), WTCP(0x627a8b00, 0x51c484d6), + WTCP(0x6258422c, 0x51edbdd4), WTCP(0x6235e816, 0x5216e871), WTCP(0x62137cc5, 0x524004a7), WTCP(0x61f1003f, 0x5269126e), + WTCP(0x61ce7289, 0x529211c0), WTCP(0x61abd3ab, 0x52bb0295), WTCP(0x618923a9, 0x52e3e4e6), WTCP(0x61666289, 0x530cb8ac), + WTCP(0x61439053, 0x53357ddf), WTCP(0x6120ad0d, 0x535e3479), WTCP(0x60fdb8bb, 0x5386dc72), WTCP(0x60dab365, 0x53af75c3), + WTCP(0x60b79d10, 0x53d80065), WTCP(0x609475c3, 0x54007c51), WTCP(0x60713d84, 0x5428e980), WTCP(0x604df459, 0x545147eb), + WTCP(0x602a9a48, 0x5479978a), WTCP(0x60072f57, 0x54a1d857), WTCP(0x5fe3b38d, 0x54ca0a4b), WTCP(0x5fc026f0, 0x54f22d5d), + WTCP(0x5f9c8987, 0x551a4189), WTCP(0x5f78db56, 0x554246c6), WTCP(0x5f551c65, 0x556a3d0d), WTCP(0x5f314cba, 0x55922457), + WTCP(0x5f0d6c5b, 0x55b9fc9e), WTCP(0x5ee97b4f, 0x55e1c5da), WTCP(0x5ec5799b, 0x56098005), WTCP(0x5ea16747, 0x56312b17), + WTCP(0x5e7d4458, 0x5658c709), WTCP(0x5e5910d4, 0x568053d5), WTCP(0x5e34ccc3, 0x56a7d174), WTCP(0x5e10782b, 0x56cf3fde), + WTCP(0x5dec1311, 0x56f69f0d), WTCP(0x5dc79d7c, 0x571deefa), WTCP(0x5da31773, 0x57452f9d), WTCP(0x5d7e80fc, 0x576c60f1), + WTCP(0x5d59da1e, 0x579382ee), WTCP(0x5d3522de, 0x57ba958d), WTCP(0x5d105b44, 0x57e198c7), WTCP(0x5ceb8355, 0x58088c96), + WTCP(0x5cc69b19, 0x582f70f3), WTCP(0x5ca1a295, 0x585645d7), WTCP(0x5c7c99d1, 0x587d0b3b), WTCP(0x5c5780d3, 0x58a3c118), + WTCP(0x5c3257a0, 0x58ca6767), WTCP(0x5c0d1e41, 0x58f0fe23), WTCP(0x5be7d4ba, 0x59178543), WTCP(0x5bc27b14, 0x593dfcc2), + WTCP(0x5b9d1154, 0x59646498), WTCP(0x5b779780, 0x598abcbe), WTCP(0x5b520da1, 0x59b1052f), WTCP(0x5b2c73bb, 0x59d73de3), + WTCP(0x5b06c9d6, 0x59fd66d4), WTCP(0x5ae10ff9, 0x5a237ffa), WTCP(0x5abb4629, 0x5a498950), WTCP(0x5a956c6e, 0x5a6f82ce), +}; + +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_WTP KBDWindow960[] = +{ + WTCP(0x7fffff9e, 0x0009e6ac), WTCP(0x7fffff2b, 0x000e96d5), WTCP(0x7ffffea6, 0x0012987e), WTCP(0x7ffffe0e, 0x001652b6), + WTCP(0x7ffffd60, 0x0019ebce), WTCP(0x7ffffc9c, 0x001d76bf), WTCP(0x7ffffbbf, 0x0020fe79), WTCP(0x7ffffac9, 0x002489ef), + WTCP(0x7ffff9b7, 0x00281de2), WTCP(0x7ffff887, 0x002bbdbb), WTCP(0x7ffff737, 0x002f6c0d), WTCP(0x7ffff5c6, 0x00332ad8), + WTCP(0x7ffff431, 0x0036fbb9), WTCP(0x7ffff276, 0x003ae004), WTCP(0x7ffff092, 0x003ed8d8), WTCP(0x7fffee84, 0x0042e72f), + WTCP(0x7fffec48, 0x00470be3), WTCP(0x7fffe9dd, 0x004b47b8), WTCP(0x7fffe73f, 0x004f9b5f), WTCP(0x7fffe46b, 0x0054077a), + WTCP(0x7fffe15f, 0x00588ca1), WTCP(0x7fffde17, 0x005d2b61), WTCP(0x7fffda91, 0x0061e442), WTCP(0x7fffd6c9, 0x0066b7c2), + WTCP(0x7fffd2bb, 0x006ba65c), WTCP(0x7fffce65, 0x0070b087), WTCP(0x7fffc9c2, 0x0075d6b5), WTCP(0x7fffc4cf, 0x007b1955), + WTCP(0x7fffbf87, 0x008078d5), WTCP(0x7fffb9e7, 0x0085f5a0), WTCP(0x7fffb3ea, 0x008b901d), WTCP(0x7fffad8c, 0x009148b4), + WTCP(0x7fffa6c9, 0x00971fcb), WTCP(0x7fff9f9c, 0x009d15c7), WTCP(0x7fff9800, 0x00a32b0b), WTCP(0x7fff8ff0, 0x00a95ff9), + WTCP(0x7fff8767, 0x00afb4f4), WTCP(0x7fff7e5f, 0x00b62a5c), WTCP(0x7fff74d4, 0x00bcc093), WTCP(0x7fff6ac0, 0x00c377f8), + WTCP(0x7fff601c, 0x00ca50eb), WTCP(0x7fff54e3, 0x00d14bcb), WTCP(0x7fff490e, 0x00d868f7), WTCP(0x7fff3c98, 0x00dfa8ce), + WTCP(0x7fff2f79, 0x00e70bad), WTCP(0x7fff21ac, 0x00ee91f3), WTCP(0x7fff1328, 0x00f63bfe), WTCP(0x7fff03e7, 0x00fe0a2c), + WTCP(0x7ffef3e1, 0x0105fcd9), WTCP(0x7ffee310, 0x010e1462), WTCP(0x7ffed16a, 0x01165126), WTCP(0x7ffebee9, 0x011eb381), + WTCP(0x7ffeab83, 0x01273bd0), WTCP(0x7ffe9731, 0x012fea6f), WTCP(0x7ffe81ea, 0x0138bfbc), WTCP(0x7ffe6ba4, 0x0141bc12), + WTCP(0x7ffe5457, 0x014adfce), WTCP(0x7ffe3bfa, 0x01542b4d), WTCP(0x7ffe2282, 0x015d9ee9), WTCP(0x7ffe07e6, 0x01673b01), + WTCP(0x7ffdec1b, 0x0170ffee), WTCP(0x7ffdcf17, 0x017aee0e), WTCP(0x7ffdb0d0, 0x018505bc), WTCP(0x7ffd913b, 0x018f4754), + WTCP(0x7ffd704b, 0x0199b330), WTCP(0x7ffd4df7, 0x01a449ad), WTCP(0x7ffd2a31, 0x01af0b25), WTCP(0x7ffd04ef, 0x01b9f7f4), + WTCP(0x7ffcde23, 0x01c51074), WTCP(0x7ffcb5c1, 0x01d05501), WTCP(0x7ffc8bbc, 0x01dbc5f5), WTCP(0x7ffc6006, 0x01e763ab), + WTCP(0x7ffc3293, 0x01f32e7d), WTCP(0x7ffc0354, 0x01ff26c5), WTCP(0x7ffbd23b, 0x020b4cde), WTCP(0x7ffb9f3a, 0x0217a120), + WTCP(0x7ffb6a41, 0x022423e6), WTCP(0x7ffb3342, 0x0230d58a), WTCP(0x7ffafa2d, 0x023db664), WTCP(0x7ffabef2, 0x024ac6ce), + WTCP(0x7ffa8180, 0x02580720), WTCP(0x7ffa41c9, 0x026577b3), WTCP(0x7ff9ffb9, 0x027318e0), WTCP(0x7ff9bb41, 0x0280eaff), + WTCP(0x7ff9744e, 0x028eee68), WTCP(0x7ff92acf, 0x029d2371), WTCP(0x7ff8deb1, 0x02ab8a74), WTCP(0x7ff88fe2, 0x02ba23c7), + WTCP(0x7ff83e4d, 0x02c8efc0), WTCP(0x7ff7e9e1, 0x02d7eeb7), WTCP(0x7ff79288, 0x02e72101), WTCP(0x7ff7382f, 0x02f686f5), + WTCP(0x7ff6dac1, 0x030620e9), WTCP(0x7ff67a29, 0x0315ef31), WTCP(0x7ff61651, 0x0325f224), WTCP(0x7ff5af23, 0x03362a14), + WTCP(0x7ff5448a, 0x03469758), WTCP(0x7ff4d66d, 0x03573a42), WTCP(0x7ff464b7, 0x03681327), WTCP(0x7ff3ef4f, 0x0379225a), + WTCP(0x7ff3761d, 0x038a682e), WTCP(0x7ff2f90a, 0x039be4f4), WTCP(0x7ff277fb, 0x03ad9900), WTCP(0x7ff1f2d8, 0x03bf84a3), + WTCP(0x7ff16986, 0x03d1a82e), WTCP(0x7ff0dbec, 0x03e403f3), WTCP(0x7ff049ef, 0x03f69840), WTCP(0x7fefb373, 0x04096568), + WTCP(0x7fef185d, 0x041c6bb8), WTCP(0x7fee7890, 0x042fab81), WTCP(0x7fedd3f1, 0x04432510), WTCP(0x7fed2a61, 0x0456d8b4), + WTCP(0x7fec7bc4, 0x046ac6ba), WTCP(0x7febc7fb, 0x047eef70), WTCP(0x7feb0ee8, 0x04935322), WTCP(0x7fea506b, 0x04a7f21d), + WTCP(0x7fe98c65, 0x04bcccab), WTCP(0x7fe8c2b7, 0x04d1e318), WTCP(0x7fe7f33e, 0x04e735af), WTCP(0x7fe71ddb, 0x04fcc4ba), + WTCP(0x7fe6426c, 0x05129081), WTCP(0x7fe560ce, 0x0528994d), WTCP(0x7fe478df, 0x053edf68), WTCP(0x7fe38a7c, 0x05556318), + WTCP(0x7fe29581, 0x056c24a5), WTCP(0x7fe199ca, 0x05832455), WTCP(0x7fe09733, 0x059a626e), WTCP(0x7fdf8d95, 0x05b1df35), + WTCP(0x7fde7ccb, 0x05c99aef), WTCP(0x7fdd64af, 0x05e195e0), WTCP(0x7fdc451a, 0x05f9d04b), WTCP(0x7fdb1de4, 0x06124a73), + WTCP(0x7fd9eee5, 0x062b0499), WTCP(0x7fd8b7f5, 0x0643ff00), WTCP(0x7fd778ec, 0x065d39e7), WTCP(0x7fd6319e, 0x0676b58f), + WTCP(0x7fd4e1e2, 0x06907237), WTCP(0x7fd3898d, 0x06aa701d), WTCP(0x7fd22873, 0x06c4af80), WTCP(0x7fd0be6a, 0x06df309c), + WTCP(0x7fcf4b44, 0x06f9f3ad), WTCP(0x7fcdced4, 0x0714f8f0), WTCP(0x7fcc48ed, 0x0730409f), WTCP(0x7fcab960, 0x074bcaf5), + WTCP(0x7fc91fff, 0x0767982a), WTCP(0x7fc77c9a, 0x0783a877), WTCP(0x7fc5cf02, 0x079ffc14), WTCP(0x7fc41705, 0x07bc9338), + WTCP(0x7fc25474, 0x07d96e19), WTCP(0x7fc0871b, 0x07f68ced), WTCP(0x7fbeaeca, 0x0813efe7), WTCP(0x7fbccb4c, 0x0831973d), + WTCP(0x7fbadc70, 0x084f8320), WTCP(0x7fb8e200, 0x086db3c3), WTCP(0x7fb6dbc8, 0x088c2957), WTCP(0x7fb4c993, 0x08aae40c), + WTCP(0x7fb2ab2b, 0x08c9e412), WTCP(0x7fb0805a, 0x08e92997), WTCP(0x7fae48e9, 0x0908b4c9), WTCP(0x7fac04a0, 0x092885d6), + WTCP(0x7fa9b347, 0x09489ce8), WTCP(0x7fa754a6, 0x0968fa2c), WTCP(0x7fa4e884, 0x09899dcb), WTCP(0x7fa26ea6, 0x09aa87ee), + WTCP(0x7f9fe6d1, 0x09cbb8be), WTCP(0x7f9d50cc, 0x09ed3062), WTCP(0x7f9aac5a, 0x0a0eef00), WTCP(0x7f97f93f, 0x0a30f4bf), + WTCP(0x7f95373e, 0x0a5341c2), WTCP(0x7f92661b, 0x0a75d62e), WTCP(0x7f8f8596, 0x0a98b224), WTCP(0x7f8c9572, 0x0abbd5c7), + WTCP(0x7f89956f, 0x0adf4137), WTCP(0x7f86854d, 0x0b02f494), WTCP(0x7f8364cd, 0x0b26effd), WTCP(0x7f8033ae, 0x0b4b338f), + WTCP(0x7f7cf1ae, 0x0b6fbf67), WTCP(0x7f799e8b, 0x0b9493a0), WTCP(0x7f763a03, 0x0bb9b056), WTCP(0x7f72c3d2, 0x0bdf15a2), + WTCP(0x7f6f3bb5, 0x0c04c39c), WTCP(0x7f6ba168, 0x0c2aba5d), WTCP(0x7f67f4a6, 0x0c50f9fa), WTCP(0x7f643529, 0x0c77828a), + WTCP(0x7f6062ac, 0x0c9e5420), WTCP(0x7f5c7ce8, 0x0cc56ed1), WTCP(0x7f588397, 0x0cecd2ae), WTCP(0x7f547670, 0x0d147fc8), + WTCP(0x7f50552c, 0x0d3c7630), WTCP(0x7f4c1f83, 0x0d64b5f6), WTCP(0x7f47d52a, 0x0d8d3f26), WTCP(0x7f4375d9, 0x0db611ce), + WTCP(0x7f3f0144, 0x0ddf2dfa), WTCP(0x7f3a7723, 0x0e0893b4), WTCP(0x7f35d729, 0x0e324306), WTCP(0x7f31210a, 0x0e5c3bf9), + WTCP(0x7f2c547b, 0x0e867e94), WTCP(0x7f27712e, 0x0eb10add), WTCP(0x7f2276d8, 0x0edbe0da), WTCP(0x7f1d6529, 0x0f07008e), + WTCP(0x7f183bd3, 0x0f3269fc), WTCP(0x7f12fa89, 0x0f5e1d27), WTCP(0x7f0da0fb, 0x0f8a1a0e), WTCP(0x7f082ed8, 0x0fb660b1), + WTCP(0x7f02a3d2, 0x0fe2f10f), WTCP(0x7efcff98, 0x100fcb25), WTCP(0x7ef741d9, 0x103ceeee), WTCP(0x7ef16a42, 0x106a5c66), + WTCP(0x7eeb7884, 0x10981386), WTCP(0x7ee56c4a, 0x10c61447), WTCP(0x7edf4543, 0x10f45ea0), WTCP(0x7ed9031b, 0x1122f288), + WTCP(0x7ed2a57f, 0x1151cff3), WTCP(0x7ecc2c1a, 0x1180f6d5), WTCP(0x7ec59699, 0x11b06720), WTCP(0x7ebee4a6, 0x11e020c8), + WTCP(0x7eb815ed, 0x121023ba), WTCP(0x7eb12a18, 0x12406fe8), WTCP(0x7eaa20d1, 0x1271053e), WTCP(0x7ea2f9c2, 0x12a1e3a9), + WTCP(0x7e9bb494, 0x12d30b15), WTCP(0x7e9450f0, 0x13047b6c), WTCP(0x7e8cce7f, 0x13363497), WTCP(0x7e852ce9, 0x1368367f), + WTCP(0x7e7d6bd6, 0x139a8109), WTCP(0x7e758aee, 0x13cd141b), WTCP(0x7e6d89d9, 0x13ffef99), WTCP(0x7e65683d, 0x14331368), + WTCP(0x7e5d25c1, 0x14667f67), WTCP(0x7e54c20b, 0x149a3379), WTCP(0x7e4c3cc3, 0x14ce2f7c), WTCP(0x7e43958e, 0x1502734f), + WTCP(0x7e3acc11, 0x1536fece), WTCP(0x7e31dff2, 0x156bd1d6), WTCP(0x7e28d0d7, 0x15a0ec41), WTCP(0x7e1f9e63, 0x15d64de9), + WTCP(0x7e16483d, 0x160bf6a5), WTCP(0x7e0cce08, 0x1641e64c), WTCP(0x7e032f6a, 0x16781cb4), WTCP(0x7df96c05, 0x16ae99b2), + WTCP(0x7def837e, 0x16e55d18), WTCP(0x7de57579, 0x171c66ba), WTCP(0x7ddb419a, 0x1753b667), WTCP(0x7dd0e784, 0x178b4bef), + WTCP(0x7dc666d9, 0x17c32721), WTCP(0x7dbbbf3e, 0x17fb47ca), WTCP(0x7db0f056, 0x1833adb5), WTCP(0x7da5f9c3, 0x186c58ae), + WTCP(0x7d9adb29, 0x18a5487d), WTCP(0x7d8f9429, 0x18de7cec), WTCP(0x7d842467, 0x1917f5c1), WTCP(0x7d788b86, 0x1951b2c2), + WTCP(0x7d6cc927, 0x198bb3b4), WTCP(0x7d60dced, 0x19c5f85a), WTCP(0x7d54c67c, 0x1a008077), WTCP(0x7d488574, 0x1a3b4bcb), + WTCP(0x7d3c1979, 0x1a765a17), WTCP(0x7d2f822d, 0x1ab1ab18), WTCP(0x7d22bf32, 0x1aed3e8d), WTCP(0x7d15d02b, 0x1b291432), + WTCP(0x7d08b4ba, 0x1b652bc1), WTCP(0x7cfb6c82, 0x1ba184f5), WTCP(0x7cedf725, 0x1bde1f86), WTCP(0x7ce05445, 0x1c1afb2c), + WTCP(0x7cd28386, 0x1c58179c), WTCP(0x7cc48489, 0x1c95748d), WTCP(0x7cb656f3, 0x1cd311b1), WTCP(0x7ca7fa65, 0x1d10eebd), + WTCP(0x7c996e83, 0x1d4f0b60), WTCP(0x7c8ab2f0, 0x1d8d674c), WTCP(0x7c7bc74f, 0x1dcc0230), WTCP(0x7c6cab44, 0x1e0adbbb), + WTCP(0x7c5d5e71, 0x1e49f398), WTCP(0x7c4de07c, 0x1e894973), WTCP(0x7c3e3108, 0x1ec8dcf8), WTCP(0x7c2e4fb9, 0x1f08add0), + WTCP(0x7c1e3c34, 0x1f48bba3), WTCP(0x7c0df61d, 0x1f890618), WTCP(0x7bfd7d18, 0x1fc98cd6), WTCP(0x7becd0cc, 0x200a4f80), + WTCP(0x7bdbf0dd, 0x204b4dbc), WTCP(0x7bcadcf1, 0x208c872c), WTCP(0x7bb994ae, 0x20cdfb71), WTCP(0x7ba817b9, 0x210faa2c), + WTCP(0x7b9665bb, 0x215192fc), WTCP(0x7b847e58, 0x2193b57f), WTCP(0x7b726139, 0x21d61153), WTCP(0x7b600e05, 0x2218a614), + WTCP(0x7b4d8463, 0x225b735d), WTCP(0x7b3ac3fc, 0x229e78c7), WTCP(0x7b27cc79, 0x22e1b5eb), WTCP(0x7b149d82, 0x23252a62), + WTCP(0x7b0136c1, 0x2368d5c2), WTCP(0x7aed97df, 0x23acb7a0), WTCP(0x7ad9c087, 0x23f0cf92), WTCP(0x7ac5b063, 0x24351d2a), + WTCP(0x7ab1671e, 0x24799ffc), WTCP(0x7a9ce464, 0x24be5799), WTCP(0x7a8827e1, 0x25034391), WTCP(0x7a733142, 0x25486375), + WTCP(0x7a5e0033, 0x258db6d2), WTCP(0x7a489461, 0x25d33d35), WTCP(0x7a32ed7c, 0x2618f62c), WTCP(0x7a1d0b31, 0x265ee143), + WTCP(0x7a06ed2f, 0x26a4fe02), WTCP(0x79f09327, 0x26eb4bf5), WTCP(0x79d9fcc8, 0x2731caa3), WTCP(0x79c329c2, 0x27787995), + WTCP(0x79ac19c9, 0x27bf5850), WTCP(0x7994cc8d, 0x2806665c), WTCP(0x797d41c1, 0x284da33c), WTCP(0x79657918, 0x28950e74), + WTCP(0x794d7247, 0x28dca788), WTCP(0x79352d01, 0x29246dfa), WTCP(0x791ca8fc, 0x296c614a), WTCP(0x7903e5ee, 0x29b480f9), + WTCP(0x78eae38d, 0x29fccc87), WTCP(0x78d1a191, 0x2a454372), WTCP(0x78b81fb1, 0x2a8de537), WTCP(0x789e5da6, 0x2ad6b155), + WTCP(0x78845b29, 0x2b1fa745), WTCP(0x786a17f5, 0x2b68c684), WTCP(0x784f93c4, 0x2bb20e8c), WTCP(0x7834ce53, 0x2bfb7ed7), + WTCP(0x7819c75c, 0x2c4516dc), WTCP(0x77fe7e9e, 0x2c8ed615), WTCP(0x77e2f3d7, 0x2cd8bbf7), WTCP(0x77c726c5, 0x2d22c7fa), + WTCP(0x77ab1728, 0x2d6cf993), WTCP(0x778ec4c0, 0x2db75037), WTCP(0x77722f4e, 0x2e01cb59), WTCP(0x77555695, 0x2e4c6a6d), + WTCP(0x77383a58, 0x2e972ce6), WTCP(0x771ada5a, 0x2ee21235), WTCP(0x76fd3660, 0x2f2d19cc), WTCP(0x76df4e30, 0x2f78431a), + WTCP(0x76c12190, 0x2fc38d91), WTCP(0x76a2b047, 0x300ef89d), WTCP(0x7683fa1e, 0x305a83af), WTCP(0x7664fede, 0x30a62e34), + WTCP(0x7645be51, 0x30f1f798), WTCP(0x76263842, 0x313ddf49), WTCP(0x76066c7e, 0x3189e4b1), WTCP(0x75e65ad1, 0x31d6073d), + WTCP(0x75c60309, 0x32224657), WTCP(0x75a564f6, 0x326ea168), WTCP(0x75848067, 0x32bb17da), WTCP(0x7563552d, 0x3307a917), + WTCP(0x7541e31a, 0x33545486), WTCP(0x75202a02, 0x33a1198e), WTCP(0x74fe29b8, 0x33edf798), WTCP(0x74dbe211, 0x343aee09), + WTCP(0x74b952e3, 0x3487fc48), WTCP(0x74967c06, 0x34d521bb), WTCP(0x74735d51, 0x35225dc7), WTCP(0x744ff69f, 0x356fafcf), + WTCP(0x742c47c9, 0x35bd173a), WTCP(0x740850ab, 0x360a9369), WTCP(0x73e41121, 0x365823c1), WTCP(0x73bf8909, 0x36a5c7a4), + WTCP(0x739ab842, 0x36f37e75), WTCP(0x73759eab, 0x37414796), WTCP(0x73503c26, 0x378f2268), WTCP(0x732a9095, 0x37dd0e4c), + WTCP(0x73049bda, 0x382b0aa4), WTCP(0x72de5ddb, 0x387916d0), WTCP(0x72b7d67d, 0x38c73230), WTCP(0x729105a6, 0x39155c24), + WTCP(0x7269eb3f, 0x3963940c), WTCP(0x72428730, 0x39b1d946), WTCP(0x721ad964, 0x3a002b31), WTCP(0x71f2e1c5, 0x3a4e892c), + WTCP(0x71caa042, 0x3a9cf296), WTCP(0x71a214c7, 0x3aeb66cc), WTCP(0x71793f43, 0x3b39e52c), WTCP(0x71501fa6, 0x3b886d14), + WTCP(0x7126b5e3, 0x3bd6fde1), WTCP(0x70fd01eb, 0x3c2596f1), WTCP(0x70d303b2, 0x3c74379f), WTCP(0x70a8bb2e, 0x3cc2df49), + WTCP(0x707e2855, 0x3d118d4c), WTCP(0x70534b1e, 0x3d604103), WTCP(0x70282381, 0x3daef9cc), WTCP(0x6ffcb17a, 0x3dfdb702), + WTCP(0x6fd0f504, 0x3e4c7800), WTCP(0x6fa4ee1a, 0x3e9b3c25), WTCP(0x6f789cbb, 0x3eea02ca), WTCP(0x6f4c00e5, 0x3f38cb4b), + WTCP(0x6f1f1a9a, 0x3f879505), WTCP(0x6ef1e9da, 0x3fd65f53), WTCP(0x6ec46ea9, 0x40252990), WTCP(0x6e96a90b, 0x4073f318), + WTCP(0x6e689905, 0x40c2bb46), WTCP(0x6e3a3e9d, 0x41118176), WTCP(0x6e0b99dd, 0x41604504), WTCP(0x6ddcaacc, 0x41af054a), + WTCP(0x6dad7177, 0x41fdc1a5), WTCP(0x6d7dede8, 0x424c7970), WTCP(0x6d4e202e, 0x429b2c06), WTCP(0x6d1e0855, 0x42e9d8c4), + WTCP(0x6ceda66f, 0x43387f05), WTCP(0x6cbcfa8d, 0x43871e26), WTCP(0x6c8c04c0, 0x43d5b581), WTCP(0x6c5ac51d, 0x44244474), + WTCP(0x6c293bb8, 0x4472ca5a), WTCP(0x6bf768a8, 0x44c14690), WTCP(0x6bc54c06, 0x450fb873), WTCP(0x6b92e5e9, 0x455e1f5f), + WTCP(0x6b60366c, 0x45ac7ab2), WTCP(0x6b2d3dab, 0x45fac9c8), WTCP(0x6af9fbc2, 0x46490bff), WTCP(0x6ac670d1, 0x469740b5), + WTCP(0x6a929cf6, 0x46e56747), WTCP(0x6a5e8053, 0x47337f13), WTCP(0x6a2a1b0a, 0x47818779), WTCP(0x69f56d3e, 0x47cf7fd6), + WTCP(0x69c07715, 0x481d678a), WTCP(0x698b38b4, 0x486b3df3), WTCP(0x6955b243, 0x48b90272), WTCP(0x691fe3ec, 0x4906b466), + WTCP(0x68e9cdd8, 0x49545330), WTCP(0x68b37033, 0x49a1de30), WTCP(0x687ccb29, 0x49ef54c8), WTCP(0x6845dee9, 0x4a3cb657), + WTCP(0x680eaba3, 0x4a8a0242), WTCP(0x67d73187, 0x4ad737e9), WTCP(0x679f70c7, 0x4b2456af), WTCP(0x67676997, 0x4b715df7), + WTCP(0x672f1c2b, 0x4bbe4d25), WTCP(0x66f688ba, 0x4c0b239c), WTCP(0x66bdaf7b, 0x4c57e0c2), WTCP(0x668490a6, 0x4ca483fa), + WTCP(0x664b2c76, 0x4cf10cac), WTCP(0x66118326, 0x4d3d7a3b), WTCP(0x65d794f3, 0x4d89cc0f), WTCP(0x659d621a, 0x4dd6018f), + WTCP(0x6562eada, 0x4e221a22), WTCP(0x65282f74, 0x4e6e1530), WTCP(0x64ed302b, 0x4eb9f222), WTCP(0x64b1ed40, 0x4f05b061), + WTCP(0x647666f8, 0x4f514f57), WTCP(0x643a9d99, 0x4f9cce6f), WTCP(0x63fe916a, 0x4fe82d13), WTCP(0x63c242b2, 0x50336aaf), + WTCP(0x6385b1bc, 0x507e86b0), WTCP(0x6348ded1, 0x50c98082), WTCP(0x630bca3f, 0x51145793), WTCP(0x62ce7451, 0x515f0b51), + WTCP(0x6290dd57, 0x51a99b2b), WTCP(0x625305a0, 0x51f40692), WTCP(0x6214ed7d, 0x523e4cf5), WTCP(0x61d69541, 0x52886dc5), + WTCP(0x6197fd3e, 0x52d26875), WTCP(0x615925c9, 0x531c3c77), WTCP(0x611a0f39, 0x5365e93e), WTCP(0x60dab9e3, 0x53af6e3e), + WTCP(0x609b2621, 0x53f8caed), WTCP(0x605b544c, 0x5441fec0), WTCP(0x601b44bf, 0x548b092e), WTCP(0x5fdaf7d5, 0x54d3e9ae), + WTCP(0x5f9a6deb, 0x551c9fb7), WTCP(0x5f59a761, 0x55652ac3), WTCP(0x5f18a494, 0x55ad8a4d), WTCP(0x5ed765e6, 0x55f5bdcd), + WTCP(0x5e95ebb8, 0x563dc4c1), WTCP(0x5e54366d, 0x56859ea3), WTCP(0x5e12466a, 0x56cd4af3), WTCP(0x5dd01c13, 0x5714c92d), + WTCP(0x5d8db7cf, 0x575c18d0), WTCP(0x5d4b1a05, 0x57a3395e), WTCP(0x5d08431e, 0x57ea2a56), WTCP(0x5cc53384, 0x5830eb3a), + WTCP(0x5c81eba0, 0x58777b8e), WTCP(0x5c3e6bdf, 0x58bddad5), WTCP(0x5bfab4af, 0x59040893), WTCP(0x5bb6c67c, 0x594a044f), + WTCP(0x5b72a1b6, 0x598fcd8e), WTCP(0x5b2e46ce, 0x59d563d9), WTCP(0x5ae9b634, 0x5a1ac6b8), WTCP(0x5aa4f05a, 0x5a5ff5b5), +}; + +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_WTP SineWindow120[] = +{ + WTCP(0x7fff4c54, 0x00d676eb), WTCP(0x7ff9af04, 0x02835b5a), WTCP(0x7fee74a2, 0x0430238f), WTCP(0x7fdd9dad, 0x05dcbcbe), + WTCP(0x7fc72ae2, 0x07891418), WTCP(0x7fab1d3d, 0x093516d4), WTCP(0x7f8975f9, 0x0ae0b22c), WTCP(0x7f62368f, 0x0c8bd35e), + WTCP(0x7f3560b9, 0x0e3667ad), WTCP(0x7f02f66f, 0x0fe05c64), WTCP(0x7ecaf9e5, 0x11899ed3), WTCP(0x7e8d6d91, 0x13321c53), + WTCP(0x7e4a5426, 0x14d9c245), WTCP(0x7e01b096, 0x16807e15), WTCP(0x7db3860f, 0x18263d36), WTCP(0x7d5fd801, 0x19caed29), + WTCP(0x7d06aa16, 0x1b6e7b7a), WTCP(0x7ca80038, 0x1d10d5c2), WTCP(0x7c43de8e, 0x1eb1e9a7), WTCP(0x7bda497d, 0x2051a4dd), + WTCP(0x7b6b45a5, 0x21eff528), WTCP(0x7af6d7e6, 0x238cc85d), WTCP(0x7a7d055b, 0x25280c5e), WTCP(0x79fdd35c, 0x26c1af22), + WTCP(0x7979477d, 0x28599eb0), WTCP(0x78ef678f, 0x29efc925), WTCP(0x7860399e, 0x2b841caf), WTCP(0x77cbc3f2, 0x2d168792), + WTCP(0x77320d0d, 0x2ea6f827), WTCP(0x76931bae, 0x30355cdd), WTCP(0x75eef6ce, 0x31c1a43b), WTCP(0x7545a5a0, 0x334bbcde), + WTCP(0x74972f92, 0x34d3957e), WTCP(0x73e39c49, 0x36591cea), WTCP(0x732af3a7, 0x37dc420c), WTCP(0x726d3dc6, 0x395cf3e9), + WTCP(0x71aa82f7, 0x3adb21a1), WTCP(0x70e2cbc6, 0x3c56ba70), WTCP(0x701620f5, 0x3dcfadb0), WTCP(0x6f448b7e, 0x3f45ead8), + WTCP(0x6e6e1492, 0x40b9617d), WTCP(0x6d92c59b, 0x422a0154), WTCP(0x6cb2a837, 0x4397ba32), WTCP(0x6bcdc639, 0x45027c0c), + WTCP(0x6ae429ae, 0x466a36f9), WTCP(0x69f5dcd3, 0x47cedb31), WTCP(0x6902ea1d, 0x4930590f), WTCP(0x680b5c33, 0x4a8ea111), + WTCP(0x670f3df3, 0x4be9a3db), WTCP(0x660e9a6a, 0x4d415234), WTCP(0x65097cdb, 0x4e959d08), WTCP(0x63fff0ba, 0x4fe6756a), + WTCP(0x62f201ac, 0x5133cc94), WTCP(0x61dfbb8a, 0x527d93e6), WTCP(0x60c92a5a, 0x53c3bcea), WTCP(0x5fae5a55, 0x55063951), + WTCP(0x5e8f57e2, 0x5644faf4), WTCP(0x5d6c2f99, 0x577ff3da), WTCP(0x5c44ee40, 0x58b71632), WTCP(0x5b19a0c8, 0x59ea5454), +}; + +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_WTP KBDWindow120[] = +{ + WTCP(0x7ffffffe, 0x00017b6f), WTCP(0x7fffffef, 0x00042d2f), WTCP(0x7fffffbb, 0x000849d0), WTCP(0x7fffff36, 0x000e3494), + WTCP(0x7ffffe0c, 0x00165efd), WTCP(0x7ffffbac, 0x002149be), WTCP(0x7ffff72e, 0x002f854c), WTCP(0x7fffef24, 0x0041b235), + WTCP(0x7fffe167, 0x0058814f), WTCP(0x7fffcacd, 0x0074b3af), WTCP(0x7fffa6d0, 0x00971a67), WTCP(0x7fff6f1e, 0x00c0960e), + WTCP(0x7fff1b12, 0x00f21602), WTCP(0x7ffe9f0b, 0x012c9775), WTCP(0x7ffdebb2, 0x01712428), WTCP(0x7ffced1b, 0x01c0d0f7), + WTCP(0x7ffb89c2, 0x021cbc12), WTCP(0x7ff9a17c, 0x02860b05), WTCP(0x7ff70c39, 0x02fde875), WTCP(0x7ff398bc, 0x038581b3), + WTCP(0x7fef0b3b, 0x041e040c), WTCP(0x7fe91bf3, 0x04c899f4), WTCP(0x7fe175ba, 0x05866803), WTCP(0x7fd7b493, 0x065889d5), + WTCP(0x7fcb6459, 0x07400ed4), WTCP(0x7fbbff82, 0x083df6e9), WTCP(0x7fa8ee09, 0x09532f37), WTCP(0x7f91849a, 0x0a808ed1), + WTCP(0x7f7503f2, 0x0bc6d381), WTCP(0x7f52989a, 0x0d269eb0), WTCP(0x7f295af4, 0x0ea07270), WTCP(0x7ef84fb6, 0x1034aeb6), + WTCP(0x7ebe68c5, 0x11e38ed2), WTCP(0x7e7a8686, 0x13ad2733), WTCP(0x7e2b79a3, 0x1591636d), WTCP(0x7dd0053c, 0x179004a7), + WTCP(0x7d66e18b, 0x19a8a05f), WTCP(0x7ceebef0, 0x1bda9fa2), WTCP(0x7c664953, 0x1e253ea1), WTCP(0x7bcc2be8, 0x20878cce), + WTCP(0x7b1f1526, 0x23006d5d), WTCP(0x7a5dbb01, 0x258e9848), WTCP(0x7986df3e, 0x28309bc6), WTCP(0x789953e0, 0x2ae4de3e), + WTCP(0x7793ff88, 0x2da9a0a8), WTCP(0x7675e1cc, 0x307d0163), WTCP(0x753e1763, 0x335cff72), WTCP(0x73ebde10, 0x36477e1f), + WTCP(0x727e984e, 0x393a48f1), WTCP(0x70f5d09b, 0x3c3317f9), WTCP(0x6f513c60, 0x3f2f945c), WTCP(0x6d90be61, 0x422d5d18), + WTCP(0x6bb468b1, 0x452a0bf3), WTCP(0x69bc7e1e, 0x48233a81), WTCP(0x67a97317, 0x4b16873e), WTCP(0x657bedfa, 0x4e019a9d), + WTCP(0x6334c6d2, 0x50e22c0b), WTCP(0x60d50689, 0x53b606cb), WTCP(0x5e5de588, 0x567b0ea7), WTCP(0x5bd0c9c6, 0x592f4460), +}; + +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_WTP SineWindow512[] = +{ + WTCP(0x7ffff621, 0x003243f5), WTCP(0x7fffa72c, 0x0096cbc1), WTCP(0x7fff0943, 0x00fb5330), WTCP(0x7ffe1c65, 0x015fda03), + WTCP(0x7ffce093, 0x01c45ffe), WTCP(0x7ffb55ce, 0x0228e4e2), WTCP(0x7ff97c18, 0x028d6870), WTCP(0x7ff75370, 0x02f1ea6c), + WTCP(0x7ff4dbd9, 0x03566a96), WTCP(0x7ff21553, 0x03bae8b2), WTCP(0x7feeffe1, 0x041f6480), WTCP(0x7feb9b85, 0x0483ddc3), + WTCP(0x7fe7e841, 0x04e8543e), WTCP(0x7fe3e616, 0x054cc7b1), WTCP(0x7fdf9508, 0x05b137df), WTCP(0x7fdaf519, 0x0615a48b), + WTCP(0x7fd6064c, 0x067a0d76), WTCP(0x7fd0c8a3, 0x06de7262), WTCP(0x7fcb3c23, 0x0742d311), WTCP(0x7fc560cf, 0x07a72f45), + WTCP(0x7fbf36aa, 0x080b86c2), WTCP(0x7fb8bdb8, 0x086fd947), WTCP(0x7fb1f5fc, 0x08d42699), WTCP(0x7faadf7c, 0x09386e78), + WTCP(0x7fa37a3c, 0x099cb0a7), WTCP(0x7f9bc640, 0x0a00ece8), WTCP(0x7f93c38c, 0x0a6522fe), WTCP(0x7f8b7227, 0x0ac952aa), + WTCP(0x7f82d214, 0x0b2d7baf), WTCP(0x7f79e35a, 0x0b919dcf), WTCP(0x7f70a5fe, 0x0bf5b8cb), WTCP(0x7f671a05, 0x0c59cc68), + WTCP(0x7f5d3f75, 0x0cbdd865), WTCP(0x7f531655, 0x0d21dc87), WTCP(0x7f489eaa, 0x0d85d88f), WTCP(0x7f3dd87c, 0x0de9cc40), + WTCP(0x7f32c3d1, 0x0e4db75b), WTCP(0x7f2760af, 0x0eb199a4), WTCP(0x7f1baf1e, 0x0f1572dc), WTCP(0x7f0faf25, 0x0f7942c7), + WTCP(0x7f0360cb, 0x0fdd0926), WTCP(0x7ef6c418, 0x1040c5bb), WTCP(0x7ee9d914, 0x10a4784b), WTCP(0x7edc9fc6, 0x11082096), + WTCP(0x7ecf1837, 0x116bbe60), WTCP(0x7ec14270, 0x11cf516a), WTCP(0x7eb31e78, 0x1232d979), WTCP(0x7ea4ac58, 0x1296564d), + WTCP(0x7e95ec1a, 0x12f9c7aa), WTCP(0x7e86ddc6, 0x135d2d53), WTCP(0x7e778166, 0x13c0870a), WTCP(0x7e67d703, 0x1423d492), + WTCP(0x7e57dea7, 0x148715ae), WTCP(0x7e47985b, 0x14ea4a1f), WTCP(0x7e37042a, 0x154d71aa), WTCP(0x7e26221f, 0x15b08c12), + WTCP(0x7e14f242, 0x16139918), WTCP(0x7e0374a0, 0x1676987f), WTCP(0x7df1a942, 0x16d98a0c), WTCP(0x7ddf9034, 0x173c6d80), + WTCP(0x7dcd2981, 0x179f429f), WTCP(0x7dba7534, 0x1802092c), WTCP(0x7da77359, 0x1864c0ea), WTCP(0x7d9423fc, 0x18c7699b), + WTCP(0x7d808728, 0x192a0304), WTCP(0x7d6c9ce9, 0x198c8ce7), WTCP(0x7d58654d, 0x19ef0707), WTCP(0x7d43e05e, 0x1a517128), + WTCP(0x7d2f0e2b, 0x1ab3cb0d), WTCP(0x7d19eebf, 0x1b161479), WTCP(0x7d048228, 0x1b784d30), WTCP(0x7ceec873, 0x1bda74f6), + WTCP(0x7cd8c1ae, 0x1c3c8b8c), WTCP(0x7cc26de5, 0x1c9e90b8), WTCP(0x7cabcd28, 0x1d00843d), WTCP(0x7c94df83, 0x1d6265dd), + WTCP(0x7c7da505, 0x1dc4355e), WTCP(0x7c661dbc, 0x1e25f282), WTCP(0x7c4e49b7, 0x1e879d0d), WTCP(0x7c362904, 0x1ee934c3), + WTCP(0x7c1dbbb3, 0x1f4ab968), WTCP(0x7c0501d2, 0x1fac2abf), WTCP(0x7bebfb70, 0x200d888d), WTCP(0x7bd2a89e, 0x206ed295), + WTCP(0x7bb9096b, 0x20d0089c), WTCP(0x7b9f1de6, 0x21312a65), WTCP(0x7b84e61f, 0x219237b5), WTCP(0x7b6a6227, 0x21f3304f), + WTCP(0x7b4f920e, 0x225413f8), WTCP(0x7b3475e5, 0x22b4e274), WTCP(0x7b190dbc, 0x23159b88), WTCP(0x7afd59a4, 0x23763ef7), + WTCP(0x7ae159ae, 0x23d6cc87), WTCP(0x7ac50dec, 0x243743fa), WTCP(0x7aa8766f, 0x2497a517), WTCP(0x7a8b9348, 0x24f7efa2), + WTCP(0x7a6e648a, 0x2558235f), WTCP(0x7a50ea47, 0x25b84012), WTCP(0x7a332490, 0x26184581), WTCP(0x7a151378, 0x26783370), + WTCP(0x79f6b711, 0x26d809a5), WTCP(0x79d80f6f, 0x2737c7e3), WTCP(0x79b91ca4, 0x27976df1), WTCP(0x7999dec4, 0x27f6fb92), + WTCP(0x797a55e0, 0x2856708d), WTCP(0x795a820e, 0x28b5cca5), WTCP(0x793a6361, 0x29150fa1), WTCP(0x7919f9ec, 0x29743946), + WTCP(0x78f945c3, 0x29d34958), WTCP(0x78d846fb, 0x2a323f9e), WTCP(0x78b6fda8, 0x2a911bdc), WTCP(0x789569df, 0x2aefddd8), + WTCP(0x78738bb3, 0x2b4e8558), WTCP(0x7851633b, 0x2bad1221), WTCP(0x782ef08b, 0x2c0b83fa), WTCP(0x780c33b8, 0x2c69daa6), + WTCP(0x77e92cd9, 0x2cc815ee), WTCP(0x77c5dc01, 0x2d263596), WTCP(0x77a24148, 0x2d843964), WTCP(0x777e5cc3, 0x2de2211e), + WTCP(0x775a2e89, 0x2e3fec8b), WTCP(0x7735b6af, 0x2e9d9b70), WTCP(0x7710f54c, 0x2efb2d95), WTCP(0x76ebea77, 0x2f58a2be), + WTCP(0x76c69647, 0x2fb5fab2), WTCP(0x76a0f8d2, 0x30133539), WTCP(0x767b1231, 0x30705217), WTCP(0x7654e279, 0x30cd5115), + WTCP(0x762e69c4, 0x312a31f8), WTCP(0x7607a828, 0x3186f487), WTCP(0x75e09dbd, 0x31e39889), WTCP(0x75b94a9c, 0x32401dc6), + WTCP(0x7591aedd, 0x329c8402), WTCP(0x7569ca99, 0x32f8cb07), WTCP(0x75419de7, 0x3354f29b), WTCP(0x751928e0, 0x33b0fa84), + WTCP(0x74f06b9e, 0x340ce28b), WTCP(0x74c7663a, 0x3468aa76), WTCP(0x749e18cd, 0x34c4520d), WTCP(0x74748371, 0x351fd918), + WTCP(0x744aa63f, 0x357b3f5d), WTCP(0x74208150, 0x35d684a6), WTCP(0x73f614c0, 0x3631a8b8), WTCP(0x73cb60a8, 0x368cab5c), + WTCP(0x73a06522, 0x36e78c5b), WTCP(0x73752249, 0x37424b7b), WTCP(0x73499838, 0x379ce885), WTCP(0x731dc70a, 0x37f76341), + WTCP(0x72f1aed9, 0x3851bb77), WTCP(0x72c54fc1, 0x38abf0ef), WTCP(0x7298a9dd, 0x39060373), WTCP(0x726bbd48, 0x395ff2c9), + WTCP(0x723e8a20, 0x39b9bebc), WTCP(0x7211107e, 0x3a136712), WTCP(0x71e35080, 0x3a6ceb96), WTCP(0x71b54a41, 0x3ac64c0f), + WTCP(0x7186fdde, 0x3b1f8848), WTCP(0x71586b74, 0x3b78a007), WTCP(0x7129931f, 0x3bd19318), WTCP(0x70fa74fc, 0x3c2a6142), + WTCP(0x70cb1128, 0x3c830a50), WTCP(0x709b67c0, 0x3cdb8e09), WTCP(0x706b78e3, 0x3d33ec39), WTCP(0x703b44ad, 0x3d8c24a8), + WTCP(0x700acb3c, 0x3de4371f), WTCP(0x6fda0cae, 0x3e3c2369), WTCP(0x6fa90921, 0x3e93e950), WTCP(0x6f77c0b3, 0x3eeb889c), + WTCP(0x6f463383, 0x3f430119), WTCP(0x6f1461b0, 0x3f9a5290), WTCP(0x6ee24b57, 0x3ff17cca), WTCP(0x6eaff099, 0x40487f94), + WTCP(0x6e7d5193, 0x409f5ab6), WTCP(0x6e4a6e66, 0x40f60dfb), WTCP(0x6e174730, 0x414c992f), WTCP(0x6de3dc11, 0x41a2fc1a), + WTCP(0x6db02d29, 0x41f93689), WTCP(0x6d7c3a98, 0x424f4845), WTCP(0x6d48047e, 0x42a5311b), WTCP(0x6d138afb, 0x42faf0d4), + WTCP(0x6cdece2f, 0x4350873c), WTCP(0x6ca9ce3b, 0x43a5f41e), WTCP(0x6c748b3f, 0x43fb3746), WTCP(0x6c3f055d, 0x4450507e), + WTCP(0x6c093cb6, 0x44a53f93), WTCP(0x6bd3316a, 0x44fa0450), WTCP(0x6b9ce39b, 0x454e9e80), WTCP(0x6b66536b, 0x45a30df0), + WTCP(0x6b2f80fb, 0x45f7526b), WTCP(0x6af86c6c, 0x464b6bbe), WTCP(0x6ac115e2, 0x469f59b4), WTCP(0x6a897d7d, 0x46f31c1a), + WTCP(0x6a51a361, 0x4746b2bc), WTCP(0x6a1987b0, 0x479a1d67), WTCP(0x69e12a8c, 0x47ed5be6), WTCP(0x69a88c19, 0x48406e08), + WTCP(0x696fac78, 0x48935397), WTCP(0x69368bce, 0x48e60c62), WTCP(0x68fd2a3d, 0x49389836), WTCP(0x68c387e9, 0x498af6df), + WTCP(0x6889a4f6, 0x49dd282a), WTCP(0x684f8186, 0x4a2f2be6), WTCP(0x68151dbe, 0x4a8101de), WTCP(0x67da79c3, 0x4ad2a9e2), + WTCP(0x679f95b7, 0x4b2423be), WTCP(0x676471c0, 0x4b756f40), WTCP(0x67290e02, 0x4bc68c36), WTCP(0x66ed6aa1, 0x4c177a6e), + WTCP(0x66b187c3, 0x4c6839b7), WTCP(0x6675658c, 0x4cb8c9dd), WTCP(0x66390422, 0x4d092ab0), WTCP(0x65fc63a9, 0x4d595bfe), + WTCP(0x65bf8447, 0x4da95d96), WTCP(0x65826622, 0x4df92f46), WTCP(0x6545095f, 0x4e48d0dd), WTCP(0x65076e25, 0x4e984229), + WTCP(0x64c99498, 0x4ee782fb), WTCP(0x648b7ce0, 0x4f369320), WTCP(0x644d2722, 0x4f857269), WTCP(0x640e9386, 0x4fd420a4), + WTCP(0x63cfc231, 0x50229da1), WTCP(0x6390b34a, 0x5070e92f), WTCP(0x635166f9, 0x50bf031f), WTCP(0x6311dd64, 0x510ceb40), + WTCP(0x62d216b3, 0x515aa162), WTCP(0x6292130c, 0x51a82555), WTCP(0x6251d298, 0x51f576ea), WTCP(0x6211557e, 0x524295f0), + WTCP(0x61d09be5, 0x528f8238), WTCP(0x618fa5f7, 0x52dc3b92), WTCP(0x614e73da, 0x5328c1d0), WTCP(0x610d05b7, 0x537514c2), + WTCP(0x60cb5bb7, 0x53c13439), WTCP(0x60897601, 0x540d2005), WTCP(0x604754bf, 0x5458d7f9), WTCP(0x6004f819, 0x54a45be6), + WTCP(0x5fc26038, 0x54efab9c), WTCP(0x5f7f8d46, 0x553ac6ee), WTCP(0x5f3c7f6b, 0x5585adad), WTCP(0x5ef936d1, 0x55d05faa), + WTCP(0x5eb5b3a2, 0x561adcb9), WTCP(0x5e71f606, 0x566524aa), WTCP(0x5e2dfe29, 0x56af3750), WTCP(0x5de9cc33, 0x56f9147e), + WTCP(0x5da5604f, 0x5742bc06), WTCP(0x5d60baa7, 0x578c2dba), WTCP(0x5d1bdb65, 0x57d5696d), WTCP(0x5cd6c2b5, 0x581e6ef1), + WTCP(0x5c9170bf, 0x58673e1b), WTCP(0x5c4be5b0, 0x58afd6bd), WTCP(0x5c0621b2, 0x58f838a9), WTCP(0x5bc024f0, 0x594063b5), + WTCP(0x5b79ef96, 0x598857b2), WTCP(0x5b3381ce, 0x59d01475), WTCP(0x5aecdbc5, 0x5a1799d1), WTCP(0x5aa5fda5, 0x5a5ee79a), +}; + +/* The window coefficients are calculated according to the formula: + * N=FRAME_LEN_LONG_LD480 + * win[n]=sin(pi*(n+0.5)/(2*N)) for n=0,..,N-1 */ +RAM_ALIGN +LNK_SECTION_CONSTDATA +const FIXP_WTP SineWindow480[480] = +{ + WTCP(0x7ffff4c5, 0x00359dd2), WTCP(0x7fff9aef, 0x00a0d951), WTCP(0x7ffee744, 0x010c1460), WTCP(0x7ffdd9c4, 0x01774eb2), + WTCP(0x7ffc726f, 0x01e287fc), WTCP(0x7ffab147, 0x024dbff4), WTCP(0x7ff8964d, 0x02b8f64e), WTCP(0x7ff62182, 0x03242abf), + WTCP(0x7ff352e8, 0x038f5cfb), WTCP(0x7ff02a82, 0x03fa8cb8), WTCP(0x7feca851, 0x0465b9aa), WTCP(0x7fe8cc57, 0x04d0e386), + WTCP(0x7fe49698, 0x053c0a01), WTCP(0x7fe00716, 0x05a72ccf), WTCP(0x7fdb1dd5, 0x06124ba5), WTCP(0x7fd5dad8, 0x067d6639), + WTCP(0x7fd03e23, 0x06e87c3f), WTCP(0x7fca47b9, 0x07538d6b), WTCP(0x7fc3f7a0, 0x07be9973), WTCP(0x7fbd4dda, 0x0829a00c), + WTCP(0x7fb64a6e, 0x0894a0ea), WTCP(0x7faeed5f, 0x08ff9bc2), WTCP(0x7fa736b4, 0x096a9049), WTCP(0x7f9f2671, 0x09d57e35), + WTCP(0x7f96bc9c, 0x0a40653a), WTCP(0x7f8df93c, 0x0aab450d), WTCP(0x7f84dc55, 0x0b161d63), WTCP(0x7f7b65ef, 0x0b80edf1), + WTCP(0x7f719611, 0x0bebb66c), WTCP(0x7f676cc0, 0x0c56768a), WTCP(0x7f5cea05, 0x0cc12dff), WTCP(0x7f520de6, 0x0d2bdc80), + WTCP(0x7f46d86c, 0x0d9681c2), WTCP(0x7f3b499d, 0x0e011d7c), WTCP(0x7f2f6183, 0x0e6baf61), WTCP(0x7f232026, 0x0ed63727), + WTCP(0x7f16858e, 0x0f40b483), WTCP(0x7f0991c4, 0x0fab272b), WTCP(0x7efc44d0, 0x10158ed4), WTCP(0x7eee9ebe, 0x107feb33), + WTCP(0x7ee09f95, 0x10ea3bfd), WTCP(0x7ed24761, 0x115480e9), WTCP(0x7ec3962a, 0x11beb9aa), WTCP(0x7eb48bfb, 0x1228e5f8), + WTCP(0x7ea528e0, 0x12930586), WTCP(0x7e956ce1, 0x12fd180b), WTCP(0x7e85580c, 0x13671d3d), WTCP(0x7e74ea6a, 0x13d114d0), + WTCP(0x7e642408, 0x143afe7b), WTCP(0x7e5304f2, 0x14a4d9f4), WTCP(0x7e418d32, 0x150ea6ef), WTCP(0x7e2fbcd6, 0x15786522), + WTCP(0x7e1d93ea, 0x15e21445), WTCP(0x7e0b127a, 0x164bb40b), WTCP(0x7df83895, 0x16b5442b), WTCP(0x7de50646, 0x171ec45c), + WTCP(0x7dd17b9c, 0x17883452), WTCP(0x7dbd98a4, 0x17f193c5), WTCP(0x7da95d6c, 0x185ae269), WTCP(0x7d94ca03, 0x18c41ff6), + WTCP(0x7d7fde76, 0x192d4c21), WTCP(0x7d6a9ad5, 0x199666a0), WTCP(0x7d54ff2e, 0x19ff6f2a), WTCP(0x7d3f0b90, 0x1a686575), + WTCP(0x7d28c00c, 0x1ad14938), WTCP(0x7d121cb0, 0x1b3a1a28), WTCP(0x7cfb218c, 0x1ba2d7fc), WTCP(0x7ce3ceb2, 0x1c0b826a), + WTCP(0x7ccc2430, 0x1c74192a), WTCP(0x7cb42217, 0x1cdc9bf2), WTCP(0x7c9bc87a, 0x1d450a78), WTCP(0x7c831767, 0x1dad6473), + WTCP(0x7c6a0ef2, 0x1e15a99a), WTCP(0x7c50af2b, 0x1e7dd9a4), WTCP(0x7c36f824, 0x1ee5f447), WTCP(0x7c1ce9ef, 0x1f4df93a), + WTCP(0x7c02849f, 0x1fb5e836), WTCP(0x7be7c847, 0x201dc0ef), WTCP(0x7bccb4f8, 0x2085831f), WTCP(0x7bb14ac5, 0x20ed2e7b), + WTCP(0x7b9589c3, 0x2154c2bb), WTCP(0x7b797205, 0x21bc3f97), WTCP(0x7b5d039e, 0x2223a4c5), WTCP(0x7b403ea2, 0x228af1fe), + WTCP(0x7b232325, 0x22f226f8), WTCP(0x7b05b13d, 0x2359436c), WTCP(0x7ae7e8fc, 0x23c04710), WTCP(0x7ac9ca7a, 0x2427319d), + WTCP(0x7aab55ca, 0x248e02cb), WTCP(0x7a8c8b01, 0x24f4ba50), WTCP(0x7a6d6a37, 0x255b57e6), WTCP(0x7a4df380, 0x25c1db44), + WTCP(0x7a2e26f2, 0x26284422), WTCP(0x7a0e04a4, 0x268e9238), WTCP(0x79ed8cad, 0x26f4c53e), WTCP(0x79ccbf22, 0x275adcee), + WTCP(0x79ab9c1c, 0x27c0d8fe), WTCP(0x798a23b1, 0x2826b928), WTCP(0x796855f9, 0x288c7d24), WTCP(0x7946330c, 0x28f224ab), + WTCP(0x7923bb01, 0x2957af74), WTCP(0x7900edf2, 0x29bd1d3a), WTCP(0x78ddcbf5, 0x2a226db5), WTCP(0x78ba5524, 0x2a87a09d), + WTCP(0x78968998, 0x2aecb5ac), WTCP(0x7872696a, 0x2b51ac9a), WTCP(0x784df4b3, 0x2bb68522), WTCP(0x78292b8d, 0x2c1b3efb), + WTCP(0x78040e12, 0x2c7fd9e0), WTCP(0x77de9c5b, 0x2ce45589), WTCP(0x77b8d683, 0x2d48b1b1), WTCP(0x7792bca5, 0x2dacee11), + WTCP(0x776c4edb, 0x2e110a62), WTCP(0x77458d40, 0x2e75065e), WTCP(0x771e77f0, 0x2ed8e1c0), WTCP(0x76f70f05, 0x2f3c9c40), + WTCP(0x76cf529c, 0x2fa03599), WTCP(0x76a742d1, 0x3003ad85), WTCP(0x767edfbe, 0x306703bf), WTCP(0x76562982, 0x30ca3800), + WTCP(0x762d2038, 0x312d4a03), WTCP(0x7603c3fd, 0x31903982), WTCP(0x75da14ef, 0x31f30638), WTCP(0x75b01329, 0x3255afe0), + WTCP(0x7585becb, 0x32b83634), WTCP(0x755b17f2, 0x331a98ef), WTCP(0x75301ebb, 0x337cd7cd), WTCP(0x7504d345, 0x33def287), + WTCP(0x74d935ae, 0x3440e8da), WTCP(0x74ad4615, 0x34a2ba81), WTCP(0x74810499, 0x35046736), WTCP(0x74547158, 0x3565eeb6), + WTCP(0x74278c72, 0x35c750bc), WTCP(0x73fa5607, 0x36288d03), WTCP(0x73ccce36, 0x3689a348), WTCP(0x739ef51f, 0x36ea9346), + WTCP(0x7370cae2, 0x374b5cb9), WTCP(0x73424fa0, 0x37abff5d), WTCP(0x73138379, 0x380c7aee), WTCP(0x72e4668f, 0x386ccf2a), + WTCP(0x72b4f902, 0x38ccfbcb), WTCP(0x72853af3, 0x392d008f), WTCP(0x72552c85, 0x398cdd32), WTCP(0x7224cdd8, 0x39ec9172), + WTCP(0x71f41f0f, 0x3a4c1d09), WTCP(0x71c3204c, 0x3aab7fb7), WTCP(0x7191d1b1, 0x3b0ab937), WTCP(0x71603361, 0x3b69c947), + WTCP(0x712e457f, 0x3bc8afa5), WTCP(0x70fc082d, 0x3c276c0d), WTCP(0x70c97b90, 0x3c85fe3d), WTCP(0x70969fca, 0x3ce465f3), + WTCP(0x706374ff, 0x3d42a2ec), WTCP(0x702ffb54, 0x3da0b4e7), WTCP(0x6ffc32eb, 0x3dfe9ba1), WTCP(0x6fc81bea, 0x3e5c56d8), + WTCP(0x6f93b676, 0x3eb9e64b), WTCP(0x6f5f02b2, 0x3f1749b8), WTCP(0x6f2a00c4, 0x3f7480dd), WTCP(0x6ef4b0d1, 0x3fd18b7a), + WTCP(0x6ebf12ff, 0x402e694c), WTCP(0x6e892772, 0x408b1a12), WTCP(0x6e52ee52, 0x40e79d8c), WTCP(0x6e1c67c4, 0x4143f379), + WTCP(0x6de593ee, 0x41a01b97), WTCP(0x6dae72f7, 0x41fc15a6), WTCP(0x6d770506, 0x4257e166), WTCP(0x6d3f4a40, 0x42b37e96), + WTCP(0x6d0742cf, 0x430eecf6), WTCP(0x6cceeed8, 0x436a2c45), WTCP(0x6c964e83, 0x43c53c44), WTCP(0x6c5d61f9, 0x44201cb2), + WTCP(0x6c242960, 0x447acd50), WTCP(0x6beaa4e2, 0x44d54ddf), WTCP(0x6bb0d4a7, 0x452f9e1e), WTCP(0x6b76b8d6, 0x4589bdcf), + WTCP(0x6b3c519a, 0x45e3acb1), WTCP(0x6b019f1a, 0x463d6a87), WTCP(0x6ac6a180, 0x4696f710), WTCP(0x6a8b58f6, 0x46f0520f), + WTCP(0x6a4fc5a6, 0x47497b44), WTCP(0x6a13e7b8, 0x47a27271), WTCP(0x69d7bf57, 0x47fb3757), WTCP(0x699b4cad, 0x4853c9b9), + WTCP(0x695e8fe5, 0x48ac2957), WTCP(0x69218929, 0x490455f4), WTCP(0x68e438a4, 0x495c4f52), WTCP(0x68a69e81, 0x49b41533), + WTCP(0x6868baec, 0x4a0ba75b), WTCP(0x682a8e0f, 0x4a63058a), WTCP(0x67ec1817, 0x4aba2f84), WTCP(0x67ad592f, 0x4b11250c), + WTCP(0x676e5183, 0x4b67e5e4), WTCP(0x672f013f, 0x4bbe71d1), WTCP(0x66ef6891, 0x4c14c894), WTCP(0x66af87a4, 0x4c6ae9f2), + WTCP(0x666f5ea6, 0x4cc0d5ae), WTCP(0x662eedc3, 0x4d168b8b), WTCP(0x65ee3529, 0x4d6c0b4e), WTCP(0x65ad3505, 0x4dc154bb), + WTCP(0x656bed84, 0x4e166795), WTCP(0x652a5ed6, 0x4e6b43a2), WTCP(0x64e88926, 0x4ebfe8a5), WTCP(0x64a66ca5, 0x4f145662), + WTCP(0x6464097f, 0x4f688ca0), WTCP(0x64215fe5, 0x4fbc8b22), WTCP(0x63de7003, 0x501051ae), WTCP(0x639b3a0b, 0x5063e008), + WTCP(0x6357be2a, 0x50b735f8), WTCP(0x6313fc90, 0x510a5340), WTCP(0x62cff56c, 0x515d37a9), WTCP(0x628ba8ef, 0x51afe2f6), + WTCP(0x62471749, 0x520254ef), WTCP(0x620240a8, 0x52548d59), WTCP(0x61bd253f, 0x52a68bfb), WTCP(0x6177c53c, 0x52f8509b), + WTCP(0x613220d2, 0x5349daff), WTCP(0x60ec3830, 0x539b2af0), WTCP(0x60a60b88, 0x53ec4032), WTCP(0x605f9b0b, 0x543d1a8e), + WTCP(0x6018e6eb, 0x548db9cb), WTCP(0x5fd1ef59, 0x54de1db1), WTCP(0x5f8ab487, 0x552e4605), WTCP(0x5f4336a7, 0x557e3292), + WTCP(0x5efb75ea, 0x55cde31e), WTCP(0x5eb37285, 0x561d5771), WTCP(0x5e6b2ca8, 0x566c8f55), WTCP(0x5e22a487, 0x56bb8a90), + WTCP(0x5dd9da55, 0x570a48ec), WTCP(0x5d90ce45, 0x5758ca31), WTCP(0x5d47808a, 0x57a70e29), WTCP(0x5cfdf157, 0x57f5149d), + WTCP(0x5cb420e0, 0x5842dd54), WTCP(0x5c6a0f59, 0x5890681a), WTCP(0x5c1fbcf6, 0x58ddb4b8), WTCP(0x5bd529eb, 0x592ac2f7), + WTCP(0x5b8a566c, 0x597792a1), WTCP(0x5b3f42ae, 0x59c42381), WTCP(0x5af3eee6, 0x5a107561), WTCP(0x5aa85b48, 0x5a5c880a), +}; + + + + + + +/** + * \brief Helper table containing the length, rasterand shape mapping to individual window slope tables. + * [0: sine ][0: radix2 raster ][ceil(log2(length)) length 4 .. 1024 ] + * [1: 10ms raster ][ceil(log2(length)) length 3.25 .. 960 ] + * [2: 3/4 of radix 2 raster][ceil(log2(length)) length 3 .. 768 ] + * [1: KBD ][0: radix2 raster ][ceil(log2(length)) length 128 .. 1024 ] + * [1: 10ms raster ][ceil(log2(length)) length 120 .. 960 ] + * [2: 3/4 of radix 2 raster][ceil(log2(length)) length 96 .. 768 ] + */ +const FIXP_WTP *const windowSlopes[2][3][9] = +{ + { /* Sine */ + { /* Radix 2 */ + NULL, + NULL, + NULL, + SineWindow32, + SineWindow64, + SineWindow128, + NULL, + SineWindow512, + SineWindow1024 + }, + { /* 10ms raster */ + NULL, /* 3.25 */ + NULL, /* 7.5 */ + NULL, + NULL, + NULL, + SineWindow120, + NULL, + SineWindow480, + SineWindow960 + }, + { /* 3/4 radix2 raster */ + NULL, /* 3 */ + NULL, /* 6 */ +#ifdef INCLUDE_SineWindow12 + SineWindow12, +#else + NULL, +#endif + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + } + }, + { /* KBD */ + { /* Radix 2 */ + KBDWindow128, + NULL, + SineWindow512, + KBDWindow1024 + }, + { /* 10ms raster */ + KBDWindow120, + NULL, + SineWindow480, + KBDWindow960 + }, + { /* 3/4 radix2 raster */ + NULL, + NULL, + NULL, + NULL + } + } +}; + +const FIXP_WTP * FDKgetWindowSlope(int length, int shape) +{ + const FIXP_WTP * w = NULL; + int raster, ld2_length; + + /* Get ld2 of length - 2 + 1 + -2: because first table entry is window of size 4 + +1: because we already include +1 because of ceil(log2(length)) */ + ld2_length = DFRACT_BITS-1-fNormz((FIXP_DBL)length) - 1; + + /* Extract sort of "eigenvalue" (the 4 left most bits) of length. */ + switch ( (length) >> (ld2_length-2) ) { + case 0x8: /* radix 2 */ + raster = 0; + ld2_length--; /* revert + 1 because of ceil(log2(length)) from above. */ + break; + case 0xf: /* 10 ms */ + raster = 1; + break; + case 0xc: /* 3/4 of radix 2 */ + raster = 2; + break; + default: + raster = 0; + break; + } + + /* The table for sine windows (shape == 0) is 5 entries longer. */ + if (shape == 1) { + ld2_length-=5; + } + + /* Look up table */ + w = windowSlopes[shape&1][raster][ld2_length]; + + FDK_ASSERT(w != NULL); + + return w; +} + + +/* + * QMF filter and twiddle tables + */ + +#ifdef QMF_COEFF_16BIT +#define QFC(x) FX_DBL2FXCONST_SGL(x) +#define QTCFL(x) FL2FXCONST_SGL(x) +#define QTC(x) FX_DBL2FXCONST_SGL(x) +#else +#define QFC(x) (x) +#define QTCFL(x) FL2FXCONST_DBL(x) +#define QTC(x) (x) +#endif /* ARCH_PREFER_MULT_32x16 */ + +#ifndef LOW_POWER_SBR_ONLY +/*! + \name QMF-Twiddle + \brief QMF twiddle factors + + L=32, gain=2.0, angle = 0.75 +*/ + +const FIXP_QTW qmf_phaseshift_cos32[32] = +{ + QTCFL( 0.99932238458835f),QTCFL( 0.99390697000236f),QTCFL( 0.98310548743122f),QTCFL( 0.96697647104485f), + QTCFL( 0.94560732538052f),QTCFL( 0.91911385169006f),QTCFL( 0.88763962040285f),QTCFL( 0.85135519310527f), + QTCFL( 0.81045719825259f),QTCFL( 0.76516726562246f),QTCFL( 0.71573082528382f),QTCFL( 0.66241577759017f), + QTCFL( 0.60551104140433f),QTCFL( 0.54532498842205f),QTCFL( 0.48218377207912f),QTCFL( 0.41642956009764f), + QTCFL( 0.34841868024943f),QTCFL( 0.27851968938505f),QTCFL( 0.20711137619222f),QTCFL( 0.13458070850713f), + QTCFL( 0.06132073630221f),QTCFL(-0.01227153828572f),QTCFL(-0.08579731234444f),QTCFL(-0.15885814333386f), + QTCFL(-0.23105810828067f),QTCFL(-0.30200594931923f),QTCFL(-0.37131719395184f),QTCFL(-0.43861623853853f), + QTCFL(-0.50353838372572f),QTCFL(-0.56573181078361f),QTCFL(-0.62485948814239f),QTCFL(-0.68060099779545f) +}; + +const FIXP_QTW qmf_phaseshift_sin32[32] = +{ + QTCFL( 0.03680722294136f),QTCFL( 0.11022220729388f),QTCFL( 0.18303988795514f),QTCFL( 0.25486565960451f), + QTCFL( 0.32531029216226f),QTCFL( 0.39399204006105f),QTCFL( 0.46053871095824f),QTCFL( 0.52458968267847f), + QTCFL( 0.58579785745644f),QTCFL( 0.64383154288979f),QTCFL( 0.69837624940897f),QTCFL( 0.74913639452346f), + QTCFL( 0.79583690460888f),QTCFL( 0.83822470555484f),QTCFL( 0.87607009419541f),QTCFL( 0.90916798309052f), + QTCFL( 0.93733901191257f),QTCFL( 0.96043051941557f),QTCFL( 0.97831737071963f),QTCFL( 0.99090263542778f), + QTCFL( 0.99811811290015f),QTCFL( 0.99992470183914f),QTCFL( 0.99631261218278f),QTCFL( 0.98730141815786f), + QTCFL( 0.97293995220556f),QTCFL( 0.95330604035419f),QTCFL( 0.92850608047322f),QTCFL( 0.89867446569395f), + QTCFL( 0.86397285612159f),QTCFL( 0.82458930278503f),QTCFL( 0.78073722857209f),QTCFL( 0.73265427167241f) +}; +const FIXP_QTW qmf_phaseshift_cos64[64] = { + QTC(0x7ff62181), QTC(0x7fa736b3), QTC(0x7f0991c3), QTC(0x7e1d93e9), QTC(0x7ce3ceb1), QTC(0x7b5d039d), QTC(0x798a23b0), QTC(0x776c4eda), + QTC(0x7504d344), QTC(0x72552c84), QTC(0x6f5f02b1), QTC(0x6c24295f), QTC(0x68a69e80), QTC(0x64e88925), QTC(0x60ec382f), QTC(0x5cb420df), + QTC(0x5842dd54), QTC(0x539b2aef), QTC(0x4ebfe8a4), QTC(0x49b41533), QTC(0x447acd50), QTC(0x3f1749b7), QTC(0x398cdd32), QTC(0x33def287), + QTC(0x2e110a62), QTC(0x2826b928), QTC(0x2223a4c5), QTC(0x1c0b826a), QTC(0x15e21444), QTC(0x0fab272b), QTC(0x096a9049), QTC(0x03242abf), + QTC(0xfcdbd541), QTC(0xf6956fb7), QTC(0xf054d8d5), QTC(0xea1debbc), QTC(0xe3f47d96), QTC(0xdddc5b3b), QTC(0xd7d946d8), QTC(0xd1eef59e), + QTC(0xcc210d79), QTC(0xc67322ce), QTC(0xc0e8b649), QTC(0xbb8532b0), QTC(0xb64beacd), QTC(0xb140175c), QTC(0xac64d511), QTC(0xa7bd22ac), + QTC(0xa34bdf21), QTC(0x9f13c7d1), QTC(0x9b1776db), QTC(0x97596180), QTC(0x93dbd6a1), QTC(0x90a0fd4f), QTC(0x8daad37c), QTC(0x8afb2cbc), + QTC(0x8893b126), QTC(0x8675dc50), QTC(0x84a2fc63), QTC(0x831c314f), QTC(0x81e26c17), QTC(0x80f66e3d), QTC(0x8058c94d), QTC(0x8009de7f) +}; + +const FIXP_QTW qmf_phaseshift_sin64[64] = { + QTC(0x03242abf), QTC(0x096a9049), QTC(0x0fab272b), QTC(0x15e21444), QTC(0x1c0b826a), QTC(0x2223a4c5), QTC(0x2826b928), QTC(0x2e110a62), + QTC(0x33def287), QTC(0x398cdd32), QTC(0x3f1749b7), QTC(0x447acd50), QTC(0x49b41533), QTC(0x4ebfe8a4), QTC(0x539b2aef), QTC(0x5842dd54), + QTC(0x5cb420df), QTC(0x60ec382f), QTC(0x64e88925), QTC(0x68a69e80), QTC(0x6c24295f), QTC(0x6f5f02b1), QTC(0x72552c84), QTC(0x7504d344), + QTC(0x776c4eda), QTC(0x798a23b0), QTC(0x7b5d039d), QTC(0x7ce3ceb1), QTC(0x7e1d93e9), QTC(0x7f0991c3), QTC(0x7fa736b3), QTC(0x7ff62181), + QTC(0x7ff62181), QTC(0x7fa736b3), QTC(0x7f0991c3), QTC(0x7e1d93e9), QTC(0x7ce3ceb1), QTC(0x7b5d039d), QTC(0x798a23b0), QTC(0x776c4eda), + QTC(0x7504d344), QTC(0x72552c84), QTC(0x6f5f02b1), QTC(0x6c24295f), QTC(0x68a69e80), QTC(0x64e88925), QTC(0x60ec382f), QTC(0x5cb420df), + QTC(0x5842dd54), QTC(0x539b2aef), QTC(0x4ebfe8a4), QTC(0x49b41533), QTC(0x447acd50), QTC(0x3f1749b7), QTC(0x398cdd32), QTC(0x33def287), + QTC(0x2e110a62), QTC(0x2826b928), QTC(0x2223a4c5), QTC(0x1c0b826a), QTC(0x15e21444), QTC(0x0fab272b), QTC(0x096a9049), QTC(0x03242abf) +}; + +//@} + +#endif /* #ifdef LOW_POWER_SBR_ONLY */ + + + +/*! + \name QMF + \brief QMF-Table + 64 channels, N = 640, optimized by PE 010516 + + The coeffs are rearranged compared with the reference in the following + way, exploiting symmetry : + sbr_qmf_64[5] = p_64_640_qmf[0]; + sbr_qmf_64[6] = p_64_640_qmf[128]; + sbr_qmf_64[7] = p_64_640_qmf[256]; + sbr_qmf_64[8] = p_64_640_qmf[384]; + sbr_qmf_64[9] = p_64_640_qmf[512]; + + sbr_qmf_64[10] = p_64_640_qmf[1]; + sbr_qmf_64[11] = p_64_640_qmf[129]; + sbr_qmf_64[12] = p_64_640_qmf[257]; + sbr_qmf_64[13] = p_64_640_qmf[385]; + sbr_qmf_64[14] = p_64_640_qmf[513]; + . + . + . + sbr_qmf_64_640_qmf[315] = p_64_640_qmf[62]; + sbr_qmf_64_640_qmf[316] = p_64_640_qmf[190]; + sbr_qmf_64_640_qmf[317] = p_64_640_qmf[318]; + sbr_qmf_64_640_qmf[318] = p_64_640_qmf[446]; + sbr_qmf_64_640_qmf[319] = p_64_640_qmf[574]; + + sbr_qmf_64_640_qmf[320] = p_64_640_qmf[63]; + sbr_qmf_64_640_qmf[321] = p_64_640_qmf[191]; + sbr_qmf_64_640_qmf[322] = p_64_640_qmf[319]; + sbr_qmf_64_640_qmf[323] = p_64_640_qmf[447]; + sbr_qmf_64_640_qmf[324] = p_64_640_qmf[575]; + + sbr_qmf_64_640_qmf[319] = p_64_640_qmf[64]; + sbr_qmf_64_640_qmf[318] = p_64_640_qmf[192]; + sbr_qmf_64_640_qmf[317] = p_64_640_qmf[320]; + sbr_qmf_64_640_qmf[316] = p_64_640_qmf[448]; + sbr_qmf_64_640_qmf[315] = p_64_640_qmf[576]; + + sbr_qmf_64_640_qmf[314] = p_64_640_qmf[65]; + sbr_qmf_64_640_qmf[313] = p_64_640_qmf[193]; + sbr_qmf_64_640_qmf[312] = p_64_640_qmf[321]; + sbr_qmf_64_640_qmf[311] = p_64_640_qmf[449]; + sbr_qmf_64_640_qmf[310] = p_64_640_qmf[577]; + . + . + . + sbr_qmf_64[9] = p_64_640_qmf[126] + sbr_qmf_64[8] = p_64_640_qmf[254]; + sbr_qmf_64[7] = p_64_640_qmf[382]; + sbr_qmf_64[6] = p_64_640_qmf[510]; + sbr_qmf_64[5] = p_64_640_qmf[638]; + + sbr_qmf_64[4] = p_64_640_qmf[127] + sbr_qmf_64[3] = p_64_640_qmf[255]; + sbr_qmf_64[2] = p_64_640_qmf[383]; + sbr_qmf_64[1] = p_64_640_qmf[511]; + sbr_qmf_64[0] = p_64_640_qmf[639]; + + Max sum of all FIR filter absolute coefficients is: 0x7FF5B201 + thus, the filter output is not required to be scaled. + + \showinitializer +*/ +//@{ +#if QMF_NO_POLY==5 +LNK_SECTION_CONSTDATA_L1 +RAM_ALIGN +const FIXP_PFT qmf_64[QMF640_PFT_TABLE_SIZE+QMF_NO_POLY] = +{ + QFC(0x00000000), QFC(0x01b2e41d), QFC(0x2e3a7532), QFC(0xd1c58ace), QFC(0xfe4d1be3), + QFC(0xffede50e), QFC(0x01d78bfc), QFC(0x2faa221c), QFC(0xd3337b3e), QFC(0xfe70b8d1), + QFC(0xffed978a), QFC(0x01fd3ba0), QFC(0x311af3a4), QFC(0xd49fd55f), QFC(0xfe933dc0), + QFC(0xffefc9b9), QFC(0x02244a24), QFC(0x328cc6f0), QFC(0xd60a46e6), QFC(0xfeb48d0d), + QFC(0xfff0065d), QFC(0x024bf7a1), QFC(0x33ff670e), QFC(0xd7722f04), QFC(0xfed4bec3), + QFC(0xffeff6ca), QFC(0x0274ba43), QFC(0x3572ec70), QFC(0xd8d7f220), QFC(0xfef3f6ab), + QFC(0xffef7b8b), QFC(0x029e35b4), QFC(0x36e69691), QFC(0xda3b176a), QFC(0xff120d70), + QFC(0xffeedfa4), QFC(0x02c89901), QFC(0x385a49c3), QFC(0xdb9b5b12), QFC(0xff2ef725), + QFC(0xffee1650), QFC(0x02f3e48d), QFC(0x39ce0477), QFC(0xdcf898fb), QFC(0xff4aabc8), + QFC(0xffed651d), QFC(0x03201116), QFC(0x3b415115), QFC(0xde529087), QFC(0xff6542d1), + QFC(0xffecc31b), QFC(0x034d01f1), QFC(0x3cb41219), QFC(0xdfa93ab5), QFC(0xff7ee3f1), + QFC(0xffebe77b), QFC(0x037ad438), QFC(0x3e25b17e), QFC(0xe0fc421e), QFC(0xff975c01), + QFC(0xffeb50b2), QFC(0x03a966bb), QFC(0x3f962fb8), QFC(0xe24b8f67), QFC(0xffaea5d6), + QFC(0xffea9192), QFC(0x03d8afe6), QFC(0x41058bc5), QFC(0xe396a45d), QFC(0xffc4e365), + QFC(0xffe9ca76), QFC(0x04083fec), QFC(0x4272a385), QFC(0xe4de0cb0), QFC(0xffda17f2), + QFC(0xffe940f4), QFC(0x043889c6), QFC(0x43de620a), QFC(0xe620c476), QFC(0xffee183b), + QFC(0xffe88ba8), QFC(0x04694101), QFC(0x4547daea), QFC(0xe75f8bb8), QFC(0x0000e790), + QFC(0xffe83a07), QFC(0x049aa82f), QFC(0x46aea856), QFC(0xe89971b7), QFC(0x00131c75), + QFC(0xffe79e16), QFC(0x04cc2fcf), QFC(0x4812f848), QFC(0xe9cea84a), QFC(0x0023b989), + QFC(0xffe7746e), QFC(0x04fe20be), QFC(0x4973fef1), QFC(0xeafee7f1), QFC(0x0033b927), + QFC(0xffe6d466), QFC(0x05303f88), QFC(0x4ad237a2), QFC(0xec2a3f60), QFC(0x00426f36), + QFC(0xffe6afed), QFC(0x05626209), QFC(0x4c2ca3df), QFC(0xed50a31d), QFC(0x00504f41), + QFC(0xffe65416), QFC(0x05950122), QFC(0x4d83976c), QFC(0xee71b2fe), QFC(0x005d36df), + QFC(0xffe681c6), QFC(0x05c76fed), QFC(0x4ed62be2), QFC(0xef8d4d7b), QFC(0x006928a0), + QFC(0xffe66dd0), QFC(0x05f9c051), QFC(0x5024d70e), QFC(0xf0a3959f), QFC(0x007400b8), + QFC(0xffe66fab), QFC(0x062bf5ec), QFC(0x516eefb8), QFC(0xf1b461ab), QFC(0x007e0393), + QFC(0xffe69423), QFC(0x065dd56a), QFC(0x52b449dd), QFC(0xf2bf6ea4), QFC(0x00872c63), + QFC(0xffe6fed4), QFC(0x068f8b44), QFC(0x53f495a9), QFC(0xf3c4e887), QFC(0x008f87aa), + QFC(0xffe75361), QFC(0x06c0f0c0), QFC(0x552f8ff6), QFC(0xf4c473c6), QFC(0x0096dcc2), + QFC(0xffe80414), QFC(0x06f1825d), QFC(0x56654bdc), QFC(0xf5be0fa9), QFC(0x009da526), + QFC(0xffe85b4a), QFC(0x0721bf22), QFC(0x579505f4), QFC(0xf6b1f3c3), QFC(0x00a3508f), + QFC(0xffe954d0), QFC(0x075112a2), QFC(0x58befacc), QFC(0xf79fa13a), QFC(0x00a85e94), + QFC(0xffea353a), QFC(0x077fedb3), QFC(0x59e2f69e), QFC(0xf887507c), QFC(0x00acbd2f), + QFC(0xffeb3849), QFC(0x07ad8c26), QFC(0x5b001db7), QFC(0xf96916f5), QFC(0x00b06b68), + QFC(0xffec8409), QFC(0x07da2b7f), QFC(0x5c16d0ae), QFC(0xfa44a069), QFC(0x00b36acd), + QFC(0xffedc418), QFC(0x08061671), QFC(0x5d26be9b), QFC(0xfb19b7bd), QFC(0x00b58c8d), + QFC(0xffef2395), QFC(0x08303897), QFC(0x5e2f6366), QFC(0xfbe8f5bd), QFC(0x00b73ab0), + QFC(0xfff0e7ef), QFC(0x08594887), QFC(0x5f30ff5e), QFC(0xfcb1d740), QFC(0x00b85f70), + QFC(0xfff294c3), QFC(0x0880ffdd), QFC(0x602b0c7e), QFC(0xfd7475d8), QFC(0x00b8c6b0), + QFC(0xfff48700), QFC(0x08a75da4), QFC(0x611d58a2), QFC(0xfe310657), QFC(0x00b8fe0d), + QFC(0xfff681d6), QFC(0x08cb4e23), QFC(0x6207f21f), QFC(0xfee723c6), QFC(0x00b8394b), + QFC(0xfff91fc9), QFC(0x08edfeaa), QFC(0x62ea6473), QFC(0xff96db8f), QFC(0x00b74c37), + QFC(0xfffb42b0), QFC(0x090ec1fc), QFC(0x63c45243), QFC(0x0040c497), QFC(0x00b5c867), + QFC(0xfffdfa24), QFC(0x092d7970), QFC(0x64964062), QFC(0x00e42fa2), QFC(0x00b3d15c), + QFC(0x00007134), QFC(0x0949eaac), QFC(0x655f63f1), QFC(0x01816e06), QFC(0x00b1978d), + QFC(0x00039609), QFC(0x0963ed46), QFC(0x661fd6b7), QFC(0x02186a92), QFC(0x00af374c), + QFC(0x0006b1cf), QFC(0x097c1ee8), QFC(0x66d76724), QFC(0x02a99097), QFC(0x00abe79e), + QFC(0x0009aa3f), QFC(0x099140a7), QFC(0x6785c24c), QFC(0x03343534), QFC(0x00a8739d), + QFC(0x000d31b5), QFC(0x09a3e163), QFC(0x682b39a3), QFC(0x03b8f8dc), QFC(0x00a520bb), + QFC(0x0010bc63), QFC(0x09b3d77f), QFC(0x68c7269b), QFC(0x0437fb0a), QFC(0x00a1039c), + QFC(0x001471f8), QFC(0x09c0e59f), QFC(0x6959709c), QFC(0x04b0adcb), QFC(0x009d10bf), + QFC(0x0018703f), QFC(0x09cab9f2), QFC(0x69e29783), QFC(0x05237f9d), QFC(0x0098b855), + QFC(0x001c3549), QFC(0x09d19ca9), QFC(0x6a619c5e), QFC(0x0590a67d), QFC(0x009424c6), + QFC(0x002064f8), QFC(0x09d52709), QFC(0x6ad73e8d), QFC(0x05f7fb90), QFC(0x008f4bfd), + QFC(0x0024dd50), QFC(0x09d5560b), QFC(0x6b42a863), QFC(0x06593912), QFC(0x008a7dd7), + QFC(0x00293718), QFC(0x09d1fa23), QFC(0x6ba4629e), QFC(0x06b559c3), QFC(0x0085c217), + QFC(0x002d8e42), QFC(0x09caeb0f), QFC(0x6bfbdd97), QFC(0x070bbf58), QFC(0x00807994), + QFC(0x00329ab6), QFC(0x09c018ce), QFC(0x6c492216), QFC(0x075ca90c), QFC(0x007b3875), + QFC(0x003745f9), QFC(0x09b18a1d), QFC(0x6c8c4c79), QFC(0x07a8127d), QFC(0x0075fded), + QFC(0x003c1fa4), QFC(0x099ec3dc), QFC(0x6cc59baa), QFC(0x07ee507c), QFC(0x0070c8a5), + QFC(0x004103f5), QFC(0x09881dc5), QFC(0x6cf4073d), QFC(0x082f552e), QFC(0x006b47fa), + QFC(0x00465348), QFC(0x096d0e21), QFC(0x6d18520d), QFC(0x086b1eec), QFC(0x0065fde5), + QFC(0x004b6c46), QFC(0x094d7ec2), QFC(0x6d32730e), QFC(0x08a24899), QFC(0x006090c4), + QFC(0x0050b177), QFC(0x09299ead), QFC(0x6d41d963), QFC(0x08d3e41b), QFC(0x005b5371), + QFC(0x0055dba1), QFC(0x09015651), QFC(0x6d474e1d), QFC(0x09015651), QFC(0x0055dba1), + QFC(0xfe4d1be3), QFC(0xd1c58ace), QFC(0x2e3a7532), QFC(0x01b2e41d), QFC(0x00000000), +}; + +#else /* QMF_NO_POLY == 5 */ +#endif /* QMF_NO_POLY==5 */ + + + + + +/* + * Low Delay QMF aka CLDFB + */ + +#if defined(QMF_COEFF_16BIT) +#define QTCFLLD(x) FL2FXCONST_SGL(x/(float)(1< 59 dB SNR 1 --> 65 dB SNR +#define MINSFTAB 7 +#define MAXSFTAB 25 + +#if IMPROVE_ATAN2_ACCURACY +static const FIXP_DBL f_atan_expand_range[MAXSFTAB-(MINSFTAB-1)] = +{ + /***************************************************************************** + * + * Table holds fixp_atan() output values which are outside of input range + * of fixp_atan() to improve SNR of fixp_atan2(). + * + * This Table might also be used in fixp_atan() [todo] so there a wider input + * range can be covered, too. + * + * Matlab (generate table): + * for scl = 7:25 % MINSFTAB .. MAXSFTAB + * at=atan(0.5 *(2^scl)); % 0.5 because get in 'middle' area of current scale level 'scl' + * at/2 % div at by ATO_SCALE + * end + * + * Table divided by 2=ATO_SCALE <-- SF=ATO_SF + *****************************************************************************/ + FL2FXCONST_DBL(7.775862990872099e-001), FL2FXCONST_DBL(7.814919928673978e-001), FL2FXCONST_DBL(7.834450483314648e-001), + FL2FXCONST_DBL(7.844216021392089e-001), FL2FXCONST_DBL(7.849098823026687e-001), FL2FXCONST_DBL(7.851540227918509e-001), + FL2FXCONST_DBL(7.852760930873737e-001), FL2FXCONST_DBL(7.853371282415015e-001), FL2FXCONST_DBL(7.853676458193612e-001), + FL2FXCONST_DBL(7.853829046083906e-001), FL2FXCONST_DBL(7.853905340029177e-001), FL2FXCONST_DBL(7.853943487001828e-001), + FL2FXCONST_DBL(7.853962560488155e-001), FL2FXCONST_DBL(7.853972097231319e-001), FL2FXCONST_DBL(7.853976865602901e-001), + FL2FXCONST_DBL(7.853979249788692e-001), FL2FXCONST_DBL(7.853980441881587e-001), FL2FXCONST_DBL(7.853981037928035e-001), + FL2FXCONST_DBL(7.853981335951259e-001) + // pi/4 = 0.785398163397448 = pi/2/ATO_SCALE +}; +#endif + +FIXP_DBL fixp_atan2(FIXP_DBL y, FIXP_DBL x) +{ + FIXP_DBL q; + FIXP_DBL at; // atan out + FIXP_DBL at2; // atan2 out + FIXP_DBL ret = FL2FXCONST_DBL(-1.0f); + INT sf,sfo,stf; + + // --- division + + if (y > FL2FXCONST_DBL(0.0f)) + { + if (x > FL2FXCONST_DBL(0.0f)) { + q = fDivNormHighPrec( y, x, &sf); // both pos. + } + else if (x < FL2FXCONST_DBL(0.0f)) { + q = -fDivNormHighPrec( y,-x, &sf); // x neg. + } + else {//(x ==FL2FXCONST_DBL(0.0f)) + q = FL2FXCONST_DBL(+1.0f); // y/x = pos/zero = +Inf + sf = 0; + } + } + else if (y < FL2FXCONST_DBL(0.0f)) + { + if (x > FL2FXCONST_DBL(0.0f)) { + q = -fDivNormHighPrec(-y, x, &sf); // y neg. + } + else if (x < FL2FXCONST_DBL(0.0f)) { + q = fDivNormHighPrec(-y,-x, &sf); // both neg. + } + else {//(x ==FL2FXCONST_DBL(0.0f)) + q = FL2FXCONST_DBL(-1.0f); // y/x = neg/zero = -Inf + sf = 0; + } + } + else { // (y ==FL2FXCONST_DBL(0.0f)) + q = FL2FXCONST_DBL(0.0f); + sf = 0; + } + sfo = sf; + //write2file(fpF__h,(float)y/(float)x); + //write2file(fpC__h,(float) q * (float)FDKpow(2,sfo)); // SNR 86 dB But range not limited to [-64..64] which is the input range of fixp_atan() + + // --- atan() + + if ( sfo > ATI_SF ) { + // --- could not calc fixp_atan() here bec of input data out of range + // ==> therefore give back boundary values + + #if IMPROVE_ATAN2_ACCURACY + if (sfo > MAXSFTAB) sfo = MAXSFTAB; + #endif + + if ( q > FL2FXCONST_DBL(0.0f) ) { + #if IMPROVE_ATAN2_ACCURACY + at = +f_atan_expand_range[sfo-ATI_SF-1]; + #else + at = FL2FXCONST_DBL( +M_PI/2 / ATO_SCALE); + #endif + } + else if ( q < FL2FXCONST_DBL(0.0f) ) { + #if IMPROVE_ATAN2_ACCURACY + at = -f_atan_expand_range[sfo-ATI_SF-1]; + #else + at = FL2FXCONST_DBL( -M_PI/2 / ATO_SCALE); + #endif + } + else { // q== FL2FXCONST_DBL(0.0f) + at = FL2FXCONST_DBL( 0.0f ); + } + }else{ + // --- calc of fixp_atan() is possible; input data within range + // ==> set q on fixed scale level as desired from fixp_atan() + stf = sfo - ATI_SF; + if (stf > 0) q = q << (INT)fMin( stf,DFRACT_BITS-1); + else q = q >> (INT)fMin(-stf,DFRACT_BITS-1); + //write2file(fpF__e,(float)y/(float)x); + //write2file(fpC__e,(float)q * (float)FDKpow(2,ATI_SF)); // 88.9 dB + at = fixp_atan(q); // ATO_SF + } + //write2file(fpF__g,(float)FDKatan( (float)y/(float)x )); + //write2file(fpC__g,(float) at * (float)FDKpow(2,ATO_SF) ); // todo dB + + // --- atan2() + + at2 = at >> (AT2O_SF - ATO_SF); // now AT2O_SF for atan2 + if ( x > FL2FXCONST_DBL(0.0f) ) { + ret = at2; + } + else if ( x < FL2FXCONST_DBL(0.0f) ) { + if ( y >= FL2FXCONST_DBL(0.0f) ) { + ret = at2 + FL2FXCONST_DBL( M_PI / AT2O_SCALE); + } else { + ret = at2 - FL2FXCONST_DBL( M_PI / AT2O_SCALE); + } + } + else { + // x == 0 + if ( y > FL2FXCONST_DBL(0.0f) ) { + ret = FL2FXCONST_DBL( +M_PI/2 / AT2O_SCALE); + } + else if ( y < FL2FXCONST_DBL(0.0f) ) { + ret = FL2FXCONST_DBL( -M_PI/2 / AT2O_SCALE); + } + else if ( y == FL2FXCONST_DBL(0.0f) ) { + ret = FL2FXCONST_DBL(0.0f); + } + } + //write2file(fpC__f,(float)ret * (float)FDKpow(2,AT2O_SF)); // 65 dB + //write2file(fpF__f,(float)FDKatan2(y,x)); + return ret; +} + + +FIXP_DBL fixp_atan(FIXP_DBL x) +{ + INT sign; + FIXP_DBL result, temp; + + // SNR of fixp_atan() = 56 dB + FIXP_DBL ONEBY3P56 = (FIXP_DBL)0x26800000; // 1.0/3.56 in q31 + FIXP_DBL P281 = (FIXP_DBL)0x00013000; // 0.281 in q18 + FIXP_DBL ONEP571 = (FIXP_DBL)0x6487ef00; // 1.571 in q30 + + if (x < FIXP_DBL(0)) { + sign = 1; + x = - x ; + } else { + sign = 0; + } + + /* calc of arctan */ + if(x < ( Q(Q_ATANINP)-FL2FXCONST_DBL(0.00395)) ) + { + INT res_e; + + temp = fPow2(x); // q25 * q25 - (DFRACT_BITS-1) = q19 + temp = fMult(temp, ONEBY3P56); // q19 * q31 - (DFRACT_BITS-1) = q19 + temp = temp + Q(19); // q19 + q19 = q19 + result = fDivNorm(x, temp, &res_e); + result = scaleValue(result, (Q_ATANOUT-Q_ATANINP+19-DFRACT_BITS+1) + res_e ); + } + else if( x < FL2FXCONST_DBL(1.28/64.0) ) + { + FIXP_DBL delta_fix; + FIXP_DBL PI_BY_4 = FL2FXCONST_DBL(3.1415926/4.0) >> 1; /* pi/4 in q30 */ + + delta_fix = (x - FL2FXCONST_DBL(1.0/64.0)) << 5; /* q30 */ + result = PI_BY_4 + (delta_fix >> 1) - (fPow2Div2(delta_fix)); + } + else + { + INT res_e; + + temp = fPow2Div2(x); // q25 * q25 - (DFRACT_BITS-1) - 1 = q18 + temp = temp + P281; // q18 + q18 = q18 + result = fDivNorm(x, temp, &res_e); + result = scaleValue(result, (Q_ATANOUT-Q_ATANINP+18-DFRACT_BITS+1) + res_e ); + result = ONEP571 - result; // q30 + q30 = q30 + } + if (sign) { + result = -result; + } + + return(result); +} + + +#ifndef CORDIC_SINCOS + +#include "FDK_tools_rom.h" + +FIXP_DBL fixp_cos(FIXP_DBL x, int scale) +{ + FIXP_DBL residual, error, sine, cosine; + + residual = fixp_sin_cos_residual_inline(x, scale, &sine, &cosine); + error = fMult(sine, residual); + + return cosine - error; +} + +FIXP_DBL fixp_sin(FIXP_DBL x, int scale) +{ + FIXP_DBL residual, error, sine, cosine; + + residual = fixp_sin_cos_residual_inline(x, scale, &sine, &cosine); + error = fMult(cosine, residual); + + return sine + error; +} + +void fixp_cos_sin (FIXP_DBL x, int scale, FIXP_DBL *cos, FIXP_DBL *sin) +{ + FIXP_DBL residual, error0, error1, sine, cosine; + + residual = fixp_sin_cos_residual_inline(x, scale, &sine, &cosine); + error0 = fMult(sine, residual); + error1 = fMult(cosine, residual); + *cos = cosine - error0; + *sin = sine + error1; +} + +#else /* #ifndef CORDIC_SINCOS */ + +/* + // Matlab + function v = cordic(beta,n) + % This function computes v = [cos(beta), sin(beta)] (beta in radians) + % using n iterations. Increasing n will increase the precision. + + if beta < -pi/2 | beta > pi/2 + if beta < 0 + v = cordic(beta + pi, n); + else + v = cordic(beta - pi, n); + end + v = -v; % flip the sign for second or third quadrant + return + end + + % Initialization of tables of constants used by CORDIC + % need a table of arctangents of negative powers of two, in radians: + % angles = atan(2.^-(0:27)); + angles = [ ... + 0.78539816339745 0.46364760900081 0.24497866312686 0.12435499454676 ... + 0.06241880999596 0.03123983343027 0.01562372862048 0.00781234106010 ... + 0.00390623013197 0.00195312251648 0.00097656218956 0.00048828121119 ... + 0.00024414062015 0.00012207031189 0.00006103515617 0.00003051757812 ... + 0.00001525878906 0.00000762939453 0.00000381469727 0.00000190734863 ... + 0.00000095367432 0.00000047683716 0.00000023841858 0.00000011920929 ... + 0.00000005960464 0.00000002980232 0.00000001490116 0.00000000745058 ]; + % and a table of products of reciprocal lengths of vectors [1, 2^-j]: + Kvalues = [ ... + 0.70710678118655 0.63245553203368 0.61357199107790 0.60883391251775 ... + 0.60764825625617 0.60735177014130 0.60727764409353 0.60725911229889 ... + 0.60725447933256 0.60725332108988 0.60725303152913 0.60725295913894 ... + 0.60725294104140 0.60725293651701 0.60725293538591 0.60725293510314 ... + 0.60725293503245 0.60725293501477 0.60725293501035 0.60725293500925 ... + 0.60725293500897 0.60725293500890 0.60725293500889 0.60725293500888 ]; + Kn = Kvalues(min(n, length(Kvalues))); + + % Initialize loop variables: + v = [1;0]; % start with 2-vector cosine and sine of zero + poweroftwo = 1; + angle = angles(1); + + % Iterations + for j = 0:n-1; + if beta < 0 + sigma = -1; + else + sigma = 1; + end + factor = sigma * poweroftwo; + R = [1, -factor; factor, 1]; + v = R * v; % 2-by-2 matrix multiply + beta = beta - sigma * angle; % update the remaining angle + poweroftwo = poweroftwo / 2; + % update the angle from table, or eventually by just dividing by two + if j+2 > length(angles) + angle = angle / 2; + else + angle = angles(j+2); + end + end + + % Adjust length of output vector to be [cos(beta), sin(beta)]: + v = v * Kn; + return + + // C++ + #define C1 + #define C2 + #define TYPE double + + TYPE fixp_cordic(TYPE in, + int n, + int type) + { + int i; + TYPE c,s,a; + TYPE x,y,v; + TYPE b; + + c = 0.5; + s = 0.0; + b = 1.0; + + for (i=0; i M_PI/2) ) { + if (in < 0) + in = in + M_PI; + else + in = in - M_PI; + + if (sign == 0) + sign = 1; + else + sign = 0; + } + + v = fixp_cordic(in,n,0); + + if (sign) + v = -v; + + return (v); + } + + TYPE fixp_sin(TYPE in, + int n, + int scale) + { + TYPE v; + INT sign = 0; + + while ( (in < -M_PI/2) || (in > M_PI/2) ) { + if (in < 0) + in = in + M_PI; + else + in = in - M_PI; + + if (sign == 0) + sign = 1; + else + sign = 0; + } + + v = fixp_cordic(in,n,1); + + if (sign) + v = -v; + + return (v); + } +*/ + + +#define SF_C1 1 +#define C1(x) FL2FXCONST_DBL(x/(1<> 1; + s = FL2FXCONST_DBL(0.0f); + + for (i=0; i> i; + y = c >> i; + + if (in < FL2FXCONST_DBL(0.0)) { + c = c + x; + s = s - y; + in = in + a; + } + else { + c = c - x; + s = s + y; + in = in - a; + } + } + + /* 1 headroom bit */ + if (type == 0) + return (c); + else + return (s); +} + +/* + in: argument + scale: scalefactor of argument has to be in the range of 0, ... ,DFRACT_BITS-1 + type: calculate cosine 0 + calculate sine 1 +*/ +static FIXP_DBL fixp_sincos(FIXP_DBL in, + INT scale, + INT type) +{ + FIXP_DBL v; + INT sign = 0; + FIXP_DBL pi,pi_2; + + if (scale < 2) { + in = in >> (2-scale); + scale = 2; + } + + pi = M_PI_4 >> (scale-2); + pi_2 = M_PI_4 >> (scale-1); + + /* move signal into the range of -pi/2 to +pi/2 */ + while ( (in < (-pi_2)) || (in > (pi_2)) ) { + if (in < FL2FXCONST_DBL(0.0)) + in = in + pi; + else + in = in - pi; + + sign = ~sign; + } + + /* scale signal with 2/pi => unscaled signal is in the range of [-1.0,...,+1.0[ */ + in = fMult(in,FL2FXCONST_DBL(2/M_PI)) << scale; + + v = fixp_cordic(in,type); + + if (sign) + v = -v; + + /* compensate 1 headroom bit */ + if ( v <= FL2FXCONST_DBL(-0.5f) ) + v = (FIXP_DBL) (MINVAL_DBL+1); + else + v = SATURATE_LEFT_SHIFT(v,1,DFRACT_BITS); + + return (v); +} + +/* + in: argument + scale: scalefactor of argument has to be in the range of 0, ... ,DFRACT_BITS-1 +*/ +FIXP_DBL fixp_cos(FIXP_DBL in, + INT scale) + +{ + FDK_ASSERT ((scale >= 0) && (scale < DFRACT_BITS)); + + if (in == FL2FXCONST_DBL(0.0f)) + return /*FL2FXCONST_DBL(1.0)*/ (FIXP_DBL)MAXVAL_DBL; + + return (fixp_sincos(in,scale,0)); +} + +/* + in: argument + scale: scalefactor of argument has to be in the range of 0, ... ,DFRACT_BITS-1 +*/ +FIXP_DBL fixp_sin(FIXP_DBL in, + INT scale) + +{ + FDK_ASSERT ((scale >= 0) && (scale < DFRACT_BITS)); + + if (in == FL2FXCONST_DBL(0.0f)) + return FL2FXCONST_DBL(0.0f); + + return (fixp_sincos(in,scale,1)); +} + +#endif /* #ifndef CORDIC_SINCOS */ + + + + diff --git a/libFDK/src/arm/autocorr2nd.cpp b/libFDK/src/arm/autocorr2nd.cpp new file mode 100644 index 0000000..85926af --- /dev/null +++ b/libFDK/src/arm/autocorr2nd.cpp @@ -0,0 +1,33 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +/*! + * + * \brief Calculate second order autocorrelation + * + */ + + diff --git a/libFDK/src/arm/dct_arm.cpp b/libFDK/src/arm/dct_arm.cpp new file mode 100644 index 0000000..dd0ca09 --- /dev/null +++ b/libFDK/src/arm/dct_arm.cpp @@ -0,0 +1,395 @@ +/**************************************************************************** + + (C) copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + + $Id$ + +***************************************************************************/ + + + +#ifdef FUNCTION_dct_IV_func1 + +/* + Note: This assembler routine is here, because the ARM926 compiler does + not encode the inline assembler with optimal speed. + With this version, we save 2 cycles per loop iteration. +*/ + +__asm void dct_IV_func1( + int i, + const FIXP_SPK *twiddle, + FIXP_DBL *RESTRICT pDat_0, + FIXP_DBL *RESTRICT pDat_1) +{ + /* Register map: + r0 i + r1 twiddle + r2 pDat_0 + r3 pDat_1 + r4 accu1 + r5 accu2 + r6 accu3 + r7 accu4 + r8 val_tw + r9 accuX + */ + PUSH {r4-r9} + + /* 44 cycles for 2 iterations = 22 cycles/iteration */ +dct_IV_loop1_start +/* First iteration */ + LDR r8, [r1], #4 // val_tw = *twiddle++; + LDR r5, [r2, #0] // accu2 = pDat_0[0] + LDR r4, [r3, #0] // accu1 = pDat_1[0] + + SMULWT r9, r5, r8 // accuX = accu2*val_tw.l + SMULWB r5, r5, r8 // accu2 = accu2*val_tw.h + RSB r9, r9, #0 // accuX =-accu2*val_tw.l + SMLAWT r5, r4, r8, r5 // accu2 = accu2*val_tw.h + accu1*val_tw.l + SMLAWB r4, r4, r8, r9 // accu1 = accu1*val_tw.h - accu2*val_tw.l + + LDR r8, [r1], #4 // val_tw = *twiddle++; + LDR r7, [r3, #-4] // accu4 = pDat_1[-1] + LDR r6, [r2, #4] // accu3 = pDat_0[1] + + SMULWB r9, r7, r8 // accuX = accu4*val_tw.h + SMULWT r7, r7, r8 // accu4 = accu4*val_tw.l + RSB r9, r9, #0 // accuX =-accu4*val_tw.h + SMLAWB r7, r6, r8, r7 // accu4 = accu4*val_tw.l+accu3*val_tw.h + SMLAWT r6, r6, r8, r9 // accu3 = accu3*val_tw.l-accu4*val_tw.h + + STR r5, [r2], #4 // *pDat_0++ = accu2 + STR r4, [r2], #4 // *pDat_0++ = accu1 + STR r6, [r3], #-4 // *pDat_1-- = accu3 + STR r7, [r3], #-4 // *pDat_1-- = accu4 + +/* Second iteration */ + LDR r8, [r1], #4 // val_tw = *twiddle++; + LDR r5, [r2, #0] // accu2 = pDat_0[0] + LDR r4, [r3, #0] // accu1 = pDat_1[0] + + SMULWT r9, r5, r8 // accuX = accu2*val_tw.l + SMULWB r5, r5, r8 // accu2 = accu2*val_tw.h + RSB r9, r9, #0 // accuX =-accu2*val_tw.l + SMLAWT r5, r4, r8, r5 // accu2 = accu2*val_tw.h + accu1*val_tw.l + SMLAWB r4, r4, r8, r9 // accu1 = accu1*val_tw.h - accu2*val_tw.l + + LDR r8, [r1], #4 // val_tw = *twiddle++; + LDR r7, [r3, #-4] // accu4 = pDat_1[-1] + LDR r6, [r2, #4] // accu3 = pDat_0[1] + + SMULWB r9, r7, r8 // accuX = accu4*val_tw.h + SMULWT r7, r7, r8 // accu4 = accu4*val_tw.l + RSB r9, r9, #0 // accuX =-accu4*val_tw.h + SMLAWB r7, r6, r8, r7 // accu4 = accu4*val_tw.l+accu3*val_tw.h + SMLAWT r6, r6, r8, r9 // accu3 = accu3*val_tw.l-accu4*val_tw.h + + STR r5, [r2], #4 // *pDat_0++ = accu2 + STR r4, [r2], #4 // *pDat_0++ = accu1 + STR r6, [r3], #-4 // *pDat_1-- = accu3 + STR r7, [r3], #-4 // *pDat_1-- = accu4 + + SUBS r0, r0, #1 + BNE dct_IV_loop1_start + + POP {r4-r9} + + BX lr +} + +#endif /* FUNCTION_dct_IV_func1 */ + + +#ifdef FUNCTION_dct_IV_func2 + +FDK_INLINE +/* __attribute__((noinline)) */ +static void dct_IV_func2( + int i, + const FIXP_SPK *twiddle, + FIXP_DBL *pDat_0, + FIXP_DBL *pDat_1, + int inc) +{ + FIXP_DBL accu1, accu2, accu3, accu4, accuX; + LONG val_tw; + + accu1 = pDat_1[-2]; + accu2 = pDat_1[-1]; + + *--pDat_1 = -(pDat_0[1]>>1); + *pDat_0++ = (pDat_0[0]>>1); + + twiddle += inc; + +__asm + { + LDR val_tw, [twiddle], inc, LSL #2 // val_tw = *twiddle; twiddle += inc + B dct_IV_loop2_2nd_part + + /* 42 cycles for 2 iterations = 21 cycles/iteration */ +dct_IV_loop2: + SMULWT accuX, accu2, val_tw + SMULWB accu2, accu2, val_tw + RSB accuX, accuX, #0 + SMLAWB accuX, accu1, val_tw, accuX + SMLAWT accu2, accu1, val_tw, accu2 + STR accuX, [pDat_0], #4 + STR accu2, [pDat_1, #-4] ! + + LDR accu4, [pDat_0, #4] + LDR accu3, [pDat_0] + SMULWB accuX, accu4, val_tw + SMULWT accu4, accu4, val_tw + RSB accuX, accuX, #0 + SMLAWT accuX, accu3, val_tw, accuX + SMLAWB accu4, accu3, val_tw, accu4 + + LDR accu1, [pDat_1, #-8] + LDR accu2, [pDat_1, #-4] + + LDR val_tw, [twiddle], inc, LSL #2 // val_tw = *twiddle; twiddle += inc + + STR accuX, [pDat_1, #-4] ! + STR accu4, [pDat_0], #4 + +dct_IV_loop2_2nd_part: + SMULWT accuX, accu2, val_tw + SMULWB accu2, accu2, val_tw + RSB accuX, accuX, #0 + SMLAWB accuX, accu1, val_tw, accuX + SMLAWT accu2, accu1, val_tw, accu2 + STR accuX, [pDat_0], #4 + STR accu2, [pDat_1, #-4] ! + + LDR accu4, [pDat_0, #4] + LDR accu3, [pDat_0] + SMULWB accuX, accu4, val_tw + SMULWT accu4, accu4, val_tw + RSB accuX, accuX, #0 + SMLAWT accuX, accu3, val_tw, accuX + SMLAWB accu4, accu3, val_tw, accu4 + + LDR accu1, [pDat_1, #-8] + LDR accu2, [pDat_1, #-4] + + STR accuX, [pDat_1, #-4] ! + STR accu4, [pDat_0], #4 + + LDR val_tw, [twiddle], inc, LSL #2 // val_tw = *twiddle; twiddle += inc + + SUBS i, i, #1 + BNE dct_IV_loop2 + } + + /* Last Sin and Cos value pair are the same */ + accu1 = fMultDiv2(accu1, WTC(0x5a82799a)); + accu2 = fMultDiv2(accu2, WTC(0x5a82799a)); + + *--pDat_1 = accu1 + accu2; + *pDat_0++ = accu1 - accu2; +} +#endif /* FUNCTION_dct_IV_func2 */ + + +#ifdef FUNCTION_dst_IV_func1 + +__asm void dst_IV_func1( + int i, + const FIXP_SPK *twiddle, + FIXP_DBL *pDat_0, + FIXP_DBL *pDat_1) +{ + /* Register map: + r0 i + r1 twiddle + r2 pDat_0 + r3 pDat_1 + r4 accu1 + r5 accu2 + r6 accu3 + r7 accu4 + r8 val_tw + r9 accuX + */ + PUSH {r4-r9} + +dst_IV_loop1 + LDR r8, [r1], #4 // val_tw = *twiddle++ + LDR r5, [r2] // accu2 = pDat_0[0] + LDR r6, [r2, #4] // accu3 = pDat_0[1] + RSB r5, r5, #0 // accu2 = -accu2 + SMULWT r9, r5, r8 // accuX = (-accu2)*val_tw.l + LDR r4, [r3, #-4] // accu1 = pDat_1[-1] + RSB r9, r9, #0 // accuX = -(-accu2)*val_tw.l + SMLAWB r9, r4, r8, r9 // accuX = accu1*val_tw.h-(-accu2)*val_tw.l + SMULWT r4, r4, r8 // accu1 = accu1*val_tw.l + LDR r7, [r3, #-8] // accu4 = pDat_1[-2] + SMLAWB r5, r5, r8, r4 // accu2 = (-accu2)*val_tw.t+accu1*val_tw.l + LDR r8, [r1], #4 // val_tw = *twiddle++ + STR r5, [r2], #4 // *pDat_0++ = accu2 + STR r9, [r2], #4 // *pDat_0++ = accu1 (accuX) + RSB r7, r7, #0 // accu4 = -accu4 + SMULWB r5, r7, r8 // accu2 = (-accu4)*val_tw.h + SMULWB r4, r6, r8 // accu1 = (-accu4)*val_tw.l + RSB r5, r5, #0 // accu2 = -(-accu4)*val_tw.h + SMLAWT r6, r6, r8, r5 // accu3 = (-accu4)*val_tw.l-(-accu3)*val_tw.h + SMLAWT r7, r7, r8, r4 // accu4 = (-accu3)*val_tw.l+(-accu4)*val_tw.h + STR r6, [r3, #-4] ! // *--pDat_1 = accu3 + STR r7, [r3, #-4] ! // *--pDat_1 = accu4 + + LDR r8, [r1], #4 // val_tw = *twiddle++ + LDR r5, [r2] // accu2 = pDat_0[0] + LDR r6, [r2, #4] // accu3 = pDat_0[1] + RSB r5, r5, #0 // accu2 = -accu2 + SMULWT r9, r5, r8 // accuX = (-accu2)*val_tw.l + LDR r4, [r3, #-4] // accu1 = pDat_1[-1] + RSB r9, r9, #0 // accuX = -(-accu2)*val_tw.l + SMLAWB r9, r4, r8, r9 // accuX = accu1*val_tw.h-(-accu2)*val_tw.l + SMULWT r4, r4, r8 // accu1 = accu1*val_tw.l + LDR r7, [r3, #-8] // accu4 = pDat_1[-2] + SMLAWB r5, r5, r8, r4 // accu2 = (-accu2)*val_tw.t+accu1*val_tw.l + LDR r8, [r1], #4 // val_tw = *twiddle++ + STR r5, [r2], #4 // *pDat_0++ = accu2 + STR r9, [r2], #4 // *pDat_0++ = accu1 (accuX) + RSB r7, r7, #0 // accu4 = -accu4 + SMULWB r5, r7, r8 // accu2 = (-accu4)*val_tw.h + SMULWB r4, r6, r8 // accu1 = (-accu4)*val_tw.l + RSB r5, r5, #0 // accu2 = -(-accu4)*val_tw.h + SMLAWT r6, r6, r8, r5 // accu3 = (-accu4)*val_tw.l-(-accu3)*val_tw.h + SMLAWT r7, r7, r8, r4 // accu4 = (-accu3)*val_tw.l+(-accu4)*val_tw.h + STR r6, [r3, #-4] ! // *--pDat_1 = accu3 + STR r7, [r3, #-4] ! // *--pDat_1 = accu4 + + SUBS r0, r0, #4 // i-= 4 + BNE dst_IV_loop1 + + POP {r4-r9} + BX lr +} +#endif /* FUNCTION_dst_IV_func1 */ + +#ifdef FUNCTION_dst_IV_func2 + +FDK_INLINE +/* __attribute__((noinline)) */ +static void dst_IV_func2( + int i, + const FIXP_SPK *twiddle, + FIXP_DBL *RESTRICT pDat_0, + FIXP_DBL *RESTRICT pDat_1, + int inc) +{ + FIXP_DBL accu1,accu2,accu3,accu4; + LONG val_tw; + + accu4 = pDat_0[0]; + accu3 = pDat_0[1]; + accu4 >>= 1; + accu3 >>= 1; + accu4 = -accu4; + + accu1 = pDat_1[-1]; + accu2 = pDat_1[0]; + + *pDat_0++ = accu3; + *pDat_1-- = accu4; + + + __asm + { + B dst_IV_loop2_2nd_part + + /* 50 cycles for 2 iterations = 25 cycles/iteration */ + +dst_IV_loop2: + + LDR val_tw, [twiddle], inc, LSL #2 // val_tw = *twiddle; twiddle += inc + + RSB accu2, accu2, #0 // accu2 = -accu2 + RSB accu1, accu1, #0 // accu1 = -accu1 + SMULWT accu3, accu2, val_tw // accu3 = (-accu2)*val_tw.l + SMULWT accu4, accu1, val_tw // accu4 = (-accu1)*val_tw.l + RSB accu3, accu3, #0 // accu3 = -accu2*val_tw.l + SMLAWB accu1, accu1, val_tw, accu3 // accu1 = -accu1*val_tw.h-(-accu2)*val_tw.l + SMLAWB accu2, accu2, val_tw, accu4 // accu2 = (-accu1)*val_tw.l+(-accu2)*val_tw.h + STR accu1, [pDat_1], #-4 // *pDat_1-- = accu1 + STR accu2, [pDat_0], #4 // *pDat_0++ = accu2 + + LDR accu4, [pDat_0] // accu4 = pDat_0[0] + LDR accu3, [pDat_0, #4] // accu3 = pDat_0[1] + + RSB accu4, accu4, #0 // accu4 = -accu4 + RSB accu3, accu3, #0 // accu3 = -accu3 + + SMULWB accu1, accu3, val_tw // accu1 = (-accu3)*val_tw.h + SMULWT accu2, accu3, val_tw // accu2 = (-accu3)*val_tw.l + RSB accu1, accu1, #0 // accu1 = -(-accu3)*val_tw.h + SMLAWT accu3, accu4, val_tw, accu1 // accu3 = (-accu4)*val_tw.l-(-accu3)*val_tw.h + SMLAWB accu4, accu4, val_tw, accu2 // accu4 = (-accu3)*val_tw.l+(-accu4)*val_tw.h + + LDR accu1, [pDat_1, #-4] // accu1 = pDat_1[-1] + LDR accu2, [pDat_1] // accu2 = pDat_1[0] + + STR accu3, [pDat_0], #4 // *pDat_0++ = accu3 + STR accu4, [pDat_1], #-4 // *pDat_1-- = accu4 + +dst_IV_loop2_2nd_part: + + LDR val_tw, [twiddle], inc, LSL #2 // val_tw = *twiddle; twiddle += inc + + RSB accu2, accu2, #0 // accu2 = -accu2 + RSB accu1, accu1, #0 // accu1 = -accu1 + SMULWT accu3, accu2, val_tw // accu3 = (-accu2)*val_tw.l + SMULWT accu4, accu1, val_tw // accu4 = (-accu1)*val_tw.l + RSB accu3, accu3, #0 // accu3 = -accu2*val_tw.l + SMLAWB accu1, accu1, val_tw, accu3 // accu1 = -accu1*val_tw.h-(-accu2)*val_tw.l + SMLAWB accu2, accu2, val_tw, accu4 // accu2 = (-accu1)*val_tw.l+(-accu2)*val_tw.h + STR accu1, [pDat_1], #-4 // *pDat_1-- = accu1 + STR accu2, [pDat_0], #4 // *pDat_0++ = accu2 + + LDR accu4, [pDat_0] // accu4 = pDat_0[0] + LDR accu3, [pDat_0, #4] // accu3 = pDat_0[1] + + RSB accu4, accu4, #0 // accu4 = -accu4 + RSB accu3, accu3, #0 // accu3 = -accu3 + + SMULWB accu1, accu3, val_tw // accu1 = (-accu3)*val_tw.h + SMULWT accu2, accu3, val_tw // accu2 = (-accu3)*val_tw.l + RSB accu1, accu1, #0 // accu1 = -(-accu3)*val_tw.h + SMLAWT accu3, accu4, val_tw, accu1 // accu3 = (-accu4)*val_tw.l-(-accu3)*val_tw.h + SMLAWB accu4, accu4, val_tw, accu2 // accu4 = (-accu3)*val_tw.l+(-accu4)*val_tw.h + + LDR accu1, [pDat_1, #-4] // accu1 = pDat_1[-1] + LDR accu2, [pDat_1] // accu2 = pDat_1[0] + + STR accu3, [pDat_0], #4 // *pDat_0++ = accu3 + STR accu4, [pDat_1], #-4 // *pDat_1-- = accu4 + + SUBS i, i, #1 + BNE dst_IV_loop2 + } + + /* Last Sin and Cos value pair are the same */ + accu1 = fMultDiv2(-accu1, WTC(0x5a82799a)); + accu2 = fMultDiv2(-accu2, WTC(0x5a82799a)); + + *pDat_0 = accu1 + accu2; + *pDat_1 = accu1 - accu2; +} +#endif /* FUNCTION_dst_IV_func2 */ diff --git a/libFDK/src/arm/fft_rad2_arm.cpp b/libFDK/src/arm/fft_rad2_arm.cpp new file mode 100644 index 0000000..f40961a --- /dev/null +++ b/libFDK/src/arm/fft_rad2_arm.cpp @@ -0,0 +1,259 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: dit_fft ARM assembler replacements. + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +/* NEON optimized FFT currently builds only with RVCT toolchain */ + +#ifndef FUNCTION_dit_fft + +/* If dit_fft was not yet defined by ARM-Cortex ... */ + +#if defined(SINETABLE_16BIT) + +#define FUNCTION_dit_fft + +/***************************************************************************** + + date: 28.07.2005 srl + + Contents/description: dit-tukey-FFT-algorithm + +******************************************************************************/ + +#if defined(FUNCTION_dit_fft) + + +void dit_fft(FIXP_DBL *x, const INT ldn, const FIXP_STP *trigdata, const INT trigDataSize) +{ + const INT n=1<>1; /* Re A + Re B */ + a10 = (x[i + 4] + x[i + 6])>>1; /* Re C + Re D */ + a20 = (x[i + 1] + x[i + 3])>>1; /* Im A + Im B */ + a30 = (x[i + 5] + x[i + 7])>>1; /* Im C + Im D */ + + x[i + 0] = a00 + a10; /* Re A' = Re A + Re B + Re C + Re D */ + x[i + 4] = a00 - a10; /* Re C' = Re A + Re B - Re C - Re D */ + x[i + 1] = a20 + a30; /* Im A' = Im A + Im B + Im C + Im D */ + x[i + 5] = a20 - a30; /* Im C' = Im A + Im B - Im C - Im D */ + + a00 = a00 - x[i + 2]; /* Re A - Re B */ + a10 = a10 - x[i + 6]; /* Re C - Re D */ + a20 = a20 - x[i + 3]; /* Im A - Im B */ + a30 = a30 - x[i + 7]; /* Im C - Im D */ + + x[i + 2] = a00 + a30; /* Re B' = Re A - Re B + Im C - Im D */ + x[i + 6] = a00 - a30; /* Re D' = Re A - Re B - Im C + Im D */ + x[i + 3] = a20 - a10; /* Im B' = Im A - Im B - Re C + Re D */ + x[i + 7] = a20 + a10; /* Im D' = Im A - Im B + Re C - Re D */ + } + + INT mh = 1 << 1; + INT ldm = ldn - 2; + INT trigstep = trigDataSize; + + do + { + const FIXP_STP *pTrigData = trigdata; + INT j; + + mh <<= 1; + trigstep >>= 1; + + FDK_ASSERT(trigstep > 0); + + /* Do first iteration with c=1.0 and s=0.0 separately to avoid loosing to much precision. + Beware: The impact on the overal FFT precision is rather large. */ + { + FIXP_DBL *xt1 = x; + int r = n; + + do { + FIXP_DBL *xt2 = xt1 + (mh<<1); + /* + FIXP_DBL *xt1 = x+ ((r)<<1); + FIXP_DBL *xt2 = xt1 + (mh<<1); + */ + FIXP_DBL vr,vi,ur,ui; + + //cplxMultDiv2(&vi, &vr, x[t2+1], x[t2], (FIXP_SGL)1.0, (FIXP_SGL)0.0); + vi = xt2[1]>>1; + vr = xt2[0]>>1; + + ur = xt1[0]>>1; + ui = xt1[1]>>1; + + xt1[0] = ur+vr; + xt1[1] = ui+vi; + + xt2[0] = ur-vr; + xt2[1] = ui-vi; + + xt1 += mh; + xt2 += mh; + + //cplxMultDiv2(&vr, &vi, x[t2+1], x[t2], (FIXP_SGL)1.0, (FIXP_SGL)0.0); + vr = xt2[1]>>1; + vi = xt2[0]>>1; + + ur = xt1[0]>>1; + ui = xt1[1]>>1; + + xt1[0] = ur+vr; + xt1[1] = ui-vi; + + xt2[0] = ur-vr; + xt2[1] = ui+vi; + + xt1 = xt2 + mh; + } while ((r=r-(mh<<1)) != 0); + } + for(j=4; j>1); + FIXP_SPK cs; + int r = n; + + pTrigData += trigstep; + cs = *pTrigData; + + do + { + FIXP_DBL *xt2 = xt1 + (mh<<1); + FIXP_DBL vr,vi,ur,ui; + + cplxMultDiv2(&vi, &vr, xt2[1], xt2[0], cs); + + ur = xt1[0]>>1; + ui = xt1[1]>>1; + + xt1[0] = ur+vr; + xt1[1] = ui+vi; + + xt2[0] = ur-vr; + xt2[1] = ui-vi; + + xt1 += mh; + xt2 += mh; + + cplxMultDiv2(&vr, &vi, xt2[1], xt2[0], cs); + + ur = xt1[0]>>1; + ui = xt1[1]>>1; + + xt1[0] = ur+vr; + xt1[1] = ui-vi; + + xt2[0] = ur-vr; + xt2[1] = ui+vi; + + /* Same as above but for t1,t2 with j>mh/4 and thus cs swapped */ + xt1 = xt1 - (j); + xt2 = xt1 + (mh<<1); + + cplxMultDiv2(&vi, &vr, xt2[0], xt2[1], cs); + + ur = xt1[0]>>1; + ui = xt1[1]>>1; + + xt1[0] = ur+vr; + xt1[1] = ui-vi; + + xt2[0] = ur-vr; + xt2[1] = ui+vi; + + xt1 += mh; + xt2 += mh; + + cplxMultDiv2(&vr, &vi, xt2[0], xt2[1], cs); + + ur = xt1[0]>>1; + ui = xt1[1]>>1; + + xt1[0] = ur-vr; + xt1[1] = ui-vi; + + xt2[0] = ur+vr; + xt2[1] = ui+vi; + + xt1 = xt2 + (j); + } while ((r=r-(mh<<1)) != 0); + } + { + FIXP_DBL *xt1 = x + (mh>>1); + int r = n; + + do + { + FIXP_DBL *xt2 = xt1 + (mh<<1); + FIXP_DBL vr,vi,ur,ui; + + cplxMultDiv2(&vi, &vr, xt2[1], xt2[0], STC(0x5a82799a), STC(0x5a82799a)); + + ur = xt1[0]>>1; + ui = xt1[1]>>1; + + xt1[0] = ur+vr; + xt1[1] = ui+vi; + + xt2[0] = ur-vr; + xt2[1] = ui-vi; + + xt1 += mh; + xt2 += mh; + + cplxMultDiv2(&vr, &vi, xt2[1], xt2[0], STC(0x5a82799a), STC(0x5a82799a)); + + ur = xt1[0]>>1; + ui = xt1[1]>>1; + + xt1[0] = ur+vr; + xt1[1] = ui-vi; + + xt2[0] = ur-vr; + xt2[1] = ui+vi; + + xt1 = xt2 + mh; + } while ((r=r-(mh<<1)) != 0); + } + } while (--ldm != 0); +} + +#endif /* if defined(FUNCTION_dit_fft) */ + +#endif /* if defined(SINETABLE_16BIT) */ + +#endif /* ifndef FUNCTION_dit_fft */ diff --git a/libFDK/src/arm/qmf_arm.cpp b/libFDK/src/arm/qmf_arm.cpp new file mode 100644 index 0000000..df538a4 --- /dev/null +++ b/libFDK/src/arm/qmf_arm.cpp @@ -0,0 +1,710 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + + History: 04-NOV-2009 A. Tritthart Optimized qmfSynPrototypeFirSlot1 + +****************************************************************************/ +#if (QMF_NO_POLY==5) + +#define FUNCTION_qmfForwardModulationLP_odd + +#ifdef FUNCTION_qmfForwardModulationLP_odd +static void +qmfForwardModulationLP_odd( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */ + const FIXP_QMF *timeIn, /*!< Time Signal */ + FIXP_QMF *rSubband ) /*!< Real Output */ +{ + int i; + int L = anaQmf->no_channels; + int M = L>>1; + int shift = (anaQmf->no_channels>>6) + 1; + int rSubband_e = 0; + + FIXP_QMF *rSubbandPtr0 = &rSubband[M+0]; /* runs with increment */ + FIXP_QMF *rSubbandPtr1 = &rSubband[M-1]; /* runs with decrement */ + FIXP_QMF *timeIn0 = (FIXP_DBL *) &timeIn[0]; /* runs with increment */ + FIXP_QMF *timeIn1 = (FIXP_DBL *) &timeIn[L]; /* runs with increment */ + FIXP_QMF *timeIn2 = (FIXP_DBL *) &timeIn[L-1]; /* runs with decrement */ + FIXP_QMF *timeIn3 = (FIXP_DBL *) &timeIn[2*L-1]; /* runs with decrement */ + + for (i = 0; i < M; i++) + { + *rSubbandPtr0++ = (*timeIn2-- >> 1) - (*timeIn0++ >> shift); + *rSubbandPtr1-- = (*timeIn1++ >> 1) + (*timeIn3-- >> shift); + } + + dct_IV(rSubband,L, &rSubband_e); +} +#endif /* FUNCTION_qmfForwardModulationLP_odd */ + + +/* NEON optimized QMF currently builts only with RVCT toolchain */ + +#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_5TE__) + +#if (SAMPLE_BITS == 16) +#define FUNCTION_qmfAnaPrototypeFirSlot +#endif + +#ifdef FUNCTION_qmfAnaPrototypeFirSlot + +#if defined(__GNUC__) /* cppp replaced: elif */ + +inline INT SMULBB (const SHORT a, const LONG b) +{ + INT result ; + __asm__ ("smulbb %0, %1, %2" + : "=r" (result) + : "r" (a), "r" (b)) ; + return result ; +} +inline INT SMULBT (const SHORT a, const LONG b) +{ + INT result ; + __asm__ ("smulbt %0, %1, %2" + : "=r" (result) + : "r" (a), "r" (b)) ; + return result ; +} + +inline INT SMLABB(const LONG accu, const SHORT a, const LONG b) +{ + INT result ; + __asm__ ("smlabb %0, %1, %2,%3" + : "=r" (result) + : "r" (a), "r" (b), "r" (accu)) ; + return result; +} +inline INT SMLABT(const LONG accu, const SHORT a, const LONG b) +{ + INT result ; + __asm__ ("smlabt %0, %1, %2,%3" + : "=r" (result) + : "r" (a), "r" (b), "r" (accu)) ; + return result; +} +#endif /* compiler selection */ + + +void qmfAnaPrototypeFirSlot( FIXP_QMF *analysisBuffer, + int no_channels, /*!< Number channels of analysis filter */ + const FIXP_PFT *p_filter, + int p_stride, /*!< Stide of analysis filter */ + FIXP_QAS *RESTRICT pFilterStates + ) +{ + LONG *p_flt = (LONG *) p_filter; + LONG flt; + FIXP_QMF *RESTRICT pData_0 = analysisBuffer + 2*no_channels - 1; + FIXP_QMF *RESTRICT pData_1 = analysisBuffer; + + FIXP_QAS *RESTRICT sta_0 = (FIXP_QAS *)pFilterStates; + FIXP_QAS *RESTRICT sta_1 = (FIXP_QAS *)pFilterStates + (2*QMF_NO_POLY*no_channels) - 1; + + FIXP_DBL accu0, accu1; + FIXP_QAS sta0, sta1; + + int staStep1 = no_channels<<1; + int staStep2 = (no_channels<<3) - 1; /* Rewind one less */ + + if (p_stride == 1) + { + /* FIR filter 0 */ + flt = *p_flt++; + sta1 = *sta_1; sta_1 -= staStep1; + accu1 = SMULBB( sta1, flt); + sta1 = *sta_1; sta_1 -= staStep1; + accu1 = SMLABT( accu1, sta1, flt); + + flt = *p_flt++; + sta1 = *sta_1; sta_1 -= staStep1; + accu1 = SMLABB( accu1, sta1, flt); + sta1 = *sta_1; sta_1 -= staStep1; + accu1 = SMLABT( accu1, sta1, flt); + + flt = *p_flt++; + sta1 = *sta_1; sta_1 += staStep2; + accu1 = SMLABB( accu1, sta1, flt); + *pData_1++ = FX_DBL2FX_QMF(accu1<<1); + + /* FIR filters 1..63 127..65 or 1..31 63..33 */ + no_channels >>= 1; + for (; --no_channels; ) + { + sta0 = *sta_0; sta_0 += staStep1; /* 1,3,5, ... 29/61 */ + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMULBT( sta0, flt); + accu1 = SMULBT( sta1, flt); + + flt = *p_flt++; + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMLABB( accu0, sta0, flt); + accu1 = SMLABB( accu1, sta1, flt); + + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMLABT( accu0, sta0, flt); + accu1 = SMLABT( accu1, sta1, flt); + + flt = *p_flt++; + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMLABB( accu0, sta0, flt); + accu1 = SMLABB( accu1, sta1, flt); + + sta0 = *sta_0; sta_0 -= staStep2; + sta1 = *sta_1; sta_1 += staStep2; + accu0 = SMLABT( accu0, sta0, flt); + accu1 = SMLABT( accu1, sta1, flt); + + *pData_0-- = FX_DBL2FX_QMF(accu0<<1); + *pData_1++ = FX_DBL2FX_QMF(accu1<<1); + + /* Same sequence as above, but mix B=bottom with T=Top */ + + flt = *p_flt++; + sta0 = *sta_0; sta_0 += staStep1; /* 2,4,6, ... 30/62 */ + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMULBB( sta0, flt); + accu1 = SMULBB( sta1, flt); + + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMLABT( accu0, sta0, flt); + accu1 = SMLABT( accu1, sta1, flt); + + flt = *p_flt++; + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMLABB( accu0, sta0, flt); + accu1 = SMLABB( accu1, sta1, flt); + + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMLABT( accu0, sta0, flt); + accu1 = SMLABT( accu1, sta1, flt); + + flt = *p_flt++; + sta0 = *sta_0; sta_0 -= staStep2; + sta1 = *sta_1; sta_1 += staStep2; + accu0 = SMLABB( accu0, sta0, flt); + accu1 = SMLABB( accu1, sta1, flt); + + *pData_0-- = FX_DBL2FX_QMF(accu0<<1); + *pData_1++ = FX_DBL2FX_QMF(accu1<<1); + } + + /* FIR filter 31/63 and 33/65 */ + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMULBT( sta0, flt); + accu1 = SMULBT( sta1, flt); + + flt = *p_flt++; + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMLABB( accu0, sta0, flt); + accu1 = SMLABB( accu1, sta1, flt); + + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMLABT( accu0, sta0, flt); + accu1 = SMLABT( accu1, sta1, flt); + + flt = *p_flt++; + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMLABB( accu0, sta0, flt); + accu1 = SMLABB( accu1, sta1, flt); + + sta0 = *sta_0; sta_0 -= staStep2; + sta1 = *sta_1; sta_1 += staStep2; + accu0 = SMLABT( accu0, sta0, flt); + accu1 = SMLABT( accu1, sta1, flt); + + *pData_0-- = FX_DBL2FX_QMF(accu0<<1); + *pData_1++ = FX_DBL2FX_QMF(accu1<<1); + + /* FIR filter 32/64 */ + flt = *p_flt++; + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMULBB( sta0, flt); + accu1 = SMULBB( sta1, flt); + + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMLABT( accu0, sta0, flt); + accu1 = SMLABT( accu1, sta1, flt); + + flt = *p_flt++; + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMLABB( accu0, sta0, flt); + accu1 = SMLABB( accu1, sta1, flt); + + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMLABT( accu0, sta0, flt); + accu1 = SMLABT( accu1, sta1, flt); + + flt = *p_flt; + sta0 = *sta_0; + sta1 = *sta_1; + accu0 = SMLABB( accu0, sta0, flt); + accu1 = SMLABB( accu1, sta1, flt); + + *pData_0-- = FX_DBL2FX_QMF(accu0<<1); + *pData_1++ = FX_DBL2FX_QMF(accu1<<1); + } + else + { + int pfltStep = QMF_NO_POLY * (p_stride-1); + + flt = p_flt[0]; + sta1 = *sta_1; sta_1 -= staStep1; + accu1 = SMULBB( sta1, flt); + sta1 = *sta_1; sta_1 -= staStep1; + accu1 = SMLABT( accu1, sta1, flt); + + flt = p_flt[1]; + sta1 = *sta_1; sta_1 -= staStep1; + accu1 = SMLABB( accu1, sta1, flt); + sta1 = *sta_1; sta_1 -= staStep1; + accu1 = SMLABT( accu1, sta1, flt); + + flt = p_flt[2]; p_flt += pfltStep; + sta1 = *sta_1; sta_1 += staStep2; + accu1 = SMLABB( accu1, sta1, flt); + *pData_1++ = FX_DBL2FX_QMF(accu1<<1); + + /* FIR filters 1..63 127..65 or 1..31 63..33 */ + for (; --no_channels; ) + { + flt = p_flt[0]; + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMULBB( sta0, flt); + accu1 = SMULBB( sta1, flt); + + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMLABT( accu0, sta0, flt); + accu1 = SMLABT( accu1, sta1, flt); + + flt = p_flt[1]; + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMLABB( accu0, sta0, flt); + accu1 = SMLABB( accu1, sta1, flt); + + sta0 = *sta_0; sta_0 += staStep1; + sta1 = *sta_1; sta_1 -= staStep1; + accu0 = SMLABT( accu0, sta0, flt); + accu1 = SMLABT( accu1, sta1, flt); + + flt = p_flt[2]; p_flt += pfltStep; + sta0 = *sta_0; sta_0 -= staStep2; + sta1 = *sta_1; sta_1 += staStep2; + accu0 = SMLABB( accu0, sta0, flt); + accu1 = SMLABB( accu1, sta1, flt); + + *pData_0-- = FX_DBL2FX_QMF(accu0<<1); + *pData_1++ = FX_DBL2FX_QMF(accu1<<1); + } + + /* FIR filter 32/64 */ + flt = p_flt[0]; + sta0 = *sta_0; sta_0 += staStep1; + accu0 = SMULBB( sta0, flt); + sta0 = *sta_0; sta_0 += staStep1; + accu0 = SMLABT( accu0, sta0, flt); + + flt = p_flt[1]; + sta0 = *sta_0; sta_0 += staStep1; + accu0 = SMLABB( accu0, sta0, flt); + sta0 = *sta_0; sta_0 += staStep1; + accu0 = SMLABT( accu0, sta0, flt); + + flt = p_flt[2]; + sta0 = *sta_0; + accu0 = SMLABB( accu0, sta0, flt); + *pData_0-- = FX_DBL2FX_QMF(accu0<<1); + } +} +#endif /* FUNCTION_qmfAnaPrototypeFirSlot */ +#endif /* #if defined(__CC_ARM) && defined(__ARM_ARCH_6__) */ + +#if ( defined(__ARM_ARCH_5TE__) && (SAMPLE_BITS == 16) ) && !defined(QMF_TABLE_FULL) + +#define FUNCTION_qmfSynPrototypeFirSlot + +#if defined(FUNCTION_qmfSynPrototypeFirSlot) + +#if defined(__GNUC__) /* cppp replaced: elif */ + +inline INT SMULWB (const LONG a, const LONG b) +{ + INT result ; + __asm__ ("smulwb %0, %1, %2" + : "=r" (result) + : "r" (a), "r" (b)) ; + + return result ; +} +inline INT SMULWT (const LONG a, const LONG b) +{ + INT result ; + __asm__ ("smulwt %0, %1, %2" + : "=r" (result) + : "r" (a), "r" (b)) ; + + return result ; +} + +inline INT SMLAWB(const LONG accu, const LONG a, const LONG b) +{ + INT result; + asm("smlawb %0, %1, %2, %3 " + : "=r" (result) + : "r" (a), "r" (b), "r" (accu) ); + return result ; +} + +inline INT SMLAWT(const LONG accu, const LONG a, const LONG b) +{ + INT result; + asm("smlawt %0, %1, %2, %3 " + : "=r" (result) + : "r" (a), "r" (b), "r" (accu) ); + return result ; +} + +#endif /* ARM compiler selector */ + + +static void qmfSynPrototypeFirSlot1_filter(FIXP_QMF *RESTRICT realSlot, + FIXP_QMF *RESTRICT imagSlot, + const FIXP_DBL *RESTRICT p_flt, + FIXP_QSS *RESTRICT sta, + FIXP_DBL *pMyTimeOut, + int no_channels) +{ + /* This code was the base for the above listed assembler sequence */ + /* It can be used for debugging purpose or further optimizations */ + const FIXP_DBL *RESTRICT p_fltm = p_flt + 155; + + do + { + FIXP_DBL result; + FIXP_DBL A, B, real, imag, sta0; + + real = *--realSlot; + imag = *--imagSlot; + B = p_flt[4]; /* Bottom=[8] Top=[9] */ + A = p_fltm[3]; /* Bottom=[316] Top=[317] */ + sta0 = sta[0]; /* save state[0] */ + *sta++ = SMLAWT( sta[1], imag, B ); /* index=9...........319 */ + *sta++ = SMLAWB( sta[1], real, A ); /* index=316...........6 */ + *sta++ = SMLAWB( sta[1], imag, B ); /* index=8,18, ...318 */ + B = p_flt[3]; /* Bottom=[6] Top=[7] */ + *sta++ = SMLAWT( sta[1], real, A ); /* index=317...........7 */ + A = p_fltm[4]; /* Bottom=[318] Top=[319] */ + *sta++ = SMLAWT( sta[1], imag, B ); /* index=7...........317 */ + *sta++ = SMLAWB( sta[1], real, A ); /* index=318...........8 */ + *sta++ = SMLAWB( sta[1], imag, B ); /* index=6...........316 */ + B = p_flt[2]; /* Bottom=[X] Top=[5] */ + *sta++ = SMLAWT( sta[1], real, A ); /* index=9...........319 */ + A = p_fltm[2]; /* Bottom=[X] Top=[315] */ + *sta++ = SMULWT( imag, B ); /* index=5,15, ... 315 */ + result = SMLAWT( sta0, real, A ); /* index=315...........5 */ + + *pMyTimeOut++ = result; + + real = *--realSlot; + imag = *--imagSlot; + A = p_fltm[0]; /* Bottom=[310] Top=[311] */ + B = p_flt[7]; /* Bottom=[14] Top=[15] */ + result = SMLAWB( sta[0], real, A ); /* index=310...........0 */ + *sta++ = SMLAWB( sta[1], imag, B ); /* index=14..........324 */ + *pMyTimeOut++ = result; + B = p_flt[6]; /* Bottom=[12] Top=[13] */ + *sta++ = SMLAWT( sta[1], real, A ); /* index=311...........1 */ + A = p_fltm[1]; /* Bottom=[312] Top=[313] */ + *sta++ = SMLAWT( sta[1], imag, B ); /* index=13..........323 */ + *sta++ = SMLAWB( sta[1], real, A ); /* index=312...........2 */ + *sta++ = SMLAWB( sta[1], imag, B ); /* index=12..........322 */ + *sta++ = SMLAWT( sta[1], real, A ); /* index=313...........3 */ + A = p_fltm[2]; /* Bottom=[314] Top=[315] */ + B = p_flt[5]; /* Bottom=[10] Top=[11] */ + *sta++ = SMLAWT( sta[1], imag, B ); /* index=11..........321 */ + *sta++ = SMLAWB( sta[1], real, A ); /* index=314...........4 */ + *sta++ = SMULWB( imag, B ); /* index=10..........320 */ + + + p_flt += 5; + p_fltm -= 5; + } + while ((--no_channels) != 0); + +} + + + +INT qmfSynPrototypeFirSlot2( + HANDLE_QMF_FILTER_BANK qmf, + FIXP_QMF *RESTRICT realSlot, /*!< Input: Pointer to real Slot */ + FIXP_QMF *RESTRICT imagSlot, /*!< Input: Pointer to imag Slot */ + INT_PCM *RESTRICT timeOut, /*!< Time domain data */ + INT stride /*!< Time output buffer stride factor*/ + ) +{ + FIXP_QSS *RESTRICT sta = (FIXP_QSS*)qmf->FilterStates; + int no_channels = qmf->no_channels; + int scale = ((DFRACT_BITS-SAMPLE_BITS)-1-qmf->outScalefactor); + + /* We map an arry of 16-bit values upon an array of 2*16-bit values to read 2 values in one shot */ + const FIXP_DBL *RESTRICT p_flt = (FIXP_DBL *) qmf->p_filter; /* low=[0], high=[1] */ + const FIXP_DBL *RESTRICT p_fltm = (FIXP_DBL *) qmf->p_filter + 155; /* low=[310], high=[311] */ + + FDK_ASSERT(SAMPLE_BITS-1-qmf->outScalefactor >= 0); // (DFRACT_BITS-SAMPLE_BITS)-1-qmf->outScalefactor >= 0); + FDK_ASSERT(qmf->p_stride==2 && qmf->no_channels == 32); + + FDK_ASSERT((no_channels&3) == 0); /* should be a multiple of 4 */ + + realSlot += no_channels-1; // ~~"~~ + imagSlot += no_channels-1; // no_channels-1 .. 0 + + FIXP_DBL MyTimeOut[32]; + FIXP_DBL *pMyTimeOut = &MyTimeOut[0]; + + for (no_channels = no_channels; no_channels--;) + { + FIXP_DBL result; + FIXP_DBL A, B, real, imag; + + real = *realSlot--; + imag = *imagSlot--; + A = p_fltm[0]; /* Bottom=[310] Top=[311] */ + B = p_flt[7]; /* Bottom=[14] Top=[15] */ + result = SMLAWB( sta[0], real, A ); /* index=310...........0 */ + *sta++ = SMLAWB( sta[1], imag, B ); /* index=14..........324 */ + B = p_flt[6]; /* Bottom=[12] Top=[13] */ + *sta++ = SMLAWT( sta[1], real, A ); /* index=311...........1 */ + A = p_fltm[1]; /* Bottom=[312] Top=[313] */ + *sta++ = SMLAWT( sta[1], imag, B ); /* index=13..........323 */ + *sta++ = SMLAWB( sta[1], real, A ); /* index=312...........2 */ + *sta++ = SMLAWB( sta[1], imag, B ); /* index=12..........322 */ + *sta++ = SMLAWT( sta[1], real, A ); /* index=313...........3 */ + A = p_fltm[2]; /* Bottom=[314] Top=[315] */ + B = p_flt[5]; /* Bottom=[10] Top=[11] */ + *sta++ = SMLAWT( sta[1], imag, B ); /* index=11..........321 */ + *sta++ = SMLAWB( sta[1], real, A ); /* index=314...........4 */ + *sta++ = SMULWB( imag, B ); /* index=10..........320 */ + + *pMyTimeOut++ = result; + + p_fltm -= 5; + p_flt += 5; + } + + pMyTimeOut = &MyTimeOut[0]; +#if (SAMPLE_BITS == 16) + const FIXP_DBL max_pos = (FIXP_DBL) 0x00007FFF << scale; + const FIXP_DBL max_neg = (FIXP_DBL) 0xFFFF8001 << scale; +#else + scale = -scale; + const FIXP_DBL max_pos = (FIXP_DBL) 0x7FFFFFFF >> scale; + const FIXP_DBL max_neg = (FIXP_DBL) 0x80000001 >> scale; +#endif + const FIXP_DBL add_neg = (1 << scale) - 1; + + no_channels = qmf->no_channels; + + timeOut += no_channels*stride; + + FDK_ASSERT(scale >= 0); + + if (qmf->outGain != 0x80000000) + { + FIXP_DBL gain = qmf->outGain; + for (no_channels>>=2; no_channels--;) + { + FIXP_DBL result1, result2; + + result1 = *pMyTimeOut++; + result2 = *pMyTimeOut++; + + result1 = fMult(result1,gain); + timeOut -= stride; + if (result1 < 0) result1 += add_neg; + if (result1 < max_neg) result1 = max_neg; + if (result1 > max_pos) result1 = max_pos; +#if (SAMPLE_BITS == 16) + timeOut[0] = result1 >> scale; +#else + timeOut[0] = result1 << scale; +#endif + + result2 = fMult(result2,gain); + timeOut -= stride; + if (result2 < 0) result2 += add_neg; + if (result2 < max_neg) result2 = max_neg; + if (result2 > max_pos) result2 = max_pos; +#if (SAMPLE_BITS == 16) + timeOut[0] = result2 >> scale; +#else + timeOut[0] = result2 << scale; +#endif + + result1 = *pMyTimeOut++; + result2 = *pMyTimeOut++; + + result1 = fMult(result1,gain); + timeOut -= stride; + if (result1 < 0) result1 += add_neg; + if (result1 < max_neg) result1 = max_neg; + if (result1 > max_pos) result1 = max_pos; +#if (SAMPLE_BITS == 16) + timeOut[0] = result1 >> scale; +#else + timeOut[0] = result1 << scale; +#endif + + result2 = fMult(result2,gain); + timeOut -= stride; + if (result2 < 0) result2 += add_neg; + if (result2 < max_neg) result2 = max_neg; + if (result2 > max_pos) result2 = max_pos; +#if (SAMPLE_BITS == 16) + timeOut[0] = result2 >> scale; +#else + timeOut[0] = result2 << scale; +#endif + } + } + else + { + for (no_channels>>=2; no_channels--;) + { + FIXP_DBL result1, result2; + result1 = *pMyTimeOut++; + result2 = *pMyTimeOut++; + timeOut -= stride; + if (result1 < 0) result1 += add_neg; + if (result1 < max_neg) result1 = max_neg; + if (result1 > max_pos) result1 = max_pos; +#if (SAMPLE_BITS == 16) + timeOut[0] = result1 >> scale; +#else + timeOut[0] = result1 << scale; +#endif + + timeOut -= stride; + if (result2 < 0) result2 += add_neg; + if (result2 < max_neg) result2 = max_neg; + if (result2 > max_pos) result2 = max_pos; +#if (SAMPLE_BITS == 16) + timeOut[0] = result2 >> scale; +#else + timeOut[0] = result2 << scale; +#endif + + result1 = *pMyTimeOut++; + result2 = *pMyTimeOut++; + timeOut -= stride; + if (result1 < 0) result1 += add_neg; + if (result1 < max_neg) result1 = max_neg; + if (result1 > max_pos) result1 = max_pos; +#if (SAMPLE_BITS == 16) + timeOut[0] = result1 >> scale; +#else + timeOut[0] = result1 << scale; +#endif + + timeOut -= stride; + if (result2 < 0) result2 += add_neg; + if (result2 < max_neg) result2 = max_neg; + if (result2 > max_pos) result2 = max_pos; +#if (SAMPLE_BITS == 16) + timeOut[0] = result2 >> scale; +#else + timeOut[0] = result2 << scale; +#endif + } + } + return 0; +} + +static +void qmfSynPrototypeFirSlot_fallback( HANDLE_QMF_FILTER_BANK qmf, + FIXP_DBL *realSlot, /*!< Input: Pointer to real Slot */ + FIXP_DBL *imagSlot, /*!< Input: Pointer to imag Slot */ + INT_PCM *timeOut, /*!< Time domain data */ + const int stride + ); + +/*! + \brief Perform Synthesis Prototype Filtering on a single slot of input data. + + The filter takes 2 * #MAX_SYNTHESIS_CHANNELS of input data and + generates #MAX_SYNTHESIS_CHANNELS time domain output samples. +*/ + +static +void qmfSynPrototypeFirSlot( HANDLE_QMF_FILTER_BANK qmf, + FIXP_DBL *realSlot, /*!< Input: Pointer to real Slot */ + FIXP_DBL *imagSlot, /*!< Input: Pointer to imag Slot */ + INT_PCM *timeOut, /*!< Time domain data */ + const int stride + ) +{ + INT err = -1; + + switch (qmf->p_stride) { + case 2: + err = qmfSynPrototypeFirSlot2(qmf, realSlot, imagSlot, timeOut, stride); + break; + default: + err = -1; + } + + /* fallback if configuration not available or failed */ + if(err!=0) { + qmfSynPrototypeFirSlot_fallback(qmf, realSlot, imagSlot, timeOut, stride); + } +} +#endif /* FUNCTION_qmfSynPrototypeFirSlot */ + +#endif /* ( defined(__CC_ARM) && defined(__ARM_ARCH_5TE__) && (SAMPLE_BITS == 16) ) && !defined(QMF_TABLE_FULL) */ + + + +/* #####################################################################################*/ + + + +#endif /* (QMF_NO_POLY==5) */ + diff --git a/libFDK/src/arm/scale_arm.cpp b/libFDK/src/arm/scale_arm.cpp new file mode 100644 index 0000000..906766f --- /dev/null +++ b/libFDK/src/arm/scale_arm.cpp @@ -0,0 +1,110 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Arthur Tritthart + Description: Scaling operations for ARM + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +/* prevent multiple inclusion with re-definitions */ +#ifndef __INCLUDE_SCALE_ARM__ +#define __INCLUDE_SCALE_ARM__ + +#define FUNCTION_scaleValuesWithFactor_DBL + +SCALE_INLINE +void scaleValuesWithFactor( + FIXP_DBL *vector, + FIXP_DBL factor, + INT len, + INT scalefactor + ) +{ + /* This code combines the fMult with the scaling */ + /* It performs a fMultDiv2 and increments shift by 1 */ + int shift = scalefactor + 1; + FIXP_DBL *mySpec = vector; + + shift = fixmin_I(shift,(INT)DFRACT_BITS-1); + + if (shift >= 0) + { + for (int i=0; i<(len>>2); i++) + { + FIXP_DBL tmp0 = mySpec[0]; + FIXP_DBL tmp1 = mySpec[1]; + FIXP_DBL tmp2 = mySpec[2]; + FIXP_DBL tmp3 = mySpec[3]; + tmp0 = fMultDiv2(tmp0, factor); + tmp1 = fMultDiv2(tmp1, factor); + tmp2 = fMultDiv2(tmp2, factor); + tmp3 = fMultDiv2(tmp3, factor); + tmp0 <<= shift; + tmp1 <<= shift; + tmp2 <<= shift; + tmp3 <<= shift; + *mySpec++ = tmp0; + *mySpec++ = tmp1; + *mySpec++ = tmp2; + *mySpec++ = tmp3; + } + for (int i=len&3; i--;) + { + FIXP_DBL tmp0 = mySpec[0]; + tmp0 = fMultDiv2(tmp0, factor); + tmp0 <<= shift; + *mySpec++ = tmp0; + } + } + else + { + shift = -shift; + for (int i=0; i<(len>>2); i++) + { + FIXP_DBL tmp0 = mySpec[0]; + FIXP_DBL tmp1 = mySpec[1]; + FIXP_DBL tmp2 = mySpec[2]; + FIXP_DBL tmp3 = mySpec[3]; + tmp0 = fMultDiv2(tmp0, factor); + tmp1 = fMultDiv2(tmp1, factor); + tmp2 = fMultDiv2(tmp2, factor); + tmp3 = fMultDiv2(tmp3, factor); + tmp0 >>= shift; + tmp1 >>= shift; + tmp2 >>= shift; + tmp3 >>= shift; + *mySpec++ = tmp0; + *mySpec++ = tmp1; + *mySpec++ = tmp2; + *mySpec++ = tmp3; + } + for (int i=len&3; i--;) + { + FIXP_DBL tmp0 = mySpec[0]; + tmp0 = fMultDiv2(tmp0, factor); + tmp0 >>= shift; + *mySpec++ = tmp0; + } + } +} + +#endif /* #ifndef __INCLUDE_SCALE_ARM__ */ diff --git a/libFDK/src/autocorr2nd.cpp b/libFDK/src/autocorr2nd.cpp new file mode 100644 index 0000000..83ccc31 --- /dev/null +++ b/libFDK/src/autocorr2nd.cpp @@ -0,0 +1,216 @@ +/*************************** Fraunhofer IIS FDK Tools *********************** + + (C) Copyright Fraunhofer IIS (2009) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Lohwasser + Description: auto-correlation functions + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "autocorr2nd.h" + + + +/* If the accumulator does not provide enough overflow bits, + products have to be shifted down in the autocorrelation below. */ +#define SHIFT_FACTOR (5) +#define SHIFT >> (SHIFT_FACTOR) + + +#if defined(__CC_ARM) || defined(__arm__) +#include "arm/autocorr2nd.cpp" +#endif + + +/*! + * + * \brief Calculate second order autocorrelation using 2 accumulators + * + */ +#if !defined(FUNCTION_autoCorr2nd_real) +INT +autoCorr2nd_real (ACORR_COEFS *ac, /*!< Pointer to autocorrelation coeffs */ + const FIXP_DBL *reBuffer, /*!< Pointer to to real part of input samples */ + const int len /*!< Number input samples */ + ) +{ + int j, autoCorrScaling, mScale; + + FIXP_DBL accu1, accu2, accu3, accu4, accu5; + + const FIXP_DBL *pReBuf; + + const FIXP_DBL *realBuf = reBuffer; + + /* + r11r,r22r + r01r,r12r + r02r + */ + pReBuf = realBuf-2; + accu5 = ( (fMultDiv2(pReBuf[0], pReBuf[2]) + + fMultDiv2(pReBuf[1], pReBuf[3])) SHIFT); + pReBuf++; + + //len must be even + accu1 = fPow2Div2(pReBuf[0]) SHIFT; + accu3 = fMultDiv2(pReBuf[0], pReBuf[1]) SHIFT; + pReBuf++; + + for ( j = (len - 2)>>1; j != 0; j--,pReBuf+=2 ) { + + accu1 += ( (fPow2Div2(pReBuf[0]) + + fPow2Div2(pReBuf[1])) SHIFT); + + accu3 += ( (fMultDiv2(pReBuf[0], pReBuf[1]) + + fMultDiv2(pReBuf[1], pReBuf[2])) SHIFT); + + accu5 += ( (fMultDiv2(pReBuf[0], pReBuf[2]) + + fMultDiv2(pReBuf[1], pReBuf[3])) SHIFT); + + } + + accu2 = (fPow2Div2(realBuf[-2]) SHIFT); + accu2 += accu1; + + accu1 += (fPow2Div2(realBuf[len - 2]) SHIFT); + + accu4 = (fMultDiv2(realBuf[-1],realBuf[-2]) SHIFT); + accu4 += accu3; + + accu3 += (fMultDiv2(realBuf[len - 1],realBuf[len - 2]) SHIFT); + + mScale = CntLeadingZeros( (accu1 | accu2 | fAbs(accu3) | fAbs(accu4) | fAbs(accu5)) ) - 1; + autoCorrScaling = mScale - 1 - SHIFT_FACTOR; /* -1 because of fMultDiv2*/ + + /* Scale to common scale factor */ + ac->r11r = accu1 << mScale; + ac->r22r = accu2 << mScale; + ac->r01r = accu3 << mScale; + ac->r12r = accu4 << mScale; + ac->r02r = accu5 << mScale; + + ac->det = (fMultDiv2(ac->r11r,ac->r22r) - fMultDiv2(ac->r12r,ac->r12r)) ; + mScale = CountLeadingBits(fAbs(ac->det)); + + ac->det <<= mScale; + ac->det_scale = mScale - 1; + + return autoCorrScaling; +} +#endif + +#ifndef LOW_POWER_SBR_ONLY +#if !defined(FUNCTION_autoCorr2nd_cplx) +INT +autoCorr2nd_cplx (ACORR_COEFS *ac, /*!< Pointer to autocorrelation coeffs */ + const FIXP_DBL *reBuffer, /*!< Pointer to real part of input samples */ + const FIXP_DBL *imBuffer, /*!< Pointer to imag part of input samples */ + const int len /*!< Number of input samples */ + ) +{ + + int j, autoCorrScaling, mScale, len_scale; + + FIXP_DBL accu0, accu1,accu2, accu3, accu4, accu5, accu6, accu7, accu8; + + const FIXP_DBL *pReBuf, *pImBuf; + + const FIXP_DBL *realBuf = reBuffer; + const FIXP_DBL *imagBuf = imBuffer; + + (len>64) ? (len_scale = 6) : (len_scale = 5); + /* + r00r, + r11r,r22r + r01r,r12r + r01i,r12i + r02r,r02i + */ + accu1 = accu3 = accu5 = accu7 = accu8 = FL2FXCONST_DBL(0.0f); + + pReBuf = realBuf-2, pImBuf = imagBuf-2; + accu7 += ( (fMultDiv2(pReBuf[2], pReBuf[0]) + fMultDiv2(pImBuf[2], pImBuf[0])) >> len_scale); + accu8 += ( (fMultDiv2(pImBuf[2], pReBuf[0]) - fMultDiv2(pReBuf[2], pImBuf[0])) >> len_scale); + + pReBuf = realBuf-1, pImBuf = imagBuf-1; + for ( j = (len - 1); j != 0; j--,pReBuf++,pImBuf++ ){ + accu1 += ( (fPow2Div2(pReBuf[0] ) + fPow2Div2(pImBuf[0] )) >> len_scale); + accu3 += ( (fMultDiv2(pReBuf[0], pReBuf[1]) + fMultDiv2(pImBuf[0], pImBuf[1])) >> len_scale); + accu5 += ( (fMultDiv2(pImBuf[1], pReBuf[0]) - fMultDiv2(pReBuf[1], pImBuf[0])) >> len_scale); + accu7 += ( (fMultDiv2(pReBuf[2], pReBuf[0]) + fMultDiv2(pImBuf[2], pImBuf[0])) >> len_scale); + accu8 += ( (fMultDiv2(pImBuf[2], pReBuf[0]) - fMultDiv2(pReBuf[2], pImBuf[0])) >> len_scale); + } + + accu2 = ( (fPow2Div2(realBuf[-2]) + fPow2Div2(imagBuf[-2])) >> len_scale); + accu2 += accu1; + + accu1 += ( (fPow2Div2(realBuf[len-2]) + + fPow2Div2(imagBuf[len-2])) >> len_scale); + accu0 = ( (fPow2Div2(realBuf[len-1]) + + fPow2Div2(imagBuf[len-1])) >> len_scale) - + ( (fPow2Div2(realBuf[-1]) + + fPow2Div2(imagBuf[-1])) >> len_scale); + accu0 += accu1; + + accu4 = ( (fMultDiv2(realBuf[-1], realBuf[-2]) + + fMultDiv2(imagBuf[-1], imagBuf[-2])) >> len_scale); + accu4 += accu3; + + accu3 += ( (fMultDiv2(realBuf[len-1], realBuf[len-2]) + + fMultDiv2(imagBuf[len-1], imagBuf[len-2])) >> len_scale); + + accu6 = ( (fMultDiv2(imagBuf[-1], realBuf[-2]) - + fMultDiv2(realBuf[-1], imagBuf[-2])) >> len_scale); + accu6 += accu5; + + accu5 += ( (fMultDiv2(imagBuf[len - 1], realBuf[len - 2]) - + fMultDiv2(realBuf[len - 1], imagBuf[len - 2])) >> len_scale); + + mScale = CntLeadingZeros( (accu0 | accu1 | accu2 | fAbs(accu3) | fAbs(accu4) | fAbs(accu5) | + fAbs(accu6) | fAbs(accu7) | fAbs(accu8)) ) - 1; + autoCorrScaling = mScale - 1 - len_scale; /* -1 because of fMultDiv2*/ + + /* Scale to common scale factor */ + ac->r00r = (FIXP_DBL)accu0 << mScale; + ac->r11r = (FIXP_DBL)accu1 << mScale; + ac->r22r = (FIXP_DBL)accu2 << mScale; + ac->r01r = (FIXP_DBL)accu3 << mScale; + ac->r12r = (FIXP_DBL)accu4 << mScale; + ac->r01i = (FIXP_DBL)accu5 << mScale; + ac->r12i = (FIXP_DBL)accu6 << mScale; + ac->r02r = (FIXP_DBL)accu7 << mScale; + ac->r02i = (FIXP_DBL)accu8 << mScale; + + ac->det = ( fMultDiv2(ac->r11r,ac->r22r) >> 1 ) - + ( (fMultDiv2(ac->r12r,ac->r12r) + fMultDiv2(ac->r12i,ac->r12i)) >> 1 ); + mScale = CountLeadingBits(fAbs(ac->det)); + + ac->det <<= mScale; + ac->det_scale = mScale - 2; + + return autoCorrScaling; +} +#endif /* FUNCTION_autoCorr2nd_cplx */ +#endif /* LOW_POWER_SBR_ONLY */ + + diff --git a/libFDK/src/dct.cpp b/libFDK/src/dct.cpp new file mode 100644 index 0000000..d05a26f --- /dev/null +++ b/libFDK/src/dct.cpp @@ -0,0 +1,513 @@ +/**************************************************************************** + + (C) copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + + $Id$ + +*******************************************************************************/ +/*! + \file dct.cpp + \brief DCT Implementations $Revision: 36871 $ + Library functions to calculate standard DCTs. This will most likely be replaced by hand-optimized + functions for the specific target processor. + + Three different implementations of the dct type II and the dct type III transforms are provided. + + By default implementations which are based on a single, standard complex FFT-kernel are used (dctII_f() and dctIII_f()). + These are specifically helpful in cases where optimized FFT libraries are already available. The FFT used in these + implementation is FFT rad2 from FDK_tools. + + Of course, one might also use DCT-libraries should they be available. The DCT and DST + type IV implementations are only available in a version based on a complex FFT kernel. +*/ + +#include "dct.h" + + +#include "FDK_tools_rom.h" +#include "fft.h" + + +#if defined(__arm__) +#include "arm/dct_arm.cpp" +#endif + + +/*! + * + * \brief Perform dct type 3 + * The dct 3 is calculated by a inverse real fft, with + * some pre twiddeling before the inverse real fft, as discribed by Takuya OOURA. + * (http://momonga.t.u-tokyo.ac.jp/~ooura/fftman/ftmn2_32.html#sec2_3_2) + * The real inverse fft is calculated by a inverse complex fft, as described + * in numerical recipes in C, Cambridge University press + * the auxiliary function is built by reversing the odd samples + * + * Instead of doing 2 times the conjugation to calculate the + * inverse cfft with the cfft, one can also swap elements before + * calling the cfft to get the same result: + * swap + * r(1),i(1) with r(n-1),i(n-1), + * r(2),i(2) with r(n-2),i(n-2), ... + * r(n/2-1),i(n/2-1) with r(n/2+1),i(n/2+1) + * + * + * Scaling 1 shift in pre twiddeling, + * log2(L)-1 in cfft + */ +#if !defined(FUNCTION_dct_III) +void dct_III(FIXP_DBL *pDat, /*!< pointer to input/output */ + FIXP_DBL *tmp, /*!< pointer to temporal working buffer */ + int L, /*!< lenght of transform */ + int *pDat_e + ) +{ + FDK_ASSERT(L == 64 || L == 32); + int i; + FIXP_DBL xr, accu1, accu2; + int inc; + int M = L>>1; + int ld_M; + + if (L == 64) ld_M = 5; + else ld_M = 4; + + /* This loop performs multiplication for index i (i*inc) */ + inc = (64/2) >> ld_M; /* 64/L */ + + FIXP_DBL *pTmp_0 = &tmp[2]; + FIXP_DBL *pTmp_1 = &tmp[(M-1)*2]; + + for(i=1; i>1; i++,pTmp_0+=2,pTmp_1-=2) { + + FIXP_DBL accu3,accu4,accu5,accu6; + + cplxMultDiv2(&accu2, &accu1, pDat[L - i], pDat[i], sin_twiddle_L64[i*inc]); + cplxMultDiv2(&accu4, &accu3, pDat[M+i], pDat[M-i], sin_twiddle_L64[(M-i)*inc]); + accu3 >>= 1; accu4 >>= 1; + + /* This method is better for ARM926, that uses operand2 shifted right by 1 always */ + cplxMultDiv2(&accu6, &accu5, (accu3 - (accu1>>1)), ((accu2>>1) + accu4), sin_twiddle_L64[(4*i)*inc]); + xr = (accu1>>1) + accu3; + pTmp_0[0] = (xr>>1) - accu5; + pTmp_1[0] = (xr>>1) + accu5; + + xr = (accu2>>1) - accu4; + pTmp_0[1] = (xr>>1) - accu6; + pTmp_1[1] = -((xr>>1) + accu6); + + } + + xr = fMultDiv2(pDat[M], sin_twiddle_L64[64/2].v.re );/* cos((PI/(2*L))*M); */ + tmp[0] = ((pDat[0]>>1) + xr)>>1; + tmp[1] = ((pDat[0]>>1) - xr)>>1; + + cplxMultDiv2(&accu2, &accu1, pDat[L - (M/2)], pDat[M/2], sin_twiddle_L64[64/4]); + tmp[M] = accu1>>1; + tmp[M+1] = accu2>>1; + + /* dit_fft expects 1 bit scaled input values */ + fft(M, tmp, pDat_e); + + /* ARM926: 12 cycles per 2-iteration, no overhead code by compiler */ + pTmp_1 = &tmp[L]; + for (i = M>>1; i--;) + { + FIXP_DBL tmp1, tmp2, tmp3, tmp4; + tmp1 = *tmp++; + tmp2 = *tmp++; + tmp3 = *--pTmp_1; + tmp4 = *--pTmp_1; + *pDat++ = tmp1; + *pDat++ = tmp3; + *pDat++ = tmp2; + *pDat++ = tmp4; + } + + *pDat_e += 2; +} +#endif + +/*! + * + * \brief Perform dct type 2 + * The dct 2 is calculated by a real inverse fft, with + * some pre twiddeling after the fft, as discribed by Takuya OOURA. + * (http://momonga.t.u-tokyo.ac.jp/~ooura/fftman/ftmn2_32.html#sec2_3_2) + * The real inverse fft is calculated by a inverse complex fft, as described + * in numerical recipes in C, Cambridge University press + * the auxilery function is build by reversing the odd samples + * + * Scaling 1 shift in pre twiddeling, + * 5 in cfft + */ +#if !defined(FUNCTION_dct_II) +void dct_II(FIXP_DBL *pDat, /*!< pointer to input/output */ + FIXP_DBL *tmp, /*!< pointer to temporal working buffer */ + int L, /*!< lenght of transform */ + int *pDat_e + ) +{ + FDK_ASSERT(L == 64 || L == 32); + FIXP_DBL accu1,accu2; + FIXP_DBL *pTmp_0, *pTmp_1; + + int i; + int inc; + int M = L>>1; + int ld_M; + + FDK_ASSERT(L == 64 || L == 32); + ld_M = 4 + (L >> 6); /* L=64: 5, L=32: 4 */ + + inc = (64/2) >> ld_M; /* L=64: 1, L=32: 2 */ + + FIXP_DBL *pdat = &pDat[0]; + FIXP_DBL accu3, accu4; + pTmp_0 = &tmp[0]; + pTmp_1 = &tmp[L-1]; + for (i = M>>1; i--; ) + { + accu1 = *pdat++; + accu2 = *pdat++; + accu3 = *pdat++; + accu4 = *pdat++; + accu1 >>= 1; + accu2 >>= 1; + accu3 >>= 1; + accu4 >>= 1; + *pTmp_0++ = accu1; + *pTmp_0++ = accu3; + *pTmp_1-- = accu2; + *pTmp_1-- = accu4; + } + + + fft(M, tmp, pDat_e); + + pTmp_0 = &tmp[2]; + pTmp_1 = &tmp[(M-1)*2]; + + for (i=1; i>1; i++,pTmp_0+=2,pTmp_1-=2) { + + FIXP_DBL a1,a2; + FIXP_DBL accu3, accu4; + + a1 = ((pTmp_0[1]>>1) + (pTmp_1[1]>>1)); + a2 = ((pTmp_1[0]>>1) - (pTmp_0[0]>>1)); + + cplxMultDiv2(&accu1, &accu2, a2, a1, sin_twiddle_L64[(4*i)*inc]); + accu1<<=1; accu2<<=1; + + a1 = ((pTmp_0[0]>>1) + (pTmp_1[0]>>1)); + a2 = ((pTmp_0[1]>>1) - (pTmp_1[1]>>1)); + + cplxMultDiv2(&accu3, &accu4, (a1 + accu2), -(accu1 + a2), sin_twiddle_L64[i*inc]); + pDat[L - i] = accu4; + pDat[i] = accu3; + + cplxMultDiv2(&accu3, &accu4, (a1 - accu2), -(accu1 - a2), sin_twiddle_L64[(M-i)*inc]); + pDat[M + i] = accu4; + pDat[M - i] = accu3; + + } + + cplxMultDiv2(&accu1, &accu2, tmp[M], tmp[M+1], sin_twiddle_L64[(M/2)*inc]); + pDat[L - (M/2)] = accu2; + pDat[M/2] = accu1; + + pDat[0] = (tmp[0]>>1)+(tmp[1]>>1); + pDat[M] = fMult(((tmp[0]>>1)-(tmp[1]>>1)), sin_twiddle_L64[64/2].v.re);/* cos((PI/(2*L))*M); */ + + *pDat_e += 2; +} +#endif + +static +void getTables(const FIXP_WTP **twiddle, const FIXP_STP **sin_twiddle, int *sin_step, int length) +{ + int ld2_length; + + /* Get ld2 of length - 2 + 1 + -2: because first table entry is window of size 4 + +1: because we already include +1 because of ceil(log2(length)) */ + ld2_length = DFRACT_BITS-1-fNormz((FIXP_DBL)length) - 1; + + /* Extract sort of "eigenvalue" (the 4 left most bits) of length. */ + switch ( (length) >> (ld2_length-1) ) { + case 0x4: /* radix 2 */ + *sin_twiddle = SineTable512; + *sin_step = 1<<(9 - ld2_length); + *twiddle = windowSlopes[0][0][ld2_length-1]; + break; + case 0x7: /* 10 ms */ + *sin_twiddle = SineTable480; + *sin_step = 1<<(8 - ld2_length); + *twiddle = windowSlopes[0][1][ld2_length]; + break; + default: + *sin_twiddle = NULL; + *sin_step = 0; + *twiddle = NULL; + break; + } + + FDK_ASSERT(*twiddle != NULL); + + FDK_ASSERT(*sin_step > 0); + +} + +#if !defined(FUNCTION_dct_IV) + +void dct_IV(FIXP_DBL *pDat, + int L, + int *pDat_e) +{ + int sin_step = 0; + int M = L >> 1; + + const FIXP_WTP *twiddle; + const FIXP_STP *sin_twiddle; + + FDK_ASSERT(L >= 4); + + getTables(&twiddle, &sin_twiddle, &sin_step, L); + +#ifdef FUNCTION_dct_IV_func1 + if (M>=4 && (M&3) == 0) { + /* ARM926: 44 cycles for 2 iterations = 22 cycles/iteration */ + dct_IV_func1(M>>2, twiddle, &pDat[0], &pDat[L-1]); + } else +#endif /* FUNCTION_dct_IV_func1 */ + { + FIXP_DBL *RESTRICT pDat_0 = &pDat[0]; + FIXP_DBL *RESTRICT pDat_1 = &pDat[L - 2]; + register int i; + + /* 29 cycles on ARM926 */ + for (i = 0; i < M-1; i+=2,pDat_0+=2,pDat_1-=2) + { + register FIXP_DBL accu1,accu2,accu3,accu4; + + accu1 = pDat_1[1]; accu2 = pDat_0[0]; + accu3 = pDat_0[1]; accu4 = pDat_1[0]; + + cplxMultDiv2(&accu1, &accu2, accu1, accu2, twiddle[i]); + cplxMultDiv2(&accu3, &accu4, accu4, accu3, twiddle[i+1]); + + pDat_0[0] = accu2; pDat_0[1] = accu1; + pDat_1[0] = accu4; pDat_1[1] = -accu3; + } + if (M&1) + { + register FIXP_DBL accu1,accu2; + + accu1 = pDat_1[1]; accu2 = pDat_0[0]; + + cplxMultDiv2(&accu1, &accu2, accu1, accu2, twiddle[i]); + + pDat_0[0] = accu2; pDat_0[1] = accu1; + } + } + + fft(M, pDat, pDat_e); + +#ifdef FUNCTION_dct_IV_func2 + if (M>=4 && (M&3) == 0) { + /* ARM926: 42 cycles for 2 iterations = 21 cycles/iteration */ + dct_IV_func2(M>>2, sin_twiddle, &pDat[0], &pDat[L], sin_step); + } else +#endif /* FUNCTION_dct_IV_func2 */ + { + FIXP_DBL *RESTRICT pDat_0 = &pDat[0]; + FIXP_DBL *RESTRICT pDat_1 = &pDat[L - 2]; + register FIXP_DBL accu1,accu2,accu3,accu4; + int idx, i; + + /* Sin and Cos values are 0.0f and 1.0f */ + accu1 = pDat_1[0]; + accu2 = pDat_1[1]; + + pDat_1[1] = -(pDat_0[1]>>1); + pDat_0[0] = (pDat_0[0]>>1); + + + /* 28 cycles for ARM926 */ + for (idx = sin_step,i=1; i<(M+1)>>1; i++, idx+=sin_step) + { + FIXP_STP twd = sin_twiddle[idx]; + cplxMultDiv2(&accu3, &accu4, accu1, accu2, twd); + pDat_0[1] = accu3; + pDat_1[0] = accu4; + + pDat_0+=2; + pDat_1-=2; + + cplxMultDiv2(&accu3, &accu4, pDat_0[1], pDat_0[0], twd); + + accu1 = pDat_1[0]; + accu2 = pDat_1[1]; + + pDat_1[1] = -accu3; + pDat_0[0] = accu4; + } + + if ( (M&1) == 0 ) + { + /* Last Sin and Cos value pair are the same */ + accu1 = fMultDiv2(accu1, WTC(0x5a82799a)); + accu2 = fMultDiv2(accu2, WTC(0x5a82799a)); + + pDat_1[0] = accu1 + accu2; + pDat_0[1] = accu1 - accu2; + } + } + + /* Add twiddeling scale. */ + *pDat_e += 2; +} +#endif /* defined (FUNCTION_dct_IV) */ + +#if !defined(FUNCTION_dst_IV) +void dst_IV(FIXP_DBL *pDat, + int L, + int *pDat_e ) +{ + int sin_step = 0; + int M = L >> 1; + + const FIXP_WTP *twiddle; + const FIXP_STP *sin_twiddle; + +#ifdef DSTIV2_ENABLE + if (L == 2) { + const FIXP_STP tab = STCP(0x7641AF3D, 0x30FB9452); + FIXP_DBL tmp1, tmp2; + + cplxMultDiv2(&tmp2, &tmp1, pDat[0], pDat[1], tab); + + pDat[0] = tmp1; + pDat[1] = tmp2; + + *pDat_e += 1; + + return; + } +#else + FDK_ASSERT(L >= 4); +#endif + + getTables(&twiddle, &sin_twiddle, &sin_step, L); + +#ifdef FUNCTION_dst_IV_func1 + if ( (M>=4) && ((M&3) == 0) ) { + dst_IV_func1(M, twiddle, &pDat[0], &pDat[L]); + } else +#endif + { + FIXP_DBL *RESTRICT pDat_0 = &pDat[0]; + FIXP_DBL *RESTRICT pDat_1 = &pDat[L - 2]; + + register int i; + + /* 34 cycles on ARM926 */ + for (i = 0; i < M-1; i+=2,pDat_0+=2,pDat_1-=2) + { + register FIXP_DBL accu1,accu2,accu3,accu4; + + accu1 = pDat_1[1]; accu2 = -pDat_0[0]; + accu3 = pDat_0[1]; accu4 = -pDat_1[0]; + + cplxMultDiv2(&accu1, &accu2, accu1, accu2, twiddle[i]); + cplxMultDiv2(&accu3, &accu4, accu4, accu3, twiddle[i+1]); + + pDat_0[0] = accu2; pDat_0[1] = accu1; + pDat_1[0] = accu4; pDat_1[1] = -accu3; + } + if (M&1) + { + register FIXP_DBL accu1,accu2; + + accu1 = pDat_1[1]; accu2 = -pDat_0[0]; + + cplxMultDiv2(&accu1, &accu2, accu1, accu2, twiddle[i]); + + pDat_0[0] = accu2; pDat_0[1] = accu1; + } + } + + fft(M, pDat, pDat_e); + +#ifdef FUNCTION_dst_IV_func2 + if ( (M>=4) && ((M&3) == 0) ) { + dst_IV_func2(M>>2, sin_twiddle + sin_step, &pDat[0], &pDat[L - 1], sin_step); + } else +#endif /* FUNCTION_dst_IV_func2 */ + { + FIXP_DBL *RESTRICT pDat_0; + FIXP_DBL *RESTRICT pDat_1; + register FIXP_DBL accu1,accu2,accu3,accu4; + int idx, i; + + pDat_0 = &pDat[0]; + pDat_1 = &pDat[L - 2]; + + /* Sin and Cos values are 0.0f and 1.0f */ + accu1 = pDat_1[0]; + accu2 = pDat_1[1]; + + pDat_1[1] = -(pDat_0[0]>>1); + pDat_0[0] = (pDat_0[1]>>1); + + for (idx = sin_step,i=1; i<(M+1)>>1; i++, idx+=sin_step) + { + FIXP_STP twd = sin_twiddle[idx]; + + cplxMultDiv2(&accu3, &accu4, accu1, accu2, twd); + pDat_1[0] = -accu3; + pDat_0[1] = -accu4; + + pDat_0+=2; + pDat_1-=2; + + cplxMultDiv2(&accu3, &accu4, pDat_0[1], pDat_0[0], twd); + + accu1 = pDat_1[0]; + accu2 = pDat_1[1]; + + pDat_0[0] = accu3; + pDat_1[1] = -accu4; + } + + if ( (M&1) == 0 ) + { + /* Last Sin and Cos value pair are the same */ + accu1 = fMultDiv2(accu1, WTC(0x5a82799a)); + accu2 = fMultDiv2(accu2, WTC(0x5a82799a)); + + pDat_0[1] = - accu1 - accu2; + pDat_1[0] = accu2 - accu1; + } + } + + /* Add twiddeling scale. */ + *pDat_e += 2; +} +#endif /* !defined(FUNCTION_dst_IV) */ + + diff --git a/libFDK/src/fft.cpp b/libFDK/src/fft.cpp new file mode 100644 index 0000000..9f47807 --- /dev/null +++ b/libFDK/src/fft.cpp @@ -0,0 +1,1395 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2001) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl, DSP Solutions + Description: Fix point FFT + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + History: + 20-APR-2010 A. Tritthart replaced modulo operations with comparisons in fft15 + to avoid failures with ARM RVCT 4.0 compiler + Tuned fft15 by 18% (Cortex-A8) to 25% (ARM926) by reprogramming + with merged loops. + +******************************************************************************/ + +#include "fft.h" + +#include "fft_rad2.h" +#include "FDK_tools_rom.h" + + + + + +#define F3C(x) STC(x) + +#define C31 (F3C(0x91261468)) /* FL2FXCONST_DBL(-0.86602540) */ + +/* Performs the FFT of length 3 according to the algorithm after winograd. + No scaling of the input vector because the scaling is already done in the rotation vector. */ +static FORCEINLINE void fft3(FIXP_DBL *RESTRICT pDat) +{ + FIXP_DBL r1,r2; + FIXP_DBL s1,s2; + /* real part */ + r1 = pDat[2] + pDat[4]; + r2 = fMult((pDat[2] - pDat[4]), C31); + pDat[0] = pDat[0] + r1; + r1 = pDat[0] - r1 - (r1>>1); + + /* imaginary part */ + s1 = pDat[3] + pDat[5]; + s2 = fMult((pDat[3] - pDat[5]), C31); + pDat[1] = pDat[1] + s1; + s1 = pDat[1] - s1 - (s1>>1); + + /* combination */ + pDat[2] = r1 - s2; + pDat[4] = r1 + s2; + pDat[3] = s1 + r2; + pDat[5] = s1 - r2; +} + + +//#define F5C(x) ((FIXP_DBL)x) +#define F5C(x) STC(x) + +#define C51 (F5C(0x79bc3854)) /* FL2FXCONST_DBL( 0.95105652) */ +#define C52 (F5C(0x9d839db0)) /* FL2FXCONST_DBL(-1.53884180/2) */ +#define C53 (F5C(0xd18053ce)) /* FL2FXCONST_DBL(-0.36327126) */ +#define C54 (F5C(0x478dde64)) /* FL2FXCONST_DBL( 0.55901699) */ +#define C55 (F5C(0xb0000001)) /* FL2FXCONST_DBL(-1.25/2) */ + +/* performs the FFT of length 5 according to the algorithm after winograd */ +static FORCEINLINE void fft5(FIXP_DBL *RESTRICT pDat) +{ + FIXP_DBL r1,r2,r3,r4; + FIXP_DBL s1,s2,s3,s4; + FIXP_DBL t; + + /* real part */ + r1 = pDat[2] + pDat[8]; + r4 = pDat[2] - pDat[8]; + r3 = pDat[4] + pDat[6]; + r2 = pDat[4] - pDat[6]; + t = fMult((r1-r3), C54); + r1 = r1 + r3; + pDat[0] = pDat[0] + r1; + /* Bit shift left because of the constant C55 which was scaled with the factor 0.5 because of the representation of + the values as fracts */ + r1 = pDat[0] + (fMultDiv2(r1, C55) <<(2)); + r3 = r1 - t; + r1 = r1 + t; + t = fMult((r4 + r2), C51); + /* Bit shift left because of the constant C55 which was scaled with the factor 0.5 because of the representation of + the values as fracts */ + r4 = t + (fMultDiv2(r4, C52) <<(2)); + r2 = t + fMult(r2, C53); + + /* imaginary part */ + s1 = pDat[3] + pDat[9]; + s4 = pDat[3] - pDat[9]; + s3 = pDat[5] + pDat[7]; + s2 = pDat[5] - pDat[7]; + t = fMult((s1 - s3), C54); + s1 = s1 + s3; + pDat[1] = pDat[1] + s1; + /* Bit shift left because of the constant C55 which was scaled with the factor 0.5 because of the representation of + the values as fracts */ + s1 = pDat[1] + (fMultDiv2(s1, C55) <<(2)); + s3 = s1 - t; + s1 = s1 + t; + t = fMult((s4 + s2), C51); + /* Bit shift left because of the constant C55 which was scaled with the factor 0.5 because of the representation of + the values as fracts */ + s4 = t + (fMultDiv2(s4, C52) <<(2)); + s2 = t + fMult(s2, C53); + + /* combination */ + pDat[2] = r1 + s2; + pDat[8] = r1 - s2; + pDat[4] = r3 - s4; + pDat[6] = r3 + s4; + + pDat[3] = s1 - r2; + pDat[9] = s1 + r2; + pDat[5] = s3 + r4; + pDat[7] = s3 - r4; +} + + + + +#define N3 3 +#define N5 5 +#define N6 6 +#define N15 15 + +/* Performs the FFT of length 15. It is split into FFTs of length 3 and length 5. */ +static inline void fft15(FIXP_DBL *pInput) +{ +#if FORCE_CRITICAL_CODE_FOR_RVCT4 + FIXP_DBL accu; + int j; +#endif + FIXP_DBL aDst[2*N15]; + FIXP_DBL aDst1[2*N15]; + int i,k,l; + + /* Sort input vector for fft's of length 3 + input3(0:2) = [input(0) input(5) input(10)]; + input3(3:5) = [input(3) input(8) input(13)]; + input3(6:8) = [input(6) input(11) input(1)]; + input3(9:11) = [input(9) input(14) input(4)]; + input3(12:14) = [input(12) input(2) input(7)]; */ +#if FORCE_CRITICAL_CODE_FOR_RVCT4 + /* This branch generate failures on RVCT 4.0 with ARM926/ARM1136/ARM1176/C-R4, but not on Cortex-A8 */ + pSrc = pInput; + pDst = aDst; + for(i=0,l=0,k=0; i= (2*N15)) + l -= (2*N15); + } + l += (2*N3); + if (l >= (2*N15)) + l -= (2*N15); + } + /* Perform 5 times the fft of length 3 + output3(0:2) = fft3(input3(0:2)); + output3(3:5) = fft3(input3(3:5)); + output3(6:8) = fft3(input3(6:8)); + output3(9:11) = fft3(input3(9:11)); + output3(12:14) = fft3(input3(12:14)); */ + pSrc=aDst; + for(i=0; i>= 2; + pSrc[j] = accu; + } +#else + { + const FIXP_DBL *pSrc = pInput; + FIXP_DBL *RESTRICT pDst = aDst; + /* Merge 3 loops into one, skip call of fft3 */ + for(i=0,l=0,k=0; i= (2*N15)) + l -= (2*N15); + + pDst[k+2] = pSrc[l]; + pDst[k+3] = pSrc[l+1]; + l += 2*N5; + if (l >= (2*N15)) + l -= (2*N15); + pDst[k+4] = pSrc[l]; + pDst[k+5] = pSrc[l+1]; + l += (2*N5) + (2*N3); + if (l >= (2*N15)) + l -= (2*N15); + + /* fft3 merged with shift right by 2 loop */ + FIXP_DBL r1,r2,r3; + FIXP_DBL s1,s2; + /* real part */ + r1 = pDst[k+2] + pDst[k+4]; + r2 = fMult((pDst[k+2] - pDst[k+4]), C31); + s1 = pDst[k+0]; + pDst[k+0] = (s1 + r1)>>2; + r1 = s1 - (r1>>1); + + /* imaginary part */ + s1 = pDst[k+3] + pDst[k+5]; + s2 = fMult((pDst[k+3] - pDst[k+5]), C31); + r3 = pDst[k+1]; + pDst[k+1] = (r3 + s1)>>2; + s1 = r3 - (s1>>1); + + /* combination */ + pDst[k+2] = (r1 - s2)>>2; + pDst[k+4] = (r1 + s2)>>2; + pDst[k+3] = (s1 + r2)>>2; + pDst[k+5] = (s1 - r2)>>2; + } + } +#endif + /* Sort input vector for fft's of length 5 + input5(0:4) = [output3(0) output3(3) output3(6) output3(9) output3(12)]; + input5(5:9) = [output3(1) output3(4) output3(7) output3(10) output3(13)]; + input5(10:14) = [output3(2) output3(5) output3(8) output3(11) output3(14)]; */ + /* Merge 2 loops into one, brings about 10% */ + { + const FIXP_DBL *pSrc = aDst; + FIXP_DBL *RESTRICT pDst = aDst1; + for(i=0,l=0,k=0; i= (2*N15)) + l -= (2*N15); + pDst[k+2] = pSrc[l]; + pDst[k+3] = pSrc[l+1]; + l += (2*N6); + if (l >= (2*N15)) + l -= (2*N15); + pDst[k+4] = pSrc[l]; + pDst[k+5] = pSrc[l+1]; + l += (2*N6); + if (l >= (2*N15)) + l -= (2*N15); + pDst[k+6] = pSrc[l]; + pDst[k+7] = pSrc[l+1]; + l += (2*N6); + if (l >= (2*N15)) + l -= (2*N15); + pDst[k+8] = pSrc[l]; + pDst[k+9] = pSrc[l+1]; + l += 2; /* no modulo check needed, it cannot occur */ + } + } +} + +#define W_PiFOURTH STC(0x5a82799a) +#ifndef SUMDIFF_PIFOURTH +#define SUMDIFF_PIFOURTH(diff,sum,a,b) \ + { \ + FIXP_DBL wa, wb;\ + wa = fMultDiv2(a, W_PiFOURTH);\ + wb = fMultDiv2(b, W_PiFOURTH);\ + diff = wb - wa;\ + sum = wb + wa;\ + } +#endif + +/* This version is more overflow save, but less cycle optimal. */ +#define SUMDIFF_EIGTH(x, y, ix, iy, vr, vi, ur, ui) \ + vr = (x[ 0 + ix]>>1) + (x[16 + ix]>>1); /* Re A + Re B */ \ + vi = (x[ 8 + ix]>>1) + (x[24 + ix]>>1); /* Re C + Re D */ \ + ur = (x[ 1 + ix]>>1) + (x[17 + ix]>>1); /* Im A + Im B */ \ + ui = (x[ 9 + ix]>>1) + (x[25 + ix]>>1); /* Im C + Im D */ \ + y[ 0 + iy] = vr + vi; /* Re A' = ReA + ReB +ReC + ReD */ \ + y[ 4 + iy] = vr - vi; /* Re C' = -(ReC+ReD) + (ReA+ReB) */ \ + y[ 1 + iy] = ur + ui; /* Im A' = sum of imag values */ \ + y[ 5 + iy] = ur - ui; /* Im C' = -Im C -Im D +Im A +Im B */ \ + vr -= x[16 + ix]; /* Re A - Re B */ \ + vi = vi - x[24 + ix]; /* Re C - Re D */ \ + ur -= x[17 + ix]; /* Im A - Im B */ \ + ui = ui - x[25 + ix]; /* Im C - Im D */ \ + y[ 2 + iy] = ui + vr; /* Re B' = Im C - Im D + Re A - Re B */ \ + y[ 6 + iy] = vr - ui; /* Re D' = -Im C + Im D + Re A - Re B */ \ + y[ 3 + iy] = ur - vi; /* Im B'= -Re C + Re D + Im A - Im B */ \ + y[ 7 + iy] = vi + ur; /* Im D'= Re C - Re D + Im A - Im B */ + +static const FIXP_SPK fft16_w16[2] = { {{STC(0x7641af3d), STC(0x30fbc54d)}}, {{ STC(0x30fbc54d), STC(0x7641af3d)}} }; + +LNK_SECTION_CODE_L1 +inline void fft_16(FIXP_DBL *RESTRICT x) +{ + FIXP_DBL vr, vi, ur, ui; + FIXP_DBL y[32]; + + SUMDIFF_EIGTH(x, y, 0, 0, vr, vi, ur, ui); + SUMDIFF_EIGTH(x, y, 4, 8, vr, vi, ur, ui); + SUMDIFF_EIGTH(x, y, 2, 16, vr, vi, ur, ui); + SUMDIFF_EIGTH(x, y, 6, 24, vr, vi, ur, ui); + +// xt1 = 0 +// xt2 = 8 + vr = y[ 8]; + vi = y[ 9]; + ur = y[ 0]>>1; + ui = y[ 1]>>1; + x[ 0] = ur + (vr>>1); + x[ 1] = ui + (vi>>1); + x[ 8] = ur - (vr>>1); + x[ 9] = ui - (vi>>1); + +// xt1 = 4 +// xt2 = 12 + vr = y[13]; + vi = y[12]; + ur = y[ 4]>>1; + ui = y[ 5]>>1; + x[ 4] = ur + (vr>>1); + x[ 5] = ui - (vi>>1); + x[12] = ur - (vr>>1); + x[13] = ui + (vi>>1); + +// xt1 = 16 +// xt2 = 24 + vr = y[24]; + vi = y[25]; + ur = y[16]>>1; + ui = y[17]>>1; + x[16] = ur + (vr>>1); + x[17] = ui + (vi>>1); + x[24] = ur - (vr>>1); + x[25] = ui - (vi>>1); + +// xt1 = 20 +// xt2 = 28 + vr = y[29]; + vi = y[28]; + ur = y[20]>>1; + ui = y[21]>>1; + x[20] = ur + (vr>>1); + x[21] = ui - (vi>>1); + x[28] = ur - (vr>>1); + x[29] = ui + (vi>>1); + + // xt1 = 2 +// xt2 = 10 + SUMDIFF_PIFOURTH(vi, vr, y[10], y[11]) + //vr = fMultDiv2((y[11] + y[10]),W_PiFOURTH); + //vi = fMultDiv2((y[11] - y[10]),W_PiFOURTH); + ur = y[ 2]; + ui = y[ 3]; + x[ 2] = (ur>>1) + vr; + x[ 3] = (ui>>1) + vi; + x[10] = (ur>>1) - vr; + x[11] = (ui>>1) - vi; + +// xt1 = 6 +// xt2 = 14 + SUMDIFF_PIFOURTH(vr, vi, y[14], y[15]) + ur = y[ 6]; + ui = y[ 7]; + x[ 6] = (ur>>1) + vr; + x[ 7] = (ui>>1) - vi; + x[14] = (ur>>1) - vr; + x[15] = (ui>>1) + vi; + +// xt1 = 18 +// xt2 = 26 + SUMDIFF_PIFOURTH(vi, vr, y[26], y[27]) + ur = y[18]; + ui = y[19]; + x[18] = (ur>>1) + vr; + x[19] = (ui>>1) + vi; + x[26] = (ur>>1) - vr; + x[27] = (ui>>1) - vi; + +// xt1 = 22 +// xt2 = 30 + SUMDIFF_PIFOURTH(vr, vi, y[30], y[31]) + ur = y[22]; + ui = y[23]; + x[22] = (ur>>1) + vr; + x[23] = (ui>>1) - vi; + x[30] = (ur>>1) - vr; + x[31] = (ui>>1) + vi; + +// xt1 = 0 +// xt2 = 16 + vr = x[16]; + vi = x[17]; + ur = x[ 0]>>1; + ui = x[ 1]>>1; + x[ 0] = ur + (vr>>1); + x[ 1] = ui + (vi>>1); + x[16] = ur - (vr>>1); + x[17] = ui - (vi>>1); + +// xt1 = 8 +// xt2 = 24 + vi = x[24]; + vr = x[25]; + ur = x[ 8]>>1; + ui = x[ 9]>>1; + x[ 8] = ur + (vr>>1); + x[ 9] = ui - (vi>>1); + x[24] = ur - (vr>>1); + x[25] = ui + (vi>>1); + +// xt1 = 2 +// xt2 = 18 + cplxMultDiv2(&vi, &vr, x[19], x[18], fft16_w16[0]); + ur = x[ 2]; + ui = x[ 3]; + x[ 2] = (ur>>1) + vr; + x[ 3] = (ui>>1) + vi; + x[18] = (ur>>1) - vr; + x[19] = (ui>>1) - vi; + +// xt1 = 10 +// xt2 = 26 + cplxMultDiv2(&vr, &vi, x[27], x[26], fft16_w16[0]); + ur = x[10]; + ui = x[11]; + x[10] = (ur>>1) + vr; + x[11] = (ui>>1) - vi; + x[26] = (ur>>1) - vr; + x[27] = (ui>>1) + vi; + +// xt1 = 4 +// xt2 = 20 + SUMDIFF_PIFOURTH(vi, vr, x[20], x[21]) + ur = x[ 4]; + ui = x[ 5]; + x[ 4] = (ur>>1) + vr; + x[ 5] = (ui>>1) + vi; + x[20] = (ur>>1) - vr; + x[21] = (ui>>1) - vi; + +// xt1 = 12 +// xt2 = 28 + SUMDIFF_PIFOURTH(vr, vi, x[28], x[29]) + ur = x[12]; + ui = x[13]; + x[12] = (ur>>1) + vr; + x[13] = (ui>>1) - vi; + x[28] = (ur>>1) - vr; + x[29] = (ui>>1) + vi; + +// xt1 = 6 +// xt2 = 22 + cplxMultDiv2(&vi, &vr, x[23], x[22], fft16_w16[1]); + ur = x[ 6]; + ui = x[ 7]; + x[ 6] = (ur>>1) + vr; + x[ 7] = (ui>>1) + vi; + x[22] = (ur>>1) - vr; + x[23] = (ui>>1) - vi; + +// xt1 = 14 +// xt2 = 30 + cplxMultDiv2(&vr, &vi, x[31], x[30], fft16_w16[1]); + ur = x[14]; + ui = x[15]; + x[14] = (ur>>1) + vr; + x[15] = (ui>>1) - vi; + x[30] = (ur>>1) - vr; + x[31] = (ui>>1) + vi; +} + +#ifndef FUNCTION_fft_32 +static const FIXP_SPK fft32_w32[6] = +{ + {{ STC(0x7641af3d), STC(0x30fbc54d)}}, {{ STC(0x30fbc54d), STC(0x7641af3d)}}, {{ STC(0x7d8a5f40), STC(0x18f8b83c)}}, + {{ STC(0x6a6d98a4), STC(0x471cece7)}}, {{ STC(0x471cece7), STC(0x6a6d98a4)}}, {{ STC(0x18f8b83c), STC(0x7d8a5f40)}} +}; + +LNK_SECTION_CODE_L1 +inline void fft_32(FIXP_DBL *x) +{ + +#define W_PiFOURTH STC(0x5a82799a) + + FIXP_DBL vr,vi,ur,ui; + FIXP_DBL y[64]; + + /* + * 1+2 stage radix 4 + */ + +///////////////////////////////////////////////////////////////////////////////////////// + + // i = 0 + vr = (x[ 0] + x[32])>>1; /* Re A + Re B */ + vi = (x[16] + x[48]); /* Re C + Re D */ + ur = (x[ 1] + x[33])>>1; /* Im A + Im B */ + ui = (x[17] + x[49]); /* Im C + Im D */ + + y[ 0] = vr + (vi>>1); /* Re A' = ReA + ReB +ReC + ReD */ + y[ 4] = vr - (vi>>1); /* Re C' = -(ReC+ReD) + (ReA+ReB) */ + y[ 1] = ur + (ui>>1); /* Im A' = sum of imag values */ + y[ 5] = ur - (ui>>1); /* Im C' = -Im C -Im D +Im A +Im B */ + + vr -= x[32]; /* Re A - Re B */ + vi = (vi>>1) - x[48]; /* Re C - Re D */ + ur -= x[33]; /* Im A - Im B */ + ui = (ui>>1) - x[49]; /* Im C - Im D */ + + y[ 2] = ui + vr; /* Re B' = Im C - Im D + Re A - Re B */ + y[ 6] = vr - ui; /* Re D' = -Im C + Im D + Re A - Re B */ + y[ 3] = ur - vi; /* Im B'= -Re C + Re D + Im A - Im B */ + y[ 7] = vi + ur; /* Im D'= Re C - Re D + Im A - Im B */ + + //i=8 + vr = (x[ 8] + x[40])>>1; /* Re A + Re B */ + vi = (x[24] + x[56]); /* Re C + Re D */ + ur = (x[ 9] + x[41])>>1; /* Im A + Im B */ + ui = (x[25] + x[57]); /* Im C + Im D */ + + y[ 8] = vr + (vi>>1); /* Re A' = ReA + ReB +ReC + ReD */ + y[12] = vr - (vi>>1); /* Re C' = -(ReC+ReD) + (ReA+ReB) */ + y[ 9] = ur + (ui>>1); /* Im A' = sum of imag values */ + y[13] = ur - (ui>>1); /* Im C' = -Im C -Im D +Im A +Im B */ + + vr -= x[40]; /* Re A - Re B */ + vi = (vi>>1) - x[56]; /* Re C - Re D */ + ur -= x[41]; /* Im A - Im B */ + ui = (ui>>1) - x[57]; /* Im C - Im D */ + + y[10] = ui + vr; /* Re B' = Im C - Im D + Re A - Re B */ + y[14] = vr - ui; /* Re D' = -Im C + Im D + Re A - Re B */ + y[11] = ur - vi; /* Im B'= -Re C + Re D + Im A - Im B */ + y[15] = vi + ur; /* Im D'= Re C - Re D + Im A - Im B */ + + //i=16 + vr = (x[ 4] + x[36])>>1; /* Re A + Re B */ + vi = (x[20] + x[52]); /* Re C + Re D */ + ur = (x[ 5] + x[37])>>1; /* Im A + Im B */ + ui = (x[21] + x[53]); /* Im C + Im D */ + + y[16] = vr + (vi>>1); /* Re A' = ReA + ReB +ReC + ReD */ + y[20] = vr - (vi>>1); /* Re C' = -(ReC+ReD) + (ReA+ReB) */ + y[17] = ur + (ui>>1); /* Im A' = sum of imag values */ + y[21] = ur - (ui>>1); /* Im C' = -Im C -Im D +Im A +Im B */ + + vr -= x[36]; /* Re A - Re B */ + vi = (vi>>1) - x[52]; /* Re C - Re D */ + ur -= x[37]; /* Im A - Im B */ + ui = (ui>>1) - x[53]; /* Im C - Im D */ + + y[18] = ui + vr; /* Re B' = Im C - Im D + Re A - Re B */ + y[22] = vr - ui; /* Re D' = -Im C + Im D + Re A - Re B */ + y[19] = ur - vi; /* Im B'= -Re C + Re D + Im A - Im B */ + y[23] = vi + ur; /* Im D'= Re C - Re D + Im A - Im B */ + + //i=24 + vr = (x[12] + x[44])>>1; /* Re A + Re B */ + vi = (x[28] + x[60]); /* Re C + Re D */ + ur = (x[13] + x[45])>>1; /* Im A + Im B */ + ui = (x[29] + x[61]); /* Im C + Im D */ + + y[24] = vr + (vi>>1); /* Re A' = ReA + ReB +ReC + ReD */ + y[28] = vr - (vi>>1); /* Re C' = -(ReC+ReD) + (ReA+ReB) */ + y[25] = ur + (ui>>1); /* Im A' = sum of imag values */ + y[29] = ur - (ui>>1); /* Im C' = -Im C -Im D +Im A +Im B */ + + vr -= x[44]; /* Re A - Re B */ + vi = (vi>>1) - x[60]; /* Re C - Re D */ + ur -= x[45]; /* Im A - Im B */ + ui = (ui>>1) - x[61]; /* Im C - Im D */ + + y[26] = ui + vr; /* Re B' = Im C - Im D + Re A - Re B */ + y[30] = vr - ui; /* Re D' = -Im C + Im D + Re A - Re B */ + y[27] = ur - vi; /* Im B'= -Re C + Re D + Im A - Im B */ + y[31] = vi + ur; /* Im D'= Re C - Re D + Im A - Im B */ + + // i = 32 + vr = (x[ 2] + x[34])>>1; /* Re A + Re B */ + vi = (x[18] + x[50]); /* Re C + Re D */ + ur = (x[ 3] + x[35])>>1; /* Im A + Im B */ + ui = (x[19] + x[51]); /* Im C + Im D */ + + y[32] = vr + (vi>>1); /* Re A' = ReA + ReB +ReC + ReD */ + y[36] = vr - (vi>>1); /* Re C' = -(ReC+ReD) + (ReA+ReB) */ + y[33] = ur + (ui>>1); /* Im A' = sum of imag values */ + y[37] = ur - (ui>>1); /* Im C' = -Im C -Im D +Im A +Im B */ + + vr -= x[34]; /* Re A - Re B */ + vi = (vi>>1) - x[50]; /* Re C - Re D */ + ur -= x[35]; /* Im A - Im B */ + ui = (ui>>1) - x[51]; /* Im C - Im D */ + + y[34] = ui + vr; /* Re B' = Im C - Im D + Re A - Re B */ + y[38] = vr - ui; /* Re D' = -Im C + Im D + Re A - Re B */ + y[35] = ur - vi; /* Im B'= -Re C + Re D + Im A - Im B */ + y[39] = vi + ur; /* Im D'= Re C - Re D + Im A - Im B */ + + //i=40 + vr = (x[10] + x[42])>>1; /* Re A + Re B */ + vi = (x[26] + x[58]); /* Re C + Re D */ + ur = (x[11] + x[43])>>1; /* Im A + Im B */ + ui = (x[27] + x[59]); /* Im C + Im D */ + + y[40] = vr + (vi>>1); /* Re A' = ReA + ReB +ReC + ReD */ + y[44] = vr - (vi>>1); /* Re C' = -(ReC+ReD) + (ReA+ReB) */ + y[41] = ur + (ui>>1); /* Im A' = sum of imag values */ + y[45] = ur - (ui>>1); /* Im C' = -Im C -Im D +Im A +Im B */ + + vr -= x[42]; /* Re A - Re B */ + vi = (vi>>1) - x[58]; /* Re C - Re D */ + ur -= x[43]; /* Im A - Im B */ + ui = (ui>>1) - x[59]; /* Im C - Im D */ + + y[42] = ui + vr; /* Re B' = Im C - Im D + Re A - Re B */ + y[46] = vr - ui; /* Re D' = -Im C + Im D + Re A - Re B */ + y[43] = ur - vi; /* Im B'= -Re C + Re D + Im A - Im B */ + y[47] = vi + ur; /* Im D'= Re C - Re D + Im A - Im B */ + + //i=48 + vr = (x[ 6] + x[38])>>1; /* Re A + Re B */ + vi = (x[22] + x[54]); /* Re C + Re D */ + ur = (x[ 7] + x[39])>>1; /* Im A + Im B */ + ui = (x[23] + x[55]); /* Im C + Im D */ + + y[48] = vr + (vi>>1); /* Re A' = ReA + ReB +ReC + ReD */ + y[52] = vr - (vi>>1); /* Re C' = -(ReC+ReD) + (ReA+ReB) */ + y[49] = ur + (ui>>1); /* Im A' = sum of imag values */ + y[53] = ur - (ui>>1); /* Im C' = -Im C -Im D +Im A +Im B */ + + vr -= x[38]; /* Re A - Re B */ + vi = (vi>>1) - x[54]; /* Re C - Re D */ + ur -= x[39]; /* Im A - Im B */ + ui = (ui>>1) - x[55]; /* Im C - Im D */ + + y[50] = ui + vr; /* Re B' = Im C - Im D + Re A - Re B */ + y[54] = vr - ui; /* Re D' = -Im C + Im D + Re A - Re B */ + y[51] = ur - vi; /* Im B'= -Re C + Re D + Im A - Im B */ + y[55] = vi + ur; /* Im D'= Re C - Re D + Im A - Im B */ + + //i=56 + vr = (x[14] + x[46])>>1; /* Re A + Re B */ + vi = (x[30] + x[62]); /* Re C + Re D */ + ur = (x[15] + x[47])>>1; /* Im A + Im B */ + ui = (x[31] + x[63]); /* Im C + Im D */ + + y[56] = vr + (vi>>1); /* Re A' = ReA + ReB +ReC + ReD */ + y[60] = vr - (vi>>1); /* Re C' = -(ReC+ReD) + (ReA+ReB) */ + y[57] = ur + (ui>>1); /* Im A' = sum of imag values */ + y[61] = ur - (ui>>1); /* Im C' = -Im C -Im D +Im A +Im B */ + + vr -= x[46]; /* Re A - Re B */ + vi = (vi>>1) - x[62]; /* Re C - Re D */ + ur -= x[47]; /* Im A - Im B */ + ui = (ui>>1) - x[63]; /* Im C - Im D */ + + y[58] = ui + vr; /* Re B' = Im C - Im D + Re A - Re B */ + y[62] = vr - ui; /* Re D' = -Im C + Im D + Re A - Re B */ + y[59] = ur - vi; /* Im B'= -Re C + Re D + Im A - Im B */ + y[63] = vi + ur; /* Im D'= Re C - Re D + Im A - Im B */ + + + FIXP_DBL *xt = &x[0]; + FIXP_DBL *yt = &y[0]; + + int j = 4; + do + { + vr = yt[8]; + vi = yt[9]; + ur = yt[0]>>1; + ui = yt[1]>>1; + xt[ 0] = ur + (vr>>1); + xt[ 1] = ui + (vi>>1); + xt[ 8] = ur - (vr>>1); + xt[ 9] = ui - (vi>>1); + + vr = yt[13]; + vi = yt[12]; + ur = yt[4]>>1; + ui = yt[5]>>1; + xt[ 4] = ur + (vr>>1); + xt[ 5] = ui - (vi>>1); + xt[12] = ur - (vr>>1); + xt[13] = ui + (vi>>1); + + SUMDIFF_PIFOURTH(vi, vr, yt[10], yt[11]) + ur = yt[2]; + ui = yt[3]; + xt[ 2] = (ur>>1) + vr; + xt[ 3] = (ui>>1) + vi; + xt[10] = (ur>>1) - vr; + xt[11] = (ui>>1) - vi; + + SUMDIFF_PIFOURTH(vr, vi, yt[14], yt[15]) + ur = yt[6]; + ui = yt[7]; + + xt[ 6] = (ur>>1) + vr; + xt[ 7] = (ui>>1) - vi; + xt[14] = (ur>>1) - vr; + xt[15] = (ui>>1) + vi; + xt += 16; + yt += 16; + } while (--j != 0); + + vr = x[16]; + vi = x[17]; + ur = x[ 0]>>1; + ui = x[ 1]>>1; + x[ 0] = ur + (vr>>1); + x[ 1] = ui + (vi>>1); + x[16] = ur - (vr>>1); + x[17] = ui - (vi>>1); + + vi = x[24]; + vr = x[25]; + ur = x[ 8]>>1; + ui = x[ 9]>>1; + x[ 8] = ur + (vr>>1); + x[ 9] = ui - (vi>>1); + x[24] = ur - (vr>>1); + x[25] = ui + (vi>>1); + + vr = x[48]; + vi = x[49]; + ur = x[32]>>1; + ui = x[33]>>1; + x[32] = ur + (vr>>1); + x[33] = ui + (vi>>1); + x[48] = ur - (vr>>1); + x[49] = ui - (vi>>1); + + vi = x[56]; + vr = x[57]; + ur = x[40]>>1; + ui = x[41]>>1; + x[40] = ur + (vr>>1); + x[41] = ui - (vi>>1); + x[56] = ur - (vr>>1); + x[57] = ui + (vi>>1); + + cplxMultDiv2(&vi, &vr, x[19], x[18], fft32_w32[0]); + ur = x[ 2]; + ui = x[ 3]; + x[ 2] = (ur>>1) + vr; + x[ 3] = (ui>>1) + vi; + x[18] = (ur>>1) - vr; + x[19] = (ui>>1) - vi; + + cplxMultDiv2(&vr, &vi, x[27], x[26], fft32_w32[0]); + ur = x[10]; + ui = x[11]; + x[10] = (ur>>1) + vr; + x[11] = (ui>>1) - vi; + x[26] = (ur>>1) - vr; + x[27] = (ui>>1) + vi; + + cplxMultDiv2(&vi, &vr, x[51], x[50], fft32_w32[0]); + ur = x[34]; + ui = x[35]; + x[34] = (ur>>1) + vr; + x[35] = (ui>>1) + vi; + x[50] = (ur>>1) - vr; + x[51] = (ui>>1) - vi; + + cplxMultDiv2(&vr, &vi, x[59], x[58], fft32_w32[0]); + ur = x[42]; + ui = x[43]; + x[42] = (ur>>1) + vr; + x[43] = (ui>>1) - vi; + x[58] = (ur>>1) - vr; + x[59] = (ui>>1) + vi; + + SUMDIFF_PIFOURTH(vi, vr, x[20], x[21]) + ur = x[ 4]; + ui = x[ 5]; + x[ 4] = (ur>>1) + vr; + x[ 5] = (ui>>1) + vi; + x[20] = (ur>>1) - vr; + x[21] = (ui>>1) - vi; + + SUMDIFF_PIFOURTH(vr, vi, x[28], x[29]) + ur = x[12]; + ui = x[13]; + x[12] = (ur>>1) + vr; + x[13] = (ui>>1) - vi; + x[28] = (ur>>1) - vr; + x[29] = (ui>>1) + vi; + + SUMDIFF_PIFOURTH(vi, vr, x[52], x[53]) + ur = x[36]; + ui = x[37]; + x[36] = (ur>>1) + vr; + x[37] = (ui>>1) + vi; + x[52] = (ur>>1) - vr; + x[53] = (ui>>1) - vi; + + SUMDIFF_PIFOURTH(vr, vi, x[60], x[61]) + ur = x[44]; + ui = x[45]; + x[44] = (ur>>1) + vr; + x[45] = (ui>>1) - vi; + x[60] = (ur>>1) - vr; + x[61] = (ui>>1) + vi; + + + cplxMultDiv2(&vi, &vr, x[23], x[22], fft32_w32[1]); + ur = x[ 6]; + ui = x[ 7]; + x[ 6] = (ur>>1) + vr; + x[ 7] = (ui>>1) + vi; + x[22] = (ur>>1) - vr; + x[23] = (ui>>1) - vi; + + cplxMultDiv2(&vr, &vi, x[31], x[30], fft32_w32[1]); + ur = x[14]; + ui = x[15]; + x[14] = (ur>>1) + vr; + x[15] = (ui>>1) - vi; + x[30] = (ur>>1) - vr; + x[31] = (ui>>1) + vi; + + cplxMultDiv2(&vi, &vr, x[55], x[54], fft32_w32[1]); + ur = x[38]; + ui = x[39]; + x[38] = (ur>>1) + vr; + x[39] = (ui>>1) + vi; + x[54] = (ur>>1) - vr; + x[55] = (ui>>1) - vi; + + cplxMultDiv2(&vr, &vi, x[63], x[62], fft32_w32[1]); + ur = x[46]; + ui = x[47]; + + x[46] = (ur>>1) + vr; + x[47] = (ui>>1) - vi; + x[62] = (ur>>1) - vr; + x[63] = (ui>>1) + vi; + + vr = x[32]; + vi = x[33]; + ur = x[ 0]>>1; + ui = x[ 1]>>1; + x[ 0] = ur + (vr>>1); + x[ 1] = ui + (vi>>1); + x[32] = ur - (vr>>1); + x[33] = ui - (vi>>1); + + vi = x[48]; + vr = x[49]; + ur = x[16]>>1; + ui = x[17]>>1; + x[16] = ur + (vr>>1); + x[17] = ui - (vi>>1); + x[48] = ur - (vr>>1); + x[49] = ui + (vi>>1); + + cplxMultDiv2(&vi, &vr, x[35], x[34], fft32_w32[2]); + ur = x[ 2]; + ui = x[ 3]; + x[ 2] = (ur>>1) + vr; + x[ 3] = (ui>>1) + vi; + x[34] = (ur>>1) - vr; + x[35] = (ui>>1) - vi; + + cplxMultDiv2(&vr, &vi, x[51], x[50], fft32_w32[2]); + ur = x[18]; + ui = x[19]; + x[18] = (ur>>1) + vr; + x[19] = (ui>>1) - vi; + x[50] = (ur>>1) - vr; + x[51] = (ui>>1) + vi; + + cplxMultDiv2(&vi, &vr, x[37], x[36], fft32_w32[0]); + ur = x[ 4]; + ui = x[ 5]; + x[ 4] = (ur>>1) + vr; + x[ 5] = (ui>>1) + vi; + x[36] = (ur>>1) - vr; + x[37] = (ui>>1) - vi; + + cplxMultDiv2(&vr, &vi, x[53], x[52], fft32_w32[0]); + ur = x[20]; + ui = x[21]; + x[20] = (ur>>1) + vr; + x[21] = (ui>>1) - vi; + x[52] = (ur>>1) - vr; + x[53] = (ui>>1) + vi; + + cplxMultDiv2(&vi, &vr, x[39], x[38], fft32_w32[3]); + ur = x[ 6]; + ui = x[ 7]; + x[ 6] = (ur>>1) + vr; + x[ 7] = (ui>>1) + vi; + x[38] = (ur>>1) - vr; + x[39] = (ui>>1) - vi; + + cplxMultDiv2(&vr, &vi, x[55], x[54], fft32_w32[3]); + ur = x[22]; + ui = x[23]; + x[22] = (ur>>1) + vr; + x[23] = (ui>>1) - vi; + x[54] = (ur>>1) - vr; + x[55] = (ui>>1) + vi; + + SUMDIFF_PIFOURTH(vi, vr, x[40], x[41]) + ur = x[ 8]; + ui = x[ 9]; + x[ 8] = (ur>>1) + vr; + x[ 9] = (ui>>1) + vi; + x[40] = (ur>>1) - vr; + x[41] = (ui>>1) - vi; + + SUMDIFF_PIFOURTH(vr, vi, x[56], x[57]) + ur = x[24]; + ui = x[25]; + x[24] = (ur>>1) + vr; + x[25] = (ui>>1) - vi; + x[56] = (ur>>1) - vr; + x[57] = (ui>>1) + vi; + + cplxMultDiv2(&vi, &vr, x[43], x[42], fft32_w32[4]); + ur = x[10]; + ui = x[11]; + + x[10] = (ur>>1) + vr; + x[11] = (ui>>1) + vi; + x[42] = (ur>>1) - vr; + x[43] = (ui>>1) - vi; + + cplxMultDiv2(&vr, &vi, x[59], x[58], fft32_w32[4]); + ur = x[26]; + ui = x[27]; + x[26] = (ur>>1) + vr; + x[27] = (ui>>1) - vi; + x[58] = (ur>>1) - vr; + x[59] = (ui>>1) + vi; + + cplxMultDiv2(&vi, &vr, x[45], x[44], fft32_w32[1]); + ur = x[12]; + ui = x[13]; + x[12] = (ur>>1) + vr; + x[13] = (ui>>1) + vi; + x[44] = (ur>>1) - vr; + x[45] = (ui>>1) - vi; + + cplxMultDiv2(&vr, &vi, x[61], x[60], fft32_w32[1]); + ur = x[28]; + ui = x[29]; + x[28] = (ur>>1) + vr; + x[29] = (ui>>1) - vi; + x[60] = (ur>>1) - vr; + x[61] = (ui>>1) + vi; + + cplxMultDiv2(&vi, &vr, x[47], x[46], fft32_w32[5]); + ur = x[14]; + ui = x[15]; + x[14] = (ur>>1) + vr; + x[15] = (ui>>1) + vi; + x[46] = (ur>>1) - vr; + x[47] = (ui>>1) - vi; + + cplxMultDiv2(&vr, &vi, x[63], x[62], fft32_w32[5]); + ur = x[30]; + ui = x[31]; + x[30] = (ur>>1) + vr; + x[31] = (ui>>1) - vi; + x[62] = (ur>>1) - vr; + x[63] = (ui>>1) + vi; +} +#endif /* #ifndef FUNCTION_fft_32 */ + + +/** + * \brief Apply rotation vectors to a data buffer. + * \param cl length of each row of input data. + * \param l total length of input data. + * \param pVecRe real part of rotation ceofficient vector. + * \param pVecIm imaginary part of rotation ceofficient vector. + */ +static inline void fft_apply_rot_vector(FIXP_DBL *RESTRICT pData, const int cl, const int l, const FIXP_STB *pVecRe, const FIXP_STB *pVecIm) +{ + FIXP_DBL re, im; + FIXP_STB vre, vim; + + int i, c; + + for(i=0; i>2; /* * 0.25 */ + pData[2*i+1] = im>>2; /* * 0.25 */ + } + for(; i>2; /* * 0.25 */ + pData[2*i+1] = im>>2; /* * 0.25 */ + + for (c=i+1; c>1; + im = pData[2*c+1]>>1; + vre = *pVecRe++; + vim = *pVecIm++; + + cplxMultDiv2(&pData[2*c+1], &pData[2*c], im, re, vre, vim); + } + } +} + +#define FFT_TWO_STAGE_MACRO_ENABLE + + +#ifdef FFT_TWO_STAGE_MACRO_ENABLE + +#define fftN2(pInput, length, dim1, dim2, fft_func1, fft_func2, RotVectorReal, RotVectorImag) \ +{ \ + int i, j; \ + \ + C_ALLOC_SCRATCH_START(aDst, FIXP_DBL, length*2); \ + C_ALLOC_SCRATCH_START(aDst2, FIXP_DBL, dim2*2); \ + \ + FDK_ASSERT(length == dim1*dim2); \ + \ + /* Perform dim2 times the fft of length dim1. The input samples are at the address of pSrc and the \ + output samples are at the address of pDst. The input vector for the fft of length dim1 is built \ + of the interleaved samples in pSrc, the output samples are stored consecutively. \ + */ \ + { \ + const FIXP_DBL* pSrc = pInput; \ + FIXP_DBL *RESTRICT pDst = aDst; \ + \ + for(i=0; i>1; /* Re A + Re B */ + a10 = (x[i + 4] + x[i + 6])>>1; /* Re C + Re D */ + a20 = (x[i + 1] + x[i + 3])>>1; /* Im A + Im B */ + a30 = (x[i + 5] + x[i + 7])>>1; /* Im C + Im D */ + + x[i + 0] = a00 + a10; /* Re A' = Re A + Re B + Re C + Re D */ + x[i + 4] = a00 - a10; /* Re C' = Re A + Re B - Re C - Re D */ + x[i + 1] = a20 + a30; /* Im A' = Im A + Im B + Im C + Im D */ + x[i + 5] = a20 - a30; /* Im C' = Im A + Im B - Im C - Im D */ + + a00 = a00 - x[i + 2]; /* Re A - Re B */ + a10 = a10 - x[i + 6]; /* Re C - Re D */ + a20 = a20 - x[i + 3]; /* Im A - Im B */ + a30 = a30 - x[i + 7]; /* Im C - Im D */ + + x[i + 2] = a00 + a30; /* Re B' = Re A - Re B + Im C - Im D */ + x[i + 6] = a00 - a30; /* Re D' = Re A - Re B - Im C + Im D */ + x[i + 3] = a20 - a10; /* Im B' = Im A - Im B - Re C + Re D */ + x[i + 7] = a20 + a10; /* Im D' = Im A - Im B + Re C - Re D */ + } + + for(ldm=3; ldm<=ldn; ++ldm) + { + INT m=(1<>1); + INT j,r; + + trigstep=((trigDataSize << 2)>>ldm); + + FDK_ASSERT(trigstep > 0); + + /* Do first iteration with c=1.0 and s=0.0 separately to avoid loosing to much precision. + Beware: The impact on the overal FFT precision is rather large. */ + { + j = 0; + + for(r=0; r>1; + vr = x[t2]>>1; + + ur = x[t1]>>1; + ui = x[t1+1]>>1; + + x[t1] = ur+vr; + x[t1+1] = ui+vi; + + x[t2] = ur-vr; + x[t2+1] = ui-vi; + + t1 += mh; + t2 = t1+(mh<<1); + + //cplxMultDiv2(&vr, &vi, x[t2+1], x[t2], (FIXP_SGL)1.0, (FIXP_SGL)0.0); + vr = x[t2+1]>>1; + vi = x[t2]>>1; + + ur = x[t1]>>1; + ui = x[t1+1]>>1; + + x[t1] = ur+vr; + x[t1+1] = ui-vi; + + x[t2] = ur-vr; + x[t2+1] = ui+vi; + } + } + for(j=1; j>1; + ui = x[t1+1]>>1; + + x[t1] = ur+vr; + x[t1+1] = ui+vi; + + x[t2] = ur-vr; + x[t2+1] = ui-vi; + + t1 += mh; + t2 = t1+(mh<<1); + + cplxMultDiv2(&vr, &vi, x[t2+1], x[t2], cs); + + ur = x[t1]>>1; + ui = x[t1+1]>>1; + + x[t1] = ur+vr; + x[t1+1] = ui-vi; + + x[t2] = ur-vr; + x[t2+1] = ui+vi; + + /* Same as above but for t1,t2 with j>mh/4 and thus cs swapped */ + t1 = (r+mh/2-j)<<1; + t2 = t1 + (mh<<1); + + cplxMultDiv2(&vi, &vr, x[t2], x[t2+1], cs); + + ur = x[t1]>>1; + ui = x[t1+1]>>1; + + x[t1] = ur+vr; + x[t1+1] = ui-vi; + + x[t2] = ur-vr; + x[t2+1] = ui+vi; + + t1 += mh; + t2 = t1+(mh<<1); + + cplxMultDiv2(&vr, &vi, x[t2], x[t2+1], cs); + + ur = x[t1]>>1; + ui = x[t1+1]>>1; + + x[t1] = ur-vr; + x[t1+1] = ui-vi; + + x[t2] = ur+vr; + x[t2+1] = ui+vi; + } + } + { + j = mh/4; + + for(r=0; r>1; + ui = x[t1+1]>>1; + + x[t1] = ur+vr; + x[t1+1] = ui+vi; + + x[t2] = ur-vr; + x[t2+1] = ui-vi; + + t1 += mh; + t2 = t1+(mh<<1); + + cplxMultDiv2(&vr, &vi, x[t2+1], x[t2], STC(0x5a82799a), STC(0x5a82799a)); + + ur = x[t1]>>1; + ui = x[t1+1]>>1; + + x[t1] = ur+vr; + x[t1+1] = ui-vi; + + x[t2] = ur-vr; + x[t2+1] = ui+vi; + } + } + } +} +#endif + + +/***************************************************************************** + + functionname: dit_ifft (synthesis) + description: dit-tukey-algorithm + scrambles data at entry + i.e. loop is made with scrambled data + returns: + input: + output: + +*****************************************************************************/ + +#if !defined(FUNCTION_dit_ifft) +void dit_ifft(FIXP_DBL *x, const INT ldn, const FIXP_STP *trigdata, const INT trigDataSize) +{ + const INT n=1<>1; /* Re A + Re B */ + a10 = (x[i + 4] + x[i + 6])>>1; /* Re C + Re D */ + a20 = (x[i + 1] + x[i + 3])>>1; /* Im A + Im B */ + a30 = (x[i + 5] + x[i + 7])>>1; /* Im C + Im D */ + a0 = (x[i + 0] - x[i + 2])>>1; /* Re A - Re B */ + a2 = (x[i + 4] - x[i + 6])>>1; /* Re C - Re D */ + a3 = (x[i + 1] - x[i + 3])>>1; /* Im A - Im B */ + a1 = (x[i + 5] - x[i + 7])>>1; /* Im C - Im D */ + + x[i + 0] = a00 + a10; /* Re A' = Re A + Re B + Re C + Re D */ + x[i + 4] = a00 - a10; /* Re C' = Re A + Re B - Re C - Re D */ + x[i + 1] = a20 + a30; /* Im A' = Im A + Im B + Im C + Im D */ + x[i + 5] = a20 - a30; /* Im C' = Im A + Im B - Im C - Im D */ + x[i + 2] = a0 - a1; /* Re B' = Re A - Re B - Im C + Im D */ + x[i + 6] = a0 + a1; /* Re D' = Re A - Re B + Im C - Im D */ + x[i + 3] = a3 + a2; /* Im B' = Im A - Im B + Re C - Re D */ + x[i + 7] = a3 - a2; /* Im D' = Im A - Im B - Re C + Re D */ + } + + for(ldm=3; ldm<=ldn; ++ldm) + { + const INT m=(1<>1); + + INT j,r; + + trigstep=((trigDataSize << 2)>>ldm); + + { + j = 0; + + for(r=0; r>1; + vr = x[t2]>>1; + + ur = x[t1]>>1; + ui = x[t1+1]>>1; + + x[t1] = ur+vr; + x[t1+1] = ui+vi; + + x[t2] = ur-vr; + x[t2+1] = ui-vi; + + t1 += mh; + t2 = t1+(mh<<1); + + //cplxMultDiv2(&vi, &vr, x[t2], x[t2+1], FL2FXCONST_SGL(1.0), FL2FXCONST_SGL(0.0)); + vr = x[t2+1]>>1; + vi = x[t2]>>1; + + ur = x[t1]>>1; + ui = x[t1+1]>>1; + + x[t1] = ur-vr; + x[t1+1] = ui+vi; + + x[t2] = ur+vr; + x[t2+1] = ui-vi; + } + } + for(j=1; j>1; + ui = x[t1+1]>>1; + + x[t1] = ur+vr; + x[t1+1] = ui+vi; + + x[t2] = ur-vr; + x[t2+1] = ui-vi; + + t1 += mh; + t2 = t1+(mh<<1); + + cplxMultDiv2(&vi, &vr, x[t2], x[t2+1], cs); + + ur = x[t1]>>1; + ui = x[t1+1]>>1; + + x[t1] = ur-vr; + x[t1+1] = ui+vi; + + x[t2] = ur+vr; + x[t2+1] = ui-vi; + + /* Same as above but for t1,t2 with j>mh/4 and thus cs swapped */ + t1 = (r+mh/2-j)<<1; + t2 = t1 + (mh<<1); + + cplxMultDiv2(&vr, &vi, x[t2+1], x[t2], cs); + + ur = x[t1]>>1; + ui = x[t1+1]>>1; + + x[t1] = ur-vr; + x[t1+1] = ui+vi; + + x[t2] = ur+vr; + x[t2+1] = ui-vi; + + t1 += mh; + t2 = t1+(mh<<1); + + cplxMultDiv2(&vi, &vr, x[t2+1], x[t2], cs); + + ur = x[t1]>>1; + ui = x[t1+1]>>1; + + x[t1] = ur-vr; + x[t1+1] = ui-vi; + + x[t2] = ur+vr; + x[t2+1] = ui+vi; + } + } + { + j = mh/4; + for(r=0; r>1; + ui = x[t1+1]>>1; + + x[t1] = ur+vr; + x[t1+1] = ui+vi; + + x[t2] = ur-vr; + x[t2+1] = ui-vi; + + t1 += mh; + t2 = t1+(mh<<1); + + cplxMultDiv2(&vi, &vr, x[t2], x[t2+1], STC(0x5a82799a), STC(0x5a82799a)); + + ur = x[t1]>>1; + ui = x[t1+1]>>1; + + x[t1] = ur-vr; + x[t1+1] = ui+vi; + + x[t2] = ur+vr; + x[t2+1] = ui-vi; + } + } + } +} +#endif + diff --git a/libFDK/src/fixpoint_math.cpp b/libFDK/src/fixpoint_math.cpp new file mode 100644 index 0000000..45b3023 --- /dev/null +++ b/libFDK/src/fixpoint_math.cpp @@ -0,0 +1,1164 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): M. Gayer + Description: Fixed point specific mathematical functions + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "fixpoint_math.h" + + +#define MAX_LD_PRECISION 10 +#define LD_PRECISION 10 + +/* Taylor series coeffcients for ln(1-x), centered at 0 (MacLaurin polinomial). */ +#ifndef LDCOEFF_16BIT +LNK_SECTION_CONSTDATA_L1 +static const FIXP_DBL ldCoeff[MAX_LD_PRECISION] = { + FL2FXCONST_DBL(-1.0), + FL2FXCONST_DBL(-1.0/2.0), + FL2FXCONST_DBL(-1.0/3.0), + FL2FXCONST_DBL(-1.0/4.0), + FL2FXCONST_DBL(-1.0/5.0), + FL2FXCONST_DBL(-1.0/6.0), + FL2FXCONST_DBL(-1.0/7.0), + FL2FXCONST_DBL(-1.0/8.0), + FL2FXCONST_DBL(-1.0/9.0), + FL2FXCONST_DBL(-1.0/10.0) +}; +#else +LNK_SECTION_CONSTDATA_L1 +static const FIXP_SGL ldCoeff[MAX_LD_PRECISION] = { + FL2FXCONST_SGL(-1.0), + FL2FXCONST_SGL(-1.0/2.0), + FL2FXCONST_SGL(-1.0/3.0), + FL2FXCONST_SGL(-1.0/4.0), + FL2FXCONST_SGL(-1.0/5.0), + FL2FXCONST_SGL(-1.0/6.0), + FL2FXCONST_SGL(-1.0/7.0), + FL2FXCONST_SGL(-1.0/8.0), + FL2FXCONST_SGL(-1.0/9.0), + FL2FXCONST_SGL(-1.0/10.0) +}; +#endif + +/***************************************************************************** + + functionname: CalcLdData + description: Delivers the Logarithm Dualis ld(op)/LD_DATA_SCALING with polynomial approximation. + input: Input op is assumed to be double precision fractional 0 < op < 1.0 + This function does not accept negative values. + output: For op == 0, the result is saturated to -1.0 + This function does not return positive values since input values are treated as fractional values. + It does not make sense to input an integer value into this function (and expect a positive output value) + since input values are treated as fractional values. + +*****************************************************************************/ + +LNK_SECTION_CODE_L1 +FIXP_DBL CalcLdData(FIXP_DBL op) +{ + return fLog2(op, 0); +} + + +/***************************************************************************** + functionname: LdDataVector +*****************************************************************************/ +LNK_SECTION_CODE_L1 +void LdDataVector( FIXP_DBL *srcVector, + FIXP_DBL *destVector, + INT n) +{ + INT i; + for ( i=0; i>FRACT_BITS); */ +//LNK_SECTION_CONSTDATA +//static const LONG accu_r = 0x00008000; +#define ACCU_R (LONG) 0x00008000 + +LNK_SECTION_CODE_L1 +FIXP_DBL mul_dbl_sgl_rnd (const FIXP_DBL op1, const FIXP_SGL op2) +{ + FIXP_DBL prod; + LONG v = (LONG)(op1); + SHORT u = (SHORT)(op2); + + LONG low = u*(v&SGL_MASK); + low = (low+(ACCU_R>>1)) >> (FRACT_BITS-1); /* round */ + LONG high = u * ((v>>FRACT_BITS)<<1); + + prod = (LONG)(high+low); + + return((FIXP_DBL)prod); +} + + +/***************************************************************************** + + functionname: CalcInvLdData + description: Delivers the inverse of function CalcLdData(). + Delivers 2^(op*LD_DATA_SCALING) + input: Input op is assumed to be fractional -1.0 < op < 1.0 + output: For op == 0, the result is MAXVAL_DBL (almost 1.0). + For negative input values the output should be treated as a positive fractional value. + For positive input values the output should be treated as a positive integer value. + This function does not output negative values. + +*****************************************************************************/ +LNK_SECTION_CODE_L1 +FIXP_DBL CalcInvLdData(FIXP_DBL op) +{ + FIXP_DBL result_m; + + if ( op == FL2FXCONST_DBL(0.0f) ) { + result_m = (FIXP_DBL)MAXVAL_DBL; + } + else if ( op < FL2FXCONST_DBL(0.0f) ) { + result_m = f2Pow(op, LD_DATA_SHIFT); + } + else { + int result_e; + + result_m = f2Pow(op, LD_DATA_SHIFT, &result_e); + result_e = fixMin(fixMax(result_e+1-(DFRACT_BITS-1), -(DFRACT_BITS-1)), (DFRACT_BITS-1)); /* rounding and saturation */ + + if ( (result_e>0) && ( result_m > (((FIXP_DBL)MAXVAL_DBL)>>result_e) ) ) { + result_m = (FIXP_DBL)MAXVAL_DBL; /* saturate to max representable value */ + } + else { + result_m = (scaleValue(result_m, result_e)+(FIXP_DBL)1)>>1; /* descale result + rounding */ + } + } + return result_m; +} + + + + + +/***************************************************************************** + functionname: InitLdInt and CalcLdInt + description: Create and access table with integer LdData (0 to 193) +*****************************************************************************/ + + + LNK_SECTION_CONSTDATA_L1 + static const FIXP_DBL ldIntCoeff[] = { + 0x80000001, 0x00000000, 0x02000000, 0x032b8034, 0x04000000, 0x04a4d3c2, 0x052b8034, 0x059d5da0, + 0x06000000, 0x06570069, 0x06a4d3c2, 0x06eb3a9f, 0x072b8034, 0x0766a009, 0x079d5da0, 0x07d053f7, + 0x08000000, 0x082cc7ee, 0x08570069, 0x087ef05b, 0x08a4d3c2, 0x08c8ddd4, 0x08eb3a9f, 0x090c1050, + 0x092b8034, 0x0949a785, 0x0966a009, 0x0982809d, 0x099d5da0, 0x09b74949, 0x09d053f7, 0x09e88c6b, + 0x0a000000, 0x0a16bad3, 0x0a2cc7ee, 0x0a423162, 0x0a570069, 0x0a6b3d79, 0x0a7ef05b, 0x0a92203d, + 0x0aa4d3c2, 0x0ab7110e, 0x0ac8ddd4, 0x0ada3f60, 0x0aeb3a9f, 0x0afbd42b, 0x0b0c1050, 0x0b1bf312, + 0x0b2b8034, 0x0b3abb40, 0x0b49a785, 0x0b584822, 0x0b66a009, 0x0b74b1fd, 0x0b82809d, 0x0b900e61, + 0x0b9d5da0, 0x0baa708f, 0x0bb74949, 0x0bc3e9ca, 0x0bd053f7, 0x0bdc899b, 0x0be88c6b, 0x0bf45e09, + 0x0c000000, 0x0c0b73cb, 0x0c16bad3, 0x0c21d671, 0x0c2cc7ee, 0x0c379085, 0x0c423162, 0x0c4caba8, + 0x0c570069, 0x0c6130af, 0x0c6b3d79, 0x0c7527b9, 0x0c7ef05b, 0x0c88983f, 0x0c92203d, 0x0c9b8926, + 0x0ca4d3c2, 0x0cae00d2, 0x0cb7110e, 0x0cc0052b, 0x0cc8ddd4, 0x0cd19bb0, 0x0cda3f60, 0x0ce2c97d, + 0x0ceb3a9f, 0x0cf39355, 0x0cfbd42b, 0x0d03fda9, 0x0d0c1050, 0x0d140ca0, 0x0d1bf312, 0x0d23c41d, + 0x0d2b8034, 0x0d3327c7, 0x0d3abb40, 0x0d423b08, 0x0d49a785, 0x0d510118, 0x0d584822, 0x0d5f7cff, + 0x0d66a009, 0x0d6db197, 0x0d74b1fd, 0x0d7ba190, 0x0d82809d, 0x0d894f75, 0x0d900e61, 0x0d96bdad, + 0x0d9d5da0, 0x0da3ee7f, 0x0daa708f, 0x0db0e412, 0x0db74949, 0x0dbda072, 0x0dc3e9ca, 0x0dca258e, + 0x0dd053f7, 0x0dd6753e, 0x0ddc899b, 0x0de29143, 0x0de88c6b, 0x0dee7b47, 0x0df45e09, 0x0dfa34e1, + 0x0e000000, 0x0e05bf94, 0x0e0b73cb, 0x0e111cd2, 0x0e16bad3, 0x0e1c4dfb, 0x0e21d671, 0x0e275460, + 0x0e2cc7ee, 0x0e323143, 0x0e379085, 0x0e3ce5d8, 0x0e423162, 0x0e477346, 0x0e4caba8, 0x0e51daa8, + 0x0e570069, 0x0e5c1d0b, 0x0e6130af, 0x0e663b74, 0x0e6b3d79, 0x0e7036db, 0x0e7527b9, 0x0e7a1030, + 0x0e7ef05b, 0x0e83c857, 0x0e88983f, 0x0e8d602e, 0x0e92203d, 0x0e96d888, 0x0e9b8926, 0x0ea03232, + 0x0ea4d3c2, 0x0ea96df0, 0x0eae00d2, 0x0eb28c7f, 0x0eb7110e, 0x0ebb8e96, 0x0ec0052b, 0x0ec474e4, + 0x0ec8ddd4, 0x0ecd4012, 0x0ed19bb0, 0x0ed5f0c4, 0x0eda3f60, 0x0ede8797, 0x0ee2c97d, 0x0ee70525, + 0x0eeb3a9f, 0x0eef69ff, 0x0ef39355, 0x0ef7b6b4, 0x0efbd42b, 0x0effebcd, 0x0f03fda9, 0x0f0809cf, + 0x0f0c1050, 0x0f10113b, 0x0f140ca0, 0x0f18028d, 0x0f1bf312, 0x0f1fde3d, 0x0f23c41d, 0x0f27a4c0, + 0x0f2b8034 + }; + + + LNK_SECTION_INITCODE + void InitLdInt() + { + /* nothing to do! Use preinitialized logarithm table */ + } + + + +LNK_SECTION_CODE_L1 +FIXP_DBL CalcLdInt(INT i) +{ + /* calculates ld(op)/LD_DATA_SCALING */ + /* op is assumed to be an integer value between 1 and 193 */ + + FDK_ASSERT((193>0) && ((FIXP_DBL)ldIntCoeff[0]==(FIXP_DBL)0x80000001)); /* tab has to be initialized */ + + if ((i>0)&&(i<193)) + return ldIntCoeff[i]; + else + { + return (0); + } +} + + +/***************************************************************************** + + functionname: invSqrtNorm2 + description: delivers 1/sqrt(op) normalized to .5...1 and the shift value of the OUTPUT + +*****************************************************************************/ +#define SQRT_BITS 7 +#define SQRT_VALUES 128 +#define SQRT_BITS_MASK 0x7f + +LNK_SECTION_CONSTDATA_L1 +static const FIXP_DBL invSqrtTab[SQRT_VALUES] = { + 0x5a827999, 0x5a287e03, 0x59cf8cbb, 0x5977a0ab, 0x5920b4de, 0x58cac480, 0x5875cade, 0x5821c364, + 0x57cea99c, 0x577c792f, 0x572b2ddf, 0x56dac38d, 0x568b3631, 0x563c81df, 0x55eea2c3, 0x55a19521, + 0x55555555, 0x5509dfd0, 0x54bf311a, 0x547545d0, 0x542c1aa3, 0x53e3ac5a, 0x539bf7cc, 0x5354f9e6, + 0x530eafa4, 0x52c91617, 0x52842a5e, 0x523fe9ab, 0x51fc513f, 0x51b95e6b, 0x51770e8e, 0x51355f19, + 0x50f44d88, 0x50b3d768, 0x5073fa4f, 0x5034b3e6, 0x4ff601df, 0x4fb7e1f9, 0x4f7a5201, 0x4f3d4fce, + 0x4f00d943, 0x4ec4ec4e, 0x4e8986e9, 0x4e4ea718, 0x4e144ae8, 0x4dda7072, 0x4da115d9, 0x4d683948, + 0x4d2fd8f4, 0x4cf7f31b, 0x4cc08604, 0x4c898fff, 0x4c530f64, 0x4c1d0293, 0x4be767f5, 0x4bb23df9, + 0x4b7d8317, 0x4b4935ce, 0x4b1554a6, 0x4ae1de2a, 0x4aaed0f0, 0x4a7c2b92, 0x4a49ecb3, 0x4a1812fa, + 0x49e69d16, 0x49b589bb, 0x4984d7a4, 0x49548591, 0x49249249, 0x48f4fc96, 0x48c5c34a, 0x4896e53c, + 0x48686147, 0x483a364c, 0x480c6331, 0x47dee6e0, 0x47b1c049, 0x4784ee5f, 0x4758701c, 0x472c447c, + 0x47006a80, 0x46d4e130, 0x46a9a793, 0x467ebcb9, 0x46541fb3, 0x4629cf98, 0x45ffcb80, 0x45d61289, + 0x45aca3d5, 0x45837e88, 0x455aa1ca, 0x45320cc8, 0x4509beb0, 0x44e1b6b4, 0x44b9f40b, 0x449275ec, + 0x446b3b95, 0x44444444, 0x441d8f3b, 0x43f71bbe, 0x43d0e917, 0x43aaf68e, 0x43854373, 0x435fcf14, + 0x433a98c5, 0x43159fdb, 0x42f0e3ae, 0x42cc6397, 0x42a81ef5, 0x42841527, 0x4260458d, 0x423caf8c, + 0x4219528b, 0x41f62df1, 0x41d3412a, 0x41b08ba1, 0x418e0cc7, 0x416bc40d, 0x4149b0e4, 0x4127d2c3, + 0x41062920, 0x40e4b374, 0x40c3713a, 0x40a261ef, 0x40818511, 0x4060da21, 0x404060a1, 0x40201814 +}; + +LNK_SECTION_INITCODE +void InitInvSqrtTab() +{ + /* nothing to do ! + use preinitialized square root table + */ +} + + + +#if !defined(FUNCTION_invSqrtNorm2) +/***************************************************************************** + delivers 1/sqrt(op) normalized to .5...1 and the shift value of the OUTPUT, + i.e. the denormalized result is 1/sqrt(op) = invSqrtNorm(op) * 2^(shift) + uses Newton-iteration for approximation + Q(n+1) = Q(n) + Q(n) * (0.5 - 2 * V * Q(n)^2) + with Q = 0.5* V ^-0.5; 0.5 <= V < 1.0 +*****************************************************************************/ +FIXP_DBL invSqrtNorm2(FIXP_DBL op, INT *shift) +{ + + FIXP_DBL val = op ; + FIXP_DBL reg1, reg2, regtmp ; + + if (val == FL2FXCONST_DBL(0.0)) { + *shift = 1 ; + return((LONG)1); /* minimum positive value */ + } + + + /* normalize input, calculate shift value */ + FDK_ASSERT(val > FL2FXCONST_DBL(0.0)); + *shift = fNormz(val) - 1; /* CountLeadingBits() is not necessary here since test value is always > 0 */ + val <<=*shift ; /* normalized input V */ + *shift+=2 ; /* bias for exponent */ + + /* Newton iteration of 1/sqrt(V) */ + reg1 = invSqrtTab[ (INT)(val>>(DFRACT_BITS-1-(SQRT_BITS+1))) & SQRT_BITS_MASK ]; + reg2 = FL2FXCONST_DBL(0.0625f); /* 0.5 >> 3 */ + + regtmp= fPow2Div2(reg1); /* a = Q^2 */ + regtmp= reg2 - fMultDiv2(regtmp, val); /* b = 0.5 - 2 * V * Q^2 */ + reg1 += (fMultDiv2(regtmp, reg1)<<4); /* Q = Q + Q*b */ + + /* calculate the output exponent = input exp/2 */ + if (*shift & 0x00000001) { /* odd shift values ? */ + reg2 = FL2FXCONST_DBL(0.707106781186547524400844362104849f); /* 1/sqrt(2); */ + reg1 = fMultDiv2(reg1, reg2) << 2; + } + + *shift = *shift>>1; + + return(reg1); +} +#endif /* !defined(FUNCTION_invSqrtNorm2) */ + +/***************************************************************************** + + functionname: sqrtFixp + description: delivers sqrt(op) + +*****************************************************************************/ +FIXP_DBL sqrtFixp(FIXP_DBL op) +{ + INT tmp_exp = 0; + FIXP_DBL tmp_inv = invSqrtNorm2(op, &tmp_exp); + + FDK_ASSERT(tmp_exp > 0) ; + return( (FIXP_DBL) ( fMultDiv2( (op<<(tmp_exp-1)), tmp_inv ) << 2 )); +} + + +#if !defined(FUNCTION_schur_div) +/***************************************************************************** + + functionname: schur_div + description: delivers op1/op2 with op3-bit accuracy + +*****************************************************************************/ + + +FIXP_DBL schur_div(FIXP_DBL num, FIXP_DBL denum, INT count) +{ + INT L_num = (LONG)num>>1; + INT L_denum = (LONG)denum>>1; + INT div = 0; + INT k = count; + + FDK_ASSERT (num>=(FIXP_DBL)0); + FDK_ASSERT (denum>(FIXP_DBL)0); + FDK_ASSERT (num <= denum); + + if (L_num != 0) + while (--k) + { + div <<= 1; + L_num <<= 1; + if (L_num >= L_denum) + { + L_num -= L_denum; + div++; + } + } + return (FIXP_DBL)(div << (DFRACT_BITS - count)); +} + + +#endif /* !defined(FUNCTION_schur_div) */ + + +#ifndef FUNCTION_fMultNorm +FIXP_DBL fMultNorm(FIXP_DBL f1, FIXP_DBL f2, INT *result_e) +{ + INT product = 0; + INT norm_f1, norm_f2; + + if ( (f1 == (FIXP_DBL)0) || (f2 == (FIXP_DBL)0) ) { + *result_e = 0; + return (FIXP_DBL)0; + } + norm_f1 = CountLeadingBits(f1); + f1 = f1 << norm_f1; + norm_f2 = CountLeadingBits(f2); + f2 = f2 << norm_f2; + + product = fMult(f1, f2); + *result_e = - (norm_f1 + norm_f2); + + return (FIXP_DBL)product; +} +#endif + +#ifndef FUNCTION_fDivNorm +FIXP_DBL fDivNorm(FIXP_DBL L_num, FIXP_DBL L_denum, INT *result_e) +{ + FIXP_DBL div; + INT norm_num, norm_den; + + FDK_ASSERT (L_num >= (FIXP_DBL)0); + FDK_ASSERT (L_denum > (FIXP_DBL)0); + + if(L_num == (FIXP_DBL)0) + { + *result_e = 0; + return ((FIXP_DBL)0); + } + + norm_num = CountLeadingBits(L_num); + L_num = L_num << norm_num; + L_num = L_num >> 1; + *result_e = - norm_num + 1; + + norm_den = CountLeadingBits(L_denum); + L_denum = L_denum << norm_den; + *result_e -= - norm_den; + + div = schur_div(L_num, L_denum, FRACT_BITS); + + return div; +} +#endif /* !FUNCTION_fDivNorm */ + +#ifndef FUNCTION_fDivNorm +FIXP_DBL fDivNorm(FIXP_DBL num, FIXP_DBL denom) +{ + INT e; + FIXP_DBL res; + + FDK_ASSERT (denom >= num); + + res = fDivNorm(num, denom, &e); + + /* Avoid overflow since we must output a value with exponent 0 + there is no other choice than saturating to almost 1.0f */ + if(res == (FIXP_DBL)(1<<(DFRACT_BITS-2)) && e == 1) + { + res = (FIXP_DBL)MAXVAL_DBL; + } + else + { + res = scaleValue(res, e); + } + + return res; +} +#endif /* !FUNCTION_fDivNorm */ + +#ifndef FUNCTION_fDivNormHighPrec +FIXP_DBL fDivNormHighPrec(FIXP_DBL num, FIXP_DBL denom, INT *result_e) +{ + FIXP_DBL div; + INT norm_num, norm_den; + + FDK_ASSERT (num >= (FIXP_DBL)0); + FDK_ASSERT (denom > (FIXP_DBL)0); + + if(num == (FIXP_DBL)0) + { + *result_e = 0; + return ((FIXP_DBL)0); + } + + norm_num = CountLeadingBits(num); + num = num << norm_num; + num = num >> 1; + *result_e = - norm_num + 1; + + norm_den = CountLeadingBits(denom); + denom = denom << norm_den; + *result_e -= - norm_den; + + div = schur_div(num, denom, 31); + return div; +} +#endif /* !FUNCTION_fDivNormHighPrec */ + + + +FIXP_DBL CalcLog2(FIXP_DBL base_m, INT base_e, INT *result_e) +{ + return fLog2(base_m, base_e, result_e); +} + +FIXP_DBL f2Pow( + const FIXP_DBL exp_m, const INT exp_e, + INT *result_e + ) +{ + FIXP_DBL frac_part, result_m; + INT int_part; + + if (exp_e > 0) + { + INT exp_bits = DFRACT_BITS-1 - exp_e; + int_part = exp_m >> exp_bits; + frac_part = exp_m - (FIXP_DBL)(int_part << exp_bits); + frac_part = frac_part << exp_e; + } + else + { + int_part = 0; + frac_part = exp_m >> -exp_e; + } + + /* Best accuracy is around 0, so try to get there with the fractional part. */ + if( frac_part > FL2FXCONST_DBL(0.5f) ) + { + int_part = int_part + 1; + frac_part = frac_part + FL2FXCONST_DBL(-1.0f); + } + if( frac_part < FL2FXCONST_DBL(-0.5f) ) + { + int_part = int_part - 1; + frac_part = -(FL2FXCONST_DBL(-1.0f) - frac_part); + } + + /* Evaluate taylor polynomial which approximates 2^x */ + { + FIXP_DBL p; + + /* result_m ~= 2^frac_part */ + p = frac_part; + /* First taylor series coefficient a_0 = 1.0, scaled by 0.5 due to fMultDiv2(). */ + result_m = FL2FXCONST_DBL(1.0f/2.0f); + for (INT i = 0; i < POW2_PRECISION; i++) { + /* next taylor series term: a_i * x^i, x=0 */ + result_m = fMultAddDiv2(result_m, pow2Coeff[i], p); + p = fMult(p, frac_part); + } + } + + /* "+ 1" compensates fMultAddDiv2() of the polynomial evaluation above. */ + *result_e = int_part + 1; + + return result_m; +} + +FIXP_DBL f2Pow( + const FIXP_DBL exp_m, const INT exp_e + ) +{ + FIXP_DBL result_m; + INT result_e; + + result_m = f2Pow(exp_m, exp_e, &result_e); + result_e = fixMin(DFRACT_BITS-1,fixMax(-(DFRACT_BITS-1),result_e)); + + return scaleValue(result_m, result_e); +} + +FIXP_DBL fPow( + FIXP_DBL base_m, INT base_e, + FIXP_DBL exp_m, INT exp_e, + INT *result_e + ) +{ + INT ans_lg2_e, baselg2_e; + FIXP_DBL base_lg2, ans_lg2, result; + + /* Calc log2 of base */ + base_lg2 = fLog2(base_m, base_e, &baselg2_e); + + /* Prepare exp */ + { + INT leadingBits; + + leadingBits = CountLeadingBits(fAbs(exp_m)); + exp_m = exp_m << leadingBits; + exp_e -= leadingBits; + } + + /* Calc base pow exp */ + ans_lg2 = fMult(base_lg2, exp_m); + ans_lg2_e = exp_e + baselg2_e; + + /* Calc antilog */ + result = f2Pow(ans_lg2, ans_lg2_e, result_e); + + return result; +} + +FIXP_DBL fLdPow( + FIXP_DBL baseLd_m, + INT baseLd_e, + FIXP_DBL exp_m, INT exp_e, + INT *result_e + ) +{ + INT ans_lg2_e; + FIXP_DBL ans_lg2, result; + + /* Prepare exp */ + { + INT leadingBits; + + leadingBits = CountLeadingBits(fAbs(exp_m)); + exp_m = exp_m << leadingBits; + exp_e -= leadingBits; + } + + /* Calc base pow exp */ + ans_lg2 = fMult(baseLd_m, exp_m); + ans_lg2_e = exp_e + baseLd_e; + + /* Calc antilog */ + result = f2Pow(ans_lg2, ans_lg2_e, result_e); + + return result; +} + +FIXP_DBL fLdPow( + FIXP_DBL baseLd_m, INT baseLd_e, + FIXP_DBL exp_m, INT exp_e + ) +{ + FIXP_DBL result_m; + int result_e; + + result_m = fLdPow(baseLd_m, baseLd_e, exp_m, exp_e, &result_e); + + return SATURATE_SHIFT(result_m, -result_e, DFRACT_BITS); +} + +FIXP_DBL fPowInt( + FIXP_DBL base_m, INT base_e, + INT exp, + INT *pResult_e + ) +{ + FIXP_DBL result; + + if (exp != 0) { + INT result_e = 0; + + if (base_m != (FIXP_DBL)0) { + { + INT leadingBits; + leadingBits = CountLeadingBits( base_m ); + base_m <<= leadingBits; + base_e -= leadingBits; + } + + result = base_m; + + { + int i; + for (i = 1; i < fAbs(exp); i++) { + result = fMult(result, base_m); + } + } + + if (exp < 0) { + /* 1.0 / ans */ + result = fDivNorm( FL2FXCONST_DBL(0.5f), result, &result_e ); + result_e++; + } else { + int ansScale = CountLeadingBits( result ); + result <<= ansScale; + result_e -= ansScale; + } + + result_e += exp * base_e; + + } else { + result = (FIXP_DBL)0; + } + *pResult_e = result_e; + } + else { + result = FL2FXCONST_DBL(0.5f); + *pResult_e = 1; + } + + return result; +} + +FIXP_DBL fLog2(FIXP_DBL x_m, INT x_e, INT *result_e) +{ + FIXP_DBL result_m; + + /* Short cut for zero and negative numbers. */ + if ( x_m <= FL2FXCONST_DBL(0.0f) ) { + *result_e = DFRACT_BITS-1; + return FL2FXCONST_DBL(-1.0f); + } + + /* Calculate log2() */ + { + FIXP_DBL px2_m, x2_m; + + /* Move input value x_m * 2^x_e toward 1.0, where the taylor approximation + of the function log(1-x) centered at 0 is most accurate. */ + { + INT b_norm; + + b_norm = fNormz(x_m)-1; + x2_m = x_m << b_norm; + x_e = x_e - b_norm; + } + + /* map x from log(x) domain to log(1-x) domain. */ + x2_m = - (x2_m + FL2FXCONST_DBL(-1.0) ); + + /* Taylor polinomial approximation of ln(1-x) */ + result_m = FL2FXCONST_DBL(0.0); + px2_m = x2_m; + for (int i=0; i> (enorm-1)) + ((FIXP_DBL)x_e << (DFRACT_BITS-1-enorm)); + + *result_e = enorm; + } else { + /* 1 compensates the fMultDiv2() above in the taylor polinomial evaluation loop.*/ + *result_e = 1; + } + } + + return result_m; +} + +FIXP_DBL fLog2(FIXP_DBL x_m, INT x_e) +{ + if ( x_m <= FL2FXCONST_DBL(0.0f) ) { + x_m = FL2FXCONST_DBL(-1.0f); + } + else { + INT result_e; + x_m = fLog2(x_m, x_e, &result_e); + x_m = scaleValue(x_m, result_e-LD_DATA_SHIFT); + } + return x_m; +} + + + + +#if TEST_ROUNDING +#include + +void writeToFile( FDKFILE *fh, float v) { + FDKfprintf(fh, "%22.16f\n", v ); +} +FDKFILE* openAppend(CHAR* filNam) +{ + FDKFILE* fh = NULL; + fh = FDKfopen(filNam, "a"); + if (!fh) { + FDKprintf("\nError at fio_open\n"); + return NULL; + } + return fh; +} + +// loop version, long duration, huge output data +void checkRound() +{ + #define IN_INT 0 // all four rounding modes are bitexact for 0 and for 1 + + float inp; + FIXP_DBL f_inp; + float r, rnd; + FIXP_DBL f_trc,f_rnd; + float step; + + //step=0.1f; + step=0.001f; + //step=0.0001f; + //step=0.00001f; + //step=0.0000001f; // BEWARE output data of test might get huge! + //step=0.00000000005f; // BEWARE output data of test might get huge! + + double d_floor,d_ceil; + FIXP_DBL f_floor,f_ceil; + INT i,j,floorInt,ceilInt,roundInt,truncInt; + + FDKFILE *fpF_a = NULL; FDKFILE *fpC_a = NULL; + FDKFILE *fpF_b = NULL; FDKFILE *fpC_b = NULL; + FDKFILE *fpF_c = NULL; FDKFILE *fpC_c = NULL; + FDKFILE *fpF_d = NULL; FDKFILE *fpC_d = NULL; + FDKFILE *fpF_e = NULL; FDKFILE *fpC_e = NULL; + + fpF_a = openAppend("_FLT_a.txt"); fpC_a = openAppend("_FDK_a.txt"); + fpF_b = openAppend("_FLT_b.txt"); fpC_b = openAppend("_FDK_b.txt"); + fpF_c = openAppend("_FLT_c.txt"); fpC_c = openAppend("_FDK_c.txt"); + fpF_d = openAppend("_FLT_d.txt"); fpC_d = openAppend("_FDK_d.txt"); + fpF_e = openAppend("_FLT_e.txt"); fpC_e = openAppend("_FDK_e.txt"); + + + + #define INPUT_SF 3 // BEWARE at SF 0 !!! over/under-flow + #define INPUT_SCALE (float)(1< 0) rnd = inp + r; + if (inp < 0) rnd = -(-inp + r); // avoid offset; you might get offset with 'rnd = inp - r' + j = (INT)(rnd); writeToFile(fpF_e,(float) j); + // --- round fixedpoint + roundInt = fixp_roundToInt(f_inp,INPUT_SF); + f_rnd = fixp_round (f_inp,INPUT_SF); + #if IN_INT + writeToFile(fpC_e,(float) roundInt); + #else + writeToFile(fpC_e,(float) f_rnd * (float)FDKpow(2,INPUT_SF)); + #endif + } + + if (fpF_a) FDKfclose(fpF_a); if (fpC_a) FDKfclose(fpC_a); + if (fpF_b) FDKfclose(fpF_b); if (fpC_b) FDKfclose(fpC_b); + if (fpF_c) FDKfclose(fpF_c); if (fpC_c) FDKfclose(fpC_c); + if (fpF_d) FDKfclose(fpF_d); if (fpC_d) FDKfclose(fpC_d); + if (fpF_e) FDKfclose(fpF_e); if (fpC_e) FDKfclose(fpC_e); +} + + +// round only a few selected values (faster) +void checkRound2() +{ + // set point + #define BLOD 24 // left bits (of dot): number of bits _left_ of decimal point ==> Q 24.8 format (incl. sign bit) + #define BROD 8 // right bits (of dot): number of bits _right_ of decimal point ==> Q 24.8 format + FDK_ASSERT((BROD+BLOD)==DFRACT_BITS); + + // scale factors + #define FL_SF BLOD + #define FL_SCALE (1< this is needed to get a valid float reference for floor and trunc ] + #define X_MAX ((-0.0000000004656613f) + 128.0000f) + + + FIXP_DBL f_reg0, f_reg1, f_reg2, f_reg3, f_reg4, f_reg5, f_reg6, f_reg7, f_reg8, f_reg_min, f_reg_max, f_reg_null; + INT res0, res1, res2, res3, res4, res5, res6, res7, res8; + FIXP_DBL f_res0, f_res1, f_res2, f_res3, f_res4, f_res5, f_res6, f_res7, f_res8; + + f_reg_min = (LONG)0x80000000 ; // data taken from above dump; cast to LONG needed because of + f_reg0 = (LONG)0x81000000 ; // fract-class needs a sign; 0x######## is of type unsigned int. + f_reg1 = (LONG)0xfb000000 ; + f_reg2 = (LONG)0xfb000690 ; + f_reg3 = (LONG)0xfb800000 ; + f_reg4 = (LONG)0xffe068dc ; + f_reg_null = (LONG)0x00000000 ; + f_reg5 = (LONG)0x001f9724 ; + f_reg6 = (LONG)0x04800000 ; + f_reg7 = (LONG)0x04fff970 ; + f_reg8 = (LONG)0x05000000 ; + f_reg_max = (LONG)0x7fffffff ; + + + FDKprintf("---- input values ----\n"); + FDKprintf("%f %f %f %f %f %f %f %f %f\n", X0 + , X1 + , X2 + , X3 + , X4 + , X5 + , X6 + , X7 + , X8 + ); + FDKprintf("%f %f %f %f %f %f %f %f %f\n", (float)f_reg0 * (float)FDKpow(2,INL_SF) + , (float)f_reg1 * (float)FDKpow(2,INL_SF) + , (float)f_reg2 * (float)FDKpow(2,INL_SF) + , (float)f_reg3 * (float)FDKpow(2,INL_SF) + , (float)f_reg4 * (float)FDKpow(2,INL_SF) + , (float)f_reg5 * (float)FDKpow(2,INL_SF) + , (float)f_reg6 * (float)FDKpow(2,INL_SF) + , (float)f_reg7 * (float)FDKpow(2,INL_SF) + , (float)f_reg8 * (float)FDKpow(2,INL_SF) + ); + FDKprintf("---- min/max input values ----\n"); + FDKprintf("%f %f %f\n", X_MIN + , X_NULL + , X_MAX + ); + FDKprintf("%f %f %f\n", (float)f_reg_min * (float)FDKpow(2,INL_SF) + , (float)f_reg_null * (float)FDKpow(2,INL_SF) + , (float)f_reg_max * (float)FDKpow(2,INL_SF) + ); + FDKprintf("\n"); + + FDKprintf("\n---- floor ----\n"); + res0 = fixp_floorToInt(f_reg0, INL_SF); f_res0 = fixp_floor(f_reg0, INL_SF); + res1 = fixp_floorToInt(f_reg1, INL_SF); f_res1 = fixp_floor(f_reg1, INL_SF); + res2 = fixp_floorToInt(f_reg2, INL_SF); f_res2 = fixp_floor(f_reg2, INL_SF); + res3 = fixp_floorToInt(f_reg3, INL_SF); f_res3 = fixp_floor(f_reg3, INL_SF); + res4 = fixp_floorToInt(f_reg4, INL_SF); f_res4 = fixp_floor(f_reg4, INL_SF); + res5 = fixp_floorToInt(f_reg5, INL_SF); f_res5 = fixp_floor(f_reg5, INL_SF); + res6 = fixp_floorToInt(f_reg6, INL_SF); f_res6 = fixp_floor(f_reg6, INL_SF); + res7 = fixp_floorToInt(f_reg7, INL_SF); f_res7 = fixp_floor(f_reg7, INL_SF); + res8 = fixp_floorToInt(f_reg8, INL_SF); f_res8 = fixp_floor(f_reg8, INL_SF); + FDKprintf("reference %i %i %i %i %i %i %i %i %i\n", (int)floor(X0), (int)floor(X1), (int)floor(X2), (int)floor(X3), (int)floor(X4), (int)floor(X5), (int)floor(X6), (int)floor(X7), (int)floor(X8)); + FDKprintf("fixp_floorToInt %i %i %i %i %i %i %i %i %i\n", res0, res1, res2, res3, res4, res5, res6, res7, res8); + FDKprintf("fixp_floor %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f\n", (float)f_res0*(float)FDKpow(2,INL_SF), + (float)f_res1*(float)FDKpow(2,INL_SF), + (float)f_res2*(float)FDKpow(2,INL_SF), + (float)f_res3*(float)FDKpow(2,INL_SF), + (float)f_res4*(float)FDKpow(2,INL_SF), + (float)f_res5*(float)FDKpow(2,INL_SF), + (float)f_res6*(float)FDKpow(2,INL_SF), + (float)f_res7*(float)FDKpow(2,INL_SF), + (float)f_res8*(float)FDKpow(2,INL_SF)); + + FDKprintf("\n---- min/max floor ----\n"); + res1 = fixp_floorToInt(f_reg_min, INL_SF); f_res1 = fixp_floor(f_reg_min, INL_SF); + res2 = fixp_floorToInt(f_reg_null, INL_SF); f_res2 = fixp_floor(f_reg_null, INL_SF); + res3 = fixp_floorToInt(f_reg_max, INL_SF); f_res3 = fixp_floor(f_reg_max, INL_SF); + FDKprintf("reference %i %i %i\n", (int)floor(X_MIN), (int)floor(X_NULL), (int)floor(X_MAX)); + FDKprintf("fixp_floorToInt %i %i %i\n", res1, res2, res3); + FDKprintf("fixp_floor %10.7f %10.7f %10.7f\n", (float)f_res1*(float)FDKpow(2,INL_SF), + (float)f_res2*(float)FDKpow(2,INL_SF), + (float)f_res3*(float)FDKpow(2,INL_SF)); + FDKprintf("\n\n\n"); + + + FDKprintf("---- ceil ----\n"); + res0 = fixp_ceilToInt(f_reg0, INL_SF); f_res0 = fixp_ceil(f_reg0, INL_SF); + res1 = fixp_ceilToInt(f_reg1, INL_SF); f_res1 = fixp_ceil(f_reg1, INL_SF); + res2 = fixp_ceilToInt(f_reg2, INL_SF); f_res2 = fixp_ceil(f_reg2, INL_SF); + res3 = fixp_ceilToInt(f_reg3, INL_SF); f_res3 = fixp_ceil(f_reg3, INL_SF); + res4 = fixp_ceilToInt(f_reg4, INL_SF); f_res4 = fixp_ceil(f_reg4, INL_SF); + res5 = fixp_ceilToInt(f_reg5, INL_SF); f_res5 = fixp_ceil(f_reg5, INL_SF); + res6 = fixp_ceilToInt(f_reg6, INL_SF); f_res6 = fixp_ceil(f_reg6, INL_SF); + res7 = fixp_ceilToInt(f_reg7, INL_SF); f_res7 = fixp_ceil(f_reg7, INL_SF); + res8 = fixp_ceilToInt(f_reg8, INL_SF); f_res8 = fixp_ceil(f_reg8, INL_SF); + FDKprintf("reference %i %i %i %i %i %i %i %i %i\n", (int)ceil(X0), (int)ceil(X1), (int)ceil(X2), (int)ceil(X3), (int)ceil(X4), (int)ceil(X5), (int)ceil(X6), (int)ceil(X7), (int)ceil(X8)); + FDKprintf("fixp_ceilToInt %i %i %i %i %i %i %i %i %i\n", res0, res1, res2, res3, res4, res5, res6, res7, res8); + FDKprintf("fixp_ceil %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f\n", (float)f_res0*(float)FDKpow(2,INL_SF), + (float)f_res1*(float)FDKpow(2,INL_SF), + (float)f_res2*(float)FDKpow(2,INL_SF), + (float)f_res3*(float)FDKpow(2,INL_SF), + (float)f_res4*(float)FDKpow(2,INL_SF), + (float)f_res5*(float)FDKpow(2,INL_SF), + (float)f_res6*(float)FDKpow(2,INL_SF), + (float)f_res7*(float)FDKpow(2,INL_SF), + (float)f_res8*(float)FDKpow(2,INL_SF)); + + FDKprintf("\n---- min/max ceil ----\n"); + res1 = fixp_ceilToInt(f_reg_min, INL_SF); + res2 = fixp_ceilToInt(f_reg_null, INL_SF); + res3 = fixp_ceilToInt(f_reg_max, INL_SF); + + f_res1 = fixp_ceil(f_reg_min, INL_SF); + f_res2 = fixp_ceil(f_reg_null, INL_SF); + f_res3 = fixp_ceil(f_reg_max, INL_SF); + + FDKprintf("reference %i %i %i\n", (int)ceil(X_MIN), (int)ceil(X_NULL), (int)ceil(X_MAX)); + FDKprintf("fixp_ceilToInt %i %i %i\n", res1, res2, res3); + FDKprintf("fixp_ceil %10.7f %10.7f %10.7f\n", (float)f_res1*(float)FDKpow(2,INL_SF), + (float)f_res2*(float)FDKpow(2,INL_SF), + (float)f_res3*(float)FDKpow(2,INL_SF)); + FDKprintf("\n\n\n"); + + + FDKprintf("---- trunc ----\n"); + res0 = fixp_truncateToInt(f_reg0, INL_SF); f_res0 = fixp_truncate(f_reg0, INL_SF); + res1 = fixp_truncateToInt(f_reg1, INL_SF); f_res1 = fixp_truncate(f_reg1, INL_SF); + res2 = fixp_truncateToInt(f_reg2, INL_SF); f_res2 = fixp_truncate(f_reg2, INL_SF); + res3 = fixp_truncateToInt(f_reg3, INL_SF); f_res3 = fixp_truncate(f_reg3, INL_SF); + res4 = fixp_truncateToInt(f_reg4, INL_SF); f_res4 = fixp_truncate(f_reg4, INL_SF); + res5 = fixp_truncateToInt(f_reg5, INL_SF); f_res5 = fixp_truncate(f_reg5, INL_SF); + res6 = fixp_truncateToInt(f_reg6, INL_SF); f_res6 = fixp_truncate(f_reg6, INL_SF); + res7 = fixp_truncateToInt(f_reg7, INL_SF); f_res7 = fixp_truncate(f_reg7, INL_SF); + res8 = fixp_truncateToInt(f_reg8, INL_SF); f_res8 = fixp_truncate(f_reg8, INL_SF); + FDKprintf("reference %i %i %i %i %i %i %i %i %i\n", (int)(X0), (int)(X1), (int)(X2), (int)(X3), (int)(X4), (int)(X5), (int)(X6), (int)(X7), (int)(X8)); + FDKprintf("fixp_truncateToInt %i %i %i %i %i %i %i %i %i\n", res0, res1, res2, res3, res4, res5, res6, res7, res8); + FDKprintf("fixp_truncate %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f\n", (float)f_res0*(float)FDKpow(2,INL_SF), + (float)f_res1*(float)FDKpow(2,INL_SF), + (float)f_res2*(float)FDKpow(2,INL_SF), + (float)f_res3*(float)FDKpow(2,INL_SF), + (float)f_res4*(float)FDKpow(2,INL_SF), + (float)f_res5*(float)FDKpow(2,INL_SF), + (float)f_res6*(float)FDKpow(2,INL_SF), + (float)f_res7*(float)FDKpow(2,INL_SF), + (float)f_res8*(float)FDKpow(2,INL_SF)); + + FDKprintf("\n---- min/max trunc ----\n"); + res1 = fixp_truncateToInt(f_reg_min, INL_SF); f_res1 = fixp_truncate(f_reg_min, INL_SF); + res2 = fixp_truncateToInt(f_reg_null,INL_SF); f_res2 = fixp_truncate(f_reg_null,INL_SF); + res3 = fixp_truncateToInt(f_reg_max, INL_SF); f_res3 = fixp_truncate(f_reg_max, INL_SF); + FDKprintf("reference %i %i %i\n", (int)(X_MIN), (int)(X_NULL), (int)(X_MAX)); + FDKprintf("fixp_truncateToInt %i %i %i\n", res1, res2, res3); + FDKprintf("fixp_truncate %10.7f %10.7f %10.7f\n", (float)f_res1*(float)FDKpow(2,INL_SF), + (float)f_res2*(float)FDKpow(2,INL_SF), + (float)f_res3*(float)FDKpow(2,INL_SF)); + FDKprintf("\n\n\n"); + + + FDKprintf("---- round ----\n"); + res0 = fixp_roundToInt(f_reg0, INL_SF); f_res0 = fixp_round(f_reg0, INL_SF); + res1 = fixp_roundToInt(f_reg1, INL_SF); f_res1 = fixp_round(f_reg1, INL_SF); + res2 = fixp_roundToInt(f_reg2, INL_SF); f_res2 = fixp_round(f_reg2, INL_SF); + res3 = fixp_roundToInt(f_reg3, INL_SF); f_res3 = fixp_round(f_reg3, INL_SF); + res4 = fixp_roundToInt(f_reg4, INL_SF); f_res4 = fixp_round(f_reg4, INL_SF); + res5 = fixp_roundToInt(f_reg5, INL_SF); f_res5 = fixp_round(f_reg5, INL_SF); + res6 = fixp_roundToInt(f_reg6, INL_SF); f_res6 = fixp_round(f_reg6, INL_SF); + res7 = fixp_roundToInt(f_reg7, INL_SF); f_res7 = fixp_round(f_reg7, INL_SF); + res8 = fixp_roundToInt(f_reg8, INL_SF); f_res8 = fixp_round(f_reg8, INL_SF); + FDKprintf("reference %i %i %i %i %i %i %i %i %i\n", roundRef(X0), + roundRef(X1), + roundRef(X2), + roundRef(X3), + roundRef(X4), + roundRef(X5), + roundRef(X6), + roundRef(X7), + roundRef(X8)); + FDKprintf("fixp_roundToInt %i %i %i %i %i %i %i %i %i\n", res0, res1, res2, res3, res4, res5, res6, res7, res8); + FDKprintf("fixp_round %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f %10.7f\n", (float)f_res0*(float)FDKpow(2,INL_SF), + (float)f_res1*(float)FDKpow(2,INL_SF), + (float)f_res2*(float)FDKpow(2,INL_SF), + (float)f_res3*(float)FDKpow(2,INL_SF), + (float)f_res4*(float)FDKpow(2,INL_SF), + (float)f_res5*(float)FDKpow(2,INL_SF), + (float)f_res6*(float)FDKpow(2,INL_SF), + (float)f_res7*(float)FDKpow(2,INL_SF), + (float)f_res8*(float)FDKpow(2,INL_SF)); + + FDKprintf("\n---- min/max round ----\n"); + res1 = fixp_roundToInt(f_reg_min, INL_SF); f_res1 = fixp_round(f_reg_min, INL_SF); + res2 = fixp_roundToInt(f_reg_null,INL_SF); f_res2 = fixp_round(f_reg_null,INL_SF); + res3 = fixp_roundToInt(f_reg_max, INL_SF); f_res3 = fixp_round(f_reg_max, INL_SF); + + FDKprintf("reference %i %i %i\n", roundRef(X_MIN), + roundRef(X_NULL), + roundRef(X_MAX)); + FDKprintf("fixp_roundToInt %i %i %i\n", res1, res2, res3); + FDKprintf("fixp_round %10.7f %10.7f %10.7f\n", (float)f_res1*(float)FDKpow(2,INL_SF), + (float)f_res2*(float)FDKpow(2,INL_SF), + (float)f_res3*(float)FDKpow(2,INL_SF)); + FDKprintf("\n\n\n"); + +} +#endif diff --git a/libFDK/src/mdct.cpp b/libFDK/src/mdct.cpp new file mode 100644 index 0000000..ed8ec0c --- /dev/null +++ b/libFDK/src/mdct.cpp @@ -0,0 +1,339 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2011) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl, Manuel Jander + Description: MDCT routines + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "mdct.h" + + +#include "FDK_tools_rom.h" +#include "dct.h" +#include "fixpoint_math.h" + +#define OPT_OVERLAP_ADD + +void mdct_init( H_MDCT hMdct, + FIXP_DBL *overlap, + INT overlapBufferSize ) +{ + hMdct->overlap.freq = overlap; + //FDKmemclear(overlap, overlapBufferSize*sizeof(FIXP_DBL)); + hMdct->prev_fr = 0; + hMdct->prev_nr = 0; + hMdct->prev_tl = 0; + hMdct->ov_size = overlapBufferSize; +} + +INT mdct( H_MDCT hMdct, + FIXP_DBL *spectrum, + INT *scalefactor, + INT_PCM *input, + INT tl, + INT nr, + INT fr, + const FIXP_WTP *wrs ) +{ + /* Fold and windowing */ + + /* DCT IV */ + // dct_IV(); + return tl; +} + +void imdct_gain(FIXP_DBL *pGain_m, int *pGain_e, int tl) +{ + FIXP_DBL gain_m = *pGain_m; + int gain_e = *pGain_e; + int log2_tl; + + log2_tl = DFRACT_BITS-1-fNormz((FIXP_DBL)tl); + + gain_e += -MDCT_OUTPUT_GAIN - log2_tl - MDCT_OUT_HEADROOM + 1; + + /* Detect non-radix 2 transform length and add amplitude compensation factor + which cannot be included into the exponent above */ + switch ( (tl) >> (log2_tl - 2) ) { + case 0x7: /* 10 ms, 1/tl = 1.0/(FDKpow(2.0, -log2_tl) * 0.53333333333333333333) */ + if (gain_m == (FIXP_DBL)0) { + gain_m = FL2FXCONST_DBL(0.53333333333333333333f); + } else { + gain_m = fMult(gain_m, FL2FXCONST_DBL(0.53333333333333333333f)); + } + break; + case 0x6: /* 3/4 of radix 2, 1/tl = 1.0/(FDKpow(2.0, -log2_tl) * 2.0/3.0) */ + if (gain_m == (FIXP_DBL)0) { + gain_m = FL2FXCONST_DBL(2.0/3.0f); + } else { + gain_m = fMult(gain_m, FL2FXCONST_DBL(2.0/3.0f)); + } + break; + case 0x4: + /* radix 2, nothing to do. */ + break; + default: + /* unsupported */ + FDK_ASSERT(0); + break; + } + + *pGain_m = gain_m; + *pGain_e = gain_e; +} + +INT imdct_drain( + H_MDCT hMdct, + FIXP_DBL *output, + INT nrSamplesRoom + ) +{ + int buffered_samples = 0; + + if (nrSamplesRoom > 0) { + buffered_samples = hMdct->ov_offset; + + FDK_ASSERT(buffered_samples <= nrSamplesRoom); + + if (buffered_samples > 0) { + FDKmemcpy(output, hMdct->overlap.time, buffered_samples*sizeof(FIXP_DBL)); + hMdct->ov_offset = 0; + } + } + return buffered_samples; +} + +INT imdct_copy_ov_and_nr( + H_MDCT hMdct, + FIXP_DBL * pTimeData, + INT nrSamples + ) +{ + FIXP_DBL *pOvl; + int nt, nf, i; + + nt = fMin(hMdct->ov_offset, nrSamples); + nrSamples -= nt; + nf = fMin(hMdct->prev_nr, nrSamples); + nrSamples -= nf; + FDKmemcpy(pTimeData, hMdct->overlap.time, nt*sizeof(FIXP_DBL)); + pTimeData += nt; + + pOvl = hMdct->overlap.freq + hMdct->ov_size - 1; + for (i=0; iprev_tl == 0) { + hMdct->prev_wrs = wls; + hMdct->prev_fr = fl; + hMdct->prev_nr = (noOutSamples-fl)>>1; + hMdct->prev_tl = noOutSamples; + hMdct->ov_offset = 0; + use_current = 1; + } + + window_diff = (hMdct->prev_fr - fl)>>1; + + /* check if the previous window slope can be adjusted to match the current window slope */ + if (hMdct->prev_nr + window_diff > 0) { + use_current = 1; + } + /* check if the current window slope can be adjusted to match the previous window slope */ + if (nl - window_diff > 0 ) { + use_previous = 1; + } + + /* if both is possible choose the larger of both window slope lengths */ + if (use_current && use_previous) { + if (fl < hMdct->prev_fr) { + use_current = 0; + } else { + use_previous = 0; + } + } + /* + * If the previous transform block is big enough, enlarge previous window overlap, + * if not, then shrink current window overlap. + */ + if (use_current) { + hMdct->prev_nr += window_diff; + hMdct->prev_fr = fl; + hMdct->prev_wrs = wls; + } else { + nl -= window_diff; + fl = hMdct->prev_fr; + } + + *pfl = fl; + *pnl = nl; +} + +INT imdct_block( + H_MDCT hMdct, + FIXP_DBL *output, + FIXP_DBL *spectrum, + const SHORT scalefactor[], + const INT nSpec, + const INT noOutSamples, + const INT tl, + const FIXP_WTP *wls, + INT fl, + const FIXP_WTP *wrs, + const INT fr, + FIXP_DBL gain + ) +{ + FIXP_DBL *pOvl; + FIXP_DBL *pOut0 = output, *pOut1; + INT nl, nr; + int w, i, nrSamples = 0, specShiftScale, transform_gain_e = 0; + + /* Derive NR and NL */ + nr = (tl - fr)>>1; + nl = (tl - fl)>>1; + + /* Include 2/N IMDCT gain into gain factor and exponent. */ + imdct_gain(&gain, &transform_gain_e, tl); + + /* Detect FRprevious / FL mismatches and override parameters accordingly */ + if (hMdct->prev_fr != fl) { + imdct_adapt_parameters(hMdct, &fl, &nl, tl, wls, noOutSamples); + } + + pOvl = hMdct->overlap.freq + hMdct->ov_size - 1; + + if ( noOutSamples > nrSamples ) { + /* Purge buffered output. */ + for (i=0; iov_offset; i++) { + *pOut0 = hMdct->overlap.time[i]; + pOut0 ++; + } + nrSamples = hMdct->ov_offset; + hMdct->ov_offset = 0; + } + + for (w=0; wprev_wrs; + + /* Current spectrum */ + pSpec = spectrum+w*tl; + + /* DCT IV of current spectrum. */ + dct_IV(pSpec, tl, &specShiftScale); + + /* Optional scaling of time domain - no yet windowed - of current spectrum */ + /* and de-scale current spectrum signal (time domain, no yet windowed) */ + if (gain != (FIXP_DBL)0) { + scaleValuesWithFactor(pSpec, gain, tl, scalefactor[w] + specShiftScale); + } else { + scaleValues(pSpec, tl, scalefactor[w] + specShiftScale); + } + + if ( noOutSamples <= nrSamples ) { + /* Divert output first half to overlap buffer if we already got enough output samples. */ + pOut0 = hMdct->overlap.time + hMdct->ov_offset; + hMdct->ov_offset += hMdct->prev_nr + fl/2; + } else { + /* Account output samples */ + nrSamples += hMdct->prev_nr + fl/2; + } + + /* NR output samples 0 .. NR. -overlap[TL/2..TL/2-NR] */ + for (i=0; iprev_nr; i++) { + FIXP_DBL x = - (*pOvl--); + *pOut0 = IMDCT_SCALE_DBL(x); + pOut0 ++; + } + + if ( noOutSamples <= nrSamples ) { + /* Divert output second half to overlap buffer if we already got enough output samples. */ + pOut1 = hMdct->overlap.time + hMdct->ov_offset + fl/2 - 1; + hMdct->ov_offset += fl/2 + nl; + } else { + pOut1 = pOut0 + (fl - 1); + nrSamples += fl/2 + nl; + } + + /* output samples before window crossing point NR .. TL/2. -overlap[TL/2-NR..TL/2-NR-FL/2] + current[NR..TL/2] */ + /* output samples after window crossing point TL/2 .. TL/2+FL/2. -overlap[0..FL/2] - current[TL/2..FL/2] */ + pCurr = pSpec + tl - fl/2; + for (i=0; iprev_nr = nr; + hMdct->prev_fr = fr; + hMdct->prev_tl = tl; + hMdct->prev_wrs = wrs; + } + + /* Save overlap */ + + pOvl = hMdct->overlap.freq + hMdct->ov_size - tl/2; + FDK_ASSERT(pOvl >= hMdct->overlap.time + hMdct->ov_offset); + FDK_ASSERT(tl/2 <= hMdct->ov_size); + for (i=0; iAbout polyphase filtering + The polyphase implementation of a filterbank requires filtering at the input and output. + This is implemented as part of cplxAnalysisQmfFiltering() and cplxSynthesisQmfFiltering(). + The implementation requires the filter coefficients in a specific structure as described in + #sbr_qmf_64_640_qmf (in sbr_rom.cpp). + + This module comprises the computationally most expensive functions of the SBR decoder. The accuracy of + computations is also important and has a direct impact on the overall sound quality. Therefore a special + test program is available which can be used to only test the filterbank: main_audio.cpp + + This modules also uses scaling of data to provide better SNR on fixed-point processors. See #QMF_SCALE_FACTOR (in sbr_scale.h) for details. + An interesting note: The function getScalefactor() can constitute a significant amount of computational complexity - very much depending on the + bitrate. Since it is a rather small function, effective assembler optimization might be possible. + +*/ + +#include "qmf.h" + + +#include "fixpoint_math.h" +#include "dct.h" + +#ifdef QMFSYN_STATES_16BIT +#define QSSCALE (7) +#define FX_DBL2FX_QSS(x) ((FIXP_QSS) ((x)>>(DFRACT_BITS-QSS_BITS-QSSCALE) )) +#define FX_QSS2FX_DBL(x) ((FIXP_DBL)((LONG)x)<<(DFRACT_BITS-QSS_BITS-QSSCALE)) +#else +#define QSSCALE (0) +#define FX_DBL2FX_QSS(x) (x) +#define FX_QSS2FX_DBL(x) (x) +#endif + + +#if defined(__arm__) +#include "arm/qmf_arm.cpp" + +#endif + +/*! + * \brief Algorithmic scaling in sbrForwardModulation() + * + * The scaling in sbrForwardModulation() is caused by: + * + * \li 1 R_SHIFT in sbrForwardModulation() + * \li 5/6 R_SHIFT in dct3() if using 32/64 Bands + * \li 1 ommited gain of 2.0 in qmfForwardModulation() + */ +#define ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK 7 + +/*! + * \brief Algorithmic scaling in cplxSynthesisQmfFiltering() + * + * The scaling in cplxSynthesisQmfFiltering() is caused by: + * + * \li 5/6 R_SHIFT in dct2() if using 32/64 Bands + * \li 1 ommited gain of 2.0 in qmfInverseModulation() + * \li -6 division by 64 in synthesis filterbank + * \li x bits external influence + */ +#define ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK 1 + + +/*! + \brief Perform Synthesis Prototype Filtering on a single slot of input data. + + The filter takes 2 * qmf->no_channels of input data and + generates qmf->no_channels time domain output samples. +*/ +static +#ifndef FUNCTION_qmfSynPrototypeFirSlot +void qmfSynPrototypeFirSlot( +#else +void qmfSynPrototypeFirSlot_fallback( +#endif + HANDLE_QMF_FILTER_BANK qmf, + FIXP_QMF *RESTRICT realSlot, /*!< Input: Pointer to real Slot */ + FIXP_QMF *RESTRICT imagSlot, /*!< Input: Pointer to imag Slot */ + INT_PCM *RESTRICT timeOut, /*!< Time domain data */ + int stride + ) +{ + FIXP_QSS* FilterStates = (FIXP_QSS*)qmf->FilterStates; + int no_channels = qmf->no_channels; + const FIXP_PFT *p_Filter = qmf->p_filter; + int p_stride = qmf->p_stride; + int j; + FIXP_QSS *RESTRICT sta = FilterStates; + const FIXP_PFT *RESTRICT p_flt, *RESTRICT p_fltm; + int scale = ((DFRACT_BITS-SAMPLE_BITS)-1-qmf->outScalefactor); + + p_flt = p_Filter+p_stride*QMF_NO_POLY; /* 5-ter von 330 */ + p_fltm = p_Filter+(qmf->FilterSize/2)-p_stride*QMF_NO_POLY; /* 5 + (320 - 2*5) = 315-ter von 330 */ + + FDK_ASSERT(SAMPLE_BITS-1-qmf->outScalefactor >= 0); // (DFRACT_BITS-SAMPLE_BITS)-1-qmf->outScalefactor >= 0); + + for (j = no_channels-1; j >= 0; j--) { /* ---- läuft ueber alle Linien eines Slots ---- */ + FIXP_QMF imag = imagSlot[j]; // no_channels-1 .. 0 + FIXP_QMF real = realSlot[j]; // ~~"~~ + { + INT_PCM tmp; + FIXP_DBL Are = FX_QSS2FX_DBL(sta[0]) + fMultDiv2( p_fltm[0] , real); + + if (qmf->outGain!=(FIXP_DBL)0x80000000) { + Are = fMult(Are,qmf->outGain); + } + + #if SAMPLE_BITS > 16 + tmp = (INT_PCM)(SATURATE_SHIFT(fAbs(Are), scale, SAMPLE_BITS)); + #else + tmp = (INT_PCM)(SATURATE_RIGHT_SHIFT(fAbs(Are), scale, SAMPLE_BITS)); + #endif + if (Are < (FIXP_QMF)0) { + tmp = -tmp; + } + timeOut[ (j)*stride ] = tmp; + } + + sta[0] = sta[1] + FX_DBL2FX_QSS(fMultDiv2( p_flt [4] , imag )); + sta[1] = sta[2] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[1] , real )); + sta[2] = sta[3] + FX_DBL2FX_QSS(fMultDiv2( p_flt [3] , imag )); + sta[3] = sta[4] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[2] , real )); + sta[4] = sta[5] + FX_DBL2FX_QSS(fMultDiv2( p_flt [2] , imag )); + sta[5] = sta[6] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[3] , real )); + sta[6] = sta[7] + FX_DBL2FX_QSS(fMultDiv2( p_flt [1] , imag )); + sta[7] = sta[8] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[4] , real )); + sta[8] = FX_DBL2FX_QSS(fMultDiv2( p_flt [0] , imag )); + + p_flt += (p_stride*QMF_NO_POLY); + p_fltm -= (p_stride*QMF_NO_POLY); + sta += 9; // = (2*QMF_NO_POLY-1); + } +} + +#ifndef FUNCTION_qmfSynPrototypeFirSlot_NonSymmetric +/*! + \brief Perform Synthesis Prototype Filtering on a single slot of input data. + + The filter takes 2 * qmf->no_channels of input data and + generates qmf->no_channels time domain output samples. +*/ +static +void qmfSynPrototypeFirSlot_NonSymmetric( + HANDLE_QMF_FILTER_BANK qmf, + FIXP_QMF *RESTRICT realSlot, /*!< Input: Pointer to real Slot */ + FIXP_QMF *RESTRICT imagSlot, /*!< Input: Pointer to imag Slot */ + INT_PCM *RESTRICT timeOut, /*!< Time domain data */ + int stride + ) +{ + FIXP_QSS* FilterStates = (FIXP_QSS*)qmf->FilterStates; + int no_channels = qmf->no_channels; + const FIXP_PFT *p_Filter = qmf->p_filter; + int p_stride = qmf->p_stride; + int j; + FIXP_QSS *RESTRICT sta = FilterStates; + const FIXP_PFT *RESTRICT p_flt, *RESTRICT p_fltm; + int scale = ((DFRACT_BITS-SAMPLE_BITS)-1-qmf->outScalefactor); + + p_flt = p_Filter; /*!< Pointer to first half of filter coefficients */ + p_fltm = &p_flt[qmf->FilterSize/2]; /* at index 320, overall 640 coefficients */ + + FDK_ASSERT(SAMPLE_BITS-1-qmf->outScalefactor >= 0); // (DFRACT_BITS-SAMPLE_BITS)-1-qmf->outScalefactor >= 0); + + for (j = no_channels-1; j >= 0; j--) { /* ---- läuft ueber alle Linien eines Slots ---- */ + + FIXP_QMF imag = imagSlot[j]; // no_channels-1 .. 0 + FIXP_QMF real = realSlot[j]; // ~~"~~ + { + INT_PCM tmp; + FIXP_QMF Are = sta[0] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[4] , real )); + + #if SAMPLE_BITS > 16 + tmp = (INT_PCM)(SATURATE_SHIFT(fAbs(Are), scale, SAMPLE_BITS)); + #else + tmp = (INT_PCM)(SATURATE_RIGHT_SHIFT(fAbs(Are), scale, SAMPLE_BITS)); + #endif + if (Are < (FIXP_QMF)0) { + tmp = -tmp; + } + timeOut[j*stride] = tmp; + } + + sta[0] = sta[1] + FX_DBL2FX_QSS(fMultDiv2( p_flt [4] , imag )); + sta[1] = sta[2] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[3] , real )); + sta[2] = sta[3] + FX_DBL2FX_QSS(fMultDiv2( p_flt [3] , imag )); + + sta[3] = sta[4] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[2] , real )); + sta[4] = sta[5] + FX_DBL2FX_QSS(fMultDiv2( p_flt [2] , imag )); + sta[5] = sta[6] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[1] , real )); + sta[6] = sta[7] + FX_DBL2FX_QSS(fMultDiv2( p_flt [1] , imag )); + + sta[7] = sta[8] + FX_DBL2FX_QSS(fMultDiv2( p_fltm[0] , real )); + sta[8] = FX_DBL2FX_QSS(fMultDiv2( p_flt [0] , imag )); + + p_flt += (p_stride*QMF_NO_POLY); + p_fltm += (p_stride*QMF_NO_POLY); + sta += 9; // = (2*QMF_NO_POLY-1); + } + +} +#endif /* FUNCTION_qmfSynPrototypeFirSlot_NonSymmetric */ + +#ifndef FUNCTION_qmfAnaPrototypeFirSlot +/*! + \brief Perform Analysis Prototype Filtering on a single slot of input data. +*/ +static +void qmfAnaPrototypeFirSlot( FIXP_QMF *analysisBuffer, + int no_channels, /*!< Number channels of analysis filter */ + const FIXP_PFT *p_filter, + int p_stride, /*!< Stide of analysis filter */ + FIXP_QAS *RESTRICT pFilterStates + ) +{ + int k; + + FIXP_DBL accu; + const FIXP_PFT *RESTRICT p_flt = p_filter; + FIXP_QMF *RESTRICT pData_0 = analysisBuffer + 2*no_channels - 1; + FIXP_QMF *RESTRICT pData_1 = analysisBuffer; + + FIXP_QAS *RESTRICT sta_0 = (FIXP_QAS *)pFilterStates; + FIXP_QAS *RESTRICT sta_1 = (FIXP_QAS *)pFilterStates + (2*QMF_NO_POLY*no_channels) - 1; + int pfltStep = QMF_NO_POLY * (p_stride); + int staStep1 = no_channels<<1; + int staStep2 = (no_channels<<3) - 1; /* Rewind one less */ + + /* FIR filter 0 */ + accu = fMultDiv2( p_flt[0], *sta_1); sta_1 -= staStep1; + accu += fMultDiv2( p_flt[1], *sta_1); sta_1 -= staStep1; + accu += fMultDiv2( p_flt[2], *sta_1); sta_1 -= staStep1; + accu += fMultDiv2( p_flt[3], *sta_1); sta_1 -= staStep1; + accu += fMultDiv2( p_flt[4], *sta_1); + *pData_1++ = FX_DBL2FX_QMF(accu<<1); + sta_1 += staStep2; + + p_flt += pfltStep; + + /* FIR filters 1..63 127..65 */ + for (k=0; kno_channels; + int M = L>>1; + int scale; + FIXP_QMF accu; + + const FIXP_QMF *timeInTmp1 = (FIXP_QMF *) &timeIn[3 * M]; + const FIXP_QMF *timeInTmp2 = timeInTmp1; + FIXP_QMF *rSubbandTmp = rSubband; + + rSubband[0] = timeIn[3 * M] >> 1; + + for (i = M-1; i != 0; i--) { + accu = ((*--timeInTmp1) >> 1) + ((*++timeInTmp2) >> 1); + *++rSubbandTmp = accu; + } + + timeInTmp1 = &timeIn[2 * M]; + timeInTmp2 = &timeIn[0]; + rSubbandTmp = &rSubband[M]; + + for (i = L-M; i != 0; i--) { + accu = ((*timeInTmp1--) >> 1) - ((*timeInTmp2++) >> 1); + *rSubbandTmp++ = accu; + } + + dct_III(rSubband, timeIn, L, &scale); +} + +#if !defined(FUNCTION_qmfForwardModulationLP_odd) +static void +qmfForwardModulationLP_odd( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */ + const FIXP_QMF *timeIn, /*!< Time Signal */ + FIXP_QMF *rSubband ) /*!< Real Output */ +{ + int i; + int L = anaQmf->no_channels; + int M = L>>1; + int shift = (anaQmf->no_channels>>6) + 1; + + for (i = 0; i < M; i++) { + rSubband[M + i] = (timeIn[L - 1 - i]>>1) - (timeIn[i]>>shift); + rSubband[M - 1 - i] = (timeIn[L + i]>>1) + (timeIn[2 * L - 1 - i]>>shift); + } + + dct_IV(rSubband, L, &shift); +} +#endif /* !defined(FUNCTION_qmfForwardModulationLP_odd) */ + + + +/*! + * + * \brief Perform complex-valued forward modulation of the time domain + * data of timeIn and stores the real part of the subband + * samples in rSubband, and the imaginary part in iSubband + * + * Only the lower bands are obtained (upto anaQmf->lsb). For + * a full bandwidth analysis it is required to set both anaQmf->lsb + * and anaQmf->usb to the amount of QMF bands. + * + */ +static void +qmfForwardModulationHQ( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */ + const FIXP_QMF *RESTRICT timeIn, /*!< Time Signal */ + FIXP_QMF *RESTRICT rSubband, /*!< Real Output */ + FIXP_QMF *RESTRICT iSubband /*!< Imaginary Output */ + ) +{ + int i; + int L = anaQmf->no_channels; + int L2 = L<<1; + int shift = 0; + + for (i = 0; i < L; i+=2) { + FIXP_QMF x0, x1, y0, y1; + + x0 = timeIn[i] >> 1; + x1 = timeIn[i+1] >> 1; + y0 = timeIn[L2 - 1 - i] >> 1; + y1 = timeIn[L2 - 2 - i] >> 1; + + rSubband[i] = x0 - y0; + rSubband[i+1] = x1 - y1; + iSubband[i] = x0 + y0; + iSubband[i+1] = x1 + y1; + } + + dct_IV(rSubband, L, &shift); + dst_IV(iSubband, L, &shift); + + { + { + const FIXP_QTW *RESTRICT sbr_t_cos; + const FIXP_QTW *RESTRICT sbr_t_sin; + sbr_t_cos = anaQmf->t_cos; + sbr_t_sin = anaQmf->t_sin; + + for (i = 0; i < anaQmf->lsb; i++) { + cplxMult(&iSubband[i], &rSubband[i], iSubband[i], rSubband[i], sbr_t_cos[i], sbr_t_sin[i]); + } + } + } +} + +/* + * \brief Perform one QMF slot analysis of the time domain data of timeIn + * with specified stride and stores the real part of the subband + * samples in rSubband, and the imaginary part in iSubband + * + * Only the lower bands are obtained (upto anaQmf->lsb). For + * a full bandwidth analysis it is required to set both anaQmf->lsb + * and anaQmf->usb to the amount of QMF bands. + */ +void +qmfAnalysisFilteringSlot( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank */ + FIXP_QMF *qmfReal, /*!< Low and High band, real */ + FIXP_QMF *qmfImag, /*!< Low and High band, imag */ + const INT_PCM *RESTRICT timeIn, /*!< Pointer to input */ + const int stride, /*!< stride factor of input */ + FIXP_QMF *pWorkBuffer /*!< pointer to temporal working buffer */ + ) +{ + int i; + int offset = anaQmf->no_channels*(QMF_NO_POLY*2-1); + /* + Feed time signal into oldest anaQmf->no_channels states + */ + { + FIXP_QAS *RESTRICT FilterStatesAnaTmp = ((FIXP_QAS*)anaQmf->FilterStates)+offset; + + /* Feed and scale actual time in slot */ + for(i=anaQmf->no_channels>>1; i!=0; i--) { + /* Place INT_PCM value left aligned in scaledTimeIn */ +#if (QAS_BITS==SAMPLE_BITS) + *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn; timeIn += stride; + *FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn; timeIn += stride; +#elif (QAS_BITS>SAMPLE_BITS) + *FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn)<<(QAS_BITS-SAMPLE_BITS)); timeIn += stride; + *FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn)<<(QAS_BITS-SAMPLE_BITS)); timeIn += stride; +#else + *FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn)>>(SAMPLE_BITS-QAS_BITS)); timeIn += stride; + *FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn)>>(SAMPLE_BITS-QAS_BITS)); timeIn += stride; +#endif + } + } + + if (anaQmf->flags & QMF_FLAG_NONSYMMETRIC) { + qmfAnaPrototypeFirSlot_NonSymmetric( + pWorkBuffer, + anaQmf->no_channels, + anaQmf->p_filter, + anaQmf->p_stride, + (FIXP_QAS*)anaQmf->FilterStates + ); + } else { + qmfAnaPrototypeFirSlot( pWorkBuffer, + anaQmf->no_channels, + anaQmf->p_filter, + anaQmf->p_stride, + (FIXP_QAS*)anaQmf->FilterStates + ); + } + + if (anaQmf->flags & QMF_FLAG_LP) { + if (anaQmf->flags & QMF_FLAG_CLDFB) + qmfForwardModulationLP_odd( anaQmf, + pWorkBuffer, + qmfReal ); + else + qmfForwardModulationLP_even( anaQmf, + pWorkBuffer, + qmfReal ); + + } else { + qmfForwardModulationHQ( anaQmf, + pWorkBuffer, + qmfReal, + qmfImag + ); + } + /* + Shift filter states + + Should be realized with modulo adressing on a DSP instead of a true buffer shift + */ + FDKmemmove ((FIXP_QAS*)anaQmf->FilterStates, (FIXP_QAS*)anaQmf->FilterStates+anaQmf->no_channels, offset*sizeof(FIXP_QAS)); +} + + +/*! + * + * \brief Perform complex-valued subband filtering of the time domain + * data of timeIn and stores the real part of the subband + * samples in rAnalysis, and the imaginary part in iAnalysis + * The qmf coefficient table is symmetric. The symmetry is expoited by + * shrinking the coefficient table to half the size. The addressing mode + * takes care of the symmetries. + * + * Only the lower bands are obtained (upto anaQmf->lsb). For + * a full bandwidth analysis it is required to set both anaQmf->lsb + * and anaQmf->usb to the amount of QMF bands. + * + * \sa PolyphaseFiltering + */ + +void +qmfAnalysisFiltering( HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */ + FIXP_QMF **qmfReal, /*!< Pointer to real subband slots */ + FIXP_QMF **qmfImag, /*!< Pointer to imag subband slots */ + QMF_SCALE_FACTOR *scaleFactor, + const INT_PCM *timeIn, /*!< Time signal */ + const int stride, + FIXP_QMF *pWorkBuffer /*!< pointer to temporal working buffer */ + ) +{ + int i; + int no_channels = anaQmf->no_channels; + + scaleFactor->lb_scale = -ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK; + scaleFactor->lb_scale -= anaQmf->filterScale; + + for (i = 0; i < anaQmf->no_col; i++) + { + FIXP_QMF *qmfImagSlot = NULL; + + if (!(anaQmf->flags & QMF_FLAG_LP)) { + qmfImagSlot = qmfImag[i]; + } + + qmfAnalysisFilteringSlot( anaQmf, qmfReal[i], qmfImagSlot, timeIn , stride, pWorkBuffer ); + + timeIn += no_channels*stride; + + } /* no_col loop i */ +} + +/*! + * + * \brief Perform low power inverse modulation of the subband + * samples stored in rSubband (real part) and iSubband (imaginary + * part) and stores the result in pWorkBuffer. + * + */ +inline +static void +qmfInverseModulationLP_even( HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */ + const FIXP_QMF *qmfReal, /*!< Pointer to qmf real subband slot (input) */ + const int scaleFactorLowBand, /*!< Scalefactor for Low band */ + const int scaleFactorHighBand, /*!< Scalefactor for High band */ + FIXP_QMF *pTimeOut /*!< Pointer to qmf subband slot (output)*/ + ) +{ + int i; + int L = synQmf->no_channels; + int M = L>>1; + int scale; + FIXP_QMF tmp; + FIXP_QMF *RESTRICT tReal = pTimeOut; + FIXP_QMF *RESTRICT tImag = pTimeOut + L; + + /* Move input to output vector with offset */ + scaleValues(&tReal[0], &qmfReal[0], synQmf->lsb, scaleFactorLowBand); + scaleValues(&tReal[0+synQmf->lsb], &qmfReal[0+synQmf->lsb], synQmf->usb-synQmf->lsb, scaleFactorHighBand); + FDKmemclear(&tReal[0+synQmf->usb], (L-synQmf->usb)*sizeof(FIXP_QMF)); + + /* Dct type-2 transform */ + dct_II(tReal, tImag, L, &scale); + + /* Expand output and replace inplace the output buffers */ + tImag[0] = tReal[M]; + tImag[M] = (FIXP_QMF)0; + tmp = tReal [0]; + tReal [0] = tReal[M]; + tReal [M] = tmp; + + for (i = 1; i < M/2; i++) { + /* Imag */ + tmp = tReal[L - i]; + tImag[M - i] = tmp; + tImag[i + M] = -tmp; + + tmp = tReal[M + i]; + tImag[i] = tmp; + tImag[L - i] = -tmp; + + /* Real */ + tReal [M + i] = tReal[i]; + tReal [L - i] = tReal[M - i]; + tmp = tReal[i]; + tReal[i] = tReal [M - i]; + tReal [M - i] = tmp; + + } + /* Remaining odd terms */ + tmp = tReal[M + M/2]; + tImag[M/2] = tmp; + tImag[M/2 + M] = -tmp; + + tReal [M + M/2] = tReal[M/2]; +} + +inline +static void +qmfInverseModulationLP_odd( HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */ + const FIXP_QMF *qmfReal, /*!< Pointer to qmf real subband slot (input) */ + const int scaleFactorLowBand, /*!< Scalefactor for Low band */ + const int scaleFactorHighBand, /*!< Scalefactor for High band */ + FIXP_QMF *pTimeOut /*!< Pointer to qmf subband slot (output)*/ + ) +{ + int i; + int L = synQmf->no_channels; + int M = L>>1; + int shift = 0; + + /* Move input to output vector with offset */ + scaleValues(pTimeOut+M, qmfReal, synQmf->lsb, scaleFactorLowBand); + scaleValues(pTimeOut+M+synQmf->lsb, qmfReal+synQmf->lsb, synQmf->usb-synQmf->lsb, scaleFactorHighBand); + FDKmemclear(pTimeOut+M+synQmf->usb, (L-synQmf->usb)*sizeof(FIXP_QMF)); + + dct_IV(pTimeOut+M, L, &shift); + for (i = 0; i < M; i++) { + pTimeOut[i] = pTimeOut[L - 1 - i]; + pTimeOut[2 * L - 1 - i] = -pTimeOut[L + i]; + } +} + + +/*! + * + * \brief Perform complex-valued inverse modulation of the subband + * samples stored in rSubband (real part) and iSubband (imaginary + * part) and stores the result in pWorkBuffer. + * + */ +inline +static void +qmfInverseModulationHQ( HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */ + const FIXP_QMF *qmfReal, /*!< Pointer to qmf real subband slot */ + const FIXP_QMF *qmfImag, /*!< Pointer to qmf imag subband slot */ + const int scaleFactorLowBand, /*!< Scalefactor for Low band */ + const int scaleFactorHighBand,/*!< Scalefactor for High band */ + FIXP_QMF *pWorkBuffer /*!< WorkBuffer (output) */ + ) +{ + int i; + int L = synQmf->no_channels; + int M = L>>1; + int shift = 0; + FIXP_QMF *RESTRICT tReal = pWorkBuffer; + FIXP_QMF *RESTRICT tImag = pWorkBuffer+L; + + if (synQmf->flags & QMF_FLAG_CLDFB){ + for (i = 0; i < synQmf->lsb; i++) { + cplxMult(&tImag[i], &tReal[i], + scaleValue(qmfImag[i],scaleFactorLowBand), scaleValue(qmfReal[i],scaleFactorLowBand), + synQmf->t_cos[i], synQmf->t_sin[i]); + } + for (; i < synQmf->usb; i++) { + cplxMult(&tImag[i], &tReal[i], + scaleValue(qmfImag[i],scaleFactorHighBand), scaleValue(qmfReal[i],scaleFactorHighBand), + synQmf->t_cos[i], synQmf->t_sin[i]); + } + } + + if ( (synQmf->flags & QMF_FLAG_CLDFB) == 0) { + scaleValues(&tReal[0], &qmfReal[0], synQmf->lsb, scaleFactorLowBand); + scaleValues(&tReal[0+synQmf->lsb], &qmfReal[0+synQmf->lsb], synQmf->usb-synQmf->lsb, scaleFactorHighBand); + scaleValues(&tImag[0], &qmfImag[0], synQmf->lsb, scaleFactorLowBand); + scaleValues(&tImag[0+synQmf->lsb], &qmfImag[0+synQmf->lsb], synQmf->usb-synQmf->lsb, scaleFactorHighBand); + } + + FDKmemclear(&tReal[synQmf->usb], (synQmf->no_channels-synQmf->usb)*sizeof(FIXP_QMF)); + FDKmemclear(&tImag[synQmf->usb], (synQmf->no_channels-synQmf->usb)*sizeof(FIXP_QMF)); + + dct_IV(tReal, L, &shift); + dst_IV(tImag, L, &shift); + + if (synQmf->flags & QMF_FLAG_CLDFB){ + for (i = 0; i < M; i++) { + FIXP_QMF r1, i1, r2, i2; + r1 = tReal[i]; + i2 = tImag[L - 1 - i]; + r2 = tReal[L - i - 1]; + i1 = tImag[i]; + + tReal[i] = (r1 - i1)>>1; + tImag[L - 1 - i] = -(r1 + i1)>>1; + tReal[L - i - 1] = (r2 - i2)>>1; + tImag[i] = -(r2 + i2)>>1; + } + } else + { + /* The array accesses are negative to compensate the missing minus sign in the low and hi band gain. */ + /* 26 cycles on ARM926 */ + for (i = 0; i < M; i++) { + FIXP_QMF r1, i1, r2, i2; + r1 = -tReal[i]; + i2 = -tImag[L - 1 - i]; + r2 = -tReal[L - i - 1]; + i1 = -tImag[i]; + + tReal[i] = (r1 - i1)>>1; + tImag[L - 1 - i] = -(r1 + i1)>>1; + tReal[L - i - 1] = (r2 - i2)>>1; + tImag[i] = -(r2 + i2)>>1; + } + } +} + +void qmfSynthesisFilteringSlot( HANDLE_QMF_FILTER_BANK synQmf, + const FIXP_QMF *realSlot, + const FIXP_QMF *imagSlot, + const int scaleFactorLowBand, + const int scaleFactorHighBand, + INT_PCM *timeOut, + const int stride, + FIXP_QMF *pWorkBuffer) +{ + if (!(synQmf->flags & QMF_FLAG_LP)) + qmfInverseModulationHQ ( synQmf, + realSlot, + imagSlot, + scaleFactorLowBand, + scaleFactorHighBand, + pWorkBuffer + ); + else + { + if (synQmf->flags & QMF_FLAG_CLDFB) { + qmfInverseModulationLP_odd ( synQmf, + realSlot, + scaleFactorLowBand, + scaleFactorHighBand, + pWorkBuffer + ); + } else { + qmfInverseModulationLP_even ( synQmf, + realSlot, + scaleFactorLowBand, + scaleFactorHighBand, + pWorkBuffer + ); + } + } + + if (synQmf->flags & QMF_FLAG_NONSYMMETRIC) { + qmfSynPrototypeFirSlot_NonSymmetric ( + synQmf, + pWorkBuffer, + pWorkBuffer+synQmf->no_channels, + timeOut, + stride + ); + } else { + qmfSynPrototypeFirSlot ( synQmf, + pWorkBuffer, + pWorkBuffer+synQmf->no_channels, + timeOut, + stride + ); + } +} + + +/*! + * + * + * \brief Perform complex-valued subband synthesis of the + * low band and the high band and store the + * time domain data in timeOut + * + * First step: Calculate the proper scaling factor of current + * spectral data in qmfReal/qmfImag, old spectral data in the overlap + * range and filter states. + * + * Second step: Perform Frequency-to-Time mapping with inverse + * Modulation slot-wise. + * + * Third step: Perform FIR-filter slot-wise. To save space for filter + * states, the MAC operations are executed directly on the filter states + * instead of accumulating several products in the accumulator. The + * buffer shift at the end of the function should be replaced by a + * modulo operation, which is available on some DSPs. + * + * Last step: Copy the upper part of the spectral data to the overlap buffer. + * + * The qmf coefficient table is symmetric. The symmetry is exploited by + * shrinking the coefficient table to half the size. The addressing mode + * takes care of the symmetries. If the #define #QMFTABLE_FULL is set, + * coefficient addressing works on the full table size. The code will be + * slightly faster and slightly more compact. + * + * Workbuffer requirement: 2 x sizeof(**QmfBufferReal) * synQmf->no_channels + */ +void +qmfSynthesisFiltering( HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */ + FIXP_QMF **QmfBufferReal, /*!< Low and High band, real */ + FIXP_QMF **QmfBufferImag, /*!< Low and High band, imag */ + const QMF_SCALE_FACTOR *scaleFactor, + const INT ov_len, /*!< split Slot of overlap and actual slots */ + INT_PCM *timeOut, /*!< Pointer to output */ + const INT stride, /*!< stride factor of output */ + FIXP_QMF *pWorkBuffer /*!< pointer to temporal working buffer */ + ) +{ + int i; + int L = synQmf->no_channels; + SCHAR scaleFactorHighBand; + SCHAR scaleFactorLowBand_ov, scaleFactorLowBand_no_ov; + + /* adapt scaling */ + scaleFactorHighBand = -ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - scaleFactor->hb_scale; + scaleFactorLowBand_ov = - ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - scaleFactor->ov_lb_scale; + scaleFactorLowBand_no_ov = - ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - scaleFactor->lb_scale; + + for (i = 0; i < synQmf->no_col; i++) /* ----- no_col loop ----- */ + { + const FIXP_DBL *QmfBufferImagSlot = NULL; + + SCHAR scaleFactorLowBand = (iflags & QMF_FLAG_LP)) + QmfBufferImagSlot = QmfBufferImag[i]; + + qmfSynthesisFilteringSlot( synQmf, + QmfBufferReal[i], + QmfBufferImagSlot, + scaleFactorLowBand, + scaleFactorHighBand, + timeOut+(i*L*stride), + stride, + pWorkBuffer); + } /* no_col loop i */ + +} + + +/*! + * + * \brief Create QMF filter bank instance + * + * \return 0 if successful + * + */ +static int +qmfInitFilterBank (HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Handle to return */ + void *pFilterStates, /*!< Handle to filter states */ + int noCols, /*!< Number of timeslots per frame */ + int lsb, /*!< Lower end of QMF frequency range */ + int usb, /*!< Upper end of QMF frequency range */ + int no_channels, /*!< Number of channels (bands) */ + UINT flags) /*!< flags */ +{ + FDKmemclear(h_Qmf,sizeof(QMF_FILTER_BANK)); + + if (flags & QMF_FLAG_MPSLDFB) + { + return -1; + } + + if ( !(flags & QMF_FLAG_MPSLDFB) && (flags & QMF_FLAG_CLDFB) ) + { + flags |= QMF_FLAG_NONSYMMETRIC; + h_Qmf->filterScale = QMF_CLDFB_PFT_SCALE; + + h_Qmf->p_stride = 1; + switch (no_channels) { + case 64: + h_Qmf->t_cos = qmf_phaseshift_cos64_cldfb; + h_Qmf->t_sin = qmf_phaseshift_sin64_cldfb; + h_Qmf->p_filter = qmf_cldfb_640; + h_Qmf->FilterSize = 640; + break; + case 32: + h_Qmf->t_cos = qmf_phaseshift_cos32_cldfb; + h_Qmf->t_sin = qmf_phaseshift_sin32_cldfb; + h_Qmf->p_filter = qmf_cldfb_320; + h_Qmf->FilterSize = 320; + break; + default: + return -1; + } + } + + if ( !(flags & QMF_FLAG_MPSLDFB) && ((flags & QMF_FLAG_CLDFB) == 0) ) + { + switch (no_channels) { + case 64: + h_Qmf->p_filter = qmf_64; + h_Qmf->t_cos = qmf_phaseshift_cos64; + h_Qmf->t_sin = qmf_phaseshift_sin64; + h_Qmf->p_stride = 1; + h_Qmf->FilterSize = 640; + h_Qmf->filterScale = 0; + break; + case 32: + h_Qmf->p_filter = qmf_64; + h_Qmf->t_cos = qmf_phaseshift_cos32; + h_Qmf->t_sin = qmf_phaseshift_sin32; + h_Qmf->p_stride = 2; + h_Qmf->FilterSize = 640; + h_Qmf->filterScale = 0; + break; + default: + return -1; + } + } + + h_Qmf->flags = flags; + + h_Qmf->no_channels = no_channels; + h_Qmf->no_col = noCols; + + h_Qmf->lsb = lsb; + h_Qmf->usb = fMin(usb, h_Qmf->no_channels); + + h_Qmf->FilterStates = (void*)pFilterStates; + + h_Qmf->outScalefactor = ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK + ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK + h_Qmf->filterScale; + + if (h_Qmf->p_stride == 2) { + h_Qmf->outScalefactor -= 1; + } + h_Qmf->outGain = (FIXP_DBL)0x80000000; /* default init value will be not applied */ + + return (0); +} + +/*! + * + * \brief Adjust synthesis qmf filter states + * + * \return void + * + */ +static inline void +qmfAdaptFilterStates (HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Filter Bank */ + int scaleFactorDiff) /*!< Scale factor difference to be applied */ +{ + if (synQmf == NULL || synQmf->FilterStates == NULL) { + return; + } + scaleValues((FIXP_QSS*)synQmf->FilterStates, synQmf->no_channels*(QMF_NO_POLY*2 - 1), scaleFactorDiff); +} + +/*! + * + * \brief Create QMF filter bank instance + * + * Only the lower bands are obtained (upto anaQmf->lsb). For + * a full bandwidth analysis it is required to set both anaQmf->lsb + * and anaQmf->usb to the amount of QMF bands. + * + * \return 0 if succesful + * + */ +int +qmfInitAnalysisFilterBank (HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Returns handle */ + FIXP_QAS *pFilterStates, /*!< Handle to filter states */ + int noCols, /*!< Number of timeslots per frame */ + int lsb, /*!< lower end of QMF */ + int usb, /*!< upper end of QMF */ + int no_channels, /*!< Number of channels (bands) */ + int flags) /*!< Low Power flag */ +{ + int err = qmfInitFilterBank(h_Qmf, pFilterStates, noCols, lsb, usb, no_channels, flags); + if ( !(flags & QMF_FLAG_KEEP_STATES) && (h_Qmf->FilterStates != NULL) ) { + FDKmemclear(h_Qmf->FilterStates, (2*QMF_NO_POLY-1)*h_Qmf->no_channels*sizeof(FIXP_QAS)); + } + + return err; +} + +/*! + * + * \brief Create QMF filter bank instance + * + * Only the lower bands are obtained (upto anaQmf->lsb). For + * a full bandwidth analysis it is required to set both anaQmf->lsb + * and anaQmf->usb to the amount of QMF bands. + * + * \return 0 if succesful + * + */ +int +qmfInitSynthesisFilterBank (HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Returns handle */ + FIXP_QSS *pFilterStates, /*!< Handle to filter states */ + int noCols, /*!< Number of timeslots per frame */ + int lsb, /*!< lower end of QMF */ + int usb, /*!< upper end of QMF */ + int no_channels, /*!< Number of channels (bands) */ + int flags) /*!< Low Power flag */ +{ + int oldOutScale = h_Qmf->outScalefactor; + int err = qmfInitFilterBank(h_Qmf, pFilterStates, noCols, lsb, usb, no_channels, flags); + if ( h_Qmf->FilterStates != NULL ) { + if ( !(flags & QMF_FLAG_KEEP_STATES) ) { + FDKmemclear(h_Qmf->FilterStates, (2*QMF_NO_POLY-1)*h_Qmf->no_channels*sizeof(FIXP_QSS)); + } else { + qmfAdaptFilterStates(h_Qmf, oldOutScale-h_Qmf->outScalefactor); + } + } + return err; +} + + + + +/*! + * + * \brief Change scale factor for output data and adjust qmf filter states + * + * \return void + * + */ +void +qmfChangeOutScalefactor (HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */ + int outScalefactor /*!< New scaling factor for output data */ + ) +{ + if (synQmf == NULL || synQmf->FilterStates == NULL) { + return; + } + + /* Add internal filterbank scale */ + outScalefactor += ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK + ALGORITHMIC_SCALING_IN_SYNTHESIS_FILTERBANK + synQmf->filterScale; + + if (synQmf->p_stride == 2) { + outScalefactor -= 1; + } + + /* adjust filter states when scale factor has been changed */ + if (synQmf->outScalefactor != outScalefactor) + { + int diff; + + if (outScalefactor > (SAMPLE_BITS - 1)) { + outScalefactor = SAMPLE_BITS - 1; + } else if (outScalefactor < (1 - SAMPLE_BITS)) { + outScalefactor = 1 - SAMPLE_BITS; + } + + diff = synQmf->outScalefactor - outScalefactor; + + qmfAdaptFilterStates(synQmf, diff); + + /* save new scale factor */ + synQmf->outScalefactor = outScalefactor; + } +} + +/*! + * + * \brief Change gain for output data + * + * \return void + * + */ +void +qmfChangeOutGain (HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */ + FIXP_DBL outputGain /*!< New gain for output data */ + ) +{ + synQmf->outGain = outputGain; +} + diff --git a/libFDK/src/scale.cpp b/libFDK/src/scale.cpp new file mode 100644 index 0000000..174677d --- /dev/null +++ b/libFDK/src/scale.cpp @@ -0,0 +1,399 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: Scaling operations + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "common_fix.h" + +#include "genericStds.h" + +/************************************************** + * Inline definitions + **************************************************/ + +#define SCALE_INLINE inline + + +#if defined(__mips__) /* cppp replaced: elif */ +#include "mips/scale.cpp" + +#elif defined(__arm__) +#include "arm/scale_arm.cpp" + +#endif + +#ifndef FUNCTION_scaleValues_SGL +/*! + * + * \brief Multiply input vector by \f$ 2^{scalefactor} \f$ + * \param len must be larger than 4 + * \return void + * + */ +#define FUNCTION_scaleValues_SGL +SCALE_INLINE +void scaleValues(FIXP_SGL *vector, /*!< Vector */ + INT len, /*!< Length */ + INT scalefactor /*!< Scalefactor */ + ) +{ + INT i; + + /* Return if scalefactor is Zero */ + if (scalefactor==0) return; + + if(scalefactor > 0){ + scalefactor = fixmin_I(scalefactor,(INT)(DFRACT_BITS-1)); + for (i = len&3; i--; ) + { + *(vector++) <<= scalefactor; + } + for (i = len>>2; i--; ) + { + *(vector++) <<= scalefactor; + *(vector++) <<= scalefactor; + *(vector++) <<= scalefactor; + *(vector++) <<= scalefactor; + } + } else { + INT negScalefactor = fixmin_I(-scalefactor,(INT)DFRACT_BITS-1); + for (i = len&3; i--; ) + { + *(vector++) >>= negScalefactor; + } + for (i = len>>2; i--; ) + { + *(vector++) >>= negScalefactor; + *(vector++) >>= negScalefactor; + *(vector++) >>= negScalefactor; + *(vector++) >>= negScalefactor; + } + } +} +#endif + +#ifndef FUNCTION_scaleValues_DBL +/*! + * + * \brief Multiply input vector by \f$ 2^{scalefactor} \f$ + * \param len must be larger than 4 + * \return void + * + */ +#define FUNCTION_scaleValues_DBL +SCALE_INLINE +void scaleValues(FIXP_DBL *vector, /*!< Vector */ + INT len, /*!< Length */ + INT scalefactor /*!< Scalefactor */ + ) +{ + INT i; + + /* Return if scalefactor is Zero */ + if (scalefactor==0) return; + + if(scalefactor > 0){ + scalefactor = fixmin_I(scalefactor,(INT)DFRACT_BITS-1); + for (i = len&3; i--; ) + { + *(vector++) <<= scalefactor; + } + for (i = len>>2; i--; ) + { + *(vector++) <<= scalefactor; + *(vector++) <<= scalefactor; + *(vector++) <<= scalefactor; + *(vector++) <<= scalefactor; + } + } else { + INT negScalefactor = fixmin_I(-scalefactor,(INT)DFRACT_BITS-1); + for (i = len&3; i--; ) + { + *(vector++) >>= negScalefactor; + } + for (i = len>>2; i--; ) + { + *(vector++) >>= negScalefactor; + *(vector++) >>= negScalefactor; + *(vector++) >>= negScalefactor; + *(vector++) >>= negScalefactor; + } + } +} +#endif + +#ifndef FUNCTION_scaleValues_DBLDBL +/*! + * + * \brief Multiply input vector src by \f$ 2^{scalefactor} \f$ + * and place result into dst + * \param dst detination buffer + * \param src source buffer + * \param len must be larger than 4 + * \param scalefactor amount of left shifts to be applied + * \return void + * + */ +#define FUNCTION_scaleValues_DBLDBL +SCALE_INLINE +void scaleValues(FIXP_DBL *dst, /*!< dst Vector */ + const FIXP_DBL *src, /*!< src Vector */ + INT len, /*!< Length */ + INT scalefactor /*!< Scalefactor */ + ) +{ + INT i; + + /* Return if scalefactor is Zero */ + if (scalefactor==0) { + if (dst != src) + FDKmemmove(dst, src, len*sizeof(FIXP_DBL)); + } + else { + + if(scalefactor > 0){ + scalefactor = fixmin_I(scalefactor,(INT)DFRACT_BITS-1); + for (i = len&3; i--; ) + { + *(dst++) = *(src++) << scalefactor; + } + for (i = len>>2; i--; ) + { + *(dst++) = *(src++) << scalefactor; + *(dst++) = *(src++) << scalefactor; + *(dst++) = *(src++) << scalefactor; + *(dst++) = *(src++) << scalefactor; + } + } else { + INT negScalefactor = fixmin_I(-scalefactor,(INT)DFRACT_BITS-1); + for (i = len&3; i--; ) + { + *(dst++) = *(src++) >> negScalefactor; + } + for (i = len>>2; i--; ) + { + *(dst++) = *(src++) >> negScalefactor; + *(dst++) = *(src++) >> negScalefactor; + *(dst++) = *(src++) >> negScalefactor; + *(dst++) = *(src++) >> negScalefactor; + } + } + } +} +#endif + +#ifndef FUNCTION_scaleValuesWithFactor_DBL +/*! + * + * \brief Multiply input vector by \f$ 2^{scalefactor} \f$ + * \param len must be larger than 4 + * \return void + * + */ +#define FUNCTION_scaleValuesWithFactor_DBL +SCALE_INLINE +void scaleValuesWithFactor( + FIXP_DBL *vector, + FIXP_DBL factor, + INT len, + INT scalefactor + ) +{ + INT i; + + /* Compensate fMultDiv2 */ + scalefactor++; + + if(scalefactor > 0){ + scalefactor = fixmin_I(scalefactor,(INT)DFRACT_BITS-1); + for (i = len&3; i--; ) + { + *vector = fMultDiv2(*vector, factor) << scalefactor; + vector++; + } + for (i = len>>2; i--; ) + { + *vector = fMultDiv2(*vector, factor) << scalefactor; vector++; + *vector = fMultDiv2(*vector, factor) << scalefactor; vector++; + *vector = fMultDiv2(*vector, factor) << scalefactor; vector++; + *vector = fMultDiv2(*vector, factor) << scalefactor; vector++; + } + } else { + INT negScalefactor = fixmin_I(-scalefactor,(INT)DFRACT_BITS-1); + for (i = len&3; i--; ) + { + *vector = fMultDiv2(*vector, factor) >> negScalefactor; + vector++; + } + for (i = len>>2; i--; ) + { + *vector = fMultDiv2(*vector, factor) >> negScalefactor; vector++; + *vector = fMultDiv2(*vector, factor) >> negScalefactor; vector++; + *vector = fMultDiv2(*vector, factor) >> negScalefactor; vector++; + *vector = fMultDiv2(*vector, factor) >> negScalefactor; vector++; + } + } +} +#endif /* FUNCTION_scaleValuesWithFactor_DBL */ + + +/******************************************* + +IMPORTANT NOTE for usage of getScalefactor() + +If the input array contains negative values too, then these functions may sometimes return +the actual maximum value minus 1, due to the nature of the applied algorithm. +So be careful with possible fractional -1 values that may lead to overflows when being fPow2()'ed. + +********************************************/ + + + +#ifndef FUNCTION_getScalefactorShort +/*! + * + * \brief Calculate max possible scale factor for input vector of shorts + * + * \return Maximum scale factor / possible left shift + * + */ +#define FUNCTION_getScalefactorShort +SCALE_INLINE +INT getScalefactorShort(const SHORT *vector, /*!< Pointer to input vector */ + INT len /*!< Length of input vector */ + ) +{ + INT i; + SHORT temp, maxVal = 0; + + for(i=len;i!=0;i--){ + temp = (SHORT)(*vector++); + maxVal |= (temp^(temp>>(SHORT_BITS-1))); + } + + return fixmax_I((INT)0,(INT)(fixnormz_D((INT)maxVal) - (INT)1 - (INT)(DFRACT_BITS - SHORT_BITS))); +} +#endif + +#ifndef FUNCTION_getScalefactorPCM +/*! + * + * \brief Calculate max possible scale factor for input vector of shorts + * + * \return Maximum scale factor + * + */ +#define FUNCTION_getScalefactorPCM +SCALE_INLINE +INT getScalefactorPCM(const INT_PCM *vector, /*!< Pointer to input vector */ + INT len, /*!< Length of input vector */ + INT stride + ) +{ + INT i; + INT_PCM temp, maxVal = 0; + + for(i=len;i!=0;i--){ + temp = (INT_PCM)(*vector); vector+=stride; + maxVal |= (temp^(temp>>((sizeof(INT_PCM)*8)-1))); + } + return fixmax_I((INT)0,(INT)(fixnormz_D((INT)maxVal) - (INT)1 - (INT)(DFRACT_BITS - SAMPLE_BITS))); +} +#endif + +#ifndef FUNCTION_getScalefactorShort +/*! + * + * \brief Calculate max possible scale factor for input vector of shorts + * \param stride, item increment between verctor members. + * \return Maximum scale factor + * + */ +#define FUNCTION_getScalefactorShort +SCALE_INLINE +INT getScalefactorShort(const SHORT *vector, /*!< Pointer to input vector */ + INT len, /*!< Length of input vector */ + INT stride + ) +{ + INT i; + SHORT temp, maxVal = 0; + + for(i=len;i!=0;i--){ + temp = (SHORT)(*vector); vector+=stride; + maxVal |= (temp^(temp>>(SHORT_BITS-1))); + } + + return fixmax_I((INT)0,(INT)(fixnormz_D((INT)maxVal) - (INT)1 - (INT)(DFRACT_BITS - SHORT_BITS))); +} +#endif + +#ifndef FUNCTION_getScalefactor_DBL +/*! + * + * \brief Calculate max possible scale factor for input vector + * + * \return Maximum scale factor + * + * This function can constitute a significant amount of computational complexity - very much depending on the + * bitrate. Since it is a rather small function, effective assembler optimization might be possible. + * + */ +#define FUNCTION_getScalefactor_DBL +SCALE_INLINE +INT getScalefactor(const FIXP_DBL *vector, /*!< Pointer to input vector */ + INT len) /*!< Length of input vector */ +{ + INT i; + FIXP_DBL temp, maxVal = (FIXP_DBL)0; + + for(i=len;i!=0;i--){ + temp = (LONG)(*vector++); + maxVal |= (FIXP_DBL)((LONG)temp^(LONG)(temp>>(DFRACT_BITS-1))); + } + + return fixmax_I((INT)0,(INT)(fixnormz_D(maxVal) - 1)); +} +#endif + +#ifndef FUNCTION_getScalefactor_SGL +#define FUNCTION_getScalefactor_SGL +SCALE_INLINE +INT getScalefactor(const FIXP_SGL *vector, /*!< Pointer to input vector */ + INT len) /*!< Length of input vector */ +{ + INT i; + SHORT temp, maxVal = (FIXP_SGL)0; + + for(i=len;i!=0;i--){ + temp = (SHORT)(*vector++); + maxVal |= (temp^(temp>>(FRACT_BITS-1))); + } + + return fixmax_I((INT)0,(INT)(fixnormz_D(FX_SGL2FX_DBL((FIXP_SGL)maxVal)) - 1)); +} +#endif + diff --git a/libMpegTPDec/Android.mk b/libMpegTPDec/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/libMpegTPDec/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/libMpegTPDec/include/mpegFileRead.h b/libMpegTPDec/include/mpegFileRead.h new file mode 100644 index 0000000..c86b5f9 --- /dev/null +++ b/libMpegTPDec/include/mpegFileRead.h @@ -0,0 +1,132 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: Bitstream data provider for MP4 decoders + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "machine_type.h" +#include "FDK_audio.h" + +#define MPFREAD_MP4FF_DISABLE + +#ifndef MPFREAD_MP4FF_DISABLE + /*!< If MPFREAD_MP4FF_ENABLE is set, include support for MPEG ISO fileformat. + If not set, no .mp4, .m4a and .3gp files can be used for input. */ + #define MPFREAD_MP4FF_ENABLE +#endif + +/* maximum number of layers which can be read */ +/* shall equal max number of layers read by iisisoff */ +#define FILEREAD_MAX_LAYERS (2) + +typedef struct STRUCT_FILEREAD *HANDLE_FILEREAD; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Open an MPEG audio file and try to detect its format. + * \param filename String of the filename to be opened. + * \param fileFormat Skip file format detection and use given format if fileFormat != FF_UNKNOWN. + Else store detected format into *fileFmt. + * \param transportType Skip transport type detection and use given format if transportType != TT_UNKNOWN. + Else store detected format into *fileFmt. + * \param conf Pointer to unsigned char to hold the AudioSpecificConfig of the input file, if + any (MPEG 4 file format). In case of RAW LATM it holds the StreamMuxConfig. + * \param confSize Pointer to an integer, where the length of the ASC or SMC (in case of RAW LATM) + is stored to. + * \return MPEG file read handle. + */ +HANDLE_FILEREAD mpegFileRead_Open( const char *filename, + FILE_FORMAT fileFormat, + TRANSPORT_TYPE transportType, + UCHAR *conf[], + UINT confSize[], + INT *noOfLayers + ); + +/** + * \brief Get the file format of the input file. + * \param hDataSrc MPEG file read handle. + * \return File format of the input file. + */ +FILE_FORMAT mpegFileRead_GetFileFormat(HANDLE_FILEREAD hDataSrc); + +/** + * \brief Get the transport type of the input file. + * \param hDataSrc MPEG file read handle. + * \return Transport type of the input file. + */ +TRANSPORT_TYPE mpegFileRead_GetTransportType(HANDLE_FILEREAD hDataSrc); + +/** + * \brief Read data from MPEG file. In case of packet file, read one packet, in case + * of streaming file with embedded synchronisation layer (LOAS/ADTS...), just + * fill the buffer. + * + * \param hMpegFile MPEG file read handle. + * \param inBuffer Pointer to input buffer. + * \param bufferSize Size of input buffer. + * \param bytesValid Number of bytes that were read. + * \return 0 on success, -1 if unsupported file format or file read error. + */ +int mpegFileRead_Read( HANDLE_FILEREAD hMpegFile, + UCHAR *inBuffer[], + UINT bufferSize, + UINT *bytesValid + ); + +/** + * \brief Seek in file from origin by given offset in frames. + * \param hMpegFile MPEG file read handle. + * \param origin If 0, the origin is the file beginning (absolute seek). + * If 1, the origin is the current position (relative seek). + * \param offset The amount of frames to seek from the given origin. + * \return 0 on sucess, -1 if offset < 0 or file read error. + */ +int mpegFileRead_seek( HANDLE_FILEREAD hMpegFile, + INT origin, + INT offset + ); + +/** + * \brief Get file position in percent. + * \param hMpegFile MPEG file read handle. + * \return File position in percent. + */ +int mpegFileRead_getPercent(HANDLE_FILEREAD hMpegFile); + + +/** + * \brief Close MPEG audio file. + * \param hMpegFile Mpeg file read handle. + * \return 0 on sucess. + */ +int mpegFileRead_Close(HANDLE_FILEREAD *hMpegFile); + +#ifdef __cplusplus +} +#endif diff --git a/libMpegTPDec/include/tp_data.h b/libMpegTPDec/include/tp_data.h new file mode 100644 index 0000000..6149608 --- /dev/null +++ b/libMpegTPDec/include/tp_data.h @@ -0,0 +1,277 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: MPEG Transport data tables + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#ifndef __TP_DATA_H__ +#define __TP_DATA_H__ + +#include "machine_type.h" +#include "FDK_audio.h" +#include "FDK_bitstream.h" + +/* + * Configuration + */ +#define TP_GA_ENABLE +/* #define TP_CELP_ENABLE */ +/* #define TP_HVXC_ENABLE */ +/* #define TP_SLS_ENABLE */ +#define TP_ELD_ENABLE +/* #define TP_USAC_ENABLE */ +/* #define TP_RSVD50_ENABLE */ + +#if defined(TP_GA_ENABLE) || defined(TP_SLS_ENABLE) +#define TP_PCE_ENABLE /**< Enable full PCE support */ +#endif + +/** + * ProgramConfig struct. + */ +/* ISO/IEC 14496-3 4.4.1.1 Table 4.2 Program config element */ +#define PC_FSB_CHANNELS_MAX 16 /* Front/Side/Back channels */ +#define PC_LFE_CHANNELS_MAX 4 +#define PC_ASSOCDATA_MAX 8 +#define PC_CCEL_MAX 16 /* CC elements */ +#define PC_COMMENTLENGTH 256 + +typedef struct +{ +#ifdef TP_PCE_ENABLE + /* PCE bitstream elements: */ + UCHAR ElementInstanceTag; + UCHAR Profile; + UCHAR SamplingFrequencyIndex; + UCHAR NumFrontChannelElements; + UCHAR NumSideChannelElements; + UCHAR NumBackChannelElements; + UCHAR NumLfeChannelElements; + UCHAR NumAssocDataElements; + UCHAR NumValidCcElements; + + UCHAR MonoMixdownPresent; + UCHAR MonoMixdownElementNumber; + + UCHAR StereoMixdownPresent; + UCHAR StereoMixdownElementNumber; + + UCHAR MatrixMixdownIndexPresent; + UCHAR MatrixMixdownIndex; + UCHAR PseudoSurroundEnable; + + UCHAR FrontElementIsCpe[PC_FSB_CHANNELS_MAX]; + UCHAR FrontElementTagSelect[PC_FSB_CHANNELS_MAX]; + + UCHAR SideElementIsCpe[PC_FSB_CHANNELS_MAX]; + UCHAR SideElementTagSelect[PC_FSB_CHANNELS_MAX]; + + UCHAR BackElementIsCpe[PC_FSB_CHANNELS_MAX]; + UCHAR BackElementTagSelect[PC_FSB_CHANNELS_MAX]; + + UCHAR LfeElementTagSelect[PC_LFE_CHANNELS_MAX]; + + UCHAR AssocDataElementTagSelect[PC_ASSOCDATA_MAX]; + + UCHAR CcElementIsIndSw[PC_CCEL_MAX]; + UCHAR ValidCcElementTagSelect[PC_CCEL_MAX]; + + UCHAR CommentFieldBytes; + UCHAR Comment[PC_COMMENTLENGTH]; +#endif /* TP_PCE_ENABLE */ + + /* Helper variables for administration: */ + UCHAR isValid; /*!< Flag showing if PCE has been read successfully. */ + UCHAR NumChannels; /*!< Amount of audio channels summing all channel elements including LFEs */ + UCHAR NumEffectiveChannels; /*!< Amount of audio channels summing only SCEs and CPEs */ + UCHAR elCounter; + +} CProgramConfig; + +typedef enum { + ASCEXT_UNKOWN = -1, + ASCEXT_SBR = 0x2b7, + ASCEXT_PS = 0x548, + ASCEXT_MPS = 0x76a, + ASCEXT_SAOC = 0x7cb, + ASCEXT_LDMPS = 0x7cc + +} TP_ASC_EXTENSION_ID; + +#ifdef TP_GA_ENABLE +/** + * GaSpecificConfig struct + */ +typedef struct { + UINT m_frameLengthFlag ; + UINT m_dependsOnCoreCoder ; + UINT m_coreCoderDelay ; + + UINT m_extensionFlag ; + UINT m_extensionFlag3 ; + + UINT m_layer; + UINT m_numOfSubFrame; + UINT m_layerLength; + +} CSGaSpecificConfig; +#endif /* TP_GA_ENABLE */ + + + + +#ifdef TP_ELD_ENABLE + +typedef enum { + ELDEXT_TERM = 0x0, /* Termination tag */ + ELDEXT_SAOC = 0x1, /* SAOC config */ + ELDEXT_LDSAC = 0x2 /* LD MPEG Surround config */ + /* reserved */ +} ASC_ELD_EXT_TYPE; + +typedef struct { + UCHAR m_frameLengthFlag; + + UCHAR m_sbrPresentFlag; + UCHAR m_useLdQmfTimeAlign; /* Use LD-MPS QMF in SBR to achive time alignment */ + UCHAR m_sbrSamplingRate; + UCHAR m_sbrCrcFlag; + +} CSEldSpecificConfig; +#endif /* TP_ELD_ENABLE */ + + + + +/** + * Audio configuration struct, suitable for encoder and decoder configuration. + */ +typedef struct { + + /* XYZ Specific Data */ + union { +#ifdef TP_GA_ENABLE + CSGaSpecificConfig m_gaSpecificConfig; /**< General audio specific configuration. */ +#endif /* TP_GA_ENABLE */ +#ifdef TP_ELD_ENABLE + CSEldSpecificConfig m_eldSpecificConfig; /**< ELD specific configuration. */ +#endif /* TP_ELD_ENABLE */ + } m_sc; + + /* Common ASC parameters */ +#ifdef TP_PCE_ENABLE + CProgramConfig m_progrConfigElement; /**< Program configuration. */ +#endif /* TP_PCE_ENABLE */ + + AUDIO_OBJECT_TYPE m_aot; /**< Audio Object Type. */ + UINT m_samplingFrequency; /**< Samplerate. */ + UINT m_samplesPerFrame; /**< Amount of samples per frame. */ + UINT m_directMapping; /**< Document this please !! */ + + AUDIO_OBJECT_TYPE m_extensionAudioObjectType; /**< Audio object type */ + UINT m_extensionSamplingFrequency; /**< Samplerate */ + + SCHAR m_channelConfiguration; /**< Channel configuration index */ + + SCHAR m_epConfig; /**< Error protection index */ + SCHAR m_vcb11Flag; /**< aacSectionDataResilienceFlag */ + SCHAR m_rvlcFlag; /**< aacScalefactorDataResilienceFlag */ + SCHAR m_hcrFlag; /**< aacSpectralDataResilienceFlag */ + + SCHAR m_sbrPresentFlag; /**< Flag indicating the presence of SBR data in the bitstream */ + SCHAR m_psPresentFlag; /**< Flag indicating the presence of parametric stereo data in the bitstream */ + UCHAR m_samplingFrequencyIndex; /**< Samplerate index */ + UCHAR m_extensionSamplingFrequencyIndex; /**< Samplerate index */ + SCHAR m_extensionChannelConfiguration; /**< Channel configuration index */ + +} CSAudioSpecificConfig; + +typedef INT (*cbUpdateConfig_t)(void*, const CSAudioSpecificConfig*); +typedef INT (*cbSsc_t)( + void*, HANDLE_FDK_BITSTREAM, + const AUDIO_OBJECT_TYPE coreCodec, + const INT samplingFrequency, + const INT muxMode, + const INT configBytes + ); +typedef INT (*cbSbr_t)( + void * self, + HANDLE_FDK_BITSTREAM hBs, + const INT sampleRateIn, + const INT sampleRateOut, + const INT samplesPerFrame, + const AUDIO_OBJECT_TYPE coreCodec, + const MP4_ELEMENT_ID elementID, + const INT elementIndex + ); + +typedef struct { + cbUpdateConfig_t cbUpdateConfig; /*!< Function pointer for Config change notify callback. */ + void *cbUpdateConfigData; /*!< User data pointer for Config change notify callback. */ + cbSsc_t cbSsc; /*!< Function pointer for SSC parser callback. */ + void *cbSscData; /*!< User data pointer for SSC parser callback. */ + cbSbr_t cbSbr; /*!< Function pointer for SBR header parser callback. */ + void *cbSbrData; /*!< User data pointer for SBR header parser callback. */ +} CSTpCallBacks; + +static const UINT SamplingRateTable[] = +{ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, + 0 +}; + +static inline +int getSamplingRateIndex( UINT samplingRate ) +{ + UINT sf_index, tableSize=sizeof(SamplingRateTable)/sizeof(UINT); + + for (sf_index=0; sf_indextableSize-1) { + return tableSize-1; + } + + return sf_index; +} + +/* + * Get Channel count from channel configuration + */ +static inline int getNumberOfTotalChannels(int channelConfig) +{ + if (channelConfig > 0 && channelConfig < 8) + return (channelConfig == 7)?8:channelConfig; + else + return 0; +} + +static inline +int getNumberOfEffectiveChannels(const int channelConfig) +{ + const int n[] = {0,1,2,3,4,5,5,7}; + return n[channelConfig]; +} + +#endif /* __TP_DATA_H__ */ diff --git a/libMpegTPDec/include/tpdec_lib.h b/libMpegTPDec/include/tpdec_lib.h new file mode 100644 index 0000000..f32f6d8 --- /dev/null +++ b/libMpegTPDec/include/tpdec_lib.h @@ -0,0 +1,430 @@ +/************************** MPEG-4 Transport Decoder *********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: MPEG Transport decoder + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef __TPDEC_LIB_H__ +#define __TPDEC_LIB_H__ + +#include "tp_data.h" + +#include "FDK_bitstream.h" + +#define TRANSPORTDEC_INBUF_SIZE ( 8192 ) /*!< Size is in bytes. + Set the transport input buffer size carefully and + assure that it fulfills the requirements of the + supported transport format(s). */ + +typedef enum { + TRANSPORTDEC_OK = 0, /*!< All fine. */ + + /* Synchronization errors. Wait for new input data and try again. */ + tpdec_sync_error_start = 0x100, + TRANSPORTDEC_NOT_ENOUGH_BITS, /*!< Out of bits. Provide more bits and try again. */ + TRANSPORTDEC_SYNC_ERROR, /*!< No sync was found or sync got lost. Keep trying. */ + tpdec_sync_error_end, + + /* Decode errors. Mostly caused due to bit errors. */ + tpdec_decode_error_start = 0x400, + TRANSPORTDEC_PARSE_ERROR, /*!< Bitstream data showed inconsistencies (wrong syntax). */ + TRANSPORTDEC_UNSUPPORTED_FORMAT, /*!< Unsupported format or feature found in the bitstream data. */ + TRANSPORTDEC_CRC_ERROR, /*!< CRC error encountered in bitstream data. */ + tpdec_decode_error_end, + + /* Fatal errors. Stop immediately on one of these errors! */ + tpdec_fatal_error_start = 0x200, + TRANSPORTDEC_UNKOWN_ERROR, /*!< An unknown error occured. */ + TRANSPORTDEC_INVALID_PARAMETER, /*!< An invalid parameter was passed to a function. */ + TRANSPORTDEC_NEED_TO_RESTART, /*!< The decoder needs to be restarted, since the requiered + configuration change cannot be performed. */ + tpdec_fatal_error_end + +} TRANSPORTDEC_ERROR; + + +/** Macro to identify decode errors. */ +#define TPDEC_IS_DECODE_ERROR(err) ( ((err>=tpdec_decode_error_start) && (err<=tpdec_decode_error_end)) ? 1 : 0) +/** Macro to identify fatal errors. */ +#define TPDEC_IS_FATAL_ERROR(err) ( ((err>=tpdec_fatal_error_start) && (err<=tpdec_fatal_error_end)) ? 1 : 0) + + +/** + * \brief Parameter identifiers for transportDec_SetParam() + */ +typedef enum { + TPDEC_PARAM_MINIMIZE_DELAY = 1, /** Delay minimization strategy. 0: none, 1: discard as many frames as possible. */ + TPDEC_PARAM_EARLY_CONFIG, /** Enable early config discovery. */ + TPDEC_PARAM_IGNORE_BUFFERFULLNESS, /** Ignore buffer fullness. */ + TPDEC_PARAM_SET_BITRATE, /** Set average bit rate for bit stream interruption frame misses estimation. */ + TPDEC_PARAM_RESET, /** Reset transport decoder instance status. */ + TPDEC_PARAM_BURST_PERIOD /** Set data reception burst period in mili seconds. */ +} TPDEC_PARAM; + +/* ISO/IEC 14496-3 4.4.1.1 Table 4.2 Program config element */ +#define PC_FSB_CHANNELS_MAX 16 /* Front/Side/Back channels */ +#define PC_LFE_CHANNELS_MAX 4 +#define PC_ASSOCDATA_MAX 8 +#define PC_CCEL_MAX 16 /* CC elements */ +#define PC_COMMENTLENGTH 256 + + +/*! + \brief Reset Program Config Element. + \param pPce Program Config Element structure. + \return void +*/ +void CProgramConfig_Reset ( CProgramConfig *pPce ); + +/*! + \brief Initialize Program Config Element. + \param pPce Program Config Element structure. + \return void +*/ +void CProgramConfig_Init ( CProgramConfig *pPce ); + +/*! + \brief Inquire state of present Program Config Element structure. + \param pPce Program Config Element structure. + \return 1 if the PCE structure is filled correct, + 0 if no valid PCE present. +*/ +int CProgramConfig_IsValid ( const CProgramConfig *pPce ); + +#ifdef TP_PCE_ENABLE +/*! + \brief Read Program Config Element. + \param pPce Program Config Element structure. + \param bs Bitstream buffer to read from. + \param alignAnchor Align bitstream to alignAnchor bits after all read operations. + \return void +*/ +void CProgramConfig_Read ( CProgramConfig *pPce, + HANDLE_FDK_BITSTREAM bs, + UINT alignAnchor ); +#endif /* TP_PCE_ENABLE */ + +/** + * \brief Lookup and verify a given element. The decoder calls this + * method with every new element ID found in the bitstream. + * + * \param pPce A valid Program config structure. + * \param tag Tag of the current element to be looked up. + * \param channelIdx The current channel count of the decoder parser. + * \param chMapping Array to store the canonical channel mapping indexes. + * \param chType Array to store the audio channel type. + * \param chIndex Array to store the individual audio channel type index. + * \param elMapping Pointer where the canonical element index is stored. + * \param elType The element id of the current element to be looked up. + * + * \return Non-zero if the element belongs to the current program, zero + * if it does not. + */ +int CProgramConfig_LookupElement( + CProgramConfig *pPce, + const UINT channelConfig, + const UINT tag, + const UINT channelIdx, + UCHAR chMapping[], + AUDIO_CHANNEL_TYPE chType[], + UCHAR chIndex[], + UCHAR *elMapping, + MP4_ELEMENT_ID elList[], + MP4_ELEMENT_ID elType + ); + +/** + * \brief Get table of elements in canonical order. + * \param pPce A valid program config structure. + * \param table An array where the element IDs are stored. + * \return Total element count including all SCE, CPE and LFE. + */ +int CProgramConfig_GetElementTable( const CProgramConfig *pPce, + MP4_ELEMENT_ID table[] ); + +/** + * \brief Initialize a given AudioSpecificConfig structure. + * \param pAsc A pointer to an allocated CSAudioSpecificConfig struct. + * \return void + */ +void AudioSpecificConfig_Init(CSAudioSpecificConfig *pAsc); + +/** + * \brief Parse a AudioSpecificConfig from a given bitstream handle. + * + * \param pAsc A pointer to an allocated CSAudioSpecificConfig struct. + * \param hBs Bitstream handle. + * \param fExplicitBackwardCompatible Do explicit backward compatibility parsing if set (flag). + * \param cb pointer to structure holding callback information + * + * \return Total element count including all SCE, CPE and LFE. + */ +TRANSPORTDEC_ERROR AudioSpecificConfig_Parse( + CSAudioSpecificConfig *pAsc, + HANDLE_FDK_BITSTREAM hBs, + int fExplicitBackwardCompatible, + CSTpCallBacks *cb + ); + +/* CELP stuff */ +enum { + MPE = 0, + RPE = 1, + fs8KHz = 0, + fs16KHz = 1 +}; + +/* Defintion of flags that can be passed to transportDecOpen() */ +#define TP_FLAG_MPEG4 1 + +/* Capability flags */ +#define CAPF_TPDEC_ADIF 0x00001000 /**< Flag indicating support for ADIF transport format. */ +#define CAPF_TPDEC_ADTS 0x00002000 /**< Flag indicating support for ADTS transport format. */ +#define CAPF_TPDEC_LOAS 0x00004000 /**< Flag indicating support for LOAS transport format. */ +#define CAPF_TPDEC_LATM 0x00008000 /**< Flag indicating support for LATM transport format. */ +#define CAPF_TPDEC_RAWPACKETS 0x00010000 /**< Flag indicating support for raw packets transport format. */ + +typedef struct TRANSPORTDEC *HANDLE_TRANSPORTDEC; + + +/** + * \brief Configure Transport Decoder via a binary coded AudioSpecificConfig or StreamMuxConfig. + * The previously requested configuration callback will be called as well. The buffer conf + * must containt a SMC in case of LOAS/LATM transport format, and an ASC elseways. + * + * \param hTp Handle of a transport decoder. + * \param conf UCHAR buffer of the binary coded config (ASC or SMC). + * \param length The length in bytes of the conf buffer. + * + * \return Error code. + */ +TRANSPORTDEC_ERROR transportDec_OutOfBandConfig( const HANDLE_TRANSPORTDEC hTp, + UCHAR *conf, + const UINT length, + const UINT layer ); + +/** + * \brief Open Transport medium for reading. + * + * \param transportDecFmt Format of the transport decoder medium to be accessed. + * \param flags Transport decoder flags. Currently only TP_FLAG_MPEG4, which signals a + * MPEG4 capable decoder (relevant for ADTS only). + * + * \return A pointer to a valid and allocated HANDLE_TRANSPORTDEC or a null pointer on failure. + */ +HANDLE_TRANSPORTDEC transportDec_Open( TRANSPORT_TYPE transportDecFmt, + const UINT flags ); + +/** + * \brief Register configuration change callback. + * \param hTp Handle of transport decoder. + * \param cbUpdateConfig Pointer to a callback function to handle audio config changes. + * \param user_data void pointer for user data passed to the callback as first parameter. + * \return 0 on success. + */ +int transportDec_RegisterAscCallback ( + HANDLE_TRANSPORTDEC hTp, + const cbUpdateConfig_t cbUpdateConfig, + void* user_data ); + +/** + * \brief Register SSC parser callback. + * \param hTp Handle of transport decoder. + * \param cbUpdateConfig Pointer to a callback function to handle SSC parsing. + * \param user_data void pointer for user data passed to the callback as first parameter. + * \return 0 on success. + */ +int transportDec_RegisterSscCallback ( + HANDLE_TRANSPORTDEC hTp, + const cbSsc_t cbSscParse, + void* user_data ); + +/** + * \brief Register SBR header parser callback. + * \param hTp Handle of transport decoder. + * \param cbUpdateConfig Pointer to a callback function to handle SBR header parsing. + * \param user_data void pointer for user data passed to the callback as first parameter. + * \return 0 on success. + */ +int transportDec_RegisterSbrCallback( HANDLE_TRANSPORTDEC hTpDec, const cbSbr_t cbSbr, void* user_data); + +/** + * \brief Fill internal input buffer with bitstream data from the external input buffer. + * The function only copies such data as long as the decoder-internal input buffer is not full. + * So it grabs whatever it can from pBuffer and returns information (bytesValid) so that at a + * subsequent call of %transportDec_FillData(), the right position in pBuffer can be determined to + * grab the next data. + * + * \param hTp Handle of transportDec. + * \param pBuffer Pointer to external input buffer. + * \param bufferSize Size of external input buffer. This argument is required because decoder-internally + * we need the information to calculate the offset to pBuffer, where the next + * available data is, which is then fed into the decoder-internal buffer (as much + * as possible). Our example framework implementation fills the buffer at pBuffer + * again, once it contains no available valid bytes anymore (meaning bytesValid equal 0). + * \param bytesValid Number of bitstream bytes in the external bitstream buffer that have not yet been + * copied into the decoder's internal bitstream buffer by calling this function. + * The value is updated according to the amount of newly copied bytes. + * \param layer The layer the bitstream belongs to. + * \return Error code. + */ +TRANSPORTDEC_ERROR transportDec_FillData( + const HANDLE_TRANSPORTDEC hTp, + UCHAR *pBuffer, + const UINT bufferSize, + UINT *pBytesValid, + const INT layer ); + +/** + * \brief Get transportDec bitstream handle. + * \param hTp Pointer to a transport decoder handle. + * \return HANDLE_FDK_BITSTREAM bitstream handle. + */ +HANDLE_FDK_BITSTREAM transportDec_GetBitstream ( const HANDLE_TRANSPORTDEC hTp, const UINT layer ); + +/** + * \brief Get transport format. + * \param hTp Pointer to a transport decoder handle. + * \return The transport format. + */ +TRANSPORT_TYPE transportDec_GetFormat ( const HANDLE_TRANSPORTDEC hTp ); + +/** + * \brief Get the current buffer fullness value. + * + * \param hTp Handle of a transport decoder. + * + * \return Buffer fullness + */ +INT transportDec_GetBufferFullness( const HANDLE_TRANSPORTDEC hTp ); + +/** + * \brief Close and deallocate transportDec. + * \param phTp Pointer to a previously allocated transport decoder handle. + * \return void + */ +void transportDec_Close ( HANDLE_TRANSPORTDEC *phTp ); + +/** + * \brief Read one access unit from the transportDec medium. + * \param hTp Handle of transportDec. + * \param length On return, this value is overwritten with the actual access unit length in bits. + * Set to -1 if length is unknown. + * \return Error code. + */ +TRANSPORTDEC_ERROR transportDec_ReadAccessUnit ( const HANDLE_TRANSPORTDEC hTp, const UINT layer ); + +/** + * \brief Get the remaining amount of bits of the current access unit. The result + * can be below zero, meaning that too many bits have been read. + * \param hTp Handle of transportDec. + * \return amount of remaining bits. + */ +INT transportDec_GetAuBitsRemaining( const HANDLE_TRANSPORTDEC hTp, const UINT layer ); + +/** + * \brief Get the total amount of bits of the current access unit. + * \param hTp Handle of transportDec. + * \return amount of total bits. + */ +INT transportDec_GetAuBitsTotal( const HANDLE_TRANSPORTDEC hTp, const UINT layer ); + +/** + * \brief This function is required to be called when the decoder has finished parsing + * one Access Unit for bitstream housekeeping. + * \param hTp Transport Handle. + * \return Error code. + */ +TRANSPORTDEC_ERROR transportDec_EndAccessUnit ( const HANDLE_TRANSPORTDEC hTp ); + +/** + * \brief Obtain the amount of missing access units if applicable in case of + * a bit stream synchronization error. Each time transportDec_ReadAccessUnit() + * returns TRANSPORTDEC_SYNC_ERROR this function can be called to retrieve an estimate + * of the amount of missing access units. This works only in case of constant average + * bit rate (has to be known) and if the parameter TPDEC_PARAM_SET_BITRATE has been set + * accordingly. + * \param hTp Transport Handle. + * \param pNAccessUnits pointer to a memory location where the estimated lost frame count will be stored into. + * \return Error code. + */ +TRANSPORTDEC_ERROR transportDec_GetMissingAccessUnitCount ( INT *pNAccessUnits, HANDLE_TRANSPORTDEC hTp ); + + +/** + * \brief Set a given setting. + * \param hTp Transport Handle. + * \param param Identifier of the parameter to be changed. + * \param value Value for the parameter to be changed. + * \return Error code. + */ +TRANSPORTDEC_ERROR transportDec_SetParam ( const HANDLE_TRANSPORTDEC hTp, + const TPDEC_PARAM param, + const INT value ); + +/** + * \brief Get number of subframes (for LATM or ADTS) + * \param hTp Transport Handle. + * \return Number of ADTS/LATM subframes (return 1 for all other transport types). + */ +UINT transportDec_GetNrOfSubFrames(HANDLE_TRANSPORTDEC hTp); + + +/** + * \brief Get info structure of transport decoder library. + * \param info A pointer to an allocated LIB_INFO struct. + * \return Error code. + */ +TRANSPORTDEC_ERROR transportDec_GetLibInfo( LIB_INFO *info ); + +/* ADTS CRC support */ + +/** + * \brief Set current bitstream position as start of a new data region. + * \param hTp Transport handle. + * \param mBits Size in bits of the data region. Set to 0 if it should not be of a fixed size. + * \return Data region ID, which should be used when calling transportDec_CrcEndReg(). + */ +int transportDec_CrcStartReg ( const HANDLE_TRANSPORTDEC hTp, + const INT mBits ); + +/** + * \brief Set end of data region. + * \param hTp Transport handle. + * \param reg Data region ID, opbtained from transportDec_CrcStartReg(). + * \return void + */ +void transportDec_CrcEndReg ( const HANDLE_TRANSPORTDEC hTp, + const INT reg ); + +/** + * \brief Calculate ADTS crc and check if it is correct. The ADTS checksum is held internally. + * \param hTp Transport handle. + * \return Return TRANSPORTDEC_OK if the CRC is ok, or error if CRC is not correct. + */ +TRANSPORTDEC_ERROR transportDec_CrcCheck ( const HANDLE_TRANSPORTDEC hTp ); + + +#endif /* #ifndef __TPDEC_LIB_H__ */ diff --git a/libMpegTPDec/src/Android.mk b/libMpegTPDec/src/Android.mk new file mode 100644 index 0000000..ae9096d --- /dev/null +++ b/libMpegTPDec/src/Android.mk @@ -0,0 +1,21 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + tpdec_adif.cpp \ + tpdec_adts.cpp \ + tpdec_asc.cpp \ + tpdec_latm.cpp \ + tpdec_lib.cpp + +LOCAL_CFLAGS := -DANDROID + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../../libSYS/include \ + $(LOCAL_PATH)/../../libFDK/include + +LOCAL_MODULE:= libMpegTPDec + +include $(BUILD_STATIC_LIBRARY) diff --git a/libMpegTPDec/src/mpegFileFormat.h b/libMpegTPDec/src/mpegFileFormat.h new file mode 100644 index 0000000..d780832 --- /dev/null +++ b/libMpegTPDec/src/mpegFileFormat.h @@ -0,0 +1,52 @@ +/*************************** Fraunhofer IIS FDK Tools *********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Oliver Moser + Description: bitstream format detection routines + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#if !defined(__BITSTREAM_FORMAT_H__) +#define __BITSTREAM_FORMAT_H__ + +#include "machine_type.h" +#include "FDK_audio.h" + +/** + * \brief Try to find out the format of a file, given the few first bytes. + * \param fileData pointer to a buffer holding the first bytes of a file. + * \param pAu pointer to UCHAR*, returns the address of the first AU found or NULL. + * \param length pointer to the length of the buffer fileData. Return length of first AU. + * \return the detected file format, or FF_UNKNOWN in case of failure. + */ +FILE_FORMAT GetFileFormat(UCHAR *fileData, UCHAR **pAu, UINT *length); + +/** + * \brief Try to find out the transport type contained in a given file. + * \param filename name of the file to be analysed. + * \param fileFormat pointer to a variable where the detected file format is stored into. + * \return the detected transport type or TT_UNKNOWN in case of failure. + */ +TRANSPORT_TYPE GetTransportType(const char* filename, FILE_FORMAT *fileFormat); + +#endif diff --git a/libMpegTPDec/src/tpdec_adif.cpp b/libMpegTPDec/src/tpdec_adif.cpp new file mode 100644 index 0000000..7c47ea3 --- /dev/null +++ b/libMpegTPDec/src/tpdec_adif.cpp @@ -0,0 +1,93 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: ADIF reader + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "tpdec_adif.h" + + +#include "FDK_bitstream.h" +#include "genericStds.h" + +TRANSPORTDEC_ERROR adifRead_DecodeHeader( + CAdifHeader *pAdifHeader, + CProgramConfig *pPce, + HANDLE_FDK_BITSTREAM bs + ) +{ + int i; + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + UINT startAnchor = FDKgetValidBits(bs); + + if ((INT)startAnchor < MIN_ADIF_HEADERLENGTH) { + return (TRANSPORTDEC_NOT_ENOUGH_BITS); + } + + if (FDKreadBits(bs,8) != 'A') { + return (TRANSPORTDEC_SYNC_ERROR); + } + if (FDKreadBits(bs,8) != 'D') { + return (TRANSPORTDEC_SYNC_ERROR); + } + if (FDKreadBits(bs,8) != 'I') { + return (TRANSPORTDEC_SYNC_ERROR); + } + if (FDKreadBits(bs,8) != 'F') { + return (TRANSPORTDEC_SYNC_ERROR); + } + + if ( (pAdifHeader->CopyrightIdPresent = FDKreadBits(bs,1)) != 0 ) + FDKpushBiDirectional(bs,72); /* CopyrightId */ + + + pAdifHeader->OriginalCopy = FDKreadBits(bs,1); + pAdifHeader->Home = FDKreadBits(bs,1); + pAdifHeader->BitstreamType = FDKreadBits(bs,1); + + /* pAdifHeader->BitRate = FDKreadBits(bs, 23); */ + pAdifHeader->BitRate = FDKreadBits(bs,16); + pAdifHeader->BitRate <<= 7; + pAdifHeader->BitRate |= FDKreadBits(bs,7); + + pAdifHeader->NumProgramConfigElements = FDKreadBits(bs,4) + 1; + + if (pAdifHeader->BitstreamType == 0) { + FDKpushBiDirectional(bs,20); /* adif_buffer_fullness */ + } + + /* Parse all PCEs but keep only one */ + for (i=0; i < pAdifHeader->NumProgramConfigElements; i++) + { + CProgramConfig_Read(pPce, bs, startAnchor); + } + + FDKbyteAlign(bs, startAnchor); + + return (ErrorStatus); +} + + + diff --git a/libMpegTPDec/src/tpdec_adif.h b/libMpegTPDec/src/tpdec_adif.h new file mode 100644 index 0000000..30c2084 --- /dev/null +++ b/libMpegTPDec/src/tpdec_adif.h @@ -0,0 +1,61 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: ADIF reader + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef TPDEC_ADIF_H +#define TPDEC_ADIF_H + +#include "tpdec_lib.h" + +#define MIN_ADIF_HEADERLENGTH 63 /* in bits */ + +typedef struct +{ + INT NumProgramConfigElements; + UINT BitRate; + UCHAR CopyrightIdPresent; + UCHAR OriginalCopy; + UCHAR Home; + UCHAR BitstreamType; +} CAdifHeader; + +/** + * \brief Parse a ADIF header at the given bitstream and store the parsed data into a given CAdifHeader + * and CProgramConfig struct + * + * \param pAdifHeader pointer to a CAdifHeader structure to hold the parsed ADIF header data. + * \param pPce pointer to a CProgramConfig structure where the last PCE will remain. + * + * \return TRANSPORTDEC_ERROR error code + */ +TRANSPORTDEC_ERROR adifRead_DecodeHeader( + CAdifHeader *pAdifHeader, + CProgramConfig *pPce, + HANDLE_FDK_BITSTREAM bs + ); + +#endif /* TPDEC_ADIF_H */ diff --git a/libMpegTPDec/src/tpdec_adts.cpp b/libMpegTPDec/src/tpdec_adts.cpp new file mode 100644 index 0000000..e64ae82 --- /dev/null +++ b/libMpegTPDec/src/tpdec_adts.cpp @@ -0,0 +1,326 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: ADTS interface + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "tpdec_adts.h" + + +#include "FDK_bitstream.h" + + + +void adtsRead_CrcInit(HANDLE_ADTS pAdts) /*!< pointer to adts crc info stucture */ +{ + FDKcrcInit(&pAdts->crcInfo, 0x8005, 0xFFFF, 16); +} + +int adtsRead_CrcStartReg( + HANDLE_ADTS pAdts, /*!< pointer to adts stucture */ + HANDLE_FDK_BITSTREAM hBs, /*!< handle to current bit buffer structure */ + int mBits /*!< number of bits in crc region */ + ) +{ + if (pAdts->bs.protection_absent) { + return 0; + } + + return ( FDKcrcStartReg(&pAdts->crcInfo, hBs, mBits) ); + +} + +void adtsRead_CrcEndReg( + HANDLE_ADTS pAdts, /*!< pointer to adts crc info stucture */ + HANDLE_FDK_BITSTREAM hBs, /*!< handle to current bit buffer structure */ + int reg /*!< crc region */ + ) +{ + if (pAdts->bs.protection_absent == 0) + { + FDKcrcEndReg(&pAdts->crcInfo, hBs, reg); + } +} + +TRANSPORTDEC_ERROR adtsRead_CrcCheck( HANDLE_ADTS pAdts ) +{ + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + USHORT crc; + + if (pAdts->bs.protection_absent) + return TRANSPORTDEC_OK; + + crc = FDKcrcGetCRC(&pAdts->crcInfo); + if (crc != pAdts->crcReadValue) + { + return (TRANSPORTDEC_CRC_ERROR); + } + + return (ErrorStatus); +} + + + +#define Adts_Length_SyncWord 12 +#define Adts_Length_Id 1 +#define Adts_Length_Layer 2 +#define Adts_Length_ProtectionAbsent 1 +#define Adts_Length_Profile 2 +#define Adts_Length_SamplingFrequencyIndex 4 +#define Adts_Length_PrivateBit 1 +#define Adts_Length_ChannelConfiguration 3 +#define Adts_Length_OriginalCopy 1 +#define Adts_Length_Home 1 +#define Adts_Length_CopyrightIdentificationBit 1 +#define Adts_Length_CopyrightIdentificationStart 1 +#define Adts_Length_FrameLength 13 +#define Adts_Length_BufferFullness 11 +#define Adts_Length_NumberOfRawDataBlocksInFrame 2 +#define Adts_Length_CrcCheck 16 + +TRANSPORTDEC_ERROR adtsRead_DecodeHeader( + HANDLE_ADTS pAdts, + CSAudioSpecificConfig *pAsc, + HANDLE_FDK_BITSTREAM hBs, + const INT ignoreBufferFullness + ) +{ + INT crcReg; + + INT valBits; + INT cmp_buffer_fullness; + int i, adtsHeaderLength; + + STRUCT_ADTS_BS bs; + +#ifdef TP_PCE_ENABLE + CProgramConfig oldPce; + /* Store the old PCE temporarily. Maybe we'll need it later if we + have channelConfig=0 and no PCE in this frame. */ + FDKmemcpy(&oldPce, &pAsc->m_progrConfigElement, sizeof(CProgramConfig)); +#endif + + valBits = FDKgetValidBits(hBs); + + /* adts_fixed_header */ + bs.mpeg_id = FDKreadBits(hBs, Adts_Length_Id); + bs.layer = FDKreadBits(hBs, Adts_Length_Layer); + bs.protection_absent = FDKreadBits(hBs, Adts_Length_ProtectionAbsent); + bs.profile = FDKreadBits(hBs, Adts_Length_Profile); + bs.sample_freq_index = FDKreadBits(hBs, Adts_Length_SamplingFrequencyIndex); + bs.private_bit = FDKreadBits(hBs, Adts_Length_PrivateBit); + bs.channel_config = FDKreadBits(hBs, Adts_Length_ChannelConfiguration); + bs.original = FDKreadBits(hBs, Adts_Length_OriginalCopy); + bs.home = FDKreadBits(hBs, Adts_Length_Home); + + /* adts_variable_header */ + bs.copyright_id = FDKreadBits(hBs, Adts_Length_CopyrightIdentificationBit); + bs.copyright_start = FDKreadBits(hBs, Adts_Length_CopyrightIdentificationStart); + bs.frame_length = FDKreadBits(hBs, Adts_Length_FrameLength); + bs.adts_fullness = FDKreadBits(hBs, Adts_Length_BufferFullness); + bs.num_raw_blocks = FDKreadBits(hBs, Adts_Length_NumberOfRawDataBlocksInFrame); + bs.num_pce_bits = 0; + + adtsHeaderLength = ADTS_HEADERLENGTH; + + if (!bs.protection_absent) { + FDKcrcReset(&pAdts->crcInfo); + FDKpushBack(hBs, 56); /* complete fixed and variable header! */ + crcReg = FDKcrcStartReg(&pAdts->crcInfo, hBs, 0); + FDKpushFor(hBs, 56); + } + + if (! bs.protection_absent && bs.num_raw_blocks>0) { + for (i=0; irawDataBlockDist[i] = (USHORT)FDKreadBits(hBs, 16); + adtsHeaderLength += 16; + } + /* Change raw data blocks to delta values */ + pAdts->rawDataBlockDist[bs.num_raw_blocks] = bs.frame_length - 7 - bs.num_raw_blocks*2 - 2 ; + for (i=bs.num_raw_blocks; i>0; i--) { + pAdts->rawDataBlockDist[i] -= pAdts->rawDataBlockDist[i-1]; + } + } + + /* adts_error_check */ + if (!bs.protection_absent) + { + USHORT crc_check; + + FDKcrcEndReg(&pAdts->crcInfo, hBs, crcReg); + crc_check = FDKreadBits(hBs, Adts_Length_CrcCheck); + adtsHeaderLength += Adts_Length_CrcCheck; + + pAdts->crcReadValue = crc_check; + /* Check header CRC in case of multiple raw data blocks */ + if (bs.num_raw_blocks > 0) { + if (pAdts->crcReadValue != FDKcrcGetCRC(&pAdts->crcInfo)) { + return TRANSPORTDEC_CRC_ERROR; + } + /* Reset CRC for the upcoming raw_data_block() */ + FDKcrcReset(&pAdts->crcInfo); + } + } + + + /* check if valid header */ + if ( + (bs.layer != 0) || // we only support MPEG ADTS + (bs.sample_freq_index >= 13) // we only support 96kHz - 7350kHz + ) { + FDKpushFor(hBs, bs.frame_length * 8); // try again one frame later + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + + /* special treatment of id-bit */ + if ( (bs.mpeg_id == 0) && (pAdts->decoderCanDoMpeg4 == 0) ) + { + /* MPEG-2 decoder cannot play MPEG-4 bitstreams */ + + + FDKpushFor(hBs, bs.frame_length * 8); // try again one frame later + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + + if (!ignoreBufferFullness) + { + cmp_buffer_fullness = bs.frame_length*8 + bs.adts_fullness*32*getNumberOfEffectiveChannels(bs.channel_config); + + + /* Evaluate buffer fullness */ + if (bs.adts_fullness != 0x7FF) + { + if (pAdts->BufferFullnesStartFlag) + { + if ( valBits < cmp_buffer_fullness ) + { + /* Condition for start of decoding is not fulfilled */ + + /* The current frame will not be decoded */ + FDKpushBack(hBs, adtsHeaderLength); + + if ( (cmp_buffer_fullness+adtsHeaderLength) > ((TRANSPORTDEC_INBUF_SIZE<<3)-7) ) { + return TRANSPORTDEC_SYNC_ERROR; + } else { + return TRANSPORTDEC_NOT_ENOUGH_BITS; + } + } + else + { + pAdts->BufferFullnesStartFlag = 0; + } + } + } + } + + + /* Get info from ADTS header */ + AudioSpecificConfig_Init(pAsc); + pAsc->m_aot = (AUDIO_OBJECT_TYPE)(bs.profile + 1); + pAsc->m_samplingFrequencyIndex = bs.sample_freq_index; + pAsc->m_samplingFrequency = SamplingRateTable[bs.sample_freq_index]; + pAsc->m_channelConfiguration = bs.channel_config; + pAsc->m_samplesPerFrame = 1024; + +#ifdef TP_PCE_ENABLE + if (bs.channel_config == 0) + { + int pceBits = 0; + UINT alignAnchor = FDKgetValidBits(hBs); + + if (FDKreadBits(hBs,3) == ID_PCE) { + /* Got luck! Parse the PCE */ + int crcReg; + crcReg = adtsRead_CrcStartReg(pAdts, hBs, 0); + + CProgramConfig_Read(&pAsc->m_progrConfigElement, hBs, alignAnchor); + + adtsRead_CrcEndReg(pAdts, hBs, crcReg); + pceBits = alignAnchor - FDKgetValidBits(hBs); + /* store the number of PCE bits */ + bs.num_pce_bits = pceBits; + } + else { + /* No PCE in this frame! Push back the ID tag bits. */ + FDKpushBack(hBs,3); + + /* Encoders do not have to write a PCE in each frame. + So if we already have a valid PCE we have to use it. */ + if ( oldPce.isValid + && (bs.sample_freq_index == pAdts->bs.sample_freq_index) /* we could compare the complete fixed header (bytes) here! */ + && (bs.channel_config == pAdts->bs.channel_config) /* == 0 */ + && (bs.mpeg_id == pAdts->bs.mpeg_id) ) + { /* Restore previous PCE which is still valid */ + FDKmemcpy(&pAsc->m_progrConfigElement, &oldPce, sizeof(CProgramConfig)); + } + else if (bs.mpeg_id == 0) { + /* If not it seems that we have a implicit channel configuration. + This mode is not allowed in the context of ISO/IEC 14496-3. + Skip this frame and try the next one. */ + FDKpushFor(hBs, (bs.frame_length<<3) - adtsHeaderLength - 3); + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + /* else { + ISO/IEC 13818-7 implicit channel mapping is allowed. + So just open the box of chocolates to see what we got. + } */ + } + } +#endif /* TP_PCE_ENABLE */ + + /* Copy bit stream data struct to persistent memory now, once we passed all sanity checks above. */ + FDKmemcpy(&pAdts->bs, &bs, sizeof(STRUCT_ADTS_BS)); + + return TRANSPORTDEC_OK; +} + +int adtsRead_GetRawDataBlockLength( + HANDLE_ADTS pAdts, + INT blockNum + ) +{ + int length; + + if (pAdts->bs.num_raw_blocks == 0) { + length = (pAdts->bs.frame_length - 7) << 3; /* aac_frame_length subtracted by the header size (7 bytes). */ + if (pAdts->bs.protection_absent == 0) + length -= 16; /* substract 16 bit CRC */ + } else { + if (pAdts->bs.protection_absent) { + length = -1; /* raw data block length is unknown */ + } else { + if (blockNum < 0 || blockNum > 3) { + return TRANSPORTDEC_INVALID_PARAMETER; + } + length = (pAdts->rawDataBlockDist[blockNum] << 3) - 16; + } + } + if (blockNum == 0) { + length -= pAdts->bs.num_pce_bits; + } + return length; +} + + diff --git a/libMpegTPDec/src/tpdec_adts.h b/libMpegTPDec/src/tpdec_adts.h new file mode 100644 index 0000000..13c66a4 --- /dev/null +++ b/libMpegTPDec/src/tpdec_adts.h @@ -0,0 +1,174 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Josef Hoepfl + Description: ADTS interface + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef TPDEC_ADTS_H +#define TPDEC_ADTS_H + +#include "tpdec_lib.h" + + +#define ADTS_SYNCWORD ( 0xfff ) +#define ADTS_SYNCLENGTH ( 12 ) /* in bits */ +#define ADTS_HEADERLENGTH ( 56 ) /* minimum header size in bits */ +#define ADTS_FIXED_HEADERLENGTH ( 28 ) /* in bits */ +#define ADTS_VARIABLE_HEADERLENGTH ( ADTS_HEADERLENGTH - ADTS_FIXED_HEADERLENGTH ) + +#ifdef CHECK_TWO_SYNCS + #define ADTS_MIN_TP_BUF_SIZE ( 8191 + 2 ) +#else + #define ADTS_MIN_TP_BUF_SIZE ( 8191 ) +#endif + +#include "FDK_crc.h" + +typedef struct { + /* ADTS header fields */ + UCHAR mpeg_id; + UCHAR layer; + UCHAR protection_absent; + UCHAR profile; + UCHAR sample_freq_index; + UCHAR private_bit; + UCHAR channel_config; + UCHAR original; + UCHAR home; + UCHAR copyright_id; + UCHAR copyright_start; + USHORT frame_length; + USHORT adts_fullness; + UCHAR num_raw_blocks; + UCHAR num_pce_bits; +} STRUCT_ADTS_BS; + +struct STRUCT_ADTS { + + STRUCT_ADTS_BS bs; + + UCHAR decoderCanDoMpeg4; + UCHAR BufferFullnesStartFlag; + + FDK_CRCINFO crcInfo; /* CRC state info */ + USHORT crcReadValue; /* CRC value read from bitstream data */ + USHORT rawDataBlockDist[4]; /* distance between each raw data block. Not the same as found in the bitstream */ +} ; + +typedef struct STRUCT_ADTS *HANDLE_ADTS; + +/*! + \brief Initialize ADTS CRC + + The function initialzes the crc buffer and the crc lookup table. + + \return none +*/ +void adtsRead_CrcInit( HANDLE_ADTS pAdts ); + +/** + * \brief Starts CRC region with a maximum number of bits + * If mBits is positive zero padding will be used for CRC calculation, if there + * are less than mBits bits available. + * If mBits is negative no zero padding is done. + * If mBits is zero the memory for the buffer is allocated dynamically, the + * number of bits is not limited. + * + * \param pAdts ADTS data handle + * \param hBs bitstream handle, on which the CRC region referes to + * \param mBits max number of bits in crc region to be considered + * + * \return ID for the created region, -1 in case of an error + */ +int adtsRead_CrcStartReg( + HANDLE_ADTS pAdts, + HANDLE_FDK_BITSTREAM hBs, + int mBits + ); + +/** + * \brief Ends CRC region identified by reg + * + * \param pAdts ADTS data handle + * \param hBs bitstream handle, on which the CRC region referes to + * \param reg CRC regions ID returned by adtsRead_CrcStartReg() + * + * \return none + */ +void adtsRead_CrcEndReg( + HANDLE_ADTS pAdts, + HANDLE_FDK_BITSTREAM hBs, + int reg + ); + +/** + * \brief Check CRC + * + * Checks if the currently calculated CRC matches the CRC field read from the bitstream + * Deletes all CRC regions. + * + * \param pAdts ADTS data handle + * + * \return Returns 0 if they are identical otherwise 1 + */ +TRANSPORTDEC_ERROR adtsRead_CrcCheck( HANDLE_ADTS pAdts ); + + +/** + * \brief Check if we have a valid ADTS frame at the current bitbuffer position + * + * This function assumes enough bits in buffer for the current frame. + * It reads out the header bits to prepare the bitbuffer for the decode loop. + * In case the header bits show an invalid bitstream/frame, the whole frame is skipped. + * + * \param pAdts ADTS data handle which is filled with parsed ADTS header data + * \param bs handle of bitstream from whom the ADTS header is read + * + * \return error status + */ +TRANSPORTDEC_ERROR adtsRead_DecodeHeader( + HANDLE_ADTS pAdts, + CSAudioSpecificConfig *pAsc, + HANDLE_FDK_BITSTREAM bs, + const INT ignoreBufferFullness + ); + +/** + * \brief Get the raw data block length of the given block number. + * + * \param pAdts ADTS data handle + * \param blockNum current raw data block index + * \param pLength pointer to an INT where the length of the given raw data block is stored into + * the returned value might be -1, in which case the raw data block length is unknown. + * + * \return error status + */ +int adtsRead_GetRawDataBlockLength( + HANDLE_ADTS pAdts, + INT blockNum + ); + + +#endif /* TPDEC_ADTS_H */ diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp new file mode 100644 index 0000000..ee7c7cf --- /dev/null +++ b/libMpegTPDec/src/tpdec_asc.cpp @@ -0,0 +1,867 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Daniel Homm + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "tpdec_lib.h" +#include "tp_data.h" + + +void CProgramConfig_Reset(CProgramConfig *pPce) +{ + pPce->elCounter = 0; +} + +void CProgramConfig_Init(CProgramConfig *pPce) +{ + FDKmemclear(pPce, sizeof(CProgramConfig)); +#ifdef TP_PCE_ENABLE + pPce->SamplingFrequencyIndex = 0xf; +#endif +} + +int CProgramConfig_IsValid ( const CProgramConfig *pPce ) +{ + return ( (pPce->isValid) ? 1 : 0); +} + +#ifdef TP_PCE_ENABLE +void CProgramConfig_Read( + CProgramConfig *pPce, + HANDLE_FDK_BITSTREAM bs, + UINT alignmentAnchor + ) +{ + int i; + + pPce->NumEffectiveChannels = 0; + pPce->NumChannels = 0; + pPce->ElementInstanceTag = (UCHAR) FDKreadBits(bs,4); + pPce->Profile = (UCHAR) FDKreadBits(bs,2); + pPce->SamplingFrequencyIndex = (UCHAR) FDKreadBits(bs,4); + pPce->NumFrontChannelElements = (UCHAR) FDKreadBits(bs,4); + pPce->NumSideChannelElements = (UCHAR) FDKreadBits(bs,4); + pPce->NumBackChannelElements = (UCHAR) FDKreadBits(bs,4); + pPce->NumLfeChannelElements = (UCHAR) FDKreadBits(bs,2); + pPce->NumAssocDataElements = (UCHAR) FDKreadBits(bs,3); + pPce->NumValidCcElements = (UCHAR) FDKreadBits(bs,4); + + if ((pPce->MonoMixdownPresent = (UCHAR) FDKreadBits(bs,1)) != 0) + { + pPce->MonoMixdownElementNumber = (UCHAR) FDKreadBits(bs,4); + } + + if ((pPce->StereoMixdownPresent = (UCHAR) FDKreadBits(bs,1)) != 0) + { + pPce->StereoMixdownElementNumber = (UCHAR) FDKreadBits(bs,4); + } + + if ((pPce->MatrixMixdownIndexPresent = (UCHAR) FDKreadBits(bs,1)) != 0) + { + pPce->MatrixMixdownIndex = (UCHAR) FDKreadBits(bs,2); + pPce->PseudoSurroundEnable = (UCHAR) FDKreadBits(bs,1); + } + + for (i=0; i < pPce->NumFrontChannelElements; i++) + { + pPce->FrontElementIsCpe[i] = (UCHAR) FDKreadBits(bs,1); + pPce->FrontElementTagSelect[i] = (UCHAR) FDKreadBits(bs,4); + pPce->NumChannels += pPce->FrontElementIsCpe[i] ? 2 : 1; + } + + for (i=0; i < pPce->NumSideChannelElements; i++) + { + pPce->SideElementIsCpe[i] = (UCHAR) FDKreadBits(bs,1); + pPce->SideElementTagSelect[i] = (UCHAR) FDKreadBits(bs,4); + pPce->NumChannels += pPce->SideElementIsCpe[i] ? 2 : 1; + } + + for (i=0; i < pPce->NumBackChannelElements; i++) + { + pPce->BackElementIsCpe[i] = (UCHAR) FDKreadBits(bs,1); + pPce->BackElementTagSelect[i] = (UCHAR) FDKreadBits(bs,4); + pPce->NumChannels += pPce->BackElementIsCpe[i] ? 2 : 1; + } + + pPce->NumEffectiveChannels = pPce->NumChannels; + + for (i=0; i < pPce->NumLfeChannelElements; i++) + { + pPce->LfeElementTagSelect[i] = (UCHAR) FDKreadBits(bs,4); + pPce->NumChannels += 1; + } + + for (i=0; i < pPce->NumAssocDataElements; i++) + { + pPce->AssocDataElementTagSelect[i] = (UCHAR) FDKreadBits(bs,4); + } + + for (i=0; i < pPce->NumValidCcElements; i++) + { + pPce->CcElementIsIndSw[i] = (UCHAR) FDKreadBits(bs,1); + pPce->ValidCcElementTagSelect[i] = (UCHAR) FDKreadBits(bs,4); + } + + FDKbyteAlign(bs, alignmentAnchor); + + pPce->CommentFieldBytes = (UCHAR) FDKreadBits(bs,8); + + for (i=0; i < pPce->CommentFieldBytes; i++) + { + UCHAR text; + + text = (UCHAR)FDKreadBits(bs,8); + + if (i < PC_COMMENTLENGTH) + { + pPce->Comment[i] = text; + } + } + + pPce->isValid = 1; +} +#endif /* TP_PCE_ENABLE */ + +/** + * \brief get implicit audio channel type for given channelConfig and MPEG ordered channel index + * \param channelConfig MPEG channelConfiguration from 1 upto 7 + * \param index MPEG channel order index + * \return audio channel type. + */ +void getImplicitAudioChannelTypeAndIndex( + AUDIO_CHANNEL_TYPE *chType, + UCHAR *chIndex, + UINT channelConfig, + UINT index + ) +{ + if (index < 3) { + *chType = ACT_FRONT; + *chIndex = index; + } else { + switch (channelConfig) { + case MODE_1_2_1: + case MODE_1_2_2: + case MODE_1_2_2_1: + switch (index) { + case 3: + case 4: + *chType = ACT_BACK; + *chIndex = index - 3; + break; + case 5: + *chType = ACT_LFE; + *chIndex = 0; + break; + } + break; + case MODE_1_2_2_2_1: + switch (index) { + case 3: + case 4: + *chType = ACT_SIDE; + *chIndex = index - 3; + break; + case 5: + case 6: + *chType = ACT_BACK; + *chIndex = index - 5; + break; + case 7: + *chType = ACT_LFE; + *chIndex = 0; + break; + } + break; + default: + *chType = ACT_NONE; + break; + } + } +} + +int CProgramConfig_LookupElement( + CProgramConfig *pPce, + const UINT channelConfig, + const UINT tag, + const UINT channelIdx, + UCHAR chMapping[], + AUDIO_CHANNEL_TYPE chType[], + UCHAR chIndex[], + UCHAR *elMapping, + MP4_ELEMENT_ID elList[], + MP4_ELEMENT_ID elType + ) +{ + if (channelConfig > 0) + { + /* Constant channel mapping must have + been set during initialization. */ + if ( elType == ID_SCE + || elType == ID_CPE + || elType == ID_LFE ) + { + *elMapping = pPce->elCounter; + if (elList[pPce->elCounter] != elType) { + /* Not in the list */ + return 0; + } + /* Assume all front channels */ + getImplicitAudioChannelTypeAndIndex(&chType[channelIdx], &chIndex[channelIdx], channelConfig, channelIdx); + if (elType == ID_CPE) { + chType[channelIdx+1] = chType[channelIdx]; + chIndex[channelIdx+1] = chIndex[channelIdx]+1; + } + pPce->elCounter++; + } + /* Accept all non-channel elements, too. */ + return 1; + } + else + { +#ifdef TP_PCE_ENABLE + if (!pPce->isValid) +#endif /* TP_PCE_ENABLE */ + { + /* Implicit channel mapping. */ + if ( elType == ID_SCE + || elType == ID_CPE + || elType == ID_LFE ) + { + /* Store all channel element IDs */ + elList[pPce->elCounter] = elType; + *elMapping = pPce->elCounter++; + } + } +#ifdef TP_PCE_ENABLE + else { + /* Accept the additional channel(s), only if the tag is in the lists */ + int isCpe = 0, i; + int cc = 0, fc = 0, sc = 0, bc = 0, lc = 0, ec = 0; /* Channel and element counters */ + + switch (elType) + { + case ID_CPE: + isCpe = 1; + case ID_SCE: + /* search in front channels */ + for (i = 0; i < pPce->NumFrontChannelElements; i++) { + if (isCpe == pPce->FrontElementIsCpe[i] && pPce->FrontElementTagSelect[i] == tag) { + chMapping[cc] = channelIdx; + chType[cc] = ACT_FRONT; + chIndex[cc] = fc; + if (isCpe) { + chMapping[cc+1] = channelIdx+1; + chType[cc+1] = ACT_FRONT; + chIndex[cc+1] = fc+1; + } + *elMapping = ec; + return 1; + } + ec++; + if (pPce->FrontElementIsCpe[i]) { + cc+=2; fc+=2; + } else { + cc++; fc++; + } + } + /* search in side channels */ + for (i = 0; i < pPce->NumSideChannelElements; i++) { + if (isCpe == pPce->SideElementIsCpe[i] && pPce->SideElementTagSelect[i] == tag) { + chMapping[cc] = channelIdx; + chType[cc] = ACT_SIDE; + chIndex[cc] = sc; + if (isCpe) { + chMapping[cc+1] = channelIdx+1; + chType[cc+1] = ACT_SIDE; + chIndex[cc+1] = sc+1; + } + *elMapping = ec; + return 1; + } + ec++; + if (pPce->SideElementIsCpe[i]) { + cc+=2; sc+=2; + } else { + cc++; sc++; + } + } + /* search in back channels */ + for (i = 0; i < pPce->NumBackChannelElements; i++) { + if (isCpe == pPce->BackElementIsCpe[i] && pPce->BackElementTagSelect[i] == tag) { + chMapping[cc] = channelIdx; + chType[cc] = ACT_BACK; + chIndex[cc] = bc; + if (isCpe) { + chMapping[cc+1] = channelIdx+1; + chType[cc+1] = ACT_BACK; + chIndex[cc+1] = bc+1; + } + *elMapping = ec; + return 1; + } + ec++; + if (pPce->BackElementIsCpe[i]) { + cc+=2; bc+=2; + } else { + cc++; bc++; + } + } + break; + + case ID_LFE: + /* Initialize channel counter and element counter */ + cc = pPce->NumEffectiveChannels; + ec = pPce->NumFrontChannelElements+ pPce->NumSideChannelElements + pPce->NumBackChannelElements; + /* search in lfe channels */ + for (i = 0; i < pPce->NumLfeChannelElements; i++) { + if ( pPce->LfeElementTagSelect[i] == tag ) { + chMapping[cc] = channelIdx; + *elMapping = ec; + chType[cc] = ACT_LFE; + chIndex[cc] = lc; + return 1; + } + ec++; + cc++; + lc++; + } + break; + + /* Non audio elements */ + case ID_CCE: + /* search in cce channels */ + for (i = 0; i < pPce->NumValidCcElements; i++) { + if (pPce->ValidCcElementTagSelect[i] == tag) { + return 1; + } + } + break; + case ID_DSE: + /* search associated data elements */ + for (i = 0; i < pPce->NumAssocDataElements; i++) { + if (pPce->AssocDataElementTagSelect[i] == tag) { + return 1; + } + } + break; + default: + return 0; + } + return 0; /* not found in any list */ + } +#endif /* TP_PCE_ENABLE */ + } + + return 1; +} + +#ifdef TP_PCE_ENABLE +int CProgramConfig_GetElementTable( + const CProgramConfig *pPce, + MP4_ELEMENT_ID elList[] + ) +{ + int i, el = 0; + + for (i=0; i < pPce->NumFrontChannelElements; i++) + { + elList[el++] = (pPce->FrontElementIsCpe[i]) ? ID_CPE : ID_SCE; + } + + for (i=0; i < pPce->NumSideChannelElements; i++) + { + elList[el++] = (pPce->SideElementIsCpe[i]) ? ID_CPE : ID_SCE; + } + + for (i=0; i < pPce->NumBackChannelElements; i++) + { + elList[el++] = (pPce->BackElementIsCpe[i]) ? ID_CPE : ID_SCE; + } + + for (i=0; i < pPce->NumLfeChannelElements; i++) + { + elList[el++] = ID_LFE; + } + + + return el; +} +#endif + +static AUDIO_OBJECT_TYPE getAOT(HANDLE_FDK_BITSTREAM bs) +{ + int tmp = 0; + + tmp = FDKreadBits(bs,5); + if (tmp == AOT_ESCAPE) { + int tmp2 = FDKreadBits(bs,6); + tmp = 32 + tmp2; + } + + return (AUDIO_OBJECT_TYPE)tmp; +} + +static INT getSampleRate(HANDLE_FDK_BITSTREAM bs, UCHAR *index, int nBits) +{ + INT sampleRate; + int idx; + + idx = FDKreadBits(bs, nBits); + if( idx == (1<m_frameLengthFlag = FDKreadBits(bs,1); + + self->m_dependsOnCoreCoder = FDKreadBits(bs,1); + + if( self->m_dependsOnCoreCoder ) + self->m_coreCoderDelay = FDKreadBits(bs,14); + + self->m_extensionFlag = FDKreadBits(bs,1); + + if( asc->m_channelConfiguration == 0 ) { + CProgramConfig_Read(&asc->m_progrConfigElement, bs, ascStartAnchor); + } + + if ((asc->m_aot == AOT_AAC_SCAL) || (asc->m_aot == AOT_ER_AAC_SCAL)) { + self->m_layer = FDKreadBits(bs,3); + } + + if (self->m_extensionFlag) { + if (asc->m_aot == AOT_ER_BSAC) { + self->m_numOfSubFrame = FDKreadBits(bs,5); + self->m_layerLength = FDKreadBits(bs,11); + } + + if ((asc->m_aot == AOT_ER_AAC_LC) || (asc->m_aot == AOT_ER_AAC_LTP) || + (asc->m_aot == AOT_ER_AAC_SCAL) || (asc->m_aot == AOT_ER_AAC_LD)) + { + asc->m_vcb11Flag = FDKreadBits(bs,1); /* aacSectionDataResilienceFlag */ + asc->m_rvlcFlag = FDKreadBits(bs,1); /* aacScalefactorDataResilienceFlag */ + asc->m_hcrFlag = FDKreadBits(bs,1); /* aacSpectralDataResilienceFlag */ + } + + self->m_extensionFlag3 = FDKreadBits(bs,1); + + } + return (ErrorStatus); +} +#endif /* TP_GA_ENABLE */ + + + + + +#ifdef TP_ELD_ENABLE + +static INT ld_sbr_header( const CSAudioSpecificConfig *asc, + HANDLE_FDK_BITSTREAM hBs, + CSTpCallBacks *cb ) +{ + const int channelConfiguration = asc->m_channelConfiguration; + int i = 0; + INT error = 0; + + if (channelConfiguration == 2) { + error = cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++); + } else { + error = cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_SCE, i++); + } + + switch ( channelConfiguration ) { + case 5: + error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++); + case 3: + error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++); + break; + + case 7: + error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_SCE, i++); + case 6: + error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++); + case 4: + error |= cb->cbSbr(cb->cbSbrData, hBs, asc->m_samplingFrequency, asc->m_extensionSamplingFrequency, asc->m_samplesPerFrame, AOT_ER_AAC_ELD, ID_CPE, i++); + break; + } + + return error; +} + +static +TRANSPORTDEC_ERROR EldSpecificConfig_Parse( + CSAudioSpecificConfig *asc, + HANDLE_FDK_BITSTREAM hBs, + CSTpCallBacks *cb + ) +{ + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + CSEldSpecificConfig *esc = &asc->m_sc.m_eldSpecificConfig; + ASC_ELD_EXT_TYPE eldExtType; + int eldExtLen, len, cnt; + + FDKmemclear(esc, sizeof(CSEldSpecificConfig)); + + esc->m_frameLengthFlag = FDKreadBits(hBs, 1 ); + if (esc->m_frameLengthFlag) { + asc->m_samplesPerFrame = 480; + } else { + asc->m_samplesPerFrame = 512; + } + + asc->m_vcb11Flag = FDKreadBits(hBs, 1 ); + asc->m_rvlcFlag = FDKreadBits(hBs, 1 ); + asc->m_hcrFlag = FDKreadBits(hBs, 1 ); + + esc->m_sbrPresentFlag = FDKreadBits(hBs, 1 ); + + if (esc->m_sbrPresentFlag == 1) { + esc->m_sbrSamplingRate = FDKreadBits(hBs, 1 ); /* 0: single rate, 1: dual rate */ + esc->m_sbrCrcFlag = FDKreadBits(hBs, 1 ); + + asc->m_extensionSamplingFrequency = asc->m_samplingFrequency << esc->m_sbrSamplingRate; + + if (cb->cbSbr != NULL){ + if ( 0 != ld_sbr_header(asc, hBs, cb) ) { + return TRANSPORTDEC_PARSE_ERROR; + } + } + } + esc->m_useLdQmfTimeAlign = 0; + + /* new ELD syntax */ + /* parse ExtTypeConfigData */ + while ((eldExtType = (ASC_ELD_EXT_TYPE)FDKreadBits(hBs, 4 )) != ELDEXT_TERM) { + eldExtLen = len = FDKreadBits(hBs, 4 ); + if ( len == 0xf ) { + len = FDKreadBits(hBs, 8 ); + eldExtLen += len; + + if ( len == 0xff ) { + len = FDKreadBits(hBs, 16 ); + eldExtLen += len; + } + } + + switch (eldExtType) { + case ELDEXT_LDSAC: + esc->m_useLdQmfTimeAlign = 1; + if (cb->cbSsc != NULL) { + ErrorStatus = (TRANSPORTDEC_ERROR)cb->cbSsc( + cb->cbSscData, + hBs, + asc->m_aot, + asc->m_samplingFrequency, + 1, /* muxMode */ + len + ); + } else { + ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + if (ErrorStatus != TRANSPORTDEC_OK) { + goto bail; + } + break; + default: + for(cnt=0; cnt= 11) + { + lastAscExt = ascExtId; + ascExtId = (TP_ASC_EXTENSION_ID)FDKreadBits(bs, 11); + bitsAvailable -= 11; + + switch (ascExtId) { + case ASCEXT_SBR: /* 0x2b7 */ + if ( (self->m_extensionAudioObjectType != AOT_SBR) && (bitsAvailable >= 5) ) { + self->m_extensionAudioObjectType = getAOT(bs); + + if ( (self->m_extensionAudioObjectType == AOT_SBR) + || (self->m_extensionAudioObjectType == AOT_ER_BSAC) ) + { /* Get SBR extension configuration */ + self->m_sbrPresentFlag = FDKreadBits(bs, 1); + bitsAvailable -= 1; + + if ( self->m_sbrPresentFlag == 1 ) { + self->m_extensionSamplingFrequency = getSampleRate(bs, &self->m_extensionSamplingFrequencyIndex, 4); + + if ((INT)self->m_extensionSamplingFrequency <= 0) { + return TRANSPORTDEC_PARSE_ERROR; + } + } + if ( self->m_extensionAudioObjectType == AOT_ER_BSAC ) { + self->m_extensionChannelConfiguration = FDKreadBits(bs, 4); + bitsAvailable -= 4; + } + } + /* Update counter because of variable length fields (AOT and sampling rate) */ + bitsAvailable = (INT)FDKgetValidBits(bs); + } + break; + case ASCEXT_PS: /* 0x548 */ + if ( (lastAscExt == ASCEXT_SBR) + && (self->m_extensionAudioObjectType == AOT_SBR) + && (bitsAvailable > 0) ) + { /* Get PS extension configuration */ + self->m_psPresentFlag = FDKreadBits(bs, 1); + bitsAvailable -= 1; + } + break; + case ASCEXT_MPS: /* 0x76a */ + if ( self->m_extensionAudioObjectType == AOT_MPEGS ) + break; + case ASCEXT_LDMPS: /* 0x7cc */ + if ( (ascExtId == ASCEXT_LDMPS) + && (self->m_extensionAudioObjectType == AOT_LD_MPEGS) ) + break; + if (bitsAvailable >= 1) + { + bitsAvailable -= 1; + if ( FDKreadBits(bs, 1) ) { /* self->m_mpsPresentFlag */ + int sscLen = FDKreadBits(bs, 8); + bitsAvailable -= 8; + if (sscLen == 0xFF) { + sscLen += FDKreadBits(bs, 16); + bitsAvailable -= 16; + } + if (cb->cbSsc != NULL) { + cb->cbSsc( + cb->cbSscData, + bs, + self->m_aot, + self->m_samplingFrequency, + 1, + sscLen + ); + } else + FDKpushFor(bs, sscLen); /* Skip SSC to be able to read the next extension if there is one. */ + + bitsAvailable -= sscLen*8; + } + } + break; + default: + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + } + + return TRANSPORTDEC_OK; +} + +/* + * API Functions + */ + +void AudioSpecificConfig_Init(CSAudioSpecificConfig *asc) +{ + FDKmemclear(asc, sizeof(CSAudioSpecificConfig)); + + /* Init all values that should not be zero. */ + asc->m_aot = AOT_NONE; + asc->m_samplingFrequencyIndex = 0xf; + asc->m_epConfig = -1; + asc->m_extensionAudioObjectType = AOT_NULL_OBJECT; +#ifdef TP_PCE_ENABLE + CProgramConfig_Init(&asc->m_progrConfigElement); +#endif +} + +TRANSPORTDEC_ERROR AudioSpecificConfig_Parse( + CSAudioSpecificConfig *self, + HANDLE_FDK_BITSTREAM bs, + int fExplicitBackwardCompatible, + CSTpCallBacks *cb + ) +{ + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + UINT ascStartAnchor = FDKgetValidBits(bs); + int frameLengthFlag = -1; + + AudioSpecificConfig_Init(self); + + self->m_aot = getAOT(bs); + self->m_samplingFrequency = getSampleRate(bs, &self->m_samplingFrequencyIndex, 4); + if (self->m_samplingFrequency <= 0) { + return TRANSPORTDEC_PARSE_ERROR; + } + + self->m_channelConfiguration = FDKreadBits(bs,4); + + /* SBR extension ( explicit non-backwards compatible mode ) */ + self->m_sbrPresentFlag = 0; + self->m_psPresentFlag = 0; + + if ( self->m_aot == AOT_SBR || self->m_aot == AOT_PS ) { + self->m_extensionAudioObjectType = AOT_SBR; + + self->m_sbrPresentFlag = 1; + if ( self->m_aot == AOT_PS ) { + self->m_psPresentFlag = 1; + } + + self->m_extensionSamplingFrequency = getSampleRate(bs, &self->m_extensionSamplingFrequencyIndex, 4); + self->m_aot = getAOT(bs); + + } else { + self->m_extensionAudioObjectType = AOT_NULL_OBJECT; + } + + /* Parse whatever specific configs */ + switch (self->m_aot) + { +#ifdef TP_GA_ENABLE + case AOT_AAC_LC: + case AOT_ER_AAC_LC: + case AOT_ER_AAC_LD: + case AOT_ER_AAC_SCAL: + case AOT_ER_BSAC: + if ((ErrorStatus = GaSpecificConfig_Parse(&self->m_sc.m_gaSpecificConfig, self, bs, ascStartAnchor)) != TRANSPORTDEC_OK ) { + return (ErrorStatus); + } + frameLengthFlag = self->m_sc.m_gaSpecificConfig.m_frameLengthFlag; + break; +#endif /* TP_GA_ENABLE */ + case AOT_MPEGS: + if (cb->cbSsc != NULL) { + cb->cbSsc( + cb->cbSscData, + bs, + self->m_aot, + self->m_samplingFrequency, + 1, + 0 /* don't know the length */ + ); + } else { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + break; +#ifdef TP_ELD_ENABLE + case AOT_ER_AAC_ELD: + if ((ErrorStatus = EldSpecificConfig_Parse(self, bs, cb)) != TRANSPORTDEC_OK ) { + return (ErrorStatus); + } + frameLengthFlag = self->m_sc.m_eldSpecificConfig.m_frameLengthFlag; + self->m_sbrPresentFlag = self->m_sc.m_eldSpecificConfig.m_sbrPresentFlag; + self->m_extensionSamplingFrequency = (self->m_sc.m_eldSpecificConfig.m_sbrSamplingRate+1) * self->m_samplingFrequency; + break; +#endif /* TP_ELD_ENABLE */ + + default: + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + break; + } + + /* Frame length */ + switch (self->m_aot) + { +#if defined(TP_GA_ENABLE) || defined(TP_USAC_ENABLE) + case AOT_AAC_LC: + case AOT_ER_AAC_LC: + case AOT_ER_AAC_SCAL: + case AOT_ER_BSAC: + /*case AOT_USAC:*/ + if (!frameLengthFlag) + self->m_samplesPerFrame = 1024; + else + self->m_samplesPerFrame = 960; + break; +#endif /* TP_GA_ENABLE */ +#if defined(TP_GA_ENABLE) + case AOT_ER_AAC_LD: + if (!frameLengthFlag) + self->m_samplesPerFrame = 512; + else + self->m_samplesPerFrame = 480; + break; +#endif /* defined(TP_GA_ENABLE) */ + default: + break; + } + + switch (self->m_aot) + { + case AOT_ER_AAC_LC: + case AOT_ER_AAC_LD: + case AOT_ER_AAC_ELD: + case AOT_ER_AAC_SCAL: + case AOT_ER_CELP: + case AOT_ER_HVXC: + case AOT_ER_BSAC: + self->m_epConfig = FDKreadBits(bs,2); + + if (self->m_epConfig > 1) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; // EPCONFIG; + } + break; + default: + break; + } + + if (fExplicitBackwardCompatible) { + ErrorStatus = AudioSpecificConfig_ExtensionParse(self, bs, cb); + } + + return (ErrorStatus); +} + + diff --git a/libMpegTPDec/src/tpdec_latm.cpp b/libMpegTPDec/src/tpdec_latm.cpp new file mode 100644 index 0000000..28daebc --- /dev/null +++ b/libMpegTPDec/src/tpdec_latm.cpp @@ -0,0 +1,364 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Daniel Homm + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "tpdec_latm.h" + + +#include "FDK_bitstream.h" + + +#define TPDEC_TRACKINDEX(p,l) (2*(p) + (l)) + +static +UINT CLatmDemux_GetValue(HANDLE_FDK_BITSTREAM bs) +{ + UCHAR bytesForValue = 0, tmp = 0; + int value = 0; + + bytesForValue = (UCHAR) FDKreadBits(bs,2); + + for (UINT i=0; i<=bytesForValue; i++) { + value <<= 8; + tmp = (UCHAR) FDKreadBits(bs,8); + value += tmp; + } + + return value; +} + + +static +TRANSPORTDEC_ERROR CLatmDemux_ReadAudioMuxElement( + HANDLE_FDK_BITSTREAM bs, + CLatmDemux *pLatmDemux, + int m_muxConfigPresent, + CSTpCallBacks *pTpDecCallbacks, + CSAudioSpecificConfig *pAsc + ) +{ + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + + if (m_muxConfigPresent) { + pLatmDemux->m_useSameStreamMux = FDKreadBits(bs,1); + + if (!pLatmDemux->m_useSameStreamMux) { + if ((ErrorStatus = CLatmDemux_ReadStreamMuxConfig(bs, pLatmDemux, pTpDecCallbacks, pAsc))) { + return (ErrorStatus); + } + } + } + + if (pLatmDemux->m_AudioMuxVersionA == 0) { + /* Do only once per call, because parsing and decoding is done in-line. */ + if ((ErrorStatus = CLatmDemux_ReadPayloadLengthInfo(bs,pLatmDemux))) { + return (ErrorStatus); + } + } else { + /* audioMuxVersionA > 0 is reserved for future extensions */ + ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + + return (ErrorStatus); +} + +TRANSPORTDEC_ERROR CLatmDemux_Read( + HANDLE_FDK_BITSTREAM bs, + CLatmDemux *pLatmDemux, + TRANSPORT_TYPE tt, + CSTpCallBacks *pTpDecCallbacks, + CSAudioSpecificConfig *pAsc, + const INT ignoreBufferFullness + ) +{ + UINT cntBits; + UINT cmpBufferFullness; + UINT audioMuxLengthBytesLast = 0; + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + + cntBits = FDKgetValidBits(bs); + + if ((INT)cntBits < MIN_LATM_HEADERLENGTH) { + return TRANSPORTDEC_NOT_ENOUGH_BITS; + } + + if ((ErrorStatus = CLatmDemux_ReadAudioMuxElement(bs, pLatmDemux, (tt != TT_MP4_LATM_MCP0), pTpDecCallbacks, pAsc))) + return (ErrorStatus); + + if (!ignoreBufferFullness) + { + cmpBufferFullness = 24+audioMuxLengthBytesLast*8 + + pLatmDemux->m_linfo[0][0].m_bufferFullness* pAsc[TPDEC_TRACKINDEX(0,0)].m_channelConfiguration*32; + + /* evaluate buffer fullness */ + + if (pLatmDemux->m_linfo[0][0].m_bufferFullness != 0xFF) + { + if (!pLatmDemux->BufferFullnessAchieved) + { + if (cntBits < cmpBufferFullness) + { + /* condition for start of decoding is not fulfilled */ + + /* the current frame will not be decoded */ + return TRANSPORTDEC_NOT_ENOUGH_BITS; + } + else + { + pLatmDemux->BufferFullnessAchieved = 1; + } + } + } + } + + return (ErrorStatus); +} + + +TRANSPORTDEC_ERROR CLatmDemux_ReadStreamMuxConfig( + HANDLE_FDK_BITSTREAM bs, + CLatmDemux *pLatmDemux, + CSTpCallBacks *pTpDecCallbacks, + CSAudioSpecificConfig *pAsc + ) +{ + LATM_LAYER_INFO *p_linfo = NULL; + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + + pLatmDemux->m_AudioMuxVersion = FDKreadBits(bs,1); + + if (pLatmDemux->m_AudioMuxVersion == 0) { + pLatmDemux->m_AudioMuxVersionA = 0; + } else { + pLatmDemux->m_AudioMuxVersionA = FDKreadBits(bs,1); + } + + if (pLatmDemux->m_AudioMuxVersionA == 0) { + if (pLatmDemux->m_AudioMuxVersion == 1) { + pLatmDemux->m_taraBufferFullness = CLatmDemux_GetValue(bs); + } + pLatmDemux->m_allStreamsSameTimeFraming = FDKreadBits(bs,1); + pLatmDemux->m_noSubFrames = FDKreadBits(bs,6) + 1; + pLatmDemux->m_numProgram = FDKreadBits(bs,4) + 1; + + if (pLatmDemux->m_numProgram > 1) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + + int idCnt = 0; + for (UINT prog = 0; prog < pLatmDemux->m_numProgram; prog++) { + pLatmDemux->m_numLayer = FDKreadBits(bs,3) + 1; + if (pLatmDemux->m_numLayer > 2) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + + for (UINT lay = 0; lay < pLatmDemux->m_numLayer; lay++) { + p_linfo = &pLatmDemux->m_linfo[prog][lay]; + + p_linfo->m_streamID = idCnt++; + p_linfo->m_frameLengthInBits = 0; + + if( (prog == 0) && (lay == 0) ) { + pLatmDemux->m_useSameConfig = 0; + } else { + pLatmDemux->m_useSameConfig = FDKreadBits(bs,1); + } + + if (pLatmDemux->m_useSameConfig) { + if (lay > 1) { + FDKmemcpy(&pAsc[TPDEC_TRACKINDEX(prog,lay)], &pAsc[TPDEC_TRACKINDEX(prog,lay-1)], sizeof(CSAudioSpecificConfig)); + } else { + return TRANSPORTDEC_PARSE_ERROR; + } + } else { + if (pLatmDemux->m_AudioMuxVersion == 1) + { + FDK_BITSTREAM tmpBs; + UINT ascStartPos, ascLen=0; + + ascLen = CLatmDemux_GetValue(bs); + ascStartPos = FDKgetValidBits(bs); + tmpBs = *bs; + FDKsyncCache(&tmpBs); + tmpBs.hBitBuf.ValidBits = ascLen; + + /* Read ASC */ + if ((ErrorStatus = AudioSpecificConfig_Parse(&pAsc[TPDEC_TRACKINDEX(prog,lay)], &tmpBs, 1, pTpDecCallbacks))) { + return (ErrorStatus); + } + + /* The field p_linfo->m_ascLen could be wrong, so check if */ + if ( 0 > (INT)FDKgetValidBits(&tmpBs)) { + return TRANSPORTDEC_PARSE_ERROR; + } + FDKpushFor(bs, ascLen); /* position bitstream after ASC */ + } + else { + /* Read ASC */ + if ((ErrorStatus = AudioSpecificConfig_Parse(&pAsc[TPDEC_TRACKINDEX(prog,lay)], bs, 0, pTpDecCallbacks))) { + return (ErrorStatus); + } + } + { + int cbError; + + cbError = pTpDecCallbacks->cbUpdateConfig(pTpDecCallbacks->cbUpdateConfigData, &pAsc[TPDEC_TRACKINDEX(prog,lay)]); + if (cbError != 0) { + return TRANSPORTDEC_UNKOWN_ERROR; + } + } + } + + p_linfo->m_frameLengthType = FDKreadBits(bs,3); + switch( p_linfo->m_frameLengthType ) { + case 0: + p_linfo->m_bufferFullness = FDKreadBits(bs,8); + + if (!pLatmDemux->m_allStreamsSameTimeFraming) { + if ((lay > 0) && (pAsc[TPDEC_TRACKINDEX(prog,lay)].m_aot == AOT_AAC_SCAL || pAsc[TPDEC_TRACKINDEX(prog,lay)].m_aot == AOT_ER_AAC_SCAL)) { + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + } + break; + case 1: + /* frameLength = FDKreadBits(bs,9); */ + case 3: + case 4: + case 5: + /* CELP */ + case 6: + case 7: + /* HVXC */ + default: + return TRANSPORTDEC_PARSE_ERROR; //_LATM_INVALIDFRAMELENGTHTYPE; + + } /* switch framelengthtype*/ + + } /* layer loop */ + } /* prog loop */ + + pLatmDemux->m_otherDataPresent = FDKreadBits(bs,1); + pLatmDemux->m_otherDataLength = 0; + + if (pLatmDemux->m_otherDataPresent) { + int otherDataLenEsc = 0; + do { + pLatmDemux->m_otherDataLength <<= 8; // *= 256 + otherDataLenEsc = FDKreadBits(bs,1); + pLatmDemux->m_otherDataLength += FDKreadBits(bs,8); + } while (otherDataLenEsc); + } + + pLatmDemux->m_crcCheckPresent = FDKreadBits(bs,1); + pLatmDemux->m_crcCheckSum = 0; + + if (pLatmDemux->m_crcCheckPresent) { + pLatmDemux->m_crcCheckSum = FDKreadBits(bs,8); + } + + } + else { + /* audioMuxVersionA > 0 is reserved for future extensions */ + ErrorStatus = TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + return (ErrorStatus); +} + +TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs, CLatmDemux *pLatmDemux) +{ + TRANSPORTDEC_ERROR ErrorStatus = TRANSPORTDEC_OK; + int totalPayloadBits = 0; + + if( pLatmDemux->m_allStreamsSameTimeFraming == 1 ) { + for (UINT prog=0; progm_numProgram; prog++ ) { + for (UINT lay=0; laym_numLayer; lay++ ) { + LATM_LAYER_INFO *p_linfo = &pLatmDemux->m_linfo[prog][lay]; + + switch (p_linfo->m_frameLengthType ) { + case 0: + p_linfo->m_frameLengthInBits = CLatmDemux_ReadAuChunkLengthInfo(bs); + totalPayloadBits += p_linfo->m_frameLengthInBits; + break; + case 3: + case 5: + case 7: + default: + return TRANSPORTDEC_PARSE_ERROR; //AAC_DEC_LATM_INVALIDFRAMELENGTHTYPE; + } + } + } + } + else { + ErrorStatus = TRANSPORTDEC_PARSE_ERROR; //AAC_DEC_LATM_TIMEFRAMING; + } + if ((INT)FDKgetValidBits(bs) < totalPayloadBits) { + return TRANSPORTDEC_NOT_ENOUGH_BITS; + } + if (pLatmDemux->m_audioMuxLengthBytes > 0 && totalPayloadBits > pLatmDemux->m_audioMuxLengthBytes*8) { + return TRANSPORTDEC_PARSE_ERROR; + } + return (ErrorStatus); +} + +int CLatmDemux_ReadAuChunkLengthInfo(HANDLE_FDK_BITSTREAM bs) +{ + UCHAR endFlag; + int len = 0; + + do { + UCHAR tmp = (UCHAR) FDKreadBits(bs,8); + endFlag = (tmp < 255); + + len += tmp; + + } while( endFlag == 0 ); + + len <<= 3; /* convert from bytes to bits */ + + return len; +} + +int CLatmDemux_GetFrameLengthInBits(CLatmDemux *pLatmDemux) +{ + return pLatmDemux->m_linfo[0][0].m_frameLengthInBits; +} + +int CLatmDemux_GetOtherDataPresentFlag(CLatmDemux *pLatmDemux) +{ + return pLatmDemux->m_otherDataPresent ? 1 : 0; +} + +int CLatmDemux_GetOtherDataLength(CLatmDemux *pLatmDemux) +{ + return pLatmDemux->m_otherDataLength; +} + +UINT CLatmDemux_GetNrOfSubFrames(CLatmDemux *pLatmDemux) +{ + return pLatmDemux->m_noSubFrames; +} + diff --git a/libMpegTPDec/src/tpdec_latm.h b/libMpegTPDec/src/tpdec_latm.h new file mode 100644 index 0000000..54854b3 --- /dev/null +++ b/libMpegTPDec/src/tpdec_latm.h @@ -0,0 +1,103 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Daniel Homm + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef LATM_DEMUX_H +#define LATM_DEMUX_H + +#include "tpdec_lib.h" + + +#include "FDK_bitstream.h" + +#define MIN_LATM_HEADERLENGTH 9 +#define MIN_LOAS_HEADERLENGTH MIN_LATM_HEADERLENGTH + 24 /* both in bits */ + #define MIN_TP_BUF_SIZE_LOAS ( 8194 ) + +enum { + LATM_MAX_PROG = 1, + LATM_MAX_LAYER = 2, + LATM_MAX_VAR_CHUNKS=16, + LATM_MAX_ID=16 +}; + +typedef struct { + UINT m_frameLengthType; + UINT m_bufferFullness; + UINT m_streamID; + UINT m_frameLengthInBits; +} LATM_LAYER_INFO; + +typedef struct { + LATM_LAYER_INFO m_linfo[LATM_MAX_PROG][LATM_MAX_LAYER]; + UINT m_taraBufferFullness; + UINT m_otherDataLength; + UINT m_audioMuxLengthBytes; /* Length of LOAS payload */ + + UCHAR m_useSameStreamMux; + UCHAR m_AudioMuxVersion; + UCHAR m_AudioMuxVersionA; + UCHAR m_allStreamsSameTimeFraming; + UCHAR m_noSubFrames; + UCHAR m_numProgram; + UCHAR m_numLayer; + UCHAR m_useSameConfig; + + UCHAR m_otherDataPresent; + UCHAR m_crcCheckPresent; + UCHAR m_crcCheckSum; + + SCHAR BufferFullnessAchieved; +} CLatmDemux; + +int CLatmDemux_ReadAuChunkLengthInfo(HANDLE_FDK_BITSTREAM bs); + +TRANSPORTDEC_ERROR CLatmDemux_Read( + HANDLE_FDK_BITSTREAM bs, + CLatmDemux *pLatmDemux, + TRANSPORT_TYPE tt, + CSTpCallBacks *pTpDecCallbacks, + CSAudioSpecificConfig *pAsc, + const INT ignoreBufferFullness + ); + +TRANSPORTDEC_ERROR CLatmDemux_ReadStreamMuxConfig( + HANDLE_FDK_BITSTREAM bs, + CLatmDemux *pLatmDemux, + CSTpCallBacks *pTpDecCallbacks, + CSAudioSpecificConfig *pAsc + ); + +TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs, CLatmDemux *pLatmDemux); + +int CLatmDemux_GetFrameLengthInBits(CLatmDemux *pLatmDemux); +int CLatmDemux_GetOtherDataPresentFlag(CLatmDemux *pLatmDemux); +int CLatmDemux_GetOtherDataLength(CLatmDemux *pLatmDemux); +UINT CLatmDemux_GetNrOfSubFrames(CLatmDemux *pLatmDemux); + + +#endif /* LATM_DEMUX_H */ diff --git a/libMpegTPDec/src/tpdec_lib.cpp b/libMpegTPDec/src/tpdec_lib.cpp new file mode 100644 index 0000000..4387847 --- /dev/null +++ b/libMpegTPDec/src/tpdec_lib.cpp @@ -0,0 +1,1127 @@ +/************************** MPEG-4 Transport Decoder ************************ + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: MPEG Transport decoder + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "tpdec_lib.h" + +/* library version */ +#include "version" + + +#include "tp_data.h" + +#include "tpdec_adts.h" + +#include "tpdec_adif.h" + +#include "tpdec_latm.h" + + + +#define MODULE_NAME "transportDec" + +typedef union { + STRUCT_ADTS adts; + + CAdifHeader adif; + + CLatmDemux latm; + + +} transportdec_parser_t; + +struct TRANSPORTDEC +{ + TRANSPORT_TYPE transportFmt; /*!< MPEG4 transportDec type. */ + + CSTpCallBacks callbacks; /*!< Struct holding callback and its data */ + + FDK_BITSTREAM bitStream[2]; /* Bitstream reader */ + UCHAR *bsBuffer; /* Internal bitstreamd data buffer (unallocated in case of TT_MP4_RAWPACKETS) */ + + transportdec_parser_t parser; /* Format specific parser structs. */ + + CSAudioSpecificConfig asc[(1*2)]; /* Audio specific config from the last config found. */ + UINT globalFramePos; /* Global transport frame reference bit position. */ + UINT accessUnitAnchor[2]; /* Current access unit start bit position. */ + INT auLength[2]; /* Length of current access unit. */ + INT numberOfRawDataBlocks; /* Current number of raw data blocks contained remaining from the current transport frame. */ + UINT avgBitRate; /* Average bit rate used for frame loss estimation. */ + UINT lastValidBufferFullness; /* Last valid buffer fullness value for frame loss estimation */ + INT remainder; /* Reminder in division during lost access unit estimation. */ + INT missingAccessUnits; /* Estimated missing access units. */ + UINT burstPeriod; /* Data burst period in mili seconds. */ + UINT holdOffFrames; /* Amount of frames that were already hold off due to buffer fullness condition not being met. */ + UINT flags; /* Flags. */ +}; + +/* Flag bitmasks for "flags" member of struct TRANSPORTDEC */ +#define TPDEC_SYNCOK 1 +#define TPDEC_MINIMIZE_DELAY 2 +#define TPDEC_IGNORE_BUFFERFULLNESS 4 +#define TPDEC_EARLY_CONFIG 8 +#define TPDEC_LOST_FRAMES_PENDING 16 + +C_ALLOC_MEM(Ram_TransportDecoder, TRANSPORTDEC, 1) +C_ALLOC_MEM(Ram_TransportDecoderBuffer, UCHAR, TRANSPORTDEC_INBUF_SIZE) + + + + +HANDLE_TRANSPORTDEC transportDec_Open( const TRANSPORT_TYPE transportFmt, const UINT flags) +{ + HANDLE_TRANSPORTDEC hInput; + + hInput = GetRam_TransportDecoder(0); + if ( hInput == NULL ) { + return NULL; + } + + /* Init transportDec struct. */ + hInput->transportFmt = transportFmt; + + switch (transportFmt) { + + case TT_MP4_ADIF: + break; + + case TT_MP4_ADTS: + if (flags & TP_FLAG_MPEG4) + hInput->parser.adts.decoderCanDoMpeg4 = 1; + else + hInput->parser.adts.decoderCanDoMpeg4 = 0; + adtsRead_CrcInit(&hInput->parser.adts); + hInput->parser.adts.BufferFullnesStartFlag = 1; + hInput->numberOfRawDataBlocks = 0; + break; + + + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + case TT_MP4_LOAS: + case TT_MP4_RAW: + break; + + default: + FreeRam_TransportDecoder(&hInput); + hInput = NULL; + break; + } + + if (hInput != NULL) { + /* Create bitstream */ + if ( (transportFmt == TT_MP4_RAW) + || (transportFmt == TT_DRM) ){ + hInput->bsBuffer = NULL; + } else { + hInput->bsBuffer = GetRam_TransportDecoderBuffer(0); + if (hInput->bsBuffer == NULL) { + transportDec_Close( &hInput ); + return NULL; + } + FDKinitBitStream(&hInput->bitStream[0], hInput->bsBuffer, TRANSPORTDEC_INBUF_SIZE, 0, BS_READER); + } + + hInput->burstPeriod = 0; + } + + return hInput; +} + +TRANSPORTDEC_ERROR transportDec_OutOfBandConfig(HANDLE_TRANSPORTDEC hTp, UCHAR *conf, const UINT length, UINT layer ) +{ + TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; + + FDK_BITSTREAM bs; + HANDLE_FDK_BITSTREAM hBs = &bs; + + FDKinitBitStream(hBs, conf, 0x80000000, length<<3, BS_READER); + + /* config transport decoder */ + switch (hTp->transportFmt) { + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + case TT_MP4_LOAS: + { + if (layer != 0) { + return TRANSPORTDEC_INVALID_PARAMETER; + } + CLatmDemux *pLatmDemux = &hTp->parser.latm; + err = CLatmDemux_ReadStreamMuxConfig(hBs, pLatmDemux, &hTp->callbacks, hTp->asc); + if (err != TRANSPORTDEC_OK) { + return err; + } + } + break; + case TT_MP4_RAW: + err = AudioSpecificConfig_Parse(&hTp->asc[layer], hBs, 1, &hTp->callbacks); + break; + default: + return TRANSPORTDEC_UNSUPPORTED_FORMAT; + } + if (err == TRANSPORTDEC_OK) { + int errC; + + errC = hTp->callbacks.cbUpdateConfig(hTp->callbacks.cbUpdateConfigData, &hTp->asc[layer]); + if (errC != 0) { + err = TRANSPORTDEC_PARSE_ERROR; + } + } + + return err; +} + +int transportDec_RegisterAscCallback( HANDLE_TRANSPORTDEC hTpDec, const cbUpdateConfig_t cbUpdateConfig, void* user_data) +{ + if (hTpDec == NULL) { + return -1; + } + hTpDec->callbacks.cbUpdateConfig = cbUpdateConfig; + hTpDec->callbacks.cbUpdateConfigData = user_data; + return 0; +} + +int transportDec_RegisterSscCallback( HANDLE_TRANSPORTDEC hTpDec, const cbSsc_t cbSsc, void* user_data) +{ + if (hTpDec == NULL) { + return -1; + } + hTpDec->callbacks.cbSsc = cbSsc; + hTpDec->callbacks.cbSscData = user_data; + return 0; +} + +int transportDec_RegisterSbrCallback( HANDLE_TRANSPORTDEC hTpDec, const cbSbr_t cbSbr, void* user_data) +{ + if (hTpDec == NULL) { + return -1; + } + hTpDec->callbacks.cbSbr = cbSbr; + hTpDec->callbacks.cbSbrData = user_data; + return 0; +} + +TRANSPORTDEC_ERROR transportDec_FillData( + const HANDLE_TRANSPORTDEC hTp, + UCHAR *pBuffer, + const UINT bufferSize, + UINT *pBytesValid, + const INT layer ) +{ + HANDLE_FDK_BITSTREAM hBs; + + if ( (hTp == NULL) + || (layer >= 2) ) { + return TRANSPORTDEC_INVALID_PARAMETER; + } + + if (*pBytesValid == 0) { + /* nothing to do */ + return TRANSPORTDEC_OK; + } + + /* set bitbuffer shortcut */ + hBs = &hTp->bitStream[layer]; + + switch (hTp->transportFmt) { + case TT_MP4_RAW: + case TT_DRM: + /* For packet based transport, pass input buffer to bitbuffer without copying the data. + Unfortunately we do not know the actual buffer size. And the FDK bit buffer implementation + needs a number 2^x. So we assume the maximum of 48 channels with 6144 bits per channel + and round it up to the next power of 2 => 65536 bytes */ + FDKinitBitStream(hBs, pBuffer, 0x10000, (*pBytesValid)<<3, BS_READER); + *pBytesValid = 0; + break; + + default: + /* ... else feed bitbuffer with new stream data (append). */ + if (hTp->numberOfRawDataBlocks <= 0) { + FDKfeedBuffer (hBs, pBuffer, bufferSize, pBytesValid) ; + } + } + + return TRANSPORTDEC_OK; +} + +HANDLE_FDK_BITSTREAM transportDec_GetBitstream( const HANDLE_TRANSPORTDEC hTp, const UINT layer ) +{ + return &hTp->bitStream[layer]; +} + +TRANSPORT_TYPE transportDec_GetFormat( const HANDLE_TRANSPORTDEC hTp ) +{ + return hTp->transportFmt; +} + +INT transportDec_GetBufferFullness( const HANDLE_TRANSPORTDEC hTp ) +{ + INT bufferFullness = -1; + + switch (hTp->transportFmt) { + case TT_MP4_ADTS: + if (hTp->parser.adts.bs.adts_fullness != 0x7ff) { + bufferFullness = hTp->parser.adts.bs.frame_length*8 + hTp->parser.adts.bs.adts_fullness * 32 * getNumberOfEffectiveChannels(hTp->parser.adts.bs.channel_config); + } + break; + case TT_MP4_LOAS: + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + if (hTp->parser.latm.m_linfo[0][0].m_bufferFullness != 0xff) { + bufferFullness = hTp->parser.latm.m_linfo[0][0].m_bufferFullness; + } + break; + default: + break; + } + + return bufferFullness; +} + +/** + * \brief Determine additional buffer fullness contraint due to burst data reception. + * The parameter TPDEC_PARAM_BURSTPERIOD must have been set as a precondition. + * \param hTp transport decoder handle. + * \param bufferFullness the buffer fullness value of the first frame to be decoded. + * \param bitsAvail the amount of available bits at the end of the first frame to be decoded. + * \return error code + */ +static +TRANSPORTDEC_ERROR additionalHoldOffNeeded( + HANDLE_TRANSPORTDEC hTp, + INT bufferFullness, + INT bitsAvail + ) +{ + INT checkLengthBits, avgBitsPerFrame; + INT maxAU; /* maximum number of frames per Master Frame */ + INT samplesPerFrame = hTp->asc->m_samplesPerFrame; + INT samplingFrequency = (INT)hTp->asc->m_samplingFrequency; + + if ( (hTp->avgBitRate == 0) || (hTp->burstPeriod == 0) ) { + return TRANSPORTDEC_OK; + } + if ( (samplesPerFrame == 0 ) || (samplingFrequency == 0) ) { + return TRANSPORTDEC_NOT_ENOUGH_BITS; + } + + /* One Master Frame is sent every hTp->burstPeriod ms */ + maxAU = hTp->burstPeriod * samplingFrequency + (samplesPerFrame*1000 - 1); + maxAU = maxAU / (samplesPerFrame*1000); + /* Subtract number of frames which were already held off. */ + maxAU -= hTp->holdOffFrames; + + avgBitsPerFrame = hTp->avgBitRate * samplesPerFrame + (samplingFrequency-1); + avgBitsPerFrame = avgBitsPerFrame / samplingFrequency; + + /* Consider worst case of bufferFullness quantization. */ + switch (hTp->transportFmt) { + case TT_MP4_ADIF: + case TT_MP4_ADTS: + case TT_MP4_LOAS: + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + bufferFullness += 31; + break; + default: + break; + } + + checkLengthBits = bufferFullness + (maxAU-1)*avgBitsPerFrame; + + /* Check if buffer is big enough to fullfill buffer fullness condition */ + if ( (checkLengthBits /*+headerBits*/) > ((TRANSPORTDEC_INBUF_SIZE<<3)-7) ) { + return TRANSPORTDEC_SYNC_ERROR; + } + + if ( bitsAvail < checkLengthBits ) { + return TRANSPORTDEC_NOT_ENOUGH_BITS; + } + else { + return TRANSPORTDEC_OK; + } +} + +/** + * \brief adjust bit stream position and the end of an access unit. + * \param hTp transport decoder handle. + * \return error code. + */ +static +TRANSPORTDEC_ERROR transportDec_AdjustEndOfAccessUnit(HANDLE_TRANSPORTDEC hTp) +{ + HANDLE_FDK_BITSTREAM hBs = &hTp->bitStream[0]; + TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; + + switch (hTp->transportFmt) { + case TT_MP4_LOAS: + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + if ( hTp->numberOfRawDataBlocks == 0 ) + { + /* Check global frame length */ + if (hTp->transportFmt == TT_MP4_LOAS && hTp->parser.latm.m_audioMuxLengthBytes > 0) + { + int loasOffset; + + loasOffset = (hTp->parser.latm.m_audioMuxLengthBytes*8 + FDKgetValidBits(hBs)) - hTp->globalFramePos; + if (loasOffset != 0) { + FDKpushBiDirectional(hBs, loasOffset); + /* For ELD and other payloads there is an unknown amount of padding, so ignore unread bits, but + throw an error only if too many bits where read. */ + if (loasOffset < 0) { + err = TRANSPORTDEC_PARSE_ERROR; + } + } + } + + /* Do global LOAS/LATM audioMuxElement byte alignment */ + FDKbyteAlign(hBs, hTp->globalFramePos); + } + break; + default: + break; + } + + return err; +} + + +/* How many bits to advance for synchronization search. */ +#define TPDEC_SYNCSKIP 8 + +static +TRANSPORTDEC_ERROR synchronization( + HANDLE_TRANSPORTDEC hTp, + INT *pHeaderBits + ) +{ + TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK, errFirstFrame = TRANSPORTDEC_OK; + HANDLE_FDK_BITSTREAM hBs = &hTp->bitStream[0]; + + INT syncLayerFrameBits = 0; /* Length of sync layer frame (i.e. LOAS) */ + INT rawDataBlockLength = 0, rawDataBlockLengthPrevious; + INT totalBits; + INT headerBits = 0, headerBitsFirstFrame = 0, headerBitsPrevious; + INT numFramesTraversed = 0, fTraverseMoreFrames, fConfigFound = 0, startPos, startPosFirstFrame = -1; + INT numRawDataBlocksFirstFrame = 0, numRawDataBlocksPrevious, globalFramePosFirstFrame = 0, rawDataBlockLengthFirstFrame = 0; + INT ignoreBufferFullness = hTp->flags & (TPDEC_IGNORE_BUFFERFULLNESS|TPDEC_SYNCOK); + + /* Synch parameters */ + INT syncLength; /* Length of sync word in bits */ + UINT syncWord; /* Sync word to be found */ + UINT syncMask; /* Mask for sync word (for adding one bit, so comprising one bit less) */ + C_ALLOC_SCRATCH_START(contextFirstFrame, transportdec_parser_t, 1); + + totalBits = (INT)FDKgetValidBits(hBs); + + fTraverseMoreFrames = (hTp->flags & (TPDEC_MINIMIZE_DELAY|TPDEC_EARLY_CONFIG)) && ! (hTp->flags & TPDEC_SYNCOK); + + /* Set transport specific sync parameters */ + switch (hTp->transportFmt) { + case TT_MP4_ADTS: + syncWord = ADTS_SYNCWORD; + syncLength = ADTS_SYNCLENGTH; + break; + case TT_MP4_LOAS: + syncWord = 0x2B7; + syncLength = 11; + break; + default: + syncWord = 0; + syncLength = 0; + break; + } + + syncMask = (1<numberOfRawDataBlocks == 0) { + /* search synchword */ + + FDK_ASSERT( (bitsAvail % TPDEC_SYNCSKIP) == 0); + + if ((bitsAvail-syncLength) < TPDEC_SYNCSKIP) { + err = TRANSPORTDEC_NOT_ENOUGH_BITS; + headerBits = 0; + } else { + + synch = FDKreadBits(hBs, syncLength); + + if ( !(hTp->flags & TPDEC_SYNCOK) ) { + for (; (bitsAvail-syncLength) >= TPDEC_SYNCSKIP; bitsAvail-=TPDEC_SYNCSKIP) { + if (synch == syncWord) { + break; + } + synch = ((synch << TPDEC_SYNCSKIP) & syncMask) | FDKreadBits(hBs, TPDEC_SYNCSKIP); + } + } + if (synch != syncWord) { + /* No correct syncword found. */ + err = TRANSPORTDEC_SYNC_ERROR; + } else { + err = TRANSPORTDEC_OK; + } + headerBits = syncLength; + } + } else { + headerBits = 0; + } + + /* Save previous raw data block data */ + rawDataBlockLengthPrevious = rawDataBlockLength; + numRawDataBlocksPrevious = hTp->numberOfRawDataBlocks; + + /* Parse transport header (raw data block granularity) */ + startPos = FDKgetValidBits(hBs); + + if (err == TRANSPORTDEC_OK ) + { + switch (hTp->transportFmt) { + case TT_MP4_ADTS: + if (hTp->numberOfRawDataBlocks <= 0) + { + int errC; + + /* Parse ADTS header */ + err = adtsRead_DecodeHeader( &hTp->parser.adts, &hTp->asc[0], hBs, ignoreBufferFullness ); + if (err != TRANSPORTDEC_OK) { + if (err != TRANSPORTDEC_NOT_ENOUGH_BITS) { + err = TRANSPORTDEC_SYNC_ERROR; + } + } else { + errC = hTp->callbacks.cbUpdateConfig(hTp->callbacks.cbUpdateConfigData, &hTp->asc[0]); + if (errC != 0) { + err = TRANSPORTDEC_SYNC_ERROR; + } else { + hTp->numberOfRawDataBlocks = hTp->parser.adts.bs.num_raw_blocks+1; + /* CAUTION: The PCE (if available) is declared to be a part of the header! */ + hTp->globalFramePos = FDKgetValidBits(hBs) + hTp->parser.adts.bs.num_pce_bits; + } + } + } + else { + /* Reset CRC because the next bits are the beginning of a raw_data_block() */ + FDKcrcReset(&hTp->parser.adts.crcInfo); + hTp->globalFramePos = FDKgetValidBits(hBs); + } + if (err == TRANSPORTDEC_OK) { + hTp->numberOfRawDataBlocks--; + rawDataBlockLength = adtsRead_GetRawDataBlockLength(&hTp->parser.adts, (hTp->parser.adts.bs.num_raw_blocks-hTp->numberOfRawDataBlocks)); + syncLayerFrameBits = (hTp->parser.adts.bs.frame_length<<3) - (startPos - FDKgetValidBits(hBs)) - syncLength; + if (syncLayerFrameBits <= 0) { + err = TRANSPORTDEC_SYNC_ERROR; + } + } else { + hTp->numberOfRawDataBlocks = 0; + } + break; + case TT_MP4_LOAS: + if (hTp->numberOfRawDataBlocks <= 0) + { + syncLayerFrameBits = FDKreadBits(hBs, 13); + hTp->parser.latm.m_audioMuxLengthBytes = syncLayerFrameBits; + syncLayerFrameBits <<= 3; + } + case TT_MP4_LATM_MCP1: + case TT_MP4_LATM_MCP0: + if (hTp->numberOfRawDataBlocks <= 0) + { + hTp->globalFramePos = FDKgetValidBits(hBs); + + err = CLatmDemux_Read( + hBs, + &hTp->parser.latm, + hTp->transportFmt, + &hTp->callbacks, + hTp->asc, + ignoreBufferFullness); + + if (err != TRANSPORTDEC_OK) { + if (err != TRANSPORTDEC_NOT_ENOUGH_BITS) { + err = TRANSPORTDEC_SYNC_ERROR; + } + } else { + hTp->numberOfRawDataBlocks = CLatmDemux_GetNrOfSubFrames(&hTp->parser.latm); + syncLayerFrameBits -= startPos - FDKgetValidBits(hBs) - (13); + } + } else { + err = CLatmDemux_ReadPayloadLengthInfo(hBs, &hTp->parser.latm); + if (err != TRANSPORTDEC_OK) { + err = TRANSPORTDEC_SYNC_ERROR; + } + } + if (err == TRANSPORTDEC_OK) { + rawDataBlockLength = CLatmDemux_GetFrameLengthInBits(&hTp->parser.latm); + hTp->numberOfRawDataBlocks--; + } else { + hTp->numberOfRawDataBlocks = 0; + } + break; + default: + { + syncLayerFrameBits = 0; + } + break; + } + } + + headerBits += startPos - (INT)FDKgetValidBits(hBs); + bitsAvail -= headerBits; + + checkLengthBits = syncLayerFrameBits; + + /* Check if the whole frame would fit the bitstream buffer */ + if (err == TRANSPORTDEC_OK) { + if ( (checkLengthBits+headerBits) > ((TRANSPORTDEC_INBUF_SIZE<<3)-7) ) { + /* We assume that the size of the transport bit buffer has been + chosen to meet all system requirements, thus this condition + is considered a synchronisation error. */ + err = TRANSPORTDEC_SYNC_ERROR; + } else { + if ( bitsAvail < checkLengthBits ) { + err = TRANSPORTDEC_NOT_ENOUGH_BITS; + } + } + } + + if (err == TRANSPORTDEC_NOT_ENOUGH_BITS) { + break; + } + + + if (err == TRANSPORTDEC_SYNC_ERROR) { + int bits; + + FDK_ASSERT(hTp->numberOfRawDataBlocks == 0); + /* Ensure that the bit amount lands and a multiple of TPDEC_SYNCSKIP */ + bits = (bitsAvail + headerBits) % TPDEC_SYNCSKIP; + /* Rewind - TPDEC_SYNCSKIP, in order to look for a synch one bit ahead next time. */ + FDKpushBiDirectional(hBs, -(headerBits - TPDEC_SYNCSKIP) + bits); + bitsAvail += headerBits - TPDEC_SYNCSKIP - bits; + headerBits = 0; + } + + /* Frame traversal */ + if ( fTraverseMoreFrames ) + { + /* Save parser context for early config discovery "rewind all frames" */ + if ( (hTp->flags & TPDEC_EARLY_CONFIG) && !(hTp->flags & TPDEC_MINIMIZE_DELAY)) + { + /* ignore buffer fullness if just traversing additional frames for ECD */ + ignoreBufferFullness = 1; + + /* Save context in order to return later */ + if ( err == TRANSPORTDEC_OK && startPosFirstFrame == -1 ) { + startPosFirstFrame = FDKgetValidBits(hBs); + numRawDataBlocksFirstFrame = hTp->numberOfRawDataBlocks; + globalFramePosFirstFrame = hTp->globalFramePos; + rawDataBlockLengthFirstFrame = rawDataBlockLength; + headerBitsFirstFrame = headerBits; + errFirstFrame = err; + FDKmemcpy(contextFirstFrame, &hTp->parser, sizeof(transportdec_parser_t)); + } + + /* Break when config was found or it is not possible anymore to find a config */ + if (startPosFirstFrame != -1 && (fConfigFound || err != TRANSPORTDEC_OK)) { + break; + } + } + + if (err == TRANSPORTDEC_OK) { + FDKpushFor(hBs, rawDataBlockLength); + bitsAvail -= rawDataBlockLength; + numFramesTraversed++; + /* Ignore error here itentionally. */ + transportDec_AdjustEndOfAccessUnit(hTp); + } + } + } while ( fTraverseMoreFrames || (err == TRANSPORTDEC_SYNC_ERROR && !(hTp->flags & TPDEC_SYNCOK))); + + /* Restore context in case of ECD frame traversal */ + if ( startPosFirstFrame != -1 && (fConfigFound || err != TRANSPORTDEC_OK) ) { + FDKpushBiDirectional(hBs, FDKgetValidBits(hBs) - startPosFirstFrame); + FDKmemcpy(&hTp->parser, contextFirstFrame, sizeof(transportdec_parser_t)); + hTp->numberOfRawDataBlocks = numRawDataBlocksFirstFrame; + hTp->globalFramePos = globalFramePosFirstFrame; + rawDataBlockLength = rawDataBlockLengthFirstFrame; + headerBits = headerBitsFirstFrame; + err = errFirstFrame; + numFramesTraversed = 0; + } + + /* Additional burst data mode buffer fullness check. */ + if ( !(hTp->flags & (TPDEC_IGNORE_BUFFERFULLNESS|TPDEC_SYNCOK)) && err == TRANSPORTDEC_OK) { + err = additionalHoldOffNeeded(hTp, transportDec_GetBufferFullness(hTp), FDKgetValidBits(hBs) - syncLayerFrameBits); + if (err == TRANSPORTDEC_NOT_ENOUGH_BITS) { + hTp->holdOffFrames++; + } + } + + /* Rewind for retry because of not enough bits */ + if (err == TRANSPORTDEC_NOT_ENOUGH_BITS) { + FDKpushBack(hBs, headerBits); + headerBits = 0; + } + else { + /* reset hold off frame counter */ + hTp->holdOffFrames = 0; + } + + /* Return to last good frame in case of frame traversal but not ECD. */ + if (numFramesTraversed > 0) { + FDKpushBack(hBs, rawDataBlockLengthPrevious); + if (err != TRANSPORTDEC_OK) { + hTp->numberOfRawDataBlocks = numRawDataBlocksPrevious; + headerBits = headerBitsPrevious; + } + err = TRANSPORTDEC_OK; + } + + hTp->auLength[0] = rawDataBlockLength; + + if (err == TRANSPORTDEC_OK) { + hTp->flags |= TPDEC_SYNCOK; + } + + if (pHeaderBits != NULL) { + *pHeaderBits = headerBits; + } + + if (err == TRANSPORTDEC_SYNC_ERROR) { + hTp->flags &= ~TPDEC_SYNCOK; + } + + C_ALLOC_SCRATCH_END(contextFirstFrame, transportdec_parser_t, 1); + + return err; +} + +/** + * \brief Synchronize to stream and estimate the amount of missing access units due + * to a current synchronization error in case of constant average bit rate. + */ +static +TRANSPORTDEC_ERROR transportDec_readStream ( HANDLE_TRANSPORTDEC hTp, const UINT layer ) +{ + + TRANSPORTDEC_ERROR error = TRANSPORTDEC_OK; + HANDLE_FDK_BITSTREAM hBs = &hTp->bitStream[layer]; + INT nAU = -1; + INT headerBits; + INT bitDistance, bfDelta; + + /* Obtain distance to next synch word */ + bitDistance = FDKgetValidBits(hBs); + error = synchronization(hTp, &headerBits); + bitDistance -= FDKgetValidBits(hBs); + + + FDK_ASSERT(bitDistance >= 0); + + if (error == TRANSPORTDEC_SYNC_ERROR || (hTp->flags & TPDEC_LOST_FRAMES_PENDING)) + { + /* Check if estimating lost access units is feasible. */ + if (hTp->avgBitRate > 0 && hTp->asc[0].m_samplesPerFrame > 0 && hTp->asc[0].m_samplingFrequency > 0) + { + if (error == TRANSPORTDEC_OK) + { + int aj; + + aj = transportDec_GetBufferFullness(hTp); + if (aj > 0) { + bfDelta = aj; + } else { + bfDelta = 0; + } + /* sync was ok: last of a series of bad access units. */ + hTp->flags &= ~TPDEC_LOST_FRAMES_PENDING; + /* Add up bitDistance until end of the current frame. Later we substract + this frame from the grand total, since this current successfully synchronized + frame should not be skipped of course; but it must be accounted into the + bufferfulness math. */ + bitDistance += hTp->auLength[0]; + } else { + if ( !(hTp->flags & TPDEC_LOST_FRAMES_PENDING) ) { + /* sync not ok: one of many bad access units. */ + hTp->flags |= TPDEC_LOST_FRAMES_PENDING; + bfDelta = - (INT)hTp->lastValidBufferFullness; + } else { + bfDelta = 0; + } + } + + { + int num, denom; + + /* Obtain estimate of number of lost frames */ + num = hTp->asc[0].m_samplingFrequency * (bfDelta + bitDistance) + hTp->remainder; + denom = hTp->avgBitRate * hTp->asc[0].m_samplesPerFrame; + if (num > 0) { + nAU = num / denom; + hTp->remainder = num % denom; + } else { + hTp->remainder = num; + } + + if (error == TRANSPORTDEC_OK) + { + /* Final adjustment of remainder, taken -1 into account because current + frame should not be skipped, thus substract -1 or do nothing instead + of +1-1 accordingly. */ + if ( (denom - hTp->remainder) >= hTp->remainder ) { + nAU--; + } + + if (nAU < 0) { + /* There was one frame too much concealed, so unfortunately we will have to skip one good frame. */ + transportDec_EndAccessUnit(hTp); + error = synchronization(hTp, &headerBits); + nAU = -1; +#ifdef DEBUG + FDKprintf("ERROR: Bufferfullness accounting failed. remainder=%d, nAU=%d\n", hTp->remainder, nAU); +#endif + } + hTp->remainder = 0; + /* Enforce last missed frames to be concealed. */ + if (nAU > 0) { + FDKpushBack(hBs, headerBits); + } + } + } + } + } + + /* Be sure that lost frames are handled correctly. This is necessary due to some + sync error sequences where later it turns out that there is not enough data, but + the bits upto the sync word are discarded, thus causing a value of nAU > 0 */ + if (nAU > 0) { + error = TRANSPORTDEC_SYNC_ERROR; + } + + hTp->missingAccessUnits = nAU; + + return error; +} + +/* returns error code */ +TRANSPORTDEC_ERROR transportDec_ReadAccessUnit( const HANDLE_TRANSPORTDEC hTp, const UINT layer ) +{ + TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; + HANDLE_FDK_BITSTREAM hBs; + + if (!hTp) { + return TRANSPORTDEC_INVALID_PARAMETER; + } + + hBs = &hTp->bitStream[layer]; + + switch (hTp->transportFmt) { + + case TT_MP4_ADIF: + /* Read header if not already done */ + if (!(hTp->flags & TPDEC_SYNCOK)) + { + CProgramConfig *pce; + + AudioSpecificConfig_Init(&hTp->asc[0]); + pce = &hTp->asc[0].m_progrConfigElement; + err = adifRead_DecodeHeader(&hTp->parser.adif, pce, hBs); + if (err) + goto bail; + + /* Map adif header to ASC */ + hTp->asc[0].m_aot = (AUDIO_OBJECT_TYPE)(pce->Profile + 1); + hTp->asc[0].m_samplingFrequencyIndex = pce->SamplingFrequencyIndex; + hTp->asc[0].m_samplingFrequency = SamplingRateTable[pce->SamplingFrequencyIndex]; + hTp->asc[0].m_channelConfiguration = 0; + hTp->asc[0].m_samplesPerFrame = 1024; + hTp->avgBitRate = hTp->parser.adif.BitRate; + + /* Call callback to decoder. */ + { + int errC; + + errC = hTp->callbacks.cbUpdateConfig(hTp->callbacks.cbUpdateConfigData, &hTp->asc[0]); + if (errC == 0) { + /* Misuse sync flag to parse header only once. */ + hTp->flags |= TPDEC_SYNCOK; + } else { + err = TRANSPORTDEC_PARSE_ERROR; + goto bail; + } + } + } + hTp->auLength[layer] = -1; /* Access Unit data length is unknown. */ + break; + + case TT_MP4_RAW: + if ((INT)FDKgetValidBits(hBs) <= 0 && layer == 0) { + err = TRANSPORTDEC_NOT_ENOUGH_BITS; + } + /* One Access Unit was filled into buffer. + So get the length out of the buffer. */ + hTp->auLength[layer] = FDKgetValidBits(hBs); + hTp->flags |= TPDEC_SYNCOK; + break; + + case TT_RSVD50: + case TT_MP4_ADTS: + case TT_MP4_LOAS: + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + err = transportDec_readStream(hTp, layer); + break; + + default: + err = TRANSPORTDEC_UNSUPPORTED_FORMAT; + break; + } + + if (err == TRANSPORTDEC_OK) { + hTp->accessUnitAnchor[layer] = FDKgetValidBits(hBs); + } else { + hTp->accessUnitAnchor[layer] = 0; + } + +bail: + return err; +} + +INT transportDec_GetAuBitsRemaining( const HANDLE_TRANSPORTDEC hTp, const UINT layer ) +{ + INT bits; + + if (hTp->accessUnitAnchor[layer] > 0 && hTp->auLength[layer] > 0) { + bits = hTp->auLength[layer] - (hTp->accessUnitAnchor[layer] - FDKgetValidBits(&hTp->bitStream[layer])); + } else { + bits = FDKgetValidBits(&hTp->bitStream[layer]); + } + + return bits; +} + +INT transportDec_GetAuBitsTotal( const HANDLE_TRANSPORTDEC hTp, const UINT layer ) +{ + return hTp->auLength[layer]; +} + +TRANSPORTDEC_ERROR transportDec_GetMissingAccessUnitCount ( INT *pNAccessUnits, HANDLE_TRANSPORTDEC hTp ) +{ + *pNAccessUnits = hTp->missingAccessUnits; + + return TRANSPORTDEC_OK; +} + +/* Inform the transportDec layer that reading of access unit has finished. */ +TRANSPORTDEC_ERROR transportDec_EndAccessUnit(HANDLE_TRANSPORTDEC hTp) +{ + TRANSPORTDEC_ERROR err = TRANSPORTDEC_OK; + + err = transportDec_AdjustEndOfAccessUnit(hTp); + + switch (hTp->transportFmt) { + case TT_MP4_LOAS: + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + break; + default: + break; + } + + return err; +} + +TRANSPORTDEC_ERROR transportDec_SetParam ( const HANDLE_TRANSPORTDEC hTp, + const TPDEC_PARAM param, + const INT value) +{ + TRANSPORTDEC_ERROR error = TRANSPORTDEC_OK; + + switch (param) { + case TPDEC_PARAM_MINIMIZE_DELAY: + if (value) { + hTp->flags |= TPDEC_MINIMIZE_DELAY; + } else { + hTp->flags &= ~TPDEC_MINIMIZE_DELAY; + } + break; + case TPDEC_PARAM_EARLY_CONFIG: + if (value) { + hTp->flags |= TPDEC_EARLY_CONFIG; + } else { + hTp->flags &= ~TPDEC_EARLY_CONFIG; + } + break; + case TPDEC_PARAM_IGNORE_BUFFERFULLNESS: + if (value) { + hTp->flags |= TPDEC_IGNORE_BUFFERFULLNESS; + } else { + hTp->flags &= ~TPDEC_IGNORE_BUFFERFULLNESS; + } + break; + case TPDEC_PARAM_SET_BITRATE: + hTp->avgBitRate = value; + break; + case TPDEC_PARAM_BURST_PERIOD: + hTp->burstPeriod = value; + break; + case TPDEC_PARAM_RESET: + { + int i; + + for (i=0; i<(1*2); i++) { + FDKresetBitbuffer(&hTp->bitStream[i]); + hTp->auLength[i] = 0; + hTp->accessUnitAnchor[i] = 0; + } + hTp->flags &= ~(TPDEC_SYNCOK|TPDEC_LOST_FRAMES_PENDING); + hTp->remainder = 0; + hTp->avgBitRate = 0; + hTp->missingAccessUnits = 0; + hTp->numberOfRawDataBlocks = 0; + hTp->globalFramePos = 0; + hTp->holdOffFrames = 0; + } + break; + } + + return error; +} + +UINT transportDec_GetNrOfSubFrames(HANDLE_TRANSPORTDEC hTp) +{ + UINT nSubFrames = 0; + + if (hTp == NULL) + return 0; + + if (hTp->transportFmt==TT_MP4_LATM_MCP1 || hTp->transportFmt==TT_MP4_LATM_MCP0 || hTp->transportFmt==TT_MP4_LOAS) + nSubFrames = CLatmDemux_GetNrOfSubFrames(&hTp->parser.latm); + else if (hTp->transportFmt==TT_MP4_ADTS) + nSubFrames = hTp->parser.adts.bs.num_raw_blocks; + + return nSubFrames; +} + +void transportDec_Close(HANDLE_TRANSPORTDEC *phTp) +{ + if (phTp != NULL) + { + if (*phTp != NULL) { + if ((*phTp)->transportFmt != TT_MP4_RAW && (*phTp)->transportFmt != TT_DRM) { + FreeRam_TransportDecoderBuffer(&(*phTp)->bsBuffer); + } + if (*phTp != NULL) { + FreeRam_TransportDecoder(phTp); + } + } + } +} + +TRANSPORTDEC_ERROR transportDec_GetLibInfo( LIB_INFO *info ) +{ + int i; + + if (info == NULL) { + return TRANSPORTDEC_UNKOWN_ERROR; + } + + /* search for next free tab */ + for (i = 0; i < FDK_MODULE_LAST; i++) { + if (info[i].module_id == FDK_NONE) break; + } + if (i == FDK_MODULE_LAST) return TRANSPORTDEC_UNKOWN_ERROR; + info += i; + + info->module_id = FDK_TPDEC; + info->build_date = __DATE__; + info->build_time = __TIME__; + info->title = TP_LIB_TITLE; + info->version = LIB_VERSION(TP_LIB_VL0, TP_LIB_VL1, TP_LIB_VL2); + LIB_VERSION_STRING(info); + info->flags = 0 + | CAPF_ADIF + | CAPF_ADTS + | CAPF_LATM + | CAPF_LOAS + | CAPF_RAWPACKETS + ; + + return TRANSPORTDEC_OK; /* FDKERR_NOERROR; */ +} + + +int transportDec_CrcStartReg(HANDLE_TRANSPORTDEC pTp, INT mBits) +{ + switch (pTp->transportFmt) { + case TT_MP4_ADTS: + return adtsRead_CrcStartReg(&pTp->parser.adts, &pTp->bitStream[0], mBits); + default: + return 0; + } +} + +void transportDec_CrcEndReg(HANDLE_TRANSPORTDEC pTp, INT reg) +{ + switch (pTp->transportFmt) { + case TT_MP4_ADTS: + adtsRead_CrcEndReg(&pTp->parser.adts, &pTp->bitStream[0], reg); + break; + default: + break; + } +} + +TRANSPORTDEC_ERROR transportDec_CrcCheck(HANDLE_TRANSPORTDEC pTp) +{ + switch (pTp->transportFmt) { + case TT_MP4_ADTS: + if ( (pTp->parser.adts.bs.num_raw_blocks > 0) && (pTp->parser.adts.bs.protection_absent == 0) ) + { + HANDLE_FDK_BITSTREAM hBs = &pTp->bitStream[0]; + int bitDiff; + + /* Calculate possible offset to CRC value. */ + bitDiff = pTp->parser.adts.rawDataBlockDist[pTp->parser.adts.bs.num_raw_blocks-pTp->numberOfRawDataBlocks]<<3; + bitDiff -= pTp->globalFramePos - FDKgetValidBits(hBs) + 16; + FDKpushBiDirectional(hBs, bitDiff); + pTp->parser.adts.crcReadValue = FDKreadBits(hBs, 16); + } + return adtsRead_CrcCheck(&pTp->parser.adts); + default: + return TRANSPORTDEC_OK; + } +} diff --git a/libMpegTPDec/src/version b/libMpegTPDec/src/version new file mode 100644 index 0000000..6aa18cf --- /dev/null +++ b/libMpegTPDec/src/version @@ -0,0 +1,8 @@ + +/* library info */ +#define TP_LIB_VL0 2 +#define TP_LIB_VL1 2 +#define TP_LIB_VL2 0 +#define TP_LIB_TITLE "MPEG Transport" +#define TP_LIB_BUILD_DATE __DATE__ +#define TP_LIB_BUILD_TIME __TIME__ diff --git a/libMpegTPEnc/Android.mk b/libMpegTPEnc/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/libMpegTPEnc/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/libMpegTPEnc/include/mpegFileWrite.h b/libMpegTPEnc/include/mpegFileWrite.h new file mode 100644 index 0000000..c515d0c --- /dev/null +++ b/libMpegTPEnc/include/mpegFileWrite.h @@ -0,0 +1,78 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: Bitstream data provider for MP4 decoders + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "machine_type.h" +#include "FDK_audio.h" + +/*!< If MPFWRITE_MP4FF_ENABLE is set, include support for MPEG ISO fileformat. + If not set, no .mp4, .m4a and .3gp files can be used for input. */ +/* #define MPFWRITE_MP4FF_ENABLE */ + +typedef struct STRUCT_FILEWRITE *HANDLE_FILEWRITE; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Open an MPEG audio file. + * \param mpegFileWrite_Filename String of the filename to be opened. + * \param fileFmt Transport format to use. + * \param conf + * \param confSize + * \return MPEG file write handle. + */ +HANDLE_FILEWRITE mpegFileWrite_Open( char *mpegFileWrite_Filename, + FILE_FORMAT fileFmt, + TRANSPORT_TYPE transportType, + UCHAR *conf, + UINT confSize + ); + +/** + * \brief Write to an MPEG audio file. + * \param inBuffer Buffer to write. + * \param bufferSize Size of buffer to write in bytes. + * \return 0 on sucess, -1 on unsupported file format or write error. + */ +int mpegFileWrite_Write( HANDLE_FILEWRITE hFileWrite, + UCHAR *inBuffer, + int bufferSize + ); + +/** + * \brief Deallocate memory and close file. + * \param hFileWrite MPEG file write handle. + * \return 0 on sucess. + */ +int mpegFileWrite_Close( HANDLE_FILEWRITE *hFileWrite ); + + +#ifdef __cplusplus +} +#endif diff --git a/libMpegTPEnc/include/tp_data.h b/libMpegTPEnc/include/tp_data.h new file mode 100644 index 0000000..6149608 --- /dev/null +++ b/libMpegTPEnc/include/tp_data.h @@ -0,0 +1,277 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: MPEG Transport data tables + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#ifndef __TP_DATA_H__ +#define __TP_DATA_H__ + +#include "machine_type.h" +#include "FDK_audio.h" +#include "FDK_bitstream.h" + +/* + * Configuration + */ +#define TP_GA_ENABLE +/* #define TP_CELP_ENABLE */ +/* #define TP_HVXC_ENABLE */ +/* #define TP_SLS_ENABLE */ +#define TP_ELD_ENABLE +/* #define TP_USAC_ENABLE */ +/* #define TP_RSVD50_ENABLE */ + +#if defined(TP_GA_ENABLE) || defined(TP_SLS_ENABLE) +#define TP_PCE_ENABLE /**< Enable full PCE support */ +#endif + +/** + * ProgramConfig struct. + */ +/* ISO/IEC 14496-3 4.4.1.1 Table 4.2 Program config element */ +#define PC_FSB_CHANNELS_MAX 16 /* Front/Side/Back channels */ +#define PC_LFE_CHANNELS_MAX 4 +#define PC_ASSOCDATA_MAX 8 +#define PC_CCEL_MAX 16 /* CC elements */ +#define PC_COMMENTLENGTH 256 + +typedef struct +{ +#ifdef TP_PCE_ENABLE + /* PCE bitstream elements: */ + UCHAR ElementInstanceTag; + UCHAR Profile; + UCHAR SamplingFrequencyIndex; + UCHAR NumFrontChannelElements; + UCHAR NumSideChannelElements; + UCHAR NumBackChannelElements; + UCHAR NumLfeChannelElements; + UCHAR NumAssocDataElements; + UCHAR NumValidCcElements; + + UCHAR MonoMixdownPresent; + UCHAR MonoMixdownElementNumber; + + UCHAR StereoMixdownPresent; + UCHAR StereoMixdownElementNumber; + + UCHAR MatrixMixdownIndexPresent; + UCHAR MatrixMixdownIndex; + UCHAR PseudoSurroundEnable; + + UCHAR FrontElementIsCpe[PC_FSB_CHANNELS_MAX]; + UCHAR FrontElementTagSelect[PC_FSB_CHANNELS_MAX]; + + UCHAR SideElementIsCpe[PC_FSB_CHANNELS_MAX]; + UCHAR SideElementTagSelect[PC_FSB_CHANNELS_MAX]; + + UCHAR BackElementIsCpe[PC_FSB_CHANNELS_MAX]; + UCHAR BackElementTagSelect[PC_FSB_CHANNELS_MAX]; + + UCHAR LfeElementTagSelect[PC_LFE_CHANNELS_MAX]; + + UCHAR AssocDataElementTagSelect[PC_ASSOCDATA_MAX]; + + UCHAR CcElementIsIndSw[PC_CCEL_MAX]; + UCHAR ValidCcElementTagSelect[PC_CCEL_MAX]; + + UCHAR CommentFieldBytes; + UCHAR Comment[PC_COMMENTLENGTH]; +#endif /* TP_PCE_ENABLE */ + + /* Helper variables for administration: */ + UCHAR isValid; /*!< Flag showing if PCE has been read successfully. */ + UCHAR NumChannels; /*!< Amount of audio channels summing all channel elements including LFEs */ + UCHAR NumEffectiveChannels; /*!< Amount of audio channels summing only SCEs and CPEs */ + UCHAR elCounter; + +} CProgramConfig; + +typedef enum { + ASCEXT_UNKOWN = -1, + ASCEXT_SBR = 0x2b7, + ASCEXT_PS = 0x548, + ASCEXT_MPS = 0x76a, + ASCEXT_SAOC = 0x7cb, + ASCEXT_LDMPS = 0x7cc + +} TP_ASC_EXTENSION_ID; + +#ifdef TP_GA_ENABLE +/** + * GaSpecificConfig struct + */ +typedef struct { + UINT m_frameLengthFlag ; + UINT m_dependsOnCoreCoder ; + UINT m_coreCoderDelay ; + + UINT m_extensionFlag ; + UINT m_extensionFlag3 ; + + UINT m_layer; + UINT m_numOfSubFrame; + UINT m_layerLength; + +} CSGaSpecificConfig; +#endif /* TP_GA_ENABLE */ + + + + +#ifdef TP_ELD_ENABLE + +typedef enum { + ELDEXT_TERM = 0x0, /* Termination tag */ + ELDEXT_SAOC = 0x1, /* SAOC config */ + ELDEXT_LDSAC = 0x2 /* LD MPEG Surround config */ + /* reserved */ +} ASC_ELD_EXT_TYPE; + +typedef struct { + UCHAR m_frameLengthFlag; + + UCHAR m_sbrPresentFlag; + UCHAR m_useLdQmfTimeAlign; /* Use LD-MPS QMF in SBR to achive time alignment */ + UCHAR m_sbrSamplingRate; + UCHAR m_sbrCrcFlag; + +} CSEldSpecificConfig; +#endif /* TP_ELD_ENABLE */ + + + + +/** + * Audio configuration struct, suitable for encoder and decoder configuration. + */ +typedef struct { + + /* XYZ Specific Data */ + union { +#ifdef TP_GA_ENABLE + CSGaSpecificConfig m_gaSpecificConfig; /**< General audio specific configuration. */ +#endif /* TP_GA_ENABLE */ +#ifdef TP_ELD_ENABLE + CSEldSpecificConfig m_eldSpecificConfig; /**< ELD specific configuration. */ +#endif /* TP_ELD_ENABLE */ + } m_sc; + + /* Common ASC parameters */ +#ifdef TP_PCE_ENABLE + CProgramConfig m_progrConfigElement; /**< Program configuration. */ +#endif /* TP_PCE_ENABLE */ + + AUDIO_OBJECT_TYPE m_aot; /**< Audio Object Type. */ + UINT m_samplingFrequency; /**< Samplerate. */ + UINT m_samplesPerFrame; /**< Amount of samples per frame. */ + UINT m_directMapping; /**< Document this please !! */ + + AUDIO_OBJECT_TYPE m_extensionAudioObjectType; /**< Audio object type */ + UINT m_extensionSamplingFrequency; /**< Samplerate */ + + SCHAR m_channelConfiguration; /**< Channel configuration index */ + + SCHAR m_epConfig; /**< Error protection index */ + SCHAR m_vcb11Flag; /**< aacSectionDataResilienceFlag */ + SCHAR m_rvlcFlag; /**< aacScalefactorDataResilienceFlag */ + SCHAR m_hcrFlag; /**< aacSpectralDataResilienceFlag */ + + SCHAR m_sbrPresentFlag; /**< Flag indicating the presence of SBR data in the bitstream */ + SCHAR m_psPresentFlag; /**< Flag indicating the presence of parametric stereo data in the bitstream */ + UCHAR m_samplingFrequencyIndex; /**< Samplerate index */ + UCHAR m_extensionSamplingFrequencyIndex; /**< Samplerate index */ + SCHAR m_extensionChannelConfiguration; /**< Channel configuration index */ + +} CSAudioSpecificConfig; + +typedef INT (*cbUpdateConfig_t)(void*, const CSAudioSpecificConfig*); +typedef INT (*cbSsc_t)( + void*, HANDLE_FDK_BITSTREAM, + const AUDIO_OBJECT_TYPE coreCodec, + const INT samplingFrequency, + const INT muxMode, + const INT configBytes + ); +typedef INT (*cbSbr_t)( + void * self, + HANDLE_FDK_BITSTREAM hBs, + const INT sampleRateIn, + const INT sampleRateOut, + const INT samplesPerFrame, + const AUDIO_OBJECT_TYPE coreCodec, + const MP4_ELEMENT_ID elementID, + const INT elementIndex + ); + +typedef struct { + cbUpdateConfig_t cbUpdateConfig; /*!< Function pointer for Config change notify callback. */ + void *cbUpdateConfigData; /*!< User data pointer for Config change notify callback. */ + cbSsc_t cbSsc; /*!< Function pointer for SSC parser callback. */ + void *cbSscData; /*!< User data pointer for SSC parser callback. */ + cbSbr_t cbSbr; /*!< Function pointer for SBR header parser callback. */ + void *cbSbrData; /*!< User data pointer for SBR header parser callback. */ +} CSTpCallBacks; + +static const UINT SamplingRateTable[] = +{ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, + 0 +}; + +static inline +int getSamplingRateIndex( UINT samplingRate ) +{ + UINT sf_index, tableSize=sizeof(SamplingRateTable)/sizeof(UINT); + + for (sf_index=0; sf_indextableSize-1) { + return tableSize-1; + } + + return sf_index; +} + +/* + * Get Channel count from channel configuration + */ +static inline int getNumberOfTotalChannels(int channelConfig) +{ + if (channelConfig > 0 && channelConfig < 8) + return (channelConfig == 7)?8:channelConfig; + else + return 0; +} + +static inline +int getNumberOfEffectiveChannels(const int channelConfig) +{ + const int n[] = {0,1,2,3,4,5,5,7}; + return n[channelConfig]; +} + +#endif /* __TP_DATA_H__ */ diff --git a/libMpegTPEnc/include/tpenc_lib.h b/libMpegTPEnc/include/tpenc_lib.h new file mode 100644 index 0000000..9c40211 --- /dev/null +++ b/libMpegTPEnc/include/tpenc_lib.h @@ -0,0 +1,234 @@ +/************************** MPEG-4 Transport Encoder ************************ + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: MPEG Transport encode + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef __TPENC_LIB_H__ +#define __TPENC_LIB_H__ + +#include "tp_data.h" +#include "FDK_bitstream.h" + +#define TRANSPORTENC_INBUF_SIZE 8192 + +typedef enum { + TRANSPORTENC_OK = 0, /*!< All fine. */ + TRANSPORTENC_NO_MEM, /*!< Out of memory. */ + TRANSPORTENC_UNKOWN_ERROR = 1, /*!< Unknown error (embarrasing). */ + TRANSPORTENC_INVALID_PARAMETER, /*!< An invalid parameter was passed to a function . */ + TRANSPORTENC_PARSE_ERROR, /*!< Bitstream data contained inconsistencies (wrong syntax). */ + TRANSPORTENC_UNSUPPORTED_FORMAT, /*!< Unsupported transport format. */ + TRANSPORTENC_NOT_ENOUGH_BITS, /*!< Out of bits. Provide more bits and try again. */ + + TRANSPORTENC_INVALID_CONFIG, /*!< Error in configuration. */ + TRANSPORTENC_LATM_INVALID_NR_OF_SUBFRAMES, /*!< LATM: number of subframes out of range. */ + TRANSPORTENC_LOAS_NOT_AVAILABLE, /*!< LOAS format not supported. */ + TRANSPORTENC_INVALID_LATM_ALIGNMENT, /*!< AudioMuxElement length not aligned to 1 byte. */ + + TRANSPORTENC_INVALID_TRANSMISSION_FRAME_LENGTH, /*!< Invalid transmission frame length (< 0). */ + TRANSPORTENC_INVALID_CELP_FRAME_LENGTH, /*!< Invalid CELP frame length found (>= 62). */ + TRANSPORTENC_INVALID_FRAME_BITS, /*!< Frame bits is not 40 and not 80. */ + TRANSPORTENC_INVALID_AOT, /*!< Unknown AOT found. */ + TRANSPORTENC_INVALID_AU_LENGTH /*!< Invalid Access Unit length (not byte-aligned). */ + +} TRANSPORTENC_ERROR; + +typedef struct TRANSPORTENC *HANDLE_TRANSPORTENC; + +/** + * \brief Determine a reasonable channel configuration on the basis of channel_mode. + * \param noChannels Number of audio channels. + * \return CHANNEL_MODE value that matches the given amount of audio channels. + */ +CHANNEL_MODE transportEnc_GetChannelMode( int noChannels ); + +/** + * \brief Register SBR heaqder writer callback. + * \param hTp Handle of transport decoder. + * \param cbUpdateConfig Pointer to a callback function to handle SBR header writing. + * \param user_data void pointer for user data passed to the callback as first parameter. + * \return 0 on success. + */ +int transportEnc_RegisterSbrCallback ( + HANDLE_TRANSPORTENC hTpEnc, + const cbSbr_t cbSbr, + void* user_data + ); + +/** + * \brief Register SSC writer callback. + * \param hTp Handle of transport decoder. + * \param cbUpdateConfig Pointer to a callback function to handle SSC writing. + * \param user_data void pointer for user data passed to the callback as first parameter. + * \return 0 on success. + */ +int transportEnc_RegisterSscCallback ( + HANDLE_TRANSPORTENC hTpEnc, + const cbSsc_t cbSsc, + void* user_data + ); + +/** + * \brief Write ASC from given parameters. + * \param asc A HANDLE_FDK_BITSTREAM where the ASC is written to. + * \param config Structure containing the codec configuration settings. + * \param cb callback information structure. + * \return 0 on success. + */ +int transportEnc_writeASC ( + HANDLE_FDK_BITSTREAM asc, + CODER_CONFIG *config, + CSTpCallBacks *cb + ); + + +/* Defintion of flags that can be passed to transportEnc_Open() */ +#define TP_FLAG_MPEG4 1 /** MPEG4 (instead of MPEG2) */ +#define TP_FLAG_LATM_AMV 2 /** LATM AudioMuxVersion */ +#define TP_FLAG_LATM_AMVA 4 /** LATM AudioMuxVersionA */ + +/** + * \brief Allocate transport encoder. + * \param phTpEnc Pointer to transport encoder handle. + * \return Error code. + */ +TRANSPORTENC_ERROR transportEnc_Open( HANDLE_TRANSPORTENC *phTpEnc ); + +/** + * \brief Init transport encoder. + * \param bsBuffer Pointer to transport encoder. + * \param bsBuffer Pointer to bitstream buffer. + * \param bsBufferSize Size in bytes of bsBuffer. + * \param transportFmt Format of the transport to be written. + * \param config Pointer to a valid CODER_CONFIG struct. + * \param flags Transport encoder flags. + * \return Error code. + */ +TRANSPORTENC_ERROR transportEnc_Init( + HANDLE_TRANSPORTENC hTpEnc, + UCHAR *bsBuffer, + INT bsBufferSize, + TRANSPORT_TYPE transportFmt, + CODER_CONFIG *config, + UINT flags + ); + +/** + * \brief Get transport encoder bitstream. + * \param hTp Pointer to a transport encoder handle. + * \return The handle to the requested FDK bitstream. + */ +HANDLE_FDK_BITSTREAM transportEnc_GetBitstream( HANDLE_TRANSPORTENC hTp ); + +/** + * \brief Get amount of bits required by the transport headers. + * \param hTp Handle of transport encoder. + * \param auBits Amount of payload bits required for the current subframe. + * \return Error code. + */ +INT transportEnc_GetStaticBits( HANDLE_TRANSPORTENC hTp, int auBits ); + +/** + * \brief Close transport encoder. This function assures that all allocated memory is freed. + * \param phTp Pointer to a previously allocated transport encoder handle. + */ +void transportEnc_Close( HANDLE_TRANSPORTENC *phTp ); + +/** + * \brief Write one access unit. + * \param hTp Handle of transport encoder. + * \param total_bits Amount of total access unit bits. + * \param bufferFullness Value of current buffer fullness in bits. + * \param noConsideredChannels Number of bitrate wise considered channels (all minus LFE channels). + * \return Error code. + */ +TRANSPORTENC_ERROR transportEnc_WriteAccessUnit( HANDLE_TRANSPORTENC hTp, + INT total_bits, + int bufferFullness, + int noConsideredChannels ); + +/** + * \brief Inform the transportEnc layer that writing of access unit has finished. This function + * is required to be called when the encoder has finished writing one Access + * one Access Unit for bitstream housekeeping. + * \param hTp Transport handle. + * \param pBits Pointer to an int, where the current amount of frame bits is passed + * and where the current amount of subframe bits is returned. + * + * OR: This integer is modified by the amount of extra bit alignment that may occurr. + * + * \return Error code. + */ +TRANSPORTENC_ERROR transportEnc_EndAccessUnit( HANDLE_TRANSPORTENC hTp, int *pBits); + +/* + * \brief Get a payload frame. + * \param hTpEnc Transport encoder handle. + * \param nBytes Pointer to an int to hold the frame size in bytes. Returns zero + * if currently there is no complete frame for output (number of sub frames > 1). + * \return Error code. + */ +TRANSPORTENC_ERROR transportEnc_GetFrame(HANDLE_TRANSPORTENC hTpEnc, int *nbytes); + +/* ADTS CRC support */ + +/** + * \brief Set current bitstream position as start of a new data region. + * \param hTpEnc Transport encoder handle. + * \param mBits Size in bits of the data region. Set to 0 if it should not be of a fixed size. + * \return Data region ID, which should be used when calling transportEnc_CrcEndReg(). + */ +int transportEnc_CrcStartReg(HANDLE_TRANSPORTENC hTpEnc, int mBits); + +/** + * \brief Set end of data region. + * \param hTpEnc Transport encoder handle. + * \param reg Data region ID, opbtained from transportEnc_CrcStartReg(). + * \return void + */ +void transportEnc_CrcEndReg(HANDLE_TRANSPORTENC hTpEnc, int reg); + +/** + * \brief Get AudioSpecificConfig or StreamMuxConfig from transport encoder handle and write it to dataBuffer. + * \param hTpEnc Transport encoder handle. + * \param cc Pointer to the current and valid configuration contained in a CODER_CONFIG struct. + * \param dataBuffer Bitbuffer holding binary configuration. + * \param confType Pointer to an UINT where the configuration type is returned (0:ASC, 1:SMC). + * \return Error code. + */ +TRANSPORTENC_ERROR transportEnc_GetConf( HANDLE_TRANSPORTENC hTpEnc, + CODER_CONFIG *cc, + FDK_BITSTREAM *dataBuffer, + UINT *confType ); + +/** + * \brief Get information (version among other things) of the transport encoder library. + * \param info Pointer to an allocated LIB_INFO struct. + * \return Error code. + */ +TRANSPORTENC_ERROR transportEnc_GetLibInfo( LIB_INFO *info ); + +#endif /* #ifndef __TPENC_LIB_H__ */ diff --git a/libMpegTPEnc/src/Android.mk b/libMpegTPEnc/src/Android.mk new file mode 100644 index 0000000..5d6d7e0 --- /dev/null +++ b/libMpegTPEnc/src/Android.mk @@ -0,0 +1,21 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + tpenc_adif.cpp \ + tpenc_adts.cpp \ + tpenc_asc.cpp \ + tpenc_latm.cpp \ + tpenc_lib.cpp + +LOCAL_CFLAGS := -DANDROID + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../../libSYS/include \ + $(LOCAL_PATH)/../../libFDK/include + +LOCAL_MODULE:= libMpegTPEnc + +include $(BUILD_STATIC_LIBRARY) diff --git a/libMpegTPEnc/src/tpenc_adif.cpp b/libMpegTPEnc/src/tpenc_adif.cpp new file mode 100644 index 0000000..d217643 --- /dev/null +++ b/libMpegTPEnc/src/tpenc_adif.cpp @@ -0,0 +1,120 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (2009) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + contents/description: ADIF Transport Headers writing + +******************************************************************************/ + +#include "tpenc_adif.h" + +#include "tpenc_lib.h" +#include "tpenc_asc.h" + + + +int adifWrite_EncodeHeader(ADIF_INFO *adif, + HANDLE_FDK_BITSTREAM hBs, + INT adif_buffer_fullness) +{ + /* ADIF/PCE/ADTS definitions */ + const char adifId[5]="ADIF"; + const int copyRightIdPresent=0; + const int originalCopy=0; + const int home=0; + + int i; + + INT sampleRate = adif->samplingRate; + INT totalBitRate = adif->bitRate; + + if (adif->headerWritten) + return 0; + + /* Align inside PCE with respect to the first bit of the header */ + UINT alignAnchor = FDKgetValidBits(hBs); + + /* Signal variable bitrate if buffer fullnes exceeds 20 bit */ + adif->bVariableRate = ( adif_buffer_fullness >= (INT)(0x1<<20) ) ? 1 : 0; + + FDKwriteBits(hBs, adifId[0],8); + FDKwriteBits(hBs, adifId[1],8); + FDKwriteBits(hBs, adifId[2],8); + FDKwriteBits(hBs, adifId[3],8); + + + FDKwriteBits(hBs, copyRightIdPresent ? 1:0,1); + + if(copyRightIdPresent) { + for(i=0;i<72;i++) { + FDKwriteBits(hBs,0,1); + } + } + FDKwriteBits(hBs, originalCopy ? 1:0,1); + FDKwriteBits(hBs, home ? 1:0,1); + FDKwriteBits(hBs, adif->bVariableRate?1:0, 1); + FDKwriteBits(hBs, totalBitRate,23); + + /* we write only one PCE at the moment */ + FDKwriteBits(hBs, 0, 4); + + if(!adif->bVariableRate) { + FDKwriteBits(hBs, adif_buffer_fullness, 20); + } + + /* Write PCE */ + transportEnc_writePCE(hBs, adif->cm, sampleRate, adif->instanceTag, adif->profile, 0, 0, alignAnchor); + + return 0; +} + +int adifWrite_GetHeaderBits(ADIF_INFO *adif) +{ + /* ADIF definitions */ + const int copyRightIdPresent=0; + + if (adif->headerWritten) + return 0; + + int bits = 0; + + bits += 8*4; /* ADIF ID */ + + bits += 1; /* Copyright present */ + + if (copyRightIdPresent) + bits += 72; /* Copyright ID */ + + bits += 26; + + bits += 4; /* Number of PCE's */ + + if(!adif->bVariableRate) { + bits += 20; + } + + /* write PCE */ + bits = transportEnc_GetPCEBits(adif->cm, 0, bits); + + return bits; +} + diff --git a/libMpegTPEnc/src/tpenc_adif.h b/libMpegTPEnc/src/tpenc_adif.h new file mode 100644 index 0000000..989ed9a --- /dev/null +++ b/libMpegTPEnc/src/tpenc_adif.h @@ -0,0 +1,73 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (2009) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: Alex Goeschel + contents/description: Transport Headers support + +******************************************************************************/ + +#ifndef TPENC_ADIF_H +#define TPENC_ADIF_H + +#include "machine_type.h" +#include "FDK_bitstream.h" + +#include "tp_data.h" + +typedef struct { + CHANNEL_MODE cm; + INT samplingRate; + INT bitRate; + int profile; + int bVariableRate; + int instanceTag; + int headerWritten; +} ADIF_INFO; + +/** + * \brief encodes ADIF Header + * + * \param adif pointer to ADIF_INFO structure + * \param hBitStream handle of bitstream, where the ADIF header is written into + * \param adif_buffer_fullness buffer fullness value for the ADIF header + * + * \return 0 on success + */ +int adifWrite_EncodeHeader( + ADIF_INFO *adif, + HANDLE_FDK_BITSTREAM hBitStream, + INT adif_buffer_fullness + ); + +/** + * \brief Get bit demand of a ADIF header + * + * \param adif pointer to ADIF_INFO structure + * + * \return amount of bits required to write the ADIF header according to the data + * contained in the adif parameter + */ +int adifWrite_GetHeaderBits( ADIF_INFO *adif ); + +#endif /* TPENC_ADIF_H */ + diff --git a/libMpegTPEnc/src/tpenc_adts.cpp b/libMpegTPEnc/src/tpenc_adts.cpp new file mode 100644 index 0000000..86b11c1 --- /dev/null +++ b/libMpegTPEnc/src/tpenc_adts.cpp @@ -0,0 +1,253 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) copyright Fraunhofer-IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: Alex Groeschel + contents/description: ADTS Transport Headers support + +******************************************************************************/ + +#include "tpenc_adts.h" + + +#include "tpenc_lib.h" +#include "tpenc_asc.h" + + +int adtsWrite_CrcStartReg( + HANDLE_ADTS pAdts, /*!< pointer to adts stucture */ + HANDLE_FDK_BITSTREAM hBs, /*!< handle to current bit buffer structure */ + int mBits /*!< number of bits in crc region */ + ) +{ + if (pAdts->protection_absent) { + return 0; + } + return ( FDKcrcStartReg(&pAdts->crcInfo, hBs, mBits) ); +} + +void adtsWrite_CrcEndReg( + HANDLE_ADTS pAdts, /*!< pointer to adts crc info stucture */ + HANDLE_FDK_BITSTREAM hBs, /*!< handle to current bit buffer structure */ + int reg /*!< crc region */ + ) +{ + if (pAdts->protection_absent == 0) + { + FDKcrcEndReg(&pAdts->crcInfo, hBs, reg); + } +} + +int adtsWrite_GetHeaderBits( HANDLE_ADTS hAdts ) +{ + int bits = 0; + + if (hAdts->currentBlock == 0) { + /* Static and variable header bits */ + bits = 56; + if (!hAdts->protection_absent) { + /* Add header/ single raw data block CRC bits */ + bits += 16; + if (hAdts->num_raw_blocks>0) { + /* Add bits of raw data block position markers */ + bits += (hAdts->num_raw_blocks)*16; + } + } + } + if (!hAdts->protection_absent && hAdts->num_raw_blocks>0) { + /* Add raw data block CRC bits. Not really part of the header, put they cause bit overhead to be accounted. */ + bits += 16; + } + + hAdts->headerBits = bits; + + return bits; +} + +INT adtsWrite_Init(HANDLE_ADTS hAdts, CODER_CONFIG *config) +{ + /* Sanity checks */ + if ( config->nSubFrames < 1 + || config->nSubFrames > 4 + || (int)config->aot > 4 + || (int)config->aot < 1 ) { + return -1; + } + + /* fixed header */ + if (config->flags & CC_MPEG_ID) { + hAdts->mpeg_id = 0; /* MPEG 4 */ + } else { + hAdts->mpeg_id = 1; /* MPEG 2 */ + } + hAdts->layer=0; + hAdts->protection_absent = ! (config->flags & CC_PROTECTION); + hAdts->profile = ((int)config->aot) - 1; + hAdts->sample_freq_index = getSamplingRateIndex(config->samplingRate); + hAdts->sample_freq = config->samplingRate; + hAdts->private_bit=0; + hAdts->channel_mode = config->channelMode; + hAdts->original=0; + hAdts->home=0; + /* variable header */ + hAdts->copyright_id=0; + hAdts->copyright_start=0; + + hAdts->num_raw_blocks=config->nSubFrames-1; /* 0 means 1 raw data block */ + + FDKcrcInit(&hAdts->crcInfo, 0x8005, 0xFFFF, 16); + + hAdts->currentBlock = 0; + + + return 0; +} + +int adtsWrite_EncodeHeader(HANDLE_ADTS hAdts, + HANDLE_FDK_BITSTREAM hBitStream, + int buffer_fullness, + int frame_length) +{ + INT crcIndex = 0; + + + hAdts->headerBits = adtsWrite_GetHeaderBits(hAdts); + + FDK_ASSERT(((frame_length+hAdts->headerBits)/8)<0x2000); /*13 bit*/ + FDK_ASSERT(buffer_fullness<0x800); /* 11 bit */ + + if (!hAdts->protection_absent) { + FDKcrcReset(&hAdts->crcInfo); + } + + if (hAdts->currentBlock == 0) { + FDKresetBitbuffer(hBitStream, BS_WRITER); + } + + hAdts->subFrameStartBit = FDKgetValidBits(hBitStream); + + /* Skip new header if this is raw data block 1..n */ + if (hAdts->currentBlock == 0) + { + FDKresetBitbuffer(hBitStream, BS_WRITER); + + if (hAdts->num_raw_blocks == 0) { + crcIndex = adtsWrite_CrcStartReg(hAdts, hBitStream, 0); + } + + /* fixed header */ + FDKwriteBits(hBitStream, 0xFFF, 12); + FDKwriteBits(hBitStream, hAdts->mpeg_id, 1); + FDKwriteBits(hBitStream, hAdts->layer, 2); + FDKwriteBits(hBitStream, hAdts->protection_absent, 1); + FDKwriteBits(hBitStream, hAdts->profile, 2); + FDKwriteBits(hBitStream, hAdts->sample_freq_index, 4); + FDKwriteBits(hBitStream, hAdts->private_bit, 1); + FDKwriteBits(hBitStream, getChannelConfig(hAdts->channel_mode), 3); + FDKwriteBits(hBitStream, hAdts->original, 1); + FDKwriteBits(hBitStream, hAdts->home, 1); + /* variable header */ + FDKwriteBits(hBitStream, hAdts->copyright_id, 1); + FDKwriteBits(hBitStream, hAdts->copyright_start, 1); + FDKwriteBits(hBitStream, (frame_length + hAdts->headerBits)>>3, 13); + FDKwriteBits(hBitStream, buffer_fullness, 11); + FDKwriteBits(hBitStream, hAdts->num_raw_blocks, 2); + + if (!hAdts->protection_absent) { + int i; + + /* End header CRC portion for single raw data block and write dummy zero values for unknown fields. */ + if (hAdts->num_raw_blocks == 0) { + adtsWrite_CrcEndReg(hAdts, hBitStream, crcIndex); + } else { + for (i=0; inum_raw_blocks; i++) { + FDKwriteBits(hBitStream, 0, 16); + } + } + FDKwriteBits(hBitStream, 0, 16); + } + } /* End of ADTS header */ + + return 0; +} + +void adtsWrite_EndRawDataBlock(HANDLE_ADTS hAdts, + HANDLE_FDK_BITSTREAM hBs, + int *pBits) +{ + if (!hAdts->protection_absent) { + FDK_BITSTREAM bsWriter; + + FDKinitBitStream(&bsWriter, hBs->hBitBuf.Buffer, hBs->hBitBuf.bufSize, 0, BS_WRITER); + FDKpushFor(&bsWriter, 56); + + if (hAdts->num_raw_blocks == 0) { + FDKwriteBits(&bsWriter, FDKcrcGetCRC(&hAdts->crcInfo), 16); + } else { + int distance; + + /* Write CRC of current raw data block */ + FDKwriteBits(hBs, FDKcrcGetCRC(&hAdts->crcInfo), 16); + + /* Write distance to current data block */ + if (hAdts->currentBlock < hAdts->num_raw_blocks) { + FDKpushFor(&bsWriter, hAdts->currentBlock*16); + distance = FDKgetValidBits(hBs) - (56 + (hAdts->num_raw_blocks)*16 + 16); + FDKwriteBits(&bsWriter, distance>>3, 16); + } + } + FDKsyncCache(&bsWriter); + } + + /* Write total frame lenth for multiple raw data blocks and header CRC */ + if (hAdts->num_raw_blocks > 0 && hAdts->currentBlock == hAdts->num_raw_blocks) { + FDK_BITSTREAM bsWriter; + int crcIndex = 0; + + FDKinitBitStream(&bsWriter, hBs->hBitBuf.Buffer, hBs->hBitBuf.bufSize, 0, BS_WRITER); + + if (!hAdts->protection_absent) { + FDKcrcReset(&hAdts->crcInfo); + crcIndex = FDKcrcStartReg(&hAdts->crcInfo, &bsWriter, 0); + } + /* Write total frame length */ + FDKpushFor(&bsWriter, 56-28+2); + FDKwriteBits(&bsWriter, FDKgetValidBits(hBs)>>3, 13); + + /* Write header CRC */ + if (!hAdts->protection_absent) { + FDKpushFor(&bsWriter, 11+2 + (hAdts->num_raw_blocks)*16); + FDKcrcEndReg(&hAdts->crcInfo, &bsWriter, crcIndex); + FDKwriteBits(&bsWriter, FDKcrcGetCRC(&hAdts->crcInfo), 16); + } + FDKsyncCache(&bsWriter); + } + + /* Correct *pBits to reflect the amount of bits of the current subframe */ + *pBits -= hAdts->subFrameStartBit; + if (!hAdts->protection_absent && hAdts->num_raw_blocks > 0) { + /* Fixup CRC bits, since they come after each raw data block */ + *pBits += 16; + } + hAdts->currentBlock++; +} + diff --git a/libMpegTPEnc/src/tpenc_adts.h b/libMpegTPEnc/src/tpenc_adts.h new file mode 100644 index 0000000..1608769 --- /dev/null +++ b/libMpegTPEnc/src/tpenc_adts.h @@ -0,0 +1,156 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) copyright Fraunhofer-IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + Initial author: Alex Groeschel + contents/description: ADTS Transport writer + +******************************************************************************/ + +#ifndef TPENC_ADTS_H +#define TPENC_ADTS_H + + + +#include "tp_data.h" + +#include "FDK_crc.h" + +typedef struct { + INT sample_freq; + CHANNEL_MODE channel_mode; + UCHAR decoderCanDoMpeg4; + UCHAR mpeg_id; + UCHAR layer; + UCHAR protection_absent; + UCHAR profile; + UCHAR sample_freq_index; + UCHAR private_bit; + UCHAR original; + UCHAR home; + UCHAR copyright_id; + UCHAR copyright_start; + USHORT frame_length; + UCHAR num_raw_blocks; + UCHAR BufferFullnesStartFlag; + int headerBits; /*!< Header bit demand for the current raw data block */ + int currentBlock; /*!< Index of current raw data block */ + int subFrameStartBit; /*!< Bit position where the current raw data block begins */ + FDK_CRCINFO crcInfo; +} STRUCT_ADTS; + +typedef STRUCT_ADTS *HANDLE_ADTS; + +/** + * \brief Initialize ADTS data structure + * + * \param hAdts ADTS data handle + * \param config a valid CODER_CONFIG struct from where the required + * information for the ADTS header is extrated from + * + * \return 0 in case of success. + */ +INT adtsWrite_Init( + HANDLE_ADTS hAdts, + CODER_CONFIG *config + ); + +/** + * \brief Get the total bit overhead caused by ADTS + * + * \hAdts handle to ADTS data + * + * \return Amount of additional bits required for the current raw data block + */ +int adtsWrite_GetHeaderBits( HANDLE_ADTS hAdts ); + +/** + * \brief Write an ADTS header into the given bitstream. May not write a header + * in case of multiple raw data blocks. + * + * \param hAdts ADTS data handle + * \param hBitStream bitstream handle into which the ADTS may be written into + * \param buffer_fullness the buffer fullness value for the ADTS header + * \param the current raw data block length + * + * \return 0 in case of success. + */ +INT adtsWrite_EncodeHeader( + HANDLE_ADTS hAdts, + HANDLE_FDK_BITSTREAM hBitStream, + int bufferFullness, + int frame_length + ); +/** + * \brief Finish a ADTS raw data block + * + * \param hAdts ADTS data handle + * \param hBs bitstream handle into which the ADTS may be written into + * \param pBits a pointer to a integer holding the current bitstream buffer bit count, + * which is corrected to the current raw data block boundary. + * + */ +void adtsWrite_EndRawDataBlock( + HANDLE_ADTS hAdts, + HANDLE_FDK_BITSTREAM hBs, + int *bits + ); + + +/** + * \brief Start CRC region with a maximum number of bits + * If mBits is positive zero padding will be used for CRC calculation, if there + * are less than mBits bits available. + * If mBits is negative no zero padding is done. + * If mBits is zero the memory for the buffer is allocated dynamically, the + * number of bits is not limited. + * + * \param pAdts ADTS data handle + * \param hBs bitstream handle of which the CRC region ends + * \param mBits limit of number of bits to be considered for the requested CRC region + * + * \return ID for the created region, -1 in case of an error + */ +int adtsWrite_CrcStartReg( + HANDLE_ADTS pAdts, + HANDLE_FDK_BITSTREAM hBs, + int mBits + ); + +/** + * \brief Ends CRC region identified by reg + * + * \param pAdts ADTS data handle + * \param hBs bitstream handle of which the CRC region ends + * \param reg a CRC region ID returned previously by adtsWrite_CrcStartReg() + */ +void adtsWrite_CrcEndReg( + HANDLE_ADTS pAdts, + HANDLE_FDK_BITSTREAM hBs, + int reg + ); + + + + +#endif /* TPENC_ADTS_H */ + diff --git a/libMpegTPEnc/src/tpenc_asc.cpp b/libMpegTPEnc/src/tpenc_asc.cpp new file mode 100644 index 0000000..674ffe2 --- /dev/null +++ b/libMpegTPEnc/src/tpenc_asc.cpp @@ -0,0 +1,503 @@ +/***************************** MPEG-4 AAC Encoder ************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "tp_data.h" + +#include "tpenc_lib.h" +#include "tpenc_asc.h" +#include "FDK_bitstream.h" +#include "genericStds.h" + +#define ASC_FLAG_EXT 0x0001 +#define ASC_FLAG_SBR 0x0002 +#define ASC_FLAG_SBRCRC 0x0004 +#define ASC_FLAG_VCB11 0x0010 +#define ASC_FLAG_RVLC 0x0020 +#define ASC_FLAG_HCR 0x0040 +#define ASC_FLAG_HCR 0x0040 + + +#define PCE_MAX_ELEMENTS 8 + +/** + * Describe a PCE based on placed channel elements and element type sequence. + */ +typedef struct { + + UCHAR num_front_channel_elements; /*!< Number of front channel elements. */ + UCHAR num_side_channel_elements; /*!< Number of side channel elements. */ + UCHAR num_back_channel_elements; /*!< Number of back channel elements. */ + UCHAR num_lfe_channel_elements; /*!< Number of lfe channel elements. */ + MP4_ELEMENT_ID el_list[PCE_MAX_ELEMENTS];/*!< List contains sequence describing the elements + in present channel mode. (MPEG order) */ +} PCE_CONFIGURATION; + + +/** + * Map an incoming channel mode to a existing PCE configuration entry. + */ +typedef struct { + + CHANNEL_MODE channel_mode; /*!< Present channel mode. */ + PCE_CONFIGURATION pce_configuration; /*!< Program config element description. */ + +} CHANNEL_CONFIGURATION; + + +/** + * \brief Table contains all supported channel modes and according PCE configuration description. + * + * The number of channel element parameter describes the kind of consecutively elements. + * E.g. MODE_1_2_2_2_1 means: + * - First 2 elements (SCE,CPE) are front channel elements. + * - Following element (CPE) is a side channel element. + * - Next element (CPE) is a back channel element. + * - Last element (LFE) is a lfe channel element. + */ +static const CHANNEL_CONFIGURATION pceConfigTab[] = +{ + { MODE_1, { 1, 0, 0, 0, { ID_SCE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE } } }, + { MODE_2, { 1, 0, 0, 0, { ID_CPE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE } } }, + { MODE_1_2, { 2, 0, 0, 0, { ID_SCE, ID_CPE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE } } }, + { MODE_1_2_1, { 2, 0, 1, 0, { ID_SCE, ID_CPE, ID_SCE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE } } }, + { MODE_1_2_2, { 2, 0, 1, 0, { ID_SCE, ID_CPE, ID_CPE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE } } }, + { MODE_1_2_2_1, { 2, 0, 1, 1, { ID_SCE, ID_CPE, ID_CPE, ID_LFE, ID_NONE, ID_NONE, ID_NONE, ID_NONE } } }, + { MODE_1_2_2_2_1, { 2, 1, 1, 1, { ID_SCE, ID_CPE, ID_CPE, ID_CPE, ID_LFE, ID_NONE, ID_NONE, ID_NONE } } }, + + { MODE_1_1, { 2, 0, 0, 0, { ID_SCE, ID_SCE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE } } }, + { MODE_1_1_1_1, { 2, 2, 0, 0, { ID_SCE, ID_SCE, ID_SCE, ID_SCE, ID_NONE, ID_NONE, ID_NONE, ID_NONE } } }, + { MODE_1_1_1_1_1_1, { 2, 2, 2, 0, { ID_SCE, ID_SCE, ID_SCE, ID_SCE, ID_SCE, ID_SCE, ID_NONE, ID_NONE } } }, + { MODE_1_1_1_1_1_1_1_1, { 3, 2, 3, 0, { ID_SCE, ID_SCE, ID_SCE, ID_SCE, ID_SCE, ID_SCE, ID_SCE, ID_SCE } } }, + + { MODE_2_2, { 1, 0, 1, 0, { ID_CPE, ID_CPE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE } } }, + { MODE_2_2_2, { 1, 1, 1, 0, { ID_CPE, ID_CPE, ID_CPE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE } } }, + { MODE_2_2_2_2, { 4, 0, 0, 0, { ID_CPE, ID_CPE, ID_CPE, ID_CPE, ID_NONE, ID_NONE, ID_NONE, ID_NONE } } }, + + { MODE_2_1, { 1, 0, 1, 0, { ID_CPE, ID_SCE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE, ID_NONE } } } +}; + + +/** + * \brief Get program config element description for existing channel mode. + * + * \param channel_mode Current channel mode. + * + * \return + * - Pointer to PCE_CONFIGURATION entry, on success. + * - NULL, on failure. + */ +static const PCE_CONFIGURATION* getPceEntry( + const CHANNEL_MODE channel_mode + ) +{ + UINT i; + const PCE_CONFIGURATION *pce_config = NULL; + + for (i=0; i < (sizeof(pceConfigTab)/sizeof(CHANNEL_CONFIGURATION)); i++) { + if (pceConfigTab[i].channel_mode == channel_mode) { + pce_config = &pceConfigTab[i].pce_configuration; + } + } + + return pce_config; +} + +int getChannelConfig( CHANNEL_MODE channel_mode ) +{ + INT chan_config = 0; + + switch(channel_mode) { + case MODE_1: chan_config = 1; break; + case MODE_2: chan_config = 2; break; + case MODE_1_2: chan_config = 3; break; + case MODE_1_2_1: chan_config = 4; break; + case MODE_1_2_2: chan_config = 5; break; + case MODE_1_2_2_1: chan_config = 6; break; + case MODE_1_2_2_2_1: chan_config = 7; break; + + default: chan_config = 0; + } + + return chan_config; +} + +CHANNEL_MODE transportEnc_GetChannelMode( int noChannels ) +{ + CHANNEL_MODE chMode; + + if (noChannels <= 8 && noChannels > 0) + chMode = (CHANNEL_MODE)((noChannels == 8) ? 7 : noChannels); /* see : iso/mpeg4 v1 audio subpart1*/ + else + chMode = MODE_UNKNOWN; + + return chMode; +} + +#ifdef TP_PCE_ENABLE +int transportEnc_writePCE(HANDLE_FDK_BITSTREAM hBs, + CHANNEL_MODE channelMode, + INT sampleRate, + int instanceTagPCE, + int profile, + int matrixMixdownA, + int pseudoSurroundEnable, + UINT alignAnchor) +{ + int sampleRateIndex, i; + const PCE_CONFIGURATION* config = NULL; + const MP4_ELEMENT_ID* pEl_list = NULL; + UCHAR cpeCnt=0, sceCnt=0, lfeCnt=0; + + sampleRateIndex = getSamplingRateIndex(sampleRate); + if (sampleRateIndex == 15) { + return -1; + } + + if ((config=getPceEntry(channelMode))==NULL) { + return -1; + } + + /* Pointer to first element in element list. */ + pEl_list = &config->el_list[0]; + + FDKwriteBits(hBs, instanceTagPCE, 4); /* Element instance tag */ + FDKwriteBits(hBs, profile, 2); /* Object type */ + FDKwriteBits(hBs, sampleRateIndex, 4); /* Sample rate index*/ + + FDKwriteBits(hBs, config->num_front_channel_elements, 4); /* Front channel Elements */ + FDKwriteBits(hBs, config->num_side_channel_elements , 4); /* No Side Channel Elements */ + FDKwriteBits(hBs, config->num_back_channel_elements , 4); /* No Back channel Elements */ + FDKwriteBits(hBs, config->num_lfe_channel_elements , 2); /* No Lfe channel elements */ + + FDKwriteBits(hBs, 0, 3); /* No assoc data elements */ + FDKwriteBits(hBs, 0, 4); /* No valid cc elements */ + FDKwriteBits(hBs, 0, 1); /* Mono mixdown present */ + FDKwriteBits(hBs, 0, 1); /* Stereo mixdown present */ + + if ( matrixMixdownA!=0 && ((channelMode==MODE_1_2_2)||(channelMode==MODE_1_2_2_1)) ) { + FDKwriteBits(hBs, 1, 1); /* Matrix mixdown present */ + FDKwriteBits(hBs, (matrixMixdownA-1)&0x3, 2); /* matrix_mixdown_idx */ + FDKwriteBits(hBs, pseudoSurroundEnable&0x1, 1); /* pseudo_surround_enable */ + } + else { + FDKwriteBits(hBs, 0, 1); /* Matrix mixdown not present */ + } + + for(i=0; inum_front_channel_elements; i++) { + UCHAR isCpe = (*pEl_list++==ID_CPE) ? 1 : 0; + UCHAR tag = (isCpe) ? cpeCnt++ : sceCnt++; + FDKwriteBits(hBs, isCpe, 1); /* Front channel Elements is CPE? */ + FDKwriteBits(hBs, tag, 4); /* Front channel Instance Tag.*/ + } + for(i=0; inum_side_channel_elements; i++) { + UCHAR isCpe = (*pEl_list++==ID_CPE) ? 1 : 0; + UCHAR tag = (isCpe) ? cpeCnt++ : sceCnt++; + FDKwriteBits(hBs, isCpe, 1); /* Front channel Elements is CPE? */ + FDKwriteBits(hBs, tag, 4); /* Front channel Instance Tag.*/ + } + for(i=0; inum_back_channel_elements; i++) { + UCHAR isCpe = (*pEl_list++==ID_CPE) ? 1 : 0; + UCHAR tag = (isCpe) ? cpeCnt++ : sceCnt++; + FDKwriteBits(hBs, isCpe, 1); /* Front channel Elements is CPE? */ + FDKwriteBits(hBs, tag, 4); /* Front channel Instance Tag.*/ + } + for(i=0; inum_lfe_channel_elements; i++) { + FDKwriteBits(hBs, lfeCnt++, 4); /* LFE channel Instance Tag. */ + } + + /* - num_valid_cc_elements always 0. + - num_assoc_data_elements always 0. */ + + /* Byte alignment: relative to alignAnchor + ADTS: align with respect to the first bit of the raw_data_block() + ADIF: align with respect to the first bit of the header + LATM: align with respect to the first bit of the ASC */ + FDKbyteAlign(hBs, alignAnchor); /* Alignment */ + + FDKwriteBits(hBs, 0 ,8); /* Do no write any comment. */ + + /* - comment_field_bytes always 0. */ + + return 0; +} + +int transportEnc_GetPCEBits(CHANNEL_MODE channelMode, + int matrixMixdownA, + int bits) +{ + const PCE_CONFIGURATION* config = NULL; + + if ((config=getPceEntry(channelMode))==NULL) { + return -1; /* unsupported channelmapping */ + } + + bits += 4 + 2 + 4; /* Element instance tag + Object type + Sample rate index */ + bits += 4 + 4 + 4 + 2; /* No (front + side + back + lfe channel) elements */ + bits += 3 + 4; /* No (assoc data + valid cc) elements */ + bits += 1 + 1 + 1 ; /* Mono + Stereo + Matrix mixdown present */ + + if ( matrixMixdownA!=0 && ((channelMode==MODE_1_2_2)||(channelMode==MODE_1_2_2_1)) ) { + bits +=3; /* matrix_mixdown_idx + pseudo_surround_enable */ + } + + bits += (1+4) * (INT)config->num_front_channel_elements; + bits += (1+4) * (INT)config->num_side_channel_elements; + bits += (1+4) * (INT)config->num_back_channel_elements; + bits += (4) * (INT)config->num_lfe_channel_elements; + + /* - num_valid_cc_elements always 0. + - num_assoc_data_elements always 0. */ + + if ((bits%8) != 0) { + bits += (8 - (bits%8)); /* Alignment */ + } + + bits += 8; /* Comment field bytes */ + + /* - comment_field_bytes alwys 0. */ + + return bits; +} +#endif /* TP_PCE_ENABLE */ + +static void writeAot(HANDLE_FDK_BITSTREAM hBitstreamBuffer, AUDIO_OBJECT_TYPE aot) +{ + int tmp = (int) aot; + + if (tmp > 31) { + FDKwriteBits( hBitstreamBuffer, AOT_ESCAPE, 5 ); + FDKwriteBits( hBitstreamBuffer, tmp-32, 6 ); /* AudioObjectType */ + } else { + FDKwriteBits( hBitstreamBuffer, tmp, 5 ); + } +} + +static void writeSampleRate(HANDLE_FDK_BITSTREAM hBitstreamBuffer, int sampleRate) +{ + int sampleRateIndex = getSamplingRateIndex(sampleRate); + + FDKwriteBits( hBitstreamBuffer, sampleRateIndex, 4 ); + if( sampleRateIndex == 15 ) { + FDKwriteBits( hBitstreamBuffer, sampleRate, 24 ); + } +} + +#ifdef TP_GA_ENABLE +static +int transportEnc_writeGASpecificConfig( + HANDLE_FDK_BITSTREAM asc, + CODER_CONFIG *config, + int extFlg, + UINT alignAnchor + ) +{ + int aot = config->aot; + int samplesPerFrame = config->samplesPerFrame; + + /* start of GASpecificConfig according to ISO/IEC 14496-3 Subpart 4, 4.4.1 */ + FDKwriteBits( asc, ((samplesPerFrame==960 || samplesPerFrame==480)?1:0), 1); /* frameLengthFlag: 1 for a 960/480 (I)MDCT, 0 for a 1024/512 (I)MDCT*/ + FDKwriteBits( asc, 0, 1); /* dependsOnCoreCoder: Sampling Rate Coder Specific, see in ISO/IEC 14496-3 Subpart 4, 4.4.1 */ + FDKwriteBits( asc, extFlg, 1 ); /* Extension Flag: Shall be 1 for aot = 17,19,20,21,22,23 */ + + /* Write PCE if channel config is not 1-7 */ + if (getChannelConfig(config->channelMode) == 0) { + transportEnc_writePCE(asc, config->channelMode, config->samplingRate, 0, 1, 0, 0, alignAnchor); + } + if (extFlg) { + if (aot == AOT_ER_BSAC) { + FDKwriteBits( asc, config->BSACnumOfSubFrame, 5 ); /* numOfSubFrame */ + FDKwriteBits( asc, config->BSAClayerLength, 11 ); /* layer_length */ + } + if ((aot == AOT_ER_AAC_LC) || (aot == AOT_ER_AAC_LTP) || + (aot == AOT_ER_AAC_SCAL) || (aot == AOT_ER_AAC_LD)) + { + FDKwriteBits( asc, (config->flags & CC_VCB11) ? 1 : 0, 1 ); /* aacSectionDataResillienceFlag */ + FDKwriteBits( asc, (config->flags & CC_RVLC) ? 1 : 0, 1 ); /* aacScaleFactorDataResillienceFlag */ + FDKwriteBits( asc, (config->flags & CC_HCR) ? 1 : 0, 1 ); /* aacSpectralDataResillienceFlag */ + } + FDKwriteBits( asc, 0, 1 ); /* extensionFlag3: reserved. Shall be '0' */ + } + return 0; +} +#endif /* TP_GA_ENABLE */ + +#ifdef TP_ELD_ENABLE + +static +int transportEnc_writeELDSpecificConfig( + HANDLE_FDK_BITSTREAM hBs, + CODER_CONFIG *config, + int epConfig, + int flags, + CSTpCallBacks *cb + ) +{ + /* ELD specific config */ + if (config->channelMode == MODE_1_1) { + return -1; + } + FDKwriteBits(hBs, (config->samplesPerFrame == 480) ? 1 : 0, 1); + + FDKwriteBits(hBs, (flags & ASC_FLAG_VCB11) ? 1:0, 1); + FDKwriteBits(hBs, (flags & ASC_FLAG_RVLC ) ? 1:0, 1); + FDKwriteBits(hBs, (flags & ASC_FLAG_HCR ) ? 1:0, 1); + + FDKwriteBits(hBs, (flags & ASC_FLAG_SBR) ? 1:0, 1); /* SBR header flag */ + if ( (flags & ASC_FLAG_SBR) ) { + FDKwriteBits(hBs, (config->samplingRate == config->extSamplingRate) ? 0:1, 1); /* Samplerate Flag */ + FDKwriteBits(hBs, (flags &ASC_FLAG_SBRCRC) ? 1:0, 1); /* SBR CRC flag*/ + + if (cb->cbSbr != NULL) { + const PCE_CONFIGURATION *pPce; + int e; + + pPce = getPceEntry(config->channelMode); + + for (e=0; eel_list[e] != ID_NONE; e++ ) { + if ( (pPce->el_list[e] == ID_SCE) || (pPce->el_list[e] == ID_CPE) ) { + cb->cbSbr(cb->cbSbrData, hBs, 0, 0, 0, config->aot, pPce->el_list[e], e); + } + } + } + } + + FDKwriteBits(hBs, 0, 4); /* ELDEXT_TERM */ + + return 0; +} +#endif /* TP_ELD_ENABLE */ + + +int transportEnc_writeASC ( + HANDLE_FDK_BITSTREAM asc, + CODER_CONFIG *config, + CSTpCallBacks *cb + ) +{ + UINT flags = 0; + int err; + int epConfig = 0; + + /* Required for the PCE. */ + UINT alignAnchor = FDKgetValidBits(asc); + + /* Extension Flag: Shall be 1 for aot = 17,19,20,21,22,23,39 */ + switch (config->aot) { + case AOT_ER_AAC_LC: + case AOT_ER_AAC_LTP: + case AOT_ER_AAC_SCAL: + case AOT_ER_TWIN_VQ: + case AOT_ER_BSAC: + case AOT_ER_AAC_LD: + case AOT_ER_AAC_ELD: + case AOT_USAC: + flags |= ASC_FLAG_EXT; + break; + default: + break; + } + if (config->flags & CC_SBR) { + flags |= ASC_FLAG_SBR; + } + + if (config->extAOT == AOT_SBR || config->extAOT == AOT_PS) + writeAot(asc, config->extAOT); + else + writeAot(asc, config->aot); + + { + writeSampleRate(asc, config->samplingRate); + } + + /* Try to guess a reasonable channel mode if not given */ + if (config->channelMode == MODE_INVALID) { + config->channelMode = transportEnc_GetChannelMode(config->noChannels); + if (config->channelMode == MODE_INVALID) + return -1; + } + + FDKwriteBits( asc, getChannelConfig(config->channelMode), 4 ); + + if (config->extAOT == AOT_SBR || config->extAOT == AOT_PS) { + writeSampleRate(asc, config->extSamplingRate); + writeAot(asc, config->aot); + } + + switch (config->aot) { +#ifdef TP_GA_ENABLE + case AOT_AAC_MAIN: + case AOT_AAC_LC: + case AOT_AAC_SSR: + case AOT_AAC_LTP: + case AOT_AAC_SCAL: + case AOT_TWIN_VQ: + case AOT_ER_AAC_LC: + case AOT_ER_AAC_LTP: + case AOT_ER_AAC_SCAL: + case AOT_ER_TWIN_VQ: + case AOT_ER_BSAC: + case AOT_ER_AAC_LD: + err = transportEnc_writeGASpecificConfig(asc, config, (flags & ASC_FLAG_EXT) ? 1:0, alignAnchor); + if (err) + return err; + break; +#endif /* TP_GA_ENABLE */ +#ifdef TP_ELD_ENABLE + case AOT_ER_AAC_ELD: + err = transportEnc_writeELDSpecificConfig(asc, config, epConfig, flags, cb); + if (err) + return err; + break; +#endif /* TP_ELD_ENABLE */ + default: + return -1; + } + + switch (config->aot) { + case AOT_ER_AAC_LC: + case AOT_ER_AAC_LTP: + case AOT_ER_AAC_SCAL: + case AOT_ER_TWIN_VQ: + case AOT_ER_BSAC: + case AOT_ER_AAC_LD: + case AOT_ER_CELP: + case AOT_ER_HVXC: + case AOT_ER_HILN: + case AOT_ER_PARA: + case AOT_ER_AAC_ELD: + FDKwriteBits( asc, 0, 2 ); /* epconfig 0 */ + break; + default: + break; + } + + /* Make sure all bits are sync'ed */ + FDKsyncCache( asc ); + + return 0; +} diff --git a/libMpegTPEnc/src/tpenc_asc.h b/libMpegTPEnc/src/tpenc_asc.h new file mode 100644 index 0000000..fbc444b --- /dev/null +++ b/libMpegTPEnc/src/tpenc_asc.h @@ -0,0 +1,80 @@ +/***************************** MPEG-4 AAC Encoder ************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: Audio Specific Config writer + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef TPENC_ASC_H +#define TPENC_ASC_H + +/** + * \brief Get channel config from channel mode. + * + * \param channel_mode channel mode + * + * \return chanel config + */ +int getChannelConfig( CHANNEL_MODE channel_mode ); + +/** + * \brief Write a Program Config Element. + * + * \param hBs bitstream handle into which the PCE is appended + * \param channelMode the channel mode to be used + * \param sampleRate the sample rate + * \param instanceTagPCE the instance tag of the Program Config Element + * \param profile the MPEG Audio profile to be used + * \param matrix mixdown gain + * \param pseudo surround indication + * \param reference bitstream position for alignment + * \return zero on success, non-zero on failure. + */ +int transportEnc_writePCE( + HANDLE_FDK_BITSTREAM hBs, + CHANNEL_MODE channelMode, + INT sampleRate, + int instanceTagPCE, + int profile, + int matrixMixdownA, + int pseudoSurroundEnable, + UINT alignAnchor + ); + +/** + * \brief Get the bit count required by a Program Config Element + * + * \param channelMode the channel mode to be used + * \param matrix mixdown gain + * \param bit offset at which the PCE would start + * \return the amount of bits required for the PCE including the given bit offset. + */ +int transportEnc_GetPCEBits( + CHANNEL_MODE channelMode, + int matrixMixdownA, + int bits + ); + +#endif /* TPENC_ASC_H */ + diff --git a/libMpegTPEnc/src/tpenc_latm.cpp b/libMpegTPEnc/src/tpenc_latm.cpp new file mode 100644 index 0000000..a26d0da --- /dev/null +++ b/libMpegTPEnc/src/tpenc_latm.cpp @@ -0,0 +1,820 @@ +/***************************** MPEG-4 AAC Encoder ************************** + + (C) Copyright Fraunhofer IIS (2001) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "tpenc_latm.h" + + +#include "genericStds.h" + +static const short celpFrameLengthTable[64] = { + 154, 170, 186, 147, 156, 165, 114, 120, + 186, 126, 132, 138, 142, 146, 154, 166, + 174, 182, 190, 198, 206, 210, 214, 110, + 114, 118, 120, 122, 218, 230, 242, 254, + 266, 278, 286, 294, 318, 342, 358, 374, + 390, 406, 422, 136, 142, 148, 154, 160, + 166, 170, 174, 186, 198, 206, 214, 222, + 230, 238, 216, 160, 280, 338, 0, 0 +}; + +/******* + write value to transport stream + first two bits define the size of the value itself + then the value itself, with a size of 0-3 bytes +*******/ +static +UINT transportEnc_LatmWriteValue(HANDLE_FDK_BITSTREAM hBs, int value) +{ + UCHAR valueBytes = 4; + unsigned int bitsWritten = 0; + int i; + + if ( value < (1<<8) ) { + valueBytes = 1; + } else if ( value < (1<<16) ) { + valueBytes = 2; + } else if ( value < (1<<24) ) { + valueBytes = 3; + } else { + valueBytes = 4; + } + + FDKwriteBits(hBs, valueBytes-1, 2 ); /* size of value in Bytes */ + for (i=0; i>((valueBytes-1-i)<<3)), 8); + } + + bitsWritten = (valueBytes<<3)+2; + + return bitsWritten; +} + +static +UINT transportEnc_LatmCountFixBitDemandHeader ( HANDLE_LATM_STREAM hAss ) +{ + int bitDemand = 0; + int insertSetupData = 0 ; + + /* only if start of new latm frame */ + if (hAss->subFrameCnt==0) + { + /* AudioSyncStream */ + + if (hAss->tt == TT_MP4_LOAS) { + bitDemand += 11 ; /* syncword */ + bitDemand += 13 ; /* audioMuxLengthBytes */ + } + + /* AudioMuxElement*/ + + /* AudioMuxElement::Stream Mux Config */ + if (hAss->muxConfigPeriod > 0) { + insertSetupData = (hAss->latmFrameCounter == 0); + } else { + insertSetupData = 0; + } + + if (hAss->tt != TT_MP4_LATM_MCP0) { + /* AudioMuxElement::useSameStreamMux Flag */ + bitDemand+=1; + + if( insertSetupData ) { + bitDemand += hAss->streamMuxConfigBits; + } + } + + /* AudioMuxElement::otherDataBits */ + bitDemand += 8*hAss->otherDataLenBytes; + + /* AudioMuxElement::ByteAlign */ + if ( bitDemand % 8 ) { + hAss->fillBits = 8 - (bitDemand % 8); + bitDemand += hAss->fillBits ; + } else { + hAss->fillBits = 0; + } + } + + return bitDemand ; +} + +static +UINT transportEnc_LatmCountVarBitDemandHeader ( HANDLE_LATM_STREAM hAss , unsigned int streamDataLength ) +{ + int bitDemand = 0; + int prog, layer; + + /* Payload Length Info*/ + if( hAss->allStreamsSameTimeFraming ) { + for( prog=0; prognoProgram; prog++ ) { + for( layer=0; layerm_linfo[prog][layer]); + + if( p_linfo->streamID >= 0 ) { + switch( p_linfo->frameLengthType ) { + case 0: + if ( streamDataLength > 0 ) { + streamDataLength -= bitDemand ; + while( streamDataLength >= (255<<3) ) { + bitDemand+=8; + streamDataLength -= (255<<3); + } + bitDemand += 8; + } + break; + + case 1: + case 4: + case 6: + bitDemand += 2; + break; + + default: + return 0; + } + } + } + } + } else { + /* there are many possibilities to use this mechanism. */ + switch( hAss->varMode ) { + case LATMVAR_SIMPLE_SEQUENCE: { + /* Use the sequence generated by the encoder */ + //int streamCntPosition = transportEnc_SetWritePointer( hAss->hAssemble, 0 ); + //int streamCntPosition = FDKgetValidBits( hAss->hAssemble ); + bitDemand+=4; + + hAss->varStreamCnt = 0; + for( prog=0; prognoProgram; prog++ ) { + for( layer=0; layerm_linfo[prog][layer]); + + if( p_linfo->streamID >= 0 ) { + + bitDemand+=4; /* streamID */ + switch( p_linfo->frameLengthType ) { + case 0: + streamDataLength -= bitDemand ; + while( streamDataLength >= (255<<3) ) { + bitDemand+=8; + streamDataLength -= (255<<3); + } + + bitDemand += 8; + break; + /*bitDemand += 1; endFlag + break;*/ + + case 1: + case 4: + case 6: + + break; + + default: + return 0; + } + hAss->varStreamCnt++; + } + } + } + bitDemand+=4; + //transportEnc_UpdateBitstreamField( hAss->hAssemble, streamCntPosition, hAss->varStreamCnt-1, 4 ); + //UINT pos = streamCntPosition-FDKgetValidBits(hAss->hAssemble); + //FDKpushBack( hAss->hAssemble, pos); + //FDKwriteBits( hAss->hAssemble, hAss->varStreamCnt-1, 4); + //FDKpushFor( hAss->hAssemble, pos-4); + } + break; + + default: + return 0; + } + } + + return bitDemand ; +} + +TRANSPORTENC_ERROR +CreateStreamMuxConfig( + HANDLE_LATM_STREAM hAss, + HANDLE_FDK_BITSTREAM hBs, + int bufferFullness, + CSTpCallBacks *cb + ) +{ + INT streamIDcnt, tmp; + int layer, prog; + + USHORT coreFrameOffset=0; + + hAss->audioMuxVersionA = 0; /* for future extensions */ + hAss->streamMuxConfigBits = 0; + + FDKwriteBits( hBs, hAss->audioMuxVersion, 1 ); /* audioMuxVersion */ + hAss->streamMuxConfigBits += 1; + + if ( hAss->audioMuxVersion == 1 ) { + FDKwriteBits( hBs, hAss->audioMuxVersionA, 1 ); /* audioMuxVersionA */ + hAss->streamMuxConfigBits+=1; + } + + if ( hAss->audioMuxVersionA == 0 ) + { + if ( hAss->audioMuxVersion == 1 ) { + hAss->streamMuxConfigBits+= transportEnc_LatmWriteValue( hBs, hAss->taraBufferFullness );/* taraBufferFullness */ + } + FDKwriteBits( hBs, hAss->allStreamsSameTimeFraming ? 1:0, 1 ); /* allStreamsSameTimeFraming */ + FDKwriteBits( hBs, hAss->noSubframes-1, 6 ); /* Number of Subframes */ + FDKwriteBits( hBs, hAss->noProgram-1, 4 ); /* Number of Programs */ + + hAss->streamMuxConfigBits+=11; + + streamIDcnt = 0; + for( prog=0; prognoProgram; prog++ ) { + int transLayer = 0; + + FDKwriteBits( hBs, hAss->noLayer[prog]-1, 3 ); + hAss->streamMuxConfigBits+=3; + + for( layer=0; layerm_linfo[prog][layer]); + CODER_CONFIG *p_lci = hAss->config[prog][layer]; + + p_linfo->streamID = -1; + + if( hAss->config[prog][layer] != NULL ) { + int useSameConfig = 0; + + if( transLayer > 0 ) { + FDKwriteBits( hBs, useSameConfig ? 1 : 0, 1 ); + hAss->streamMuxConfigBits+=1; + } + if( (useSameConfig == 0) || (transLayer==0) ) { + UINT bits; + + if ( hAss->audioMuxVersion == 1 ) { + FDKpushFor(hBs, 2); /* align to ASC, even if we do not know the length of the "ascLen" field yet */ + } + + bits = FDKgetValidBits( hBs ); + + transportEnc_writeASC( + hBs, + hAss->config[prog][layer], + cb + ); + + bits = FDKgetValidBits( hBs ) - bits; + + if ( hAss->audioMuxVersion == 1 ) { + FDKpushBack(hBs, bits+2); + hAss->streamMuxConfigBits += transportEnc_LatmWriteValue( hBs, bits ); + transportEnc_writeASC( + hBs, + hAss->config[prog][layer], + cb + ); + } + + hAss->streamMuxConfigBits += bits; /* add asc length to smc summary */ + } + transLayer++; + + if( !hAss->allStreamsSameTimeFraming ) { + if( streamIDcnt >= LATM_MAX_STREAM_ID ) + return TRANSPORTENC_INVALID_CONFIG; + } + p_linfo->streamID = streamIDcnt++; + + switch( p_lci->aot ) { + case AOT_AAC_MAIN : + case AOT_AAC_LC : + case AOT_AAC_SSR : + case AOT_AAC_LTP : + case AOT_AAC_SCAL : + case AOT_ER_AAC_LD : + case AOT_ER_AAC_ELD : + case AOT_USAC: + case AOT_RSVD50: + p_linfo->frameLengthType = 0; + + FDKwriteBits( hBs, p_linfo->frameLengthType, 3 ); /* frameLengthType */ + FDKwriteBits( hBs, bufferFullness, 8 ); /* bufferFullness */ + hAss->streamMuxConfigBits+=11; + + if ( !hAss->allStreamsSameTimeFraming ) { + CODER_CONFIG *p_lci_prev = hAss->config[prog][layer-1]; + if ( ((p_lci->aot == AOT_AAC_SCAL) || (p_lci->aot == AOT_ER_AAC_SCAL)) && + ((p_lci_prev->aot == AOT_CELP) || (p_lci_prev->aot == AOT_ER_CELP)) ) { + FDKwriteBits( hBs, coreFrameOffset, 6 ); /* coreFrameOffset */ + hAss->streamMuxConfigBits+=6; + } + } + break; + + case AOT_TWIN_VQ: + p_linfo->frameLengthType = 1; + tmp = ( (p_lci->bitsFrame+7) >> 3 ) - 20; /* transmission frame length in bytes */ + if( (tmp < 0) ) { + return TRANSPORTENC_INVALID_TRANSMISSION_FRAME_LENGTH; + } + FDKwriteBits( hBs, p_linfo->frameLengthType, 3 ); /* frameLengthType */ + FDKwriteBits( hBs, tmp, 9 ); + hAss->streamMuxConfigBits+=12; + + p_linfo->frameLengthBits = (tmp+20) << 3; + break; + + case AOT_CELP: + p_linfo->frameLengthType = 4; + FDKwriteBits( hBs, p_linfo->frameLengthType, 3 ); /* frameLengthType */ + hAss->streamMuxConfigBits+=3; + { + int i; + for( i=0; i<62; i++ ) { + if( celpFrameLengthTable[i] == p_lci->bitsFrame ) + break; + } + if( i>=62 ) { + return TRANSPORTENC_INVALID_CELP_FRAME_LENGTH; + } + + FDKwriteBits( hBs, i, 6 ); /* CELPframeLengthTabelIndex */ + hAss->streamMuxConfigBits+=6; + } + p_linfo->frameLengthBits = p_lci->bitsFrame; + break; + + case AOT_HVXC: + p_linfo->frameLengthType = 6; + FDKwriteBits( hBs, p_linfo->frameLengthType, 3 ); /* frameLengthType */ + hAss->streamMuxConfigBits+=3; + { + int i; + + if( p_lci->bitsFrame == 40 ) { + i = 0; + } else if( p_lci->bitsFrame == 80 ) { + i = 1; + } else { + return TRANSPORTENC_INVALID_FRAME_BITS; + } + FDKwriteBits( hBs, i, 1 ); /* HVXCframeLengthTableIndex */ + hAss->streamMuxConfigBits+=1; + } + p_linfo->frameLengthBits = p_lci->bitsFrame; + break; + + case AOT_NULL_OBJECT: + default: + return TRANSPORTENC_INVALID_AOT; + } + } + } + } + + FDKwriteBits( hBs, (hAss->otherDataLenBytes>0) ? 1:0, 1 ); /* otherDataPresent */ + hAss->streamMuxConfigBits+=1; + + if( hAss->otherDataLenBytes > 0 ) { + + INT otherDataLenTmp = hAss->otherDataLenBytes; + INT escCnt = 0; + INT otherDataLenEsc = 1; + + while(otherDataLenTmp) { + otherDataLenTmp >>= 8; + escCnt ++; + } + + do { + otherDataLenTmp = (hAss->otherDataLenBytes>>(escCnt*8)) & 0xFF; + escCnt--; + otherDataLenEsc = escCnt>0; + + FDKwriteBits( hBs, otherDataLenEsc, 1 ); + FDKwriteBits( hBs, otherDataLenTmp, 8 ); + hAss->streamMuxConfigBits+=9; + } while(otherDataLenEsc); + } + + { + USHORT crcCheckPresent=0; + USHORT crcCheckSum=0; + + FDKwriteBits( hBs, crcCheckPresent, 1 ); /* crcCheckPresent */ + hAss->streamMuxConfigBits+=1; + if ( crcCheckPresent ){ + FDKwriteBits( hBs, crcCheckSum, 8 ); /* crcCheckSum */ + hAss->streamMuxConfigBits+=8; + } + } + + } else { /* if ( audioMuxVersionA == 0 ) */ + + /* for future extensions */ + + } + + return TRANSPORTENC_OK; +} + + +static TRANSPORTENC_ERROR +WriteAuPayloadLengthInfo( HANDLE_FDK_BITSTREAM hBitStream, int AuLengthBits ) +{ + int restBytes; + + if( AuLengthBits % 8 ) + return TRANSPORTENC_INVALID_AU_LENGTH; + + while( AuLengthBits >= 255*8 ) { + FDKwriteBits( hBitStream, 255, 8 ); /* 255 shows incomplete AU */ + AuLengthBits -= (255*8); + } + + restBytes = (AuLengthBits) >> 3; + FDKwriteBits( hBitStream, restBytes, 8 ); + + return TRANSPORTENC_OK; +} + +static +TRANSPORTENC_ERROR transportEnc_LatmSetNrOfSubframes( HANDLE_LATM_STREAM hAss, + INT noSubframes_next) /* nr of access units / payloads within a latm frame */ +{ + /* sanity chk */ + if (noSubframes_next < 1 || noSubframes_next > MAX_NR_OF_SUBFRAMES) { + return TRANSPORTENC_LATM_INVALID_NR_OF_SUBFRAMES; + } + + hAss->noSubframes_next = noSubframes_next; + + /* if at start then we can take over the value immediately, otherwise we have to wait for the next SMC */ + if ( (hAss->subFrameCnt == 0) && (hAss->latmFrameCounter == 0) ) { + hAss->noSubframes = noSubframes_next; + } + + return TRANSPORTENC_OK; +} + +static +int allStreamsSameTimeFraming( HANDLE_LATM_STREAM hAss, UCHAR noProgram, UCHAR noLayer[] /* return */ ) +{ + int prog, layer; + + signed int lastNoSamples = -1; + signed int minFrameSamples = FDK_INT_MAX; + signed int maxFrameSamples = 0; + + signed int highestSamplingRate = -1; + + for( prog=0; progconfig[prog][layer] != NULL ) + { + INT hsfSamplesFrame; + + noLayer[prog]++; + + if( highestSamplingRate < 0 ) + highestSamplingRate = hAss->config[prog][layer]->samplingRate; + + hsfSamplesFrame = hAss->config[prog][layer]->samplesPerFrame * highestSamplingRate / hAss->config[prog][layer]->samplingRate; + + if( hsfSamplesFrame <= minFrameSamples ) minFrameSamples = hsfSamplesFrame; + if( hsfSamplesFrame >= maxFrameSamples ) maxFrameSamples = hsfSamplesFrame; + + if( lastNoSamples == -1 ) { + lastNoSamples = hsfSamplesFrame; + } else { + if( hsfSamplesFrame != lastNoSamples ) { + return 0; + } + } + } + } + } + + return 1; +} + +/** + * Initialize LATM/LOAS Stream and add layer 0 at program 0. + */ +static +TRANSPORTENC_ERROR transportEnc_InitLatmStream( HANDLE_LATM_STREAM hAss, + int fractDelayPresent, + signed int muxConfigPeriod, /* insert setup data every muxConfigPeriod frames */ + UINT audioMuxVersion, + TRANSPORT_TYPE tt + ) +{ + TRANSPORTENC_ERROR ErrorStatus = TRANSPORTENC_OK; + + if (hAss == NULL) + return TRANSPORTENC_INVALID_PARAMETER; + + hAss->tt = tt; + + hAss->noProgram = 1; + + hAss->audioMuxVersion = audioMuxVersion; + + /* Fill noLayer array using hAss->config */ + hAss->allStreamsSameTimeFraming = allStreamsSameTimeFraming( hAss, hAss->noProgram, hAss->noLayer ); + /* Only allStreamsSameTimeFraming==1 is supported */ + FDK_ASSERT(hAss->allStreamsSameTimeFraming); + + hAss->fractDelayPresent = fractDelayPresent; + hAss->otherDataLenBytes = 0; + + hAss->varMode = LATMVAR_SIMPLE_SEQUENCE; + + /* initialize counters */ + hAss->subFrameCnt = 0; + hAss->noSubframes = DEFAULT_LATM_NR_OF_SUBFRAMES; + hAss->noSubframes_next = DEFAULT_LATM_NR_OF_SUBFRAMES; + + /* sync layer related */ + hAss->audioMuxLengthBytes = 0; + + hAss->latmFrameCounter = 0; + hAss->muxConfigPeriod = muxConfigPeriod; + + return ErrorStatus; +} + + +/** + * + */ +UINT transportEnc_LatmCountTotalBitDemandHeader ( HANDLE_LATM_STREAM hAss , unsigned int streamDataLength ) +{ + UINT bitDemand = 0; + + switch (hAss->tt) { + case TT_MP4_LOAS: + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + if (hAss->subFrameCnt == 0) { + bitDemand = transportEnc_LatmCountFixBitDemandHeader ( hAss ); + } + bitDemand += transportEnc_LatmCountVarBitDemandHeader ( hAss , streamDataLength /*- bitDemand*/); + break; + default: + break; + } + + return bitDemand; +} + +static TRANSPORTENC_ERROR +AdvanceAudioMuxElement ( + HANDLE_LATM_STREAM hAss, + HANDLE_FDK_BITSTREAM hBs, + int auBits, + int bufferFullness, + CSTpCallBacks *cb + ) +{ + TRANSPORTENC_ERROR ErrorStatus = TRANSPORTENC_OK; + int insertMuxSetup; + + /* Insert setup data to assemble Buffer */ + if (hAss->subFrameCnt == 0) + { + if (hAss->muxConfigPeriod > 0) { + insertMuxSetup = (hAss->latmFrameCounter == 0); + } else { + insertMuxSetup = 0; + } + + if (hAss->tt != TT_MP4_LATM_MCP0) { + if( insertMuxSetup ) { + FDKwriteBits( hBs, 0, 1 ); /* useSameStreamMux useNewStreamMux */ + CreateStreamMuxConfig(hAss, hBs, bufferFullness, cb); + if (ErrorStatus != TRANSPORTENC_OK) + return ErrorStatus; + } else { + FDKwriteBits( hBs, 1, 1 ); /* useSameStreamMux */ + } + } + } + + /* PayloadLengthInfo */ + { + int prog, layer; + + for (prog = 0; prog < hAss->noProgram; prog++) { + for (layer = 0; layer < hAss->noLayer[prog]; layer++) { + ErrorStatus = WriteAuPayloadLengthInfo( hBs, auBits ); + if (ErrorStatus != TRANSPORTENC_OK) + return ErrorStatus; + } + } + } + /* At this point comes the access unit. */ + + return TRANSPORTENC_OK; +} + +TRANSPORTENC_ERROR +transportEnc_LatmWrite ( + HANDLE_LATM_STREAM hAss, + HANDLE_FDK_BITSTREAM hBs, + int auBits, + int bufferFullness, + CSTpCallBacks *cb + ) +{ + TRANSPORTENC_ERROR ErrorStatus; + + if (hAss->subFrameCnt == 0) { + /* Start new frame */ + FDKresetBitbuffer(hBs, BS_WRITER); + } + + hAss->latmSubframeStart = FDKgetValidBits(hBs); + + /* Insert syncword and syncword distance + - only if loas + - we must update the syncword distance (=audiomuxlengthbytes) later + */ + if( hAss->tt == TT_MP4_LOAS && hAss->subFrameCnt == 0) + { + /* Start new LOAS frame */ + FDKwriteBits( hBs, 0x2B7, 11 ); + hAss->audioMuxLengthBytes = 0; + hAss->audioMuxLengthBytesPos = FDKgetValidBits( hBs ); /* store read pointer position */ + FDKwriteBits( hBs, hAss->audioMuxLengthBytes, 13 ); + } + + ErrorStatus = AdvanceAudioMuxElement( + hAss, + hBs, + auBits, + bufferFullness, + cb + ); + + if (ErrorStatus != TRANSPORTENC_OK) + return ErrorStatus; + + return ErrorStatus; +} + +void transportEnc_LatmAdjustSubframeBits(HANDLE_LATM_STREAM hAss, + int *bits) +{ + /* Substract bits from possible previous subframe */ + *bits -= hAss->latmSubframeStart; + /* Add fill bits */ + if (hAss->subFrameCnt == 0) + *bits += hAss->fillBits; +} + + +void transportEnc_LatmGetFrame(HANDLE_LATM_STREAM hAss, + HANDLE_FDK_BITSTREAM hBs, + int *bytes) +{ + + hAss->subFrameCnt++; + if (hAss->subFrameCnt >= hAss->noSubframes) + { + + /* Add LOAS frame length if required. */ + if (hAss->tt == TT_MP4_LOAS) + { + int latmBytes; + + latmBytes = (FDKgetValidBits(hBs)+7) >> 3; + + /* write length info into assembler buffer */ + hAss->audioMuxLengthBytes = latmBytes - 3; /* 3=Syncword + length */ + { + FDK_BITSTREAM tmpBuf; + + FDKinitBitStream( &tmpBuf, hBs->hBitBuf.Buffer, hBs->hBitBuf.bufSize, 0, BS_WRITER ) ; + FDKpushFor( &tmpBuf, hAss->audioMuxLengthBytesPos ); + FDKwriteBits( &tmpBuf, hAss->audioMuxLengthBytes, 13 ); + FDKsyncCache( &tmpBuf ); + } + } + + /* Write AudioMuxElement byte alignment fill bits */ + FDKwriteBits(hBs, 0, hAss->fillBits); + + FDK_ASSERT( (FDKgetValidBits(hBs) % 8) == 0); + + hAss->subFrameCnt = 0; + + FDKsyncCache(hBs); + *bytes = (FDKgetValidBits(hBs) + 7)>>3; + //FDKfetchBuffer(hBs, buffer, (UINT*)bytes); + + if (hAss->muxConfigPeriod > 0) + { + hAss->latmFrameCounter++; + + if (hAss->latmFrameCounter >= hAss->muxConfigPeriod) { + hAss->latmFrameCounter = 0; + hAss->noSubframes = hAss->noSubframes_next; + } + } + } else { + /* No data this time */ + *bytes = 0; + } +} + +/** + * Init LATM/LOAS + */ +TRANSPORTENC_ERROR transportEnc_Latm_Init( + HANDLE_LATM_STREAM hAss, + HANDLE_FDK_BITSTREAM hBs, + CODER_CONFIG *layerConfig, + UINT audioMuxVersion, + TRANSPORT_TYPE tt, + CSTpCallBacks *cb + ) +{ + TRANSPORTENC_ERROR ErrorStatus; + int fractDelayPresent = 0; + int prog, layer; + + int setupDataDistanceFrames = layerConfig->headerPeriod; + + FDK_ASSERT(setupDataDistanceFrames>=0); + + for (prog=0; progconfig[prog][layer] = NULL; + hAss->m_linfo[prog][layer].streamID = -1; + } + } + + hAss->config[0][0] = layerConfig; + hAss->m_linfo[0][0].streamID = 0; + + ErrorStatus = transportEnc_InitLatmStream( hAss, + fractDelayPresent, + setupDataDistanceFrames, + (audioMuxVersion)?1:0, + tt + ); + if (ErrorStatus != TRANSPORTENC_OK) + goto bail; + + ErrorStatus = transportEnc_LatmSetNrOfSubframes( + hAss, + layerConfig->nSubFrames + ); + if (ErrorStatus != TRANSPORTENC_OK) + goto bail; + + /* Get the size of the StreamMuxConfig somehow */ + AdvanceAudioMuxElement(hAss, hBs, 0, 0, cb); + //CreateStreamMuxConfig(hAss, hBs, 0); + +bail: + return ErrorStatus; +} + + + + + + diff --git a/libMpegTPEnc/src/tpenc_latm.h b/libMpegTPEnc/src/tpenc_latm.h new file mode 100644 index 0000000..29dba5b --- /dev/null +++ b/libMpegTPEnc/src/tpenc_latm.h @@ -0,0 +1,204 @@ +/***************************** MPEG-4 AAC Encoder ************************** + + (C) Copyright Fraunhofer IIS (2001) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef TPENC_LATM_H +#define TPENC_LATM_H + + + +#include "tpenc_lib.h" +#include "FDK_bitstream.h" + + +#define DEFAULT_LATM_NR_OF_SUBFRAMES 1 +#define DEFAULT_LATM_SMC_REPEAT 8 + +#define MAX_AAC_LAYERS 9 + +#define LATM_MAX_PROGRAMS 1 +#define LATM_MAX_STREAM_ID 16 + +#define LATM_MAX_LAYERS 1 /*MAX_AAC_LAYERS*/ + +#define MAX_NR_OF_SUBFRAMES 2 /* set this carefully to avoid buffer overflows */ + +typedef enum { LATMVAR_SIMPLE_SEQUENCE } LATM_VAR_MODE; + +typedef struct { + signed int frameLengthType; + signed int frameLengthBits; + signed int varFrameLengthTable[4]; + signed int streamID; +} LATM_LAYER_INFO; + +#define LATM_ASSEMBLEBUF_SIZE ((200+16)*8) +#define LATM_SETUPBUF_SIZE (200*8) + +typedef struct { + LATM_LAYER_INFO m_linfo[LATM_MAX_PROGRAMS][LATM_MAX_LAYERS]; + CODER_CONFIG *config[LATM_MAX_PROGRAMS][LATM_MAX_LAYERS]; + + LATM_VAR_MODE varMode; + TRANSPORT_TYPE tt; + + int audioMuxLengthBytes; + + int audioMuxLengthBytesPos; + int taraBufferFullness; /* state of the bit reservoir */ + int varStreamCnt; + unsigned int otherDataLenBytes; + + UCHAR latmFrameCounter; /* Current frame number. Counts modulo muxConfigPeriod */ + UCHAR muxConfigPeriod; /* Distance in frames between MuxConfig */ + + UCHAR audioMuxVersion; /* AMV1 supports transmission of taraBufferFullness and ASC lengths */ + UCHAR audioMuxVersionA; /* for future extensions */ + + UCHAR noProgram; + UCHAR noLayer[LATM_MAX_PROGRAMS]; + UCHAR fractDelayPresent; + + UCHAR allStreamsSameTimeFraming; + UCHAR subFrameCnt; /* Current Subframe frame */ + UCHAR noSubframes; /* Number of subframes */ + UINT latmSubframeStart; /* Position of current subframe start */ + UCHAR noSubframes_next; + + UCHAR fillBits; /* AudioMuxElement fill bits */ + UCHAR streamMuxConfigBits; + +} LATM_STREAM; + +typedef LATM_STREAM *HANDLE_LATM_STREAM; + +/** + * \brief Initialize LATM_STREAM Handle. Creates automatically one program with one layer with + * the given layerConfig. The layerConfig must be persisten because references to this pointer + * are made at any time again. + * Use transportEnc_Latm_AddLayer() to add more programs/layers. + * + * \param hLatmStreamInfo HANDLE_LATM_STREAM handle + * \param hBs Bitstream handle + * \param layerConfig a valid CODER_CONFIG struct containing the current audio configuration parameters + * \param audioMuxVersion the LATM audioMuxVersion to be used + * \param tt the specific TRANSPORT_TYPE to be used, either TT_MP4_LOAS, TT_MP4_LATM_MCP1 or TT_MP4_LATM_MCP0 LOAS + * \param cb callback information structure. + * + * \return an TRANSPORTENC_ERROR error code + */ +TRANSPORTENC_ERROR transportEnc_Latm_Init( + HANDLE_LATM_STREAM hLatmStreamInfo, + HANDLE_FDK_BITSTREAM hBs, + CODER_CONFIG *layerConfig, + UINT audioMuxVersion, + TRANSPORT_TYPE tt, + CSTpCallBacks *cb + ); + +/** + * \brief Get bit demand of next LATM/LOAS header + * + * \param hAss HANDLE_LATM_STREAM handle + * \param streamDataLength the length of the payload + * + * \return the number of bits required by the LATM/LOAS headers + */ +unsigned int transportEnc_LatmCountTotalBitDemandHeader ( + HANDLE_LATM_STREAM hAss, + unsigned int streamDataLength + ); + +/** + * \brief Write LATM/LOAS header into given bitstream handle + * + * \param hLatmStreamInfo HANDLE_LATM_STREAM handle + * \param hBitstream Bitstream handle + * \param auBits amount of current payload bits + * \param bufferFullness LATM buffer fullness value + * \param cb callback information structure. + * + * \return an TRANSPORTENC_ERROR error code + */ +TRANSPORTENC_ERROR +transportEnc_LatmWrite ( + HANDLE_LATM_STREAM hAss, + HANDLE_FDK_BITSTREAM hBitstream, + int auBits, + int bufferFullness, + CSTpCallBacks *cb + ); + +/** + * \brief Adjust bit count relative to current subframe + * + * \param hAss HANDLE_LATM_STREAM handle + * \param pBits pointer to an int, where the current frame bit count is contained, + * and where the subframe relative bit count will be returned into + * + * \return void + */ +void transportEnc_LatmAdjustSubframeBits(HANDLE_LATM_STREAM hAss, + int *pBits); + +/** + * \brief Request an LATM frame, which may, or may not be available + * + * \param hAss HANDLE_LATM_STREAM handle + * \param hBs Bitstream handle + * \param pBytes pointer to an int, where the current frame byte count stored into. + * A return value of zero means that currently no LATM/LOAS frame can be returned. + * The latter is expected in case of multiple subframes being used. + * + * \return void + */ +void transportEnc_LatmGetFrame( + HANDLE_LATM_STREAM hAss, + HANDLE_FDK_BITSTREAM hBs, + int *pBytes + ); + +/** + * \brief Write a StreamMuxConfig into the given bitstream handle + * + * \param hAss HANDLE_LATM_STREAM handle + * \param hBs Bitstream handle + * \param bufferFullness LATM buffer fullness value + * \param cb callback information structure. + * + * \return void + */ +TRANSPORTENC_ERROR +CreateStreamMuxConfig( + HANDLE_LATM_STREAM hAss, + HANDLE_FDK_BITSTREAM hBs, + int bufferFullness, + CSTpCallBacks *cb + ); + + +#endif /* TPENC_LATM_H */ diff --git a/libMpegTPEnc/src/tpenc_lib.cpp b/libMpegTPEnc/src/tpenc_lib.cpp new file mode 100644 index 0000000..9afb669 --- /dev/null +++ b/libMpegTPEnc/src/tpenc_lib.cpp @@ -0,0 +1,569 @@ +/************************** MPEG-4 Transport Encoder ************************ + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: MPEG Transport encode + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "tpenc_lib.h" + +/* library info */ +#include "version" + +#define MODULE_NAME "transportEnc" + +#include "tpenc_asc.h" +#include "conv_string.h" + +#include "tpenc_adts.h" + +#include "tpenc_adif.h" + +#include "tpenc_latm.h" + + + +typedef struct { + int curSubFrame; + int nSubFrames; + int prevBits; +} RAWPACKETS_INFO; + +struct TRANSPORTENC +{ + CODER_CONFIG config; + TRANSPORT_TYPE transportFmt; /*!< MPEG4 transport type. */ + + FDK_BITSTREAM bitStream; + UCHAR *bsBuffer; + INT bsBufferSize; + + INT pceFrameCounter; /*!< Indicates frame period when PCE must be written in raw_data_block. + -1 means not to write a PCE in raw_dat_block. */ + union { + STRUCT_ADTS adts; + + ADIF_INFO adif; + + LATM_STREAM latm; + + RAWPACKETS_INFO raw; + + + + } writer; + + CSTpCallBacks callbacks; +}; + +typedef struct _TRANSPORTENC_STRUCT TRANSPORTENC_STRUCT; + + +/* + * MEMORY Declaration + */ + +C_ALLOC_MEM(Ram_TransportEncoder, TRANSPORTENC, 1) + +TRANSPORTENC_ERROR transportEnc_Open( HANDLE_TRANSPORTENC *phTpEnc ) +{ + HANDLE_TRANSPORTENC hTpEnc = GetRam_TransportEncoder(0); + + if ( hTpEnc == NULL ) { + return TRANSPORTENC_INVALID_PARAMETER; + } + + *phTpEnc = hTpEnc; + return TRANSPORTENC_OK; +} + +/** + * \brief Get frame period of PCE in raw_data_block. + * + * - Write PCE only if necessary. PCE can be part of the ASC if chConfig==0 whererfore + * no additonal PCE will be written in raw_data_block. + * - A matrixMixdown coefficient can only be written if chConfig is 5.0 or 5.1. + * - The PCE repetition rate in raw_data_block can be controlled via headerPeriod parameter. + * + * \param channelConfig Channel Configuration derived from Channel Mode + * \param transportFmt Format of the transport to be written. + * \param headerPeriod Chosen PCE frame repetition rate. + * \param matrixMixdownA Indicates if a valid Matrix Mixdown coefficient is available. + * + * \return PCE frame repetition rate. -1 means no PCE present in raw_data_block. + */ +static INT getPceRepetitionRate( + const int channelConfig, + const TRANSPORT_TYPE transportFmt, + const int headerPeriod, + const int matrixMixdownA + ) +{ + INT pceFrameCounter = -1; /* variable to be returned */ + + if (headerPeriod>0) { + switch ( channelConfig ) { + case 0: + switch (transportFmt) { + case TT_MP4_ADTS: + case TT_MP4_LATM_MCP0: + case TT_MP4_RAW: + pceFrameCounter = headerPeriod; + break; + case TT_MP4_ADIF: /* ADIF header comprises PCE */ + case TT_MP4_LOAS: /* PCE in ASC if chChonfig==0 */ + case TT_MP4_LATM_MCP1: /* PCE in ASC if chChonfig==0 */ + case TT_DRM: /* PCE not allowed in DRM */ + default: + pceFrameCounter = -1; /* no PCE in raw_data_block */ + } + break; + case 5: /* MODE_1_2_2 */ + case 6: /* MODE_1_2_2_1 */ + /* matrixMixdownCoefficient can only be written if 5.0 and 5.1 config present. */ + if (matrixMixdownA!=0) { + switch (transportFmt) { + case TT_MP4_ADIF: /* ADIF header comprises PCE */ + case TT_MP4_ADTS: + case TT_MP4_LOAS: /* no PCE in ASC because chConfig!=0 */ + case TT_MP4_LATM_MCP1: /* no PCE in ASC because chConfig!=0 */ + case TT_MP4_LATM_MCP0: + case TT_MP4_RAW: + pceFrameCounter = headerPeriod; + break; + case TT_DRM: /* PCE not allowed in DRM */ + default: + pceFrameCounter = -1; /* no PCE in raw_data_block */ + } /* switch transportFmt */ + } /* if matrixMixdownA!=0 */ + break; + default: + pceFrameCounter = -1; /* no PCE in raw_data_block */ + } /* switch getChannelConfig() */ + } /* if headerPeriod>0 */ + else { + pceFrameCounter = -1; /* no PCE in raw_data_block */ + } + + return pceFrameCounter; +} + +TRANSPORTENC_ERROR transportEnc_Init( + HANDLE_TRANSPORTENC hTpEnc, + UCHAR *bsBuffer, + INT bsBufferSize, + TRANSPORT_TYPE transportFmt, + CODER_CONFIG *cconfig, + UINT flags + ) +{ + /* Copy configuration structure */ + FDKmemcpy(&hTpEnc->config, cconfig, sizeof(CODER_CONFIG)); + + /* Init transportEnc struct. */ + hTpEnc->transportFmt = transportFmt; + + hTpEnc->bsBuffer = bsBuffer; + hTpEnc->bsBufferSize = bsBufferSize; + + FDKinitBitStream(&hTpEnc->bitStream, hTpEnc->bsBuffer, hTpEnc->bsBufferSize, 0, BS_WRITER); + + switch (transportFmt) { + + case TT_MP4_ADIF: + /* Sanity checks */ + if ( (hTpEnc->config.aot != AOT_AAC_LC) + ||(hTpEnc->config.samplesPerFrame != 1024)) + { + return TRANSPORTENC_INVALID_PARAMETER; + } + hTpEnc->writer.adif.headerWritten = 0; + hTpEnc->writer.adif.samplingRate = hTpEnc->config.samplingRate; + hTpEnc->writer.adif.bitRate = hTpEnc->config.bitRate; + hTpEnc->writer.adif.profile = ((int)hTpEnc->config.aot) - 1; + hTpEnc->writer.adif.cm = hTpEnc->config.channelMode; + hTpEnc->writer.adif.bVariableRate = 0; + hTpEnc->writer.adif.instanceTag = 0; + break; + + case TT_MP4_ADTS: + /* Sanity checks */ + if ( ( hTpEnc->config.aot != AOT_AAC_LC) + ||(hTpEnc->config.samplesPerFrame != 1024) ) + { + return TRANSPORTENC_INVALID_PARAMETER; + } + if ( adtsWrite_Init(&hTpEnc->writer.adts, &hTpEnc->config) != 0) { + return TRANSPORTENC_INVALID_PARAMETER; + } + break; + + case TT_MP4_LOAS: + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + { + TRANSPORTENC_ERROR error; + + error = transportEnc_Latm_Init( + &hTpEnc->writer.latm, + &hTpEnc->bitStream, + &hTpEnc->config, + flags & TP_FLAG_LATM_AMV, + transportFmt, + &hTpEnc->callbacks + ); + if (error != TRANSPORTENC_OK) { + return error; + } + } + break; + + case TT_MP4_RAW: + hTpEnc->writer.raw.curSubFrame = 0; + hTpEnc->writer.raw.nSubFrames = hTpEnc->config.nSubFrames; + break; + + + + default: + return TRANSPORTENC_INVALID_PARAMETER; + } + + /* pceFrameCounter indicates if PCE must be written in raw_data_block. */ + hTpEnc->pceFrameCounter = getPceRepetitionRate( + getChannelConfig(hTpEnc->config.channelMode), + transportFmt, + hTpEnc->config.headerPeriod, + hTpEnc->config.matrixMixdownA); + + return TRANSPORTENC_OK; +} + +HANDLE_FDK_BITSTREAM transportEnc_GetBitstream( HANDLE_TRANSPORTENC hTp ) +{ + return &hTp->bitStream; +} + +int transportEnc_RegisterSbrCallback( HANDLE_TRANSPORTENC hTpEnc, const cbSbr_t cbSbr, void* user_data) +{ + if (hTpEnc == NULL) { + return -1; + } + hTpEnc->callbacks.cbSbr = cbSbr; + hTpEnc->callbacks.cbSbrData = user_data; + return 0; +} + + +TRANSPORTENC_ERROR transportEnc_WriteAccessUnit( + HANDLE_TRANSPORTENC hTp, + INT frameUsedBits, + int bufferFullness, + int ncc + ) +{ + TRANSPORTENC_ERROR err = TRANSPORTENC_OK; + + if (!hTp) { + return TRANSPORTENC_INVALID_PARAMETER; + } + HANDLE_FDK_BITSTREAM hBs = &hTp->bitStream; + + /* In case of writing PCE in raw_data_block frameUsedBits must be adapted. */ + if (hTp->pceFrameCounter>=hTp->config.headerPeriod) { + frameUsedBits += transportEnc_GetPCEBits(hTp->config.channelMode, hTp->config.matrixMixdownA, 3); /* Consider 3 bits ID signalling in alignment */ + } + + switch (hTp->transportFmt) { + case TT_MP4_ADIF: + FDKinitBitStream(&hTp->bitStream, hTp->bsBuffer, hTp->bsBufferSize, 0, BS_WRITER); + adifWrite_EncodeHeader( + &hTp->writer.adif, + hBs, + bufferFullness + ); + break; + case TT_MP4_ADTS: + bufferFullness /= ncc; /* Number of Considered Channels */ + bufferFullness /= 32; + bufferFullness = FDKmin(0x7FF, bufferFullness); /* Signal variable rate */ + adtsWrite_EncodeHeader( + &hTp->writer.adts, + &hTp->bitStream, + bufferFullness, + frameUsedBits + ); + break; + case TT_MP4_LOAS: + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + bufferFullness /= ncc; /* Number of Considered Channels */ + bufferFullness /= 32; + bufferFullness = FDKmin(0xFF, bufferFullness); /* Signal variable rate */ + transportEnc_LatmWrite( + &hTp->writer.latm, + hBs, + frameUsedBits, + bufferFullness, + &hTp->callbacks + ); + break; + case TT_MP4_RAW: + if (hTp->writer.raw.curSubFrame >= hTp->writer.raw.nSubFrames) { + hTp->writer.raw.curSubFrame = 0; + FDKinitBitStream(&hTp->bitStream, hTp->bsBuffer, hTp->bsBufferSize, 0, BS_WRITER); + } + hTp->writer.raw.prevBits = FDKgetValidBits(hBs); + break; + default: + err = TRANSPORTENC_UNSUPPORTED_FORMAT; + break; + } + + /* Write PCE in raw_data_block if required */ + if (hTp->pceFrameCounter>=hTp->config.headerPeriod) { + INT crcIndex = 0; + /* Align inside PCE with repsect to the first bit of the raw_data_block() */ + UINT alignAnchor = FDKgetValidBits(&hTp->bitStream); + + /* Write PCE element ID bits */ + FDKwriteBits(&hTp->bitStream, ID_PCE, 3); + + if ( (hTp->transportFmt==TT_MP4_ADTS) && !hTp->writer.adts.protection_absent) { + crcIndex = adtsWrite_CrcStartReg(&hTp->writer.adts, &hTp->bitStream, 0); + } + + /* Write PCE as first raw_data_block element */ + transportEnc_writePCE(&hTp->bitStream, hTp->config.channelMode, hTp->config.samplingRate, 0, 1, hTp->config.matrixMixdownA, hTp->config.flags & CC_PSEUDO_SURROUND, alignAnchor); + + if ( (hTp->transportFmt==TT_MP4_ADTS) && !hTp->writer.adts.protection_absent) { + adtsWrite_CrcEndReg(&hTp->writer.adts, &hTp->bitStream, crcIndex); + } + hTp->pceFrameCounter = 0; /* reset pce frame counter */ + } + + if (hTp->pceFrameCounter!=-1) { + hTp->pceFrameCounter++; /* Update pceFrameCounter only if PCE writing is active. */ + } + + return err; +} + + +TRANSPORTENC_ERROR transportEnc_EndAccessUnit(HANDLE_TRANSPORTENC hTp, int *bits) +{ + switch (hTp->transportFmt) { + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + case TT_MP4_LOAS: + transportEnc_LatmAdjustSubframeBits(&hTp->writer.latm, bits); + break; + case TT_MP4_ADTS: + adtsWrite_EndRawDataBlock(&hTp->writer.adts, &hTp->bitStream, bits); + break; + case TT_MP4_ADIF: + /* Substract ADIF header from AU bits, not to be considered. */ + *bits -= adifWrite_GetHeaderBits(&hTp->writer.adif); + hTp->writer.adif.headerWritten = 1; + break; + case TT_MP4_RAW: + *bits -= hTp->writer.raw.prevBits; + break; + default: + break; + } + + return TRANSPORTENC_OK; +} + +TRANSPORTENC_ERROR transportEnc_GetFrame(HANDLE_TRANSPORTENC hTpEnc, int *nbytes) +{ + HANDLE_FDK_BITSTREAM hBs = &hTpEnc->bitStream; + + switch (hTpEnc->transportFmt) { + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + case TT_MP4_LOAS: + *nbytes = hTpEnc->bsBufferSize; + transportEnc_LatmGetFrame(&hTpEnc->writer.latm, hBs, nbytes); + break; + case TT_MP4_ADTS: + if (hTpEnc->writer.adts.currentBlock >= hTpEnc->writer.adts.num_raw_blocks+1) { + *nbytes = (FDKgetValidBits(hBs) + 7)>>3; + hTpEnc->writer.adts.currentBlock = 0; + } else { + *nbytes = 0; + } + break; + case TT_MP4_ADIF: + FDK_ASSERT((INT)FDKgetValidBits(hBs) >= 0); + *nbytes = (FDKgetValidBits(hBs) + 7)>>3; + break; + case TT_MP4_RAW: + FDKsyncCache(hBs); + hTpEnc->writer.raw.curSubFrame++; + *nbytes = ((FDKgetValidBits(hBs)-hTpEnc->writer.raw.prevBits) + 7)>>3; + break; + default: + break; + } + + return TRANSPORTENC_OK; +} + +INT transportEnc_GetStaticBits( HANDLE_TRANSPORTENC hTp, int auBits ) +{ + INT nbits = 0, nPceBits = 0; + + /* Write PCE within raw_data_block in transport lib. */ + if (hTp->pceFrameCounter>=hTp->config.headerPeriod) { + nPceBits = transportEnc_GetPCEBits(hTp->config.channelMode, hTp->config.matrixMixdownA, 3); /* Consider 3 bits ID signalling in alignment */ + auBits += nPceBits; /* Adapt required raw_data_block bit consumtpion for AU length information e.g. in LATM/LOAS configuration. */ + } + + switch (hTp->transportFmt) { + case TT_MP4_ADIF: + case TT_MP4_RAW: + nbits = 0; /* Do not consider the ADIF header into the total bitrate */ + break; + case TT_MP4_ADTS: + nbits = adtsWrite_GetHeaderBits(&hTp->writer.adts); + break; + case TT_MP4_LOAS: + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + nbits = transportEnc_LatmCountTotalBitDemandHeader( &hTp->writer.latm, auBits ); + break; + default: + nbits = 0; + break; + } + + /* PCE is written in the transport library therefore the bit consumption is part of the transport static bits. */ + nbits += nPceBits; + + return nbits; +} + +void transportEnc_Close(HANDLE_TRANSPORTENC *phTp) +{ + if (phTp != NULL) + { + if (*phTp != NULL) { + FreeRam_TransportEncoder(phTp); + } + } +} + +int transportEnc_CrcStartReg(HANDLE_TRANSPORTENC hTpEnc, int mBits) +{ + int crcReg = 0; + + switch (hTpEnc->transportFmt) { + case TT_MP4_ADTS: + crcReg = adtsWrite_CrcStartReg(&hTpEnc->writer.adts, &hTpEnc->bitStream, mBits); + break; + default: + break; + } + + return crcReg; +} + +void transportEnc_CrcEndReg(HANDLE_TRANSPORTENC hTpEnc, int reg) +{ + switch (hTpEnc->transportFmt) { + case TT_MP4_ADTS: + adtsWrite_CrcEndReg(&hTpEnc->writer.adts, &hTpEnc->bitStream, reg); + break; + default: + break; + } +} + + +TRANSPORTENC_ERROR transportEnc_GetConf(HANDLE_TRANSPORTENC hTpEnc, + CODER_CONFIG *cc, + FDK_BITSTREAM *dataBuffer, + UINT *confType) +{ + TRANSPORTENC_ERROR tpErr = TRANSPORTENC_OK; + HANDLE_LATM_STREAM hLatmConfig = &hTpEnc->writer.latm; + + *confType = 0; /* set confType variable to default */ + + /* write StreamMuxConfig or AudioSpecificConfig depending on format used */ + switch (hTpEnc->transportFmt) + { + case TT_MP4_LATM_MCP0: + case TT_MP4_LATM_MCP1: + case TT_MP4_LOAS: + tpErr = CreateStreamMuxConfig(hLatmConfig, dataBuffer, 0, &hTpEnc->callbacks); + *confType = 1; /* config is SMC */ + break; + default: + if (transportEnc_writeASC(dataBuffer, cc, &hTpEnc->callbacks) != 0) { + tpErr = TRANSPORTENC_UNKOWN_ERROR; + } + } + + return tpErr; + +} + +TRANSPORTENC_ERROR transportEnc_GetLibInfo( LIB_INFO *info ) +{ + int i; + + if (info == NULL) { + return TRANSPORTENC_INVALID_PARAMETER; + } + /* search for next free tab */ + for (i = 0; i < FDK_MODULE_LAST; i++) { + if (info[i].module_id == FDK_NONE) break; + } + if (i == FDK_MODULE_LAST) { + return TRANSPORTENC_UNKOWN_ERROR; + } + info += i; + + info->module_id = FDK_TPENC; + info->version = LIB_VERSION(TP_LIB_VL0, TP_LIB_VL1, TP_LIB_VL2); + LIB_VERSION_STRING(info); + info->build_date = __DATE__; + info->build_time = __TIME__; + info->title = TP_LIB_TITLE; + + /* Set flags */ + info->flags = 0 + | CAPF_ADIF + | CAPF_ADTS + | CAPF_LATM + | CAPF_LOAS + | CAPF_RAWPACKETS + ; + + return TRANSPORTENC_OK; +} + diff --git a/libMpegTPEnc/src/version b/libMpegTPEnc/src/version new file mode 100644 index 0000000..6aa18cf --- /dev/null +++ b/libMpegTPEnc/src/version @@ -0,0 +1,8 @@ + +/* library info */ +#define TP_LIB_VL0 2 +#define TP_LIB_VL1 2 +#define TP_LIB_VL2 0 +#define TP_LIB_TITLE "MPEG Transport" +#define TP_LIB_BUILD_DATE __DATE__ +#define TP_LIB_BUILD_TIME __TIME__ diff --git a/libPCMutils/Android.mk b/libPCMutils/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/libPCMutils/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/libPCMutils/include/pcmutils_lib.h b/libPCMutils/include/pcmutils_lib.h new file mode 100644 index 0000000..4f92e81 --- /dev/null +++ b/libPCMutils/include/pcmutils_lib.h @@ -0,0 +1,220 @@ +/************************ FDK PCM up/downmixing module ********************* + + (C) Copyright Fraunhofer IIS 2008 + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Christian Griebel + Description: Declares functions to interface with the PCM downmix processing + module. + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +*******************************************************************************/ + +#ifndef _PCMUTILS_LIB_H_ +#define _PCMUTILS_LIB_H_ + +#include "machine_type.h" +#include "common_fix.h" +#include "FDK_audio.h" + +/* ------------------------ * + * MODULE SETTINGS: * + * ------------------------ */ +/* #define PCM_UPMIX_ENABLE */ /*!< Generally enable up mixing. */ +#define PCM_DOWNMIX_ENABLE /*!< Generally enable down mixing. */ +#define DVB_MIXDOWN_ENABLE /*!< Enable this to support DVB ancillary data for encoder + assisted downmixing of MPEG-4 AAC and + MPEG-1/2 layer 2 streams. PCM_DOWNMIX_ENABLE has to + be enabled, too! */ +#define MPEG_PCE_MIXDOWN_ENABLE /*!< Enable this to support MPEG matrix mixdown with a + coefficient carried in the PCE. PCM_DOWNMIX_ENABLE + has to be enabled, too! */ +/* #define ARIB_MIXDOWN_ENABLE */ /*!< Enable modifications to the MPEG PCE mixdown method + to fulfill ARIB standard. MPEG_PCE_MIXDOWN_ENABLE has + to be set. */ + +/* ------------------------ * + * ERROR CODES: * + * ------------------------ */ +typedef enum +{ + PCMDMX_OK = 0x0, /*!< No error happened. */ + PCMDMX_OUT_OF_MEMORY = 0x2, /*!< Not enough memory to set up an instance of the module. */ + PCMDMX_UNKNOWN = 0x5, /*!< Error condition is of unknown reason, or from a third + party module. */ + PCMDMX_INVALID_HANDLE, /*!< The given instance handle is not valid. */ + PCMDMX_INVALID_ARGUMENT, /*!< One of the parameters handed over is invalid. */ + PCMDMX_INVALID_CH_CONFIG, /*!< The given channel configuration is not supported and + thus no processing was performed. */ + PCMDMX_INVALID_MODE, /*!< The set configuration/mode is not applicable. */ + PCMDMX_UNKNOWN_PARAM, /*!< The handed parameter is not known/supported. */ + PCMDMX_UNABLE_TO_SET_PARAM, /*!< Unable to set the specific parameter. Most probably + the value ist out of range. */ + PCMDMX_CORRUPT_ANC_DATA /*!< The read ancillary data was corrupt. */ + +} PCMDMX_ERROR; + + +/* ------------------------ * + * RUNTIME PARAMS: * + * ------------------------ */ +typedef enum +{ + DMX_BS_DATA_EXPIRY_FRAME, /*!< The number of frames without new metadata that have to + go by before the bitstream data expires. The value 0 + disables expiry. */ + DMX_BS_DATA_DELAY, /*!< The number of delay frames of the output samples + compared to the bitstream data. */ + NUMBER_OF_OUTPUT_CHANNELS , /*!< The number of output channels (equals the number of + channels processed by the audio output setup). */ + DUAL_CHANNEL_DOWNMIX_MODE /*!< Downmix mode for two channel audio data. */ + +} PCMDMX_PARAM; + + +typedef enum +{ + STEREO_MODE = 0x0, /*!< Leave stereo signals as they are. */ + CH1_MODE = 0x1, /*!< Create a dual mono output signal from channel 1. */ + CH2_MODE = 0x2, /*!< Create a dual mono output signal from channel 2. */ + MIXED_MODE = 0x3 /*!< Create a dual mono output signal by mixing the two channels. */ + +} DUAL_CHANNEL_MODE; + + +/* ------------------------ * + * MODULES INTERFACE: * + * ------------------------ */ +typedef struct PCM_DMX_INSTANCE *HANDLE_PCM_DOWNMIX; + +/* Modules reset flags */ +#define PCMDMX_RESET_PARAMS ( 1 ) +#define PCMDMX_RESET_BS_DATA ( 2 ) +#define PCMDMX_RESET_FULL ( PCMDMX_RESET_PARAMS | PCMDMX_RESET_BS_DATA ) + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** Open and initialize an instance of the PCM downmix module + * @param [out] Pointer to a buffer receiving the handle of the new instance. + * @returns Returns an error code. + **/ +PCMDMX_ERROR pcmDmx_Open ( + HANDLE_PCM_DOWNMIX *pSelf + ); + +/** Set one parameter for one instance of the PCM downmix module. + * @param [in] Handle of PCM downmix instance. + * @param [in] Parameter to be set. + * @param [in] Parameter value. + * @returns Returns an error code. + **/ +PCMDMX_ERROR pcmDmx_SetParam ( + HANDLE_PCM_DOWNMIX self, + PCMDMX_PARAM param, + UINT value + ); + +/** Read the ancillary data transported in DSEs of DVB streams with MPEG-4 content + * @param [in] Handle of PCM downmix instance. + * @param [in] Pointer to ancillary data buffer. + * @param [in] Size of ancillary data. + * @param [in] Flag indicating wheter the ancillary data is from a MPEG-1/2 or an MPEG-4 stream. + * @returns Returns an error code. + **/ +PCMDMX_ERROR pcmDmx_ReadDvbAncData ( + HANDLE_PCM_DOWNMIX self, + UCHAR *pAncDataBuf, + UINT ancDataBytes, + int isMpeg2 + ); + +/** Set the matrix mixdown information extracted from the PCE of an AAC bitstream. + * Note: Call only if matrix_mixdown_idx_present is true. + * @param [in] Handle of PCM downmix instance. + * @param [in] Matrix mixdown index present flag extracted from PCE. + * @param [in] The 2 bit matrix mixdown index extracted from PCE. + * @param [in] The pseudo surround enable flag extracted from PCE. + * @returns Returns an error code. + **/ +PCMDMX_ERROR pcmDmx_SetMatrixMixdownFromPce ( + HANDLE_PCM_DOWNMIX self, + int matrixMixdownPresent, + int matrixMixdownIdx, + int pseudoSurroundEnable + ); + +/** Reset the module. + * @param [in] Handle of PCM downmix instance. + * @param [in] Flags telling which parts of the module shall be reset. + * @returns Returns an error code. + **/ +PCMDMX_ERROR pcmDmx_Reset ( + HANDLE_PCM_DOWNMIX self, + UINT flags + ); + +/** Apply down or up mixing. + * + * \param [in] Handle of PCM downmix module instance. + * \param [inout] Pointer to time buffer with decoded PCM samples. + * \param [in] Pointer where the amount of output samples is returned into. + * \param [inout] Pointer where the amount of output channels is returned into. + * \param [in] Flag which indicates if output time data are writtern interleaved or as subsequent blocks. + * \param [inout] Array were the corresponding channel type for each output audio channel is stored into. + * \param [inout] Array were the corresponding channel type index for each output audio channel is stored into. + * \param [in] Array containing the output channel mapping to be used (From MPEG PCE ordering to whatever is required). + * + * @returns Returns an error code. + **/ +PCMDMX_ERROR pcmDmx_ApplyFrame ( + HANDLE_PCM_DOWNMIX self, + INT_PCM *pPcmBuf, + UINT frameSize, + INT *nChannels, + + int fInterleaved, + AUDIO_CHANNEL_TYPE channelType[], + UCHAR channelIndices[], + const UCHAR channelMapping[][8] + ); + +/** Close an instance of the PCM downmix module. + * @param [inout] Pointer to a buffer containing the handle of the instance. + * @returns Returns an error code. + **/ +PCMDMX_ERROR pcmDmx_Close ( + HANDLE_PCM_DOWNMIX *pSelf + ); + +/** Get library info for this module. + * @param [out] Pointer to an allocated LIB_INFO structure. + * @returns Returns an error code. + */ +PCMDMX_ERROR pcmDmx_GetLibInfo( LIB_INFO *info ); + + +#ifdef __cplusplus +} +#endif + +#endif /* _PCMUTILS_LIB_H_ */ diff --git a/libPCMutils/src/Android.mk b/libPCMutils/src/Android.mk new file mode 100644 index 0000000..174581c --- /dev/null +++ b/libPCMutils/src/Android.mk @@ -0,0 +1,16 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := pcmutils_lib.cpp + +LOCAL_CFLAGS := -DANDROID + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../../libSYS/include \ + $(LOCAL_PATH)/../../libFDK/include + +LOCAL_MODULE:= libPCMutils + +include $(BUILD_STATIC_LIBRARY) diff --git a/libPCMutils/src/pcmutils_lib.cpp b/libPCMutils/src/pcmutils_lib.cpp new file mode 100644 index 0000000..1beec6a --- /dev/null +++ b/libPCMutils/src/pcmutils_lib.cpp @@ -0,0 +1,1219 @@ +/**************************** FDK PCM utils module ************************** + + (C) Copyright Fraunhofer IIS 2008 + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Christian Griebel + Description: Defines functions to interface with the PCM post processing + module. + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +*******************************************************************************/ + +#include "pcmutils_lib.h" + +#include "genericStds.h" +#include "fixpoint_math.h" + +/* Decoder library info */ +#define PCMDMX_LIB_VL0 2 +#define PCMDMX_LIB_VL1 2 +#define PCMDMX_LIB_VL2 0 +#define PCMDMX_LIB_TITLE "PCM Downmix Lib" +#define PCMDMX_LIB_BUILD_DATE __DATE__ +#define PCMDMX_LIB_BUILD_TIME __TIME__ + +/* Library settings */ +#define PCM_DMX_MAX_DELAY_FRAMES ( 1 ) +#define PCM_DMX_MAX_CHANNELS ( 8 ) +#define PCM_DMX_MAX_CHANNEL_GROUPS ( 4 ) +#define PCM_DMX_MAX_CHANNELS_PER_GROUP ( 3 ) /* The maximum over all groups */ +#define PCMDMX_DFLT_EXPIRY_FRAME ( 40 ) /* At least 400ms (FL 960 @ 96kHz) */ + +/* Fixed and unique channel group indices. + * The last group index has to be smaller than PCM_DMX_MAX_CHANNEL_GROUPS. */ +#define CH_GROUP_FRONT ( 0 ) +#define CH_GROUP_SIDE ( 1 ) +#define CH_GROUP_REAR ( 2 ) +#define CH_GROUP_LFE ( 3 ) + +/* The ordering of the following fixed channel labels has to be in MPEG-4 style. + * From the center to the back with left and right channel interleaved (starting with left). + * The last channel label index has to be smaller than PCM_DMX_MAX_CHANNELS. */ +#define CENTER_FRONT_CHANNEL ( 0 ) /* C */ +#define LEFT_FRONT_CHANNEL ( 1 ) /* L */ +#define RIGHT_FRONT_CHANNEL ( 2 ) /* R */ +#define LEFT_OUTSIDE_CHANNEL ( 3 ) /* Lo */ +#define RIGHT_OUTSIDE_CHANNEL ( 4 ) /* Ro */ +#define LEFT_REAR_CHANNEL ( 5 ) /* Lr aka left back channel */ +#define RIGHT_REAR_CHANNEL ( 6 ) /* Rr aka right back channel */ +#define LOW_FREQUENCY_CHANNEL ( 7 ) /* Lf */ + +/* More constants */ +#define ANC_DATA_SYNC_BYTE ( 0xBC ) /* ancillary data sync byte. */ +#define ATTENUATION_FACTOR_1 ( FL2FXCONST_SGL(0.70710678f) ) +#define TWO_CHANNEL ( 2 ) + +/* Sanity checks on library setting: */ + +/* List of packed channel modes */ +typedef enum +{ /* CH_MODE____ */ + CH_MODE_UNDEFINED = 0x0000, + /* 1 channel */ + CH_MODE_1_0_0_0 = 0x0001, /* chCfg 1 */ + /* 2 channels */ + CH_MODE_2_0_0_0 = 0x0002, /* chCfg 2 */ + /* 3 channels */ + CH_MODE_3_0_0_0 = 0x0003, /* chCfg 3 */ + CH_MODE_2_0_1_0 = 0x0102, + CH_MODE_2_0_0_1 = 0x1002, + /* 4 channels */ + CH_MODE_3_0_1_0 = 0x0103, /* chCfg 4 */ + CH_MODE_2_0_2_0 = 0x0202, + CH_MODE_2_0_1_1 = 0x1102, + /* 5 channels */ + CH_MODE_3_0_2_0 = 0x0203, /* chCfg 5 */ + CH_MODE_2_0_2_1 = 0x1202, + CH_MODE_3_0_1_1 = 0x1103, + CH_MODE_3_2_0_0 = 0x0023, + /* 6 channels */ + CH_MODE_3_0_2_1 = 0x1203, /* chCfg 6 */ + CH_MODE_3_2_1_0 = 0x0123, + /* 7 channels */ + CH_MODE_2_2_2_1 = 0x1222, + CH_MODE_3_2_1_1 = 0x1123, + CH_MODE_3_2_2_0 = 0x0223, + /* 8 channels */ + CH_MODE_3_2_2_1 = 0x1222, /* chCfg 7 */ + CH_MODE_3_2_1_2 = 0x2123, + CH_MODE_2_2_2_2 = 0x2222 + +} PCM_DMX_CHANNEL_MODE; + + +/* These are the channel configurations linked to + the number of output channels give by the user: */ +static const PCM_DMX_CHANNEL_MODE outChModeTable[PCM_DMX_MAX_CHANNELS] = +{ + CH_MODE_1_0_0_0, /* 1 channel */ + CH_MODE_2_0_0_0, /* 2 channels */ + CH_MODE_3_0_0_0, /* 3 channels */ + CH_MODE_3_0_1_0, /* 4 channels */ + CH_MODE_3_0_2_0, /* 5 channels */ + CH_MODE_3_0_2_1, /* 6 channels */ + CH_MODE_3_2_2_0, /* 7 channels */ + CH_MODE_3_2_2_1 /* 8 channels */ +}; + +static const FIXP_SGL dvbDownmixFactors[8] = +{ + FL2FXCONST_SGL(1.0f), + FL2FXCONST_SGL(0.841f), + FL2FXCONST_SGL(0.707f), + FL2FXCONST_SGL(0.596f), + FL2FXCONST_SGL(0.500f), + FL2FXCONST_SGL(0.422f), + FL2FXCONST_SGL(0.355f), + FL2FXCONST_SGL(0.0f) +}; + + + /* MPEG matrix mixdown: + Set 1: L' = (1 + 2^-0.5 + A )^-1 * [L + C * 2^-0.5 + A * Ls]; + R' = (1 + 2^-0.5 + A )^-1 * [R + C * 2^-0.5 + A * Rs]; + + Set 2: L' = (1 + 2^-0.5 + 2A )^-1 * [L + C * 2^-0.5 - A * (Ls + Rs)]; + R' = (1 + 2^-0.5 + 2A )^-1 * [R + C * 2^-0.5 + A * (Ls + Rs)]; + + M = (3 + 2A)^-1 * [L + C + R + A*(Ls + Rs)]; + */ + static const FIXP_SGL mpegMixDownIdx2Coef[4] = + { + FL2FXCONST_SGL(0.70710678f), + FL2FXCONST_SGL(0.5f), + FL2FXCONST_SGL(0.35355339f), + FL2FXCONST_SGL(0.0f) + }; + + static const FIXP_SGL mpegMixDownIdx2PreFact[4] = + { + FL2FXCONST_SGL(0.4142135623730950f), + FL2FXCONST_SGL(0.4530818393219728f), + FL2FXCONST_SGL(0.4852813742385703f), + FL2FXCONST_SGL(0.5857864376269050f) + }; + + typedef struct + { + USHORT matrixMixdownIdx; /*!< MPEG mixdown index extracted from PCE. */ + USHORT pseudoSurroundEnable; /*!< Pseudo surround enable flag extracted from PCE. */ + USHORT mixdownAvailable; /*!< Will be set to 1 if we found a valid coefficient. */ + + } MPEG_MIXDOWN_INFO; + + +typedef struct +{ + FIXP_SGL centerMixLevelValue; /*!< DVB mixdown level for the center channel extracted from anc data. */ + FIXP_SGL surroundMixLevelValue; /*!< DVB mixdown level for back channels extracted from anc data. */ + + UCHAR mixLevelsAvail; /*!< Will be set to 1 if we found a valid coefficient. */ + +} DVB_MIXDOWN_LEVELS; + + +/* Modules main data structure: */ +struct PCM_DMX_INSTANCE +{ + DVB_MIXDOWN_LEVELS dvbMixDownLevels[PCM_DMX_MAX_DELAY_FRAMES+1]; + MPEG_MIXDOWN_INFO mpegMixDownInfo[PCM_DMX_MAX_DELAY_FRAMES+1]; + DUAL_CHANNEL_MODE dualChannelMode; + UINT expiryFrame; + UINT expiryCount; + SHORT numOutputChannels; + UCHAR applyProcessing; + UCHAR frameDelay; +}; + +/* Memory allocation macro */ +C_ALLOC_MEM_STATIC(PcmDmxInstance, struct PCM_DMX_INSTANCE, 1) + + +/** Evaluate a given channel configuration and extract a packed channel mode and generate a channel offset table + * This function is the inverse to the getChannelDescription() routine. + * @param [in] The total number of channels of the given configuration. + * @param [in] Array holding the corresponding channel types for each channel. + * @param [in] Array holding the corresponding channel type indices for each channel. + * @param [in] Array containing the channel mapping to be used (From MPEG PCE ordering to whatever is required). + * @param [out] Array where the buffer offsets for each channel are stored into. + * @returns Returns the packed channel mode. + **/ +static +PCM_DMX_CHANNEL_MODE getChannelMode ( + const INT numChannels, /* in */ + const AUDIO_CHANNEL_TYPE channelType[], /* in */ + const UCHAR channelIndices[], /* in */ + const UCHAR channelMapping[PCM_DMX_MAX_CHANNELS], /* in */ + UCHAR offsetTable[PCM_DMX_MAX_CHANNELS] /* out */ + ) +{ + UINT chMode = CH_MODE_UNDEFINED; + UCHAR chIdx[PCM_DMX_MAX_CHANNEL_GROUPS][PCM_DMX_MAX_CHANNELS_PER_GROUP]; + UCHAR numChInGrp[PCM_DMX_MAX_CHANNEL_GROUPS]; + int ch, grpIdx, err = 0; + + FDK_ASSERT(channelType != NULL); + FDK_ASSERT(channelIndices != NULL); + FDK_ASSERT(channelMapping != NULL); + FDK_ASSERT(offsetTable != NULL); + + /* For details see ISO/IEC 13818-7:2005(E), 8.5.3 Channel configuration */ + FDKmemclear(numChInGrp, PCM_DMX_MAX_CHANNEL_GROUPS*sizeof(UCHAR)); + FDKmemset(offsetTable, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR)); + + /* Categorize channels */ + for (ch = 0; ch < numChannels; ch += 1) { + int i = 0, j, chGrpIdx = channelIndices[ch]; + + switch (channelType[ch]) { + case ACT_FRONT: + case ACT_FRONT_TOP: + grpIdx = CH_GROUP_FRONT; + break; + case ACT_SIDE: + case ACT_SIDE_TOP: + grpIdx = CH_GROUP_SIDE; + break; + case ACT_BACK: + case ACT_BACK_TOP: + grpIdx = CH_GROUP_REAR; + break; + case ACT_LFE: + grpIdx = CH_GROUP_LFE; + break; + default: + err = -1; + continue; + } + + if (numChInGrp[grpIdx] < PCM_DMX_MAX_CHANNELS_PER_GROUP) { + /* Sort channels by index */ + while ( (i < numChInGrp[grpIdx]) && (chGrpIdx > channelIndices[chIdx[grpIdx][i]]) ) { + i += 1; + } + for (j = numChInGrp[grpIdx]; j > i; j -= 1) { + chIdx[grpIdx][j] = chIdx[grpIdx][j-1]; + } + chIdx[grpIdx][i] = ch; + numChInGrp[grpIdx] += 1; + } + } + + /* Compose channel offset table */ + + /* Non-symmetric channels */ + if (numChInGrp[CH_GROUP_FRONT] & 0x1) { + /* Odd number of front channels -> we have a center channel. + In MPEG-4 the center has the index 0. */ + offsetTable[CENTER_FRONT_CHANNEL] = channelMapping[chIdx[CH_GROUP_FRONT][0]]; + } + + for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) { + int chMapPos, maxChannels = 0; + ch = 0; + + switch (grpIdx) { + case CH_GROUP_FRONT: + chMapPos = LEFT_FRONT_CHANNEL; + maxChannels = 3; + ch = numChInGrp[grpIdx] & 0x1; + break; + case CH_GROUP_SIDE: + chMapPos = LEFT_OUTSIDE_CHANNEL; + maxChannels = 2; + break; + case CH_GROUP_REAR: + chMapPos = LEFT_REAR_CHANNEL; + maxChannels = 2; + break; + case CH_GROUP_LFE: + chMapPos = LOW_FREQUENCY_CHANNEL; + maxChannels = 1; + break; + default: + err = -1; + continue; + } + + for ( ; ch < numChInGrp[grpIdx]; ch += 1) { + if (ch < maxChannels) { + offsetTable[chMapPos] = channelMapping[chIdx[grpIdx][ch]]; + chMapPos += 1; + } else { + err = -1; + } + } + } + + if (err == 0) { + /* Compose the channel mode */ + chMode = (numChInGrp[CH_GROUP_LFE] & 0xF) << 12 + | (numChInGrp[CH_GROUP_REAR] & 0xF) << 8 + | (numChInGrp[CH_GROUP_SIDE] & 0xF) << 4 + | (numChInGrp[CH_GROUP_FRONT] & 0xF); + } + + return (PCM_DMX_CHANNEL_MODE)chMode; +} + + +/** Generate a channel offset table and complete channel description for a given (packed) channel mode. + * This function is the inverse to the getChannelMode() routine. + * @param [in] The total number of channels of the given configuration. + * @param [in] Array containing the channel mapping to be used (From MPEG PCE ordering to whatever is required). + * @param [out] Array where corresponding channel types for each channels are stored into. + * @param [out] Array where corresponding channel type indices for each output channel are stored into. + * @param [out] Array where the buffer offsets for each channel are stored into. + * @returns None. + **/ +void getChannelDescription ( + const PCM_DMX_CHANNEL_MODE chMode, /* in */ + const UCHAR channelMapping[][PCM_DMX_MAX_CHANNELS], /* in */ + AUDIO_CHANNEL_TYPE channelType[], /* out */ + UCHAR channelIndices[], /* out */ + UCHAR offsetTable[PCM_DMX_MAX_CHANNELS] /* out */ + ) +{ + const UCHAR *pChannelMap; + int grpIdx, ch = 0, numChannels = 0; + UCHAR numChInGrp[PCM_DMX_MAX_CHANNEL_GROUPS]; + + FDK_ASSERT(channelType != NULL); + FDK_ASSERT(channelIndices != NULL); + FDK_ASSERT(channelMapping != NULL); + FDK_ASSERT(offsetTable != NULL); + + /* Init output arrays */ + FDKmemclear(channelType, PCM_DMX_MAX_CHANNELS*sizeof(AUDIO_CHANNEL_TYPE)); + FDKmemclear(channelIndices, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR)); + FDKmemset(offsetTable, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR)); + + /* Extract the number of channels per group */ + numChInGrp[CH_GROUP_FRONT] = chMode & 0xF; + numChInGrp[CH_GROUP_SIDE] = (chMode >> 4) & 0xF; + numChInGrp[CH_GROUP_REAR] = (chMode >> 8) & 0xF; + numChInGrp[CH_GROUP_LFE] = (chMode >> 12) & 0xF; + + /* Summerize to get the total number of channels */ + for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) { + numChannels += numChInGrp[grpIdx]; + } + + /* Get the appropriate channel map */ + pChannelMap = channelMapping[numChannels-1]; + + /* Compose channel offset table */ + + /* Non-symmetric channels */ + if (numChInGrp[CH_GROUP_FRONT] & 0x1) { + /* Odd number of front channels -> we have a center channel. + In MPEG-4 the center has the index 0. */ + offsetTable[CENTER_FRONT_CHANNEL] = pChannelMap[0]; + channelType[0] = ACT_FRONT; + ch += 1; + } + + for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) { + AUDIO_CHANNEL_TYPE type; + int chMapPos, maxChannels = 0; + int chIdx = 0; + + switch (grpIdx) { + case CH_GROUP_FRONT: + type = ACT_FRONT; + chMapPos = LEFT_FRONT_CHANNEL; + maxChannels = 3; + chIdx = numChInGrp[grpIdx] & 0x1; + break; + case CH_GROUP_SIDE: + type = ACT_SIDE; + chMapPos = LEFT_OUTSIDE_CHANNEL; + maxChannels = 2; + break; + case CH_GROUP_REAR: + type = ACT_BACK; + chMapPos = LEFT_REAR_CHANNEL; + maxChannels = 2; + break; + case CH_GROUP_LFE: + type = ACT_LFE; + chMapPos = LOW_FREQUENCY_CHANNEL; + maxChannels = 1; + break; + default: + break; + } + + for ( ; (chIdx < numChInGrp[grpIdx]) && (chIdx < maxChannels); chIdx += 1) { + offsetTable[chMapPos] = pChannelMap[ch]; + channelType[ch] = type; + channelIndices[ch] = chIdx; + chMapPos += 1; + ch += 1; + } + } +} + + +/** Open and initialize an instance of the PCM downmix module + * @param [out] Pointer to a buffer receiving the handle of the new instance. + * @returns Returns an error code. + **/ +PCMDMX_ERROR pcmDmx_Open ( + HANDLE_PCM_DOWNMIX *pSelf + ) +{ + HANDLE_PCM_DOWNMIX self; + + if (pSelf == NULL) { + return (PCMDMX_INVALID_HANDLE); + } + + *pSelf = NULL; + + self = (HANDLE_PCM_DOWNMIX) GetPcmDmxInstance( 0 ); + if (self == NULL) { + return (PCMDMX_OUT_OF_MEMORY); + } + + /* Reset the full instance */ + pcmDmx_Reset( self, PCMDMX_RESET_FULL ); + + *pSelf = self; + + return (PCMDMX_OK); +} + + +/** Reset all static values like e.g. mixdown coefficients. + * @param [in] Handle of PCM downmix module instance. + * @param [in] Flags telling which parts of the module shall be reset. + * @returns Returns an error code. + **/ +PCMDMX_ERROR pcmDmx_Reset ( + HANDLE_PCM_DOWNMIX self, + UINT flags + ) +{ + if (self == NULL) { return (PCMDMX_INVALID_HANDLE); } + + if (flags & PCMDMX_RESET_PARAMS) { + self->dualChannelMode = STEREO_MODE; + self->numOutputChannels = 0; + self->applyProcessing = 0; + self->frameDelay = 0; + self->expiryFrame = PCMDMX_DFLT_EXPIRY_FRAME; + } + + if (flags & PCMDMX_RESET_BS_DATA) { + int slot; + for (slot = 0; slot <= PCM_DMX_MAX_DELAY_FRAMES; slot += 1) { + self->dvbMixDownLevels[slot].centerMixLevelValue = dvbDownmixFactors[2]; /* 0.707 */ + self->dvbMixDownLevels[slot].surroundMixLevelValue = dvbDownmixFactors[0]; /* 1.000 */ + self->dvbMixDownLevels[slot].mixLevelsAvail = 0; + + self->mpegMixDownInfo[slot].mixdownAvailable = 0; + } + /* Reset expiry counter */ + self->expiryCount = 0; + } + + return (PCMDMX_OK); +} + + +/** Set one parameter for one instance of the PCM downmix module. + * @param [in] Handle of PCM downmix module instance. + * @param [in] Parameter to be set. + * @param [in] Parameter value. + * @returns Returns an error code. + **/ +PCMDMX_ERROR pcmDmx_SetParam ( + HANDLE_PCM_DOWNMIX self, + PCMDMX_PARAM param, + UINT value + ) +{ + switch (param) + { + case DMX_BS_DATA_EXPIRY_FRAME: + if (self == NULL) + return (PCMDMX_INVALID_HANDLE); + self->expiryFrame = value; + break; + + case DMX_BS_DATA_DELAY: + if (value > PCM_DMX_MAX_DELAY_FRAMES) { + return (PCMDMX_UNABLE_TO_SET_PARAM); + } + if (self == NULL) { + return (PCMDMX_INVALID_HANDLE); + } + self->frameDelay = value; + break; + + case NUMBER_OF_OUTPUT_CHANNELS: + switch ((int)value) { /* supported output channels */ + case -1: case 0: case 1: case 2: + case 6: case 8: + break; + default: + return (PCMDMX_UNABLE_TO_SET_PARAM); + } + if (self == NULL) + return (PCMDMX_INVALID_HANDLE); + if ((int)value > 0) { + self->numOutputChannels = (int)value; + self->applyProcessing = 1; + } else { + self->numOutputChannels = 0; + self->applyProcessing = 0; + } + break; + + case DUAL_CHANNEL_DOWNMIX_MODE: + switch ((DUAL_CHANNEL_MODE)value) { + case STEREO_MODE: + case CH1_MODE: + case CH2_MODE: + case MIXED_MODE: + break; + default: + return (PCMDMX_UNABLE_TO_SET_PARAM); + } + if (self == NULL) + return (PCMDMX_INVALID_HANDLE); + self->dualChannelMode = (DUAL_CHANNEL_MODE)value; + self->applyProcessing = 1; + break; + + default: + return (PCMDMX_UNKNOWN_PARAM); + } + + return (PCMDMX_OK); +} + + +/** Read the ancillary data transported in DSEs of DVB streams with MPEG-4 content + * @param [in] Handle of PCM downmix module instance. + * @param [in] Pointer to ancillary data buffer. + * @param [in] Size of ancillary data. + * @param [in] Flag indicating wheter the DVB ancillary data is from an MPEG-1/2 or an MPEG-4 stream. + * @returns Returns an error code. + **/ +PCMDMX_ERROR pcmDmx_ReadDvbAncData ( + HANDLE_PCM_DOWNMIX self, + UCHAR *pAncDataBuf, + UINT ancDataBytes, + int isMpeg2 + ) +{ + DVB_MIXDOWN_LEVELS *pDownmixLevels = &self->dvbMixDownLevels[0]; + + int offset = (isMpeg2) ? 2 : 0; + UCHAR ancDataStatus; + + if (self == NULL) { return (PCMDMX_INVALID_HANDLE); } + + /* sanity checks */ + if (pAncDataBuf == NULL || ancDataBytes < (UCHAR)(3+offset)) { + return (PCMDMX_CORRUPT_ANC_DATA); + } + + /* check sync word */ + if (pAncDataBuf[offset] != ANC_DATA_SYNC_BYTE) { + return (PCMDMX_CORRUPT_ANC_DATA); + } + + offset += 2; + ancDataStatus = pAncDataBuf[offset++]; + + if (isMpeg2) { + /* skip advanced_dynamic_range_control */ + if (ancDataStatus & 0x80) offset += 3; + /* skip dialog_normalization */ + if (ancDataStatus & 0x40) offset += 1; + /* skip reproduction_level */ + if (ancDataStatus & 0x20) offset += 1; + } + else { + /* check reserved bits */ + if (ancDataStatus & 0xE8) { return (PCMDMX_CORRUPT_ANC_DATA); } + } + + /* downmix_levels_MPEGX */ + if (ancDataStatus & 0x10) + { + int foundNewData = 0; + UCHAR downmixData = pAncDataBuf[offset++]; + + if (downmixData & 0x80) { /* center_mix_level_on */ + pDownmixLevels->centerMixLevelValue = + dvbDownmixFactors[(downmixData >> 4) & 0x07]; + foundNewData = 1; + } else { + pDownmixLevels->centerMixLevelValue = dvbDownmixFactors[0]; + if (downmixData & 0x70) { return (PCMDMX_CORRUPT_ANC_DATA); } + } + + if (downmixData & 0x08) { /* surround_mix_level_on */ + pDownmixLevels->surroundMixLevelValue = + dvbDownmixFactors[downmixData & 0x07]; + foundNewData = 1; + } else { + pDownmixLevels->surroundMixLevelValue = dvbDownmixFactors[0]; + if (downmixData & 0x07) { return (PCMDMX_CORRUPT_ANC_DATA); } + } + + pDownmixLevels->mixLevelsAvail = foundNewData; + } + + /* Reset expiry counter */ + self->expiryCount = 0; + + return (PCMDMX_OK); +} + +/** Set the matrix mixdown information extracted from the PCE of an AAC bitstream. + * Note: Call only if matrix_mixdown_idx_present is true. + * @param [in] Handle of PCM downmix module instance. + * @param [in] The 2 bit matrix mixdown index extracted from PCE. + * @param [in] The pseudo surround enable flag extracted from PCE. + * @returns Returns an error code. + **/ +PCMDMX_ERROR pcmDmx_SetMatrixMixdownFromPce ( + HANDLE_PCM_DOWNMIX self, + int matrixMixdownPresent, + int matrixMixdownIdx, + int pseudoSurroundEnable + ) +{ + MPEG_MIXDOWN_INFO *pMpegMixDownInfo; + + if (self == NULL) { + return (PCMDMX_INVALID_HANDLE); + } + + pMpegMixDownInfo = &self->mpegMixDownInfo[0]; + + if (matrixMixdownPresent) { + pMpegMixDownInfo->matrixMixdownIdx = matrixMixdownIdx & 0x03; + pMpegMixDownInfo->pseudoSurroundEnable = pseudoSurroundEnable; + } + + pMpegMixDownInfo->mixdownAvailable = matrixMixdownPresent; + /* Reset expiry counter */ + self->expiryCount = 0; + + return (PCMDMX_OK); +} + + +/** Apply down or up mixing. + * @param [in] Handle of PCM downmix module instance. + * @param [inout] Pointer to time buffer. Depending on interface configuration, the content of pTimeData is ignored, + * and the internal QMF buffer will be used as input data source. Otherwise, the MPEG Surround processing is + * applied to the timesignal pTimeData. For both variants, the resulting MPEG Surround signal is written into pTimeData. + * @param [in] Pointer where the amount of output samples is returned into. + * @param [inout] Pointer where the amount of output channels is returned into. + * @param [in] Flag which indicates if output time data are writtern interleaved or as subsequent blocks. + * @param [inout] Array where the corresponding channel type for each output audio channel is stored into. + * @param [inout] Array where the corresponding channel type index for each output audio channel is stored into. + * @param [in] Array containing the output channel mapping to be used (From MPEG PCE ordering to whatever is required). + * @returns Returns an error code. + **/ +PCMDMX_ERROR pcmDmx_ApplyFrame ( + HANDLE_PCM_DOWNMIX self, + INT_PCM *pPcmBuf, + UINT frameSize, + INT *nChannels, + + int fInterleaved, + AUDIO_CHANNEL_TYPE channelType[], + UCHAR channelIndices[], + const UCHAR channelMapping[][8] + ) +{ + PCMDMX_ERROR errorStatus = PCMDMX_OK; + DUAL_CHANNEL_MODE dualChannelMode; + PCM_DMX_CHANNEL_MODE inChMode; + int numOutChannels; + int numInChannels = *nChannels; + int slot; + UCHAR inOffsetTable[PCM_DMX_MAX_CHANNELS]; + + MPEG_MIXDOWN_INFO mpegMixDownInfo; + DVB_MIXDOWN_LEVELS dvbMixDownLevels; + + if (self == NULL) { return (PCMDMX_INVALID_HANDLE); } + + if ( (self->expiryFrame > 0) + && (++self->expiryCount > self->expiryFrame) ) + { /* The metadata read from bitstream is too old. */ + errorStatus = pcmDmx_Reset(self, PCMDMX_RESET_BS_DATA); + } + + FDKmemcpy(&mpegMixDownInfo, &self->mpegMixDownInfo[self->frameDelay], sizeof(MPEG_MIXDOWN_INFO)); + /* Maintain delay line */ + for (slot = self->frameDelay; slot > 0; slot -= 1) { + FDKmemcpy(&self->mpegMixDownInfo[slot], &self->mpegMixDownInfo[slot-1], sizeof(MPEG_MIXDOWN_INFO)); + } + FDKmemcpy(&dvbMixDownLevels, &self->dvbMixDownLevels[self->frameDelay], sizeof(DVB_MIXDOWN_LEVELS)); + /* Maintain delay line */ + for (slot = self->frameDelay; slot > 0; slot -= 1) { + FDKmemcpy(&self->dvbMixDownLevels[slot], &self->dvbMixDownLevels[slot-1], sizeof(DVB_MIXDOWN_LEVELS)); + } + + if (self->applyProcessing == 0) { return (errorStatus); } + + if (pPcmBuf == NULL) { return (PCMDMX_INVALID_ARGUMENT); } + if (frameSize == 0) { return (PCMDMX_INVALID_ARGUMENT); } + if (numInChannels == 0) { return (PCMDMX_INVALID_ARGUMENT); } + + if (self->numOutputChannels <= 0) { + numOutChannels = numInChannels; + } else { + numOutChannels = self->numOutputChannels; + } + dualChannelMode = self->dualChannelMode; + + /* Analyse input channel configuration and get channel offset + * table that can be accessed with the fixed channel labels. */ + inChMode = getChannelMode( + numInChannels, + channelType, + channelIndices, + channelMapping[numInChannels], + inOffsetTable + ); + if (inChMode == CH_MODE_UNDEFINED) { + /* We don't need to restore because the channel + configuration has not been changed. Just exit. */ + return (PCMDMX_INVALID_CH_CONFIG); + } + + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + if ( numInChannels > numOutChannels ) + { /* Apply downmix */ + INT_PCM *pInCF, *pInLF, *pInRF, *pInLO, *pInRO, *pInLR, *pInRR, *pOutL, *pOutR; + FIXP_SGL flev, clev, slev; + + UINT sample; + int inStride, outStride, offset; + int useGuidedDownMix = 0; + UCHAR outOffsetTable[PCM_DMX_MAX_CHANNELS]; + + /* Set I/O strides and offsets */ + if (fInterleaved) { + inStride = numInChannels; + outStride = TWO_CHANNEL; /* The output of STAGE ONE is always STEREO !!! + STAGE TWO creates a downmix to mono if required. */ + offset = 1; /* Channel specific offset factor */ + } else { + inStride = 1; + outStride = 1; + offset = frameSize; /* Channel specific offset factor */ + } + + /* Get channel description and channel mapping for this + * stages number of output channels (always STEREO). */ + getChannelDescription( + CH_MODE_2_0_0_0, + channelMapping, + channelType, + channelIndices, + outOffsetTable + ); + /* Now there is no way back because we modified the channel configuration! */ + + /* Set channel pointer for input */ + pInCF = &pPcmBuf[inOffsetTable[CENTER_FRONT_CHANNEL]*offset]; + pInLF = &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL]*offset]; + pInRF = &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL]*offset]; + pInLO = &pPcmBuf[inOffsetTable[LEFT_OUTSIDE_CHANNEL]*offset]; + pInRO = &pPcmBuf[inOffsetTable[RIGHT_OUTSIDE_CHANNEL]*offset]; + pInLR = &pPcmBuf[inOffsetTable[LEFT_REAR_CHANNEL]*offset]; + pInRR = &pPcmBuf[inOffsetTable[RIGHT_REAR_CHANNEL]*offset]; + + /* Set channel pointer for output + Caution: Different channel mapping compared to input */ + pOutL = &pPcmBuf[outOffsetTable[LEFT_FRONT_CHANNEL]*offset]; /* LEFT_FRONT_CHANNEL */ + pOutR = &pPcmBuf[outOffsetTable[RIGHT_FRONT_CHANNEL]*offset]; /* RIGHT_FRONT_CHANNEL */ + + /* Set downmix levels: */ + flev = ATTENUATION_FACTOR_1; /* 0.707 */ + clev = ATTENUATION_FACTOR_1; /* 0.707 */ + slev = ATTENUATION_FACTOR_1; /* 0.707 */ + + if ( dvbMixDownLevels.mixLevelsAvail ) { + clev = dvbMixDownLevels.centerMixLevelValue; + slev = dvbMixDownLevels.surroundMixLevelValue; + useGuidedDownMix = 1; + } + + /* FIRST STAGE: + Always downmix to 2 channel output: */ + switch ( inChMode ) + { + case CH_MODE_2_0_0_0: + case CH_MODE_2_0_0_1: + /* 2/0 input: */ + switch (dualChannelMode) + { + case CH1_MODE: /* L' = 0.707 * Ch1; R' = 0.707 * Ch1 */ + for (sample = 0; sample < frameSize; sample++) { + *pOutL = *pOutR = + (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInLF, flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS); + + pInLF += inStride; + pOutL += outStride; pOutR += outStride; + } + break; + + case CH2_MODE: /* L' = 0.707 * Ch2; R' = 0.707 * Ch2 */ + for (sample = 0; sample < frameSize; sample++) { + *pOutL = *pOutR = + (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInRF, flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS); + + pInRF += inStride; + pOutL += outStride; pOutR += outStride; + } + break; + case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2; R' = 0.5*Ch1 + 0.5*Ch2 */ + for (sample = 0; sample < frameSize; sample++) { + *pOutL = *pOutR = (*pInLF >> 1) + (*pInRF >> 1); + + pInLF += inStride; pInRF += inStride; + pOutL += outStride; pOutR += outStride; + } + break; + default: + case STEREO_MODE: + /* nothing to do */ + break; + } + break; + + case CH_MODE_3_0_0_0: + /* 3/0 input: L' = L + 0.707*C; R' = R + 0.707*C; */ + for (sample = 0; sample < frameSize; sample++) + { + FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev); +#if (SAMPLE_BITS == 32) + /* left channel */ + *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>1)+tCF, 1, SAMPLE_BITS); + /* right channel */ + *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>1)+tCF, 1, SAMPLE_BITS); +#else + /* left channel */ + *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>1)+tCF, DFRACT_BITS-SAMPLE_BITS-1, SAMPLE_BITS); + /* right channel */ + *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>1)+tCF, DFRACT_BITS-SAMPLE_BITS-1, SAMPLE_BITS); +#endif + pInLF += inStride; pInRF += inStride; pInCF += inStride; + pOutL += outStride; pOutR += outStride; + } + break; + + /* 2/1 input: not supported! + case CH_MODE_2_0_1_0: */ + + case CH_MODE_3_0_1_0: + if (useGuidedDownMix) { + /* 3/1 input: L' = L + clev*C + 0.707*slev*S; R' = R + clev*C + 0.707*slev*S; */ + slev = FX_DBL2FX_SGL(fMult(flev, slev)); /* 0.707*slef */ + + for (sample = 0; sample < frameSize; sample++) + { + FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev) >> 1; + FIXP_DBL tLR = fMultDiv2((FIXP_PCM)*pInLR, slev) >> 1; +#if (SAMPLE_BITS == 32) + /* left channel */ + *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF+tLR, 2, SAMPLE_BITS); + /* right channel */ + *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tLR, 2, SAMPLE_BITS); +#else + /* left channel */ + *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF-tLR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS); + /* right channel */ + *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tLR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS); +#endif + pInLF += inStride; pInRF += inStride; pInCF += inStride; pInLR += inStride; + pOutL += outStride; pOutR += outStride; + } + } else { + /* 3/1 input: L' = L + 0.707*C - 0.707*S; R' = R + 0.707*C + 0.707*S */ + for (sample = 0; sample < frameSize; sample++) + { + FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev) >> 1; + FIXP_DBL tLR = fMultDiv2((FIXP_PCM)*pInLR, slev) >> 1; +#if (SAMPLE_BITS == 32) + /* left channel */ + *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF-tLR, 2, SAMPLE_BITS); + /* right channel */ + *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tLR, 2, SAMPLE_BITS); +#else + /* left channel */ + *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF-tLR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS); + /* right channel */ + *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tLR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS); +#endif + pInLF += inStride; pInRF += inStride; pInCF += inStride; pInLR += inStride; + pOutL += outStride; pOutR += outStride; + } + } + break; + + /* 2/2 input: not supported! + case CH_MODE_2_0_2_0: */ + + case CH_MODE_3_0_2_0: /* 5.0ch input */ + case CH_MODE_3_0_2_1: /* 5.1ch input */ + if (useGuidedDownMix) { + /* 3/2 input: L' = L + clev*C + slev*Ls; R' = R + clev*C + slev*Rs; */ + for (sample = 0; sample < frameSize; sample++) + { + FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev) >> 1; + FIXP_DBL tLR = fMultDiv2((FIXP_PCM)*pInLR, slev) >> 1; + FIXP_DBL tRR = fMultDiv2((FIXP_PCM)*pInRR, slev) >> 1; +#if (SAMPLE_BITS == 32) + /* left channel */ + *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF+tLR, 2, SAMPLE_BITS); + /* right channel */ + *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tRR, 2, SAMPLE_BITS); +#else + /* left channel */ + *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF+tLR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS); + /* right channel */ + *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tRR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS); +#endif + pInLF += inStride; pInRF += inStride; pInCF += inStride; pInLR += inStride; pInRR += inStride; + pOutL += outStride; pOutR += outStride; + } + } + else if (mpegMixDownInfo.mixdownAvailable) { + /* 3/2 input: L' = (1.707+A)^-1 * [L+0.707*C+A*Ls]; R'= (1.707+A)^-1 * [R+0.707*C+A*Rs]; */ + FIXP_SGL mtrxMixDwnCoef = mpegMixDownIdx2Coef[mpegMixDownInfo.matrixMixdownIdx]; + FIXP_SGL mtrxMixDwnPreFact = mpegMixDownIdx2PreFact[mpegMixDownInfo.matrixMixdownIdx]; + clev = FX_DBL2FX_SGL(fMult(mtrxMixDwnPreFact, flev /* 0.707 */)); + flev = mtrxMixDwnPreFact; + slev = FX_DBL2FX_SGL(fMult(mtrxMixDwnPreFact, mtrxMixDwnCoef)); + + for (sample = 0; sample < frameSize; sample++) + { + FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev); + FIXP_DBL tLF = fMultDiv2((FIXP_PCM)*pInLF, flev); + FIXP_DBL tRF = fMultDiv2((FIXP_PCM)*pInRF, flev); + FIXP_DBL tLR = fMultDiv2((FIXP_PCM)*pInLR, slev); + FIXP_DBL tRR = fMultDiv2((FIXP_PCM)*pInRR, slev); + +#if (SAMPLE_BITS == 32) + /* left channel */ + *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT(tLF+tCF+tLR, 1, SAMPLE_BITS); + /* right channel */ + *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT(tRF+tCF+tRR, 1, SAMPLE_BITS); +#else + /* left channel */ + *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT(tLF+tCF+tLR, DFRACT_BITS-SAMPLE_BITS-1, SAMPLE_BITS); + /* right channel */ + *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT(tRF+tCF+tRR, DFRACT_BITS-SAMPLE_BITS-1, SAMPLE_BITS); +#endif + + pInLF += inStride; pInRF += inStride; pInCF += inStride; pInLR += inStride; pInRR += inStride; + pOutL += outStride; pOutR += outStride; + } + } + else { + /* 3/2 input: L' = L + 0.707*C - 0.707*Ls - 0.707*Rs; R' = R + 0.707*C + 0.707*Ls + 0.707*Rs */ + for (sample = 0; sample < frameSize; sample++) + { + FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev) >> 2; + FIXP_DBL tLR = fMultDiv2((FIXP_PCM)*pInLR, slev) >> 2; + FIXP_DBL tRR = fMultDiv2((FIXP_PCM)*pInRR, slev) >> 2; +#if (SAMPLE_BITS == 32) + /* left channel */ + *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>3)+tCF-tLR-tRR, 3, SAMPLE_BITS); + /* right channel */ + *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>3)+tCF+tLR+tRR, 3, SAMPLE_BITS); +#else + /* left channel */ + *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>3)+tCF-tLR-tRR, DFRACT_BITS-SAMPLE_BITS-3, SAMPLE_BITS); + /* right channel */ + *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>3)+tCF+tLR+tRR, DFRACT_BITS-SAMPLE_BITS-3, SAMPLE_BITS); +#endif + pInLF += inStride; pInRF += inStride; pInCF += inStride; pInLR += inStride; pInRR += inStride; + pOutL += outStride; pOutR += outStride; + } + } + break; + + default: + errorStatus = PCMDMX_INVALID_MODE; + break; + } + + /* SECOND STAGE: + If desired create a mono donwmix: + Note: Input are always two channels! */ + if (numOutChannels == 1) + { + INT_PCM *pOutC; + FIXP_SGL mlev; + + if (useGuidedDownMix) mlev = FL2FXCONST_SGL(1.0f); else mlev = flev; + + /* Output of STAGE ONE = Input of STAGE TWO */ + FDKmemcpy(inOffsetTable, outOffsetTable, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR)); + + /* Set I/O strides and offsets */ + inStride = outStride; /* output from STAGE ONE */ + outStride = numOutChannels; /* final output */ + + /* Get channel description and channel mapping for this + * stages number of output channels (always MONO). */ + getChannelDescription( + CH_MODE_1_0_0_0, + channelMapping, + channelType, + channelIndices, + outOffsetTable + ); + + /* Set input channel pointer. */ + pInLF = &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL]*offset]; + pInRF = &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL]*offset]; + + /* Set output channel pointer */ + pOutC = &pPcmBuf[outOffsetTable[CENTER_FRONT_CHANNEL]*offset]; + + /* C' = 0.707*L + 0.707*R */ + for (sample = 0; sample < frameSize; sample++) { +#if (SAMPLE_BITS == 32) + *pOutC = + (INT_PCM)SATURATE_LEFT_SHIFT(fMultDiv2((FIXP_PCM)*pInLF,mlev)+fMultDiv2((FIXP_PCM)*pInRF,mlev), 1, SAMPLE_BITS); +#else + *pOutC = + (INT_PCM)SATURATE_RIGHT_SHIFT(fMultDiv2((FIXP_PCM)*pInLF,mlev)+fMultDiv2((FIXP_PCM)*pInRF,mlev), DFRACT_BITS-SAMPLE_BITS-1, SAMPLE_BITS); +#endif + + pInLF += inStride; pInRF += inStride; + pOutC += 1; + } + /* Finished STAGE TWO */ + } + + /* Update the number of output channels */ + *nChannels = self->numOutputChannels; + + } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + else + if ( numInChannels == numOutChannels ) + { + /* Don't need to change the channel description here */ + + switch (numInChannels) + { + case 2: + { /* Set up channel pointer */ + INT_PCM *pInLF, *pInRF, *pOutL, *pOutR; + FIXP_SGL flev; + + UINT sample; + int inStride, outStride, offset; + + if (fInterleaved) { + inStride = numInChannels; + outStride = 2; /* fixed !!! (below stereo is donwmixed to mono if required */ + offset = 1; /* Channel specific offset factor */ + } else { + inStride = 1; + outStride = 1; + offset = frameSize; /* Channel specific offset factor */ + } + + /* Set input channel pointer */ + pInLF = &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL]*offset]; + pInRF = &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL]*offset]; + + /* Set output channel pointer (same as input) */ + pOutL = pInLF; + pOutR = pInRF; + + /* Set downmix levels: */ + flev = ATTENUATION_FACTOR_1; /* 0.707 */ + /* 2/0 input: */ + switch (dualChannelMode) + { + case CH1_MODE: /* L' = 0.707 * Ch1; R' = 0.707 * Ch1 */ + for (sample = 0; sample < frameSize; sample++) { + *pOutL = *pOutR = + (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInLF, flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS); + + pInLF += inStride; + pOutL += outStride; pOutR += outStride; + } + break; + case CH2_MODE: /* L' = 0.707 * Ch2; R' = 0.707 * Ch2 */ + for (sample = 0; sample < frameSize; sample++) { + *pOutL = *pOutR = + (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInRF, flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS); + + pInRF += inStride; + pOutL += outStride; pOutR += outStride; + } + break; + case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2; R' = 0.5*Ch1 + 0.5*Ch2 */ + for (sample = 0; sample < frameSize; sample++) { + *pOutL = *pOutR = (*pInLF >> 1) + (*pInRF >> 1); + + pInLF += inStride; pInRF += inStride; + pOutL += outStride; pOutR += outStride; + } + break; + default: + case STEREO_MODE: + /* nothing to do */ + break; + } + } + break; + + default: + /* nothing to do */ + break; + } + } + + return (errorStatus); +} + + +/** Close an instance of the PCM downmix module. + * @param [inout] Pointer to a buffer containing the handle of the instance. + * @returns Returns an error code. + **/ +PCMDMX_ERROR pcmDmx_Close ( + HANDLE_PCM_DOWNMIX *pSelf + ) +{ + if (pSelf == NULL) { + return (PCMDMX_INVALID_HANDLE); + } + + FreePcmDmxInstance( pSelf ); + *pSelf = NULL; + + return (PCMDMX_OK); +} + + +/** Get library info for this module. + * @param [out] Pointer to an allocated LIB_INFO structure. + * @returns Returns an error code. + */ +PCMDMX_ERROR pcmDmx_GetLibInfo( LIB_INFO *info ) +{ + int i; + + if (info == NULL) { + return PCMDMX_INVALID_ARGUMENT; + } + + /* Search for next free tab */ + for (i = 0; i < FDK_MODULE_LAST; i++) { + if (info[i].module_id == FDK_NONE) break; + } + if (i == FDK_MODULE_LAST) { + return PCMDMX_UNKNOWN; + } + info += i; + + /* Add the library info */ + info->module_id = FDK_PCMDMX; + info->version = LIB_VERSION(PCMDMX_LIB_VL0, PCMDMX_LIB_VL1, PCMDMX_LIB_VL2); + LIB_VERSION_STRING(info); + info->build_date = PCMDMX_LIB_BUILD_DATE; + info->build_time = PCMDMX_LIB_BUILD_TIME; + info->title = PCMDMX_LIB_TITLE; + + /* Set flags */ + info->flags = 0 + | CAPF_DMX_BLIND /* At least blind downmixing is possible */ + | CAPF_DMX_PCE /* Guided downmix with data from MPEG-2/4 Program Config Elements (PCE). */ + | CAPF_DMX_DVB /* Guided downmix with data from DVB ancillary data fields. */ + ; + + return PCMDMX_OK; +} + + + diff --git a/libSBRdec/Android.mk b/libSBRdec/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/libSBRdec/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/libSBRdec/include/sbrdecoder.h b/libSBRdec/include/sbrdecoder.h new file mode 100644 index 0000000..00aa997 --- /dev/null +++ b/libSBRdec/include/sbrdecoder.h @@ -0,0 +1,275 @@ +/************************ Fraunhofer IIS SBR decoder library ****************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: SBR decoder front-end prototypes and definitions. + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef __SBRDECODER_H +#define __SBRDECODER_H + +#include "common_fix.h" + +#include "FDK_bitstream.h" +#include "FDK_audio.h" + + +#define SBR_DEBUG_EXTHLP "\ +--- SBR ---\n\ + 0x00000010 Ancillary data and SBR-Header\n\ + 0x00000020 SBR-Side info\n\ + 0x00000040 Decoded SBR-bitstream data, e.g. envelope data\n\ + 0x00000080 SBR-Bitstream statistics\n\ + 0x00000100 Miscellaneous SBR-messages\n\ + 0x00000200 SBR-Energies and gains in the adjustor\n\ + 0x00000400 Fatal SBR errors\n\ + 0x00000800 Transposer coefficients for inverse filtering\n\ +" + +/* Capability flags */ +#define CAPF_SBR_LP 0x00000001 /*!< Flag indicating library's capability of Low Power mode. */ +#define CAPF_SBR_HQ 0x00000002 /*!< Flag indicating library's capability of High Quality mode. */ +#define CAPF_SBR_DRM_BS 0x00000004 /*!< Flag indicating library's capability to decode DRM SBR data. */ +#define CAPF_SBR_CONCEALMENT 0x00000008 /*!< Flag indicating library's capability to conceal erroneous frames. */ +#define CAPF_SBR_DRC 0x00000010 /*!< Flag indicating library's capability for Dynamic Range Control. */ +#define CAPF_SBR_PS_MPEG 0x00000020 /*!< Flag indicating library's capability to do MPEG Parametric Stereo. */ +#define CAPF_SBR_PS_DRM 0x00000040 /*!< Flag indicating library's capability to do DRM Parametric Stereo. */ + +typedef enum +{ + SBRDEC_OK = 0, /*!< All fine. */ + /* SBRDEC_CONCEAL, */ + /* SBRDEC_NOSYNCH, */ + /* SBRDEC_ILLEGAL_PROGRAM, */ + /* SBRDEC_ILLEGAL_TAG, */ + /* SBRDEC_ILLEGAL_CHN_CONFIG, */ + /* SBRDEC_ILLEGAL_SECTION, */ + /* SBRDEC_ILLEGAL_SCFACTORS, */ + /* SBRDEC_ILLEGAL_PULSE_DATA, */ + /* SBRDEC_MAIN_PROFILE_NOT_IMPLEMENTED, */ + /* SBRDEC_GC_NOT_IMPLEMENTED, */ + /* SBRDEC_ILLEGAL_PLUS_ELE_ID, */ + SBRDEC_CREATE_ERROR, /*!< */ + SBRDEC_NOT_INITIALIZED, /*!< */ + SBRDEC_MEM_ALLOC_FAILED, /*!< Memory allocation failed. Probably not enough memory available. */ + SBRDEC_PARSE_ERROR, /*!< */ + SBRDEC_UNSUPPORTED_CONFIG, /*!< */ + SBRDEC_SET_PARAM_FAIL /*!< */ +} SBR_ERROR; + +typedef enum +{ + SBR_SYSTEM_BITSTREAM_DELAY, /*!< System: Switch to enable an additional SBR bitstream delay of one frame. */ + SBR_QMF_MODE, /*!< Set QMF mode, either complex or low power. */ + SBR_LD_QMF_TIME_ALIGN, /*!< Set QMF type, either LD-MPS or CLDFB. Relevant for ELD streams only. */ + SBR_BS_INTERRUPTION /*!< Signal bit stream interruption. Value is ignored. */ +} SBRDEC_PARAM; + +typedef struct SBR_DECODER_INSTANCE *HANDLE_SBRDECODER; + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * \brief Allocates and initializes one SBR decoder instance. + * \param pSelf Pointer to where a SBR decoder handle is copied into. + * \return Error code. + */ +SBR_ERROR sbrDecoder_Open ( HANDLE_SBRDECODER *pSelf ); + +/** + * \brief Initialize a SBR decoder runtime instance. Must be called before decoding starts. + * + * \param self Handle to a SBR decoder instance. + * \param sampleRateIn Input samplerate of the SBR decoder instance. + * \param sampleRateOut Output samplerate of the SBR decoder instance. + * \param samplesPerFrame Number of samples per frames. + * \param coreCodec Audio Object Type (AOT) of the core codec. + * \param elementID Table with MPEG-4 element Ids in canonical order. + * \param forceReset Flag that enforces a complete decoder reset. + * + * \return Error code. + */ +SBR_ERROR sbrDecoder_InitElement ( + HANDLE_SBRDECODER self, + const int sampleRateIn, + const int sampleRateOut, + const int samplesPerFrame, + const AUDIO_OBJECT_TYPE coreCodec, + const MP4_ELEMENT_ID elementID, + const int elementIndex + ); + +/** + * \brief pass out of band SBR header to SBR decoder + * + * \param self Handle to a SBR decoder instance. + * \param hBs bit stream handle data source. + * \param elementID SBR element ID. + * \param elementIndex SBR element index. + * + * \return Error code. + */ +INT sbrDecoder_Header ( + HANDLE_SBRDECODER self, + HANDLE_FDK_BITSTREAM hBs, + const INT sampleRateIn, + const INT sampleRateOut, + const INT samplesPerFrame, + const AUDIO_OBJECT_TYPE coreCodec, + const MP4_ELEMENT_ID elementID, + const INT elementIndex + ); + +/** + * \brief Set a parameter of the SBR decoder runtime instance. + * \param self SBR decoder handle. + * \param param Parameter which will be set if successfull. + * \param value New parameter value. + * \return Error code. + */ +SBR_ERROR sbrDecoder_SetParam ( HANDLE_SBRDECODER self, + const SBRDEC_PARAM param, + const INT value ); + +/** + * \brief Feed DRC channel data into a SBR decoder runtime instance. + * + * \param self SBR decoder handle. + * \param ch Channel number to which the DRC data is associated to. + * \param numBands Number of DRC bands. + * \param pNextFact_mag Pointer to a table with the DRC factor magnitudes. + * \param nextFact_exp Exponent for all DRC factors. + * \param drcInterpolationScheme DRC interpolation scheme. + * \param winSequence Window sequence from core coder (eight short or one long window). + * \param pBandTop Pointer to a table with the top borders for all DRC bands. + * + * \return Error code. + */ +SBR_ERROR sbrDecoder_drcFeedChannel ( HANDLE_SBRDECODER self, + INT ch, + UINT numBands, + FIXP_DBL *pNextFact_mag, + INT nextFact_exp, + SHORT drcInterpolationScheme, + UCHAR winSequence, + USHORT *pBandTop ); + +/** + * \brief Disable SBR DRC for a certain channel. + * + * \param hSbrDecoder SBR decoder handle. + * \param ch Number of the channel that has to be disabled. + * + * \return None. + */ +void sbrDecoder_drcDisable ( HANDLE_SBRDECODER self, + INT ch ); + + +/** + * \brief Parse one SBR element data extension data block. The bit stream position will + * be placed at the end of the SBR payload block. The remaining bits will be returned + * into *count if a payload length is given (byPayLen > 0). If no SBR payload length is + * given (bsPayLen < 0) then the bit stream position on return will be random after this + * function call in case of errors, and any further decoding will be completely pointless. + * + * \param self SBR decoder handle. + * \param hBs Bit stream handle as data source. + * \param count Pointer to an integer where the amount of parsed SBR payload bits is stored into. + * \param bsPayLen If > 0 this value is the SBR payload length. If < 0, the SBR payload length is unknown. + * \param flags CRC flag (0: EXT_SBR_DATA; 1: EXT_SBR_DATA_CRC) + * \param prev_element Previous MPEG-4 element ID. + * \param element_index Index of the current element. + * + * \return Error code. + */ +SBR_ERROR sbrDecoder_Parse ( + HANDLE_SBRDECODER self, + HANDLE_FDK_BITSTREAM hBs, + int *count, + int bsPayLen, + int crcFlag, + MP4_ELEMENT_ID prev_element, + int element_index, + int fGlobalIndependencyFlag + ); + +/** + * \brief This function decodes the given SBR bitstreams and applies SBR to the given time data. + * + * SBR-processing works InPlace. I.e. the calling function has to provide + * a time domain buffer timeData which can hold the completely decoded + * result. + * + * Left and right channel are read and stored according to the + * interleaving flag, frame length and number of channels. + * + * \param self Handle of an open SBR decoder instance. + * \param hSbrBs SBR Bitstream handle. + * \param timeData Pointer to input and finally upsampled output data. + * \param numChannels Pointer to a buffer holding the number of channels in time data buffer. + * \param sampleRate Output samplerate. + * \param channelMapping Channel mapping indices. + * \param interleaved Flag indicating if time data is stored interleaved (1: Interleaved time data, 0: non-interleaved timedata). + * \param coreDecodedOk Flag indicating if the core decoder did not find any error (0: core decoder found errors, 1: no errors). + * \param psDecoded Pointer to a buffer holding a flag. Input: PS is possible, Output: PS has been rendered. + * + * \return Error code. + */ +SBR_ERROR sbrDecoder_Apply ( HANDLE_SBRDECODER self, + INT_PCM *timeData, + int *numChannels, + int *sampleRate, + const UCHAR channelMapping[(6)], + const int interleaved, + const int coreDecodedOk, + UCHAR *psDecoded ); + + +/** + * \brief Close SBR decoder instance and free memory. + * \param self SBR decoder handle. + * \return Error Code. + */ +SBR_ERROR sbrDecoder_Close ( HANDLE_SBRDECODER *self ); + + +/** + * \brief Get SBR decoder library information. + * \param info Pointer to a LIB_INFO struct, where library information is written to. + * \return 0 on success, -1 if invalid handle or if no free element is available to write information to. + */ +INT sbrDecoder_GetLibInfo( LIB_INFO *info ); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libSBRdec/src/Android.mk b/libSBRdec/src/Android.mk new file mode 100644 index 0000000..21162b9 --- /dev/null +++ b/libSBRdec/src/Android.mk @@ -0,0 +1,32 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + env_calc.cpp \ + env_dec.cpp \ + env_extr.cpp \ + huff_dec.cpp \ + lpp_tran.cpp \ + psbitdec.cpp \ + psdec.cpp \ + psdec_hybrid.cpp \ + sbr_crc.cpp \ + sbr_deb.cpp \ + sbr_dec.cpp \ + sbrdec_drc.cpp \ + sbrdec_freq_sca.cpp \ + sbrdecoder.cpp \ + sbr_ram.cpp \ + sbr_rom.cpp + +LOCAL_CFLAGS := -DANDROID + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../../libFDK/include \ + $(LOCAL_PATH)/../../libSYS/include + +LOCAL_MODULE:= libSBRdec + +include $(BUILD_STATIC_LIBRARY) diff --git a/libSBRdec/src/arm/env_calc_arm.cpp b/libSBRdec/src/arm/env_calc_arm.cpp new file mode 100644 index 0000000..8fa3718 --- /dev/null +++ b/libSBRdec/src/arm/env_calc_arm.cpp @@ -0,0 +1,86 @@ +/******************************** Fraunhofer IIS *************************** + + (C) Copyright Fraunhofer IIS (2010) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Arthur Tritthart + Description: (ARM optimised) SBR domain coding + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#ifndef INCLUSION_GUARD_CALC_ENV_ARM +#define INCLUSION_GUARD_CALC_ENV_ARM + + +/*! + \brief Compute maximal value of a complex array (re/im) of a given width + Negative values are temporarily logically or'ed with 0xFFFFFFFF + instead of negating the value, if the sign bit is set. + \param maxVal Preset maximal value + \param reTmp real input signal + \param imTmp imaginary input signal + \return new maximal value +*/ + +#ifdef FUNCTION_FDK_get_maxval +__asm FIXP_DBL FDK_get_maxval (FIXP_DBL maxVal, FIXP_DBL *reTmp, FIXP_DBL *imTmp, int width ) +{ + + /* Register map: + r0 maxVal + r1 reTmp + r2 imTmp + r3 width + r4 real + r5 imag + */ + PUSH {r4-r5} + + MOVS r3, r3, ASR #1 + ADC r3, r3, #0 + BCS FDK_get_maxval_loop_2nd_part + BEQ FDK_get_maxval_loop_end + +FDK_get_maxval_loop + LDR r4, [r1], #4 + LDR r5, [r2], #4 + EOR r4, r4, r4, ASR #31 + EOR r5, r5, r5, ASR #31 + ORR r0, r0, r4 + ORR r0, r0, r5 + +FDK_get_maxval_loop_2nd_part + LDR r4, [r1], #4 + LDR r5, [r2], #4 + EOR r4, r4, r4, ASR #31 + EOR r5, r5, r5, ASR #31 + ORR r0, r0, r4 + ORR r0, r0, r5 + + SUBS r3, r3, #1 + BNE FDK_get_maxval_loop + +FDK_get_maxval_loop_end + POP {r4-r5} + BX lr +} +#endif /* FUNCTION_FDK_get_maxval */ + +#endif /* INCLUSION_GUARD_CALC_ENV_ARM */ diff --git a/libSBRdec/src/arm/lpp_tran_arm.cpp b/libSBRdec/src/arm/lpp_tran_arm.cpp new file mode 100644 index 0000000..789f4db --- /dev/null +++ b/libSBRdec/src/arm/lpp_tran_arm.cpp @@ -0,0 +1,89 @@ +/******************************** Fraunhofer IIS *************************** + + (C) Copyright Fraunhofer IIS (2011) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Arthur Tritthart + Description: (ARM optimised) LPP transposer subroutines + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + + +#if defined(__arm__) + + +#define FUNCTION_LPPTRANSPOSER_func1 + +#ifdef FUNCTION_LPPTRANSPOSER_func1 + +/* Note: This code requires only 43 cycles per iteration instead of 61 on ARM926EJ-S */ +__attribute__ ((noinline)) static void lppTransposer_func1( + FIXP_DBL *lowBandReal, + FIXP_DBL *lowBandImag, + FIXP_DBL **qmfBufferReal, + FIXP_DBL **qmfBufferImag, + int loops, + int hiBand, + int dynamicScale, + int descale, + FIXP_SGL a0r, + FIXP_SGL a0i, + FIXP_SGL a1r, + FIXP_SGL a1i) +{ + + FIXP_DBL real1, real2, imag1, imag2, accu1, accu2; + + real2 = lowBandReal[-2]; + real1 = lowBandReal[-1]; + imag2 = lowBandImag[-2]; + imag1 = lowBandImag[-1]; + for(int i=0; i < loops; i++) + { + accu1 = fMultDiv2( a0r,real1); + accu2 = fMultDiv2( a0i,imag1); + accu1 = fMultAddDiv2(accu1,a1r,real2); + accu2 = fMultAddDiv2(accu2,a1i,imag2); + real2 = fMultDiv2( a1i,real2); + accu1 = accu1 - accu2; + accu1 = accu1 >> dynamicScale; + + accu2 = fMultAddDiv2(real2,a1r,imag2); + real2 = real1; + imag2 = imag1; + accu2 = fMultAddDiv2(accu2,a0i,real1); + real1 = lowBandReal[i]; + accu2 = fMultAddDiv2(accu2,a0r,imag1); + imag1 = lowBandImag[i]; + accu2 = accu2 >> dynamicScale; + + accu1 <<= 1; + accu2 <<= 1; + + qmfBufferReal[i][hiBand] = accu1 + (real1>>descale); + qmfBufferImag[i][hiBand] = accu2 + (imag1>>descale); + } +} +#endif /* #ifdef FUNCTION_LPPTRANSPOSER_func1 */ +#endif /* __arm__ */ + + + diff --git a/libSBRdec/src/env_calc.cpp b/libSBRdec/src/env_calc.cpp new file mode 100644 index 0000000..4d545f4 --- /dev/null +++ b/libSBRdec/src/env_calc.cpp @@ -0,0 +1,2171 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Envelope calculation $Revision: 36841 $ + + The envelope adjustor compares the energies present in the transposed + highband to the reference energies conveyed with the bitstream. + The highband is amplified (sometimes) or attenuated (mostly) to the + desired level. + + The spectral shape of the reference energies can be changed several times per + frame if necessary. Each set of energy values corresponding to a certain range + in time will be called an envelope here. + The bitstream supports several frequency scales and two resolutions. Normally, + one or more QMF-subbands are grouped to one SBR-band. An envelope contains + reference energies for each SBR-band. + In addition to the energy envelopes, noise envelopes are transmitted that + define the ratio of energy which is generated by adding noise instead of + transposing the lowband. The noise envelopes are given in a coarser time + and frequency resolution. + If a signal contains strong tonal components, synthetic sines can be + generated in individual SBR bands. + + An overlap buffer of 6 QMF-timeslots is used to allow a more + flexible alignment of the envelopes in time that is not restricted to the + core codec's frame borders. + Therefore the envelope adjustor has access to the spectral data of the + current frame as well as the last 6 QMF-timeslots of the previous frame. + However, in average only the data of 1 frame is being processed as + the adjustor is called once per frame. + + Depending on the frequency range set in the bitstream, only QMF-subbands between + lowSubband and highSubband are adjusted. + + Scaling of spectral data to maximize SNR (see #QMF_SCALE_FACTOR) as well as a special Mantissa-Exponent format + ( see calculateSbrEnvelope() ) are being used. The main entry point for this modules is calculateSbrEnvelope(). + + \sa sbr_scale.h, #QMF_SCALE_FACTOR, calculateSbrEnvelope(), \ref documentationOverview +*/ + + +#include "env_calc.h" + +#include "sbrdec_freq_sca.h" +#include "env_extr.h" +#include "transcendent.h" +#include "sbr_ram.h" +#include "sbr_rom.h" + +#include "genericStds.h" /* need FDKpow() for debug outputs */ + +#if defined(__arm__) +#include "arm/env_calc_arm.cpp" +#endif + +typedef struct +{ + FIXP_DBL nrgRef[MAX_FREQ_COEFFS]; + FIXP_DBL nrgEst[MAX_FREQ_COEFFS]; + FIXP_DBL nrgGain[MAX_FREQ_COEFFS]; + FIXP_DBL noiseLevel[MAX_FREQ_COEFFS]; + FIXP_DBL nrgSine[MAX_FREQ_COEFFS]; + + SCHAR nrgRef_e[MAX_FREQ_COEFFS]; + SCHAR nrgEst_e[MAX_FREQ_COEFFS]; + SCHAR nrgGain_e[MAX_FREQ_COEFFS]; + SCHAR noiseLevel_e[MAX_FREQ_COEFFS]; + SCHAR nrgSine_e[MAX_FREQ_COEFFS]; +} +ENV_CALC_NRGS; + +/*static*/ void equalizeFiltBufferExp(FIXP_DBL *filtBuffer, + SCHAR *filtBuffer_e, + FIXP_DBL *NrgGain, + SCHAR *NrgGain_e, + int subbands); + +/*static*/ void calcNrgPerSubband(FIXP_DBL **analysBufferReal, + FIXP_DBL **analysBufferImag, + int lowSubband, int highSubband, + int start_pos, int next_pos, + SCHAR frameExp, + FIXP_DBL *nrgEst, + SCHAR *nrgEst_e ); + +/*static*/ void calcNrgPerSfb(FIXP_DBL **analysBufferReal, + FIXP_DBL **analysBufferImag, + int nSfb, + UCHAR *freqBandTable, + int start_pos, int next_pos, + SCHAR input_e, + FIXP_DBL *nrg_est, + SCHAR *nrg_est_e ); + +/*static*/ void calcSubbandGain(FIXP_DBL nrgRef, SCHAR nrgRef_e, ENV_CALC_NRGS* nrgs, int c, + FIXP_DBL tmpNoise, SCHAR tmpNoise_e, + UCHAR sinePresentFlag, + UCHAR sineMapped, + int noNoiseFlag); + +/*static*/ void calcAvgGain(ENV_CALC_NRGS* nrgs, + int lowSubband, + int highSubband, + FIXP_DBL *sumRef_m, + SCHAR *sumRef_e, + FIXP_DBL *ptrAvgGain_m, + SCHAR *ptrAvgGain_e); + +/*static*/ void adjustTimeSlotLC(FIXP_DBL *ptrReal, + ENV_CALC_NRGS* nrgs, + UCHAR *ptrHarmIndex, + int lowSubbands, + int noSubbands, + int scale_change, + int noNoiseFlag, + int *ptrPhaseIndex, + int fCldfb); +/*static*/ void adjustTimeSlotHQ(FIXP_DBL *ptrReal, + FIXP_DBL *ptrImag, + HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, + ENV_CALC_NRGS* nrgs, + int lowSubbands, + int noSubbands, + int scale_change, + FIXP_SGL smooth_ratio, + int noNoiseFlag, + int filtBufferNoiseShift); + + +/*! + \brief Map sine flags from bitstream to QMF bands + + The bitstream carries only 1 sine flag per band and frame. + This function maps every sine flag from the bitstream to a specific QMF subband + and to a specific envelope where the sine shall start. + The result is stored in the vector sineMapped which contains one entry per + QMF subband. The value of an entry specifies the envelope where a sine + shall start. A value of #MAX_ENVELOPES indicates that no sine is present + in the subband. + The missing harmonics flags from the previous frame (harmFlagsPrev) determine + if a sine starts at the beginning of the frame or at the transient position. + Additionally, the flags in harmFlagsPrev are being updated by this function + for the next frame. +*/ +/*static*/ void mapSineFlags(UCHAR *freqBandTable, /*!< Band borders (there's only 1 flag per band) */ + int nSfb, /*!< Number of bands in the table */ + UCHAR *addHarmonics, /*!< vector with 1 flag per sfb */ + int *harmFlagsPrev, /*!< Packed 'addHarmonics' */ + int tranEnv, /*!< Transient position */ + SCHAR *sineMapped) /*!< Resulting vector of sine start positions for each QMF band */ + +{ + int i; + int lowSubband2 = freqBandTable[0]<<1; + int bitcount = 0; + int oldflags = *harmFlagsPrev; + int newflags = 0; + + /* + Format of harmFlagsPrev: + + first word = flags for highest 16 sfb bands in use + second word = flags for next lower 16 sfb bands (if present) + third word = flags for lowest 16 sfb bands (if present) + + Up to MAX_FREQ_COEFFS sfb bands can be flagged for a sign. + The lowest bit of the first word corresponds to the _highest_ sfb band in use. + This is ensures that each flag is mapped to the same QMF band even after a + change of the crossover-frequency. + */ + + + /* Reset the output vector first */ + FDKmemset(sineMapped, MAX_ENVELOPES,MAX_FREQ_COEFFS); /* MAX_ENVELOPES means 'no sine' */ + + freqBandTable += nSfb; + addHarmonics += nSfb-1; + + for (i=nSfb; i!=0; i--) { + int ui = *freqBandTable--; /* Upper limit of the current scale factor band. */ + int li = *freqBandTable; /* Lower limit of the current scale factor band. */ + + if ( *addHarmonics-- ) { /* There is a sine in this band */ + + unsigned int mask = 1 << bitcount; + newflags |= mask; /* Set flag */ + + /* + If there was a sine in the last frame, let it continue from the first envelope on + else start at the transient position. + */ + sineMapped[(ui+li-lowSubband2) >> 1] = ( oldflags & mask ) ? 0 : tranEnv; + } + + if ((++bitcount == 16) || i==1) { + bitcount = 0; + *harmFlagsPrev++ = newflags; + oldflags = *harmFlagsPrev; /* Fetch 16 of the old flags */ + newflags = 0; + } + } +} + + +/*! + \brief Reduce gain-adjustment induced aliasing for real valued filterbank. +*/ +/*static*/ void +aliasingReduction(FIXP_DBL* degreeAlias, /*!< estimated aliasing for each QMF channel */ + ENV_CALC_NRGS* nrgs, + int* useAliasReduction, /*!< synthetic sine engergy for each subband, used as flag */ + int noSubbands) /*!< number of QMF channels to process */ +{ + FIXP_DBL* nrgGain = nrgs->nrgGain; /*!< subband gains to be modified */ + SCHAR* nrgGain_e = nrgs->nrgGain_e; /*!< subband gains to be modified (exponents) */ + FIXP_DBL* nrgEst = nrgs->nrgEst; /*!< subband energy before amplification */ + SCHAR* nrgEst_e = nrgs->nrgEst_e; /*!< subband energy before amplification (exponents) */ + int grouping = 0, index = 0, noGroups, k; + int groupVector[MAX_FREQ_COEFFS]; + + /* Calculate grouping*/ + for (k = 0; k < noSubbands-1; k++ ){ + if ( (degreeAlias[k + 1] != FL2FXCONST_DBL(0.0f)) && useAliasReduction[k] ) { + if(grouping==0){ + groupVector[index++] = k; + grouping = 1; + } + else{ + if(groupVector[index-1] + 3 == k){ + groupVector[index++] = k + 1; + grouping = 0; + } + } + } + else{ + if(grouping){ + if(useAliasReduction[k]) + groupVector[index++] = k + 1; + else + groupVector[index++] = k; + grouping = 0; + } + } + } + + if(grouping){ + groupVector[index++] = noSubbands; + } + noGroups = index >> 1; + + + /*Calculate new gain*/ + for (int group = 0; group < noGroups; group ++) { + FIXP_DBL nrgOrig = FL2FXCONST_DBL(0.0f); /* Original signal energy in current group of bands */ + SCHAR nrgOrig_e = 0; + FIXP_DBL nrgAmp = FL2FXCONST_DBL(0.0f); /* Amplified signal energy in group (using current gains) */ + SCHAR nrgAmp_e = 0; + FIXP_DBL nrgMod = FL2FXCONST_DBL(0.0f); /* Signal energy in group when applying modified gains */ + SCHAR nrgMod_e = 0; + FIXP_DBL groupGain; /* Total energy gain in group */ + SCHAR groupGain_e; + FIXP_DBL compensation; /* Compensation factor for the energy change when applying modified gains */ + SCHAR compensation_e; + + int startGroup = groupVector[2*group]; + int stopGroup = groupVector[2*group+1]; + + /* Calculate total energy in group before and after amplification with current gains: */ + for(k = startGroup; k < stopGroup; k++){ + /* Get original band energy */ + FIXP_DBL tmp = nrgEst[k]; + SCHAR tmp_e = nrgEst_e[k]; + + FDK_add_MantExp(tmp, tmp_e, nrgOrig, nrgOrig_e, &nrgOrig, &nrgOrig_e); + + /* Multiply band energy with current gain */ + tmp = fMult(tmp,nrgGain[k]); + tmp_e = tmp_e + nrgGain_e[k]; + + FDK_add_MantExp(tmp, tmp_e, nrgAmp, nrgAmp_e, &nrgAmp, &nrgAmp_e); + } + + /* Calculate total energy gain in group */ + FDK_divide_MantExp(nrgAmp, nrgAmp_e, + nrgOrig, nrgOrig_e, + &groupGain, &groupGain_e); + + for(k = startGroup; k < stopGroup; k++){ + FIXP_DBL tmp; + SCHAR tmp_e; + + FIXP_DBL alpha = degreeAlias[k]; + if (k < noSubbands - 1) { + if (degreeAlias[k + 1] > alpha) + alpha = degreeAlias[k + 1]; + } + + /* Modify gain depending on the degree of aliasing */ + FDK_add_MantExp( fMult(alpha,groupGain), groupGain_e, + fMult(/*FL2FXCONST_DBL(1.0f)*/ (FIXP_DBL)MAXVAL_DBL - alpha,nrgGain[k]), nrgGain_e[k], + &nrgGain[k], &nrgGain_e[k] ); + + /* Apply modified gain to original energy */ + tmp = fMult(nrgGain[k],nrgEst[k]); + tmp_e = nrgGain_e[k] + nrgEst_e[k]; + + /* Accumulate energy with modified gains applied */ + FDK_add_MantExp( tmp, tmp_e, + nrgMod, nrgMod_e, + &nrgMod, &nrgMod_e ); + } + + /* Calculate compensation factor to retain the energy of the amplified signal */ + FDK_divide_MantExp(nrgAmp, nrgAmp_e, + nrgMod, nrgMod_e, + &compensation, &compensation_e); + + /* Apply compensation factor to all gains of the group */ + for(k = startGroup; k < stopGroup; k++){ + nrgGain[k] = fMult(nrgGain[k],compensation); + nrgGain_e[k] = nrgGain_e[k] + compensation_e; + } + } +} + + + /* Convert headroom bits to exponent */ +#define SCALE2EXP(s) (15-(s)) +#define EXP2SCALE(e) (15-(e)) + +/*! + \brief Apply spectral envelope to subband samples + + This function is called from sbr_dec.cpp in each frame. + + To enhance accuracy and due to the usage of tables for squareroots and + inverse, some calculations are performed with the operands being split + into mantissa and exponent. The variable names in the source code carry + the suffixes _m and _e respectively. The control data + in #hFrameData containts envelope data which is represented by this format but + stored in single words. (See requantizeEnvelopeData() for details). This data + is unpacked within calculateSbrEnvelope() to follow the described suffix convention. + + The actual value (comparable to the corresponding float-variable in the + research-implementation) of a mantissa/exponent-pair can be calculated as + + \f$ value = value\_m * 2^{value\_e} \f$ + + All energies and noise levels decoded from the bitstream suit for an + original signal magnitude of \f$\pm 32768 \f$ rather than \f$ \pm 1\f$. Therefore, + the scale factor hb_scale passed into this function will be converted + to an 'input exponent' (#input_e), which fits the internal representation. + + Before the actual processing, an exponent #adj_e for resulting adjusted + samples is derived from the maximum reference energy. + + Then, for each envelope, the following steps are performed: + + \li Calculate energy in the signal to be adjusted. Depending on the the value of + #interpolFreq (interpolation mode), this is either done seperately + for each QMF-subband or for each SBR-band. + The resulting energies are stored in #nrgEst_m[#MAX_FREQ_COEFFS] (mantissas) + and #nrgEst_e[#MAX_FREQ_COEFFS] (exponents). + \li Calculate gain and noise level for each subband:
+ \f$ gain = \sqrt{ \frac{nrgRef}{nrgEst} \cdot (1 - noiseRatio) } + \hspace{2cm} + noise = \sqrt{ nrgRef \cdot noiseRatio } + \f$
+ where noiseRatio and nrgRef are extracted from the + bitstream and nrgEst is the subband energy before adjustment. + The resulting gains are stored in #nrgGain_m[#MAX_FREQ_COEFFS] + (mantissas) and #nrgGain_e[#MAX_FREQ_COEFFS] (exponents), the noise levels + are stored in #noiseLevel_m[#MAX_FREQ_COEFFS] and #noiseLevel_e[#MAX_FREQ_COEFFS] + (exponents). + The sine levels are stored in #nrgSine_m[#MAX_FREQ_COEFFS] + and #nrgSine_e[#MAX_FREQ_COEFFS]. + \li Noise limiting: The gain for each subband is limited both absolutely + and relatively compared to the total gain over all subbands. + \li Boost gain: Calculate and apply boost factor for each limiter band + in order to compensate for the energy loss imposed by the limiting. + \li Apply gains and add noise: The gains and noise levels are applied + to all timeslots of the current envelope. A short FIR-filter (length 4 + QMF-timeslots) can be used to smooth the sudden change at the envelope borders. + Each complex subband sample of the current timeslot is multiplied by the + smoothed gain, then random noise with the calculated level is added. + + \note + To reduce the stack size, some of the local arrays could be located within + the time output buffer. Of the 512 samples temporarily available there, + about half the size is already used by #SBR_FRAME_DATA. A pointer to the + remaining free memory could be supplied by an additional argument to calculateSbrEnvelope() + in sbr_dec: + + \par + \code + calculateSbrEnvelope (&hSbrDec->sbrScaleFactor, + &hSbrDec->SbrCalculateEnvelope, + hHeaderData, + hFrameData, + QmfBufferReal, + QmfBufferImag, + timeOutPtr + sizeof(SBR_FRAME_DATA)/sizeof(Float) + 1); + \endcode + + \par + Within calculateSbrEnvelope(), some pointers could be defined instead of the arrays + #nrgRef_m, #nrgRef_e, #nrgEst_m, #nrgEst_e, #noiseLevel_m: + + \par + \code + fract* nrgRef_m = timeOutPtr; + SCHAR* nrgRef_e = nrgRef_m + MAX_FREQ_COEFFS; + fract* nrgEst_m = nrgRef_e + MAX_FREQ_COEFFS; + SCHAR* nrgEst_e = nrgEst_m + MAX_FREQ_COEFFS; + fract* noiseLevel_m = nrgEst_e + MAX_FREQ_COEFFS; + \endcode + +
+*/ +void +calculateSbrEnvelope (QMF_SCALE_FACTOR *sbrScaleFactor, /*!< Scaling factors */ + HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, /*!< Handle to struct filled by the create-function */ + HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA hFrameData, /*!< Control data of current frame */ + FIXP_DBL **analysBufferReal, /*!< Real part of subband samples to be processed */ + FIXP_DBL **analysBufferImag, /*!< Imag part of subband samples to be processed */ + const int useLP, + FIXP_DBL *degreeAlias, /*!< Estimated aliasing for each QMF channel */ + const UINT flags, + const int frameErrorFlag + ) +{ + int c, i, j, envNoise = 0; + UCHAR* borders = hFrameData->frameInfo.borders; + + FIXP_SGL *noiseLevels = hFrameData->sbrNoiseFloorLevel; + HANDLE_FREQ_BAND_DATA hFreq = &hHeaderData->freqBandData; + + int lowSubband = hFreq->lowSubband; + int highSubband = hFreq->highSubband; + int noSubbands = highSubband - lowSubband; + + int noNoiseBands = hFreq->nNfb; + int no_cols = hHeaderData->numberTimeSlots * hHeaderData->timeStep; + UCHAR first_start = borders[0] * hHeaderData->timeStep; + + SCHAR sineMapped[MAX_FREQ_COEFFS]; + SCHAR ov_adj_e = SCALE2EXP(sbrScaleFactor->ov_hb_scale); + SCHAR adj_e = 0; + SCHAR output_e; + SCHAR final_e = 0; + + SCHAR maxGainLimit_e = (frameErrorFlag) ? MAX_GAIN_CONCEAL_EXP : MAX_GAIN_EXP; + + int useAliasReduction[64]; + UCHAR smooth_length = 0; + + FIXP_SGL * pIenv = hFrameData->iEnvelope; + + /* + Extract sine flags for all QMF bands + */ + mapSineFlags(hFreq->freqBandTable[1], + hFreq->nSfb[1], + hFrameData->addHarmonics, + h_sbr_cal_env->harmFlagsPrev, + hFrameData->frameInfo.tranEnv, + sineMapped); + + + /* + Scan for maximum in bufferd noise levels. + This is needed in case that we had strong noise in the previous frame + which is smoothed into the current frame. + The resulting exponent is used as start value for the maximum search + in reference energies + */ + if (!useLP) + adj_e = h_sbr_cal_env->filtBufferNoise_e - getScalefactor(h_sbr_cal_env->filtBufferNoise, noSubbands); + + /* + Scan for maximum reference energy to be able + to select appropriate values for adj_e and final_e. + */ + + for (i = 0; i < hFrameData->frameInfo.nEnvelopes; i++) { + INT maxSfbNrg_e = -FRACT_BITS+NRG_EXP_OFFSET; /* start value for maximum search */ + + /* Fetch frequency resolution for current envelope: */ + for (j=hFreq->nSfb[hFrameData->frameInfo.freqRes[i]]; j!=0; j--) { + maxSfbNrg_e = fixMax(maxSfbNrg_e,(INT)((LONG)(*pIenv++) & MASK_E)); + } + maxSfbNrg_e -= NRG_EXP_OFFSET; + + /* Energy -> magnitude (sqrt halfens exponent) */ + maxSfbNrg_e = (maxSfbNrg_e+1) >> 1; /* +1 to go safe (round to next higher int) */ + + /* Some safety margin is needed for 2 reasons: + - The signal energy is not equally spread over all subband samples in + a specific sfb of an envelope (Nrg could be too high by a factor of + envWidth * sfbWidth) + - Smoothing can smear high gains of the previous envelope into the current + */ + maxSfbNrg_e += 6; + + if (borders[i] < hHeaderData->numberTimeSlots) + /* This envelope affects timeslots that belong to the output frame */ + adj_e = (maxSfbNrg_e > adj_e) ? maxSfbNrg_e : adj_e; + + if (borders[i+1] > hHeaderData->numberTimeSlots) + /* This envelope affects timeslots after the output frame */ + final_e = (maxSfbNrg_e > final_e) ? maxSfbNrg_e : final_e; + + } + + /* + Calculate adjustment factors and apply them for every envelope. + */ + pIenv = hFrameData->iEnvelope; + + for (i = 0; i < hFrameData->frameInfo.nEnvelopes; i++) { + + int k, noNoiseFlag; + SCHAR noise_e, input_e = SCALE2EXP(sbrScaleFactor->hb_scale); + C_ALLOC_SCRATCH_START(pNrgs, ENV_CALC_NRGS, 1); + + /* + Helper variables. + */ + UCHAR start_pos = hHeaderData->timeStep * borders[i]; /* Start-position in time (subband sample) for current envelope. */ + UCHAR stop_pos = hHeaderData->timeStep * borders[i+1]; /* Stop-position in time (subband sample) for current envelope. */ + UCHAR freq_res = hFrameData->frameInfo.freqRes[i]; /* Frequency resolution for current envelope. */ + + + /* Always do fully initialize the temporary energy table. This prevents negative energies and extreme gain factors in + cases where the number of limiter bands exceeds the number of subbands. The latter can be caused by undetected bit + errors and is tested by some streams from the certification set. */ + FDKmemclear(pNrgs, sizeof(ENV_CALC_NRGS)); + + /* If the start-pos of the current envelope equals the stop pos of the current + noise envelope, increase the pointer (i.e. choose the next noise-floor).*/ + if (borders[i] == hFrameData->frameInfo.bordersNoise[envNoise+1]){ + noiseLevels += noNoiseBands; /* The noise floor data is stored in a row [noiseFloor1 noiseFloor2...].*/ + envNoise++; + } + + if(i==hFrameData->frameInfo.tranEnv || i==h_sbr_cal_env->prevTranEnv) /* attack */ + { + noNoiseFlag = 1; + if (!useLP) + smooth_length = 0; /* No smoothing on attacks! */ + } + else { + noNoiseFlag = 0; + if (!useLP) + smooth_length = (1 - hHeaderData->bs_data.smoothingLength) << 2; /* can become either 0 or 4 */ + } + + + /* + Energy estimation in transposed highband. + */ + if (hHeaderData->bs_data.interpolFreq) + calcNrgPerSubband(analysBufferReal, + (useLP) ? NULL : analysBufferImag, + lowSubband, highSubband, + start_pos, stop_pos, + input_e, + pNrgs->nrgEst, + pNrgs->nrgEst_e); + else + calcNrgPerSfb(analysBufferReal, + (useLP) ? NULL : analysBufferImag, + hFreq->nSfb[freq_res], + hFreq->freqBandTable[freq_res], + start_pos, stop_pos, + input_e, + pNrgs->nrgEst, + pNrgs->nrgEst_e); + + /* + Calculate subband gains + */ + { + UCHAR * table = hFreq->freqBandTable[freq_res]; + UCHAR * pUiNoise = &hFreq->freqBandTableNoise[1]; /*! Upper limit of the current noise floor band. */ + + FIXP_SGL * pNoiseLevels = noiseLevels; + + FIXP_DBL tmpNoise = FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pNoiseLevels) & MASK_M)); + SCHAR tmpNoise_e = (UCHAR)((LONG)(*pNoiseLevels++) & MASK_E) - NOISE_EXP_OFFSET; + + int cc = 0; + c = 0; + for (j = 0; j < hFreq->nSfb[freq_res]; j++) { + + FIXP_DBL refNrg = FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pIenv) & MASK_M)); + SCHAR refNrg_e = (SCHAR)((LONG)(*pIenv) & MASK_E) - NRG_EXP_OFFSET; + + UCHAR sinePresentFlag = 0; + int li = table[j]; + int ui = table[j+1]; + + for (k=li; k= sineMapped[cc]); + cc++; + } + + for (k=li; k= *pUiNoise) { + tmpNoise = FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pNoiseLevels) & MASK_M)); + tmpNoise_e = (SCHAR)((LONG)(*pNoiseLevels++) & MASK_E) - NOISE_EXP_OFFSET; + + pUiNoise++; + } + + FDK_ASSERT(k >= lowSubband); + + if (useLP) + useAliasReduction[k-lowSubband] = !sinePresentFlag; + + pNrgs->nrgSine[c] = FL2FXCONST_DBL(0.0f); + pNrgs->nrgSine_e[c] = 0; + + calcSubbandGain(refNrg, refNrg_e, pNrgs, c, + tmpNoise, tmpNoise_e, + sinePresentFlag, i >= sineMapped[c], + noNoiseFlag); + + pNrgs->nrgRef[c] = refNrg; + pNrgs->nrgRef_e[c] = refNrg_e; + + c++; + } + pIenv++; + } + } + + /* + Noise limiting + */ + + for (c = 0; c < hFreq->noLimiterBands; c++) { + + FIXP_DBL sumRef, boostGain, maxGain; + FIXP_DBL accu = FL2FXCONST_DBL(0.0f); + SCHAR sumRef_e, boostGain_e, maxGain_e, accu_e = 0; + + calcAvgGain(pNrgs, + hFreq->limiterBandTable[c], hFreq->limiterBandTable[c+1], + &sumRef, &sumRef_e, + &maxGain, &maxGain_e); + + /* Multiply maxGain with limiterGain: */ + maxGain = fMult(maxGain, FDK_sbrDecoder_sbr_limGains_m[hHeaderData->bs_data.limiterGains]); + maxGain_e += FDK_sbrDecoder_sbr_limGains_e[hHeaderData->bs_data.limiterGains]; + + /* Scale mantissa of MaxGain into range between 0.5 and 1: */ + if (maxGain == FL2FXCONST_DBL(0.0f)) + maxGain_e = -FRACT_BITS; + else { + SCHAR charTemp = CountLeadingBits(maxGain); + maxGain_e -= charTemp; + maxGain <<= (int)charTemp; + } + + if (maxGain_e >= maxGainLimit_e) { /* upper limit (e.g. 96 dB) */ + maxGain = FL2FXCONST_DBL(0.5f); + maxGain_e = maxGainLimit_e; + } + + + /* Every subband gain is compared to the scaled "average gain" + and limited if necessary: */ + for (k = hFreq->limiterBandTable[c]; k < hFreq->limiterBandTable[c+1]; k++) { + if ( (pNrgs->nrgGain_e[k] > maxGain_e) || (pNrgs->nrgGain_e[k] == maxGain_e && pNrgs->nrgGain[k]>maxGain) ) { + + FIXP_DBL noiseAmp; + SCHAR noiseAmp_e; + + FDK_divide_MantExp(maxGain, maxGain_e, pNrgs->nrgGain[k], pNrgs->nrgGain_e[k], &noiseAmp, &noiseAmp_e); + pNrgs->noiseLevel[k] = fMult(pNrgs->noiseLevel[k],noiseAmp); + pNrgs->noiseLevel_e[k] += noiseAmp_e; + pNrgs->nrgGain[k] = maxGain; + pNrgs->nrgGain_e[k] = maxGain_e; + } + } + + /* -- Boost gain + Calculate and apply boost factor for each limiter band: + 1. Check how much energy would be present when using the limited gain + 2. Calculate boost factor by comparison with reference energy + 3. Apply boost factor to compensate for the energy loss due to limiting + */ + for (k = hFreq->limiterBandTable[c]; k < hFreq->limiterBandTable[c + 1]; k++) { + + /* 1.a Add energy of adjusted signal (using preliminary gain) */ + FIXP_DBL tmp = fMult(pNrgs->nrgGain[k],pNrgs->nrgEst[k]); + SCHAR tmp_e = pNrgs->nrgGain_e[k] + pNrgs->nrgEst_e[k]; + FDK_add_MantExp(tmp, tmp_e, accu, accu_e, &accu, &accu_e); + + /* 1.b Add sine energy (if present) */ + if(pNrgs->nrgSine[k] != FL2FXCONST_DBL(0.0f)) { + FDK_add_MantExp(pNrgs->nrgSine[k], pNrgs->nrgSine_e[k], accu, accu_e, &accu, &accu_e); + } + else { + /* 1.c Add noise energy (if present) */ + if(noNoiseFlag == 0) { + FDK_add_MantExp(pNrgs->noiseLevel[k], pNrgs->noiseLevel_e[k], accu, accu_e, &accu, &accu_e); + } + } + } + + /* 2.a Calculate ratio of wanted energy and accumulated energy */ + if (accu == (FIXP_DBL)0) { /* If divisor is 0, limit quotient to +4 dB */ + boostGain = FL2FXCONST_DBL(0.6279716f); + boostGain_e = 2; + } else { + INT div_e; + boostGain = fDivNorm(sumRef, accu, &div_e); + boostGain_e = sumRef_e - accu_e + div_e; + } + + + /* 2.b Result too high? --> Limit the boost factor to +4 dB */ + if((boostGain_e > 3) || + (boostGain_e == 2 && boostGain > FL2FXCONST_DBL(0.6279716f)) || + (boostGain_e == 3 && boostGain > FL2FXCONST_DBL(0.3139858f)) ) + { + boostGain = FL2FXCONST_DBL(0.6279716f); + boostGain_e = 2; + } + /* 3. Multiply all signal components with the boost factor */ + for (k = hFreq->limiterBandTable[c]; k < hFreq->limiterBandTable[c + 1]; k++) { + pNrgs->nrgGain[k] = fMultDiv2(pNrgs->nrgGain[k],boostGain); + pNrgs->nrgGain_e[k] = pNrgs->nrgGain_e[k] + boostGain_e + 1; + + pNrgs->nrgSine[k] = fMultDiv2(pNrgs->nrgSine[k],boostGain); + pNrgs->nrgSine_e[k] = pNrgs->nrgSine_e[k] + boostGain_e + 1; + + pNrgs->noiseLevel[k] = fMultDiv2(pNrgs->noiseLevel[k],boostGain); + pNrgs->noiseLevel_e[k] = pNrgs->noiseLevel_e[k] + boostGain_e + 1; + } + } + /* End of noise limiting */ + + if (useLP) + aliasingReduction(degreeAlias+lowSubband, + pNrgs, + useAliasReduction, + noSubbands); + + /* For the timeslots within the range for the output frame, + use the same scale for the noise levels. + Drawback: If the envelope exceeds the frame border, the noise levels + will have to be rescaled later to fit final_e of + the gain-values. + */ + noise_e = (start_pos < no_cols) ? adj_e : final_e; + + /* + Convert energies to amplitude levels + */ + for (k=0; knrgSine[k], &pNrgs->nrgSine_e[k], &noise_e); + FDK_sqrt_MantExp(&pNrgs->nrgGain[k], &pNrgs->nrgGain_e[k], &pNrgs->nrgGain_e[k]); + FDK_sqrt_MantExp(&pNrgs->noiseLevel[k], &pNrgs->noiseLevel_e[k], &noise_e); + } + + + + /* + Apply calculated gains and adaptive noise + */ + + /* assembleHfSignals() */ + { + int scale_change, sc_change; + FIXP_SGL smooth_ratio; + int filtBufferNoiseShift=0; + + /* Initialize smoothing buffers with the first valid values */ + if (h_sbr_cal_env->startUp) + { + if (!useLP) { + h_sbr_cal_env->filtBufferNoise_e = noise_e; + + FDKmemcpy(h_sbr_cal_env->filtBuffer_e, pNrgs->nrgGain_e, noSubbands*sizeof(SCHAR)); + FDKmemcpy(h_sbr_cal_env->filtBufferNoise, pNrgs->noiseLevel, noSubbands*sizeof(FIXP_DBL)); + FDKmemcpy(h_sbr_cal_env->filtBuffer, pNrgs->nrgGain, noSubbands*sizeof(FIXP_DBL)); + + } + h_sbr_cal_env->startUp = 0; + } + + if (!useLP) { + + equalizeFiltBufferExp(h_sbr_cal_env->filtBuffer, /* buffered */ + h_sbr_cal_env->filtBuffer_e, /* buffered */ + pNrgs->nrgGain, /* current */ + pNrgs->nrgGain_e, /* current */ + noSubbands); + + /* Adapt exponent of buffered noise levels to the current exponent + so they can easily be smoothed */ + if((h_sbr_cal_env->filtBufferNoise_e - noise_e)>=0) { + int shift = fixMin(DFRACT_BITS-1,(int)(h_sbr_cal_env->filtBufferNoise_e - noise_e)); + for (k=0; kfiltBufferNoise[k] <<= shift; + } + else { + int shift = fixMin(DFRACT_BITS-1,-(int)(h_sbr_cal_env->filtBufferNoise_e - noise_e)); + for (k=0; kfiltBufferNoise[k] >>= shift; + } + + h_sbr_cal_env->filtBufferNoise_e = noise_e; + } + + /* find best scaling! */ + scale_change = -(DFRACT_BITS-1); + for(k=0;knrgGain_e[k]); + } + sc_change = (start_posnrgGain_e[k] + (sc_change-1); + pNrgs->nrgGain[k] >>= sc; + pNrgs->nrgGain_e[k] += sc; + } + + if (!useLP) { + for(k=0;kfiltBuffer_e[k] + (sc_change-1); + h_sbr_cal_env->filtBuffer[k] >>= sc; + } + } + + for (j = start_pos; j < stop_pos; j++) + { + /* This timeslot is located within the first part of the processing buffer + and will be fed into the QMF-synthesis for the current frame. + adj_e - input_e + This timeslot will not yet be fed into the QMF so we do not care + about the adj_e. + sc_change = final_e - input_e + */ + if ( (j==no_cols) && (start_posfiltBufferNoise[k] will be applied in function adjustTimeSlotHQ() */ + if (shift>=0) { + shift = fixMin(DFRACT_BITS-1,shift); + for (k=0; knrgSine[k] <<= shift; + pNrgs->noiseLevel[k] <<= shift; + /* + if (!useLP) + h_sbr_cal_env->filtBufferNoise[k] <<= shift; + */ + } + } + else { + shift = fixMin(DFRACT_BITS-1,-shift); + for (k=0; knrgSine[k] >>= shift; + pNrgs->noiseLevel[k] >>= shift; + /* + if (!useLP) + h_sbr_cal_env->filtBufferNoise[k] >>= shift; + */ + } + } + + /* update noise scaling */ + noise_e = final_e; + if (!useLP) + h_sbr_cal_env->filtBufferNoise_e = noise_e; /* scaling value unused! */ + + /* update gain buffer*/ + sc_change -= (final_e - input_e); + + if (sc_change<0) { + for(k=0;knrgGain[k] >>= -sc_change; + pNrgs->nrgGain_e[k] += -sc_change; + } + if (!useLP) { + for(k=0;kfiltBuffer[k] >>= -sc_change; + } + } + } else { + scale_change+=sc_change; + } + + } // if + + if (!useLP) { + + /* Prevent the smoothing filter from running on constant levels */ + if (j-start_pos < smooth_length) + smooth_ratio = FDK_sbrDecoder_sbr_smoothFilter[j-start_pos]; + + else + smooth_ratio = FL2FXCONST_SGL(0.0f); + + adjustTimeSlotHQ(&analysBufferReal[j][lowSubband], + &analysBufferImag[j][lowSubband], + h_sbr_cal_env, + pNrgs, + lowSubband, + noSubbands, + scale_change, + smooth_ratio, + noNoiseFlag, + filtBufferNoiseShift); + } + else + { + adjustTimeSlotLC(&analysBufferReal[j][lowSubband], + pNrgs, + &h_sbr_cal_env->harmIndex, + lowSubband, + noSubbands, + scale_change, + noNoiseFlag, + &h_sbr_cal_env->phaseIndex, + (flags & SBRDEC_ELD_GRID)); + } + } // for + + if (!useLP) { + /* Update time-smoothing-buffers for gains and noise levels + The gains and the noise values of the current envelope are copied into the buffer. + This has to be done at the end of each envelope as the values are required for + a smooth transition to the next envelope. */ + FDKmemcpy(h_sbr_cal_env->filtBuffer, pNrgs->nrgGain, noSubbands*sizeof(FIXP_DBL)); + FDKmemcpy(h_sbr_cal_env->filtBuffer_e, pNrgs->nrgGain_e, noSubbands*sizeof(SCHAR)); + FDKmemcpy(h_sbr_cal_env->filtBufferNoise, pNrgs->noiseLevel, noSubbands*sizeof(FIXP_DBL)); + } + + } + C_ALLOC_SCRATCH_END(pNrgs, ENV_CALC_NRGS, 1); + } + + /* Rescale output samples */ + { + FIXP_DBL maxVal; + int ov_reserve, reserve; + + /* Determine headroom in old adjusted samples */ + maxVal = maxSubbandSample( analysBufferReal, + (useLP) ? NULL : analysBufferImag, + lowSubband, + highSubband, + 0, + first_start); + + ov_reserve = fNorm(maxVal); + + /* Determine headroom in new adjusted samples */ + maxVal = maxSubbandSample( analysBufferReal, + (useLP) ? NULL : analysBufferImag, + lowSubband, + highSubband, + first_start, + no_cols); + + reserve = fNorm(maxVal); + + /* Determine common output exponent */ + if (ov_adj_e - ov_reserve > adj_e - reserve ) /* set output_e to the maximum */ + output_e = ov_adj_e - ov_reserve; + else + output_e = adj_e - reserve; + + /* Rescale old samples */ + rescaleSubbandSamples( analysBufferReal, + (useLP) ? NULL : analysBufferImag, + lowSubband, highSubband, + 0, first_start, + ov_adj_e - output_e); + + /* Rescale new samples */ + rescaleSubbandSamples( analysBufferReal, + (useLP) ? NULL : analysBufferImag, + lowSubband, highSubband, + first_start, no_cols, + adj_e - output_e); + } + + /* Update hb_scale */ + sbrScaleFactor->hb_scale = EXP2SCALE(output_e); + + /* Save the current final exponent for the next frame: */ + sbrScaleFactor->ov_hb_scale = EXP2SCALE(final_e); + + + /* We need to remeber to the next frame that the transient + will occur in the first envelope (if tranEnv == nEnvelopes). */ + if(hFrameData->frameInfo.tranEnv == hFrameData->frameInfo.nEnvelopes) + h_sbr_cal_env->prevTranEnv = 0; + else + h_sbr_cal_env->prevTranEnv = -1; + +} + + +/*! + \brief Create envelope instance + + Must be called once for each channel before calculateSbrEnvelope() can be used. + + \return errorCode, 0 if successful +*/ +SBR_ERROR +createSbrEnvelopeCalc (HANDLE_SBR_CALCULATE_ENVELOPE hs, /*!< pointer to envelope instance */ + HANDLE_SBR_HEADER_DATA hHeaderData, /*!< static SBR control data, initialized with defaults */ + const int chan, /*!< Channel for which to assign buffers */ + const UINT flags) +{ + SBR_ERROR err = SBRDEC_OK; + int i; + + /* Clear previous missing harmonics flags */ + for (i=0; i<(MAX_FREQ_COEFFS+15)>>4; i++) { + hs->harmFlagsPrev[i] = 0; + } + hs->harmIndex = 0; + + /* + Setup pointers for time smoothing. + The buffer itself will be initialized later triggered by the startUp-flag. + */ + hs->prevTranEnv = -1; + + + /* initialization */ + resetSbrEnvelopeCalc(hs); + + if (chan==0) { /* do this only once */ + err = resetFreqBandTables(hHeaderData, flags); + } + + return err; +} + +/*! + \brief Create envelope instance + + Must be called once for each channel before calculateSbrEnvelope() can be used. + + \return errorCode, 0 if successful +*/ +int +deleteSbrEnvelopeCalc (HANDLE_SBR_CALCULATE_ENVELOPE hs) +{ + return 0; +} + + +/*! + \brief Reset envelope instance + + This function must be called for each channel on a change of configuration. + Note that resetFreqBandTables should also be called in this case. + + \return errorCode, 0 if successful +*/ +void +resetSbrEnvelopeCalc (HANDLE_SBR_CALCULATE_ENVELOPE hCalEnv) /*!< pointer to envelope instance */ +{ + hCalEnv->phaseIndex = 0; + + /* Noise exponent needs to be reset because the output exponent for the next frame depends on it */ + hCalEnv->filtBufferNoise_e = 0; + + hCalEnv->startUp = 1; +} + + +/*! + \brief Equalize exponents of the buffered gain values and the new ones + + After equalization of exponents, the FIR-filter addition for smoothing + can be performed. + This function is called once for each envelope before adjusting. +*/ +/*static*/ void equalizeFiltBufferExp(FIXP_DBL *filtBuffer, /*!< bufferd gains */ + SCHAR *filtBuffer_e, /*!< exponents of bufferd gains */ + FIXP_DBL *nrgGain, /*!< gains for current envelope */ + SCHAR *nrgGain_e, /*!< exponents of gains for current envelope */ + int subbands) /*!< Number of QMF subbands */ +{ + int band; + int diff; + + for (band=0; band0) { + filtBuffer[band] >>= diff; /* Compensate for the scale change by shifting the mantissa. */ + filtBuffer_e[band] += diff; /* New gain is bigger, use its exponent */ + } + else if (diff<0) { + /* The buffered gains seem to be larger, but maybe there + are some unused bits left in the mantissa */ + + int reserve = CntLeadingZeros(fixp_abs(filtBuffer[band]))-1; + + if ((-diff) <= reserve) { + /* There is enough space in the buffered mantissa so + that we can take the new exponent as common. + */ + filtBuffer[band] <<= (-diff); + filtBuffer_e[band] += diff; /* becomes equal to *ptrNewExp */ + } + else { + filtBuffer[band] <<= reserve; /* Shift the mantissa as far as possible: */ + filtBuffer_e[band] -= reserve; /* Compensate in the exponent: */ + + /* For the remaining difference, change the new gain value */ + diff = fixMin(-(reserve + diff),DFRACT_BITS-1); + nrgGain[band] >>= diff; + nrgGain_e[band] += diff; + } + } + } +} + +/*! + \brief Shift left the mantissas of all subband samples + in the giventime and frequency range by the specified number of bits. + + This function is used to rescale the audio data in the overlap buffer + which has already been envelope adjusted with the last frame. +*/ +void rescaleSubbandSamples(FIXP_DBL ** re, /*!< Real part of input and output subband samples */ + FIXP_DBL ** im, /*!< Imaginary part of input and output subband samples */ + int lowSubband, /*!< Begin of frequency range to process */ + int highSubband, /*!< End of frequency range to process */ + int start_pos, /*!< Begin of time rage (QMF-timeslot) */ + int next_pos, /*!< End of time rage (QMF-timeslot) */ + int shift) /*!< number of bits to shift */ +{ + int width = highSubband-lowSubband; + + if ( (width > 0) && (shift!=0) ) { + if (im!=NULL) { + for (int l=start_pos; l 0 ) { + if (im!=NULL) + { + for (int l=start_pos; l>(DFRACT_BITS-1))); + maxVal |= (FIXP_DBL)((LONG)(tmp2)^((LONG)tmp2>>(DFRACT_BITS-1))); + } while(--k!=0); +#endif + } + } else + { + for (int l=start_pos; l>(DFRACT_BITS-1))); + }while(--k!=0); + } + } + } + + return(maxVal); +} + +#define SHIFT_BEFORE_SQUARE (3) /* (7/2) */ +/*!< + If the accumulator does not provide enough overflow bits or + does not provide a high dynamic range, the below energy calculation + requires an additional shift operation for each sample. + On the other hand, doing the shift allows using a single-precision + multiplication for the square (at least 16bit x 16bit). + For even values of OVRFLW_BITS (0, 2, 4, 6), saturated arithmetic + is required for the energy accumulation. + Theoretically, the sample-squares can sum up to a value of 76, + requiring 7 overflow bits. However since such situations are *very* + rare, accu can be limited to 64. + In case native saturated arithmetic is not available, overflows + can be prevented by replacing the above #define by + #define SHIFT_BEFORE_SQUARE ((8 - OVRFLW_BITS) / 2) + which will result in slightly reduced accuracy. +*/ + +/*! + \brief Estimates the mean energy of each filter-bank channel for the + duration of the current envelope + + This function is used when interpolFreq is true. +*/ +/*static*/ void calcNrgPerSubband(FIXP_DBL **analysBufferReal, /*!< Real part of subband samples */ + FIXP_DBL **analysBufferImag, /*!< Imaginary part of subband samples */ + int lowSubband, /*!< Begin of the SBR frequency range */ + int highSubband, /*!< High end of the SBR frequency range */ + int start_pos, /*!< First QMF-slot of current envelope */ + int next_pos, /*!< Last QMF-slot of current envelope + 1 */ + SCHAR frameExp, /*!< Common exponent for all input samples */ + FIXP_DBL *nrgEst, /*!< resulting Energy (0..1) */ + SCHAR *nrgEst_e ) /*!< Exponent of resulting Energy */ +{ + FIXP_SGL invWidth; + SCHAR preShift; + SCHAR shift; + FIXP_DBL sum; + int k,l; + + /* Divide by width of envelope later: */ + invWidth = FX_DBL2FX_SGL(GetInvInt(next_pos - start_pos)); + /* The common exponent needs to be doubled because all mantissas are squared: */ + frameExp = frameExp << 1; + + for (k=lowSubband; k>(DFRACT_BITS-1))); + bufferReal[l] = analysBufferReal[l][k]; + maxVal |= (FIXP_DBL)((LONG)(bufferReal[l])^((LONG)bufferReal[l]>>(DFRACT_BITS-1))); + } + } + else + { + for (l=start_pos;l>(DFRACT_BITS-1))); + } + } + + if (maxVal!=FL2FXCONST_DBL(0.f)) { + + + /* If the accu does not provide enough overflow bits, we cannot + shift the samples up to the limit. + Instead, keep up to 3 free bits in each sample, i.e. up to + 6 bits after calculation of square. + Please note the comment on saturated arithmetic above! + */ + FIXP_DBL accu = FL2FXCONST_DBL(0.0f); + preShift = CntLeadingZeros(maxVal)-1; + preShift -= SHIFT_BEFORE_SQUARE; + + if (preShift>=0) { + if (analysBufferImag!=NULL) { + for (l=start_pos; l> (int)negpreShift; + FIXP_DBL temp2 = bufferImag[l] >> (int)negpreShift; + accu = fPow2AddDiv2(accu, temp1); + accu = fPow2AddDiv2(accu, temp2); + } + } else + { + for (l=start_pos; l> (int)negpreShift; + accu = fPow2AddDiv2(accu, temp); + } + } + } + accu <<= 1; + + /* Convert double precision to Mantissa/Exponent: */ + shift = fNorm(accu); + sum = accu << (int)shift; + + /* Divide by width of envelope and apply frame scale: */ + *nrgEst++ = fMult(sum, invWidth); + shift += 2 * preShift; + if (analysBufferImag!=NULL) + *nrgEst_e++ = frameExp - shift; + else + *nrgEst_e++ = frameExp - shift + 1; /* +1 due to missing imag. part */ + } /* maxVal!=0 */ + else { + + /* Prevent a zero-mantissa-number from being misinterpreted + due to its exponent. */ + *nrgEst++ = FL2FXCONST_DBL(0.0f); + *nrgEst_e++ = 0; + } + } +} + +/*! + \brief Estimates the mean energy of each Scale factor band for the + duration of the current envelope. + + This function is used when interpolFreq is false. +*/ +/*static*/ void calcNrgPerSfb(FIXP_DBL **analysBufferReal, /*!< Real part of subband samples */ + FIXP_DBL **analysBufferImag, /*!< Imaginary part of subband samples */ + int nSfb, /*!< Number of scale factor bands */ + UCHAR *freqBandTable, /*!< First Subband for each Sfb */ + int start_pos, /*!< First QMF-slot of current envelope */ + int next_pos, /*!< Last QMF-slot of current envelope + 1 */ + SCHAR input_e, /*!< Common exponent for all input samples */ + FIXP_DBL *nrgEst, /*!< resulting Energy (0..1) */ + SCHAR *nrgEst_e ) /*!< Exponent of resulting Energy */ +{ + FIXP_SGL invWidth; + FIXP_DBL temp; + SCHAR preShift; + SCHAR shift, sum_e; + FIXP_DBL sum; + + int j,k,l,li,ui; + FIXP_DBL sumAll, sumLine; /* Single precision would be sufficient, + but overflow bits are required for accumulation */ + + /* Divide by width of envelope later: */ + invWidth = FX_DBL2FX_SGL(GetInvInt(next_pos - start_pos)); + /* The common exponent needs to be doubled because all mantissas are squared: */ + input_e = input_e << 1; + + for(j=0; j=0) { + for (l=start_pos; l> -(int)preShift; + sumLine += fPow2Div2(temp); + temp = analysBufferImag[l][k] >> -(int)preShift; + sumLine += fPow2Div2(temp); + } + } + } else + { + if (preShift>=0) { + for (l=start_pos; l> -(int)preShift; + sumLine += fPow2Div2(temp); + } + } + } + + /* The number of QMF-channels per SBR bands may be up to 15. + Shift right to avoid overflows in sum over all channels. */ + sumLine = sumLine >> (4-1); + sumAll += sumLine; + } + + /* Convert double precision to Mantissa/Exponent: */ + shift = fNorm(sumAll); + sum = sumAll << (int)shift; + + /* Divide by width of envelope: */ + sum = fMult(sum,invWidth); + + /* Divide by width of Sfb: */ + sum = fMult(sum, FX_DBL2FX_SGL(GetInvInt(ui-li))); + + /* Set all Subband energies in the Sfb to the average energy: */ + if (analysBufferImag!=NULL) + sum_e = input_e + 4 - shift; /* -4 to compensate right-shift */ + else + sum_e = input_e + 4 + 1 - shift; /* -4 to compensate right-shift; +1 due to missing imag. part */ + + sum_e -= 2 * preShift; + } /* maxVal!=0 */ + else { + + /* Prevent a zero-mantissa-number from being misinterpreted + due to its exponent. */ + sum = FL2FXCONST_DBL(0.0f); + sum_e = 0; + } + + for (k=li; knrgEst[i]; /*!< Energy in transposed signal */ + SCHAR nrgEst_e = nrgs->nrgEst_e[i]; /*!< Energy in transposed signal (exponent) */ + FIXP_DBL *ptrNrgGain = &nrgs->nrgGain[i]; /*!< Resulting energy gain */ + SCHAR *ptrNrgGain_e = &nrgs->nrgGain_e[i]; /*!< Resulting energy gain (exponent) */ + FIXP_DBL *ptrNoiseLevel = &nrgs->noiseLevel[i]; /*!< Resulting absolute noise energy */ + SCHAR *ptrNoiseLevel_e = &nrgs->noiseLevel_e[i]; /*!< Resulting absolute noise energy (exponent) */ + FIXP_DBL *ptrNrgSine = &nrgs->nrgSine[i]; /*!< Additional sine energy */ + SCHAR *ptrNrgSine_e = &nrgs->nrgSine_e[i]; /*!< Additional sine energy (exponent) */ + + FIXP_DBL a, b, c; + SCHAR a_e, b_e, c_e; + + /* + This addition of 1 prevents divisions by zero in the reference code. + For very small energies in nrgEst, it prevents the gains from becoming + very high which could cause some trouble due to the smoothing. + */ + b_e = (int)(nrgEst_e - 1); + if (b_e>=0) { + nrgEst = (FL2FXCONST_DBL(0.5f) >> (INT)fixMin(b_e+1,DFRACT_BITS-1)) + (nrgEst >> 1); + nrgEst_e += 1; /* shift by 1 bit to avoid overflow */ + + } else { + nrgEst = (nrgEst >> (INT)(fixMin(-b_e+1,DFRACT_BITS-1))) + (FL2FXCONST_DBL(0.5f) >> 1); + nrgEst_e = 2; /* shift by 1 bit to avoid overflow */ + } + + /* A = NrgRef * TmpNoise */ + a = fMult(nrgRef,tmpNoise); + a_e = nrgRef_e + tmpNoise_e; + + /* B = 1 + TmpNoise */ + b_e = (int)(tmpNoise_e - 1); + if (b_e>=0) { + b = (FL2FXCONST_DBL(0.5f) >> (INT)fixMin(b_e+1,DFRACT_BITS-1)) + (tmpNoise >> 1); + b_e = tmpNoise_e + 1; /* shift by 1 bit to avoid overflow */ + } else { + b = (tmpNoise >> (INT)(fixMin(-b_e+1,DFRACT_BITS-1))) + (FL2FXCONST_DBL(0.5f) >> 1); + b_e = 2; /* shift by 1 bit to avoid overflow */ + } + + /* noiseLevel = A / B = (NrgRef * TmpNoise) / (1 + TmpNoise) */ + FDK_divide_MantExp( a, a_e, + b, b_e, + ptrNoiseLevel, ptrNoiseLevel_e); + + if (sinePresentFlag) { + + /* C = (1 + TmpNoise) * NrgEst */ + c = fMult(b,nrgEst); + c_e = b_e + nrgEst_e; + + /* gain = A / C = (NrgRef * TmpNoise) / (1 + TmpNoise) * NrgEst */ + FDK_divide_MantExp( a, a_e, + c, c_e, + ptrNrgGain, ptrNrgGain_e); + + if (sineMapped) { + + /* sineLevel = nrgRef/ (1 + TmpNoise) */ + FDK_divide_MantExp( nrgRef, nrgRef_e, + b, b_e, + ptrNrgSine, ptrNrgSine_e); + } + } + else { + if (noNoiseFlag) { + /* B = NrgEst */ + b = nrgEst; + b_e = nrgEst_e; + } + else { + /* B = NrgEst * (1 + TmpNoise) */ + b = fMult(b,nrgEst); + b_e = b_e + nrgEst_e; + } + + + /* gain = nrgRef / B */ + FDK_divide_MantExp( nrgRef, nrgRef_e, + b, b_e, + ptrNrgGain, ptrNrgGain_e); + } +} + + +/*! + \brief Calculate "average gain" for the specified subband range. + + This is rather a gain of the average magnitude than the average + of gains! + The result is used as a relative limit for all gains within the + current "limiter band" (a certain frequency range). +*/ +/*static*/ void calcAvgGain(ENV_CALC_NRGS* nrgs, + int lowSubband, /*!< Begin of the limiter band */ + int highSubband, /*!< High end of the limiter band */ + FIXP_DBL *ptrSumRef, + SCHAR *ptrSumRef_e, + FIXP_DBL *ptrAvgGain, /*!< Resulting overall gain (mantissa) */ + SCHAR *ptrAvgGain_e) /*!< Resulting overall gain (exponent) */ +{ + FIXP_DBL *nrgRef = nrgs->nrgRef; /*!< Reference Energy according to envelope data */ + SCHAR *nrgRef_e = nrgs->nrgRef_e; /*!< Reference Energy according to envelope data (exponent) */ + FIXP_DBL *nrgEst = nrgs->nrgEst; /*!< Energy in transposed signal */ + SCHAR *nrgEst_e = nrgs->nrgEst_e; /*!< Energy in transposed signal (exponent) */ + + FIXP_DBL sumRef = 1; + FIXP_DBL sumEst = 1; + SCHAR sumRef_e = -FRACT_BITS; + SCHAR sumEst_e = -FRACT_BITS; + int k; + + for (k=lowSubband; knrgGain; /*!< Gains of current envelope */ + FIXP_DBL *pNoiseLevel = nrgs->noiseLevel; /*!< Noise levels of current envelope */ + FIXP_DBL *pSineLevel = nrgs->nrgSine; /*!< Sine levels */ + + int k; + int index = *ptrPhaseIndex; + UCHAR harmIndex = *ptrHarmIndex; + UCHAR freqInvFlag = (lowSubband & 1); + FIXP_DBL signalReal, sineLevel, sineLevelNext, sineLevelPrev; + int tone_count = 0; + int sineSign = 1; + + #define C1 ((FIXP_SGL)FL2FXCONST_SGL(2.f*0.00815f)) + #define C1_CLDFB ((FIXP_SGL)FL2FXCONST_SGL(2.f*0.16773f)) + + /* + First pass for k=0 pulled out of the loop: + */ + + index = (index + 1) & (SBR_NF_NO_RANDOM_VAL - 1); + + /* + The next multiplication constitutes the actual envelope adjustment + of the signal and should be carried out with full accuracy + (supplying #FRACT_BITS valid bits). + */ + signalReal = fMultDiv2(*ptrReal,*pGain++) << ((int)scale_change); + sineLevel = *pSineLevel++; + sineLevelNext = (noSubbands > 1) ? pSineLevel[0] : FL2FXCONST_DBL(0.0f); + + if (sineLevel!=FL2FXCONST_DBL(0.0f)) tone_count++; + + else if (!noNoiseFlag) + /* Add noisefloor to the amplified signal */ + signalReal += (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], pNoiseLevel[0])<<4); + + if (fCldfb) { + + if (!(harmIndex&0x1)) { + /* harmIndex 0,2 */ + signalReal += (harmIndex&0x2) ? -sineLevel : sineLevel; + *ptrReal++ = signalReal; + } + else { + /* harmIndex 1,3 in combination with freqInvFlag */ + int shift = (int) (scale_change+1); + shift = (shift>=0) ? fixMin(DFRACT_BITS-1,shift) : fixMax(-(DFRACT_BITS-1),shift); + + FIXP_DBL tmp1 = scaleValue( fMultDiv2(C1_CLDFB, sineLevel), -shift ); + + FIXP_DBL tmp2 = fMultDiv2(C1_CLDFB, sineLevelNext); + + + /* save switch and compare operations and reduce to XOR statement */ + if ( ((harmIndex>>1)&0x1)^freqInvFlag) { + *(ptrReal-1) += tmp1; + signalReal -= tmp2; + } else { + *(ptrReal-1) -= tmp1; + signalReal += tmp2; + } + *ptrReal++ = signalReal; + freqInvFlag = !freqInvFlag; + } + + } else + { + if (!(harmIndex&0x1)) { + /* harmIndex 0,2 */ + signalReal += (harmIndex&0x2) ? -sineLevel : sineLevel; + *ptrReal++ = signalReal; + } + else { + /* harmIndex 1,3 in combination with freqInvFlag */ + int shift = (int) (scale_change+1); + shift = (shift>=0) ? fixMin(DFRACT_BITS-1,shift) : fixMax(-(DFRACT_BITS-1),shift); + + FIXP_DBL tmp1 = (shift>=0) ? ( fMultDiv2(C1, sineLevel) >> shift ) + : ( fMultDiv2(C1, sineLevel) << (-shift) ); + FIXP_DBL tmp2 = fMultDiv2(C1, sineLevelNext); + + + /* save switch and compare operations and reduce to XOR statement */ + if ( ((harmIndex>>1)&0x1)^freqInvFlag) { + *(ptrReal-1) += tmp1; + signalReal -= tmp2; + } else { + *(ptrReal-1) -= tmp1; + signalReal += tmp2; + } + *ptrReal++ = signalReal; + freqInvFlag = !freqInvFlag; + } + } + + pNoiseLevel++; + + if ( noSubbands > 2 ) { + if (!(harmIndex&0x1)) { + /* harmIndex 0,2 */ + if(!harmIndex) + { + sineSign = 0; + } + + for (k=noSubbands-2; k!=0; k--) { + FIXP_DBL sinelevel = *pSineLevel++; + index++; + if (((signalReal = (sineSign ? -sinelevel : sinelevel)) == FL2FXCONST_DBL(0.0f)) && !noNoiseFlag) + { + /* Add noisefloor to the amplified signal */ + index &= (SBR_NF_NO_RANDOM_VAL - 1); + signalReal += (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], pNoiseLevel[0])<<4); + } + + /* The next multiplication constitutes the actual envelope adjustment of the signal. */ + signalReal += fMultDiv2(*ptrReal,*pGain++) << ((int)scale_change); + + pNoiseLevel++; + *ptrReal++ = signalReal; + } /* for ... */ + } + else { + /* harmIndex 1,3 in combination with freqInvFlag */ + if (harmIndex==1) freqInvFlag = !freqInvFlag; + + for (k=noSubbands-2; k!=0; k--) { + index++; + /* The next multiplication constitutes the actual envelope adjustment of the signal. */ + signalReal = fMultDiv2(*ptrReal,*pGain++) << ((int)scale_change); + + if (*pSineLevel++!=FL2FXCONST_DBL(0.0f)) tone_count++; + else if (!noNoiseFlag) { + /* Add noisefloor to the amplified signal */ + index &= (SBR_NF_NO_RANDOM_VAL - 1); + signalReal += (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], pNoiseLevel[0])<<4); + } + + pNoiseLevel++; + + if (tone_count <= 16) { + FIXP_DBL addSine = fMultDiv2((pSineLevel[-2] - pSineLevel[0]), C1); + signalReal += (freqInvFlag) ? (-addSine) : (addSine); + } + + *ptrReal++ = signalReal; + freqInvFlag = !freqInvFlag; + } /* for ... */ + } + } + + if (noSubbands > -1) { + index++; + /* The next multiplication constitutes the actual envelope adjustment of the signal. */ + signalReal = fMultDiv2(*ptrReal,*pGain) << ((int)scale_change); + sineLevelPrev = fMultDiv2(pSineLevel[-1],FL2FX_SGL(0.0163f)); + sineLevel = pSineLevel[0]; + + if (pSineLevel[0]!=FL2FXCONST_DBL(0.0f)) tone_count++; + else if (!noNoiseFlag) { + /* Add noisefloor to the amplified signal */ + index &= (SBR_NF_NO_RANDOM_VAL - 1); + signalReal = signalReal + (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], pNoiseLevel[0])<<4); + } + + if (!(harmIndex&0x1)) { + /* harmIndex 0,2 */ + *ptrReal = signalReal + ( (sineSign) ? -sineLevel : sineLevel); + } + else { + /* harmIndex 1,3 in combination with freqInvFlag */ + if(tone_count <= 16){ + if (freqInvFlag) { + *ptrReal++ = signalReal - sineLevelPrev; + if (noSubbands + lowSubband < 63) + *ptrReal = *ptrReal + fMultDiv2(C1, sineLevel); + } + else { + *ptrReal++ = signalReal + sineLevelPrev; + if (noSubbands + lowSubband < 63) + *ptrReal = *ptrReal - fMultDiv2(C1, sineLevel); + } + } + else *ptrReal = signalReal; + } + } + *ptrHarmIndex = (harmIndex + 1) & 3; + *ptrPhaseIndex = index & (SBR_NF_NO_RANDOM_VAL - 1); +} +void adjustTimeSlotHQ(FIXP_DBL *RESTRICT ptrReal, /*!< Subband samples to be adjusted, real part */ + FIXP_DBL *RESTRICT ptrImag, /*!< Subband samples to be adjusted, imag part */ + HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, + ENV_CALC_NRGS* nrgs, + int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */ + int noSubbands, /*!< Number of QMF subbands */ + int scale_change, /*!< Number of bits to shift adjusted samples */ + FIXP_SGL smooth_ratio, /*!< Impact of last envelope */ + int noNoiseFlag, /*!< Start index to random number array */ + int filtBufferNoiseShift) /*!< Shift factor of filtBufferNoise */ +{ + + FIXP_DBL *RESTRICT gain = nrgs->nrgGain; /*!< Gains of current envelope */ + FIXP_DBL *RESTRICT noiseLevel = nrgs->noiseLevel; /*!< Noise levels of current envelope */ + FIXP_DBL *RESTRICT pSineLevel = nrgs->nrgSine; /*!< Sine levels */ + + FIXP_DBL *RESTRICT filtBuffer = h_sbr_cal_env->filtBuffer; /*!< Gains of last envelope */ + FIXP_DBL *RESTRICT filtBufferNoise = h_sbr_cal_env->filtBufferNoise; /*!< Noise levels of last envelope */ + UCHAR *RESTRICT ptrHarmIndex =&h_sbr_cal_env->harmIndex; /*!< Harmonic index */ + int *RESTRICT ptrPhaseIndex =&h_sbr_cal_env->phaseIndex; /*!< Start index to random number array */ + + int k; + FIXP_DBL signalReal, signalImag; + FIXP_DBL noiseReal, noiseImag; + FIXP_DBL smoothedGain, smoothedNoise; + FIXP_SGL direct_ratio = /*FL2FXCONST_SGL(1.0f) */ (FIXP_SGL)MAXVAL_SGL - smooth_ratio; + int index = *ptrPhaseIndex; + UCHAR harmIndex = *ptrHarmIndex; + register int freqInvFlag = (lowSubband & 1); + FIXP_DBL sineLevel; + int shift; + + *ptrPhaseIndex = (index+noSubbands) & (SBR_NF_NO_RANDOM_VAL - 1); + *ptrHarmIndex = (harmIndex + 1) & 3; + + /* + Possible optimization: + smooth_ratio and harmIndex stay constant during the loop. + It might be faster to include a separate loop in each path. + + the check for smooth_ratio is now outside the loop and the workload + of the whole function decreased by about 20 % + */ + + filtBufferNoiseShift += 1; /* due to later use of fMultDiv2 instead of fMult */ + if (filtBufferNoiseShift<0) + shift = fixMin(DFRACT_BITS-1,-filtBufferNoiseShift); + else + shift = fixMin(DFRACT_BITS-1, filtBufferNoiseShift); + + if (smooth_ratio > FL2FXCONST_SGL(0.0f)) { + + for (k=0; k>shift) + + fMult(direct_ratio,noiseLevel[k]); + } + else { + smoothedNoise = (fMultDiv2(smooth_ratio,filtBufferNoise[k])<>5) { + if (workLimiterBandTable[hiLimIndex] == workLimiterBandTable[loLimIndex]) { + workLimiterBandTable[hiLimIndex] = highSubband; + nBands--; + hiLimIndex++; + continue; + } + isPatchBorder[0] = isPatchBorder[1] = 0; + for (k = 0; k <= noPatches; k++) { + if (workLimiterBandTable[hiLimIndex] == patchBorders[k]) { + isPatchBorder[1] = 1; + break; + } + } + if (!isPatchBorder[1]) { + workLimiterBandTable[hiLimIndex] = highSubband; + nBands--; + hiLimIndex++; + continue; + } + for (k = 0; k <= noPatches; k++) { + if (workLimiterBandTable[loLimIndex] == patchBorders[k]) { + isPatchBorder[0] = 1; + break; + } + } + if (!isPatchBorder[0]) { + workLimiterBandTable[loLimIndex] = highSubband; + nBands--; + } + } + loLimIndex = hiLimIndex; + hiLimIndex++; + + } + shellsort(workLimiterBandTable, tempNoLim + 1); + + /* Test if algorithm exceeded maximum allowed limiterbands */ + if( nBands > MAX_NUM_LIMITERS || nBands <= 0) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + /* Copy limiterbands from working buffer into final destination */ + for (k = 0; k <= nBands; k++) { + limiterBandTable[k] = workLimiterBandTable[k]; + } + } + *noLimiterBands = nBands; + + return SBRDEC_OK; +} + diff --git a/libSBRdec/src/env_calc.h b/libSBRdec/src/env_calc.h new file mode 100644 index 0000000..ef14996 --- /dev/null +++ b/libSBRdec/src/env_calc.h @@ -0,0 +1,107 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Envelope calculation prototypes $Revision: 36841 $ +*/ +#ifndef __ENV_CALC_H +#define __ENV_CALC_H + +#include "sbrdecoder.h" +#include "env_extr.h" /* for HANDLE_SBR_HEADER_DATA */ +#include "sbr_scale.h" + + +typedef struct +{ + FIXP_DBL filtBuffer[MAX_FREQ_COEFFS]; /*!< previous gains (required for smoothing) */ + FIXP_DBL filtBufferNoise[MAX_FREQ_COEFFS]; /*!< previous noise levels (required for smoothing) */ + SCHAR filtBuffer_e[MAX_FREQ_COEFFS]; /*!< Exponents of previous gains */ + SCHAR filtBufferNoise_e; /*!< Common exponent of previous noise levels */ + + int startUp; /*!< flag to signal initial conditions in buffers */ + int phaseIndex; /*!< Index for randomPase array */ + int prevTranEnv; /*!< The transient envelope of the previous frame. */ + + int harmFlagsPrev[(MAX_FREQ_COEFFS+15)/16]; + /*!< Words with 16 flags each indicating where a sine was added in the previous frame.*/ + UCHAR harmIndex; /*!< Current phase of synthetic sine */ + +} +SBR_CALCULATE_ENVELOPE; + +typedef SBR_CALCULATE_ENVELOPE *HANDLE_SBR_CALCULATE_ENVELOPE; + + + +void +calculateSbrEnvelope (QMF_SCALE_FACTOR *sbrScaleFactor, + HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, + HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA hFrameData, + FIXP_DBL **analysBufferReal, + FIXP_DBL **analysBufferImag, /*!< Imag part of subband samples to be processed */ + const int useLP, + FIXP_DBL *degreeAlias, /*!< Estimated aliasing for each QMF channel */ + const UINT flags, + const int frameErrorFlag + ); + +SBR_ERROR +createSbrEnvelopeCalc (HANDLE_SBR_CALCULATE_ENVELOPE hSbrCalculateEnvelope, + HANDLE_SBR_HEADER_DATA hHeaderData, + const int chan, + const UINT flags); + +int +deleteSbrEnvelopeCalc (HANDLE_SBR_CALCULATE_ENVELOPE hSbrCalculateEnvelope); + +void +resetSbrEnvelopeCalc (HANDLE_SBR_CALCULATE_ENVELOPE hCalEnv); + +SBR_ERROR +ResetLimiterBands ( UCHAR *limiterBandTable, + UCHAR *noLimiterBands, + UCHAR *freqBandTable, + int noFreqBands, + const PATCH_PARAM *patchParam, + int noPatches, + int limiterBands); + +void rescaleSubbandSamples( FIXP_DBL ** re, + FIXP_DBL ** im, + int lowSubband, int noSubbands, + int start_pos, int next_pos, + int shift); + +FIXP_DBL maxSubbandSample( FIXP_DBL ** analysBufferReal_m, + FIXP_DBL ** analysBufferImag_m, + int lowSubband, + int highSubband, + int start_pos, + int stop_pos); + +#endif // __ENV_CALC_H diff --git a/libSBRdec/src/env_dec.cpp b/libSBRdec/src/env_dec.cpp new file mode 100644 index 0000000..f49694e --- /dev/null +++ b/libSBRdec/src/env_dec.cpp @@ -0,0 +1,794 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +****************************************************************************/ +/*! + \file + \brief envelope decoding $Revision: 36841 $ + This module provides envelope decoding and error concealment algorithms. The main + entry point is decodeSbrData(). + + \sa decodeSbrData(),\ref documentationOverview +*/ + +#include "env_dec.h" + +#include "env_extr.h" +#include "transcendent.h" + +#include "genericStds.h" + + +static void decodeEnvelope (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_sbr_data, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data_otherChannel); +static void sbr_envelope_unmapping (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_data_left, + HANDLE_SBR_FRAME_DATA h_data_right); +static void requantizeEnvelopeData (HANDLE_SBR_FRAME_DATA h_sbr_data, + int ampResolution); +static void deltaToLinearPcmEnvelopeDecoding (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_sbr_data, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data); +static void decodeNoiseFloorlevels (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_sbr_data, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data); +static void timeCompensateFirstEnvelope (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_sbr_data, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data); +static int checkEnvelopeData (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_sbr_data, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data); + + + +#define SBR_ENERGY_PAN_OFFSET (12 << ENV_EXP_FRACT) +#define SBR_MAX_ENERGY (35 << ENV_EXP_FRACT) + +#define DECAY ( 1 << ENV_EXP_FRACT) + +#if ENV_EXP_FRACT +#define DECAY_COUPLING ( 1 << (ENV_EXP_FRACT-1) ) /*!< corresponds to a value of 0.5 */ +#else +#define DECAY_COUPLING 1 /*!< If the energy data is not shifted, use 1 instead of 0.5 */ +#endif + + +/*! + \brief Convert table index +*/ +static int indexLow2High(int offset, /*!< mapping factor */ + int index, /*!< index to scalefactor band */ + int res) /*!< frequency resolution */ +{ + if(res == 0) + { + if (offset >= 0) + { + if (index < offset) + return(index); + else + return(2*index - offset); + } + else + { + offset = -offset; + if (index < offset) + return(2*index+index); + else + return(2*index + offset); + } + } + else + return(index); +} + + +/*! + \brief Update previous envelope value for delta-coding + + The current envelope values needs to be stored for delta-coding + in the next frame. The stored envelope is always represented with + the high frequency resolution. If the current envelope uses the + low frequency resolution, the energy value will be mapped to the + corresponding high-res bands. +*/ +static void mapLowResEnergyVal(FIXP_SGL currVal, /*!< current energy value */ + FIXP_SGL* prevData,/*!< pointer to previous data vector */ + int offset, /*!< mapping factor */ + int index, /*!< index to scalefactor band */ + int res) /*!< frequeny resolution */ +{ + if(res == 0) + { + if (offset >= 0) + { + if(index < offset) + prevData[index] = currVal; + else + { + prevData[2*index - offset] = currVal; + prevData[2*index+1 - offset] = currVal; + } + } + else + { + offset = -offset; + if (index < offset) + { + prevData[3*index] = currVal; + prevData[3*index+1] = currVal; + prevData[3*index+2] = currVal; + } + else + { + prevData[2*index + offset] = currVal; + prevData[2*index + 1 + offset] = currVal; + } + } + } + else + prevData[index] = currVal; +} + + + +/*! + \brief Convert raw envelope and noisefloor data to energy levels + + This function is being called by sbrDecoder_ParseElement() and provides two important algorithms: + + First the function decodes envelopes and noise floor levels as described in requantizeEnvelopeData() + and sbr_envelope_unmapping(). The function also implements concealment algorithms in case there are errors + within the sbr data. For both operations fractional arithmetic is used. + Therefore you might encounter different output values on your target + system compared to the reference implementation. +*/ +void +decodeSbrData (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_data_left, /*!< pointer to left channel frame data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data_left, /*!< pointer to left channel previous frame data */ + HANDLE_SBR_FRAME_DATA h_data_right, /*!< pointer to right channel frame data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data_right)/*!< pointer to right channel previous frame data */ +{ + FIXP_SGL tempSfbNrgPrev[MAX_FREQ_COEFFS]; + int errLeft; + + /* Save previous energy values to be able to reuse them later for concealment. */ + FDKmemcpy (tempSfbNrgPrev, h_prev_data_left->sfb_nrg_prev, MAX_FREQ_COEFFS * sizeof(FIXP_SGL)); + + decodeEnvelope (hHeaderData, h_data_left, h_prev_data_left, h_prev_data_right); + decodeNoiseFloorlevels (hHeaderData, h_data_left, h_prev_data_left); + + if(h_data_right != NULL) { + errLeft = hHeaderData->frameErrorFlag; + decodeEnvelope (hHeaderData, h_data_right, h_prev_data_right, h_prev_data_left); + decodeNoiseFloorlevels (hHeaderData, h_data_right, h_prev_data_right); + + if (!errLeft && hHeaderData->frameErrorFlag) { + /* If an error occurs in the right channel where the left channel seemed ok, + we apply concealment also on the left channel. This ensures that the coupling + modes of both channels match and that we have the same number of envelopes in + coupling mode. + However, as the left channel has already been processed before, the resulting + energy levels are not the same as if the left channel had been concealed + during the first call of decodeEnvelope(). + */ + /* Restore previous energy values for concealment, because the values have been + overwritten by the first call of decodeEnvelope(). */ + FDKmemcpy (h_prev_data_left->sfb_nrg_prev, tempSfbNrgPrev, MAX_FREQ_COEFFS * sizeof(FIXP_SGL)); + /* Do concealment */ + decodeEnvelope (hHeaderData, h_data_left, h_prev_data_left, h_prev_data_right); + } + + if (h_data_left->coupling) { + sbr_envelope_unmapping (hHeaderData, h_data_left, h_data_right); + } + } + + /* Display the data for debugging: */ +} + + +/*! + \brief Convert from coupled channels to independent L/R data +*/ +static void +sbr_envelope_unmapping (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_data_left, /*!< pointer to left channel */ + HANDLE_SBR_FRAME_DATA h_data_right) /*!< pointer to right channel */ +{ + int i; + FIXP_SGL tempL_m, tempR_m, tempRplus1_m, newL_m, newR_m; + SCHAR tempL_e, tempR_e, tempRplus1_e, newL_e, newR_e; + + + /* 1. Unmap (already dequantized) coupled envelope energies */ + + for (i = 0; i < h_data_left->nScaleFactors; i++) { + tempR_m = (FIXP_SGL)((LONG)h_data_right->iEnvelope[i] & MASK_M); + tempR_e = (SCHAR)((LONG)h_data_right->iEnvelope[i] & MASK_E); + + tempR_e -= (18 + NRG_EXP_OFFSET); /* -18 = ld(UNMAPPING_SCALE / h_data_right->nChannels) */ + tempL_m = (FIXP_SGL)((LONG)h_data_left->iEnvelope[i] & MASK_M); + tempL_e = (SCHAR)((LONG)h_data_left->iEnvelope[i] & MASK_E); + + tempL_e -= NRG_EXP_OFFSET; + + /* Calculate tempRight+1 */ + FDK_add_MantExp( tempR_m, tempR_e, + FL2FXCONST_SGL(0.5f), 1, /* 1.0 */ + &tempRplus1_m, &tempRplus1_e); + + FDK_divide_MantExp( tempL_m, tempL_e+1, /* 2 * tempLeft */ + tempRplus1_m, tempRplus1_e, + &newR_m, &newR_e ); + + if (newR_m >= ((FIXP_SGL)MAXVAL_SGL - ROUNDING)) { + newR_m >>= 1; + newR_e += 1; + } + + newL_m = FX_DBL2FX_SGL(fMult(tempR_m,newR_m)); + newL_e = tempR_e + newR_e; + + h_data_right->iEnvelope[i] = ((FIXP_SGL)((SHORT)(FIXP_SGL)(newR_m + ROUNDING) & MASK_M)) + + (FIXP_SGL)((SHORT)(FIXP_SGL)(newR_e + NRG_EXP_OFFSET) & MASK_E); + h_data_left->iEnvelope[i] = ((FIXP_SGL)((SHORT)(FIXP_SGL)(newL_m + ROUNDING) & MASK_M)) + + (FIXP_SGL)((SHORT)(FIXP_SGL)(newL_e + NRG_EXP_OFFSET) & MASK_E); + } + + /* 2. Dequantize and unmap coupled noise floor levels */ + + for (i = 0; i < hHeaderData->freqBandData.nNfb * h_data_left->frameInfo.nNoiseEnvelopes; i++) { + + tempL_e = (SCHAR)(6 - (LONG)h_data_left->sbrNoiseFloorLevel[i]); + tempR_e = (SCHAR)((LONG)h_data_right->sbrNoiseFloorLevel[i] - 12) /*SBR_ENERGY_PAN_OFFSET*/; + + /* Calculate tempR+1 */ + FDK_add_MantExp( FL2FXCONST_SGL(0.5f), 1+tempR_e, /* tempR */ + FL2FXCONST_SGL(0.5f), 1, /* 1.0 */ + &tempRplus1_m, &tempRplus1_e); + + /* Calculate 2*tempLeft/(tempR+1) */ + FDK_divide_MantExp( FL2FXCONST_SGL(0.5f), tempL_e+2, /* 2 * tempLeft */ + tempRplus1_m, tempRplus1_e, + &newR_m, &newR_e ); + + /* if (newR_m >= ((FIXP_SGL)MAXVAL_SGL - ROUNDING)) { + newR_m >>= 1; + newR_e += 1; + } */ + + /* L = tempR * R */ + newL_m = newR_m; + newL_e = newR_e + tempR_e; + h_data_right->sbrNoiseFloorLevel[i] = ((FIXP_SGL)((SHORT)(FIXP_SGL)(newR_m + ROUNDING) & MASK_M)) + + (FIXP_SGL)((SHORT)(FIXP_SGL)(newR_e + NOISE_EXP_OFFSET) & MASK_E); + h_data_left->sbrNoiseFloorLevel[i] = ((FIXP_SGL)((SHORT)(FIXP_SGL)(newL_m + ROUNDING) & MASK_M)) + + (FIXP_SGL)((SHORT)(FIXP_SGL)(newL_e + NOISE_EXP_OFFSET) & MASK_E); + } +} + + +/*! + \brief Simple alternative to the real SBR concealment + + If the real frameInfo is not available due to a frame loss, a replacement will + be constructed with 1 envelope spanning the whole frame (FIX-FIX). + The delta-coded energies are set to negative values, resulting in a fade-down. + In case of coupling, the balance-channel will move towards the center. +*/ +static void +leanSbrConcealment(HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to current data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data /*!< pointer to data of last frame */ + ) +{ + FIXP_SGL target; /* targeted level for sfb_nrg_prev during fade-down */ + FIXP_SGL step; /* speed of fade */ + int i; + + int currentStartPos = h_prev_data->stopPos - hHeaderData->numberTimeSlots; + int currentStopPos = hHeaderData->numberTimeSlots; + + + /* Use some settings of the previous frame */ + h_sbr_data->ampResolutionCurrentFrame = h_prev_data->ampRes; + h_sbr_data->coupling = h_prev_data->coupling; + for(i=0;isbr_invf_mode[i] = h_prev_data->sbr_invf_mode[i]; + + /* Generate concealing control data */ + + h_sbr_data->frameInfo.nEnvelopes = 1; + h_sbr_data->frameInfo.borders[0] = currentStartPos; + h_sbr_data->frameInfo.borders[1] = currentStopPos; + h_sbr_data->frameInfo.freqRes[0] = 1; + h_sbr_data->frameInfo.tranEnv = -1; /* no transient */ + h_sbr_data->frameInfo.nNoiseEnvelopes = 1; + h_sbr_data->frameInfo.bordersNoise[0] = currentStartPos; + h_sbr_data->frameInfo.bordersNoise[1] = currentStopPos; + + h_sbr_data->nScaleFactors = hHeaderData->freqBandData.nSfb[1]; + + /* Generate fake envelope data */ + + h_sbr_data->domain_vec[0] = 1; + + if (h_sbr_data->coupling == COUPLING_BAL) { + target = (FIXP_SGL)SBR_ENERGY_PAN_OFFSET; + step = (FIXP_SGL)DECAY_COUPLING; + } + else { + target = FL2FXCONST_SGL(0.0f); + step = (FIXP_SGL)DECAY; + } + if (hHeaderData->bs_info.ampResolution == 0) { + target <<= 1; + step <<= 1; + } + + for (i=0; i < h_sbr_data->nScaleFactors; i++) { + if (h_prev_data->sfb_nrg_prev[i] > target) + h_sbr_data->iEnvelope[i] = -step; + else + h_sbr_data->iEnvelope[i] = step; + } + + /* Noisefloor levels are always cleared ... */ + + h_sbr_data->domain_vec_noise[0] = 1; + for (i=0; i < hHeaderData->freqBandData.nNfb; i++) + h_sbr_data->sbrNoiseFloorLevel[i] = FL2FXCONST_SGL(0.0f); + + /* ... and so are the sines */ + FDKmemclear(h_sbr_data->addHarmonics, MAX_FREQ_COEFFS); +} + + +/*! + \brief Build reference energies and noise levels from bitstream elements +*/ +static void +decodeEnvelope (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to current data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data, /*!< pointer to data of last frame */ + HANDLE_SBR_PREV_FRAME_DATA otherChannel /*!< other channel's last frame data */ + ) +{ + int i; + int fFrameError = hHeaderData->frameErrorFlag; + FIXP_SGL tempSfbNrgPrev[MAX_FREQ_COEFFS]; + + if (!fFrameError) { + /* + To avoid distortions after bad frames, set the error flag if delta coding in time occurs. + However, SBR can take a little longer to come up again. + */ + if ( h_prev_data->frameErrorFlag ) { + if (h_sbr_data->domain_vec[0] != 0) { + fFrameError = 1; + } + } else { + /* Check that the previous stop position and the current start position match. + (Could be done in checkFrameInfo(), but the previous frame data is not available there) */ + if ( h_sbr_data->frameInfo.borders[0] != h_prev_data->stopPos - hHeaderData->numberTimeSlots ) { + /* Both the previous as well as the current frame are flagged to be ok, but they do not match! */ + if (h_sbr_data->domain_vec[0] == 1) { + /* Prefer concealment over delta-time coding between the mismatching frames */ + fFrameError = 1; + } + else { + /* Close the gap in time by triggering timeCompensateFirstEnvelope() */ + fFrameError = 1; + } + } + } + } + + + if (fFrameError) /* Error is detected */ + { + leanSbrConcealment(hHeaderData, + h_sbr_data, + h_prev_data); + + /* decode the envelope data to linear PCM */ + deltaToLinearPcmEnvelopeDecoding (hHeaderData, h_sbr_data, h_prev_data); + } + else /*Do a temporary dummy decoding and check that the envelope values are within limits */ + { + if (h_prev_data->frameErrorFlag) { + timeCompensateFirstEnvelope (hHeaderData, h_sbr_data, h_prev_data); + if (h_sbr_data->coupling != h_prev_data->coupling) { + /* + Coupling mode has changed during concealment. + The stored energy levels need to be converted. + */ + for (i = 0; i < hHeaderData->freqBandData.nSfb[1]; i++) { + /* Former Level-Channel will be used for both channels */ + if (h_prev_data->coupling == COUPLING_BAL) + h_prev_data->sfb_nrg_prev[i] = otherChannel->sfb_nrg_prev[i]; + /* Former L/R will be combined as the new Level-Channel */ + else if (h_sbr_data->coupling == COUPLING_LEVEL) + h_prev_data->sfb_nrg_prev[i] = (h_prev_data->sfb_nrg_prev[i] + otherChannel->sfb_nrg_prev[i]) >> 1; + else if (h_sbr_data->coupling == COUPLING_BAL) + h_prev_data->sfb_nrg_prev[i] = (FIXP_SGL)SBR_ENERGY_PAN_OFFSET; + } + } + } + FDKmemcpy (tempSfbNrgPrev, h_prev_data->sfb_nrg_prev, + MAX_FREQ_COEFFS * sizeof (FIXP_SGL)); + + deltaToLinearPcmEnvelopeDecoding (hHeaderData, h_sbr_data, h_prev_data); + + fFrameError = checkEnvelopeData (hHeaderData, h_sbr_data, h_prev_data); + + if (fFrameError) + { + hHeaderData->frameErrorFlag = 1; + FDKmemcpy (h_prev_data->sfb_nrg_prev, tempSfbNrgPrev, + MAX_FREQ_COEFFS * sizeof (FIXP_SGL)); + decodeEnvelope (hHeaderData, h_sbr_data, h_prev_data, otherChannel); + return; + } + } + + requantizeEnvelopeData (h_sbr_data, h_sbr_data->ampResolutionCurrentFrame); + + hHeaderData->frameErrorFlag = fFrameError; +} + + +/*! + \brief Verify that envelope energies are within the allowed range + \return 0 if all is fine, 1 if an envelope value was too high +*/ +static int +checkEnvelopeData (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to current data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data /*!< pointer to data of last frame */ + ) +{ + FIXP_SGL *iEnvelope = h_sbr_data->iEnvelope; + FIXP_SGL *sfb_nrg_prev = h_prev_data->sfb_nrg_prev; + int i = 0, errorFlag = 0; + FIXP_SGL sbr_max_energy = + (h_sbr_data->ampResolutionCurrentFrame == 1) ? SBR_MAX_ENERGY : (SBR_MAX_ENERGY << 1); + + /* + Range check for current energies + */ + for (i = 0; i < h_sbr_data->nScaleFactors; i++) { + if (iEnvelope[i] > sbr_max_energy) { + errorFlag = 1; + } + if (iEnvelope[i] < FL2FXCONST_SGL(0.0f)) { + errorFlag = 1; + /* iEnvelope[i] = FL2FXCONST_SGL(0.0f); */ + } + } + + /* + Range check for previous energies + */ + for (i = 0; i < hHeaderData->freqBandData.nSfb[1]; i++) { + sfb_nrg_prev[i] = fixMax(sfb_nrg_prev[i], FL2FXCONST_SGL(0.0f)); + sfb_nrg_prev[i] = fixMin(sfb_nrg_prev[i], sbr_max_energy); + } + + return (errorFlag); +} + + +/*! + \brief Verify that the noise levels are within the allowed range + + The function is equivalent to checkEnvelopeData(). + When the noise-levels are being decoded, it is already too late for + concealment. Therefore the noise levels are simply limited here. +*/ +static void +limitNoiseLevels(HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_sbr_data) /*!< pointer to current data */ +{ + int i; + int nNfb = hHeaderData->freqBandData.nNfb; + + /* + Set range limits. The exact values depend on the coupling mode. + However this limitation is primarily intended to avoid unlimited + accumulation of the delta-coded noise levels. + */ + #define lowerLimit ((FIXP_SGL)0) /* lowerLimit actually refers to the _highest_ noise energy */ + #define upperLimit ((FIXP_SGL)35) /* upperLimit actually refers to the _lowest_ noise energy */ + + /* + Range check for current noise levels + */ + for (i = 0; i < h_sbr_data->frameInfo.nNoiseEnvelopes * nNfb; i++) { + h_sbr_data->sbrNoiseFloorLevel[i] = fixMin(h_sbr_data->sbrNoiseFloorLevel[i], upperLimit); + h_sbr_data->sbrNoiseFloorLevel[i] = fixMax(h_sbr_data->sbrNoiseFloorLevel[i], lowerLimit); + } +} + + +/*! + \brief Compensate for the wrong timing that might occur after a frame error. +*/ +static void +timeCompensateFirstEnvelope (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to actual data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data) /*!< pointer to data of last frame */ +{ + int i, nScalefactors; + FRAME_INFO *pFrameInfo = &h_sbr_data->frameInfo; + UCHAR *nSfb = hHeaderData->freqBandData.nSfb; + int estimatedStartPos = h_prev_data->stopPos - hHeaderData->numberTimeSlots; + int refLen, newLen, shift; + FIXP_SGL deltaExp; + + /* Original length of first envelope according to bitstream */ + refLen = pFrameInfo->borders[1] - pFrameInfo->borders[0]; + /* Corrected length of first envelope (concealing can make the first envelope longer) */ + newLen = pFrameInfo->borders[1] - estimatedStartPos; + + if (newLen <= 0) { + /* An envelope length of <= 0 would not work, so we don't use it. + May occur if the previous frame was flagged bad due to a mismatch + of the old and new frame infos. */ + newLen = refLen; + estimatedStartPos = pFrameInfo->borders[0]; + } + + deltaExp = FDK_getNumOctavesDiv8(newLen, refLen); + + /* Shift by -3 to rescale ld-table, 1-ampRes to enable coarser steps */ + shift = (FRACT_BITS - 1 - ENV_EXP_FRACT + 1 - h_sbr_data->ampResolutionCurrentFrame - 3); + deltaExp = deltaExp >> shift; + pFrameInfo->borders[0] = estimatedStartPos; + pFrameInfo->bordersNoise[0] = estimatedStartPos; + + if (h_sbr_data->coupling != COUPLING_BAL) { + nScalefactors = (pFrameInfo->freqRes[0]) ? nSfb[1] : nSfb[0]; + + for (i = 0; i < nScalefactors; i++) + h_sbr_data->iEnvelope[i] = h_sbr_data->iEnvelope[i] + deltaExp; + } +} + + + +/*! + \brief Convert each envelope value from logarithmic to linear domain + + Energy levels are transmitted in powers of 2, i.e. only the exponent + is extracted from the bitstream. + Therefore, normally only integer exponents can occur. However during + fading (in case of a corrupt bitstream), a fractional part can also + occur. The data in the array iEnvelope is shifted left by ENV_EXP_FRACT + compared to an integer representation so that numbers smaller than 1 + can be represented. + + This function calculates a mantissa corresponding to the fractional + part of the exponent for each reference energy. The array iEnvelope + is converted in place to save memory. Input and output data must + be interpreted differently, as shown in the below figure: + + \image html EnvelopeData.png + + The data is then used in calculateSbrEnvelope(). +*/ +static void +requantizeEnvelopeData (HANDLE_SBR_FRAME_DATA h_sbr_data, int ampResolution) +{ + int i; + FIXP_SGL mantissa; + int ampShift = 1 - ampResolution; + int exponent; + + /* In case that ENV_EXP_FRACT is changed to something else but 0 or 8, + the initialization of this array has to be adapted! + */ +#if ENV_EXP_FRACT + static const FIXP_SGL pow2[ENV_EXP_FRACT] = + { + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 1))), /* 0.7071 */ + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 2))), /* 0.5946 */ + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 3))), + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 4))), + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 5))), + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 6))), + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 7))), + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 8))) /* 0.5013 */ + }; + + int bit, mask; +#endif + + for (i = 0; i < h_sbr_data->nScaleFactors; i++) { + exponent = (LONG)h_sbr_data->iEnvelope[i]; + +#if ENV_EXP_FRACT + + exponent = exponent >> ampShift; + mantissa = 0.5f; + + /* Amplify mantissa according to the fractional part of the + exponent (result will be between 0.500000 and 0.999999) + */ + mask = 1; /* begin with lowest bit of exponent */ + + for ( bit=ENV_EXP_FRACT-1; bit>=0; bit-- ) { + if (exponent & mask) { + /* The current bit of the exponent is set, + multiply mantissa with the corresponding factor: */ + mantissa = (FIXP_SGL)( (mantissa * pow2[bit]) << 1); + } + /* Advance to next bit */ + mask = mask << 1; + } + + /* Make integer part of exponent right aligned */ + exponent = exponent >> ENV_EXP_FRACT; + +#else + /* In case of the high amplitude resolution, 1 bit of the exponent gets lost by the shift. + This will be compensated by a mantissa of 0.5*sqrt(2) instead of 0.5 if that bit is 1. */ + mantissa = (exponent & ampShift) ? FL2FXCONST_SGL(0.707106781186548f) : FL2FXCONST_SGL(0.5f); + exponent = exponent >> ampShift; +#endif + + /* + Mantissa was set to 0.5 (instead of 1.0, therefore increase exponent by 1). + Multiply by L=nChannels=64 by increasing exponent by another 6. + => Increase exponent by 7 + */ + exponent += 7 + NRG_EXP_OFFSET; + + /* Combine mantissa and exponent and write back the result */ + h_sbr_data->iEnvelope[i] = (FIXP_SGL)(((LONG)mantissa & MASK_M) | (exponent & MASK_E)); + + } +} + + +/*! + \brief Build new reference energies from old ones and delta coded data +*/ +static void +deltaToLinearPcmEnvelopeDecoding (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to current data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data) /*!< pointer to previous data */ +{ + int i, domain, no_of_bands, band, freqRes; + + FIXP_SGL *sfb_nrg_prev = h_prev_data->sfb_nrg_prev; + FIXP_SGL *ptr_nrg = h_sbr_data->iEnvelope; + + int offset = 2 * hHeaderData->freqBandData.nSfb[0] - hHeaderData->freqBandData.nSfb[1]; + + for (i = 0; i < h_sbr_data->frameInfo.nEnvelopes; i++) { + domain = h_sbr_data->domain_vec[i]; + freqRes = h_sbr_data->frameInfo.freqRes[i]; + + FDK_ASSERT(freqRes >= 0 && freqRes <= 1); + + no_of_bands = hHeaderData->freqBandData.nSfb[freqRes]; + + FDK_ASSERT(no_of_bands < (64)); + + if (domain == 0) + { + mapLowResEnergyVal(*ptr_nrg, sfb_nrg_prev, offset, 0, freqRes); + ptr_nrg++; + for (band = 1; band < no_of_bands; band++) + { + *ptr_nrg = *ptr_nrg + *(ptr_nrg-1); + mapLowResEnergyVal(*ptr_nrg, sfb_nrg_prev, offset, band, freqRes); + ptr_nrg++; + } + } + else + { + for (band = 0; band < no_of_bands; band++) + { + *ptr_nrg = *ptr_nrg + sfb_nrg_prev[indexLow2High(offset, band, freqRes)]; + mapLowResEnergyVal(*ptr_nrg, sfb_nrg_prev, offset, band, freqRes); + ptr_nrg++; + } + } + } +} + + +/*! + \brief Build new noise levels from old ones and delta coded data +*/ +static void +decodeNoiseFloorlevels (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to current data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data) /*!< pointer to previous data */ +{ + int i; + int nNfb = hHeaderData->freqBandData.nNfb; + int nNoiseFloorEnvelopes = h_sbr_data->frameInfo.nNoiseEnvelopes; + + /* Decode first noise envelope */ + + if (h_sbr_data->domain_vec_noise[0] == 0) { + FIXP_SGL noiseLevel = h_sbr_data->sbrNoiseFloorLevel[0]; + for (i = 1; i < nNfb; i++) { + noiseLevel += h_sbr_data->sbrNoiseFloorLevel[i]; + h_sbr_data->sbrNoiseFloorLevel[i] = noiseLevel; + } + } + else { + for (i = 0; i < nNfb; i++) { + h_sbr_data->sbrNoiseFloorLevel[i] += h_prev_data->prevNoiseLevel[i]; + } + } + + /* If present, decode the second noise envelope + Note: nNoiseFloorEnvelopes can only be 1 or 2 */ + + if (nNoiseFloorEnvelopes > 1) { + if (h_sbr_data->domain_vec_noise[1] == 0) { + FIXP_SGL noiseLevel = h_sbr_data->sbrNoiseFloorLevel[nNfb]; + for (i = nNfb + 1; i < 2*nNfb; i++) { + noiseLevel += h_sbr_data->sbrNoiseFloorLevel[i]; + h_sbr_data->sbrNoiseFloorLevel[i] = noiseLevel; + } + } + else { + for (i = 0; i < nNfb; i++) { + h_sbr_data->sbrNoiseFloorLevel[i + nNfb] += h_sbr_data->sbrNoiseFloorLevel[i]; + } + } + } + + limitNoiseLevels(hHeaderData, h_sbr_data); + + /* Update prevNoiseLevel with the last noise envelope */ + for (i = 0; i < nNfb; i++) + h_prev_data->prevNoiseLevel[i] = h_sbr_data->sbrNoiseFloorLevel[i + nNfb*(nNoiseFloorEnvelopes-1)]; + + + /* Requantize the noise floor levels in COUPLING_OFF-mode */ + if (!h_sbr_data->coupling) { + int nf_e; + + for (i = 0; i < nNoiseFloorEnvelopes*nNfb; i++) { + nf_e = 6 - (LONG)h_sbr_data->sbrNoiseFloorLevel[i] + 1 + NOISE_EXP_OFFSET; + /* +1 to compensate for a mantissa of 0.5 instead of 1.0 */ + + h_sbr_data->sbrNoiseFloorLevel[i] = + (FIXP_SGL)( ((LONG)FL2FXCONST_SGL(0.5f)) + /* mantissa */ + (nf_e & MASK_E) ); /* exponent */ + + } + } +} diff --git a/libSBRdec/src/env_dec.h b/libSBRdec/src/env_dec.h new file mode 100644 index 0000000..554c6c2 --- /dev/null +++ b/libSBRdec/src/env_dec.h @@ -0,0 +1,43 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Envelope decoding $Revision: 36841 $ +*/ +#ifndef __ENV_DEC_H +#define __ENV_DEC_H + +#include "sbrdecoder.h" +#include "env_extr.h" + +void decodeSbrData (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_data_left, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data_left, + HANDLE_SBR_FRAME_DATA h_data_right, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data_right); + + +#endif diff --git a/libSBRdec/src/env_extr.cpp b/libSBRdec/src/env_extr.cpp new file mode 100644 index 0000000..040b812 --- /dev/null +++ b/libSBRdec/src/env_extr.cpp @@ -0,0 +1,1333 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Envelope extraction $Revision: 36841 $ + The functions provided by this module are mostly called by applySBR(). After it is + determined that there is valid SBR data, sbrGetHeaderData() might be called if the current + SBR data contains an \ref SBR_HEADER_ELEMENT as opposed to a \ref SBR_STANDARD_ELEMENT. This function + may return various error codes as defined in #SBR_HEADER_STATUS . Most importantly it returns HEADER_RESET when decoder + settings need to be recalculated according to the SBR specifications. In that case applySBR() + will initiatite the required re-configuration. + + The header data is stored in a #SBR_HEADER_DATA structure. + + The actual SBR data for the current frame is decoded into SBR_FRAME_DATA stuctures by sbrGetChannelPairElement() + [for stereo streams] and sbrGetSingleChannelElement() [for mono streams]. There is no fractional arithmetic involved. + + Once the information is extracted, the data needs to be further prepared before the actual decoding process. + This is done in decodeSbrData(). + + \sa Description of buffer management in applySBR(). \ref documentationOverview + +

About the SBR data format:

+ + Each frame includes SBR data (side chain information), and can be either the \ref SBR_HEADER_ELEMENT or the \ref SBR_STANDARD_ELEMENT. + Parts of the data can be protected by a CRC checksum. + + \anchor SBR_HEADER_ELEMENT

The SBR_HEADER_ELEMENT

+ + The SBR_HEADER_ELEMENT can be transmitted with every frame, however, it typically is send every second or so. It contains fundamental + information such as SBR sampling frequency and frequency range as well as control signals that do not require frequent changes. It also + includes the \ref SBR_STANDARD_ELEMENT. + + Depending on the changes between the information in a current SBR_HEADER_ELEMENT and the previous SBR_HEADER_ELEMENT, the SBR decoder might need + to be reset and reconfigured (e.g. new tables need to be calculated). + + \anchor SBR_STANDARD_ELEMENT

The SBR_STANDARD_ELEMENT

+ + This data can be subdivided into "side info" and "raw data", where side info is defined as signals needed to decode the raw data + and some decoder tuning signals. Raw data is referred to as PCM and Huffman coded envelope and noise floor estimates. The side info also + includes information about the time-frequency grid for the current frame. + + \sa \ref documentationOverview +*/ + +#include "env_extr.h" + +#include "sbr_ram.h" +#include "sbr_rom.h" +#include "huff_dec.h" + + +#include "psbitdec.h" + +#define DRM_PARAMETRIC_STEREO 0 +#define EXTENSION_ID_PS_CODING 2 + + +static int extractFrameInfo (HANDLE_FDK_BITSTREAM hBs, + HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_frame_data, + const UINT nrOfChannels, + const UINT flags + ); + + +static int sbrGetEnvelope (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_frame_data, + HANDLE_FDK_BITSTREAM hBs, + const UINT flags); + +static void sbrGetDirectionControlData (HANDLE_SBR_FRAME_DATA hFrameData, + HANDLE_FDK_BITSTREAM hBs); + +static void sbrGetNoiseFloorData (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_frame_data, + HANDLE_FDK_BITSTREAM hBs); + +static int checkFrameInfo (FRAME_INFO *pFrameInfo, int numberOfTimeSlots, int overlap, int timeStep); + +SBR_ERROR +initHeaderData ( + HANDLE_SBR_HEADER_DATA hHeaderData, + const int sampleRateIn, + const int sampleRateOut, + const int samplesPerFrame, + const UINT flags + ) +{ + HANDLE_FREQ_BAND_DATA hFreq = &hHeaderData->freqBandData; + SBR_ERROR sbrError = SBRDEC_OK; + int numAnalysisBands; + + if ( sampleRateIn == sampleRateOut ) { + hHeaderData->sbrProcSmplRate = sampleRateOut<<1; + numAnalysisBands = 32; + } else { + hHeaderData->sbrProcSmplRate = sampleRateOut; + if ( (sampleRateOut>>1) == sampleRateIn) { + /* 1:2 */ + numAnalysisBands = 32; + } else if ( (sampleRateOut>>2) == sampleRateIn ) { + /* 1:4 */ + numAnalysisBands = 32; + } else if ( (sampleRateOut*3)>>3 == (sampleRateIn*8)>>3 ) { + /* 3:8, 3/4 core frame length */ + numAnalysisBands = 24; + } else { + sbrError = SBRDEC_UNSUPPORTED_CONFIG; + goto bail; + } + } + + /* Fill in default values first */ + hHeaderData->syncState = SBR_NOT_INITIALIZED; + hHeaderData->status = 0; + hHeaderData->frameErrorFlag = 0; + + hHeaderData->bs_info.ampResolution = 1; + hHeaderData->bs_info.xover_band = 0; + hHeaderData->bs_info.sbr_preprocessing = 0; + + hHeaderData->bs_data.startFreq = 5; + hHeaderData->bs_data.stopFreq = 0; + hHeaderData->bs_data.freqScale = 2; + hHeaderData->bs_data.alterScale = 1; + hHeaderData->bs_data.noise_bands = 2; + hHeaderData->bs_data.limiterBands = 2; + hHeaderData->bs_data.limiterGains = 2; + hHeaderData->bs_data.interpolFreq = 1; + hHeaderData->bs_data.smoothingLength = 1; + + hHeaderData->timeStep = (flags & SBRDEC_ELD_GRID) ? 1 : 2; + + /* Setup pointers to frequency band tables */ + hFreq->freqBandTable[0] = hFreq->freqBandTableLo; + hFreq->freqBandTable[1] = hFreq->freqBandTableHi; + + /* Patch some entries */ + if (sampleRateOut > 24000) { /* Trigger an error if SBR is going to be processed without */ + hHeaderData->bs_data.startFreq = 7; /* having read these frequency values from bit stream before. */ + hHeaderData->bs_data.stopFreq = 3; + } + + /* One SBR timeslot corresponds to the amount of samples equal to the amount of analysis bands, divided by the timestep. */ + hHeaderData->numberTimeSlots = (samplesPerFrame/numAnalysisBands) >> (hHeaderData->timeStep - 1); + hHeaderData->numberOfAnalysisBands = numAnalysisBands; + +bail: + return sbrError; +} + + +/*! + \brief Initialize the SBR_PREV_FRAME_DATA struct +*/ +void +initSbrPrevFrameData (HANDLE_SBR_PREV_FRAME_DATA h_prev_data, /*!< handle to struct SBR_PREV_FRAME_DATA */ + int timeSlots) /*!< Framelength in SBR-timeslots */ +{ + int i; + + /* Set previous energy and noise levels to 0 for the case + that decoding starts in the middle of a bitstream */ + for (i=0; i < MAX_FREQ_COEFFS; i++) + h_prev_data->sfb_nrg_prev[i] = (FIXP_DBL)0; + for (i=0; i < MAX_NOISE_COEFFS; i++) + h_prev_data->prevNoiseLevel[i] = (FIXP_DBL)0; + for (i=0; i < MAX_INVF_BANDS; i++) + h_prev_data->sbr_invf_mode[i] = INVF_OFF; + + h_prev_data->stopPos = timeSlots; + h_prev_data->coupling = COUPLING_OFF; + h_prev_data->ampRes = 0; +} + + +/*! + \brief Read header data from bitstream + + \return error status - 0 if ok +*/ +SBR_HEADER_STATUS +sbrGetHeaderData (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_FDK_BITSTREAM hBs, + const UINT flags, + const int fIsSbrData) +{ + SBR_HEADER_DATA_BS *pBsData; + SBR_HEADER_DATA_BS lastHeader; + SBR_HEADER_DATA_BS_INFO lastInfo; + int headerExtra1=0, headerExtra2=0; + + /* Copy SBR bit stream header to temporary header */ + lastHeader = hHeaderData->bs_data; + lastInfo = hHeaderData->bs_info; + + /* Read new header from bitstream */ + { + pBsData = &hHeaderData->bs_data; + } + + { + hHeaderData->bs_info.ampResolution = FDKreadBits (hBs, 1); + } + + pBsData->startFreq = FDKreadBits (hBs, 4); + pBsData->stopFreq = FDKreadBits (hBs, 4); + + { + hHeaderData->bs_info.xover_band = FDKreadBits (hBs, 3); + FDKreadBits (hBs, 2); + } + + headerExtra1 = FDKreadBits (hBs, 1); + headerExtra2 = FDKreadBits (hBs, 1); + + /* Handle extra header information */ + if( headerExtra1) + { + pBsData->freqScale = FDKreadBits (hBs, 2); + pBsData->alterScale = FDKreadBits (hBs, 1); + pBsData->noise_bands = FDKreadBits (hBs, 2); + } + else { + pBsData->freqScale = 2; + pBsData->alterScale = 1; + pBsData->noise_bands = 2; + } + + if (headerExtra2) { + pBsData->limiterBands = FDKreadBits (hBs, 2); + pBsData->limiterGains = FDKreadBits (hBs, 2); + pBsData->interpolFreq = FDKreadBits (hBs, 1); + pBsData->smoothingLength = FDKreadBits (hBs, 1); + } + else { + pBsData->limiterBands = 2; + pBsData->limiterGains = 2; + pBsData->interpolFreq = 1; + pBsData->smoothingLength = 1; + } + + /* Look for new settings. IEC 14496-3, 4.6.18.3.1 */ + if(hHeaderData->syncState != SBR_ACTIVE || + lastHeader.startFreq != pBsData->startFreq || + lastHeader.stopFreq != pBsData->stopFreq || + lastHeader.freqScale != pBsData->freqScale || + lastHeader.alterScale != pBsData->alterScale || + lastHeader.noise_bands != pBsData->noise_bands || + lastInfo.xover_band != hHeaderData->bs_info.xover_band) { + return HEADER_RESET; /* New settings */ + } + + return HEADER_OK; +} + +/*! + \brief Get missing harmonics parameters (only used for AAC+SBR) + + \return error status - 0 if ok +*/ +int +sbrGetSyntheticCodedData(HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA hFrameData, + HANDLE_FDK_BITSTREAM hBs) +{ + int i, bitsRead = 0; + + int flag = FDKreadBits(hBs,1); + bitsRead++; + + if(flag){ + for(i=0;ifreqBandData.nSfb[1];i++){ + hFrameData->addHarmonics[i] = FDKreadBits (hBs, 1 ); + bitsRead++; + } + } + else { + for(i=0; iaddHarmonics[i] = 0; + } + return(bitsRead); +} + +/*! + \brief Reads extension data from the bitstream + + The bitstream format allows up to 4 kinds of extended data element. + Extended data may contain several elements, each identified by a 2-bit-ID. + So far, no extended data elements are defined hence the first 2 parameters + are unused. The data should be skipped in order to update the number + of read bits for the consistency check in applySBR(). +*/ +static int extractExtendedData( + HANDLE_SBR_HEADER_DATA hHeaderData, /*!< handle to SBR header */ + HANDLE_FDK_BITSTREAM hBs /*!< Handle to the bit buffer */ + ,HANDLE_PS_DEC hParametricStereoDec /*!< Parametric Stereo Decoder */ + ) { + INT nBitsLeft; + int extended_data; + int i, frameOk = 1; + + + extended_data = FDKreadBits(hBs, 1); + + if (extended_data) { + int cnt; + int bPsRead = 0; + + cnt = FDKreadBits(hBs, 4); + if (cnt == (1<<4)-1) + cnt += FDKreadBits(hBs, 8); + + + nBitsLeft = 8 * cnt; + + /* sanity check for cnt */ + if (nBitsLeft > (INT)FDKgetValidBits(hBs)) { + /* limit nBitsLeft */ + nBitsLeft = (INT)FDKgetValidBits(hBs); + /* set frame error */ + frameOk = 0; + } + + while (nBitsLeft > 7) { + int extension_id = FDKreadBits(hBs, 2); + nBitsLeft -= 2; + + switch(extension_id) { + + + + case EXTENSION_ID_PS_CODING: + + /* Read PS data from bitstream */ + + if (hParametricStereoDec != NULL) { + if(bPsRead && !hParametricStereoDec->bsData[hParametricStereoDec->bsReadSlot].mpeg.bPsHeaderValid) { + cnt = nBitsLeft >> 3; /* number of remaining bytes */ + for (i=0; i> 3; /* number of remaining bytes */ + for (i=0; icoupling = COUPLING_OFF; + + { + /* Reserved bits */ + if (FDKreadBits(hBs, 1)) { /* bs_data_extra */ + FDKreadBits(hBs, 4); + if (flags & SBRDEC_SYNTAX_SCAL) { + FDKreadBits(hBs, 4); + } + } + } + + if (flags & SBRDEC_SYNTAX_SCAL) { + FDKreadBits (hBs, 1); /* bs_coupling */ + } + + /* + Grid control + */ + if ( !extractFrameInfo ( hBs, hHeaderData, hFrameData, 1, flags) ) + return 0; + + if ( !checkFrameInfo (&hFrameData->frameInfo, hHeaderData->numberTimeSlots, overlap, hHeaderData->timeStep) ) + return 0; + + + /* + Fetch domain vectors (time or frequency direction for delta-coding) + */ + sbrGetDirectionControlData (hFrameData, hBs); + + for (i=0; ifreqBandData.nInvfBands; i++) { + hFrameData->sbr_invf_mode[i] = + (INVF_MODE) FDKreadBits (hBs, 2); + } + + + + /* raw data */ + if ( !sbrGetEnvelope (hHeaderData, hFrameData, hBs, flags) ) + return 0; + + + sbrGetNoiseFloorData (hHeaderData, hFrameData, hBs); + + sbrGetSyntheticCodedData(hHeaderData, hFrameData, hBs); + + { + /* sbr extended data */ + if (! extractExtendedData( + hHeaderData, + hBs + ,hParametricStereoDec + )) { + return 0; + } + } + + return 1; +} + + + +/*! + \brief Read bitstream elements of a channel pair + \return SbrFrameOK +*/ +int +sbrGetChannelPairElement (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA hFrameDataLeft, /*!< Dynamic control data for first channel */ + HANDLE_SBR_FRAME_DATA hFrameDataRight,/*!< Dynamic control data for second channel */ + HANDLE_FDK_BITSTREAM hBs, /*!< handle to struct BIT_BUF */ + const UINT flags, + const int overlap ) +{ + int i, bit; + + + /* Reserved bits */ + if (FDKreadBits(hBs, 1)) { /* bs_data_extra */ + FDKreadBits(hBs, 4); + FDKreadBits(hBs, 4); + } + + /* Read coupling flag */ + bit = FDKreadBits (hBs, 1); + + if (bit) { + hFrameDataLeft->coupling = COUPLING_LEVEL; + hFrameDataRight->coupling = COUPLING_BAL; + } + else { + hFrameDataLeft->coupling = COUPLING_OFF; + hFrameDataRight->coupling = COUPLING_OFF; + } + + + /* + Grid control + */ + if ( !extractFrameInfo (hBs, hHeaderData, hFrameDataLeft, 2, flags) ) + return 0; + + if ( !checkFrameInfo (&hFrameDataLeft->frameInfo, hHeaderData->numberTimeSlots, overlap, hHeaderData->timeStep) ) + return 0; + + if (hFrameDataLeft->coupling) { + FDKmemcpy (&hFrameDataRight->frameInfo, &hFrameDataLeft->frameInfo, sizeof(FRAME_INFO)); + hFrameDataRight->ampResolutionCurrentFrame = hFrameDataLeft->ampResolutionCurrentFrame; + } + else { + if ( !extractFrameInfo (hBs, hHeaderData, hFrameDataRight, 2, flags) ) + return 0; + + if ( !checkFrameInfo (&hFrameDataRight->frameInfo, hHeaderData->numberTimeSlots, overlap, hHeaderData->timeStep) ) + return 0; + } + + /* + Fetch domain vectors (time or frequency direction for delta-coding) + */ + sbrGetDirectionControlData (hFrameDataLeft, hBs); + sbrGetDirectionControlData (hFrameDataRight, hBs); + + for (i=0; ifreqBandData.nInvfBands; i++) { + hFrameDataLeft->sbr_invf_mode[i] = (INVF_MODE) FDKreadBits (hBs, 2); + } + + if (hFrameDataLeft->coupling) { + for (i=0; ifreqBandData.nInvfBands; i++) { + hFrameDataRight->sbr_invf_mode[i] = hFrameDataLeft->sbr_invf_mode[i]; + } + + + if ( !sbrGetEnvelope (hHeaderData, hFrameDataLeft, hBs, flags) ) { + return 0; + } + + sbrGetNoiseFloorData (hHeaderData, hFrameDataLeft, hBs); + + if ( !sbrGetEnvelope (hHeaderData, hFrameDataRight, hBs, flags) ) { + return 0; + } + } + else { + + for (i=0; ifreqBandData.nInvfBands; i++) { + hFrameDataRight->sbr_invf_mode[i] = (INVF_MODE) FDKreadBits (hBs, 2); + } + + + + if ( !sbrGetEnvelope (hHeaderData, hFrameDataLeft, hBs, flags) ) + return 0; + + if ( !sbrGetEnvelope (hHeaderData, hFrameDataRight, hBs, flags) ) + return 0; + + sbrGetNoiseFloorData (hHeaderData, hFrameDataLeft, hBs); + + } + sbrGetNoiseFloorData (hHeaderData, hFrameDataRight, hBs); + + sbrGetSyntheticCodedData(hHeaderData, hFrameDataLeft, hBs); + sbrGetSyntheticCodedData(hHeaderData, hFrameDataRight, hBs); + + { + if (! extractExtendedData( + hHeaderData, + hBs + ,NULL + ) ) { + return 0; + } + } + + return 1; +} + + + + +/*! + \brief Read direction control data from bitstream +*/ +void +sbrGetDirectionControlData (HANDLE_SBR_FRAME_DATA h_frame_data, /*!< handle to struct SBR_FRAME_DATA */ + HANDLE_FDK_BITSTREAM hBs) /*!< handle to struct BIT_BUF */ +{ + int i; + + for (i = 0; i < h_frame_data->frameInfo.nEnvelopes; i++) { + h_frame_data->domain_vec[i] = FDKreadBits (hBs, 1); + } + + for (i = 0; i < h_frame_data->frameInfo.nNoiseEnvelopes; i++) { + h_frame_data->domain_vec_noise[i] = FDKreadBits (hBs, 1); + } +} + + + +/*! + \brief Read noise-floor-level data from bitstream +*/ +void +sbrGetNoiseFloorData (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_frame_data, /*!< handle to struct SBR_FRAME_DATA */ + HANDLE_FDK_BITSTREAM hBs) /*!< handle to struct BIT_BUF */ +{ + int i,j; + int delta; + COUPLING_MODE coupling; + int noNoiseBands = hHeaderData->freqBandData.nNfb; + + Huffman hcb_noiseF; + Huffman hcb_noise; + int envDataTableCompFactor; + + coupling = h_frame_data->coupling; + + + /* + Select huffman codebook depending on coupling mode + */ + if (coupling == COUPLING_BAL) { + hcb_noise = (Huffman)&FDK_sbrDecoder_sbr_huffBook_NoiseBalance11T; + hcb_noiseF = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvBalance11F; /* "sbr_huffBook_NoiseBalance11F" */ + envDataTableCompFactor = 1; + } + else { + hcb_noise = (Huffman)&FDK_sbrDecoder_sbr_huffBook_NoiseLevel11T; + hcb_noiseF = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvLevel11F; /* "sbr_huffBook_NoiseLevel11F" */ + envDataTableCompFactor = 0; + } + + /* + Read raw noise-envelope data + */ + for (i=0; iframeInfo.nNoiseEnvelopes; i++) { + + + if (h_frame_data->domain_vec_noise[i] == 0) { + if (coupling == COUPLING_BAL) { + h_frame_data->sbrNoiseFloorLevel[i*noNoiseBands] = + (FIXP_SGL) (((int)FDKreadBits (hBs, 5)) << envDataTableCompFactor); + } + else { + h_frame_data->sbrNoiseFloorLevel[i*noNoiseBands] = + (FIXP_SGL) (int)FDKreadBits (hBs, 5); + } + + for (j = 1; j < noNoiseBands; j++) { + delta = DecodeHuffmanCW(hcb_noiseF, hBs); + h_frame_data->sbrNoiseFloorLevel[i*noNoiseBands+j] = (FIXP_SGL) (delta << envDataTableCompFactor); + } + } + else { + for (j = 0; j < noNoiseBands; j++) { + delta = DecodeHuffmanCW(hcb_noise, hBs); + h_frame_data->sbrNoiseFloorLevel[i*noNoiseBands+j] = (FIXP_SGL) (delta << envDataTableCompFactor); + } + } + } +} + + +/*! + \brief Read envelope data from bitstream +*/ +static int +sbrGetEnvelope (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_frame_data, /*!< handle to struct SBR_FRAME_DATA */ + HANDLE_FDK_BITSTREAM hBs, /*!< handle to struct BIT_BUF */ + const UINT flags) +{ + int i, j; + UCHAR no_band[MAX_ENVELOPES]; + int delta = 0; + int offset = 0; + COUPLING_MODE coupling = h_frame_data->coupling; + int ampRes = hHeaderData->bs_info.ampResolution; + int nEnvelopes = h_frame_data->frameInfo.nEnvelopes; + int envDataTableCompFactor; + int start_bits, start_bits_balance; + Huffman hcb_t, hcb_f; + + h_frame_data->nScaleFactors = 0; + + if ( (h_frame_data->frameInfo.frameClass == 0) && (nEnvelopes == 1) ) { + if (flags & SBRDEC_ELD_GRID) + ampRes = h_frame_data->ampResolutionCurrentFrame; + else + ampRes = 0; + } + h_frame_data->ampResolutionCurrentFrame = ampRes; + + /* + Set number of bits for first value depending on amplitude resolution + */ + if(ampRes == 1) + { + start_bits = 6; + start_bits_balance = 5; + } + else + { + start_bits = 7; + start_bits_balance = 6; + } + + /* + Calculate number of values for each envelope and alltogether + */ + for (i = 0; i < nEnvelopes; i++) { + no_band[i] = hHeaderData->freqBandData.nSfb[h_frame_data->frameInfo.freqRes[i]]; + h_frame_data->nScaleFactors += no_band[i]; + } + if (h_frame_data->nScaleFactors > MAX_NUM_ENVELOPE_VALUES) + return 0; + + /* + Select Huffman codebook depending on coupling mode and amplitude resolution + */ + if (coupling == COUPLING_BAL) { + envDataTableCompFactor = 1; + if (ampRes == 0) { + hcb_t = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvBalance10T; + hcb_f = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvBalance10F; + } + else { + hcb_t = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvBalance11T; + hcb_f = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvBalance11F; + } + } + else { + envDataTableCompFactor = 0; + if (ampRes == 0) { + hcb_t = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvLevel10T; + hcb_f = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvLevel10F; + } + else { + hcb_t = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvLevel11T; + hcb_f = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvLevel11F; + } + } + + /* + Now read raw envelope data + */ + for (j = 0, offset = 0; j < nEnvelopes; j++) { + + + if (h_frame_data->domain_vec[j] == 0) { + if (coupling == COUPLING_BAL) { + h_frame_data->iEnvelope[offset] = + (FIXP_SGL) (( (int)FDKreadBits(hBs, start_bits_balance)) << envDataTableCompFactor); + } + else { + h_frame_data->iEnvelope[offset] = + (FIXP_SGL) (int)FDKreadBits (hBs, start_bits); + } + } + + for (i = (1 - h_frame_data->domain_vec[j]); i < no_band[j]; i++) { + + if (h_frame_data->domain_vec[j] == 0) { + delta = DecodeHuffmanCW(hcb_f, hBs); + } + else { + delta = DecodeHuffmanCW(hcb_t, hBs); + } + + h_frame_data->iEnvelope[offset + i] = (FIXP_SGL) (delta << envDataTableCompFactor); + } + offset += no_band[j]; + } + +#if ENV_EXP_FRACT + /* Convert from int to scaled fract (ENV_EXP_FRACT bits for the fractional part) */ + for (i = 0; i < h_frame_data->nScaleFactors; i++) { + h_frame_data->iEnvelope[i] <<= ENV_EXP_FRACT; + } +#endif + + return 1; +} + + +//static const FRAME_INFO v_frame_info1_8 = { 0, 1, {0, 8}, {1}, -1, 1, {0, 8} }; +static const FRAME_INFO v_frame_info2_8 = { 0, 2, {0, 4, 8}, {1, 1}, -1, 2, {0, 4, 8} }; +static const FRAME_INFO v_frame_info4_8 = { 0, 4, {0, 2, 4, 6, 8}, {1, 1, 1, 1}, -1, 2, {0, 4, 8} }; + +/***************************************************************************/ +/*! + \brief Generates frame info for FIXFIXonly frame class used for low delay version + + \return nothing + ****************************************************************************/ + static void generateFixFixOnly ( FRAME_INFO *hSbrFrameInfo, + int tranPosInternal, + int numberTimeSlots + ) +{ + int nEnv, i, tranIdx; + const int *pTable; + + switch (numberTimeSlots) { + case 8: + pTable = FDK_sbrDecoder_envelopeTable_8[tranPosInternal]; + break; + case 15: + pTable = FDK_sbrDecoder_envelopeTable_15[tranPosInternal]; + break; + case 16: + pTable = FDK_sbrDecoder_envelopeTable_16[tranPosInternal]; + break; + default: + FDK_ASSERT(0); + } + + /* look number of envelopes in table */ + nEnv = pTable[0]; + /* look up envelope distribution in table */ + for (i=1; iborders[i] = pTable[i+2]; + /* open and close frame border */ + hSbrFrameInfo->borders[0] = 0; + hSbrFrameInfo->borders[nEnv] = numberTimeSlots; + hSbrFrameInfo->nEnvelopes = nEnv; + + /* transient idx */ + tranIdx = hSbrFrameInfo->tranEnv = pTable[1]; + + /* add noise floors */ + hSbrFrameInfo->bordersNoise[0] = 0; + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[tranIdx?tranIdx:1]; + hSbrFrameInfo->bordersNoise[2] = numberTimeSlots; + /* nEnv is always > 1, so nNoiseEnvelopes is always 2 (IEC 14496-3 4.6.19.3.2) */ + hSbrFrameInfo->nNoiseEnvelopes = 2; +} + +/*! + \brief Extracts LowDelaySBR control data from the bitstream. + + \return zero for bitstream error, one for correct. +*/ +static int +extractLowDelayGrid (HANDLE_FDK_BITSTREAM hBitBuf, /*!< bitbuffer handle */ + HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_frame_data, /*!< contains the FRAME_INFO struct to be filled */ + int timeSlots + ) +{ + FRAME_INFO * pFrameInfo = &h_frame_data->frameInfo; + INT numberTimeSlots = hHeaderData->numberTimeSlots; + INT temp = 0, k; + + /* FIXFIXonly framing case */ + h_frame_data->frameInfo.frameClass = 0; + + /* get the transient position from the bitstream */ + switch (timeSlots){ + case 8: + /* 3bit transient position (temp={0;..;7}) */ + temp = FDKreadBits( hBitBuf, 3); + break; + + case 16: + case 15: + /* 4bit transient position (temp={0;..;15}) */ + temp = FDKreadBits( hBitBuf, 4); + break; + + default: + return 0; + } + + /* calculate borders according to the transient position */ + generateFixFixOnly ( pFrameInfo, + temp, + numberTimeSlots + ); + + /* decode freq res: */ + for (k = 0; k < pFrameInfo->nEnvelopes; k++) { + pFrameInfo->freqRes[k] = (UCHAR) FDKreadBits (hBitBuf, 1); /* f = F [1 bits] */ + } + + + return 1; +} + +/*! + \brief Extract the frame information (structure FRAME_INFO) from the bitstream + \return Zero for bitstream error, one for correct. +*/ +int +extractFrameInfo ( HANDLE_FDK_BITSTREAM hBs, /*!< bitbuffer handle */ + HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_frame_data, /*!< pointer to memory where the frame-info will be stored */ + const UINT nrOfChannels, + const UINT flags + ) +{ + FRAME_INFO * pFrameInfo = &h_frame_data->frameInfo; + int numberTimeSlots = hHeaderData->numberTimeSlots; + int pointer_bits = 0, nEnv = 0, b = 0, border, i, n = 0, + k, p, aL, aR, nL, nR, + temp = 0, staticFreqRes; + UCHAR frameClass; + + if (flags & SBRDEC_ELD_GRID) { + /* CODEC_AACLD (LD+SBR) only uses the normal 0 Grid for non-transient Frames and the LowDelayGrid for transient Frames */ + frameClass = FDKreadBits (hBs, 1); /* frameClass = [1 bit] */ + if ( frameClass == 1 ) { + /* if frameClass == 1, extract LowDelaySbrGrid, otherwise extract normal SBR-Grid for FIXIFX */ + /* extract the AACLD-Sbr-Grid */ + pFrameInfo->frameClass = frameClass; + extractLowDelayGrid (hBs, hHeaderData, h_frame_data, numberTimeSlots); + return 1; + } + } else + { + frameClass = FDKreadBits (hBs, 2); /* frameClass = C [2 bits] */ + } + + + switch (frameClass) { + case 0: + temp = FDKreadBits (hBs, 2); /* E [2 bits ] */ + nEnv = (int) (1 << temp); /* E -> e */ + + if ((flags & SBRDEC_ELD_GRID) && (nEnv == 1)) + h_frame_data->ampResolutionCurrentFrame = FDKreadBits( hBs, 1); /* new ELD Syntax 07-11-09 */ + + staticFreqRes = FDKreadBits (hBs, 1); + + { + if (nEnv > MAX_ENVELOPES_HEAAC) + return 0; + } + + b = nEnv + 1; + switch (nEnv) { + case 1: + switch (numberTimeSlots) { + case 15: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info1_15, sizeof(FRAME_INFO)); + break; + case 16: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info1_16, sizeof(FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; + case 2: + switch (numberTimeSlots) { + case 15: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info2_15, sizeof(FRAME_INFO)); + break; + case 16: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info2_16, sizeof(FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; + case 4: + switch (numberTimeSlots) { + case 15: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info4_15, sizeof(FRAME_INFO)); + break; + case 16: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info4_16, sizeof(FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; + case 8: +#if (MAX_ENVELOPES >= 8) + switch (numberTimeSlots) { + case 15: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info8_15, sizeof(FRAME_INFO)); + break; + case 16: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info8_16, sizeof(FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; +#else + return 0; +#endif + } + /* Apply correct freqRes (High is default) */ + if (!staticFreqRes) { + for (i = 0; i < nEnv ; i++) + pFrameInfo->freqRes[i] = 0; + } + + break; + case 1: + case 2: + temp = FDKreadBits (hBs, 2); /* A [2 bits] */ + + n = FDKreadBits (hBs, 2); /* n = N [2 bits] */ + + nEnv = n + 1; /* # envelopes */ + b = nEnv + 1; /* # borders */ + + break; + } + + switch (frameClass) { + case 1: + /* Decode borders: */ + pFrameInfo->borders[0] = 0; /* first border */ + border = temp + numberTimeSlots; /* A -> aR */ + i = b-1; /* frame info index for last border */ + pFrameInfo->borders[i] = border; /* last border */ + + for (k = 0; k < n; k++) { + temp = FDKreadBits (hBs, 2);/* R [2 bits] */ + border -= (2 * temp + 2); /* R -> r */ + pFrameInfo->borders[--i] = border; + } + + + /* Decode pointer: */ + pointer_bits = DFRACT_BITS - 1 - CountLeadingBits((FIXP_DBL)(n+1)); + p = FDKreadBits (hBs, pointer_bits); /* p = P [pointer_bits bits] */ + + if (p > n+1) + return 0; + + pFrameInfo->tranEnv = p ? n + 2 - p : -1; + + + /* Decode freq res: */ + for (k = n; k >= 0; k--) { + pFrameInfo->freqRes[k] = FDKreadBits (hBs, 1); /* f = F [1 bits] */ + } + + + /* Calculate noise floor middle border: */ + if (p == 0 || p == 1) + pFrameInfo->bordersNoise[1] = pFrameInfo->borders[n]; + else + pFrameInfo->bordersNoise[1] = pFrameInfo->borders[pFrameInfo->tranEnv]; + + break; + + case 2: + /* Decode borders: */ + border = temp; /* A -> aL */ + pFrameInfo->borders[0] = border; /* first border */ + + for (k = 1; k <= n; k++) { + temp = FDKreadBits (hBs, 2);/* R [2 bits] */ + border += (2 * temp + 2); /* R -> r */ + pFrameInfo->borders[k] = border; + } + pFrameInfo->borders[k] = numberTimeSlots; /* last border */ + + + /* Decode pointer: */ + pointer_bits = DFRACT_BITS - 1 - CountLeadingBits((FIXP_DBL)(n+1)); + p = FDKreadBits (hBs, pointer_bits); /* p = P [pointer_bits bits] */ + if (p > n+1) + return 0; + + if (p == 0 || p == 1) + pFrameInfo->tranEnv = -1; + else + pFrameInfo->tranEnv = p - 1; + + + + /* Decode freq res: */ + for (k = 0; k <= n; k++) { + pFrameInfo->freqRes[k] = FDKreadBits(hBs, 1); /* f = F [1 bits] */ + } + + + + /* Calculate noise floor middle border: */ + switch (p) { + case 0: + pFrameInfo->bordersNoise[1] = pFrameInfo->borders[1]; + break; + case 1: + pFrameInfo->bordersNoise[1] = pFrameInfo->borders[n]; + break; + default: + pFrameInfo->bordersNoise[1] = pFrameInfo->borders[pFrameInfo->tranEnv]; + break; + } + + break; + + case 3: + /* v_ctrlSignal = [frameClass,aL,aR,nL,nR,v_rL,v_rR,p,v_fLR]; */ + + aL = FDKreadBits (hBs, 2); /* AL [2 bits], AL -> aL */ + + aR = FDKreadBits (hBs, 2) + numberTimeSlots; /* AR [2 bits], AR -> aR */ + + nL = FDKreadBits (hBs, 2); /* nL = NL [2 bits] */ + + nR = FDKreadBits (hBs, 2); /* nR = NR [2 bits] */ + + + + /*------------------------------------------------------------------------- + Calculate help variables + --------------------------------------------------------------------------*/ + + /* general: */ + nEnv = nL + nR + 1; /* # envelopes */ + if (nEnv > MAX_ENVELOPES) + return 0; + b = nEnv + 1; /* # borders */ + + + + /*------------------------------------------------------------------------- + Decode envelopes + --------------------------------------------------------------------------*/ + + + /* L-borders: */ + border = aL; /* first border */ + pFrameInfo->borders[0] = border; + + for (k = 1; k <= nL; k++) { + temp = FDKreadBits (hBs, 2);/* R [2 bits] */ + border += (2 * temp + 2); /* R -> r */ + pFrameInfo->borders[k] = border; + } + + + /* R-borders: */ + border = aR; /* last border */ + i = nEnv; + + pFrameInfo->borders[i] = border; + + for (k = 0; k < nR; k++) { + temp = FDKreadBits (hBs, 2);/* R [2 bits] */ + border -= (2 * temp + 2); /* R -> r */ + pFrameInfo->borders[--i] = border; + } + + + /* decode pointer: */ + pointer_bits = DFRACT_BITS - 1 - CountLeadingBits((FIXP_DBL)(nL+nR+1)); + p = FDKreadBits (hBs, pointer_bits); /* p = P [pointer_bits bits] */ + + if (p > nL+nR+1) + return 0; + + pFrameInfo->tranEnv = p ? b - p : -1; + + + + /* decode freq res: */ + for (k = 0; k < nEnv; k++) { + pFrameInfo->freqRes[k] = FDKreadBits(hBs, 1); /* f = F [1 bits] */ + } + + + + /*------------------------------------------------------------------------- + Decode noise floors + --------------------------------------------------------------------------*/ + pFrameInfo->bordersNoise[0] = aL; + + if (nEnv == 1) { + /* 1 noise floor envelope: */ + pFrameInfo->bordersNoise[1] = aR; + } + else { + /* 2 noise floor envelopes */ + if (p == 0 || p == 1) + pFrameInfo->bordersNoise[1] = pFrameInfo->borders[nEnv - 1]; + else + pFrameInfo->bordersNoise[1] = pFrameInfo->borders[pFrameInfo->tranEnv]; + pFrameInfo->bordersNoise[2] = aR; + } + break; + } + + + /* + Store number of envelopes, noise floor envelopes and frame class + */ + pFrameInfo->nEnvelopes = nEnv; + + if (nEnv == 1) + pFrameInfo->nNoiseEnvelopes = 1; + else + pFrameInfo->nNoiseEnvelopes = 2; + + pFrameInfo->frameClass = frameClass; + + if (pFrameInfo->frameClass == 2 || pFrameInfo->frameClass == 1) { + /* calculate noise floor first and last borders: */ + pFrameInfo->bordersNoise[0] = pFrameInfo->borders[0]; + pFrameInfo->bordersNoise[pFrameInfo->nNoiseEnvelopes] = pFrameInfo->borders[nEnv]; + } + + + return 1; +} + + +/*! + \brief Check if the frameInfo vector has reasonable values. + \return Zero for error, one for correct +*/ +static int +checkFrameInfo (FRAME_INFO * pFrameInfo, /*!< pointer to frameInfo */ + int numberOfTimeSlots, /*!< QMF time slots per frame */ + int overlap, /*!< Amount of overlap QMF time slots */ + int timeStep) /*!< QMF slots to SBR slots step factor */ +{ + int maxPos,i,j; + int startPos; + int stopPos; + int tranEnv; + int startPosNoise; + int stopPosNoise; + int nEnvelopes = pFrameInfo->nEnvelopes; + int nNoiseEnvelopes = pFrameInfo->nNoiseEnvelopes; + + if(nEnvelopes < 1 || nEnvelopes > MAX_ENVELOPES) + return 0; + + if(nNoiseEnvelopes > MAX_NOISE_ENVELOPES) + return 0; + + startPos = pFrameInfo->borders[0]; + stopPos = pFrameInfo->borders[nEnvelopes]; + tranEnv = pFrameInfo->tranEnv; + startPosNoise = pFrameInfo->bordersNoise[0]; + stopPosNoise = pFrameInfo->bordersNoise[nNoiseEnvelopes]; + + if (overlap < 0 || overlap > (6)) { + return 0; + } + if (timeStep < 1 || timeStep > 2) { + return 0; + } + maxPos = numberOfTimeSlots + (overlap/timeStep); + + /* Check that the start and stop positions of the frame are reasonable values. */ + if( (startPos < 0) || (startPos >= stopPos) ) + return 0; + if( startPos > maxPos-numberOfTimeSlots ) /* First env. must start in or directly after the overlap buffer */ + return 0; + if( stopPos < numberOfTimeSlots ) /* One complete frame must be ready for output after processing */ + return 0; + if(stopPos > maxPos) + return 0; + + /* Check that the start border for every envelope is strictly later in time */ + for(i=0;iborders[i] >= pFrameInfo->borders[i+1]) + return 0; + } + + /* Check that the envelope to be shortened is actually among the envelopes */ + if(tranEnv>nEnvelopes) + return 0; + + + /* Check the noise borders */ + if(nEnvelopes==1 && nNoiseEnvelopes>1) + return 0; + + if(startPos != startPosNoise || stopPos != stopPosNoise) + return 0; + + + /* Check that the start border for every noise-envelope is strictly later in time*/ + for(i=0; ibordersNoise[i] >= pFrameInfo->bordersNoise[i+1]) + return 0; + } + + /* Check that every noise border is the same as an envelope border*/ + for(i=0; ibordersNoise[i]; + + for(j=0; jborders[j] == startPosNoise) + break; + } + if(j==nEnvelopes) + return 0; + } + + return 1; +} diff --git a/libSBRdec/src/env_extr.h b/libSBRdec/src/env_extr.h new file mode 100644 index 0000000..23721a8 --- /dev/null +++ b/libSBRdec/src/env_extr.h @@ -0,0 +1,261 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Envelope extraction prototypes $Revision: 36841 $ +*/ + +#ifndef __ENVELOPE_EXTRACTION_H +#define __ENVELOPE_EXTRACTION_H + +#include "sbrdecoder.h" + +#include "FDK_bitstream.h" +#include "lpp_tran.h" + +#include "psdec.h" + +#define ENV_EXP_FRACT 0 +/*!< Shift raw envelope data to support fractional numbers. + Can be set to 8 instead of 0 to enhance accuracy during concealment. + This is not required for conformance and #requantizeEnvelopeData() will + become more expensive. +*/ + +#define EXP_BITS 6 +/*!< Size of exponent-part of a pseudo float envelope value (should be at least 6). + The remaining bits in each word are used for the mantissa (should be at least 10). + This format is used in the arrays iEnvelope[] and sbrNoiseFloorLevel[] + in the FRAME_DATA struct which must fit in a certain part of the output buffer + (See buffer management in sbr_dec.cpp). + Exponents and mantissas could also be stored in separate arrays. + Accessing the exponent or the mantissa would be simplified and the masks #MASK_E + resp. #MASK_M would no longer be required. +*/ + +#define MASK_M (((1 << (FRACT_BITS - EXP_BITS)) - 1) << EXP_BITS) /*!< Mask for extracting the mantissa of a pseudo float envelope value */ +#define MASK_E ((1 << EXP_BITS) - 1) /*!< Mask for extracting the exponent of a pseudo float envelope value */ + +#define SIGN_EXT ( ((SCHAR)-1) ^ MASK_E) /*!< a CHAR-constant with all bits above our sign-bit set */ +#define ROUNDING ( (FIXP_SGL)(1<<(EXP_BITS-1)) ) /*!< 0.5-offset for rounding the mantissa of a pseudo-float envelope value */ +#define NRG_EXP_OFFSET 16 /*!< Will be added to the reference energy's exponent to prevent negative numbers */ +#define NOISE_EXP_OFFSET 38 /*!< Will be added to the noise level exponent to prevent negative numbers */ + +typedef enum +{ + HEADER_NOT_PRESENT, + HEADER_OK, + HEADER_RESET +} +SBR_HEADER_STATUS; + +typedef enum +{ + SBR_NOT_INITIALIZED, + UPSAMPLING, + SBR_HEADER, + SBR_ACTIVE +} +SBR_SYNC_STATE; + + +typedef enum +{ + COUPLING_OFF = 0, + COUPLING_LEVEL, + COUPLING_BAL +} +COUPLING_MODE; + +typedef struct +{ + UCHAR nSfb[2]; /*!< Number of SBR-bands for low and high freq-resolution */ + UCHAR nNfb; /*!< Actual number of noise bands to read from the bitstream*/ + UCHAR numMaster; /*!< Number of SBR-bands in v_k_master */ + UCHAR lowSubband; /*!< QMF-band where SBR frequency range starts */ + UCHAR highSubband; /*!< QMF-band where SBR frequency range ends */ + UCHAR limiterBandTable[MAX_NUM_LIMITERS+1]; /*!< Limiter band table. */ + UCHAR noLimiterBands; /*!< Number of limiter bands. */ + UCHAR nInvfBands; /*!< Number of bands for inverse filtering */ + UCHAR *freqBandTable[2]; /*!< Pointers to freqBandTableLo and freqBandTableHi */ + UCHAR freqBandTableLo[MAX_FREQ_COEFFS/2+1]; + /*!< Mapping of SBR bands to QMF bands for low frequency resolution */ + UCHAR freqBandTableHi[MAX_FREQ_COEFFS+1]; + /*!< Mapping of SBR bands to QMF bands for high frequency resolution */ + UCHAR freqBandTableNoise[MAX_NOISE_COEFFS+1]; + /*!< Mapping of SBR noise bands to QMF bands */ + UCHAR v_k_master[MAX_FREQ_COEFFS+1]; + /*!< Master BandTable which freqBandTable is derived from */ +} +FREQ_BAND_DATA; + +typedef FREQ_BAND_DATA *HANDLE_FREQ_BAND_DATA; + +#define SBRDEC_ELD_GRID 1 +#define SBRDEC_SYNTAX_SCAL 2 +#define SBRDEC_SYNTAX_USAC 4 +#define SBRDEC_SYNTAX_RSVD50 8 +#define SBRDEC_LOW_POWER 16 /* Flag indicating that Low Power QMF mode shall be used. */ +#define SBRDEC_PS_DECODED 32 /* Flag indicating that PS was decoded and rendered. */ +#define SBRDEC_LD_MPS_QMF 512 /* Flag indicating that the LD-MPS QMF shall be used. */ + +#define SBRDEC_HDR_STAT_RESET 1 +#define SBRDEC_HDR_STAT_UPDATE 2 + +typedef struct { + UCHAR ampResolution; /*!< Amplitude resolution of envelope values (0: 1.5dB, 1: 3dB) */ + UCHAR xover_band; /*!< Start index in #v_k_master[] used for dynamic crossover frequency */ + UCHAR sbr_preprocessing; /*!< SBR prewhitening flag. */ +} SBR_HEADER_DATA_BS_INFO; + +typedef struct { + /* Changes in these variables causes a reset of the decoder */ + UCHAR startFreq; /*!< Index for SBR start frequency */ + UCHAR stopFreq; /*!< Index for SBR highest frequency */ + UCHAR freqScale; /*!< 0: linear scale, 1-3 logarithmic scales */ + UCHAR alterScale; /*!< Flag for coarser frequency resolution */ + UCHAR noise_bands; /*!< Noise bands per octave, read from bitstream*/ + + /* don't require reset */ + UCHAR limiterBands; /*!< Index for number of limiter bands per octave */ + UCHAR limiterGains; /*!< Index to select gain limit */ + UCHAR interpolFreq; /*!< Select gain calculation method (1: per QMF channel, 0: per SBR band) */ + UCHAR smoothingLength; /*!< Smoothing of gains over time (0: on 1: off) */ + +} SBR_HEADER_DATA_BS; + +typedef struct +{ + SBR_SYNC_STATE syncState; /*!< The current initialization status of the header */ + + UCHAR status; /*!< Flags field used for signaling a reset right before the processing starts and an update from config (e.g. ASC). */ + UCHAR frameErrorFlag; /*!< Frame data valid flag. CAUTION: This variable will be overwritten by the flag stored in the element structure. + This is necessary because of the frame delay. There it might happen that different slots use the same header. */ + UCHAR numberTimeSlots; /*!< AAC: 16,15 */ + UCHAR numberOfAnalysisBands; /*!< Number of QMF analysis bands */ + UCHAR timeStep; /*!< Time resolution of SBR in QMF-slots */ + UINT sbrProcSmplRate; /*!< SBR processing sampling frequency (!= OutputSamplingRate) + (always: CoreSamplingRate * UpSamplingFactor; even in single rate mode) */ + + SBR_HEADER_DATA_BS bs_data; /*!< current SBR header. */ + SBR_HEADER_DATA_BS_INFO bs_info; /*!< SBR info. */ + + FREQ_BAND_DATA freqBandData; /*!< Pointer to struct #FREQ_BAND_DATA */ +} +SBR_HEADER_DATA; + +typedef SBR_HEADER_DATA *HANDLE_SBR_HEADER_DATA; + + +typedef struct +{ + UCHAR frameClass; /*!< Select grid type */ + UCHAR nEnvelopes; /*!< Number of envelopes */ + UCHAR borders[MAX_ENVELOPES+1]; /*!< Envelope borders (in SBR-timeslots, e.g. mp3PRO: 0..11) */ + UCHAR freqRes[MAX_ENVELOPES]; /*!< Frequency resolution for each envelope (0=low, 1=high) */ + SCHAR tranEnv; /*!< Transient envelope, -1 if none */ + UCHAR nNoiseEnvelopes; /*!< Number of noise envelopes */ + UCHAR bordersNoise[MAX_NOISE_ENVELOPES+1];/*!< borders of noise envelopes */ +} +FRAME_INFO; + + +typedef struct +{ + FIXP_SGL sfb_nrg_prev[MAX_FREQ_COEFFS]; /*!< Previous envelope (required for differential-coded values) */ + FIXP_SGL prevNoiseLevel[MAX_NOISE_COEFFS]; /*!< Previous noise envelope (required for differential-coded values) */ + COUPLING_MODE coupling; /*!< Stereo-mode of previous frame */ + INVF_MODE sbr_invf_mode[MAX_INVF_BANDS]; /*!< Previous strength of filtering in transposer */ + UCHAR ampRes; /*!< Previous amplitude resolution (0: 1.5dB, 1: 3dB) */ + UCHAR stopPos; /*!< Position in time where last envelope ended */ + UCHAR frameErrorFlag; /*!< Previous frame status */ +} +SBR_PREV_FRAME_DATA; + +typedef SBR_PREV_FRAME_DATA *HANDLE_SBR_PREV_FRAME_DATA; + + +typedef struct +{ + int nScaleFactors; /*!< total number of scalefactors in frame */ + + FRAME_INFO frameInfo; /*!< time grid for current frame */ + UCHAR domain_vec[MAX_ENVELOPES]; /*!< Bitfield containing direction of delta-coding for each envelope (0:frequency, 1:time) */ + UCHAR domain_vec_noise[MAX_NOISE_ENVELOPES]; /*!< Same as above, but for noise envelopes */ + + INVF_MODE sbr_invf_mode[MAX_INVF_BANDS]; /*!< Strength of filtering in transposer */ + COUPLING_MODE coupling; /*!< Stereo-mode */ + int ampResolutionCurrentFrame; /*!< Amplitude resolution of envelope values (0: 1.5dB, 1: 3dB) */ + + UCHAR addHarmonics[MAX_FREQ_COEFFS]; /*!< Flags for synthetic sine addition */ + + FIXP_SGL iEnvelope[MAX_NUM_ENVELOPE_VALUES]; /*!< Envelope data */ + FIXP_SGL sbrNoiseFloorLevel[MAX_NUM_NOISE_VALUES]; /*!< Noise envelope data */ +} +SBR_FRAME_DATA; + +typedef SBR_FRAME_DATA *HANDLE_SBR_FRAME_DATA; + +void initSbrPrevFrameData (HANDLE_SBR_PREV_FRAME_DATA h_prev_data, + int timeSlots); + + +int sbrGetSingleChannelElement (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA hFrameData, + HANDLE_FDK_BITSTREAM hBitBuf, + HANDLE_PS_DEC hParametricStereoDec, + const UINT flags, + const int overlap + ); + +int sbrGetChannelPairElement (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA hFrameDataLeft, + HANDLE_SBR_FRAME_DATA hFrameDataRight, + HANDLE_FDK_BITSTREAM hBitBuf, + const UINT flags, + const int overlap); + +SBR_HEADER_STATUS +sbrGetHeaderData (HANDLE_SBR_HEADER_DATA headerData, + HANDLE_FDK_BITSTREAM hBitBuf, + const UINT flags, + const int fIsSbrData); + +/*! + \brief Initialize SBR header data + + Copy default values to the header data struct and patch some entries + depending on the core codec. +*/ +SBR_ERROR +initHeaderData ( + HANDLE_SBR_HEADER_DATA hHeaderData, + const int sampleRateIn, + const int sampleRateOut, + const int samplesPerFrame, + const UINT flags + ); +#endif diff --git a/libSBRdec/src/huff_dec.cpp b/libSBRdec/src/huff_dec.cpp new file mode 100644 index 0000000..1af3554 --- /dev/null +++ b/libSBRdec/src/huff_dec.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Huffman Decoder $Revision: 36841 $ +*/ + +#include "huff_dec.h" + +/***************************************************************************/ +/*! + \brief Decodes one huffman code word + + Reads bits from the bitstream until a valid codeword is found. + The table entries are interpreted either as index to the next entry + or - if negative - as the codeword. + + \return decoded value + + \author + +****************************************************************************/ +int +DecodeHuffmanCW (Huffman h, /*!< pointer to huffman codebook table */ + HANDLE_FDK_BITSTREAM hBs) /*!< Handle to Bitbuffer */ +{ + SCHAR index = 0; + int value, bit; + + while (index >= 0) { + bit = FDKreadBits (hBs, 1); + index = h[index][bit]; + } + + value = index+64; /* Add offset */ + + + return value; +} diff --git a/libSBRdec/src/huff_dec.h b/libSBRdec/src/huff_dec.h new file mode 100644 index 0000000..a113c0e --- /dev/null +++ b/libSBRdec/src/huff_dec.h @@ -0,0 +1,42 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Huffman Decoder $Revision: 36841 $ +*/ +#ifndef __HUFF_DEC_H +#define __HUFF_DEC_H + +#include "sbrdecoder.h" +#include "FDK_bitstream.h" + +typedef const SCHAR (*Huffman)[2]; + +int +DecodeHuffmanCW (Huffman h, + HANDLE_FDK_BITSTREAM hBitBuf); + +#endif diff --git a/libSBRdec/src/lpp_tran.cpp b/libSBRdec/src/lpp_tran.cpp new file mode 100644 index 0000000..0a7721e --- /dev/null +++ b/libSBRdec/src/lpp_tran.cpp @@ -0,0 +1,942 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Low Power Profile Transposer, $Revision: 36841 $ + This module provides the transposer. The main entry point is lppTransposer(). The function generates + high frequency content by copying data from the low band (provided by core codec) into the high band. + This process is also referred to as "patching". The function also implements spectral whitening by means of + inverse filtering based on LPC coefficients. + + Together with the QMF filterbank the transposer can be tested using a supplied test program. See main_audio.cpp for details. + This module does use fractional arithmetic and the accuracy of the computations has an impact on the overall sound quality. + The module also needs to take into account the different scaling of spectral data. + + \sa lppTransposer(), main_audio.cpp, sbr_scale.h, \ref documentationOverview +*/ + +#include "lpp_tran.h" + +#include "sbr_ram.h" +#include "sbr_rom.h" + +#include "genericStds.h" +#include "autocorr2nd.h" + + + +#if defined(__arm__) +#include "arm/lpp_tran_arm.cpp" +#endif + + + +#define LPC_SCALE_FACTOR 2 + + +/*! + * + * \brief Get bandwidth expansion factor from filtering level + * + * Returns a filter parameter (bandwidth expansion factor) depending on + * the desired filtering level signalled in the bitstream. + * When switching the filtering level from LOW to OFF, an additional + * level is being inserted to achieve a smooth transition. + */ + +#ifndef FUNCTION_mapInvfMode +static FIXP_DBL +mapInvfMode (INVF_MODE mode, + INVF_MODE prevMode, + WHITENING_FACTORS whFactors) +{ + switch (mode) { + case INVF_LOW_LEVEL: + if(prevMode == INVF_OFF) + return whFactors.transitionLevel; + else + return whFactors.lowLevel; + + case INVF_MID_LEVEL: + return whFactors.midLevel; + + case INVF_HIGH_LEVEL: + return whFactors.highLevel; + + default: + if(prevMode == INVF_LOW_LEVEL) + return whFactors.transitionLevel; + else + return whFactors.off; + } +} +#endif /* #ifndef FUNCTION_mapInvfMode */ + +/*! + * + * \brief Perform inverse filtering level emphasis + * + * Retrieve bandwidth expansion factor and apply smoothing for each filter band + * + */ + +#ifndef FUNCTION_inverseFilteringLevelEmphasis +static void +inverseFilteringLevelEmphasis(HANDLE_SBR_LPP_TRANS hLppTrans,/*!< Handle of lpp transposer */ + UCHAR nInvfBands, /*!< Number of bands for inverse filtering */ + INVF_MODE *sbr_invf_mode, /*!< Current inverse filtering modes */ + INVF_MODE *sbr_invf_mode_prev, /*!< Previous inverse filtering modes */ + FIXP_DBL * bwVector /*!< Resulting filtering levels */ + ) +{ + for(int i = 0; i < nInvfBands; i++) { + FIXP_DBL accu; + FIXP_DBL bwTmp = mapInvfMode (sbr_invf_mode[i], + sbr_invf_mode_prev[i], + hLppTrans->pSettings->whFactors); + + if(bwTmp < hLppTrans->bwVectorOld[i]) { + accu = fMultDiv2(FL2FXCONST_DBL(0.75f),bwTmp) + + fMultDiv2(FL2FXCONST_DBL(0.25f),hLppTrans->bwVectorOld[i]); + } + else { + accu = fMultDiv2(FL2FXCONST_DBL(0.90625f),bwTmp) + + fMultDiv2(FL2FXCONST_DBL(0.09375f),hLppTrans->bwVectorOld[i]); + } + + if (accu < FL2FXCONST_DBL(0.015625f)>>1) + bwVector[i] = FL2FXCONST_DBL(0.0f); + else + bwVector[i] = fixMin(accu<<1,FL2FXCONST_DBL(0.99609375f)); + } +} +#endif /* #ifndef FUNCTION_inverseFilteringLevelEmphasis */ + +/* Resulting autocorrelation determinant exponent */ +#define ACDET_EXP (2*(DFRACT_BITS+sbrScaleFactor->lb_scale+10-ac.det_scale)) +#define AC_EXP (-sbrScaleFactor->lb_scale+LPC_SCALE_FACTOR) +#define ALPHA_EXP (-sbrScaleFactor->lb_scale+LPC_SCALE_FACTOR+1) +/* Resulting transposed QMF values exponent 16 bit normalized samplebits assumed. */ +#define QMFOUT_EXP ((SAMPLE_BITS-15)-sbrScaleFactor->lb_scale) + +/*! + * + * \brief Perform transposition by patching of subband samples. + * This function serves as the main entry point into the module. The function determines the areas for the + * patching process (these are the source range as well as the target range) and implements spectral whitening + * by means of inverse filtering. The function autoCorrelation2nd() is an auxiliary function for calculating the + * LPC coefficients for the filtering. The actual calculation of the LPC coefficients and the implementation + * of the filtering are done as part of lppTransposer(). + * + * Note that the filtering is done on all available QMF subsamples, whereas the patching is only done on those QMF + * subsamples that will be used in the next QMF synthesis. The filtering is also implemented before the patching + * includes further dependencies on parameters from the SBR data. + * + */ + +void lppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans, /*!< Handle of lpp transposer */ + QMF_SCALE_FACTOR *sbrScaleFactor, /*!< Scaling factors */ + FIXP_DBL **qmfBufferReal, /*!< Pointer to pointer to real part of subband samples (source) */ + + FIXP_DBL *degreeAlias, /*!< Vector for results of aliasing estimation */ + FIXP_DBL **qmfBufferImag, /*!< Pointer to pointer to imaginary part of subband samples (source) */ + const int useLP, + const int timeStep, /*!< Time step of envelope */ + const int firstSlotOffs, /*!< Start position in time */ + const int lastSlotOffs, /*!< Number of overlap-slots into next frame */ + const int nInvfBands, /*!< Number of bands for inverse filtering */ + INVF_MODE *sbr_invf_mode, /*!< Current inverse filtering modes */ + INVF_MODE *sbr_invf_mode_prev /*!< Previous inverse filtering modes */ + ) +{ + INT bwIndex[MAX_NUM_PATCHES]; + FIXP_DBL bwVector[MAX_NUM_PATCHES]; /*!< pole moving factors */ + + int i; + int loBand, start, stop; + TRANSPOSER_SETTINGS *pSettings = hLppTrans->pSettings; + PATCH_PARAM *patchParam = pSettings->patchParam; + int patch; + + FIXP_SGL alphar[LPC_ORDER], a0r, a1r; + FIXP_SGL alphai[LPC_ORDER], a0i=0, a1i=0; + FIXP_SGL bw = FL2FXCONST_SGL(0.0f); + + int autoCorrLength; + + FIXP_DBL k1, k1_below=0, k1_below2=0; + + ACORR_COEFS ac; + int startSample; + int stopSample; + int stopSampleClear; + + int comLowBandScale; + int ovLowBandShift; + int lowBandShift; +/* int ovHighBandShift;*/ + int targetStopBand; + + + alphai[0] = FL2FXCONST_SGL(0.0f); + alphai[1] = FL2FXCONST_SGL(0.0f); + + + startSample = firstSlotOffs * timeStep; + stopSample = pSettings->nCols + lastSlotOffs * timeStep; + + + inverseFilteringLevelEmphasis(hLppTrans, nInvfBands, sbr_invf_mode, sbr_invf_mode_prev, bwVector); + + stopSampleClear = stopSample; + + autoCorrLength = pSettings->nCols + pSettings->overlap; + + /* Set upper subbands to zero: + This is required in case that the patches do not cover the complete highband + (because the last patch would be too short). + Possible optimization: Clearing bands up to usb would be sufficient here. */ + targetStopBand = patchParam[pSettings->noOfPatches-1].targetStartBand + + patchParam[pSettings->noOfPatches-1].numBandsInPatch; + + int memSize = ((64) - targetStopBand) * sizeof(FIXP_DBL); + + if (!useLP) { + for (i = startSample; i < stopSampleClear; i++) { + FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize); + FDKmemclear(&qmfBufferImag[i][targetStopBand], memSize); + } + } else + for (i = startSample; i < stopSampleClear; i++) { + FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize); + } + + /* init bwIndex for each patch */ + FDKmemclear(bwIndex, pSettings->noOfPatches*sizeof(INT)); + + /* + Calc common low band scale factor + */ + comLowBandScale = fixMin(sbrScaleFactor->ov_lb_scale,sbrScaleFactor->lb_scale); + + ovLowBandShift = sbrScaleFactor->ov_lb_scale - comLowBandScale; + lowBandShift = sbrScaleFactor->lb_scale - comLowBandScale; + /* ovHighBandShift = firstSlotOffs == 0 ? ovLowBandShift:0;*/ + + /* outer loop over bands to do analysis only once for each band */ + + if (!useLP) { + start = pSettings->lbStartPatching; + stop = pSettings->lbStopPatching; + } else + { + start = fixMax(1, pSettings->lbStartPatching - 2); + stop = patchParam[0].targetStartBand; + } + + + for ( loBand = start; loBand < stop; loBand++ ) { + + FIXP_DBL lowBandReal[(((1024)/(32))+(6))+LPC_ORDER]; + FIXP_DBL *plowBandReal = lowBandReal; + FIXP_DBL **pqmfBufferReal = qmfBufferReal; + FIXP_DBL lowBandImag[(((1024)/(32))+(6))+LPC_ORDER]; + FIXP_DBL *plowBandImag = lowBandImag; + FIXP_DBL **pqmfBufferImag = qmfBufferImag; + int resetLPCCoeffs=0; + int dynamicScale = DFRACT_BITS-1-LPC_SCALE_FACTOR; + int acDetScale = 0; /* scaling of autocorrelation determinant */ + + for(i=0;ilpcFilterStatesReal[i][loBand]; + if (!useLP) + *plowBandImag++ = hLppTrans->lpcFilterStatesImag[i][loBand]; + } + + /* + Take old slope length qmf slot source values out of (overlap)qmf buffer + */ + if (!useLP) { + for(i=0;inCols+pSettings->overlap;i++){ + *plowBandReal++ = (*pqmfBufferReal++)[loBand]; + *plowBandImag++ = (*pqmfBufferImag++)[loBand]; + } + } else + { + /* pSettings->overlap is always even */ + FDK_ASSERT((pSettings->overlap & 1) == 0); + + for(i=0;i<((pSettings->overlap+pSettings->nCols)>>1);i++) { + *plowBandReal++ = (*pqmfBufferReal++)[loBand]; + *plowBandReal++ = (*pqmfBufferReal++)[loBand]; + } + if (pSettings->nCols & 1) { + *plowBandReal++ = (*pqmfBufferReal++)[loBand]; + } + } + + /* + Determine dynamic scaling value. + */ + dynamicScale = fixMin(dynamicScale, getScalefactor(lowBandReal, LPC_ORDER+pSettings->overlap) + ovLowBandShift); + dynamicScale = fixMin(dynamicScale, getScalefactor(&lowBandReal[LPC_ORDER+pSettings->overlap], pSettings->nCols) + lowBandShift); + if (!useLP) { + dynamicScale = fixMin(dynamicScale, getScalefactor(lowBandImag, LPC_ORDER+pSettings->overlap) + ovLowBandShift); + dynamicScale = fixMin(dynamicScale, getScalefactor(&lowBandImag[LPC_ORDER+pSettings->overlap], pSettings->nCols) + lowBandShift); + } + dynamicScale = fixMax(0, dynamicScale-1); /* one additional bit headroom to prevent -1.0 */ + + /* + Scale temporal QMF buffer. + */ + scaleValues(&lowBandReal[0], LPC_ORDER+pSettings->overlap, dynamicScale-ovLowBandShift); + scaleValues(&lowBandReal[LPC_ORDER+pSettings->overlap], pSettings->nCols, dynamicScale-lowBandShift); + + if (!useLP) { + scaleValues(&lowBandImag[0], LPC_ORDER+pSettings->overlap, dynamicScale-ovLowBandShift); + scaleValues(&lowBandImag[LPC_ORDER+pSettings->overlap], pSettings->nCols, dynamicScale-lowBandShift); + } + + + if (!useLP) { + acDetScale += autoCorr2nd_cplx(&ac, lowBandReal+LPC_ORDER, lowBandImag+LPC_ORDER, autoCorrLength); + } + else + { + acDetScale += autoCorr2nd_real(&ac, lowBandReal+LPC_ORDER, autoCorrLength); + } + + /* Examine dynamic of determinant in autocorrelation. */ + acDetScale += 2*(comLowBandScale + dynamicScale); + acDetScale *= 2; /* two times reflection coefficent scaling */ + acDetScale += ac.det_scale; /* ac scaling of determinant */ + + /* In case of determinant < 10^-38, resetLPCCoeffs=1 has to be enforced. */ + if (acDetScale>126 ) { + resetLPCCoeffs = 1; + } + + + alphar[1] = FL2FXCONST_SGL(0.0f); + if (!useLP) + alphai[1] = FL2FXCONST_SGL(0.0f); + + if (ac.det != FL2FXCONST_DBL(0.0f)) { + FIXP_DBL tmp,absTmp,absDet; + + absDet = fixp_abs(ac.det); + + if (!useLP) { + tmp = ( fMultDiv2(ac.r01r,ac.r12r) >> (LPC_SCALE_FACTOR-1) ) - + ( (fMultDiv2(ac.r01i,ac.r12i) + fMultDiv2(ac.r02r,ac.r11r)) >> (LPC_SCALE_FACTOR-1) ); + } else + { + tmp = ( fMultDiv2(ac.r01r,ac.r12r) >> (LPC_SCALE_FACTOR-1) ) - + ( fMultDiv2(ac.r02r,ac.r11r) >> (LPC_SCALE_FACTOR-1) ); + } + absTmp = fixp_abs(tmp); + + /* + Quick check: is first filter coeff >= 1(4) + */ + { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, absDet, &scale); + scale = scale+ac.det_scale; + + if ( (scale > 0) && (result >= (FIXP_DBL)MAXVAL_DBL>>scale) ) { + resetLPCCoeffs = 1; + } + else { + alphar[1] = FX_DBL2FX_SGL(scaleValue(result,scale)); + if((tmp> (LPC_SCALE_FACTOR-1) ) + + ( (fMultDiv2(ac.r01r,ac.r12i) - (FIXP_DBL)fMultDiv2(ac.r02i,ac.r11r)) >> (LPC_SCALE_FACTOR-1) ) ; + + absTmp = fixp_abs(tmp); + + /* + Quick check: is second filter coeff >= 1(4) + */ + { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, absDet, &scale); + scale = scale+ac.det_scale; + + if ( (scale > 0) && (result >= /*FL2FXCONST_DBL(1.f)*/ (FIXP_DBL)MAXVAL_DBL>>scale) ) { + resetLPCCoeffs = 1; + } + else { + alphai[1] = FX_DBL2FX_SGL(scaleValue(result,scale)); + if((tmp=0 */ + FIXP_DBL tmp,absTmp; + + if (!useLP) { + tmp = (ac.r01r>>(LPC_SCALE_FACTOR+1)) + + (fMultDiv2(alphar[1],ac.r12r) + fMultDiv2(alphai[1],ac.r12i)); + } else + { + if(ac.r01r>=FL2FXCONST_DBL(0.0f)) + tmp = (ac.r01r>>(LPC_SCALE_FACTOR+1)) + fMultDiv2(alphar[1],ac.r12r); + else + tmp = -((-ac.r01r)>>(LPC_SCALE_FACTOR+1)) + fMultDiv2(alphar[1],ac.r12r); + } + + absTmp = fixp_abs(tmp); + + /* + Quick check: is first filter coeff >= 1(4) + */ + + if (absTmp >= (ac.r11r>>1)) { + resetLPCCoeffs=1; + } + else { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale); + alphar[0] = FX_DBL2FX_SGL(scaleValue(result,scale+1)); + + if((tmp>FL2FX_DBL(0.0f)) ^ (ac.r11r>(LPC_SCALE_FACTOR+1)) + + (fMultDiv2(alphai[1],ac.r12r) - fMultDiv2(alphar[1],ac.r12i)); + + absTmp = fixp_abs(tmp); + + /* + Quick check: is second filter coeff >= 1(4) + */ + if (absTmp >= (ac.r11r>>1)) { + resetLPCCoeffs=1; + } + else { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale); + alphai[0] = FX_DBL2FX_SGL(scaleValue(result,scale+1)); + if((tmp>FL2FX_DBL(0.0f)) ^ (ac.r11r= FL2FXCONST_DBL(0.5f) ) + resetLPCCoeffs=1; + if( (fMultDiv2(alphar[1],alphar[1]) + fMultDiv2(alphai[1],alphai[1])) >= FL2FXCONST_DBL(0.5f) ) + resetLPCCoeffs=1; + } + + if(resetLPCCoeffs){ + alphar[0] = FL2FXCONST_SGL(0.0f); + alphar[1] = FL2FXCONST_SGL(0.0f); + if (!useLP) + { + alphai[0] = FL2FXCONST_SGL(0.0f); + alphai[1] = FL2FXCONST_SGL(0.0f); + } + } + + if (useLP) + { + + /* Aliasing detection */ + if(ac.r11r==FL2FXCONST_DBL(0.0f)) { + k1 = FL2FXCONST_DBL(0.0f); + } + else { + if ( fixp_abs(ac.r01r) >= fixp_abs(ac.r11r) ) { + if ( fMultDiv2(ac.r01r,ac.r11r) < FL2FX_DBL(0.0f)) { + k1 = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_SGL(1.0f)*/; + }else { + /* Since this value is squared later, it must not ever become -1.0f. */ + k1 = (FIXP_DBL)(MINVAL_DBL+1) /*FL2FXCONST_SGL(-1.0f)*/; + } + } + else { + INT scale; + FIXP_DBL result = fDivNorm(fixp_abs(ac.r01r), fixp_abs(ac.r11r), &scale); + k1 = scaleValue(result,scale); + + if(!((ac.r01r 1){ + /* Check if the gain should be locked */ + FIXP_DBL deg = /*FL2FXCONST_DBL(1.0f)*/ (FIXP_DBL)MAXVAL_DBL - fPow2(k1_below); + degreeAlias[loBand] = FL2FXCONST_DBL(0.0f); + if (((loBand & 1) == 0) && (k1 < FL2FXCONST_DBL(0.0f))){ + if (k1_below < FL2FXCONST_DBL(0.0f)) { /* 2-Ch Aliasing Detection */ + degreeAlias[loBand] = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/; + if ( k1_below2 > FL2FXCONST_DBL(0.0f) ) { /* 3-Ch Aliasing Detection */ + degreeAlias[loBand-1] = deg; + } + } + else if ( k1_below2 > FL2FXCONST_DBL(0.0f) ) { /* 3-Ch Aliasing Detection */ + degreeAlias[loBand] = deg; + } + } + if (((loBand & 1) == 1) && (k1 > FL2FXCONST_DBL(0.0f))){ + if (k1_below > FL2FXCONST_DBL(0.0f)) { /* 2-CH Aliasing Detection */ + degreeAlias[loBand] = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/; + if ( k1_below2 < FL2FXCONST_DBL(0.0f) ) { /* 3-CH Aliasing Detection */ + degreeAlias[loBand-1] = deg; + } + } + else if ( k1_below2 < FL2FXCONST_DBL(0.0f) ) { /* 3-CH Aliasing Detection */ + degreeAlias[loBand] = deg; + } + } + } + /* remember k1 values of the 2 QMF channels below the current channel */ + k1_below2 = k1_below; + k1_below = k1; + } + + patch = 0; + + while ( patch < pSettings->noOfPatches ) { /* inner loop over every patch */ + + int hiBand = loBand + patchParam[patch].targetBandOffs; + + if ( loBand < patchParam[patch].sourceStartBand + || loBand >= patchParam[patch].sourceStopBand + //|| hiBand >= hLppTrans->pSettings->noChannels + ) { + /* Lowband not in current patch - proceed */ + patch++; + continue; + } + + FDK_ASSERT( hiBand < (64) ); + + /* bwIndex[patch] is already initialized with value from previous band inside this patch */ + while (hiBand >= pSettings->bwBorders[bwIndex[patch]]) + bwIndex[patch]++; + + + /* + Filter Step 2: add the left slope with the current filter to the buffer + pure source values are already in there + */ + bw = FX_DBL2FX_SGL(bwVector[bwIndex[patch]]); + + a0r = FX_DBL2FX_SGL(fMult(bw,alphar[0])); /* Apply current bandwidth expansion factor */ + + + if (!useLP) + a0i = FX_DBL2FX_SGL(fMult(bw,alphai[0])); + bw = FX_DBL2FX_SGL(fPow2(bw)); + a1r = FX_DBL2FX_SGL(fMult(bw,alphar[1])); + if (!useLP) + a1i = FX_DBL2FX_SGL(fMult(bw,alphai[1])); + + + + /* + Filter Step 3: insert the middle part which won't be windowed + */ + + if ( bw <= FL2FXCONST_SGL(0.0f) ) { + if (!useLP) { + int descale = fixMin(DFRACT_BITS-1, (LPC_SCALE_FACTOR+dynamicScale)); + for(i = startSample; i < stopSample; i++ ) { + qmfBufferReal[i][hiBand] = lowBandReal[LPC_ORDER+i]>>descale; + qmfBufferImag[i][hiBand] = lowBandImag[LPC_ORDER+i]>>descale; + } + } else + { + int descale = fixMin(DFRACT_BITS-1, (LPC_SCALE_FACTOR+dynamicScale)); + for(i = startSample; i < stopSample; i++ ) { + qmfBufferReal[i][hiBand] = lowBandReal[LPC_ORDER+i]>>descale; + } + } + } + else { /* bw <= 0 */ + + if (!useLP) { + int descale = fixMin(DFRACT_BITS-1, (LPC_SCALE_FACTOR+dynamicScale)); +#ifdef FUNCTION_LPPTRANSPOSER_func1 + lppTransposer_func1(lowBandReal+LPC_ORDER+startSample,lowBandImag+LPC_ORDER+startSample, + qmfBufferReal+startSample,qmfBufferImag+startSample, + stopSample-startSample, (int) hiBand, + dynamicScale,descale, + a0r, a0i, a1r, a1i); +#else + for(i = startSample; i < stopSample; i++ ) { + FIXP_DBL accu1, accu2; + + accu1 = (fMultDiv2(a0r,lowBandReal[LPC_ORDER+i-1]) - fMultDiv2(a0i,lowBandImag[LPC_ORDER+i-1]) + + fMultDiv2(a1r,lowBandReal[LPC_ORDER+i-2]) - fMultDiv2(a1i,lowBandImag[LPC_ORDER+i-2]))>>dynamicScale; + accu2 = (fMultDiv2(a0i,lowBandReal[LPC_ORDER+i-1]) + fMultDiv2(a0r,lowBandImag[LPC_ORDER+i-1]) + + fMultDiv2(a1i,lowBandReal[LPC_ORDER+i-2]) + fMultDiv2(a1r,lowBandImag[LPC_ORDER+i-2]))>>dynamicScale; + + qmfBufferReal[i][hiBand] = (lowBandReal[LPC_ORDER+i]>>descale) + (accu1<<1); + qmfBufferImag[i][hiBand] = (lowBandImag[LPC_ORDER+i]>>descale) + (accu2<<1); + } +#endif + } else + { + int descale = fixMin(DFRACT_BITS-1, (LPC_SCALE_FACTOR+dynamicScale)); + + FDK_ASSERT(dynamicScale >= 0); + for(i = startSample; i < stopSample; i++ ) { + FIXP_DBL accu1; + + accu1 = (fMultDiv2(a0r,lowBandReal[LPC_ORDER+i-1]) + fMultDiv2(a1r,lowBandReal[LPC_ORDER+i-2]))>>dynamicScale; + + qmfBufferReal[i][hiBand] = (lowBandReal[LPC_ORDER+i]>>descale) + (accu1<<1); + } + } + } /* bw <= 0 */ + + patch++; + + } /* inner loop over patches */ + + /* + * store the unmodified filter coefficients if there is + * an overlapping envelope + *****************************************************************/ + + + } /* outer loop over bands (loBand) */ + + if (useLP) + { + for ( loBand = pSettings->lbStartPatching; loBand < pSettings->lbStopPatching; loBand++ ) { + patch = 0; + while ( patch < pSettings->noOfPatches ) { + + UCHAR hiBand = loBand + patchParam[patch].targetBandOffs; + + if ( loBand < patchParam[patch].sourceStartBand + || loBand >= patchParam[patch].sourceStopBand + || hiBand >= (64) /* Highband out of range (biterror) */ + ) { + /* Lowband not in current patch or highband out of range (might be caused by biterrors)- proceed */ + patch++; + continue; + } + + if(hiBand != patchParam[patch].targetStartBand) + degreeAlias[hiBand] = degreeAlias[loBand]; + + patch++; + } + }/* end for loop */ + } + + for (i = 0; i < nInvfBands; i++ ) { + hLppTrans->bwVectorOld[i] = bwVector[i]; + } + + /* + set high band scale factor + */ + sbrScaleFactor->hb_scale = comLowBandScale-(LPC_SCALE_FACTOR); + +} + +/*! + * + * \brief Initialize one low power transposer instance + * + * + */ +SBR_ERROR +createLppTransposer (HANDLE_SBR_LPP_TRANS hs, /*!< Handle of low power transposer */ + TRANSPOSER_SETTINGS *pSettings, /*!< Pointer to settings */ + const int highBandStartSb, /*!< ? */ + UCHAR *v_k_master, /*!< Master table */ + const int numMaster, /*!< Valid entries in master table */ + const int usb, /*!< Highband area stop subband */ + const int timeSlots, /*!< Number of time slots */ + const int nCols, /*!< Number of colums (codec qmf bank) */ + UCHAR *noiseBandTable, /*!< Mapping of SBR noise bands to QMF bands */ + const int noNoiseBands, /*!< Number of noise bands */ + UINT fs, /*!< Sample Frequency */ + const int chan, /*!< Channel number */ + const int overlap + ) +{ + /* FB inverse filtering settings */ + hs->pSettings = pSettings; + + pSettings->nCols = nCols; + pSettings->overlap = overlap; + + switch (timeSlots) { + + case 15: + case 16: + break; + + default: + return SBRDEC_UNSUPPORTED_CONFIG; /* Unimplemented */ + } + + if (chan==0) { + /* Init common data only once */ + hs->pSettings->nCols = nCols; + + return resetLppTransposer (hs, + highBandStartSb, + v_k_master, + numMaster, + noiseBandTable, + noNoiseBands, + usb, + fs); + } + return SBRDEC_OK; +} + + +static int findClosestEntry(UCHAR goalSb, UCHAR *v_k_master, UCHAR numMaster, UCHAR direction) +{ + int index; + + if( goalSb <= v_k_master[0] ) + return v_k_master[0]; + + if( goalSb >= v_k_master[numMaster] ) + return v_k_master[numMaster]; + + if(direction) { + index = 0; + while( v_k_master[index] < goalSb ) { + index++; + } + } else { + index = numMaster; + while( v_k_master[index] > goalSb ) { + index--; + } + } + + return v_k_master[index]; +} + + +/*! + * + * \brief Reset memory for one lpp transposer instance + * + * \return SBRDEC_OK on success, SBRDEC_UNSUPPORTED_CONFIG on error + */ +SBR_ERROR +resetLppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans, /*!< Handle of lpp transposer */ + UCHAR highBandStartSb, /*!< High band area: start subband */ + UCHAR *v_k_master, /*!< Master table */ + UCHAR numMaster, /*!< Valid entries in master table */ + UCHAR *noiseBandTable, /*!< Mapping of SBR noise bands to QMF bands */ + UCHAR noNoiseBands, /*!< Number of noise bands */ + UCHAR usb, /*!< High band area: stop subband */ + UINT fs /*!< SBR output sampling frequency */ + ) +{ + TRANSPOSER_SETTINGS *pSettings = hLppTrans->pSettings; + PATCH_PARAM *patchParam = pSettings->patchParam; + + int i, patch; + int targetStopBand; + int sourceStartBand; + int patchDistance; + int numBandsInPatch; + + int lsb = v_k_master[0]; /* Start subband expressed in "non-critical" sampling terms*/ + int xoverOffset = highBandStartSb - lsb; /* Calculate distance in QMF bands between k0 and kx */ + int startFreqHz; + + int desiredBorder; + + usb = fixMin(usb, v_k_master[numMaster]); /* Avoid endless loops (compare with float code). */ + + /* + * Plausibility check + */ + + if ( lsb - SHIFT_START_SB < 4 ) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + + /* + * Initialize the patching parameter + */ + desiredBorder = 21; + if (fs < 92017) { + desiredBorder = 23; + } + if (fs < 75132) { + desiredBorder = 32; + } + if (fs < 55426) { + desiredBorder = 43; + } + if (fs < 46009) { + desiredBorder = 46; + } + if (fs < 35777) { + desiredBorder = 64; + } + + desiredBorder = findClosestEntry(desiredBorder, v_k_master, numMaster, 1); /* Adapt region to master-table */ + + /* First patch */ + sourceStartBand = SHIFT_START_SB + xoverOffset; + targetStopBand = lsb + xoverOffset; /* upperBand */ + + /* Even (odd) numbered channel must be patched to even (odd) numbered channel */ + patch = 0; + while(targetStopBand < usb) { + + /* Too many patches? + Allow MAX_NUM_PATCHES+1 patches here. + we need to check later again, since patch might be the highest patch + AND contain less than 3 bands => actual number of patches will be reduced by 1. + */ + if (patch > MAX_NUM_PATCHES) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + patchParam[patch].guardStartBand = targetStopBand; + patchParam[patch].targetStartBand = targetStopBand; + + numBandsInPatch = desiredBorder - targetStopBand; /* Get the desired range of the patch */ + + if ( numBandsInPatch >= lsb - sourceStartBand ) { + /* Desired number bands are not available -> patch whole source range */ + patchDistance = targetStopBand - sourceStartBand; /* Get the targetOffset */ + patchDistance = patchDistance & ~1; /* Rounding off odd numbers and make all even */ + numBandsInPatch = lsb - (targetStopBand - patchDistance); /* Update number of bands to be patched */ + numBandsInPatch = findClosestEntry(targetStopBand + numBandsInPatch, v_k_master, numMaster, 0) - + targetStopBand; /* Adapt region to master-table */ + } + + /* Desired number bands are available -> get the minimal even patching distance */ + patchDistance = numBandsInPatch + targetStopBand - lsb; /* Get minimal distance */ + patchDistance = (patchDistance + 1) & ~1; /* Rounding up odd numbers and make all even */ + + if (numBandsInPatch > 0) { + patchParam[patch].sourceStartBand = targetStopBand - patchDistance; + patchParam[patch].targetBandOffs = patchDistance; + patchParam[patch].numBandsInPatch = numBandsInPatch; + patchParam[patch].sourceStopBand = patchParam[patch].sourceStartBand + numBandsInPatch; + + targetStopBand += patchParam[patch].numBandsInPatch; + patch++; + } + + /* All patches but first */ + sourceStartBand = SHIFT_START_SB; + + /* Check if we are close to desiredBorder */ + if( desiredBorder - targetStopBand < 3) /* MPEG doc */ + { + desiredBorder = usb; + } + + } + + patch--; + + /* If highest patch contains less than three subband: skip it */ + if ( (patch>0) && (patchParam[patch].numBandsInPatch < 3) ) { + patch--; + targetStopBand = patchParam[patch].targetStartBand + patchParam[patch].numBandsInPatch; + } + + /* now check if we don't have one too many */ + if (patch >= MAX_NUM_PATCHES) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + pSettings->noOfPatches = patch + 1; + + /* Check lowest and highest source subband */ + pSettings->lbStartPatching = targetStopBand; + pSettings->lbStopPatching = 0; + for ( patch = 0; patch < pSettings->noOfPatches; patch++ ) { + pSettings->lbStartPatching = fixMin( pSettings->lbStartPatching, patchParam[patch].sourceStartBand ); + pSettings->lbStopPatching = fixMax( pSettings->lbStopPatching, patchParam[patch].sourceStopBand ); + } + + for(i = 0 ; i < noNoiseBands; i++){ + pSettings->bwBorders[i] = noiseBandTable[i+1]; + } + + /* + * Choose whitening factors + */ + + startFreqHz = ( (lsb + xoverOffset)*fs ) >> 7; /* Shift does a division by 2*(64) */ + + for( i = 1; i < NUM_WHFACTOR_TABLE_ENTRIES; i++ ) + { + if( startFreqHz < FDK_sbrDecoder_sbr_whFactorsIndex[i]) + break; + } + i--; + + pSettings->whFactors.off = FDK_sbrDecoder_sbr_whFactorsTable[i][0]; + pSettings->whFactors.transitionLevel = FDK_sbrDecoder_sbr_whFactorsTable[i][1]; + pSettings->whFactors.lowLevel = FDK_sbrDecoder_sbr_whFactorsTable[i][2]; + pSettings->whFactors.midLevel = FDK_sbrDecoder_sbr_whFactorsTable[i][3]; + pSettings->whFactors.highLevel = FDK_sbrDecoder_sbr_whFactorsTable[i][4]; + + return SBRDEC_OK; +} diff --git a/libSBRdec/src/lpp_tran.h b/libSBRdec/src/lpp_tran.h new file mode 100644 index 0000000..dcaadd9 --- /dev/null +++ b/libSBRdec/src/lpp_tran.h @@ -0,0 +1,184 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Low Power Profile Transposer, $Revision: 36841 $ +*/ + +#ifndef _LPP_TRANS_H +#define _LPP_TRANS_H + +#include "sbrdecoder.h" +#include "qmf.h" + +/* + Common +*/ +#define QMF_OUT_SCALE 8 + +/* + Env-Adjust +*/ +#define MAX_NOISE_ENVELOPES 2 +#define MAX_NOISE_COEFFS 5 +#define MAX_NUM_NOISE_VALUES (MAX_NOISE_ENVELOPES * MAX_NOISE_COEFFS) +#define MAX_NUM_LIMITERS 12 + +/* Set MAX_ENVELOPES to the largest value of all supported BSFORMATs + by overriding MAX_ENVELOPES in the correct order: */ +#define MAX_ENVELOPES_HEAAC 5 +#define MAX_ENVELOPES MAX_ENVELOPES_HEAAC + +#define MAX_FREQ_COEFFS 48 +#define MAX_FREQ_COEFFS_FS44100 35 +#define MAX_FREQ_COEFFS_FS48000 32 + + +#define MAX_NUM_ENVELOPE_VALUES (MAX_ENVELOPES * MAX_FREQ_COEFFS) + +#define MAX_GAIN_EXP 34 +/* Maximum gain will be sqrt(0.5 * 2^MAX_GAIN_EXP) + example: 34=99dB */ +#define MAX_GAIN_CONCEAL_EXP 1 +/* Maximum gain will be sqrt(0.5 * 2^MAX_GAIN_CONCEAL_EXP) in concealment case (0dB) */ + +/* + LPP Transposer +*/ +#define LPC_ORDER 2 + +#define MAX_INVF_BANDS MAX_NOISE_COEFFS + +#define MAX_NUM_PATCHES 6 +#define SHIFT_START_SB 1 /*!< lowest subband of source range */ + +typedef enum +{ + INVF_OFF = 0, + INVF_LOW_LEVEL, + INVF_MID_LEVEL, + INVF_HIGH_LEVEL, + INVF_SWITCHED /* not a real choice but used here to control behaviour */ +} +INVF_MODE; + + +/** parameter set for one single patch */ +typedef struct { + UCHAR sourceStartBand; /*!< first band in lowbands where to take the samples from */ + UCHAR sourceStopBand; /*!< first band in lowbands which is not included in the patch anymore */ + UCHAR guardStartBand; /*!< first band in highbands to be filled with zeros in order to + reduce interferences between patches */ + UCHAR targetStartBand; /*!< first band in highbands to be filled with whitened lowband signal */ + UCHAR targetBandOffs; /*!< difference between 'startTargetBand' and 'startSourceBand' */ + UCHAR numBandsInPatch; /*!< number of consecutive bands in this one patch */ +} PATCH_PARAM; + + +/** whitening factors for different levels of whitening + need to be initialized corresponding to crossover frequency */ +typedef struct { + FIXP_DBL off; /*!< bw factor for signal OFF */ + FIXP_DBL transitionLevel; + FIXP_DBL lowLevel; /*!< bw factor for signal LOW_LEVEL */ + FIXP_DBL midLevel; /*!< bw factor for signal MID_LEVEL */ + FIXP_DBL highLevel; /*!< bw factor for signal HIGH_LEVEL */ +} WHITENING_FACTORS; + + +/*! The transposer settings are calculated on a header reset and are shared by both channels. */ +typedef struct { + UCHAR nCols; /*!< number subsamples of a codec frame */ + UCHAR noOfPatches; /*!< number of patches */ + UCHAR lbStartPatching; /*!< first band of lowbands that will be patched */ + UCHAR lbStopPatching; /*!< first band that won't be patched anymore*/ + UCHAR bwBorders[MAX_NUM_NOISE_VALUES]; /*!< spectral bands with different inverse filtering levels */ + + PATCH_PARAM patchParam[MAX_NUM_PATCHES]; /*!< new parameter set for patching */ + WHITENING_FACTORS whFactors; /*!< the pole moving factors for certain whitening levels as indicated + in the bitstream depending on the crossover frequency */ + UCHAR overlap; /*!< Overlap size */ +} TRANSPOSER_SETTINGS; + + +typedef struct +{ + TRANSPOSER_SETTINGS *pSettings; /*!< Common settings for both channels */ + FIXP_DBL bwVectorOld[MAX_NUM_PATCHES]; /*!< pole moving factors of past frame */ + FIXP_DBL lpcFilterStatesReal[LPC_ORDER][(32)]; /*!< pointer array to save filter states */ + FIXP_DBL lpcFilterStatesImag[LPC_ORDER][(32)]; /*!< pointer array to save filter states */ +} +SBR_LPP_TRANS; + +typedef SBR_LPP_TRANS *HANDLE_SBR_LPP_TRANS; + + +void lppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans, + QMF_SCALE_FACTOR *sbrScaleFactor, + FIXP_DBL **qmfBufferReal, + + FIXP_DBL *degreeAlias, + FIXP_DBL **qmfBufferImag, + const int useLP, + const int timeStep, + const int firstSlotOffset, + const int lastSlotOffset, + const int nInvfBands, + INVF_MODE *sbr_invf_mode, + INVF_MODE *sbr_invf_mode_prev + ); + + +SBR_ERROR +createLppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans, + TRANSPOSER_SETTINGS *pSettings, + const int highBandStartSb, + UCHAR *v_k_master, + const int numMaster, + const int usb, + const int timeSlots, + const int nCols, + UCHAR *noiseBandTable, + const int noNoiseBands, + UINT fs, + const int chan, + const int overlap); + + +SBR_ERROR +resetLppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans, + UCHAR highBandStartSb, + UCHAR *v_k_master, + UCHAR numMaster, + UCHAR *noiseBandTable, + UCHAR noNoiseBands, + UCHAR usb, + UINT fs); + + + +#endif /* _LPP_TRANS_H */ + diff --git a/libSBRdec/src/psbitdec.cpp b/libSBRdec/src/psbitdec.cpp new file mode 100644 index 0000000..0a5687a --- /dev/null +++ b/libSBRdec/src/psbitdec.cpp @@ -0,0 +1,536 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +#include "psbitdec.h" + + +#include "sbr_rom.h" +#include "huff_dec.h" + +/* PS dec privat functions */ +SBR_ERROR ResetPsDec(HANDLE_PS_DEC h_ps_d); +void ResetPsDeCor (HANDLE_PS_DEC h_ps_d); + +/***************************************************************************/ +/*! + \brief huffman decoding by codebook table + + \return index of huffman codebook table + +****************************************************************************/ +static SCHAR +decode_huff_cw (Huffman h, /*!< pointer to huffman codebook table */ + HANDLE_FDK_BITSTREAM hBitBuf, /*!< Handle to Bitbuffer */ + int *length) /*!< length of huffman codeword (or NULL) */ +{ + UCHAR bit = 0; + SCHAR index = 0; + UCHAR bitCount = 0; + + while (index >= 0) { + bit = FDKreadBits (hBitBuf, 1); + bitCount++; + index = h[index][bit]; + } + if (length) { + *length = bitCount; + } + return( index+64 ); /* Add offset */ +} + +/***************************************************************************/ +/*! + \brief helper function - limiting of value to min/max values + + \return limited value + +****************************************************************************/ + +static SCHAR +limitMinMax(SCHAR i, + SCHAR min, + SCHAR max) +{ + if (imax) + return max; + else + return i; +} + +/***************************************************************************/ +/*! + \brief Decodes delta values in-place and updates + data buffers according to quantization classes. + + When delta coded in frequency the first element is deltacode from zero. + aIndex buffer is decoded from delta values to actual values. + + \return none + +****************************************************************************/ +static void +deltaDecodeArray(SCHAR enable, + SCHAR *aIndex, /*!< ICC/IID parameters */ + SCHAR *aPrevFrameIndex, /*!< ICC/IID parameters of previous frame */ + SCHAR DtDf, + UCHAR nrElements, /*!< as conveyed in bitstream */ + /*!< output array size: nrElements*stride */ + UCHAR stride, /*!< 1=dflt, 2=half freq. resolution */ + SCHAR minIdx, + SCHAR maxIdx) +{ + int i; + + /* Delta decode */ + if ( enable==1 ) { + if (DtDf == 0) { /* Delta coded in freq */ + aIndex[0] = 0 + aIndex[0]; + aIndex[0] = limitMinMax(aIndex[0],minIdx,maxIdx); + for (i = 1; i < nrElements; i++) { + aIndex[i] = aIndex[i-1] + aIndex[i]; + aIndex[i] = limitMinMax(aIndex[i],minIdx,maxIdx); + } + } + else { /* Delta time */ + for (i = 0; i < nrElements; i++) { + aIndex[i] = aPrevFrameIndex[i*stride] + aIndex[i]; + aIndex[i] = limitMinMax(aIndex[i],minIdx,maxIdx); + } + } + } + else { /* No data is sent, set index to zero */ + for (i = 0; i < nrElements; i++) { + aIndex[i] = 0; + } + } + if (stride==2) { + for (i=nrElements*stride-1; i>0; i--) { + aIndex[i] = aIndex[i>>1]; + } + } +} + +/***************************************************************************/ +/*! + \brief Mapping of ICC/IID parameters to 20 stereo bands + + \return none + +****************************************************************************/ +static void map34IndexTo20 (SCHAR *aIndex, /*!< decoded ICC/IID parameters */ + UCHAR noBins) /*!< number of stereo bands */ +{ + aIndex[0] = (2*aIndex[0]+aIndex[1])/3; + aIndex[1] = (aIndex[1]+2*aIndex[2])/3; + aIndex[2] = (2*aIndex[3]+aIndex[4])/3; + aIndex[3] = (aIndex[4]+2*aIndex[5])/3; + aIndex[4] = (aIndex[6]+aIndex[7])/2; + aIndex[5] = (aIndex[8]+aIndex[9])/2; + aIndex[6] = aIndex[10]; + aIndex[7] = aIndex[11]; + aIndex[8] = (aIndex[12]+aIndex[13])/2; + aIndex[9] = (aIndex[14]+aIndex[15])/2; + aIndex[10] = aIndex[16]; + /* For IPD/OPD it stops here */ + + if (noBins == NO_HI_RES_BINS) + { + aIndex[11] = aIndex[17]; + aIndex[12] = aIndex[18]; + aIndex[13] = aIndex[19]; + aIndex[14] = (aIndex[20]+aIndex[21])/2; + aIndex[15] = (aIndex[22]+aIndex[23])/2; + aIndex[16] = (aIndex[24]+aIndex[25])/2; + aIndex[17] = (aIndex[26]+aIndex[27])/2; + aIndex[18] = (aIndex[28]+aIndex[29]+aIndex[30]+aIndex[31])/4; + aIndex[19] = (aIndex[32]+aIndex[33])/2; + } +} + +/***************************************************************************/ +/*! + \brief Decodes delta coded IID, ICC, IPD and OPD indices + + \return PS processing flag. If set to 1 + +****************************************************************************/ +int +DecodePs( struct PS_DEC *h_ps_d, /*!< PS handle */ + const UCHAR frameError ) /*!< Flag telling that frame had errors */ +{ + MPEG_PS_BS_DATA *pBsData; + UCHAR gr, env; + int bPsHeaderValid, bPsDataAvail; + + /* Shortcuts to avoid deferencing and keep the code readable */ + pBsData = &h_ps_d->bsData[h_ps_d->processSlot].mpeg; + bPsHeaderValid = pBsData->bPsHeaderValid; + bPsDataAvail = (h_ps_d->bPsDataAvail[h_ps_d->processSlot] == ppt_mpeg) ? 1 : 0; + + /*************************************************************************************** + * Decide whether to process or to conceal PS data or not. */ + + if ( ( h_ps_d->psDecodedPrv && !frameError && !bPsDataAvail) + || (!h_ps_d->psDecodedPrv && (frameError || !bPsDataAvail || !bPsHeaderValid)) ) { + /* Don't apply PS processing. + * Declare current PS header and bitstream data invalid. */ + pBsData->bPsHeaderValid = 0; + h_ps_d->bPsDataAvail[h_ps_d->processSlot] = ppt_none; + return (0); + } + + if (frameError || !bPsHeaderValid) + { /* no new PS data available (e.g. frame loss) */ + /* => keep latest data constant (i.e. FIX with noEnv=0) */ + pBsData->noEnv = 0; + } + + /*************************************************************************************** + * Decode bitstream payload or prepare parameter for concealment: + */ + for (env=0; envnoEnv; env++) { + SCHAR *aPrevIidIndex; + SCHAR *aPrevIccIndex; + + UCHAR noIidSteps = pBsData->bFineIidQ?NO_IID_STEPS_FINE:NO_IID_STEPS; + + if (env==0) { + aPrevIidIndex = h_ps_d->specificTo.mpeg.aIidPrevFrameIndex; + aPrevIccIndex = h_ps_d->specificTo.mpeg.aIccPrevFrameIndex; + } + else { + aPrevIidIndex = pBsData->aaIidIndex[env-1]; + aPrevIccIndex = pBsData->aaIccIndex[env-1]; + } + + deltaDecodeArray(pBsData->bEnableIid, + pBsData->aaIidIndex[env], + aPrevIidIndex, + pBsData->abIidDtFlag[env], + FDK_sbrDecoder_aNoIidBins[pBsData->freqResIid], + (pBsData->freqResIid)?1:2, + -noIidSteps, + noIidSteps); + + deltaDecodeArray(pBsData->bEnableIcc, + pBsData->aaIccIndex[env], + aPrevIccIndex, + pBsData->abIccDtFlag[env], + FDK_sbrDecoder_aNoIccBins[pBsData->freqResIcc], + (pBsData->freqResIcc)?1:2, + 0, + NO_ICC_STEPS-1); + } /* for (env=0; envnoEnv; env++) */ + + /* handling of FIX noEnv=0 */ + if (pBsData->noEnv==0) { + /* set noEnv=1, keep last parameters or force 0 if not enabled */ + pBsData->noEnv = 1; + + if (pBsData->bEnableIid) { + for (gr = 0; gr < NO_HI_RES_IID_BINS; gr++) { + pBsData->aaIidIndex[pBsData->noEnv-1][gr] = + h_ps_d->specificTo.mpeg.aIidPrevFrameIndex[gr]; + } + } + else { + for (gr = 0; gr < NO_HI_RES_IID_BINS; gr++) { + pBsData->aaIidIndex[pBsData->noEnv-1][gr] = 0; + } + } + + if (pBsData->bEnableIcc) { + for (gr = 0; gr < NO_HI_RES_ICC_BINS; gr++) { + pBsData->aaIccIndex[pBsData->noEnv-1][gr] = + h_ps_d->specificTo.mpeg.aIccPrevFrameIndex[gr]; + } + } + else { + for (gr = 0; gr < NO_HI_RES_ICC_BINS; gr++) { + pBsData->aaIccIndex[pBsData->noEnv-1][gr] = 0; + } + } + } + + /* Update previous frame index buffers */ + for (gr = 0; gr < NO_HI_RES_IID_BINS; gr++) { + h_ps_d->specificTo.mpeg.aIidPrevFrameIndex[gr] = + pBsData->aaIidIndex[pBsData->noEnv-1][gr]; + } + for (gr = 0; gr < NO_HI_RES_ICC_BINS; gr++) { + h_ps_d->specificTo.mpeg.aIccPrevFrameIndex[gr] = + pBsData->aaIccIndex[pBsData->noEnv-1][gr]; + } + + /* PS data from bitstream (if avail) was decoded now */ + h_ps_d->bPsDataAvail[h_ps_d->processSlot] = ppt_none; + + /* handling of env borders for FIX & VAR */ + if (pBsData->bFrameClass == 0) { + /* FIX_BORDERS NoEnv=0,1,2,4 */ + pBsData->aEnvStartStop[0] = 0; + for (env=1; envnoEnv; env++) { + pBsData->aEnvStartStop[env] = + (env * h_ps_d->noSubSamples) / pBsData->noEnv; + } + pBsData->aEnvStartStop[pBsData->noEnv] = h_ps_d->noSubSamples; + /* 1024 (32 slots) env borders: 0, 8, 16, 24, 32 */ + /* 960 (30 slots) env borders: 0, 7, 15, 22, 30 */ + } + else { /* if (h_ps_d->bFrameClass == 0) */ + /* VAR_BORDERS NoEnv=1,2,3,4 */ + pBsData->aEnvStartStop[0] = 0; + + /* handle case aEnvStartStop[noEnv]aEnvStartStop[pBsData->noEnv] < h_ps_d->noSubSamples) { + for (gr = 0; gr < NO_HI_RES_IID_BINS; gr++) { + pBsData->aaIidIndex[pBsData->noEnv][gr] = + pBsData->aaIidIndex[pBsData->noEnv-1][gr]; + } + for (gr = 0; gr < NO_HI_RES_ICC_BINS; gr++) { + pBsData->aaIccIndex[pBsData->noEnv][gr] = + pBsData->aaIccIndex[pBsData->noEnv-1][gr]; + } + pBsData->noEnv++; + pBsData->aEnvStartStop[pBsData->noEnv] = h_ps_d->noSubSamples; + } + + /* enforce strictly monotonic increasing borders */ + for (env=1; envnoEnv; env++) { + UCHAR thr; + thr = (UCHAR)h_ps_d->noSubSamples - (pBsData->noEnv - env); + if (pBsData->aEnvStartStop[env] > thr) { + pBsData->aEnvStartStop[env] = thr; + } + else { + thr = pBsData->aEnvStartStop[env-1]+1; + if (pBsData->aEnvStartStop[env] < thr) { + pBsData->aEnvStartStop[env] = thr; + } + } + } + } /* if (h_ps_d->bFrameClass == 0) ... else */ + + /* copy data prior to possible 20<->34 in-place mapping */ + for (env=0; envnoEnv; env++) { + UCHAR i; + for (i=0; ispecificTo.mpeg.coef.aaIidIndexMapped[env][i] = pBsData->aaIidIndex[env][i]; + } + for (i=0; ispecificTo.mpeg.coef.aaIccIndexMapped[env][i] = pBsData->aaIccIndex[env][i]; + } + } + + + /* MPEG baseline PS */ + /* Baseline version of PS always uses the hybrid filter structure with 20 stereo bands. */ + /* If ICC/IID parameters for 34 stereo bands are decoded they have to be mapped to 20 */ + /* stereo bands. */ + /* Additionaly the IPD/OPD parameters won't be used. */ + + for (env=0; envnoEnv; env++) { + if (pBsData->freqResIid == 2) + map34IndexTo20 (h_ps_d->specificTo.mpeg.coef.aaIidIndexMapped[env], NO_HI_RES_IID_BINS); + if (pBsData->freqResIcc == 2) + map34IndexTo20 (h_ps_d->specificTo.mpeg.coef.aaIccIndexMapped[env], NO_HI_RES_ICC_BINS); + + /* IPD/OPD is disabled in baseline version and thus was removed here */ + } + + return (1); +} + + +/***************************************************************************/ +/*! + + \brief Reads parametric stereo data from bitstream + + \return + +****************************************************************************/ +unsigned int +ReadPsData (HANDLE_PS_DEC h_ps_d, /*!< handle to struct PS_DEC */ + HANDLE_FDK_BITSTREAM hBitBuf, /*!< handle to struct BIT_BUF */ + int nBitsLeft /*!< max number of bits available */ + ) +{ + MPEG_PS_BS_DATA *pBsData; + + UCHAR gr, env; + SCHAR dtFlag; + INT startbits; + Huffman CurrentTable; + SCHAR bEnableHeader; + + if (!h_ps_d) + return 0; + + pBsData = &h_ps_d->bsData[h_ps_d->bsReadSlot].mpeg; + + if (h_ps_d->bsReadSlot != h_ps_d->bsLastSlot) { + /* Copy last header data */ + FDKmemcpy(pBsData, &h_ps_d->bsData[h_ps_d->bsLastSlot].mpeg, sizeof(MPEG_PS_BS_DATA)); + } + + + startbits = (INT) FDKgetValidBits(hBitBuf); + + bEnableHeader = (SCHAR) FDKreadBits (hBitBuf, 1); + + /* Read header */ + if (bEnableHeader) { + pBsData->bPsHeaderValid = 1; + pBsData->bEnableIid = (UCHAR) FDKreadBits (hBitBuf, 1); + if (pBsData->bEnableIid) { + pBsData->modeIid = (UCHAR) FDKreadBits (hBitBuf, 3); + } + + pBsData->bEnableIcc = (UCHAR) FDKreadBits (hBitBuf, 1); + if (pBsData->bEnableIcc) { + pBsData->modeIcc = (UCHAR) FDKreadBits (hBitBuf, 3); + } + + pBsData->bEnableExt = (UCHAR) FDKreadBits (hBitBuf, 1); + } + + pBsData->bFrameClass = (UCHAR) FDKreadBits (hBitBuf, 1); + if (pBsData->bFrameClass == 0) { + /* FIX_BORDERS NoEnv=0,1,2,4 */ + pBsData->noEnv = FDK_sbrDecoder_aFixNoEnvDecode[(UCHAR) FDKreadBits (hBitBuf, 2)]; + /* all additional handling of env borders is now in DecodePs() */ + } + else { + /* VAR_BORDERS NoEnv=1,2,3,4 */ + pBsData->noEnv = 1+(UCHAR) FDKreadBits (hBitBuf, 2); + for (env=1; envnoEnv+1; env++) + pBsData->aEnvStartStop[env] = ((UCHAR) FDKreadBits (hBitBuf, 5)) + 1; + /* all additional handling of env borders is now in DecodePs() */ + } + + /* verify that IID & ICC modes (quant grid, freq res) are supported */ + if ((pBsData->modeIid > 5) || (pBsData->modeIcc > 5)) { + /* no useful PS data could be read from bitstream */ + h_ps_d->bPsDataAvail[h_ps_d->bsReadSlot] = ppt_none; + /* discard all remaining bits */ + nBitsLeft -= startbits - FDKgetValidBits(hBitBuf); + while (nBitsLeft) { + int i = nBitsLeft; + if (i>8) { + i = 8; + } + FDKreadBits (hBitBuf, i); + nBitsLeft -= i; + } + return (startbits - FDKgetValidBits(hBitBuf)); + } + + if (pBsData->modeIid > 2){ + pBsData->freqResIid = pBsData->modeIid-3; + pBsData->bFineIidQ = 1; + } + else{ + pBsData->freqResIid = pBsData->modeIid; + pBsData->bFineIidQ = 0; + } + + if (pBsData->modeIcc > 2){ + pBsData->freqResIcc = pBsData->modeIcc-3; + } + else{ + pBsData->freqResIcc = pBsData->modeIcc; + } + + + /* Extract IID data */ + if (pBsData->bEnableIid) { + for (env=0; envnoEnv; env++) { + dtFlag = (SCHAR)FDKreadBits (hBitBuf, 1); + if (!dtFlag) + { + if (pBsData->bFineIidQ) + CurrentTable = (Huffman)&aBookPsIidFineFreqDecode; + else + CurrentTable = (Huffman)&aBookPsIidFreqDecode; + } + else + { + if (pBsData->bFineIidQ) + CurrentTable = (Huffman)&aBookPsIidFineTimeDecode; + else + CurrentTable = (Huffman)&aBookPsIidTimeDecode; + } + + for (gr = 0; gr < FDK_sbrDecoder_aNoIidBins[pBsData->freqResIid]; gr++) + pBsData->aaIidIndex[env][gr] = decode_huff_cw(CurrentTable,hBitBuf,NULL); + pBsData->abIidDtFlag[env] = dtFlag; + } + } + + /* Extract ICC data */ + if (pBsData->bEnableIcc) { + for (env=0; envnoEnv; env++) { + dtFlag = (SCHAR)FDKreadBits (hBitBuf, 1); + if (!dtFlag) + CurrentTable = (Huffman)&aBookPsIccFreqDecode; + else + CurrentTable = (Huffman)&aBookPsIccTimeDecode; + + for (gr = 0; gr < FDK_sbrDecoder_aNoIccBins[pBsData->freqResIcc]; gr++) + pBsData->aaIccIndex[env][gr] = decode_huff_cw(CurrentTable,hBitBuf,NULL); + pBsData->abIccDtFlag[env] = dtFlag; + } + } + + if (pBsData->bEnableExt) { + + /*! + Decoders that support only the baseline version of the PS tool are allowed + to ignore the IPD/OPD data, but according header data has to be parsed. + ISO/IEC 14496-3 Subpart 8 Annex 4 + */ + + int cnt = FDKreadBits(hBitBuf, PS_EXTENSION_SIZE_BITS); + if (cnt == (1<bPsDataAvail[h_ps_d->bsReadSlot] = ppt_mpeg; + + + + return (startbits - FDKgetValidBits(hBitBuf)); +} + diff --git a/libSBRdec/src/psbitdec.h b/libSBRdec/src/psbitdec.h new file mode 100644 index 0000000..ff94bf8 --- /dev/null +++ b/libSBRdec/src/psbitdec.h @@ -0,0 +1,46 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +#ifndef __PSBITDEC_H +#define __PSBITDEC_H + +#include "sbrdecoder.h" + + +#include "psdec.h" + + +unsigned int +ReadPsData (struct PS_DEC *h_ps_d, + HANDLE_FDK_BITSTREAM hBs, + int nBitsLeft); + +int +DecodePs(struct PS_DEC *h_ps_d, + const UCHAR frameError); + + +#endif /* __PSBITDEC_H */ diff --git a/libSBRdec/src/psdec.cpp b/libSBRdec/src/psdec.cpp new file mode 100644 index 0000000..86ccdc4 --- /dev/null +++ b/libSBRdec/src/psdec.cpp @@ -0,0 +1,1356 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief parametric stereo decoder $Revision: 36841 $ +*/ + +#include "psdec.h" + + + +#include "FDK_bitbuffer.h" +#include "psdec_hybrid.h" + +#include "sbr_rom.h" +#include "sbr_ram.h" + +#include "FDK_tools_rom.h" + +#include "genericStds.h" + +#include "FDK_trigFcts.h" + + +/********************************************************************/ +/* MLQUAL DEFINES */ +/********************************************************************/ + + #define FRACT_ZERO FRACT_BITS-1 +/********************************************************************/ + +SBR_ERROR ResetPsDec( HANDLE_PS_DEC h_ps_d ); + +void ResetPsDeCor( HANDLE_PS_DEC h_ps_d ); + + +/***** HELPERS *****/ + +static void assignTimeSlotsPS (FIXP_DBL *bufAdr, FIXP_DBL **bufPtr, const int numSlots, const int numChan); + + + +/*******************/ + +#define DIV3 FL2FXCONST_DBL(1.f/3.f) /* division 3.0 */ +#define DIV1_5 FL2FXCONST_DBL(2.f/3.f) /* division 1.5 */ + +/***************************************************************************/ +/*! + \brief Creates one instance of the PS_DEC struct + + \return Error info + +****************************************************************************/ +int +CreatePsDec( HANDLE_PS_DEC *h_PS_DEC, /*!< pointer to the module state */ + int aacSamplesPerFrame + ) +{ + SBR_ERROR errorInfo = SBRDEC_OK; + HANDLE_PS_DEC h_ps_d; + int i; + + if (*h_PS_DEC == NULL) { + /* Get ps dec ram */ + h_ps_d = GetRam_ps_dec(); + if (h_ps_d == NULL) { + errorInfo = SBRDEC_MEM_ALLOC_FAILED; + goto bail; + } + } else { + /* Reset an open instance */ + h_ps_d = *h_PS_DEC; + } + + /* initialisation */ + switch (aacSamplesPerFrame) { + case 960: + h_ps_d->noSubSamples = 30; /* col */ + break; + case 1024: + h_ps_d->noSubSamples = 32; /* col */ + break; + default: + h_ps_d->noSubSamples = -1; + break; + } + + if (h_ps_d->noSubSamples > MAX_NUM_COL + || h_ps_d->noSubSamples <= 0) + { + goto bail; + } + h_ps_d->noChannels = NO_QMF_CHANNELS; /* row */ + + h_ps_d->psDecodedPrv = 0; + h_ps_d->procFrameBased = -1; + for (i = 0; i < (1)+1; i++) { + h_ps_d->bPsDataAvail[i] = ppt_none; + } + + + for (i = 0; i < (1)+1; i++) { + FDKmemclear(&h_ps_d->bsData[i].mpeg, sizeof(MPEG_PS_BS_DATA)); + } + + errorInfo = ResetPsDec( h_ps_d ); + + if ( errorInfo != SBRDEC_OK ) + goto bail; + + ResetPsDeCor( h_ps_d ); + + *h_PS_DEC = h_ps_d; + + + + return 0; + +bail: + DeletePsDec(&h_ps_d); + + return -1; +} /*END CreatePsDec */ + +/***************************************************************************/ +/*! + \brief Delete one instance of the PS_DEC struct + + \return Error info + +****************************************************************************/ +int +DeletePsDec( HANDLE_PS_DEC *h_PS_DEC) /*!< pointer to the module state */ +{ + if (*h_PS_DEC == NULL) { + return -1; + } + + + FreeRam_ps_dec(h_PS_DEC); + + + return 0; +} /*END DeletePsDec */ + +/***************************************************************************/ +/*! + \brief resets some values of the PS handle to default states + + \return + +****************************************************************************/ +SBR_ERROR ResetPsDec( HANDLE_PS_DEC h_ps_d ) /*!< pointer to the module state */ +{ + SBR_ERROR errorInfo = SBRDEC_OK; + INT i; + + const UCHAR noQmfBandsInHybrid20 = 3; + /* const UCHAR noQmfBandsInHybrid34 = 5; */ + + const UCHAR aHybridResolution20[] = { HYBRID_8_CPLX, + HYBRID_2_REAL, + HYBRID_2_REAL }; + + h_ps_d->specificTo.mpeg.delayBufIndex = 0; + + /* explicitly init state variables to safe values (until first ps header arrives) */ + + h_ps_d->specificTo.mpeg.lastUsb = 0; + + h_ps_d->specificTo.mpeg.scaleFactorPsDelayBuffer = -(DFRACT_BITS-1); + + FDKmemclear(h_ps_d->specificTo.mpeg.aDelayBufIndexDelayQmf, (NO_QMF_CHANNELS-FIRST_DELAY_SB)*sizeof(UCHAR)); + h_ps_d->specificTo.mpeg.noSampleDelay = delayIndexQmf[0]; + + for (i=0 ; i < NO_SERIAL_ALLPASS_LINKS; i++) { + h_ps_d->specificTo.mpeg.aDelayRBufIndexSer[i] = 0; + } + + h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[0] = h_ps_d->specificTo.mpeg.aaQmfDelayBufReal; + + assignTimeSlotsPS ( h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[0] + (NO_QMF_CHANNELS-FIRST_DELAY_SB), + &h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[1], + h_ps_d->specificTo.mpeg.noSampleDelay-1, + (NO_DELAY_BUFFER_BANDS-FIRST_DELAY_SB)); + + h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[0] = h_ps_d->specificTo.mpeg.aaQmfDelayBufImag; + + assignTimeSlotsPS ( h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[0] + (NO_QMF_CHANNELS-FIRST_DELAY_SB), + &h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[1], + h_ps_d->specificTo.mpeg.noSampleDelay-1, + (NO_DELAY_BUFFER_BANDS-FIRST_DELAY_SB)); + + /* Hybrid Filter Bank 1 creation. */ + errorInfo = InitHybridFilterBank ( &h_ps_d->specificTo.mpeg.hybrid, + h_ps_d->noSubSamples, + noQmfBandsInHybrid20, + aHybridResolution20 ); + + for ( i = 0; i < NO_IID_GROUPS; i++ ) + { + h_ps_d->specificTo.mpeg.h11rPrev[i] = FL2FXCONST_DBL(0.5f); + h_ps_d->specificTo.mpeg.h12rPrev[i] = FL2FXCONST_DBL(0.5f); + } + + FDKmemclear( h_ps_d->specificTo.mpeg.h21rPrev, sizeof( h_ps_d->specificTo.mpeg.h21rPrev ) ); + FDKmemclear( h_ps_d->specificTo.mpeg.h22rPrev, sizeof( h_ps_d->specificTo.mpeg.h22rPrev ) ); + + return errorInfo; +} + +/***************************************************************************/ +/*! + \brief clear some buffers used in decorrelation process + + \return + +****************************************************************************/ +void ResetPsDeCor( HANDLE_PS_DEC h_ps_d ) /*!< pointer to the module state */ +{ + INT i; + + FDKmemclear(h_ps_d->specificTo.mpeg.aPeakDecayFastBin, NO_MID_RES_BINS*sizeof(FIXP_DBL)); + FDKmemclear(h_ps_d->specificTo.mpeg.aPrevNrgBin, NO_MID_RES_BINS*sizeof(FIXP_DBL)); + FDKmemclear(h_ps_d->specificTo.mpeg.aPrevPeakDiffBin, NO_MID_RES_BINS*sizeof(FIXP_DBL)); + FDKmemclear(h_ps_d->specificTo.mpeg.aPowerPrevScal, NO_MID_RES_BINS*sizeof(SCHAR)); + + for (i=0 ; i < FIRST_DELAY_SB ; i++) { + FDKmemclear(h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); + FDKmemclear(h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); + } + for (i=0 ; i < NO_SUB_QMF_CHANNELS ; i++) { + FDKmemclear(h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); + FDKmemclear(h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); + } + +} + +/*******************************************************************************/ + +/* slot based funcion prototypes */ + +static void deCorrelateSlotBased( HANDLE_PS_DEC h_ps_d, + + FIXP_DBL *mHybridRealLeft, + FIXP_DBL *mHybridImagLeft, + SCHAR sf_mHybridLeft, + + FIXP_DBL *rIntBufferLeft, + FIXP_DBL *iIntBufferLeft, + SCHAR sf_IntBuffer, + + FIXP_DBL *mHybridRealRight, + FIXP_DBL *mHybridImagRight, + + FIXP_DBL *rIntBufferRight, + FIXP_DBL *iIntBufferRight ); + +static void applySlotBasedRotation( HANDLE_PS_DEC h_ps_d, + + FIXP_DBL *mHybridRealLeft, + FIXP_DBL *mHybridImagLeft, + + FIXP_DBL *QmfLeftReal, + FIXP_DBL *QmfLeftImag, + + FIXP_DBL *mHybridRealRight, + FIXP_DBL *mHybridImagRight, + + FIXP_DBL *QmfRightReal, + FIXP_DBL *QmfRightImag + ); + + +/***************************************************************************/ +/*! + \brief Get scale factor for all ps delay buffer. + + \return + +****************************************************************************/ +static +int getScaleFactorPsStatesBuffer(HANDLE_PS_DEC h_ps_d) +{ + INT i; + int scale = DFRACT_BITS-1; + + for (i=0; ispecificTo.mpeg.hybrid.mQmfBufferRealSlot[i], NO_SUB_QMF_CHANNELS)); + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.hybrid.mQmfBufferImagSlot[i], NO_SUB_QMF_CHANNELS)); + } + + for (i=0; ispecificTo.mpeg.aaRealDelayBufferQmf[i], FIRST_DELAY_SB)); + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaImagDelayBufferQmf[i], FIRST_DELAY_SB)); + } + + for (i=0; ispecificTo.mpeg.aaRealDelayBufferSubQmf[i], NO_SUB_QMF_CHANNELS)); + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaImagDelayBufferSubQmf[i], NO_SUB_QMF_CHANNELS)); + } + + for (i=0; ispecificTo.mpeg.aaaRealDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS)); + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS)); + } + + for (i=0; ispecificTo.mpeg.aaaRealDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS)); + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS)); + } + + for (i=0; ispecificTo.mpeg.pAaRealDelayBufferQmf[i], len)); + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[i], len)); + } + + return (scale); +} + +/***************************************************************************/ +/*! + \brief Rescale all ps delay buffer. + + \return + +****************************************************************************/ +static +void scalePsStatesBuffer(HANDLE_PS_DEC h_ps_d, + int scale) +{ + INT i; + + if (scale < 0) + scale = fixMax((INT)scale,(INT)-(DFRACT_BITS-1)); + else + scale = fixMin((INT)scale,(INT)DFRACT_BITS-1); + + for (i=0; ispecificTo.mpeg.hybrid.mQmfBufferRealSlot[i], NO_SUB_QMF_CHANNELS, scale ); + scaleValues( h_ps_d->specificTo.mpeg.hybrid.mQmfBufferImagSlot[i], NO_SUB_QMF_CHANNELS, scale ); + } + + for (i=0; ispecificTo.mpeg.aaRealDelayBufferQmf[i], FIRST_DELAY_SB, scale ); + scaleValues( h_ps_d->specificTo.mpeg.aaImagDelayBufferQmf[i], FIRST_DELAY_SB, scale ); + } + + for (i=0; ispecificTo.mpeg.aaRealDelayBufferSubQmf[i], NO_SUB_QMF_CHANNELS, scale ); + scaleValues( h_ps_d->specificTo.mpeg.aaImagDelayBufferSubQmf[i], NO_SUB_QMF_CHANNELS, scale ); + } + + for (i=0; ispecificTo.mpeg.aaaRealDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS, scale ); + scaleValues( h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS, scale ); + } + + for (i=0; ispecificTo.mpeg.aaaRealDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS, scale ); + scaleValues( h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS, scale ); + } + + for (i=0; ispecificTo.mpeg.pAaRealDelayBufferQmf[i], len, scale ); + scaleValues( h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[i], len, scale ); + } + + scale <<= 1; + + scaleValues( h_ps_d->specificTo.mpeg.aPeakDecayFastBin, NO_MID_RES_BINS, scale ); + scaleValues( h_ps_d->specificTo.mpeg.aPrevPeakDiffBin, NO_MID_RES_BINS, scale ); + scaleValues( h_ps_d->specificTo.mpeg.aPrevNrgBin, NO_MID_RES_BINS, scale ); +} + +/***************************************************************************/ +/*! + \brief Scale input channel to the same scalefactor and rescale hybrid + filterbank values + + \return + +****************************************************************************/ + +void scalFilterBankValues( HANDLE_PS_DEC h_ps_d, + FIXP_DBL **fixpQmfReal, + FIXP_DBL **fixpQmfImag, + int lsb, + int scaleFactorLowBandSplitLow, + int scaleFactorLowBandSplitHigh, + SCHAR *scaleFactorLowBand_lb, + SCHAR *scaleFactorLowBand_hb, + int scaleFactorHighBands, + INT *scaleFactorHighBand, + INT noCols + ) +{ + INT maxScal; + + INT i; + + scaleFactorHighBands = -scaleFactorHighBands; + scaleFactorLowBandSplitLow = -scaleFactorLowBandSplitLow; + scaleFactorLowBandSplitHigh = -scaleFactorLowBandSplitHigh; + + /* get max scale factor */ + maxScal = fixMax(scaleFactorHighBands,fixMax(scaleFactorLowBandSplitLow, scaleFactorLowBandSplitHigh )); + + { + int headroom = getScaleFactorPsStatesBuffer(h_ps_d); + maxScal = fixMax(maxScal,(INT)(h_ps_d->specificTo.mpeg.scaleFactorPsDelayBuffer-headroom)); + maxScal += 1; + } + + /* scale whole left channel to the same scale factor */ + + /* low band ( overlap buffer ) */ + if ( maxScal != scaleFactorLowBandSplitLow ) { + INT scale = scaleFactorLowBandSplitLow - maxScal; + for ( i=0; i<(6); i++ ) { + scaleValues( fixpQmfReal[i], lsb, scale ); + scaleValues( fixpQmfImag[i], lsb, scale ); + } + } + /* low band ( current frame ) */ + if ( maxScal != scaleFactorLowBandSplitHigh ) { + INT scale = scaleFactorLowBandSplitHigh - maxScal; + /* for ( i=(6); i<(6)+MAX_NUM_COL; i++ ) { */ + for ( i=(6); i<(6)+noCols; i++ ) { + scaleValues( fixpQmfReal[i], lsb, scale ); + scaleValues( fixpQmfImag[i], lsb, scale ); + } + } + /* high band */ + if ( maxScal != scaleFactorHighBands ) { + INT scale = scaleFactorHighBands - maxScal; + /* for ( i=0; ispecificTo.mpeg.scaleFactorPsDelayBuffer ) + scalePsStatesBuffer(h_ps_d,(h_ps_d->specificTo.mpeg.scaleFactorPsDelayBuffer-maxScal)); + + h_ps_d->specificTo.mpeg.hybrid.sf_mQmfBuffer = maxScal; + h_ps_d->specificTo.mpeg.scaleFactorPsDelayBuffer = maxScal; + + *scaleFactorHighBand += maxScal - scaleFactorHighBands; + + h_ps_d->rescal = maxScal - scaleFactorLowBandSplitHigh; + h_ps_d->sf_IntBuffer = maxScal; + + *scaleFactorLowBand_lb += maxScal - scaleFactorLowBandSplitLow; + *scaleFactorLowBand_hb += maxScal - scaleFactorLowBandSplitHigh; +} + +void rescalFilterBankValues( HANDLE_PS_DEC h_ps_d, /* parametric stereo decoder handle */ + FIXP_DBL **QmfBufferReal, /* qmf filterbank values */ + FIXP_DBL **QmfBufferImag, /* qmf filterbank values */ + int lsb, /* sbr start subband */ + INT noCols) +{ + int i; + /* scale back 6 timeslots look ahead for hybrid filterbank to original value */ + for ( i=noCols; irescal ); + scaleValues( QmfBufferImag[i], lsb, h_ps_d->rescal ); + } +} + +/***************************************************************************/ +/*! + \brief Generate decorrelated side channel using allpass/delay + + \return + +****************************************************************************/ +static void +deCorrelateSlotBased( HANDLE_PS_DEC h_ps_d, /*!< pointer to the module state */ + + FIXP_DBL *mHybridRealLeft, /*!< left (mono) hybrid values real */ + FIXP_DBL *mHybridImagLeft, /*!< left (mono) hybrid values imag */ + SCHAR sf_mHybridLeft, /*!< scalefactor for left (mono) hybrid bands */ + + FIXP_DBL *rIntBufferLeft, /*!< real qmf bands left (mono) (38x64) */ + FIXP_DBL *iIntBufferLeft, /*!< real qmf bands left (mono) (38x64) */ + SCHAR sf_IntBuffer, /*!< scalefactor for all left and right qmf bands */ + + FIXP_DBL *mHybridRealRight, /*!< right (decorrelated) hybrid values real */ + FIXP_DBL *mHybridImagRight, /*!< right (decorrelated) hybrid values imag */ + + FIXP_DBL *rIntBufferRight, /*!< real qmf bands right (decorrelated) (38x64) */ + FIXP_DBL *iIntBufferRight ) /*!< real qmf bands right (decorrelated) (38x64) */ +{ + + INT i, m, sb, gr, bin; + + FIXP_DBL peakDiff, nrg, transRatio; + + FIXP_DBL *RESTRICT aaLeftReal; + FIXP_DBL *RESTRICT aaLeftImag; + + FIXP_DBL *RESTRICT aaRightReal; + FIXP_DBL *RESTRICT aaRightImag; + + FIXP_DBL *RESTRICT pRealDelayBuffer; + FIXP_DBL *RESTRICT pImagDelayBuffer; + + C_ALLOC_SCRATCH_START(aaPowerSlot, FIXP_DBL, NO_MID_RES_BINS); + C_ALLOC_SCRATCH_START(aaTransRatioSlot, FIXP_DBL, NO_MID_RES_BINS); + +/*! +
+   parameter index       qmf bands             hybrid bands
+  ----------------------------------------------------------------------------
+         0                   0                      0,7
+         1                   0                      1,6
+         2                   0                      2
+         3                   0                      3           HYBRID BANDS
+         4                   1                      9
+         5                   1                      8
+         6                   2                     10
+         7                   2                     11
+  ----------------------------------------------------------------------------
+         8                   3
+         9                   4
+        10                   5
+        11                   6
+        12                   7
+        13                   8
+        14                   9,10      (2 )                      QMF BANDS
+        15                   11 - 13   (3 )
+        16                   14 - 17   (4 )
+        17                   18 - 22   (5 )
+        18                   23 - 34   (12)
+        19                   35 - 63   (29)
+  ----------------------------------------------------------------------------
+
+*/ + + #define FLTR_SCALE 3 + + /* hybrid bands (parameter index 0 - 7) */ + aaLeftReal = mHybridRealLeft; + aaLeftImag = mHybridImagLeft; + + aaPowerSlot[0] = ( fMultAddDiv2( fMultDiv2(aaLeftReal[0], aaLeftReal[0]), aaLeftImag[0], aaLeftImag[0] ) >> FLTR_SCALE ) + + ( fMultAddDiv2( fMultDiv2(aaLeftReal[7], aaLeftReal[7]), aaLeftImag[7], aaLeftImag[7] ) >> FLTR_SCALE ); + + aaPowerSlot[1] = ( fMultAddDiv2( fMultDiv2(aaLeftReal[1], aaLeftReal[1]), aaLeftImag[1], aaLeftImag[1] ) >> FLTR_SCALE ) + + ( fMultAddDiv2( fMultDiv2(aaLeftReal[6], aaLeftReal[6]), aaLeftImag[6], aaLeftImag[6] ) >> FLTR_SCALE ); + + aaPowerSlot[2] = fMultAddDiv2( fMultDiv2(aaLeftReal[2], aaLeftReal[2]), aaLeftImag[2], aaLeftImag[2] ) >> FLTR_SCALE; + aaPowerSlot[3] = fMultAddDiv2( fMultDiv2(aaLeftReal[3], aaLeftReal[3]), aaLeftImag[3], aaLeftImag[3] ) >> FLTR_SCALE; + + aaPowerSlot[4] = fMultAddDiv2( fMultDiv2(aaLeftReal[9], aaLeftReal[9]), aaLeftImag[9], aaLeftImag[9] ) >> FLTR_SCALE; + aaPowerSlot[5] = fMultAddDiv2( fMultDiv2(aaLeftReal[8], aaLeftReal[8]), aaLeftImag[8], aaLeftImag[8] ) >> FLTR_SCALE; + + aaPowerSlot[6] = fMultAddDiv2( fMultDiv2(aaLeftReal[10], aaLeftReal[10]), aaLeftImag[10], aaLeftImag[10] ) >> FLTR_SCALE; + aaPowerSlot[7] = fMultAddDiv2( fMultDiv2(aaLeftReal[11], aaLeftReal[11]), aaLeftImag[11], aaLeftImag[11] ) >> FLTR_SCALE; + + /* qmf bands (parameter index 8 - 19) */ + for ( bin = 8; bin < NO_MID_RES_BINS; bin++ ) { + FIXP_DBL slotNrg = FL2FXCONST_DBL(0.f); + + for ( i = groupBorders20[bin+2]; i < groupBorders20[bin+3]; i++ ) { /* max loops: 29 */ + slotNrg += fMultAddDiv2 ( fMultDiv2(rIntBufferLeft[i], rIntBufferLeft[i]), iIntBufferLeft[i], iIntBufferLeft[i]) >> FLTR_SCALE; + } + aaPowerSlot[bin] = slotNrg; + + } + + + /* calculation of transient ratio */ + for (bin=0; bin < NO_MID_RES_BINS; bin++) { /* noBins = 20 ( BASELINE_PS ) */ + + h_ps_d->specificTo.mpeg.aPeakDecayFastBin[bin] = fMult( h_ps_d->specificTo.mpeg.aPeakDecayFastBin[bin], PEAK_DECAY_FACTOR ); + + if (h_ps_d->specificTo.mpeg.aPeakDecayFastBin[bin] < aaPowerSlot[bin]) { + h_ps_d->specificTo.mpeg.aPeakDecayFastBin[bin] = aaPowerSlot[bin]; + } + + /* calculate PSmoothPeakDecayDiffNrg */ + peakDiff = fMultAdd ( (h_ps_d->specificTo.mpeg.aPrevPeakDiffBin[bin]>>1), + INT_FILTER_COEFF, h_ps_d->specificTo.mpeg.aPeakDecayFastBin[bin] - aaPowerSlot[bin] - h_ps_d->specificTo.mpeg.aPrevPeakDiffBin[bin]); + + /* save peakDiff for the next frame */ + h_ps_d->specificTo.mpeg.aPrevPeakDiffBin[bin] = peakDiff; + + nrg = h_ps_d->specificTo.mpeg.aPrevNrgBin[bin] + fMult( INT_FILTER_COEFF, aaPowerSlot[bin] - h_ps_d->specificTo.mpeg.aPrevNrgBin[bin] ); + + /* Negative energies don't exist. But sometimes they appear due to rounding. */ + + nrg = fixMax(nrg,FL2FXCONST_DBL(0.f)); + + /* save nrg for the next frame */ + h_ps_d->specificTo.mpeg.aPrevNrgBin[bin] = nrg; + + nrg = fMult( nrg, TRANSIENT_IMPACT_FACTOR ); + + /* save transient impact factor */ + if ( peakDiff <= nrg || peakDiff == FL2FXCONST_DBL(0.0) ) { + aaTransRatioSlot[bin] = (FIXP_DBL)MAXVAL_DBL /* FL2FXCONST_DBL(1.0f)*/; + } + else if ( nrg <= FL2FXCONST_DBL(0.0f) ) { + aaTransRatioSlot[bin] = FL2FXCONST_DBL(0.f); + } + else { + /* scale to denominator */ + INT scale_left = fixMax(0, CntLeadingZeros(peakDiff) - 1); + aaTransRatioSlot[bin] = schur_div( nrg<specificTo.mpeg.delayBufIndex; /* set delay indices */ + + pRealDelayBuffer = h_ps_d->specificTo.mpeg.aaRealDelayBufferSubQmf[TempDelay]; + pImagDelayBuffer = h_ps_d->specificTo.mpeg.aaImagDelayBufferSubQmf[TempDelay]; + + aaLeftReal = mHybridRealLeft; + aaLeftImag = mHybridImagLeft; + aaRightReal = mHybridRealRight; + aaRightImag = mHybridImagRight; + + /************************/ + /* ICC groups : 0 - 9 */ + /************************/ + + /* gr = ICC groups */ + for (gr=0; gr < SUBQMF_GROUPS; gr++) { + + transRatio = aaTransRatioSlot[bins2groupMap20[gr]]; + + /* sb = subQMF/QMF subband */ + sb = groupBorders20[gr]; + + /* Update delay buffers, sample delay allpass = 2 */ + rTmp0 = pRealDelayBuffer[sb]; + iTmp0 = pImagDelayBuffer[sb]; + + pRealDelayBuffer[sb] = aaLeftReal[sb]; + pImagDelayBuffer[sb] = aaLeftImag[sb]; + + /* delay by fraction */ + cplxMultDiv2(&rR0, &iR0, rTmp0, iTmp0, aaFractDelayPhaseFactorReSubQmf20[sb], aaFractDelayPhaseFactorImSubQmf20[sb]); + rR0<<=1; + iR0<<=1; + + FIXP_DBL *pAaaRealDelayRBufferSerSubQmf = h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerSubQmf[sb]; + FIXP_DBL *pAaaImagDelayRBufferSerSubQmf = h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerSubQmf[sb]; + + for (m=0; mspecificTo.mpeg.aDelayRBufIndexSer[m]; + + /* get delayed values from according buffer : m(0)=3; m(1)=4; m(2)=5; */ + rTmp0 = pAaaRealDelayRBufferSerSubQmf[tmpDelayRSer]; + iTmp0 = pAaaImagDelayRBufferSerSubQmf[tmpDelayRSer]; + + /* delay by fraction */ + cplxMultDiv2(&rTmp, &iTmp, rTmp0, iTmp0, aaFractDelayPhaseFactorSerReSubQmf20[sb][m], aaFractDelayPhaseFactorSerImSubQmf20[sb][m]); + + rTmp = (rTmp - fMultDiv2(aAllpassLinkDecaySer[m], rR0)) << 1; + iTmp = (iTmp - fMultDiv2(aAllpassLinkDecaySer[m], iR0)) << 1; + + pAaaRealDelayRBufferSerSubQmf[tmpDelayRSer] = rR0 + fMult(aAllpassLinkDecaySer[m], rTmp); + pAaaImagDelayRBufferSerSubQmf[tmpDelayRSer] = iR0 + fMult(aAllpassLinkDecaySer[m], iTmp); + + rR0 = rTmp; + iR0 = iTmp; + + pAaaRealDelayRBufferSerSubQmf += aAllpassLinkDelaySer[m]; + pAaaImagDelayRBufferSerSubQmf += aAllpassLinkDelaySer[m]; + + } /* m */ + + /* duck if a past transient is found */ + aaRightReal[sb] = fMult(transRatio, rR0); + aaRightImag[sb] = fMult(transRatio, iR0); + + } /* gr */ + + + scaleValues( mHybridRealLeft, NO_SUB_QMF_CHANNELS, -SCAL_HEADROOM ); + scaleValues( mHybridImagLeft, NO_SUB_QMF_CHANNELS, -SCAL_HEADROOM ); + scaleValues( mHybridRealRight, NO_SUB_QMF_CHANNELS, -SCAL_HEADROOM ); + scaleValues( mHybridImagRight, NO_SUB_QMF_CHANNELS, -SCAL_HEADROOM ); + + + /************************/ + + aaLeftReal = rIntBufferLeft; + aaLeftImag = iIntBufferLeft; + aaRightReal = rIntBufferRight; + aaRightImag = iIntBufferRight; + + pRealDelayBuffer = h_ps_d->specificTo.mpeg.aaRealDelayBufferQmf[TempDelay]; + pImagDelayBuffer = h_ps_d->specificTo.mpeg.aaImagDelayBufferQmf[TempDelay]; + + /************************/ + /* ICC groups : 10 - 19 */ + /************************/ + + + /* gr = ICC groups */ + for (gr=SUBQMF_GROUPS; gr < NO_IID_GROUPS - NR_OF_DELAY_GROUPS; gr++) { + + transRatio = aaTransRatioSlot[bins2groupMap20[gr]]; + + /* sb = subQMF/QMF subband */ + for (sb = groupBorders20[gr]; sb < groupBorders20[gr+1]; sb++) { + FIXP_DBL resR, resI; + + /* decayScaleFactor = 1.0f + decay_cutoff * DECAY_SLOPE - DECAY_SLOPE * sb; DECAY_SLOPE = 0.05 */ + FIXP_DBL decayScaleFactor = decayScaleFactTable[sb]; + + /* Update delay buffers, sample delay allpass = 2 */ + rTmp0 = pRealDelayBuffer[sb]; + iTmp0 = pImagDelayBuffer[sb]; + + pRealDelayBuffer[sb] = aaLeftReal[sb]; + pImagDelayBuffer[sb] = aaLeftImag[sb]; + + /* delay by fraction */ + cplxMultDiv2(&rR0, &iR0, rTmp0, iTmp0, aaFractDelayPhaseFactorReQmf[sb], aaFractDelayPhaseFactorImQmf[sb]); + rR0<<=1; + iR0<<=1; + + resR = fMult(decayScaleFactor, rR0); + resI = fMult(decayScaleFactor, iR0); + + FIXP_DBL *pAaaRealDelayRBufferSerQmf = h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerQmf[sb]; + FIXP_DBL *pAaaImagDelayRBufferSerQmf = h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerQmf[sb]; + + for (m=0; mspecificTo.mpeg.aDelayRBufIndexSer[m]; + + /* get delayed values from according buffer : m(0)=3; m(1)=4; m(2)=5; */ + rTmp0 = pAaaRealDelayRBufferSerQmf[tmpDelayRSer]; + iTmp0 = pAaaImagDelayRBufferSerQmf[tmpDelayRSer]; + + /* delay by fraction */ + cplxMultDiv2(&rTmp, &iTmp, rTmp0, iTmp0, aaFractDelayPhaseFactorSerReQmf[sb][m], aaFractDelayPhaseFactorSerImQmf[sb][m]); + + rTmp = (rTmp - fMultDiv2(aAllpassLinkDecaySer[m], resR))<<1; + iTmp = (iTmp - fMultDiv2(aAllpassLinkDecaySer[m], resI))<<1; + + resR = fMult(decayScaleFactor, rTmp); + resI = fMult(decayScaleFactor, iTmp); + + pAaaRealDelayRBufferSerQmf[tmpDelayRSer] = rR0 + fMult(aAllpassLinkDecaySer[m], resR); + pAaaImagDelayRBufferSerQmf[tmpDelayRSer] = iR0 + fMult(aAllpassLinkDecaySer[m], resI); + + rR0 = rTmp; + iR0 = iTmp; + + pAaaRealDelayRBufferSerQmf += aAllpassLinkDelaySer[m]; + pAaaImagDelayRBufferSerQmf += aAllpassLinkDelaySer[m]; + + } /* m */ + + /* duck if a past transient is found */ + aaRightReal[sb] = fMult(transRatio, rR0); + aaRightImag[sb] = fMult(transRatio, iR0); + + } /* sb */ + } /* gr */ + + /************************/ + /* ICC groups : 20, 21 */ + /************************/ + + + /* gr = ICC groups */ + for (gr=DELAY_GROUP_OFFSET; gr < NO_IID_GROUPS; gr++) { + + INT sbStart = groupBorders20[gr]; + INT sbStop = groupBorders20[gr+1]; + + UCHAR *pDelayBufIdx = &h_ps_d->specificTo.mpeg.aDelayBufIndexDelayQmf[sbStart-FIRST_DELAY_SB]; + + transRatio = aaTransRatioSlot[bins2groupMap20[gr]]; + + /* sb = subQMF/QMF subband */ + for (sb = sbStart; sb < sbStop; sb++) { + + /* Update delay buffers */ + rR0 = h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[*pDelayBufIdx][sb-FIRST_DELAY_SB]; + iR0 = h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[*pDelayBufIdx][sb-FIRST_DELAY_SB]; + + h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[*pDelayBufIdx][sb-FIRST_DELAY_SB] = aaLeftReal[sb]; + h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[*pDelayBufIdx][sb-FIRST_DELAY_SB] = aaLeftImag[sb]; + + /* duck if a past transient is found */ + aaRightReal[sb] = fMult(transRatio, rR0); + aaRightImag[sb] = fMult(transRatio, iR0); + + if (++(*pDelayBufIdx) >= delayIndexQmf[sb]) { + *pDelayBufIdx = 0; + } + pDelayBufIdx++; + + } /* sb */ + } /* gr */ + + + /* Update delay buffer index */ + if (++h_ps_d->specificTo.mpeg.delayBufIndex >= NO_SAMPLE_DELAY_ALLPASS) + h_ps_d->specificTo.mpeg.delayBufIndex = 0; + + for (m=0; mspecificTo.mpeg.aDelayRBufIndexSer[m] >= aAllpassLinkDelaySer[m]) + h_ps_d->specificTo.mpeg.aDelayRBufIndexSer[m] = 0; + } + + + scaleValues( &rIntBufferLeft[NO_QMF_BANDS_HYBRID20], NO_QMF_CHANNELS-NO_QMF_BANDS_HYBRID20, -SCAL_HEADROOM ); + scaleValues( &iIntBufferLeft[NO_QMF_BANDS_HYBRID20], NO_QMF_CHANNELS-NO_QMF_BANDS_HYBRID20, -SCAL_HEADROOM ); + scaleValues( &rIntBufferRight[NO_QMF_BANDS_HYBRID20], NO_QMF_CHANNELS-NO_QMF_BANDS_HYBRID20, -SCAL_HEADROOM ); + scaleValues( &iIntBufferRight[NO_QMF_BANDS_HYBRID20], NO_QMF_CHANNELS-NO_QMF_BANDS_HYBRID20, -SCAL_HEADROOM ); + + /* free memory on scratch */ + C_ALLOC_SCRATCH_END(aaTransRatioSlot, FIXP_DBL, NO_MID_RES_BINS); + C_ALLOC_SCRATCH_END(aaPowerSlot, FIXP_DBL, NO_MID_RES_BINS); +} + + +void initSlotBasedRotation( HANDLE_PS_DEC h_ps_d, /*!< pointer to the module state */ + int env, + int usb + ) { + + INT group = 0; + INT bin = 0; + INT noIidSteps; + +/* const UCHAR *pQuantizedIIDs;*/ + + FIXP_SGL invL; + FIXP_DBL ScaleL, ScaleR; + FIXP_DBL Alpha, Beta; + FIXP_DBL h11r, h12r, h21r, h22r; + + const FIXP_DBL *PScaleFactors; + + /* Overwrite old values in delay buffers when upper subband is higher than in last frame */ + if (env == 0) { + + if ((usb > h_ps_d->specificTo.mpeg.lastUsb) && h_ps_d->specificTo.mpeg.lastUsb) { + + INT i,k,length; + + for (i=h_ps_d->specificTo.mpeg.lastUsb ; i < FIRST_DELAY_SB; i++) { + FDKmemclear(h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); + FDKmemclear(h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); + } + + for (k=0 ; kspecificTo.mpeg.pAaRealDelayBufferQmf[k], FIRST_DELAY_SB*sizeof(FIXP_DBL)); + } + length = (usb-FIRST_DELAY_SB)*sizeof(FIXP_DBL); + if(length>0) { + FDKmemclear(h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[0], length); + FDKmemclear(h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[0], length); + } + length = (fixMin(NO_DELAY_BUFFER_BANDS,(INT)usb)-FIRST_DELAY_SB)*sizeof(FIXP_DBL); + if(length>0) { + for (k=1 ; k < h_ps_d->specificTo.mpeg.noSampleDelay; k++) { + FDKmemclear(h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[k], length); + FDKmemclear(h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[k], length); + } + } + } + h_ps_d->specificTo.mpeg.lastUsb = usb; + } /* env == 0 */ + + if (h_ps_d->bsData[h_ps_d->processSlot].mpeg.bFineIidQ) + { + PScaleFactors = ScaleFactorsFine; /* values are shiftet right by one */ + noIidSteps = NO_IID_STEPS_FINE; + /*pQuantizedIIDs = quantizedIIDsFine;*/ + } + + else + { + PScaleFactors = ScaleFactors; /* values are shiftet right by one */ + noIidSteps = NO_IID_STEPS; + /*pQuantizedIIDs = quantizedIIDs;*/ + } + + + /* dequantize and decode */ + for ( group = 0; group < NO_IID_GROUPS; group++ ) { + + bin = bins2groupMap20[group]; + + /*! +

type 'A' rotation

+ mixing procedure R_a, used in baseline version
+ + Scale-factor vectors c1 and c2 are precalculated in initPsTables () and stored in + scaleFactors[] and scaleFactorsFine[] = pScaleFactors []. + From the linearized IID parameters (intensity differences), two scale factors are + calculated. They are used to obtain the coefficients h11... h22. + */ + + /* ScaleR and ScaleL are scaled by 1 shift right */ + + ScaleR = PScaleFactors[noIidSteps + h_ps_d->specificTo.mpeg.coef.aaIidIndexMapped[env][bin]]; + ScaleL = PScaleFactors[noIidSteps - h_ps_d->specificTo.mpeg.coef.aaIidIndexMapped[env][bin]]; + + Beta = fMult (fMult( Alphas[h_ps_d->specificTo.mpeg.coef.aaIccIndexMapped[env][bin]], ( ScaleR - ScaleL )), FIXP_SQRT05); + Alpha = Alphas[h_ps_d->specificTo.mpeg.coef.aaIccIndexMapped[env][bin]]>>1; + + /* Alpha and Beta are now both scaled by 2 shifts right */ + + /* calculate the coefficients h11... h22 from scale-factors and ICC parameters */ + + /* h values are scaled by 1 shift right */ + { + FIXP_DBL trigData[4]; + + inline_fixp_cos_sin(Beta + Alpha, Beta - Alpha, 2, trigData); + h11r = fMult( ScaleL, trigData[0]); + h12r = fMult( ScaleR, trigData[2]); + h21r = fMult( ScaleL, trigData[1]); + h22r = fMult( ScaleR, trigData[3]); + } + /*****************************************************************************************/ + /* Interpolation of the matrices H11... H22: */ + /* */ + /* H11(k,n) = H11(k,n[e]) + (n-n[e]) * (H11(k,n[e+1] - H11(k,n[e])) / (n[e+1] - n[e]) */ + /* ... */ + /*****************************************************************************************/ + + /* invL = 1/(length of envelope) */ + invL = FX_DBL2FX_SGL(GetInvInt(h_ps_d->bsData[h_ps_d->processSlot].mpeg.aEnvStartStop[env + 1] - h_ps_d->bsData[h_ps_d->processSlot].mpeg.aEnvStartStop[env])); + + h_ps_d->specificTo.mpeg.coef.H11r[group] = h_ps_d->specificTo.mpeg.h11rPrev[group]; + h_ps_d->specificTo.mpeg.coef.H12r[group] = h_ps_d->specificTo.mpeg.h12rPrev[group]; + h_ps_d->specificTo.mpeg.coef.H21r[group] = h_ps_d->specificTo.mpeg.h21rPrev[group]; + h_ps_d->specificTo.mpeg.coef.H22r[group] = h_ps_d->specificTo.mpeg.h22rPrev[group]; + + h_ps_d->specificTo.mpeg.coef.DeltaH11r[group] = fMult ( h11r - h_ps_d->specificTo.mpeg.coef.H11r[group], invL ); + h_ps_d->specificTo.mpeg.coef.DeltaH12r[group] = fMult ( h12r - h_ps_d->specificTo.mpeg.coef.H12r[group], invL ); + h_ps_d->specificTo.mpeg.coef.DeltaH21r[group] = fMult ( h21r - h_ps_d->specificTo.mpeg.coef.H21r[group], invL ); + h_ps_d->specificTo.mpeg.coef.DeltaH22r[group] = fMult ( h22r - h_ps_d->specificTo.mpeg.coef.H22r[group], invL ); + + /* update prev coefficients for interpolation in next envelope */ + + h_ps_d->specificTo.mpeg.h11rPrev[group] = h11r; + h_ps_d->specificTo.mpeg.h12rPrev[group] = h12r; + h_ps_d->specificTo.mpeg.h21rPrev[group] = h21r; + h_ps_d->specificTo.mpeg.h22rPrev[group] = h22r; + + } /* group loop */ +} + + +static void applySlotBasedRotation( HANDLE_PS_DEC h_ps_d, /*!< pointer to the module state */ + + FIXP_DBL *mHybridRealLeft, /*!< hybrid values real left */ + FIXP_DBL *mHybridImagLeft, /*!< hybrid values imag left */ + + FIXP_DBL *QmfLeftReal, /*!< real bands left qmf channel */ + FIXP_DBL *QmfLeftImag, /*!< imag bands left qmf channel */ + + FIXP_DBL *mHybridRealRight, /*!< hybrid values real right */ + FIXP_DBL *mHybridImagRight, /*!< hybrid values imag right */ + + FIXP_DBL *QmfRightReal, /*!< real bands right qmf channel */ + FIXP_DBL *QmfRightImag /*!< imag bands right qmf channel */ + ) +{ + INT group; + INT subband; + + FIXP_DBL *RESTRICT HybrLeftReal; + FIXP_DBL *RESTRICT HybrLeftImag; + FIXP_DBL *RESTRICT HybrRightReal; + FIXP_DBL *RESTRICT HybrRightImag; + + FIXP_DBL tmpLeft, tmpRight; + + + /**********************************************************************************************/ + /*! +

Mapping

+ + The number of stereo bands that is actually used depends on the number of availble + parameters for IID and ICC: +
+   nr. of IID para.| nr. of ICC para. | nr. of Stereo bands
+   ----------------|------------------|-------------------
+     10,20         |     10,20        |        20
+     10,20         |     34           |        34
+     34            |     10,20        |        34
+     34            |     34           |        34
+  
+ In the case the number of parameters for IIS and ICC differs from the number of stereo + bands, a mapping from the lower number to the higher number of parameters is applied. + Index mapping of IID and ICC parameters is already done in psbitdec.cpp. Further mapping is + not needed here in baseline version. + **********************************************************************************************/ + + /************************************************************************************************/ + /*! +

Mixing

+ + To generate the QMF subband signals for the subband samples n = n[e]+1 ,,, n_[e+1] the + parameters at position n[e] and n[e+1] are required as well as the subband domain signals + s_k(n) and d_k(n) for n = n[e]+1... n_[e+1]. n[e] represents the start position for + envelope e. The border positions n[e] are handled in DecodePS(). + + The stereo sub subband signals are constructed as: +
+  l_k(n) = H11(k,n) s_k(n) + H21(k,n) d_k(n)
+  r_k(n) = H21(k,n) s_k(n) + H22(k,n) d_k(n)
+  
+ In order to obtain the matrices H11(k,n)... H22 (k,n), the vectors h11(b)... h22(b) need to + be calculated first (b: parameter index). Depending on ICC mode either mixing procedure R_a + or R_b is used for that. For both procedures, the parameters for parameter position n[e+1] + is used. + ************************************************************************************************/ + + + /************************************************************************************************/ + /*! +

Phase parameters

+ With disabled phase parameters (which is the case in baseline version), the H-matrices are + just calculated by: + +
+  H11(k,n[e+1] = h11(b(k))
+  (...)
+  b(k): parameter index according to mapping table
+  
+ +

Processing of the samples in the sub subbands

+ this loop includes the interpolation of the coefficients Hxx + ************************************************************************************************/ + + + /* loop thru all groups ... */ + HybrLeftReal = mHybridRealLeft; + HybrLeftImag = mHybridImagLeft; + HybrRightReal = mHybridRealRight; + HybrRightImag = mHybridImagRight; + + /******************************************************/ + /* construct stereo sub subband signals according to: */ + /* */ + /* l_k(n) = H11(k,n) s_k(n) + H21(k,n) d_k(n) */ + /* r_k(n) = H12(k,n) s_k(n) + H22(k,n) d_k(n) */ + /******************************************************/ + for ( group = 0; group < SUBQMF_GROUPS; group++ ) { + + h_ps_d->specificTo.mpeg.coef.H11r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH11r[group]; + h_ps_d->specificTo.mpeg.coef.H12r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH12r[group]; + h_ps_d->specificTo.mpeg.coef.H21r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH21r[group]; + h_ps_d->specificTo.mpeg.coef.H22r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH22r[group]; + + subband = groupBorders20[group]; + + tmpLeft = fMultAddDiv2( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H11r[group], HybrLeftReal[subband]), h_ps_d->specificTo.mpeg.coef.H21r[group], HybrRightReal[subband]); + tmpRight = fMultAddDiv2( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H12r[group], HybrLeftReal[subband]), h_ps_d->specificTo.mpeg.coef.H22r[group], HybrRightReal[subband]); + HybrLeftReal [subband] = tmpLeft<<1; + HybrRightReal[subband] = tmpRight<<1; + + tmpLeft = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H11r[group], HybrLeftImag[subband]), h_ps_d->specificTo.mpeg.coef.H21r[group], HybrRightImag[subband]); + tmpRight = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H12r[group], HybrLeftImag[subband]), h_ps_d->specificTo.mpeg.coef.H22r[group], HybrRightImag[subband]); + HybrLeftImag [subband] = tmpLeft; + HybrRightImag[subband] = tmpRight; + } + + /* continue in the qmf buffers */ + HybrLeftReal = QmfLeftReal; + HybrLeftImag = QmfLeftImag; + HybrRightReal = QmfRightReal; + HybrRightImag = QmfRightImag; + + for (; group < NO_IID_GROUPS; group++ ) { + + h_ps_d->specificTo.mpeg.coef.H11r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH11r[group]; + h_ps_d->specificTo.mpeg.coef.H12r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH12r[group]; + h_ps_d->specificTo.mpeg.coef.H21r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH21r[group]; + h_ps_d->specificTo.mpeg.coef.H22r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH22r[group]; + + for ( subband = groupBorders20[group]; subband < groupBorders20[group + 1]; subband++ ) + { + tmpLeft = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H11r[group], HybrLeftReal[subband]), h_ps_d->specificTo.mpeg.coef.H21r[group], HybrRightReal[subband]); + tmpRight = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H12r[group], HybrLeftReal[subband]), h_ps_d->specificTo.mpeg.coef.H22r[group], HybrRightReal[subband]); + HybrLeftReal [subband] = tmpLeft; + HybrRightReal[subband] = tmpRight; + + tmpLeft = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H11r[group], HybrLeftImag[subband]), h_ps_d->specificTo.mpeg.coef.H21r[group], HybrRightImag[subband]); + tmpRight = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H12r[group], HybrLeftImag[subband]), h_ps_d->specificTo.mpeg.coef.H22r[group], HybrRightImag[subband]); + HybrLeftImag [subband] = tmpLeft; + HybrRightImag[subband] = tmpRight; + + } /* subband */ + } +} + + +/***************************************************************************/ +/*! + \brief Applies IID, ICC, IPD and OPD parameters to the current frame. + + \return none + +****************************************************************************/ +void +ApplyPsSlot( HANDLE_PS_DEC h_ps_d, /*!< handle PS_DEC*/ + FIXP_DBL **rIntBufferLeft, /*!< real bands left qmf channel (38x64) */ + FIXP_DBL **iIntBufferLeft, /*!< imag bands left qmf channel (38x64) */ + FIXP_DBL *rIntBufferRight, /*!< real bands right qmf channel (38x64) */ + FIXP_DBL *iIntBufferRight /*!< imag bands right qmf channel (38x64) */ + ) +{ + + /*! + The 64-band QMF representation of the monaural signal generated by the SBR tool + is used as input of the PS tool. After the PS processing, the outputs of the left + and right hybrid synthesis filterbanks are used to generate the stereo output + signal. + +
+
+             -------------            ----------            -------------
+            | Hybrid      | M_n[k,m] |          | L_n[k,m] | Hybrid      | l[n]
+   m[n] --->| analysis    |--------->|          |--------->| synthesis   |----->
+            | filter bank |          |          |          | filter bank |
+             -------------           | Stereo   |           -------------
+                   |                 | recon-   |
+                   |                 | stuction |
+                  \|/                |          |
+             -------------           |          |
+            | De-         | D_n[k,m] |          |
+            | correlation |--------->|          |
+             -------------           |          |           -------------
+                                     |          | R_n[k,m] | Hybrid      | r[n]
+                                     |          |--------->| synthesis   |----->
+   IID, ICC ------------------------>|          |          | filter bank |
+  (IPD, OPD)                          ----------            -------------
+
+  m[n]:      QMF represantation of the mono input
+  M_n[k,m]:  (sub-)sub-band domain signals of the mono input
+  D_n[k,m]:  decorrelated (sub-)sub-band domain signals
+  L_n[k,m]:  (sub-)sub-band domain signals of the left output
+  R_n[k,m]:  (sub-)sub-band domain signals of the right output
+  l[n],r[n]: left/right output signals
+
+  
+ */ + + /* get temporary hybrid qmf values of one timeslot */ + C_ALLOC_SCRATCH_START(hybridRealLeft, FIXP_DBL, NO_SUB_QMF_CHANNELS); + C_ALLOC_SCRATCH_START(hybridImagLeft, FIXP_DBL, NO_SUB_QMF_CHANNELS); + C_ALLOC_SCRATCH_START(hybridRealRight, FIXP_DBL, NO_SUB_QMF_CHANNELS); + C_ALLOC_SCRATCH_START(hybridImagRight, FIXP_DBL, NO_SUB_QMF_CHANNELS); + + SCHAR sf_IntBuffer = h_ps_d->sf_IntBuffer; + + /* clear workbuffer */ + FDKmemclear(hybridRealLeft, NO_SUB_QMF_CHANNELS*sizeof(FIXP_DBL)); + FDKmemclear(hybridImagLeft, NO_SUB_QMF_CHANNELS*sizeof(FIXP_DBL)); + FDKmemclear(hybridRealRight, NO_SUB_QMF_CHANNELS*sizeof(FIXP_DBL)); + FDKmemclear(hybridImagRight, NO_SUB_QMF_CHANNELS*sizeof(FIXP_DBL)); + + + /*! + Hybrid analysis filterbank: + The lower 3 (5) of the 64 QMF subbands are further split to provide better frequency resolution. + for PS processing. + For the 10 and 20 stereo bands configuration, the QMF band H_0(w) is split + up into 8 (sub-) sub-bands and the QMF bands H_1(w) and H_2(w) are spit into 2 (sub-) + 4th. (See figures 8.20 and 8.22 of ISO/IEC 14496-3:2001/FDAM 2:2004(E) ) + */ + + + if (h_ps_d->procFrameBased == 1) /* If we have switched from frame to slot based processing */ + { /* fill hybrid delay buffer. */ + h_ps_d->procFrameBased = 0; + + fillHybridDelayLine( rIntBufferLeft, + iIntBufferLeft, + hybridRealLeft, + hybridImagLeft, + hybridRealRight, + hybridImagRight, + &h_ps_d->specificTo.mpeg.hybrid ); + } + + slotBasedHybridAnalysis ( rIntBufferLeft[HYBRID_FILTER_DELAY], /* qmf filterbank values */ + iIntBufferLeft[HYBRID_FILTER_DELAY], /* qmf filterbank values */ + hybridRealLeft, /* hybrid filterbank values */ + hybridImagLeft, /* hybrid filterbank values */ + &h_ps_d->specificTo.mpeg.hybrid); /* hybrid filterbank handle */ + + + SCHAR hybridScal = h_ps_d->specificTo.mpeg.hybrid.sf_mQmfBuffer; + + + /*! + Decorrelation: + By means of all-pass filtering and delaying, the (sub-)sub-band samples s_k(n) are + converted into de-correlated (sub-)sub-band samples d_k(n). + - k: frequency in hybrid spectrum + - n: time index + */ + + deCorrelateSlotBased( h_ps_d, /* parametric stereo decoder handle */ + hybridRealLeft, /* left hybrid time slot */ + hybridImagLeft, + hybridScal, /* scale factor of left hybrid time slot */ + rIntBufferLeft[0], /* left qmf time slot */ + iIntBufferLeft[0], + sf_IntBuffer, /* scale factor of left and right qmf time slot */ + hybridRealRight, /* right hybrid time slot */ + hybridImagRight, + rIntBufferRight, /* right qmf time slot */ + iIntBufferRight ); + + + + /*! + Stereo Processing: + The sets of (sub-)sub-band samples s_k(n) and d_k(n) are processed according to + the stereo cues which are defined per stereo band. + */ + + + applySlotBasedRotation( h_ps_d, /* parametric stereo decoder handle */ + hybridRealLeft, /* left hybrid time slot */ + hybridImagLeft, + rIntBufferLeft[0], /* left qmf time slot */ + iIntBufferLeft[0], + hybridRealRight, /* right hybrid time slot */ + hybridImagRight, + rIntBufferRight, /* right qmf time slot */ + iIntBufferRight ); + + + + + /*! + Hybrid synthesis filterbank: + The stereo processed hybrid subband signals l_k(n) and r_k(n) are fed into the hybrid synthesis + filterbanks which are identical to the 64 complex synthesis filterbank of the SBR tool. The + input to the filterbank are slots of 64 QMF samples. For each slot the filterbank outputs one + block of 64 samples of one reconstructed stereo channel. The hybrid synthesis filterbank is + computed seperatly for the left and right channel. + */ + + + /* left channel */ + slotBasedHybridSynthesis ( hybridRealLeft, /* one timeslot of hybrid filterbank values */ + hybridImagLeft, + rIntBufferLeft[0], /* one timeslot of qmf filterbank values */ + iIntBufferLeft[0], + &h_ps_d->specificTo.mpeg.hybrid ); /* hybrid filterbank handle */ + + /* right channel */ + slotBasedHybridSynthesis ( hybridRealRight, /* one timeslot of hybrid filterbank values */ + hybridImagRight, + rIntBufferRight, /* one timeslot of qmf filterbank values */ + iIntBufferRight, + &h_ps_d->specificTo.mpeg.hybrid ); /* hybrid filterbank handle */ + + + + + + + + /* free temporary hybrid qmf values of one timeslot */ + C_ALLOC_SCRATCH_END(hybridImagRight, FIXP_DBL, NO_SUB_QMF_CHANNELS); + C_ALLOC_SCRATCH_END(hybridRealRight, FIXP_DBL, NO_SUB_QMF_CHANNELS); + C_ALLOC_SCRATCH_END(hybridImagLeft, FIXP_DBL, NO_SUB_QMF_CHANNELS); + C_ALLOC_SCRATCH_END(hybridRealLeft, FIXP_DBL, NO_SUB_QMF_CHANNELS); + +}/* END ApplyPsSlot */ + + +/***************************************************************************/ +/*! + + \brief assigns timeslots to an array + + \return + +****************************************************************************/ + +static void assignTimeSlotsPS (FIXP_DBL *bufAdr, + FIXP_DBL **bufPtr, + const int numSlots, + const int numChan) +{ + FIXP_DBL *ptr; + int slot; + ptr = bufAdr; + for(slot=0; slot < numSlots; slot++) { + bufPtr [slot] = ptr; + ptr += numChan; + } +} + diff --git a/libSBRdec/src/psdec.h b/libSBRdec/src/psdec.h new file mode 100644 index 0000000..fd0a5b6 --- /dev/null +++ b/libSBRdec/src/psdec.h @@ -0,0 +1,294 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Sbr decoder $Revision: 36841 $ +*/ +#ifndef __PSDEC_H +#define __PSDEC_H + +#include "sbrdecoder.h" + + + +/* This PS decoder implements the baseline version. So it always uses the */ +/* hybrid filter structure for 20 stereo bands and does not implemet IPD/OPD */ +/* synthesis. The baseline version has to support the complete PS bitstream */ +/* syntax. But IPD/OPD data is ignored and set to 0. If 34 stereo band config */ +/* is used in the bitstream for IIS/ICC the decoded parameters are mapped to */ +/* 20 stereo bands. */ + + +#include "FDK_bitstream.h" + +#include "psdec_hybrid.h" + +#define SCAL_HEADROOM ( 2 ) + +#define PS_EXTENSION_SIZE_BITS ( 4 ) +#define PS_EXTENSION_ESC_COUNT_BITS ( 8 ) + +#define NO_QMF_CHANNELS ( 64 ) +#define MAX_NUM_COL ( 32 ) + + + #define NO_QMF_BANDS_HYBRID20 ( 3 ) + #define NO_SUB_QMF_CHANNELS ( 12 ) + + #define NRG_INT_COEFF ( 0.75f ) + #define INT_FILTER_COEFF (FL2FXCONST_DBL( 1.0f - NRG_INT_COEFF )) + #define PEAK_DECAY_FACTOR (FL2FXCONST_DBL( 0.765928338364649f )) + #define TRANSIENT_IMPACT_FACTOR (FL2FXCONST_DBL( 2.0 / 3.0 )) + + #define NO_SERIAL_ALLPASS_LINKS ( 3 ) + #define MAX_NO_PS_ENV ( 4 + 1 ) /* +1 needed for VAR_BORDER */ + + #define MAX_DELAY_BUFFER_SIZE ( 14 ) + #define NO_DELAY_BUFFER_BANDS ( 35 ) + + #define NO_HI_RES_BINS ( 34 ) + #define NO_MID_RES_BINS ( 20 ) + #define NO_LOW_RES_BINS ( 10 ) + + #define FIRST_DELAY_SB ( 23 ) + #define NO_SAMPLE_DELAY_ALLPASS ( 2 ) + #define NO_DELAY_LENGTH_VECTORS ( 12 ) /* d(m): d(0)=3 + d(1)=4 + d(2)=5 */ + + #define NO_HI_RES_IID_BINS ( NO_HI_RES_BINS ) + #define NO_HI_RES_ICC_BINS ( NO_HI_RES_BINS ) + + #define NO_MID_RES_IID_BINS ( NO_MID_RES_BINS ) + #define NO_MID_RES_ICC_BINS ( NO_MID_RES_BINS ) + + #define NO_LOW_RES_IID_BINS ( NO_LOW_RES_BINS ) + #define NO_LOW_RES_ICC_BINS ( NO_LOW_RES_BINS ) + + #define SUBQMF_GROUPS ( 10 ) + #define QMF_GROUPS ( 12 ) + + #define SUBQMF_GROUPS_HI_RES ( 32 ) + #define QMF_GROUPS_HI_RES ( 18 ) + + #define NO_IID_GROUPS ( SUBQMF_GROUPS + QMF_GROUPS ) + #define NO_IID_GROUPS_HI_RES ( SUBQMF_GROUPS_HI_RES + QMF_GROUPS_HI_RES ) + + #define NO_IID_STEPS ( 7 ) /* 1 .. + 7 */ + #define NO_IID_STEPS_FINE ( 15 ) /* 1 .. +15 */ + #define NO_ICC_STEPS ( 8 ) /* 0 .. + 7 */ + + #define NO_IID_LEVELS ( 2 * NO_IID_STEPS + 1 ) /* - 7 .. + 7 */ + #define NO_IID_LEVELS_FINE ( 2 * NO_IID_STEPS_FINE + 1 ) /* -15 .. +15 */ + #define NO_ICC_LEVELS ( NO_ICC_STEPS ) /* 0 .. + 7 */ + + #define FIXP_SQRT05 ((FIXP_DBL)0x5a827980) /* 1/SQRT2 */ + + struct PS_DEC_COEFFICIENTS { + + FIXP_DBL H11r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + FIXP_DBL H12r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + FIXP_DBL H21r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + FIXP_DBL H22r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + + FIXP_DBL DeltaH11r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + FIXP_DBL DeltaH12r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + FIXP_DBL DeltaH21r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + FIXP_DBL DeltaH22r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + + SCHAR aaIidIndexMapped[MAX_NO_PS_ENV][NO_HI_RES_IID_BINS]; /*!< The mapped IID index for all envelopes and all IID bins */ + SCHAR aaIccIndexMapped[MAX_NO_PS_ENV][NO_HI_RES_ICC_BINS]; /*!< The mapped ICC index for all envelopes and all ICC bins */ + + }; + + + + +typedef enum { + ppt_none = 0, + ppt_mpeg = 1, + ppt_drm = 2 +} PS_PAYLOAD_TYPE; + + +typedef struct { + UCHAR bPsHeaderValid; /*!< set if new header is available from bitstream */ + + UCHAR bEnableIid; /*!< One bit denoting the presence of IID parameters */ + UCHAR bEnableIcc; /*!< One bit denoting the presence of ICC parameters */ + UCHAR bEnableExt; /*!< The PS extension layer is enabled using the enable_ext bit. + If it is set to %1 the IPD and OPD parameters are sent. + If it is disabled, i.e. %0, the extension layer is skipped. */ + + UCHAR modeIid; /*!< The configuration of IID parameters (number of bands and + quantisation grid, iid_quant) is determined by iid_mode. */ + UCHAR modeIcc; /*!< The configuration of Inter-channel Coherence parameters + (number of bands and quantisation grid) is determined by + icc_mode. */ + + UCHAR freqResIid; /*!< 0=low, 1=mid or 2=high frequency resolution for iid */ + UCHAR freqResIcc; /*!< 0=low, 1=mid or 2=high frequency resolution for icc */ + + UCHAR bFineIidQ; /*!< Use fine Iid quantisation. */ + + UCHAR bFrameClass; /*!< The frame_class bit determines whether the parameter + positions of the current frame are uniformly spaced + accross the frame or they are defined using the positions + described by border_position. */ + + UCHAR noEnv; /*!< The number of envelopes per frame */ + UCHAR aEnvStartStop[MAX_NO_PS_ENV+1]; /*!< In case of variable parameter spacing the parameter + positions are determined by border_position */ + + SCHAR abIidDtFlag[MAX_NO_PS_ENV]; /*!< Deltacoding time/freq flag for IID, 0 => freq */ + SCHAR abIccDtFlag[MAX_NO_PS_ENV]; /*!< Deltacoding time/freq flag for ICC, 0 => freq */ + + SCHAR aaIidIndex[MAX_NO_PS_ENV][NO_HI_RES_IID_BINS]; /*!< The IID index for all envelopes and all IID bins */ + SCHAR aaIccIndex[MAX_NO_PS_ENV][NO_HI_RES_ICC_BINS]; /*!< The ICC index for all envelopes and all ICC bins */ + +} MPEG_PS_BS_DATA; + + + +struct PS_DEC { + + SCHAR noSubSamples; + SCHAR noChannels; + + SCHAR procFrameBased; /*!< Helper to detected switching from frame based to slot based + processing */ + + PS_PAYLOAD_TYPE bPsDataAvail[(1)+1]; /*!< set if new data available from bitstream */ + UCHAR psDecodedPrv; /*!< set if PS has been processed in the last frame */ + + /* helpers for frame delay line */ + UCHAR bsLastSlot; /*!< Index of last read slot. */ + UCHAR bsReadSlot; /*!< Index of current read slot for additional delay. */ + UCHAR processSlot; /*!< Index of current slot for processing (need for add. delay). */ + + + INT rescal; + INT sf_IntBuffer; + + union { /* Bitstream data */ + MPEG_PS_BS_DATA mpeg; /*!< Struct containing all MPEG specific PS data from bitstream. */ + } bsData[(1)+1]; + + shouldBeUnion { /* Static data */ + struct { + SCHAR aIidPrevFrameIndex[NO_HI_RES_IID_BINS]; /*!< The IID index for previous frame */ + SCHAR aIccPrevFrameIndex[NO_HI_RES_ICC_BINS]; /*!< The ICC index for previous frame */ + + UCHAR delayBufIndex; /*!< Pointer to where the latest sample is in buffer */ + UCHAR noSampleDelay; /*!< How many QMF samples delay is used. */ + UCHAR lastUsb; /*!< uppermost WMF delay band of last frame */ + + UCHAR aDelayRBufIndexSer[NO_SERIAL_ALLPASS_LINKS]; /*!< Delay buffer for reverb filter */ + UCHAR aDelayBufIndexDelayQmf[NO_QMF_CHANNELS-FIRST_DELAY_SB]; /*!< Delay buffer for ICC group 20 & 21 */ + + SCHAR scaleFactorPsDelayBuffer; /*!< Scale factor for ps delay buffer */ + + /* hybrid filter bank delay lines */ + FIXP_DBL aaQmfDelayBufReal[(NO_QMF_CHANNELS-FIRST_DELAY_SB) + (MAX_DELAY_BUFFER_SIZE-1)*(NO_DELAY_BUFFER_BANDS-FIRST_DELAY_SB)]; + FIXP_DBL aaQmfDelayBufImag[(NO_QMF_CHANNELS-FIRST_DELAY_SB) + (MAX_DELAY_BUFFER_SIZE-1)*(NO_DELAY_BUFFER_BANDS-FIRST_DELAY_SB)]; + + FIXP_DBL *pAaRealDelayBufferQmf[MAX_DELAY_BUFFER_SIZE]; /*!< Real part delay buffer */ + FIXP_DBL *pAaImagDelayBufferQmf[MAX_DELAY_BUFFER_SIZE]; /*!< Imaginary part delay buffer */ + + FIXP_DBL aaRealDelayBufferQmf[NO_SAMPLE_DELAY_ALLPASS][FIRST_DELAY_SB]; /*!< Real part delay buffer */ + FIXP_DBL aaImagDelayBufferQmf[NO_SAMPLE_DELAY_ALLPASS][FIRST_DELAY_SB]; /*!< Imaginary part delay buffer*/ + + FIXP_DBL aaRealDelayBufferSubQmf[NO_SAMPLE_DELAY_ALLPASS][NO_SUB_QMF_CHANNELS]; /*!< Real part delay buffer */ + FIXP_DBL aaImagDelayBufferSubQmf[NO_SAMPLE_DELAY_ALLPASS][NO_SUB_QMF_CHANNELS]; /*!< Imaginary part delay buffer */ + + FIXP_DBL aaaRealDelayRBufferSerQmf[FIRST_DELAY_SB][NO_DELAY_LENGTH_VECTORS]; /*!< Real part delay buffer */ + FIXP_DBL aaaImagDelayRBufferSerQmf[FIRST_DELAY_SB][NO_DELAY_LENGTH_VECTORS]; /*!< Imaginary part delay buffer */ + + FIXP_DBL aaaRealDelayRBufferSerSubQmf[NO_SUB_QMF_CHANNELS][NO_DELAY_LENGTH_VECTORS]; /*!< Real part delay buffer */ + FIXP_DBL aaaImagDelayRBufferSerSubQmf[NO_SUB_QMF_CHANNELS][NO_DELAY_LENGTH_VECTORS]; /*!< Imaginary part delay buffer */ + + HYBRID hybrid; /*!< hybrid filter bank struct 1 or 2. */ + + FIXP_DBL aPrevNrgBin[NO_MID_RES_BINS]; /*!< energy of previous frame */ + FIXP_DBL aPrevPeakDiffBin[NO_MID_RES_BINS]; /*!< peak difference of previous frame */ + FIXP_DBL aPeakDecayFastBin[NO_MID_RES_BINS]; /*!< Saved max. peak decay value per bin */ + SCHAR aPowerPrevScal[NO_MID_RES_BINS]; /*!< Last power value (each bin) of previous frame */ + + FIXP_DBL h11rPrev[NO_IID_GROUPS]; /*!< previous calculated h(xy) coefficients */ + FIXP_DBL h12rPrev[NO_IID_GROUPS]; /*!< previous calculated h(xy) coefficients */ + FIXP_DBL h21rPrev[NO_IID_GROUPS]; /*!< previous calculated h(xy) coefficients */ + FIXP_DBL h22rPrev[NO_IID_GROUPS]; /*!< previous calculated h(xy) coefficients */ + + PS_DEC_COEFFICIENTS coef; /*!< temporal coefficients (reusable scratch memory) */ + + } mpeg; + + } specificTo; + + +}; + +typedef struct PS_DEC *HANDLE_PS_DEC; + + +int CreatePsDec(HANDLE_PS_DEC *h_PS_DEC, int aacSamplesPerFrame); + +int DeletePsDec(HANDLE_PS_DEC *h_PS_DEC); + +void +scalFilterBankValues( HANDLE_PS_DEC h_ps_d, /* parametric stereo decoder handle */ + FIXP_DBL **fixpQmfReal, /* qmf filterbank values */ + FIXP_DBL **fixpQmfImag, /* qmf filterbank values */ + int lsb, /* sbr start subband */ + int scaleFactorLowBandSplitLow, + int scaleFactorLowBandSplitHigh, + SCHAR *scaleFactorLowBand_lb, + SCHAR *scaleFactorLowBand_hb, + int scaleFactorHighBands, + INT *scaleFactorHighBand, + INT noCols); + +void +rescalFilterBankValues( HANDLE_PS_DEC h_ps_d, /* parametric stereo decoder handle */ + FIXP_DBL **QmfBufferReal, /* qmf filterbank values */ + FIXP_DBL **QmfBufferImag, /* qmf filterbank values */ + int lsb, /* sbr start subband */ + INT noCols); + + +void +initSlotBasedRotation( HANDLE_PS_DEC h_ps_d, + int env, + int usb); + +void +ApplyPsSlot( HANDLE_PS_DEC h_ps_d, /* parametric stereo decoder handle */ + FIXP_DBL **rIntBufferLeft, /* real values of left qmf timeslot */ + FIXP_DBL **iIntBufferLeft, /* imag values of left qmf timeslot */ + FIXP_DBL *rIntBufferRight, /* real values of right qmf timeslot */ + FIXP_DBL *iIntBufferRight); /* imag values of right qmf timeslot */ + + + +#endif /* __PSDEC_H */ diff --git a/libSBRdec/src/psdec_hybrid.cpp b/libSBRdec/src/psdec_hybrid.cpp new file mode 100644 index 0000000..9c73c69 --- /dev/null +++ b/libSBRdec/src/psdec_hybrid.cpp @@ -0,0 +1,595 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +#include "psdec_hybrid.h" + + +#include "fft.h" +#include "sbr_ram.h" + +#include "FDK_tools_rom.h" +#include "sbr_rom.h" + +/******************************************************************************* + Functionname: InitHybridFilterBank + ******************************************************************************* + + Description: Init one instance of HANDLE_HYBRID stuct + + Arguments: + + Return: none + +*******************************************************************************/ + + +SBR_ERROR +InitHybridFilterBank ( HANDLE_HYBRID hs, /*!< Handle to HYBRID struct. */ + SCHAR frameSize, /*!< Framesize (in Qmf súbband samples). */ + SCHAR noBands, /*!< Number of Qmf bands for hybrid filtering. */ + const UCHAR *pResolution ) /*!< Resolution in Qmf bands (length noBands). */ +{ + SCHAR i; + UCHAR maxNoChannels = 0; + + for (i = 0; i < noBands; i++) { + hs->pResolution[i] = pResolution[i]; + if(pResolution[i] > maxNoChannels) + maxNoChannels = pResolution[i]; + } + + hs->nQmfBands = noBands; + hs->frameSize = frameSize; + hs->qmfBufferMove = HYBRID_FILTER_LENGTH - 1; + + hs->sf_mQmfBuffer = 0; + + return SBRDEC_OK; +} + +/******************************************************************************* + Functionname: dualChannelFiltering + ******************************************************************************* + + Description: fast 2-channel real-valued filtering with 6-tap delay. + + Arguments: + + Return: none + +*******************************************************************************/ + +/*! +2 channel filter +
+   Filter Coefs:
+   0.0,
+   0.01899487526049,
+   0.0,
+   -0.07293139167538,
+   0.0,
+   0.30596630545168,
+   0.5,
+   0.30596630545168,
+   0.0,
+   -0.07293139167538,
+   0.0,
+   0.01899487526049,
+   0.0
+
+
+   Filter design:
+   h[q,n] = g[n] * cos(2pi/2 * q * (n-6) );  n = 0..12,  q = 0,1;
+
+   ->  h[0,n] = g[n] * 1;
+   ->  h[1,n] = g[n] * pow(-1,n);
+
+*/ + +static void slotBasedDualChannelFiltering( const FIXP_DBL *pQmfReal, + const FIXP_DBL *pQmfImag, + + FIXP_DBL *mHybridReal, + FIXP_DBL *mHybridImag) +{ + + FIXP_DBL t1, t3, t5, t6; + + /* symmetric filter coefficients */ + + /* you don't have to shift the result after fMult because of p2_13_20 <= 0.5 */ + t1 = fMultDiv2(p2_13_20[1] , ( (pQmfReal[1] >> 1) + (pQmfReal[11] >> 1))); + t3 = fMultDiv2(p2_13_20[3] , ( (pQmfReal[3] >> 1) + (pQmfReal[ 9] >> 1))); + t5 = fMultDiv2(p2_13_20[5] , ( (pQmfReal[5] >> 1) + (pQmfReal[ 7] >> 1))); + t6 = fMultDiv2(p2_13_20[6] , (pQmfReal[6] >> 1) ); + + mHybridReal[0] = (t1 + t3 + t5 + t6) << 2; + mHybridReal[1] = (- t1 - t3 - t5 + t6) << 2; + + t1 = fMultDiv2(p2_13_20[1] , ( (pQmfImag[1] >> 1) + (pQmfImag[11] >> 1))); + t3 = fMultDiv2(p2_13_20[3] , ( (pQmfImag[3] >> 1) + (pQmfImag[ 9] >> 1))); + t5 = fMultDiv2(p2_13_20[5] , ( (pQmfImag[5] >> 1) + (pQmfImag[ 7] >> 1))); + t6 = fMultDiv2(p2_13_20[6] , pQmfImag[6] >> 1 ); + + mHybridImag[0] = (t1 + t3 + t5 + t6) << 2; + mHybridImag[1] = (- t1 - t3 - t5 + t6) << 2; +} + + +/******************************************************************************* + Functionname: eightChannelFiltering + ******************************************************************************* + + Description: fast 8-channel complex-valued filtering with 6-tap delay. + + Arguments: + + Return: none + +*******************************************************************************/ +/*! + 8 channel filter + + Implementation using a FFT of length 8 +
+   prototype filter coefficients:
+   0.00746082949812   0.02270420949825   0.04546865930473   0.07266113929591   0.09885108575264   0.11793710567217
+   0.125
+   0.11793710567217   0.09885108575264   0.07266113929591   0.04546865930473   0.02270420949825   0.00746082949812
+
+   Filter design:
+   N = 13; Q = 8;
+   h[q,n]       = g[n] * exp(j * 2 * pi / Q * (q + .5) * (n - 6));  n = 0..(N-1),  q = 0..(Q-1);
+
+   Time Signal:   x[t];
+   Filter Bank Output
+   y[q,t] = conv(x[t],h[q,t]) = conv(h[q,t],x[t]) = sum(x[k] * h[q, t - k] ) = sum(h[q, k] * x[t - k] ); k = 0..(N-1);
+
+   y[q,t] =   x[t - 12]*h[q, 12]  +  x[t - 11]*h[q, 11]  +  x[t - 10]*h[q, 10]  +  x[t -  9]*h[q,  9]
+           +  x[t -  8]*h[q,  8]  +  x[t -  7]*h[q,  7]
+           +  x[t -  6]*h[q,  6]
+           +  x[t -  5]*h[q,  5]  +  x[t -  4]*h[q,  4]
+           +  x[t -  3]*h[q,  3]  +  x[t -  2]*h[q,  2]  +  x[t -  1]*h[q,  1]  +  x[t -  0]*h[q,  0];
+
+   h'[q, n] = h[q,(N-1)-n] = g[n] * exp(j * 2 * pi / Q * (q + .5) * (6 - n));  n = 0..(N-1),  q = 0..(Q-1);
+
+   y[q,t] =   x[t - 12]*h'[q,  0]  +  x[t - 11]*h'[q,  1]  +  x[t - 10]*h'[q,  2]  +  x[t -  9]*h'[q,  3]
+           +  x[t -  8]*h'[q,  4]  +  x[t -  7]*h'[q,  5]
+           +  x[t -  6]*h'[q,  6]
+           +  x[t -  5]*h'[q,  7]  +  x[t -  4]*h'[q,  8]
+           +  x[t -  3]*h'[q,  9]  +  x[t -  2]*h'[q, 10]  +  x[t -  1]*h'[q, 11]  +  x[t -  0]*h'[q, 12];
+
+   Try to split off FFT Modulation Term:
+   FFT(x[t], q) = sum(x[t+k]*exp(-j*2*pi/N *q * k))
+                                           c                                           m
+   Step 1:  h'[q,n] = g[n] * ( exp(j * 2 * pi / 8 * .5 * (6 - n)) ) * ( exp (j * 2 * pi / 8 * q * (6 - n)) );
+
+    h'[q,n] = g[n] *c[n] * m[q,n]; (see above)
+    c[n]    = exp( j * 2 * pi / 8 * .5 * (6 - n) );
+    m[q,n]  = exp( j * 2 * pi / 8 *  q * (6 - n) );
+
+    y[q,t] = x[t -  0]*g[0]*c[0]*m[q,0]  +  x[t -  1]*g[1]*c[ 1]*m[q, 1]  + ...
+             ...                         +  x[t - 12]*g[2]*c[12]*m[q,12];
+
+                                                                              |
+    n                   m                            *exp(-j*2*pi)            |   n'                   fft
+-------------------------------------------------------------------------------------------------------------------------
+    0       exp( j * 2 * pi / 8 * q * 6) ->  exp(-j * 2 * pi / 8 * q * 2)     |   2         exp(-j * 2 * pi / 8 * q * 0)
+    1       exp( j * 2 * pi / 8 * q * 5) ->  exp(-j * 2 * pi / 8 * q * 3)     |   3         exp(-j * 2 * pi / 8 * q * 1)
+    2       exp( j * 2 * pi / 8 * q * 4) ->  exp(-j * 2 * pi / 8 * q * 4)     |   4         exp(-j * 2 * pi / 8 * q * 2)
+    3       exp( j * 2 * pi / 8 * q * 3) ->  exp(-j * 2 * pi / 8 * q * 5)     |   5         exp(-j * 2 * pi / 8 * q * 3)
+    4       exp( j * 2 * pi / 8 * q * 2) ->  exp(-j * 2 * pi / 8 * q * 6)     |   6         exp(-j * 2 * pi / 8 * q * 4)
+    5       exp( j * 2 * pi / 8 * q * 1) ->  exp(-j * 2 * pi / 8 * q * 7)     |   7         exp(-j * 2 * pi / 8 * q * 5)
+    6       exp( j * 2 * pi / 8 * q * 0)                                      |   0         exp(-j * 2 * pi / 8 * q * 6)
+    7       exp(-j * 2 * pi / 8 * q * 1)                                      |   1         exp(-j * 2 * pi / 8 * q * 7)
+    8       exp(-j * 2 * pi / 8 * q * 2)                                      |   2
+    9       exp(-j * 2 * pi / 8 * q * 3)                                      |   3
+    10      exp(-j * 2 * pi / 8 * q * 4)                                      |   4
+    11      exp(-j * 2 * pi / 8 * q * 5)                                      |   5
+    12      exp(-j * 2 * pi / 8 * q * 6)                                      |   6
+
+
+    now use fft modulation coefficients
+    m[6]  =       = fft[0]
+    m[7]  =       = fft[1]
+    m[8]  = m[ 0] = fft[2]
+    m[9]  = m[ 1] = fft[3]
+    m[10] = m[ 2] = fft[4]
+    m[11] = m[ 3] = fft[5]
+    m[12] = m[ 4] = fft[6]
+            m[ 5] = fft[7]
+
+    y[q,t] = (                       x[t- 6]*g[ 6]*c[ 6] ) * fft[q,0]  +
+             (                       x[t- 7]*g[ 7]*c[ 7] ) * fft[q,1]  +
+             ( x[t- 0]*g[ 0]*c[ 0] + x[t- 8]*g[ 8]*c[ 8] ) * fft[q,2]  +
+             ( x[t- 1]*g[ 1]*c[ 1] + x[t- 9]*g[ 9]*c[ 9] ) * fft[q,3]  +
+             ( x[t- 2]*g[ 2]*c[ 2] + x[t-10]*g[10]*c[10] ) * fft[q,4]  +
+             ( x[t- 3]*g[ 3]*c[ 3] + x[t-11]*g[11]*c[11] ) * fft[q,5]  +
+             ( x[t- 4]*g[ 4]*c[ 4] + x[t-12]*g[12]*c[12] ) * fft[q,6]  +
+             ( x[t- 5]*g[ 5]*c[ 5]                       ) * fft[q,7];
+
+    pre twiddle factors c[n] = exp(j * 2 * pi / 8 * .5 * (6 - n));
+    n                c]           |  n                c[n]         |  n                c[n]
+---------------------------------------------------------------------------------------------------
+    0       exp( j * 6 * pi / 8)  |  1       exp( j * 5 * pi / 8)  |  2       exp( j * 4 * pi / 8)
+    3       exp( j * 3 * pi / 8)  |  4       exp( j * 2 * pi / 8)  |  5       exp( j * 1 * pi / 8)
+    6       exp( j * 0 * pi / 8)  |  7       exp(-j * 1 * pi / 8)  |  8       exp(-j * 2 * pi / 8)
+    9       exp(-j * 3 * pi / 8)  | 10       exp(-j * 4 * pi / 8)  | 11       exp(-j * 5 * pi / 8)
+   12       exp(-j * 6 * pi / 8)  |                                |
+
+*/ + +/* defining rotation factors for *ChannelFiltering */ + +#define cos0Pi FL2FXCONST_DBL( 1.f) +#define sin0Pi FL2FXCONST_DBL( 0.f) + +#define cos1Pi FL2FXCONST_DBL(-1.f) +#define sin1Pi FL2FXCONST_DBL( 0.f) + +#define cos1Pi_2 FL2FXCONST_DBL( 0.f) +#define sin1Pi_2 FL2FXCONST_DBL( 1.f) + +#define cos1Pi_3 FL2FXCONST_DBL( 0.5f) +#define sin1Pi_3 FL2FXCONST_DBL( 0.86602540378444f) + +#define cos0Pi_4 cos0Pi +#define cos1Pi_4 FL2FXCONST_DBL(0.70710678118655f) +#define cos2Pi_4 cos1Pi_2 +#define cos3Pi_4 (-cos1Pi_4) +#define cos4Pi_4 (-cos0Pi_4) +#define cos5Pi_4 cos3Pi_4 +#define cos6Pi_4 cos2Pi_4 + +#define sin0Pi_4 sin0Pi +#define sin1Pi_4 FL2FXCONST_DBL(0.70710678118655f) +#define sin2Pi_4 sin1Pi_2 +#define sin3Pi_4 sin1Pi_4 +#define sin4Pi_4 sin0Pi_4 +#define sin5Pi_4 (-sin3Pi_4) +#define sin6Pi_4 (-sin2Pi_4) + +#define cos0Pi_8 cos0Pi +#define cos1Pi_8 FL2FXCONST_DBL(0.92387953251129f) +#define cos2Pi_8 cos1Pi_4 +#define cos3Pi_8 FL2FXCONST_DBL(0.38268343236509f) +#define cos4Pi_8 cos2Pi_4 +#define cos5Pi_8 (-cos3Pi_8) +#define cos6Pi_8 (-cos2Pi_8) + +#define sin0Pi_8 sin0Pi +#define sin1Pi_8 cos3Pi_8 +#define sin2Pi_8 sin1Pi_4 +#define sin3Pi_8 cos1Pi_8 +#define sin4Pi_8 sin2Pi_4 +#define sin5Pi_8 sin3Pi_8 +#define sin6Pi_8 sin1Pi_4 + +#if defined(ARCH_PREFER_MULT_32x16) + #define FIXP_HYB FIXP_SGL + #define FIXP_CAST FX_DBL2FX_SGL +#else + #define FIXP_HYB FIXP_DBL + #define FIXP_CAST +#endif + +static const FIXP_HYB cr[13] = +{ + FIXP_CAST(cos6Pi_8), FIXP_CAST(cos5Pi_8), FIXP_CAST(cos4Pi_8), + FIXP_CAST(cos3Pi_8), FIXP_CAST(cos2Pi_8), FIXP_CAST(cos1Pi_8), + FIXP_CAST(cos0Pi_8), + FIXP_CAST(cos1Pi_8), FIXP_CAST(cos2Pi_8), FIXP_CAST(cos3Pi_8), + FIXP_CAST(cos4Pi_8), FIXP_CAST(cos5Pi_8), FIXP_CAST(cos6Pi_8) +}; + +static const FIXP_HYB ci[13] = +{ + FIXP_CAST( sin6Pi_8), FIXP_CAST( sin5Pi_8), FIXP_CAST( sin4Pi_8), + FIXP_CAST( sin3Pi_8), FIXP_CAST( sin2Pi_8), FIXP_CAST( sin1Pi_8), + FIXP_CAST( sin0Pi_8) , + FIXP_CAST(-sin1Pi_8), FIXP_CAST(-sin2Pi_8), FIXP_CAST(-sin3Pi_8), + FIXP_CAST(-sin4Pi_8), FIXP_CAST(-sin5Pi_8), FIXP_CAST(-sin6Pi_8) +}; + +static void slotBasedEightChannelFiltering( const FIXP_DBL *pQmfReal, + const FIXP_DBL *pQmfImag, + + FIXP_DBL *mHybridReal, + FIXP_DBL *mHybridImag) +{ + + int bin; + FIXP_DBL _fft[128 + ALIGNMENT_DEFAULT - 1]; + FIXP_DBL *fft = (FIXP_DBL *)ALIGN_PTR(_fft); + +#if defined(ARCH_PREFER_MULT_32x16) + const FIXP_SGL *p = p8_13_20; /* BASELINE_PS */ +#else + const FIXP_DBL *p = p8_13_20; /* BASELINE_PS */ +#endif + + /* pre twiddeling */ + + /* x*(a*b + c*d) = fMultDiv2(x, fMultAddDiv2(fMultDiv2(a, b), c, d)) */ + /* x*(a*b - c*d) = fMultDiv2(x, fMultSubDiv2(fMultDiv2(a, b), c, d)) */ + FIXP_DBL accu1, accu2, accu3, accu4; + + #define TWIDDLE_1(n_0,n_1,n_2) \ + cplxMultDiv2(&accu1, &accu2, pQmfReal[n_0], pQmfImag[n_0], cr[n_0], ci[n_0]); \ + accu1 = fMultDiv2(p[n_0], accu1); \ + accu2 = fMultDiv2(p[n_0], accu2); \ + cplxMultDiv2(&accu3, &accu4, pQmfReal[n_1], pQmfImag[n_1], cr[n_1], ci[n_1]); \ + accu3 = fMultDiv2(p[n_1], accu3); \ + accu4 = fMultDiv2(p[n_1], accu4); \ + fft[FIXP_FFT_IDX_R(n_2)] = accu1 + accu3; \ + fft[FIXP_FFT_IDX_I(n_2)] = accu2 + accu4; + + #define TWIDDLE_0(n_0,n_1) \ + cplxMultDiv2(&accu1, &accu2, pQmfReal[n_0], pQmfImag[n_0], cr[n_0], ci[n_0]); \ + fft[FIXP_FFT_IDX_R(n_1)] = fMultDiv2(p[n_0], accu1); \ + fft[FIXP_FFT_IDX_I(n_1)] = fMultDiv2(p[n_0], accu2); + + TWIDDLE_0( 6, 0) + TWIDDLE_0( 7, 1) + + TWIDDLE_1( 0, 8, 2) + TWIDDLE_1( 1, 9, 3) + TWIDDLE_1( 2,10, 4) + TWIDDLE_1( 3,11, 5) + TWIDDLE_1( 4,12, 6) + + TWIDDLE_0( 5, 7) + + fft_8 (fft); + + /* resort fft data into output array*/ + for(bin=0; bin<8;bin++ ) { + mHybridReal[bin] = fft[FIXP_FFT_IDX_R(bin)] << 4; + mHybridImag[bin] = fft[FIXP_FFT_IDX_I(bin)] << 4; + } +} + + +/******************************************************************************* + Functionname: fillHybridDelayLine + ******************************************************************************* + + Description: The delay line of the hybrid filter is filled and copied from + left to right. + + Return: none + +*******************************************************************************/ + +void +fillHybridDelayLine( FIXP_DBL **fixpQmfReal, /*!< Qmf real Values */ + FIXP_DBL **fixpQmfImag, /*!< Qmf imag Values */ + FIXP_DBL fixpHybridLeftR[12], /*!< Hybrid real Values left channel */ + FIXP_DBL fixpHybridLeftI[12], /*!< Hybrid imag Values left channel */ + FIXP_DBL fixpHybridRightR[12], /*!< Hybrid real Values right channel */ + FIXP_DBL fixpHybridRightI[12], /*!< Hybrid imag Values right channel */ + HANDLE_HYBRID hHybrid ) +{ + int i; + + for (i = 0; i < HYBRID_FILTER_DELAY; i++) { + slotBasedHybridAnalysis ( fixpQmfReal[i], + fixpQmfReal[i], + fixpHybridLeftR, + fixpHybridLeftI, + hHybrid ); + } + + FDKmemcpy(fixpHybridRightR, fixpHybridLeftR, sizeof(FIXP_DBL)*NO_SUB_QMF_CHANNELS); + FDKmemcpy(fixpHybridRightI, fixpHybridLeftI, sizeof(FIXP_DBL)*NO_SUB_QMF_CHANNELS); +} + + +/******************************************************************************* + Functionname: slotBasedHybridAnalysis + ******************************************************************************* + + Description: The lower QMF subbands are further split to provide better + frequency resolution for PS processing. + + Return: none + +*******************************************************************************/ + + +void +slotBasedHybridAnalysis ( FIXP_DBL *fixpQmfReal, /*!< Qmf real Values */ + FIXP_DBL *fixpQmfImag, /*!< Qmf imag Values */ + + FIXP_DBL fixpHybridReal[12], /*!< Hybrid real Values */ + FIXP_DBL fixpHybridImag[12], /*!< Hybrid imag Values */ + + HANDLE_HYBRID hHybrid) +{ + int k, band; + HYBRID_RES hybridRes; + int chOffset = 0; + + C_ALLOC_SCRATCH_START(pTempRealSlot, FIXP_DBL, 4*HYBRID_FILTER_LENGTH); + + FIXP_DBL *pTempImagSlot = pTempRealSlot + HYBRID_FILTER_LENGTH; + FIXP_DBL *pWorkRealSlot = pTempImagSlot + HYBRID_FILTER_LENGTH; + FIXP_DBL *pWorkImagSlot = pWorkRealSlot + HYBRID_FILTER_LENGTH; + + /*! + Hybrid filtering is applied to the first hHybrid->nQmfBands QMF bands (3 when 10 or 20 stereo bands + are used, 5 when 34 stereo bands are used). For the remaining QMF bands a delay would be necessary. + But there is no need to implement a delay because there is a look-ahead of HYBRID_FILTER_DELAY = 6 + QMF samples in the low-band buffer. + */ + + for(band = 0; band < hHybrid->nQmfBands; band++) { + + /* get hybrid resolution per qmf band */ + /* in case of baseline ps 10/20 band stereo mode : */ + /* */ + /* qmfBand[0] : 8 ( HYBRID_8_CPLX ) */ + /* qmfBand[1] : 2 ( HYBRID_2_REAL ) */ + /* qmfBand[2] : 2 ( HYBRID_2_REAL ) */ + /* */ + /* (split the 3 lower qmf band to 12 hybrid bands) */ + + hybridRes = (HYBRID_RES)hHybrid->pResolution[band]; + + FDKmemcpy(pWorkRealSlot, hHybrid->mQmfBufferRealSlot[band], hHybrid->qmfBufferMove * sizeof(FIXP_DBL)); + FDKmemcpy(pWorkImagSlot, hHybrid->mQmfBufferImagSlot[band], hHybrid->qmfBufferMove * sizeof(FIXP_DBL)); + + pWorkRealSlot[hHybrid->qmfBufferMove] = fixpQmfReal[band]; + pWorkImagSlot[hHybrid->qmfBufferMove] = fixpQmfImag[band]; + + FDKmemcpy(hHybrid->mQmfBufferRealSlot[band], pWorkRealSlot + 1, hHybrid->qmfBufferMove * sizeof(FIXP_DBL)); + FDKmemcpy(hHybrid->mQmfBufferImagSlot[band], pWorkImagSlot + 1, hHybrid->qmfBufferMove * sizeof(FIXP_DBL)); + + if (fixpQmfReal) { + + /* actual filtering only if output signal requested */ + switch( hybridRes ) { + + /* HYBRID_2_REAL & HYBRID_8_CPLX are only needful for baseline ps */ + case HYBRID_2_REAL: + + slotBasedDualChannelFiltering( pWorkRealSlot, + pWorkImagSlot, + pTempRealSlot, + pTempImagSlot); + break; + + case HYBRID_8_CPLX: + + slotBasedEightChannelFiltering( pWorkRealSlot, + pWorkImagSlot, + pTempRealSlot, + pTempImagSlot); + break; + + default: + FDK_ASSERT(0); + } + + for(k = 0; k < (SCHAR)hybridRes; k++) { + fixpHybridReal [chOffset + k] = pTempRealSlot[k]; + fixpHybridImag [chOffset + k] = pTempImagSlot[k]; + } + chOffset += hybridRes; + } /* if (mHybridReal) */ + } + + /* group hybrid channels 3+4 -> 3 and 2+5 -> 2 */ + fixpHybridReal[3] += fixpHybridReal[4]; + fixpHybridImag[3] += fixpHybridImag[4]; + fixpHybridReal[4] = (FIXP_DBL)0; + fixpHybridImag[4] = (FIXP_DBL)0; + + fixpHybridReal[2] += fixpHybridReal[5]; + fixpHybridImag[2] += fixpHybridImag[5]; + fixpHybridReal[5] = (FIXP_DBL)0; + fixpHybridImag[5] = (FIXP_DBL)0; + + /* free memory on scratch */ + C_ALLOC_SCRATCH_END(pTempRealSlot, FIXP_DBL, 4*HYBRID_FILTER_LENGTH); + +} + + +/******************************************************************************* + Functionname: slotBasedHybridSynthesis + ******************************************************************************* + + Description: The coefficients offering higher resolution for the lower QMF + channel are simply added prior to the synthesis with the 54 + subbands QMF. + + Arguments: + + Return: none + +*******************************************************************************/ + +/*!
+      l,r0(n) ---\
+      l,r1(n) ---- + --\
+      l,r2(n) ---/      \
+                         + --> F0(w)
+      l,r3(n) ---\      /
+      l,r4(n) ---- + --/
+      l,r5(n) ---/
+
+
+      l,r6(n) ---\
+                  + ---------> F1(w)
+      l,r7(n) ---/
+
+
+      l,r8(n) ---\
+                  + ---------> F2(w)
+      l,r9(n) ---/
+
+    
+ Hybrid QMF synthesis filterbank for the 10 and 20 stereo-bands configurations. The + coefficients offering higher resolution for the lower QMF channel are simply added + prior to the synthesis with the 54 subbands QMF. + + [see ISO/IEC 14496-3:2001/FDAM 2:2004(E) - Page 52] +*/ + + +void +slotBasedHybridSynthesis ( FIXP_DBL *fixpHybridReal, /*!< Hybrid real Values */ + FIXP_DBL *fixpHybridImag, /*!< Hybrid imag Values */ + FIXP_DBL *fixpQmfReal, /*!< Qmf real Values */ + FIXP_DBL *fixpQmfImag, /*!< Qmf imag Values */ + HANDLE_HYBRID hHybrid ) /*!< Handle to HYBRID struct. */ +{ + int k, band; + + HYBRID_RES hybridRes; + int chOffset = 0; + + for(band = 0; band < hHybrid->nQmfBands; band++) { + + FIXP_DBL qmfReal = FL2FXCONST_DBL(0.f); + FIXP_DBL qmfImag = FL2FXCONST_DBL(0.f); + hybridRes = (HYBRID_RES)hHybrid->pResolution[band]; + + for(k = 0; k < (SCHAR)hybridRes; k++) { + qmfReal += fixpHybridReal[chOffset + k]; + qmfImag += fixpHybridImag[chOffset + k]; + } + + fixpQmfReal[band] = qmfReal; + fixpQmfImag[band] = qmfImag; + + chOffset += hybridRes; + } +} + + + diff --git a/libSBRdec/src/psdec_hybrid.h b/libSBRdec/src/psdec_hybrid.h new file mode 100644 index 0000000..69e8707 --- /dev/null +++ b/libSBRdec/src/psdec_hybrid.h @@ -0,0 +1,109 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + + +#ifndef __HYBRID_H +#define __HYBRID_H + +#include "sbrdecoder.h" + + +#define HYBRID_FILTER_LENGTH 13 +#define HYBRID_FILTER_DELAY 6 + + +#define FAST_FILTER2 +#define FAST_FILTER4 +#define FAST_FILTER8 +#define FAST_FILTER12 + +#define FFT_IDX_R(a) (2*a) +#define FFT_IDX_I(a) (2*a+1) + +#define FIXP_FFT_IDX_R(a) (a<<1) +#define FIXP_FFT_IDX_I(a) ((a<<1) + 1) + + +typedef enum { + + HYBRID_2_REAL = 2, + HYBRID_4_CPLX = 4, + HYBRID_8_CPLX = 8, + HYBRID_12_CPLX = 12 + +} HYBRID_RES; + +typedef struct +{ + SCHAR nQmfBands; + SCHAR frameSize; + SCHAR qmfBufferMove; + + UCHAR pResolution[3]; + + FIXP_DBL mQmfBufferRealSlot[3][HYBRID_FILTER_LENGTH]; /**< Stores old Qmf samples. */ + FIXP_DBL mQmfBufferImagSlot[3][HYBRID_FILTER_LENGTH]; + SCHAR sf_mQmfBuffer; + +} HYBRID; + +typedef HYBRID *HANDLE_HYBRID; + +void +fillHybridDelayLine( FIXP_DBL **fixpQmfReal, + FIXP_DBL **fixpQmfImag, + FIXP_DBL fixpHybridLeftR[12], + FIXP_DBL fixpHybridLeftI[12], + FIXP_DBL fixpHybridRightR[12], + FIXP_DBL fixpHybridRightI[12], + HANDLE_HYBRID hHybrid ); + +void +slotBasedHybridAnalysis ( FIXP_DBL *fixpQmfReal, + FIXP_DBL *fixpQmfImag, + + FIXP_DBL *fixpHybridReal, + FIXP_DBL *fixpHybridImag, + + HANDLE_HYBRID hHybrid); + + +void +slotBasedHybridSynthesis ( FIXP_DBL *fixpHybridReal, + FIXP_DBL *fixpHybridImag, + + FIXP_DBL *fixpQmfReal, + FIXP_DBL *fixpQmfImag, + + HANDLE_HYBRID hHybrid ); + +SBR_ERROR InitHybridFilterBank ( HANDLE_HYBRID hHybrid, + SCHAR frameSize, + SCHAR noBands, + const UCHAR *pResolution ); + + +#endif /* __HYBRID_H */ diff --git a/libSBRdec/src/sbr_crc.cpp b/libSBRdec/src/sbr_crc.cpp new file mode 100644 index 0000000..3463710 --- /dev/null +++ b/libSBRdec/src/sbr_crc.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief CRC check coutines $Revision: 36841 $ +*/ + +#include "sbr_crc.h" + +#include "FDK_bitstream.h" +#include "transcendent.h" + +#define MAXCRCSTEP 16 +#define MAXCRCSTEP_LD 4 + +/*! + \brief crc calculation +*/ +static ULONG +calcCRC (HANDLE_CRC hCrcBuf, ULONG bValue, int nBits) +{ + int i; + ULONG bMask = (1UL << (nBits - 1)); + + for (i = 0; i < nBits; i++, bMask >>= 1) { + USHORT flag = (hCrcBuf->crcState & hCrcBuf->crcMask) ? 1 : 0; + USHORT flag1 = (bMask & bValue) ? 1 : 0; + + flag ^= flag1; + hCrcBuf->crcState <<= 1; + if (flag) + hCrcBuf->crcState ^= hCrcBuf->crcPoly; + } + + return (hCrcBuf->crcState); +} + + +/*! + \brief crc +*/ +static int +getCrc (HANDLE_FDK_BITSTREAM hBs, ULONG NrBits) +{ + int i; + CRC_BUFFER CrcBuf; + + CrcBuf.crcState = SBR_CRC_START; + CrcBuf.crcPoly = SBR_CRC_POLY; + CrcBuf.crcMask = SBR_CRC_MASK; + + int CrcStep = NrBits>>MAXCRCSTEP_LD; + + int CrcNrBitsRest = (NrBits - CrcStep * MAXCRCSTEP); + ULONG bValue; + + for (i = 0; i < CrcStep; i++) { + bValue = FDKreadBits (hBs, MAXCRCSTEP); + calcCRC (&CrcBuf, bValue, MAXCRCSTEP); + } + + bValue = FDKreadBits (hBs, CrcNrBitsRest); + calcCRC (&CrcBuf, bValue, CrcNrBitsRest); + + return (CrcBuf.crcState & SBR_CRC_RANGE); + +} + + +/*! + \brief crc interface + \return 1: CRC OK, 0: CRC check failure +*/ +int +SbrCrcCheck (HANDLE_FDK_BITSTREAM hBs, /*!< handle to bit-buffer */ + LONG NrBits) /*!< max. CRC length */ +{ + int crcResult = 1; + ULONG NrCrcBits; + ULONG crcCheckResult; + LONG NrBitsAvailable; + ULONG crcCheckSum; + + crcCheckSum = FDKreadBits (hBs, 10); + + NrBitsAvailable = FDKgetValidBits(hBs); + if (NrBitsAvailable <= 0){ + return 0; + } + + NrCrcBits = fixMin ((INT)NrBits, (INT)NrBitsAvailable); + + crcCheckResult = getCrc (hBs, NrCrcBits); + FDKpushBack(hBs, (NrBitsAvailable - FDKgetValidBits(hBs)) ); + + + if (crcCheckResult != crcCheckSum) { + crcResult = 0; + } + + return (crcResult); +} diff --git a/libSBRdec/src/sbr_crc.h b/libSBRdec/src/sbr_crc.h new file mode 100644 index 0000000..281f30c --- /dev/null +++ b/libSBRdec/src/sbr_crc.h @@ -0,0 +1,65 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief CRC checking routines $Revision: 36841 $ +*/ +#ifndef __SBR_CRC_H +#define __SBR_CRC_H + +#include "sbrdecoder.h" + +#include "FDK_bitstream.h" + +/* some useful crc polynoms: + +crc5: x^5+x^4+x^2+x^1+1 +crc6: x^6+x^5+x^3+x^2+x+1 +crc7: x^7+x^6+x^2+1 +crc8: x^8+x^2+x+x+1 +*/ + +/* default SBR CRC */ /* G(x) = x^10 + x^9 + x^5 + x^4 + x + 1 */ +#define SBR_CRC_POLY 0x0233 +#define SBR_CRC_MASK 0x0200 +#define SBR_CRC_START 0x0000 +#define SBR_CRC_RANGE 0x03FF + +typedef struct +{ + USHORT crcState; + USHORT crcMask; + USHORT crcPoly; +} +CRC_BUFFER; + +typedef CRC_BUFFER *HANDLE_CRC; + +int SbrCrcCheck (HANDLE_FDK_BITSTREAM hBitBuf, + LONG NrCrcBits); + + +#endif diff --git a/libSBRdec/src/sbr_deb.cpp b/libSBRdec/src/sbr_deb.cpp new file mode 100644 index 0000000..9bb3179 --- /dev/null +++ b/libSBRdec/src/sbr_deb.cpp @@ -0,0 +1,32 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Print selected debug messages $Revision: 36841 $ +*/ + +#include "sbr_deb.h" + diff --git a/libSBRdec/src/sbr_deb.h b/libSBRdec/src/sbr_deb.h new file mode 100644 index 0000000..9135158 --- /dev/null +++ b/libSBRdec/src/sbr_deb.h @@ -0,0 +1,36 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Debugging aids $Revision: 36841 $ +*/ + +#ifndef __SBR_DEB_H +#define __SBR_DEB_H + +#include "sbrdecoder.h" + +#endif diff --git a/libSBRdec/src/sbr_dec.cpp b/libSBRdec/src/sbr_dec.cpp new file mode 100644 index 0000000..a075ca3 --- /dev/null +++ b/libSBRdec/src/sbr_dec.cpp @@ -0,0 +1,985 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Sbr decoder $Revision: 36841 $ + This module provides the actual decoder implementation. The SBR data (side information) is already + decoded. Only three functions are provided: + + \li 1.) createSbrDec(): One time initialization + \li 2.) resetSbrDec(): Called by sbr_Apply() when the information contained in an SBR_HEADER_ELEMENT requires a reset + and recalculation of important SBR structures. + \li 3.) sbr_dec(): The actual decoder. Calls the different tools such as filterbanks, lppTransposer(), and calculateSbrEnvelope() + [the envelope adjuster]. + + \sa sbr_dec(), \ref documentationOverview +*/ + +#include "sbr_dec.h" + +#include "sbr_ram.h" +#include "env_extr.h" +#include "env_calc.h" +#include "scale.h" + +#include "genericStds.h" + +#include "sbrdec_drc.h" + + + +static void assignLcTimeSlots( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + FIXP_DBL **QmfBufferReal, + int noCols ) +{ + int slot, i; + FIXP_DBL *ptr; + + /* Number of QMF timeslots in the overlap buffer: */ + ptr = hSbrDec->pSbrOverlapBuffer; + for(slot=0; slotLppTrans.pSettings->overlap; slot++) { + QmfBufferReal[slot] = ptr; ptr += (64); + } + + /* Assign timeslots to Workbuffer1 */ + ptr = hSbrDec->WorkBuffer1; + for(i=0; i> 1) + hSbrDec->LppTrans.pSettings->overlap; + int totCols = noCols + hSbrDec->LppTrans.pSettings->overlap; + + /* Number of QMF timeslots in the overlap buffer: */ + ptr = hSbrDec->pSbrOverlapBuffer; + for(slot=0; slotLppTrans.pSettings->overlap; slot++) { + QmfBufferReal[slot] = ptr; ptr += (64); + QmfBufferImag[slot] = ptr; ptr += (64); + } + + /* Assign first half of timeslots to Workbuffer1 */ + ptr = hSbrDec->WorkBuffer1; + for(; slotWorkBuffer2; + for(; slotuseLP = useLP; + if (useLP) { + hSbrDec->SynthesisQMF.flags |= QMF_FLAG_LP; + hSbrDec->AnalysiscQMF.flags |= QMF_FLAG_LP; + } else { + hSbrDec->SynthesisQMF.flags &= ~QMF_FLAG_LP; + hSbrDec->AnalysiscQMF.flags &= ~QMF_FLAG_LP; + } + if (!useLP) + assignHqTimeSlots( hSbrDec, hSbrDec->QmfBufferReal, hSbrDec->QmfBufferImag, noCols ); + else + { + assignLcTimeSlots( hSbrDec, hSbrDec->QmfBufferReal, noCols ); + } +} + +static void changeQmfType( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + int useLdTimeAlign ) +{ + UINT synQmfFlags = hSbrDec->SynthesisQMF.flags; + UINT anaQmfFlags = hSbrDec->AnalysiscQMF.flags; + int resetSynQmf = 0; + int resetAnaQmf = 0; + + /* assign qmf type */ + if (useLdTimeAlign) { + if (synQmfFlags & QMF_FLAG_CLDFB) { + /* change the type to MPSLD */ + synQmfFlags &= ~QMF_FLAG_CLDFB; + synQmfFlags |= QMF_FLAG_MPSLDFB; + resetSynQmf = 1; + } + if (anaQmfFlags & QMF_FLAG_CLDFB) { + /* change the type to MPSLD */ + anaQmfFlags &= ~QMF_FLAG_CLDFB; + anaQmfFlags |= QMF_FLAG_MPSLDFB; + resetAnaQmf = 1; + } + } else { + if (synQmfFlags & QMF_FLAG_MPSLDFB) { + /* change the type to CLDFB */ + synQmfFlags &= ~QMF_FLAG_MPSLDFB; + synQmfFlags |= QMF_FLAG_CLDFB; + resetSynQmf = 1; + } + if (anaQmfFlags & QMF_FLAG_MPSLDFB) { + /* change the type to CLDFB */ + anaQmfFlags &= ~QMF_FLAG_MPSLDFB; + anaQmfFlags |= QMF_FLAG_CLDFB; + resetAnaQmf = 1; + } + } + + if (resetAnaQmf) { + int qmfErr = qmfInitAnalysisFilterBank ( + &hSbrDec->AnalysiscQMF, + hSbrDec->anaQmfStates, + hSbrDec->AnalysiscQMF.no_col, + hSbrDec->AnalysiscQMF.lsb, + hSbrDec->AnalysiscQMF.usb, + hSbrDec->AnalysiscQMF.no_channels, + anaQmfFlags | QMF_FLAG_KEEP_STATES + ); + if (qmfErr != 0) { + FDK_ASSERT(0); + } + } + + if (resetSynQmf) { + int qmfErr = qmfInitSynthesisFilterBank ( + &hSbrDec->SynthesisQMF, + hSbrDec->pSynQmfStates, + hSbrDec->SynthesisQMF.no_col, + hSbrDec->SynthesisQMF.lsb, + hSbrDec->SynthesisQMF.usb, + hSbrDec->SynthesisQMF.no_channels, + synQmfFlags | QMF_FLAG_KEEP_STATES + ); + + if (qmfErr != 0) { + FDK_ASSERT(0); + } + } +} + + +/*! + \brief SBR decoder core function for one channel + + \image html BufferMgmtDetailed-1632.png + + Besides the filter states of the QMF filter bank and the LPC-states of + the LPP-Transposer, processing is mainly based on four buffers: + #timeIn, #timeOut, #WorkBuffer2 and #OverlapBuffer. The #WorkBuffer2 + is reused for all channels and might be used by the core decoder, a + static overlap buffer is required for each channel. Du to in-place + processing, #timeIn and #timeOut point to identical locations. + + The spectral data is organized in so-called slots, each slot + containing 64 bands of complex data. The number of slots per frame is + dependend on the frame size. For mp3PRO, there are 18 slots per frame + and 6 slots per #OverlapBuffer. It is not necessary to have the slots + in located consecutive address ranges. + + To optimize memory usage and to minimize the number of memory + accesses, the memory management is organized as follows (Slot numbers + based on mp3PRO): + + 1.) Input time domain signal is located in #timeIn, the last slots + (0..5) of the spectral data of the previous frame are located in the + #OverlapBuffer. In addition, #frameData of the current frame resides + in the upper part of #timeIn. + + 2.) During the cplxAnalysisQmfFiltering(), 32 samples from #timeIn are transformed + into a slot of up to 32 complex spectral low band values at a + time. The first spectral slot -- nr. 6 -- is written at slot number + zero of #WorkBuffer2. #WorkBuffer2 will be completely filled with + spectral data. + + 3.) LPP-Transposition in lppTransposer() is processed on 24 slots. During the + transposition, the high band part of the spectral data is replicated + based on the low band data. + + Envelope Adjustment is processed on the high band part of the spectral + data only by calculateSbrEnvelope(). + + 4.) The cplxSynthesisQmfFiltering() creates 64 time domain samples out + of a slot of 64 complex spectral values at a time. The first 6 slots + in #timeOut are filled from the results of spectral slots 0..5 in the + #OverlapBuffer. The consecutive slots in timeOut are now filled with + the results of spectral slots 6..17. + + 5.) The preprocessed slots 18..23 have to be stored in the + #OverlapBuffer. + +*/ + +void +sbr_dec ( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + INT_PCM *timeIn, /*!< pointer to input time signal */ + INT_PCM *timeOut, /*!< pointer to output time signal */ + HANDLE_SBR_DEC hSbrDecRight, /*!< handle to Decoder channel right */ + INT_PCM *timeOutRight, /*!< pointer to output time signal */ + const int strideIn, /*!< Time data traversal strideIn */ + const int strideOut, /*!< Time data traversal strideOut */ + HANDLE_SBR_HEADER_DATA hHeaderData,/*!< Static control data */ + HANDLE_SBR_FRAME_DATA hFrameData, /*!< Control data of current frame */ + HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, /*!< Some control data of last frame */ + const int applyProcessing, /*!< Flag for SBR operation */ + HANDLE_PS_DEC h_ps_d, + const UINT flags + ) +{ + int i, slot, reserve; + int saveLbScale; + int ov_len; + int lastSlotOffs; + FIXP_DBL maxVal; + + /* 1+1/3 frames of spectral data: */ + FIXP_DBL **QmfBufferReal = hSbrDec->QmfBufferReal; + FIXP_DBL **QmfBufferImag = hSbrDec->QmfBufferImag; + + /* Number of QMF timeslots in the overlap buffer: */ + ov_len = hSbrDec->LppTrans.pSettings->overlap; + + /* Number of QMF slots per frame */ + int noCols = hHeaderData->numberTimeSlots * hHeaderData->timeStep; + + /* assign qmf time slots */ + if ( ((flags & SBRDEC_LOW_POWER ) ? 1 : 0) != ((hSbrDec->SynthesisQMF.flags & QMF_FLAG_LP) ? 1 : 0) ) { + assignTimeSlots( hSbrDec, hHeaderData->numberTimeSlots * hHeaderData->timeStep, flags & SBRDEC_LOW_POWER); + } + + if (flags & SBRDEC_ELD_GRID) { + /* Choose the right low delay filter bank */ + changeQmfType( hSbrDec, (flags & SBRDEC_LD_MPS_QMF) ? 1 : 0 ); + } + + /* + low band codec signal subband filtering + */ + + { + C_AALLOC_SCRATCH_START(qmfTemp, FIXP_DBL, 2*(64)); + + qmfAnalysisFiltering( &hSbrDec->AnalysiscQMF, + QmfBufferReal + ov_len, + QmfBufferImag + ov_len, + &hSbrDec->sbrScaleFactor, + timeIn, + strideIn, + qmfTemp + ); + + C_AALLOC_SCRATCH_END(qmfTemp, FIXP_DBL, 2*(64)); + } + + /* + Clear upper half of spectrum + */ + { + int nAnalysisBands = hHeaderData->numberOfAnalysisBands; + + if (! (flags & SBRDEC_LOW_POWER)) { + for (slot = ov_len; slot < noCols+ov_len; slot++) { + FDKmemclear(&QmfBufferReal[slot][nAnalysisBands],((64)-nAnalysisBands)*sizeof(FIXP_DBL)); + FDKmemclear(&QmfBufferImag[slot][nAnalysisBands],((64)-nAnalysisBands)*sizeof(FIXP_DBL)); + } + } else + for (slot = ov_len; slot < noCols+ov_len; slot++) { + FDKmemclear(&QmfBufferReal[slot][nAnalysisBands],((64)-nAnalysisBands)*sizeof(FIXP_DBL)); + } + } + + + + /* + Shift spectral data left to gain accuracy in transposer and adjustor + */ + maxVal = maxSubbandSample( QmfBufferReal, + (flags & SBRDEC_LOW_POWER) ? NULL : QmfBufferImag, + 0, + hSbrDec->AnalysiscQMF.lsb, + ov_len, + noCols+ov_len ); + + reserve = fixMax(0,CntLeadingZeros(maxVal)-1) ; + reserve = fixMin(reserve,DFRACT_BITS-1-hSbrDec->sbrScaleFactor.lb_scale); + + /* If all data is zero, lb_scale could become too large */ + rescaleSubbandSamples( QmfBufferReal, + (flags & SBRDEC_LOW_POWER) ? NULL : QmfBufferImag, + 0, + hSbrDec->AnalysiscQMF.lsb, + ov_len, + noCols+ov_len, + reserve); + + hSbrDec->sbrScaleFactor.lb_scale += reserve; + + /* + save low band scale, wavecoding or parametric stereo may modify it + */ + saveLbScale = hSbrDec->sbrScaleFactor.lb_scale; + + + if (applyProcessing) + { + UCHAR * borders = hFrameData->frameInfo.borders; + lastSlotOffs = borders[hFrameData->frameInfo.nEnvelopes] - hHeaderData->numberTimeSlots; + + FIXP_DBL degreeAlias[(64)]; + + /* The transposer will override most values in degreeAlias[]. + The array needs to be cleared at least from lowSubband to highSubband before. */ + if (flags & SBRDEC_LOW_POWER) + FDKmemclear(°reeAlias[hHeaderData->freqBandData.lowSubband], (hHeaderData->freqBandData.highSubband-hHeaderData->freqBandData.lowSubband)*sizeof(FIXP_DBL)); + + /* + Inverse filtering of lowband and transposition into the SBR-frequency range + */ + + lppTransposer ( &hSbrDec->LppTrans, + &hSbrDec->sbrScaleFactor, + QmfBufferReal, + degreeAlias, // only used if useLP = 1 + QmfBufferImag, + flags & SBRDEC_LOW_POWER, + hHeaderData->timeStep, + borders[0], + lastSlotOffs, + hHeaderData->freqBandData.nInvfBands, + hFrameData->sbr_invf_mode, + hPrevFrameData->sbr_invf_mode ); + + + + + + /* + Adjust envelope of current frame. + */ + + calculateSbrEnvelope (&hSbrDec->sbrScaleFactor, + &hSbrDec->SbrCalculateEnvelope, + hHeaderData, + hFrameData, + QmfBufferReal, + QmfBufferImag, + flags & SBRDEC_LOW_POWER, + + degreeAlias, + flags, + (hHeaderData->frameErrorFlag || hPrevFrameData->frameErrorFlag)); + + + /* + Update hPrevFrameData (to be used in the next frame) + */ + for (i=0; ifreqBandData.nInvfBands; i++) { + hPrevFrameData->sbr_invf_mode[i] = hFrameData->sbr_invf_mode[i]; + } + hPrevFrameData->coupling = hFrameData->coupling; + hPrevFrameData->stopPos = borders[hFrameData->frameInfo.nEnvelopes]; + hPrevFrameData->ampRes = hFrameData->ampResolutionCurrentFrame; + } + else { + /* Reset hb_scale if no highband is present, because hb_scale is considered in the QMF-synthesis */ + hSbrDec->sbrScaleFactor.hb_scale = saveLbScale; + } + + + for (i=0; iLppTrans.lpcFilterStatesReal[i], QmfBufferReal[noCols-LPC_ORDER+i], hSbrDec->AnalysiscQMF.lsb*sizeof(FIXP_DBL)); + FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesImag[i], QmfBufferImag[noCols-LPC_ORDER+i], hSbrDec->AnalysiscQMF.lsb*sizeof(FIXP_DBL)); + } else + FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesReal[i], QmfBufferReal[noCols-LPC_ORDER+i], hSbrDec->AnalysiscQMF.lsb*sizeof(FIXP_DBL)); + } + + /* + Synthesis subband filtering. + */ + + if ( ! (flags & SBRDEC_PS_DECODED) ) { + + { + int outScalefactor = 0; + + if (h_ps_d != NULL) { + h_ps_d->procFrameBased = 1; /* we here do frame based processing */ + } + + + sbrDecoder_drcApply(&hSbrDec->sbrDrcChannel, + QmfBufferReal, + (flags & SBRDEC_LOW_POWER) ? NULL : QmfBufferImag, + hSbrDec->SynthesisQMF.no_col, + &outScalefactor + ); + + + + qmfChangeOutScalefactor(&hSbrDec->SynthesisQMF, outScalefactor ); + + { + C_AALLOC_SCRATCH_START(qmfTemp, FIXP_DBL, 2*(64)); + + qmfSynthesisFiltering( &hSbrDec->SynthesisQMF, + QmfBufferReal, + (flags & SBRDEC_LOW_POWER) ? NULL : QmfBufferImag, + &hSbrDec->sbrScaleFactor, + hSbrDec->LppTrans.pSettings->overlap, + timeOut, + strideOut, + qmfTemp); + + C_AALLOC_SCRATCH_END(qmfTemp, FIXP_DBL, 2*(64)); + } + + } + + } else { /* (flags & SBRDEC_PS_DECODED) */ + INT i, sdiff, outScalefactor, scaleFactorLowBand, scaleFactorHighBand; + SCHAR scaleFactorLowBand_ov, scaleFactorLowBand_no_ov; + + HANDLE_QMF_FILTER_BANK synQmf = &hSbrDec->SynthesisQMF; + HANDLE_QMF_FILTER_BANK synQmfRight = &hSbrDecRight->SynthesisQMF; + + /* adapt scaling */ + sdiff = hSbrDec->sbrScaleFactor.lb_scale - reserve; /* Scaling difference */ + scaleFactorHighBand = sdiff - hSbrDec->sbrScaleFactor.hb_scale; /* Scale of current high band */ + scaleFactorLowBand_ov = sdiff - hSbrDec->sbrScaleFactor.ov_lb_scale; /* Scale of low band overlapping QMF data */ + scaleFactorLowBand_no_ov = sdiff - hSbrDec->sbrScaleFactor.lb_scale; /* Scale of low band current QMF data */ + outScalefactor = 0; /* Initial output scale */ + + if (h_ps_d->procFrameBased == 1) /* If we have switched from frame to slot based processing copy filter states */ + { /* procFrameBased will be unset later */ + /* copy filter states from left to right */ + FDKmemcpy(synQmfRight->FilterStates, synQmf->FilterStates, ((640)-(64))*sizeof(FIXP_QSS)); + } + + /* scale ALL qmf vales ( real and imag ) of mono / left channel to the + same scale factor ( ov_lb_sf, lb_sf and hq_sf ) */ + scalFilterBankValues( h_ps_d, /* parametric stereo decoder handle */ + QmfBufferReal, /* qmf filterbank values */ + QmfBufferImag, /* qmf filterbank values */ + synQmf->lsb, /* sbr start subband */ + hSbrDec->sbrScaleFactor.ov_lb_scale, + hSbrDec->sbrScaleFactor.lb_scale, + &scaleFactorLowBand_ov, /* adapt scaling values */ + &scaleFactorLowBand_no_ov, /* adapt scaling values */ + hSbrDec->sbrScaleFactor.hb_scale, /* current frame ( highband ) */ + &scaleFactorHighBand, + synQmf->no_col); + + /* use the same synthese qmf values for left and right channel */ + synQmfRight->no_col = synQmf->no_col; + synQmfRight->lsb = synQmf->lsb; + synQmfRight->usb = synQmf->usb; + + int env=0; + + outScalefactor += (SCAL_HEADROOM+1); /* psDiffScale! */ + + { + C_ALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, 2*(64)); + + int maxShift = 0; + + if (hSbrDec->sbrDrcChannel.prevFact_exp > maxShift) { + maxShift = hSbrDec->sbrDrcChannel.prevFact_exp; + } + if (hSbrDec->sbrDrcChannel.currFact_exp > maxShift) { + maxShift = hSbrDec->sbrDrcChannel.currFact_exp; + } + if (hSbrDec->sbrDrcChannel.nextFact_exp > maxShift) { + maxShift = hSbrDec->sbrDrcChannel.nextFact_exp; + } + + for (i = 0; i < synQmf->no_col; i++) { /* ----- no_col loop ----- */ + + INT outScalefactorR, outScalefactorL; + outScalefactorR = outScalefactorL = outScalefactor; + + /* qmf timeslot of right channel */ + FIXP_DBL* rQmfReal = pWorkBuffer; + FIXP_DBL* rQmfImag = pWorkBuffer + 64; + + + { + if ( i == h_ps_d->bsData[h_ps_d->processSlot].mpeg.aEnvStartStop[env] ) { + initSlotBasedRotation( h_ps_d, env, hHeaderData->freqBandData.highSubband ); + env++; + } + + ApplyPsSlot( h_ps_d, /* parametric stereo decoder handle */ + (QmfBufferReal + i), /* one timeslot of left/mono channel */ + (QmfBufferImag + i), /* one timeslot of left/mono channel */ + rQmfReal, /* one timeslot or right channel */ + rQmfImag); /* one timeslot or right channel */ + } + + + scaleFactorLowBand = (i<(6)) ? scaleFactorLowBand_ov : scaleFactorLowBand_no_ov; + + + sbrDecoder_drcApplySlot ( /* right channel */ + &hSbrDec->sbrDrcChannel, + rQmfReal, + rQmfImag, + i, + synQmfRight->no_col, + maxShift + ); + + outScalefactorR += maxShift; + + sbrDecoder_drcApplySlot ( /* left channel */ + &hSbrDec->sbrDrcChannel, + *(QmfBufferReal + i), + *(QmfBufferImag + i), + i, + synQmf->no_col, + maxShift + ); + + outScalefactorL += maxShift; + + + /* scale filter states for left and right channel */ + qmfChangeOutScalefactor( synQmf, outScalefactorL ); + qmfChangeOutScalefactor( synQmfRight, outScalefactorR ); + + { + + qmfSynthesisFilteringSlot( synQmfRight, + rQmfReal, /* QMF real buffer */ + rQmfImag, /* QMF imag buffer */ + scaleFactorLowBand, + scaleFactorHighBand, + timeOutRight+(i*synQmf->no_channels*strideOut), + strideOut, + pWorkBuffer); + + qmfSynthesisFilteringSlot( synQmf, + *(QmfBufferReal + i), /* QMF real buffer */ + *(QmfBufferImag + i), /* QMF imag buffer */ + scaleFactorLowBand, + scaleFactorHighBand, + timeOut+(i*synQmf->no_channels*strideOut), + strideOut, + pWorkBuffer); + + } + } /* no_col loop i */ + + /* scale back (6) timeslots look ahead for hybrid filterbank to original value */ + rescalFilterBankValues( h_ps_d, + QmfBufferReal, + QmfBufferImag, + synQmf->lsb, + synQmf->no_col ); + + C_ALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, 2*(64)); + } + } + + sbrDecoder_drcUpdateChannel( &hSbrDec->sbrDrcChannel ); + + + /* + Update overlap buffer + Even bands above usb are copied to avoid outdated spectral data in case + the stop frequency raises. + */ + + if (hSbrDec->LppTrans.pSettings->overlap > 0) + { + if (! (flags & SBRDEC_LOW_POWER)) { + for ( i=0; iLppTrans.pSettings->overlap; i++ ) { + FDKmemcpy(QmfBufferReal[i], QmfBufferReal[i+noCols], (64)*sizeof(FIXP_DBL)); + FDKmemcpy(QmfBufferImag[i], QmfBufferImag[i+noCols], (64)*sizeof(FIXP_DBL)); + } + } else + for ( i=0; iLppTrans.pSettings->overlap; i++ ) { + FDKmemcpy(QmfBufferReal[i], QmfBufferReal[i+noCols], (64)*sizeof(FIXP_DBL)); + } + } + + hSbrDec->sbrScaleFactor.ov_lb_scale = saveLbScale; + + /* Save current frame status */ + hPrevFrameData->frameErrorFlag = hHeaderData->frameErrorFlag; + +} // sbr_dec() + + +/*! + \brief Creates sbr decoder structure + \return errorCode, 0 if successful +*/ +SBR_ERROR +createSbrDec (SBR_CHANNEL * hSbrChannel, + HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + TRANSPOSER_SETTINGS *pSettings, + const int downsampleFac, /*!< Downsampling factor */ + const UINT qmfFlags, /*!< flags -> 1: HQ/LP selector, 2: CLDFB */ + const UINT flags, + const int overlap, + int chan) /*!< Channel for which to assign buffers etc. */ + +{ + SBR_ERROR err = SBRDEC_OK; + int timeSlots = hHeaderData->numberTimeSlots; /* Number of SBR slots per frame */ + int noCols = timeSlots * hHeaderData->timeStep; /* Number of QMF slots per frame */ + HANDLE_SBR_DEC hs = &(hSbrChannel->SbrDec); + + /* Initialize scale factors */ + hs->sbrScaleFactor.ov_lb_scale = 0; + hs->sbrScaleFactor.ov_hb_scale = 0; + hs->sbrScaleFactor.hb_scale = 0; + + + /* + create envelope calculator + */ + err = createSbrEnvelopeCalc (&hs->SbrCalculateEnvelope, + hHeaderData, + chan, + flags); + if (err != SBRDEC_OK) { + return err; + } + + /* + create QMF filter banks + */ + { + int qmfErr; + + qmfErr = qmfInitAnalysisFilterBank ( + &hs->AnalysiscQMF, + hs->anaQmfStates, + noCols, + hHeaderData->freqBandData.lowSubband, + hHeaderData->freqBandData.highSubband, + hHeaderData->numberOfAnalysisBands, + qmfFlags & (~QMF_FLAG_KEEP_STATES) + ); + if (qmfErr != 0) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + } + if (hs->pSynQmfStates == NULL) { + hs->pSynQmfStates = GetRam_sbr_QmfStatesSynthesis(chan); + if (hs->pSynQmfStates == NULL) + return SBRDEC_MEM_ALLOC_FAILED; + } + + { + int qmfErr; + + qmfErr = qmfInitSynthesisFilterBank ( + &hs->SynthesisQMF, + hs->pSynQmfStates, + noCols, + hHeaderData->freqBandData.lowSubband, + hHeaderData->freqBandData.highSubband, + (64) / downsampleFac, + qmfFlags & (~QMF_FLAG_KEEP_STATES) + ); + + if (qmfErr != 0) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + } + initSbrPrevFrameData (&hSbrChannel->prevFrameData, timeSlots); + + /* + create transposer + */ + err = createLppTransposer (&hs->LppTrans, + pSettings, + hHeaderData->freqBandData.lowSubband, + hHeaderData->freqBandData.v_k_master, + hHeaderData->freqBandData.numMaster, + hs->SynthesisQMF.usb, + timeSlots, + hs->AnalysiscQMF.no_col, + hHeaderData->freqBandData.freqBandTableNoise, + hHeaderData->freqBandData.nNfb, + hHeaderData->sbrProcSmplRate, + chan, + overlap ); + if (err != SBRDEC_OK) { + return err; + } + + /* The CLDFB does not have overlap */ + if ((qmfFlags & QMF_FLAG_CLDFB) == 0) { + if (hs->pSbrOverlapBuffer == NULL) { + hs->pSbrOverlapBuffer = GetRam_sbr_OverlapBuffer(chan); + if (hs->pSbrOverlapBuffer == NULL) { + return SBRDEC_MEM_ALLOC_FAILED; + } + } else { + /* Clear overlap buffer */ + FDKmemclear( hs->pSbrOverlapBuffer, + sizeof(FIXP_DBL) * 2 * (6) * (64) + ); + } + } + + /* assign qmf time slots */ + assignTimeSlots( &hSbrChannel->SbrDec, hHeaderData->numberTimeSlots * hHeaderData->timeStep, qmfFlags & QMF_FLAG_LP); + + return err; +} + +/*! + \brief Delete sbr decoder structure + \return errorCode, 0 if successful +*/ +int +deleteSbrDec (SBR_CHANNEL * hSbrChannel) +{ + HANDLE_SBR_DEC hs = &hSbrChannel->SbrDec; + + deleteSbrEnvelopeCalc (&hs->SbrCalculateEnvelope); + + /* delete QMF filter states */ + if (hs->pSynQmfStates != NULL) { + FreeRam_sbr_QmfStatesSynthesis(&hs->pSynQmfStates); + } + + + if (hs->pSbrOverlapBuffer != NULL) { + FreeRam_sbr_OverlapBuffer(&hs->pSbrOverlapBuffer); + } + + return 0; +} + + +/*! + \brief resets sbr decoder structure + \return errorCode, 0 if successful +*/ +SBR_ERROR +resetSbrDec (HANDLE_SBR_DEC hSbrDec, + HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, + const int useLP, + const int downsampleFac + ) +{ + SBR_ERROR sbrError = SBRDEC_OK; + + int old_lsb = hSbrDec->SynthesisQMF.lsb; + int new_lsb = hHeaderData->freqBandData.lowSubband; + int l, startBand, stopBand, startSlot, size; + + int source_scale, target_scale, delta_scale, target_lsb, target_usb, reserve; + FIXP_DBL maxVal; + + /* overlapBuffer point to first (6) slots */ + FIXP_DBL **OverlapBufferReal = hSbrDec->QmfBufferReal; + FIXP_DBL **OverlapBufferImag = hSbrDec->QmfBufferImag; + + /* assign qmf time slots */ + assignTimeSlots( hSbrDec, hHeaderData->numberTimeSlots * hHeaderData->timeStep, useLP); + + + + resetSbrEnvelopeCalc (&hSbrDec->SbrCalculateEnvelope); + + hSbrDec->SynthesisQMF.lsb = hHeaderData->freqBandData.lowSubband; + hSbrDec->SynthesisQMF.usb = fixMin((INT)hSbrDec->SynthesisQMF.no_channels, (INT)hHeaderData->freqBandData.highSubband); + + hSbrDec->AnalysiscQMF.lsb = hSbrDec->SynthesisQMF.lsb; + hSbrDec->AnalysiscQMF.usb = hSbrDec->SynthesisQMF.usb; + + + /* + The following initialization of spectral data in the overlap buffer + is required for dynamic x-over or a change of the start-freq for 2 reasons: + + 1. If the lowband gets _wider_, unadjusted data would remain + + 2. If the lowband becomes _smaller_, the highest bands of the old lowband + must be cleared because the whitening would be affected + */ + startBand = old_lsb; + stopBand = new_lsb; + startSlot = hHeaderData->timeStep * (hPrevFrameData->stopPos - hHeaderData->numberTimeSlots); + size = fixMax(0,stopBand-startBand); + + /* keep already adjusted data in the x-over-area */ + if (!useLP) { + for (l=startSlot; lLppTrans.pSettings->overlap; l++) { + FDKmemclear(&OverlapBufferReal[l][startBand], size*sizeof(FIXP_DBL)); + FDKmemclear(&OverlapBufferImag[l][startBand], size*sizeof(FIXP_DBL)); + } + } else + for (l=startSlot; lLppTrans.pSettings->overlap ; l++) { + FDKmemclear(&OverlapBufferReal[l][startBand], size*sizeof(FIXP_DBL)); + } + + + /* + reset LPC filter states + */ + startBand = fixMin(old_lsb,new_lsb); + stopBand = fixMax(old_lsb,new_lsb); + size = fixMax(0,stopBand-startBand); + + FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesReal[0][startBand], size*sizeof(FIXP_DBL)); + FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesReal[1][startBand], size*sizeof(FIXP_DBL)); + if (!useLP) { + FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesImag[0][startBand], size*sizeof(FIXP_DBL)); + FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesImag[1][startBand], size*sizeof(FIXP_DBL)); + } + + + /* + Rescale already processed spectral data between old and new x-over frequency. + This must be done because of the separate scalefactors for lowband and highband. + */ + startBand = fixMin(old_lsb,new_lsb); + stopBand = fixMax(old_lsb,new_lsb); + + if (new_lsb > old_lsb) { + /* The x-over-area was part of the highband before and will now belong to the lowband */ + source_scale = hSbrDec->sbrScaleFactor.ov_hb_scale; + target_scale = hSbrDec->sbrScaleFactor.ov_lb_scale; + target_lsb = 0; + target_usb = old_lsb; + } + else { + /* The x-over-area was part of the lowband before and will now belong to the highband */ + source_scale = hSbrDec->sbrScaleFactor.ov_lb_scale; + target_scale = hSbrDec->sbrScaleFactor.ov_hb_scale; + /* jdr: The values old_lsb and old_usb might be wrong because the previous frame might have been "upsamling". */ + target_lsb = hSbrDec->SynthesisQMF.lsb; + target_usb = hSbrDec->SynthesisQMF.usb; + } + + /* Shift left all samples of the x-over-area as much as possible + An unnecessary coarse scale could cause ov_lb_scale or ov_hb_scale to be + adapted and the accuracy in the next frame would seriously suffer! */ + + maxVal = maxSubbandSample( OverlapBufferReal, + (useLP) ? NULL : OverlapBufferImag, + startBand, + stopBand, + 0, + startSlot); + + reserve = CntLeadingZeros(maxVal)-1; + reserve = fixMin(reserve,DFRACT_BITS-1-source_scale); + + rescaleSubbandSamples( OverlapBufferReal, + (useLP) ? NULL : OverlapBufferImag, + startBand, + stopBand, + 0, + startSlot, + reserve); + source_scale += reserve; + + delta_scale = target_scale - source_scale; + + if (delta_scale > 0) { /* x-over-area is dominant */ + delta_scale = -delta_scale; + startBand = target_lsb; + stopBand = target_usb; + + if (new_lsb > old_lsb) { + /* The lowband has to be rescaled */ + hSbrDec->sbrScaleFactor.ov_lb_scale = source_scale; + } + else { + /* The highband has be be rescaled */ + hSbrDec->sbrScaleFactor.ov_hb_scale = source_scale; + } + } + + FDK_ASSERT(startBand <= stopBand); + + if (!useLP) { + for (l=0; lLppTrans, + hHeaderData->freqBandData.lowSubband, + hHeaderData->freqBandData.v_k_master, + hHeaderData->freqBandData.numMaster, + hHeaderData->freqBandData.freqBandTableNoise, + hHeaderData->freqBandData.nNfb, + hHeaderData->freqBandData.highSubband, + hHeaderData->sbrProcSmplRate); + if (sbrError != SBRDEC_OK) + return sbrError; + + sbrError = ResetLimiterBands ( hHeaderData->freqBandData.limiterBandTable, + &hHeaderData->freqBandData.noLimiterBands, + hHeaderData->freqBandData.freqBandTable[0], + hHeaderData->freqBandData.nSfb[0], + hSbrDec->LppTrans.pSettings->patchParam, + hSbrDec->LppTrans.pSettings->noOfPatches, + hHeaderData->bs_data.limiterBands); + + + return sbrError; +} diff --git a/libSBRdec/src/sbr_dec.h b/libSBRdec/src/sbr_dec.h new file mode 100644 index 0000000..d967957 --- /dev/null +++ b/libSBRdec/src/sbr_dec.h @@ -0,0 +1,152 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Sbr decoder $Revision: 36841 $ +*/ +#ifndef __SBR_DEC_H +#define __SBR_DEC_H + +#include "sbrdecoder.h" + +#include "lpp_tran.h" +#include "qmf.h" +#include "env_calc.h" +#include "FDK_audio.h" + + +#include "sbrdec_drc.h" + +#define SACDEC_ALIGNMENT_FIX + +typedef struct +{ + QMF_FILTER_BANK AnalysiscQMF; + QMF_FILTER_BANK SynthesisQMF; + + SBR_CALCULATE_ENVELOPE SbrCalculateEnvelope; + SBR_LPP_TRANS LppTrans; + + QMF_SCALE_FACTOR sbrScaleFactor; + QMF_SCALE_FACTOR sbrScaleFactorRight; + + /*! Delayed spectral data needed for the dynamic framing of SBR. Not required in case of CLDFB */ + FIXP_DBL * pSbrOverlapBuffer; + + /* References to workbuffers */ + FIXP_DBL * WorkBuffer1; + FIXP_DBL * WorkBuffer2; + + /* QMF filter states */ + FIXP_QAS anaQmfStates[(320)]; + FIXP_QSS * pSynQmfStates; + + /* Reference pointer arrays for QMF time slots, + mixed among overlap and current slots. */ + FIXP_DBL * QmfBufferReal[(((1024)/(32))+(6))]; + FIXP_DBL * QmfBufferImag[(((1024)/(32))+(6))]; + int useLP; + + /* QMF domain extension time slot reference pointer array */ + + SBRDEC_DRC_CHANNEL sbrDrcChannel; + +} SBR_DEC; + +typedef SBR_DEC *HANDLE_SBR_DEC; + + +typedef struct +{ + SBR_FRAME_DATA frameData[(1)+1]; + SBR_PREV_FRAME_DATA prevFrameData; + SBR_DEC SbrDec; +} +SBR_CHANNEL; + +typedef SBR_CHANNEL *HANDLE_SBR_CHANNEL; + +void +SbrDecodeAndProcess (HANDLE_SBR_DEC hSbrDec, + INT_PCM *timeIn, + HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA hFrameData, + HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, + int applyProcessing, + int channelNr + , UCHAR useLP + ); + + +void +SbrConstructTimeOutput (HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + INT_PCM *timeOut, /*!< pointer to output time signal */ + HANDLE_SBR_HEADER_DATA hHeaderData,/*!< Static control data */ + HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, /*!< Some control data of last frame */ + int channelNr + ,UCHAR useLP + ); + + +void +sbr_dec (HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + INT_PCM *timeIn, /*!< pointer to input time signal */ + INT_PCM *timeOut, /*!< pointer to output time signal */ + HANDLE_SBR_DEC hSbrDecRight, /*!< handle to Decoder channel right */ + INT_PCM *timeOutRight, /*!< pointer to output time signal */ + const int strideIn, /*!< Time data traversal strideIn */ + const int strideOut, /*!< Time data traversal strideOut */ + HANDLE_SBR_HEADER_DATA hHeaderData,/*!< Static control data */ + HANDLE_SBR_FRAME_DATA hFrameData, /*!< Control data of current frame */ + HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, /*!< Some control data of last frame */ + const int applyProcessing, /*!< Flag for SBR operation */ + HANDLE_PS_DEC h_ps_d, + const UINT flags + ); + + + +SBR_ERROR +createSbrDec (SBR_CHANNEL * hSbrChannel, + HANDLE_SBR_HEADER_DATA hHeaderData, + TRANSPOSER_SETTINGS *pSettings, + const int downsampleFac, + const UINT qmfFlags, + const UINT flags, + const int overlap, + int chan); + +int +deleteSbrDec (SBR_CHANNEL * hSbrChannel); + +SBR_ERROR +resetSbrDec (HANDLE_SBR_DEC hSbrDec, + HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, + const int useLP, + const int downsampleFac); + +#endif diff --git a/libSBRdec/src/sbr_ram.cpp b/libSBRdec/src/sbr_ram.cpp new file mode 100644 index 0000000..6fa34a5 --- /dev/null +++ b/libSBRdec/src/sbr_ram.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Memory layout + $Revision: 36841 $ + + This module declares all static and dynamic memory spaces +*/ + +#include "sbr_ram.h" + + + + +#define WORKBUFFER1_TAG 0 +#define WORKBUFFER2_TAG 1 + +/*! + \name StaticSbrData + + Static memory areas, must not be overwritten in other sections of the decoder +*/ +/* @{ */ + +/*! SBR Decoder main structure */ +C_ALLOC_MEM(Ram_SbrDecoder, struct SBR_DECODER_INSTANCE, 1) +/*! SBR Decoder element data
+ Dimension: (4) */ +C_ALLOC_MEM2(Ram_SbrDecElement, SBR_DECODER_ELEMENT, 1, (4)) +/*! SBR Decoder individual channel data
+ Dimension: (6) */ +C_ALLOC_MEM2(Ram_SbrDecChannel, SBR_CHANNEL, 1, (6)+1) + +/*! Filter states for QMF-synthesis.
+ Dimension: #(6) * (#QMF_FILTER_STATE_SYN_SIZE-#(64)) */ +C_AALLOC_MEM2_L(Ram_sbr_QmfStatesSynthesis, FIXP_QSS, (640)-(64), (6)+1, SECT_DATA_L1) + +/*! Delayed spectral data needed for the dynamic framing of SBR. + For mp3PRO, 1/3 of a frame is buffered (#(6) 6) */ +C_AALLOC_MEM2(Ram_sbr_OverlapBuffer, FIXP_DBL, 2 * (6) * (64), (6)+1) + +/*! Static Data of PS */ + +C_ALLOC_MEM(Ram_ps_dec, PS_DEC, 1) + + +/* @} */ + + +/*! + \name DynamicSbrData + + Dynamic memory areas, might be reused in other algorithm sections, + e.g. the core decoder +
+ Depending on the mode set by DONT_USE_CORE_WORKBUFFER, workbuffers are + defined additionally to the CoreWorkbuffer. +
+ The size of WorkBuffers is ((1024)/(32))*(64) = 2048. +
+ WorkBuffer2 is a pointer to the CoreWorkBuffer wich is reused here in the SBR part. In case of + DONT_USE_CORE_WORKBUFFER, the CoreWorkbuffer is not used and the according + Workbuffer2 is defined locally in this file. +
+ WorkBuffer1 is reused in the AAC core (-> aacdecoder.cpp, aac_ram.cpp) +
+ + Use of WorkBuffers: +
+
+    -------------------------------------------------------------
+    AAC core:
+
+      CoreWorkbuffer: spectral coefficients
+      WorkBuffer1:    CAacDecoderChannelInfo, CAacDecoderDynamicData
+
+    -------------------------------------------------------------
+    SBR part:
+      ----------------------------------------------
+      Low Power Mode (useLP=1 or LOW_POWER_SBR_ONLY), see assignLcTimeSlots()
+
+        SLOT_BASED_PROTOTYPE_SYN_FILTER
+
+        WorkBuffer1                                WorkBuffer2(=CoreWorkbuffer)
+         ________________                           ________________
+        | RealLeft       |                         | RealRight      |
+        |________________|                         |________________|
+
+      ----------------------------------------------
+      High Quality Mode (!LOW_POWER_SBR_ONLY and useLP=0), see assignHqTimeSlots()
+
+         SLOTBASED_PS
+
+         WorkBuffer1                                WorkBuffer2(=CoreWorkbuffer)
+         ________________                           ________________
+        | Real/Imag      |  interleaved            | Real/Imag      |  interleaved
+        |________________|  first half actual ch   |________________|  second half actual ch
+
+    -------------------------------------------------------------
+
+  
+ +*/ +/* @{ */ +C_ALLOC_MEM_OVERLAY(Ram_SbrDecWorkBuffer1, FIXP_DBL, ((1024)/(32))*(64), SECT_DATA_L1, WORKBUFFER1_TAG) +C_ALLOC_MEM_OVERLAY(Ram_SbrDecWorkBuffer2, FIXP_DBL, ((1024)/(32))*(64), SECT_DATA_L2, WORKBUFFER2_TAG) + +/* @} */ + + + + diff --git a/libSBRdec/src/sbr_ram.h b/libSBRdec/src/sbr_ram.h new file mode 100644 index 0000000..378d3c9 --- /dev/null +++ b/libSBRdec/src/sbr_ram.h @@ -0,0 +1,100 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! +\file +\brief Memory layout +$Revision: 36841 $ +*/ +#ifndef _SBR_RAM_H_ +#define _SBR_RAM_H_ + +#include "sbrdecoder.h" + +#include "env_extr.h" +#include "sbr_dec.h" + + + +#define SBRDEC_MAX_CH_PER_ELEMENT (2) + +typedef struct +{ + SBR_CHANNEL *pSbrChannel[SBRDEC_MAX_CH_PER_ELEMENT]; + TRANSPOSER_SETTINGS transposerSettings; /* Common transport settings for each individual channel of an element */ + HANDLE_FDK_BITSTREAM hBs; + + MP4_ELEMENT_ID elementID; /* Element ID set during initialization. Can be used for concealment */ + int nChannels; /* Number of elements output channels (=2 in case of PS) */ + + UCHAR frameErrorFlag[(1)+1]; /* Frame error status (for every slot in the delay line). + Will be copied into header at the very beginning of decodeElement() routine. */ + + UCHAR useFrameSlot; /* Index which defines which slot will be decoded/filled next (used with additional delay) */ + UCHAR useHeaderSlot[(1)+1]; /* Index array that provides the link between header and frame data + (important when processing with additional delay). */ +} SBR_DECODER_ELEMENT; + + +struct SBR_DECODER_INSTANCE +{ + SBR_DECODER_ELEMENT *pSbrElement[(4)]; + SBR_HEADER_DATA sbrHeader[(4)][(1)+1]; /* Sbr header for each individual channel of an element */ + + FIXP_DBL *workBuffer1; + FIXP_DBL *workBuffer2; + + HANDLE_PS_DEC hParametricStereoDec; + + /* Global parameters */ + AUDIO_OBJECT_TYPE coreCodec; /* AOT of core codec */ + int numSbrElements; + int numSbrChannels; + INT sampleRateIn; /* SBR decoder input sampling rate; might be different than the transposer input sampling rate. */ + INT sampleRateOut; /* Sampling rate of the SBR decoder output audio samples. */ + USHORT codecFrameSize; + UCHAR synDownsampleFac; + UCHAR numDelayFrames; /* The current number of additional delay frames used for processing. */ + + UINT flags; + +}; + +H_ALLOC_MEM(Ram_SbrDecElement, SBR_DECODER_ELEMENT) +H_ALLOC_MEM(Ram_SbrDecChannel, SBR_CHANNEL) +H_ALLOC_MEM(Ram_SbrDecoder, struct SBR_DECODER_INSTANCE) + +H_ALLOC_MEM(Ram_sbr_QmfStatesSynthesis, FIXP_QSS) +H_ALLOC_MEM(Ram_sbr_OverlapBuffer, FIXP_DBL) + + +H_ALLOC_MEM(Ram_ps_dec, PS_DEC) + + +H_ALLOC_MEM_OVERLAY(Ram_SbrDecWorkBuffer1, FIXP_DBL) +H_ALLOC_MEM_OVERLAY(Ram_SbrDecWorkBuffer2, FIXP_DBL) + + +#endif /* _SBR_RAM_H_ */ diff --git a/libSBRdec/src/sbr_rom.cpp b/libSBRdec/src/sbr_rom.cpp new file mode 100644 index 0000000..75e15e9 --- /dev/null +++ b/libSBRdec/src/sbr_rom.cpp @@ -0,0 +1,1354 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Definition of constant tables + $Revision: 36841 $ + + This module contains most of the constant data that can be stored in ROM. +*/ + +#include "sbr_rom.h" + + + + +/*! + \name StartStopBands + \brief Start and stop subbands of the highband. + + k_o = startMin + offset[bs_start_freq]; + startMin = {3000,4000,5000} * (128/FS_sbr) / FS_sbr < 32Khz, 32Khz <= FS_sbr < 64KHz, 64KHz <= FS_sbr + The stop subband can also be calculated to save memory by defining #CALC_STOP_BAND. +*/ +//@{ +const UCHAR FDK_sbrDecoder_sbr_start_freq_16[16] = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; +const UCHAR FDK_sbrDecoder_sbr_start_freq_22[16] = {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 28, 30}; +const UCHAR FDK_sbrDecoder_sbr_start_freq_24[16] = {11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29, 32}; +const UCHAR FDK_sbrDecoder_sbr_start_freq_32[16] = {10, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29, 32}; +const UCHAR FDK_sbrDecoder_sbr_start_freq_40[16] = {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 26, 28, 30, 32}; +const UCHAR FDK_sbrDecoder_sbr_start_freq_44[16] = { 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 23, 25, 28, 32}; +const UCHAR FDK_sbrDecoder_sbr_start_freq_48[16] = { 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 27, 31}; +//@} + + +/*! + \name Whitening + \brief Coefficients for spectral whitening in the transposer +*/ +//@{ +/*! Assignment of whitening tuning depending on the crossover frequency */ +const USHORT FDK_sbrDecoder_sbr_whFactorsIndex[NUM_WHFACTOR_TABLE_ENTRIES] = { + 0, + 5000, + 6000, + 6500, + 7000, + 7500, + 8000, + 9000, + 10000 +}; + +/*! + \brief Whithening levels tuning table + + With the current tuning, there are some redundant entries: + + \li NUM_WHFACTOR_TABLE_ENTRIES can be reduced by 3, + \li the first coloumn can be eliminated. + +*/ +const FIXP_DBL FDK_sbrDecoder_sbr_whFactorsTable[NUM_WHFACTOR_TABLE_ENTRIES][6] = { + /* OFF_LEVEL, TRANSITION_LEVEL, LOW_LEVEL, MID_LEVEL, HIGH_LEVEL */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* < 5000 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 5000 < 6000 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 6000 < 6500 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 6500 < 7000 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 7000 < 7500 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 7500 < 8000 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 8000 < 9000 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 9000 < 10000 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* > 10000 */ +}; + + +//@} + + +/*! + \name EnvAdj + \brief Constants and tables used for envelope adjustment +*/ +//@{ + +/*! Mantissas of gain limits */ +const FIXP_SGL FDK_sbrDecoder_sbr_limGains_m[4] = +{ + FL2FXCONST_SGL(0.5011932025f), /*!< -3 dB. Gain limit when limiterGains in frameData is 0 */ + FL2FXCONST_SGL(0.5f), /*!< 0 dB. Gain limit when limiterGains in frameData is 1 */ + FL2FXCONST_SGL(0.9976346258f), /*!< +3 dB. Gain limit when limiterGains in frameData is 2 */ + FL2FXCONST_SGL(0.6776263578f) /*!< Inf. Gain limit when limiterGains in frameData is 3 */ +}; + +/*! Exponents of gain limits */ +const UCHAR FDK_sbrDecoder_sbr_limGains_e[4] = +{ + 0, 1, 1, 67 +}; + +/*! Constants for calculating the number of limiter bands */ +const FIXP_SGL FDK_sbrDecoder_sbr_limiterBandsPerOctaveDiv4[4] = +{ + FL2FXCONST_SGL(1.0f / 4.0f), + FL2FXCONST_SGL(1.2f / 4.0f), + FL2FXCONST_SGL(2.0f / 4.0f), + FL2FXCONST_SGL(3.0f / 4.0f) +}; + +/*! Ratio of old gains and noise levels for the first 4 timeslots of an envelope */ +const FIXP_SGL FDK_sbrDecoder_sbr_smoothFilter[4] = { + FL2FXCONST_SGL(0.66666666666666f), + FL2FXCONST_SGL(0.36516383427084f), + FL2FXCONST_SGL(0.14699433520835f), + FL2FXCONST_SGL(0.03183050093751f) +}; + + +/*! Real and imaginary part of random noise which will be modulated + to the desired level. An accuracy of 13 bits is sufficient for these + random numbers. +*/ +const FIXP_SGL FDK_sbrDecoder_sbr_randomPhase[SBR_NF_NO_RANDOM_VAL][2] = { + { FL2FXCONST_SGL(-0.99948153278296f / 8.0), FL2FXCONST_SGL(-0.59483417516607f / 8.0) }, + { FL2FXCONST_SGL( 0.97113454393991f / 8.0), FL2FXCONST_SGL(-0.67528515225647f / 8.0) }, + { FL2FXCONST_SGL( 0.14130051758487f / 8.0), FL2FXCONST_SGL(-0.95090983575689f / 8.0) }, + { FL2FXCONST_SGL(-0.47005496701697f / 8.0), FL2FXCONST_SGL(-0.37340549728647f / 8.0) }, + { FL2FXCONST_SGL( 0.80705063769351f / 8.0), FL2FXCONST_SGL( 0.29653668284408f / 8.0) }, + { FL2FXCONST_SGL(-0.38981478896926f / 8.0), FL2FXCONST_SGL( 0.89572605717087f / 8.0) }, + { FL2FXCONST_SGL(-0.01053049862020f / 8.0), FL2FXCONST_SGL(-0.66959058036166f / 8.0) }, + { FL2FXCONST_SGL(-0.91266367957293f / 8.0), FL2FXCONST_SGL(-0.11522938140034f / 8.0) }, + { FL2FXCONST_SGL( 0.54840422910309f / 8.0), FL2FXCONST_SGL( 0.75221367176302f / 8.0) }, + { FL2FXCONST_SGL( 0.40009252867955f / 8.0), FL2FXCONST_SGL(-0.98929400334421f / 8.0) }, + { FL2FXCONST_SGL(-0.99867974711855f / 8.0), FL2FXCONST_SGL(-0.88147068645358f / 8.0) }, + { FL2FXCONST_SGL(-0.95531076805040f / 8.0), FL2FXCONST_SGL( 0.90908757154593f / 8.0) }, + { FL2FXCONST_SGL(-0.45725933317144f / 8.0), FL2FXCONST_SGL(-0.56716323646760f / 8.0) }, + { FL2FXCONST_SGL(-0.72929675029275f / 8.0), FL2FXCONST_SGL(-0.98008272727324f / 8.0) }, + { FL2FXCONST_SGL( 0.75622801399036f / 8.0), FL2FXCONST_SGL( 0.20950329995549f / 8.0) }, + { FL2FXCONST_SGL( 0.07069442601050f / 8.0), FL2FXCONST_SGL(-0.78247898470706f / 8.0) }, + { FL2FXCONST_SGL( 0.74496252926055f / 8.0), FL2FXCONST_SGL(-0.91169004445807f / 8.0) }, + { FL2FXCONST_SGL(-0.96440182703856f / 8.0), FL2FXCONST_SGL(-0.94739918296622f / 8.0) }, + { FL2FXCONST_SGL( 0.30424629369539f / 8.0), FL2FXCONST_SGL(-0.49438267012479f / 8.0) }, + { FL2FXCONST_SGL( 0.66565033746925f / 8.0), FL2FXCONST_SGL( 0.64652935542491f / 8.0) }, + { FL2FXCONST_SGL( 0.91697008020594f / 8.0), FL2FXCONST_SGL( 0.17514097332009f / 8.0) }, + { FL2FXCONST_SGL(-0.70774918760427f / 8.0), FL2FXCONST_SGL( 0.52548653416543f / 8.0) }, + { FL2FXCONST_SGL(-0.70051415345560f / 8.0), FL2FXCONST_SGL(-0.45340028808763f / 8.0) }, + { FL2FXCONST_SGL(-0.99496513054797f / 8.0), FL2FXCONST_SGL(-0.90071908066973f / 8.0) }, + { FL2FXCONST_SGL( 0.98164490790123f / 8.0), FL2FXCONST_SGL(-0.77463155528697f / 8.0) }, + { FL2FXCONST_SGL(-0.54671580548181f / 8.0), FL2FXCONST_SGL(-0.02570928536004f / 8.0) }, + { FL2FXCONST_SGL(-0.01689629065389f / 8.0), FL2FXCONST_SGL( 0.00287506445732f / 8.0) }, + { FL2FXCONST_SGL(-0.86110349531986f / 8.0), FL2FXCONST_SGL( 0.42548583726477f / 8.0) }, + { FL2FXCONST_SGL(-0.98892980586032f / 8.0), FL2FXCONST_SGL(-0.87881132267556f / 8.0) }, + { FL2FXCONST_SGL( 0.51756627678691f / 8.0), FL2FXCONST_SGL( 0.66926784710139f / 8.0) }, + { FL2FXCONST_SGL(-0.99635026409640f / 8.0), FL2FXCONST_SGL(-0.58107730574765f / 8.0) }, + { FL2FXCONST_SGL(-0.99969370862163f / 8.0), FL2FXCONST_SGL( 0.98369989360250f / 8.0) }, + { FL2FXCONST_SGL( 0.55266258627194f / 8.0), FL2FXCONST_SGL( 0.59449057465591f / 8.0) }, + { FL2FXCONST_SGL( 0.34581177741673f / 8.0), FL2FXCONST_SGL( 0.94879421061866f / 8.0) }, + { FL2FXCONST_SGL( 0.62664209577999f / 8.0), FL2FXCONST_SGL(-0.74402970906471f / 8.0) }, + { FL2FXCONST_SGL(-0.77149701404973f / 8.0), FL2FXCONST_SGL(-0.33883658042801f / 8.0) }, + { FL2FXCONST_SGL(-0.91592244254432f / 8.0), FL2FXCONST_SGL( 0.03687901376713f / 8.0) }, + { FL2FXCONST_SGL(-0.76285492357887f / 8.0), FL2FXCONST_SGL(-0.91371867919124f / 8.0) }, + { FL2FXCONST_SGL( 0.79788337195331f / 8.0), FL2FXCONST_SGL(-0.93180971199849f / 8.0) }, + { FL2FXCONST_SGL( 0.54473080610200f / 8.0), FL2FXCONST_SGL(-0.11919206037186f / 8.0) }, + { FL2FXCONST_SGL(-0.85639281671058f / 8.0), FL2FXCONST_SGL( 0.42429854760451f / 8.0) }, + { FL2FXCONST_SGL(-0.92882402971423f / 8.0), FL2FXCONST_SGL( 0.27871809078609f / 8.0) }, + { FL2FXCONST_SGL(-0.11708371046774f / 8.0), FL2FXCONST_SGL(-0.99800843444966f / 8.0) }, + { FL2FXCONST_SGL( 0.21356749817493f / 8.0), FL2FXCONST_SGL(-0.90716295627033f / 8.0) }, + { FL2FXCONST_SGL(-0.76191692573909f / 8.0), FL2FXCONST_SGL( 0.99768118356265f / 8.0) }, + { FL2FXCONST_SGL( 0.98111043100884f / 8.0), FL2FXCONST_SGL(-0.95854459734407f / 8.0) }, + { FL2FXCONST_SGL(-0.85913269895572f / 8.0), FL2FXCONST_SGL( 0.95766566168880f / 8.0) }, + { FL2FXCONST_SGL(-0.93307242253692f / 8.0), FL2FXCONST_SGL( 0.49431757696466f / 8.0) }, + { FL2FXCONST_SGL( 0.30485754879632f / 8.0), FL2FXCONST_SGL(-0.70540034357529f / 8.0) }, + { FL2FXCONST_SGL( 0.85289650925190f / 8.0), FL2FXCONST_SGL( 0.46766131791044f / 8.0) }, + { FL2FXCONST_SGL( 0.91328082618125f / 8.0), FL2FXCONST_SGL(-0.99839597361769f / 8.0) }, + { FL2FXCONST_SGL(-0.05890199924154f / 8.0), FL2FXCONST_SGL( 0.70741827819497f / 8.0) }, + { FL2FXCONST_SGL( 0.28398686150148f / 8.0), FL2FXCONST_SGL( 0.34633555702188f / 8.0) }, + { FL2FXCONST_SGL( 0.95258164539612f / 8.0), FL2FXCONST_SGL(-0.54893416026939f / 8.0) }, + { FL2FXCONST_SGL(-0.78566324168507f / 8.0), FL2FXCONST_SGL(-0.75568541079691f / 8.0) }, + { FL2FXCONST_SGL(-0.95789495447877f / 8.0), FL2FXCONST_SGL(-0.20423194696966f / 8.0) }, + { FL2FXCONST_SGL( 0.82411158711197f / 8.0), FL2FXCONST_SGL( 0.96654618432562f / 8.0) }, + { FL2FXCONST_SGL(-0.65185446735885f / 8.0), FL2FXCONST_SGL(-0.88734990773289f / 8.0) }, + { FL2FXCONST_SGL(-0.93643603134666f / 8.0), FL2FXCONST_SGL( 0.99870790442385f / 8.0) }, + { FL2FXCONST_SGL( 0.91427159529618f / 8.0), FL2FXCONST_SGL(-0.98290505544444f / 8.0) }, + { FL2FXCONST_SGL(-0.70395684036886f / 8.0), FL2FXCONST_SGL( 0.58796798221039f / 8.0) }, + { FL2FXCONST_SGL( 0.00563771969365f / 8.0), FL2FXCONST_SGL( 0.61768196727244f / 8.0) }, + { FL2FXCONST_SGL( 0.89065051931895f / 8.0), FL2FXCONST_SGL( 0.52783352697585f / 8.0) }, + { FL2FXCONST_SGL(-0.68683707712762f / 8.0), FL2FXCONST_SGL( 0.80806944710339f / 8.0) }, + { FL2FXCONST_SGL( 0.72165342518718f / 8.0), FL2FXCONST_SGL(-0.69259857349564f / 8.0) }, + { FL2FXCONST_SGL(-0.62928247730667f / 8.0), FL2FXCONST_SGL( 0.13627037407335f / 8.0) }, + { FL2FXCONST_SGL( 0.29938434065514f / 8.0), FL2FXCONST_SGL(-0.46051329682246f / 8.0) }, + { FL2FXCONST_SGL(-0.91781958879280f / 8.0), FL2FXCONST_SGL(-0.74012716684186f / 8.0) }, + { FL2FXCONST_SGL( 0.99298717043688f / 8.0), FL2FXCONST_SGL( 0.40816610075661f / 8.0) }, + { FL2FXCONST_SGL( 0.82368298622748f / 8.0), FL2FXCONST_SGL(-0.74036047190173f / 8.0) }, + { FL2FXCONST_SGL(-0.98512833386833f / 8.0), FL2FXCONST_SGL(-0.99972330709594f / 8.0) }, + { FL2FXCONST_SGL(-0.95915368242257f / 8.0), FL2FXCONST_SGL(-0.99237800466040f / 8.0) }, + { FL2FXCONST_SGL(-0.21411126572790f / 8.0), FL2FXCONST_SGL(-0.93424819052545f / 8.0) }, + { FL2FXCONST_SGL(-0.68821476106884f / 8.0), FL2FXCONST_SGL(-0.26892306315457f / 8.0) }, + { FL2FXCONST_SGL( 0.91851997982317f / 8.0), FL2FXCONST_SGL( 0.09358228901785f / 8.0) }, + { FL2FXCONST_SGL(-0.96062769559127f / 8.0), FL2FXCONST_SGL( 0.36099095133739f / 8.0) }, + { FL2FXCONST_SGL( 0.51646184922287f / 8.0), FL2FXCONST_SGL(-0.71373332873917f / 8.0) }, + { FL2FXCONST_SGL( 0.61130721139669f / 8.0), FL2FXCONST_SGL( 0.46950141175917f / 8.0) }, + { FL2FXCONST_SGL( 0.47336129371299f / 8.0), FL2FXCONST_SGL(-0.27333178296162f / 8.0) }, + { FL2FXCONST_SGL( 0.90998308703519f / 8.0), FL2FXCONST_SGL( 0.96715662938132f / 8.0) }, + { FL2FXCONST_SGL( 0.44844799194357f / 8.0), FL2FXCONST_SGL( 0.99211574628306f / 8.0) }, + { FL2FXCONST_SGL( 0.66614891079092f / 8.0), FL2FXCONST_SGL( 0.96590176169121f / 8.0) }, + { FL2FXCONST_SGL( 0.74922239129237f / 8.0), FL2FXCONST_SGL(-0.89879858826087f / 8.0) }, + { FL2FXCONST_SGL(-0.99571588506485f / 8.0), FL2FXCONST_SGL( 0.52785521494349f / 8.0) }, + { FL2FXCONST_SGL( 0.97401082477563f / 8.0), FL2FXCONST_SGL(-0.16855870075190f / 8.0) }, + { FL2FXCONST_SGL( 0.72683747733879f / 8.0), FL2FXCONST_SGL(-0.48060774432251f / 8.0) }, + { FL2FXCONST_SGL( 0.95432193457128f / 8.0), FL2FXCONST_SGL( 0.68849603408441f / 8.0) }, + { FL2FXCONST_SGL(-0.72962208425191f / 8.0), FL2FXCONST_SGL(-0.76608443420917f / 8.0) }, + { FL2FXCONST_SGL(-0.85359479233537f / 8.0), FL2FXCONST_SGL( 0.88738125901579f / 8.0) }, + { FL2FXCONST_SGL(-0.81412430338535f / 8.0), FL2FXCONST_SGL(-0.97480768049637f / 8.0) }, + { FL2FXCONST_SGL(-0.87930772356786f / 8.0), FL2FXCONST_SGL( 0.74748307690436f / 8.0) }, + { FL2FXCONST_SGL(-0.71573331064977f / 8.0), FL2FXCONST_SGL(-0.98570608178923f / 8.0) }, + { FL2FXCONST_SGL( 0.83524300028228f / 8.0), FL2FXCONST_SGL( 0.83702537075163f / 8.0) }, + { FL2FXCONST_SGL(-0.48086065601423f / 8.0), FL2FXCONST_SGL(-0.98848504923531f / 8.0) }, + { FL2FXCONST_SGL( 0.97139128574778f / 8.0), FL2FXCONST_SGL( 0.80093621198236f / 8.0) }, + { FL2FXCONST_SGL( 0.51992825347895f / 8.0), FL2FXCONST_SGL( 0.80247631400510f / 8.0) }, + { FL2FXCONST_SGL(-0.00848591195325f / 8.0), FL2FXCONST_SGL(-0.76670128000486f / 8.0) }, + { FL2FXCONST_SGL(-0.70294374303036f / 8.0), FL2FXCONST_SGL( 0.55359910445577f / 8.0) }, + { FL2FXCONST_SGL(-0.95894428168140f / 8.0), FL2FXCONST_SGL(-0.43265504344783f / 8.0) }, + { FL2FXCONST_SGL( 0.97079252950321f / 8.0), FL2FXCONST_SGL( 0.09325857238682f / 8.0) }, + { FL2FXCONST_SGL(-0.92404293670797f / 8.0), FL2FXCONST_SGL( 0.85507704027855f / 8.0) }, + { FL2FXCONST_SGL(-0.69506469500450f / 8.0), FL2FXCONST_SGL( 0.98633412625459f / 8.0) }, + { FL2FXCONST_SGL( 0.26559203620024f / 8.0), FL2FXCONST_SGL( 0.73314307966524f / 8.0) }, + { FL2FXCONST_SGL( 0.28038443336943f / 8.0), FL2FXCONST_SGL( 0.14537913654427f / 8.0) }, + { FL2FXCONST_SGL(-0.74138124825523f / 8.0), FL2FXCONST_SGL( 0.99310339807762f / 8.0) }, + { FL2FXCONST_SGL(-0.01752795995444f / 8.0), FL2FXCONST_SGL(-0.82616635284178f / 8.0) }, + { FL2FXCONST_SGL(-0.55126773094930f / 8.0), FL2FXCONST_SGL(-0.98898543862153f / 8.0) }, + { FL2FXCONST_SGL( 0.97960898850996f / 8.0), FL2FXCONST_SGL(-0.94021446752851f / 8.0) }, + { FL2FXCONST_SGL(-0.99196309146936f / 8.0), FL2FXCONST_SGL( 0.67019017358456f / 8.0) }, + { FL2FXCONST_SGL(-0.67684928085260f / 8.0), FL2FXCONST_SGL( 0.12631491649378f / 8.0) }, + { FL2FXCONST_SGL( 0.09140039465500f / 8.0), FL2FXCONST_SGL(-0.20537731453108f / 8.0) }, + { FL2FXCONST_SGL(-0.71658965751996f / 8.0), FL2FXCONST_SGL(-0.97788200391224f / 8.0) }, + { FL2FXCONST_SGL( 0.81014640078925f / 8.0), FL2FXCONST_SGL( 0.53722648362443f / 8.0) }, + { FL2FXCONST_SGL( 0.40616991671205f / 8.0), FL2FXCONST_SGL(-0.26469008598449f / 8.0) }, + { FL2FXCONST_SGL(-0.67680188682972f / 8.0), FL2FXCONST_SGL( 0.94502052337695f / 8.0) }, + { FL2FXCONST_SGL( 0.86849774348749f / 8.0), FL2FXCONST_SGL(-0.18333598647899f / 8.0) }, + { FL2FXCONST_SGL(-0.99500381284851f / 8.0), FL2FXCONST_SGL(-0.02634122068550f / 8.0) }, + { FL2FXCONST_SGL( 0.84329189340667f / 8.0), FL2FXCONST_SGL( 0.10406957462213f / 8.0) }, + { FL2FXCONST_SGL(-0.09215968531446f / 8.0), FL2FXCONST_SGL( 0.69540012101253f / 8.0) }, + { FL2FXCONST_SGL( 0.99956173327206f / 8.0), FL2FXCONST_SGL(-0.12358542001404f / 8.0) }, + { FL2FXCONST_SGL(-0.79732779473535f / 8.0), FL2FXCONST_SGL(-0.91582524736159f / 8.0) }, + { FL2FXCONST_SGL( 0.96349973642406f / 8.0), FL2FXCONST_SGL( 0.96640458041000f / 8.0) }, + { FL2FXCONST_SGL(-0.79942778496547f / 8.0), FL2FXCONST_SGL( 0.64323902822857f / 8.0) }, + { FL2FXCONST_SGL(-0.11566039853896f / 8.0), FL2FXCONST_SGL( 0.28587846253726f / 8.0) }, + { FL2FXCONST_SGL(-0.39922954514662f / 8.0), FL2FXCONST_SGL( 0.94129601616966f / 8.0) }, + { FL2FXCONST_SGL( 0.99089197565987f / 8.0), FL2FXCONST_SGL(-0.92062625581587f / 8.0) }, + { FL2FXCONST_SGL( 0.28631285179909f / 8.0), FL2FXCONST_SGL(-0.91035047143603f / 8.0) }, + { FL2FXCONST_SGL(-0.83302725605608f / 8.0), FL2FXCONST_SGL(-0.67330410892084f / 8.0) }, + { FL2FXCONST_SGL( 0.95404443402072f / 8.0), FL2FXCONST_SGL( 0.49162765398743f / 8.0) }, + { FL2FXCONST_SGL(-0.06449863579434f / 8.0), FL2FXCONST_SGL( 0.03250560813135f / 8.0) }, + { FL2FXCONST_SGL(-0.99575054486311f / 8.0), FL2FXCONST_SGL( 0.42389784469507f / 8.0) }, + { FL2FXCONST_SGL(-0.65501142790847f / 8.0), FL2FXCONST_SGL( 0.82546114655624f / 8.0) }, + { FL2FXCONST_SGL(-0.81254441908887f / 8.0), FL2FXCONST_SGL(-0.51627234660629f / 8.0) }, + { FL2FXCONST_SGL(-0.99646369485481f / 8.0), FL2FXCONST_SGL( 0.84490533520752f / 8.0) }, + { FL2FXCONST_SGL( 0.00287840603348f / 8.0), FL2FXCONST_SGL( 0.64768261158166f / 8.0) }, + { FL2FXCONST_SGL( 0.70176989408455f / 8.0), FL2FXCONST_SGL(-0.20453028573322f / 8.0) }, + { FL2FXCONST_SGL( 0.96361882270190f / 8.0), FL2FXCONST_SGL( 0.40706967140989f / 8.0) }, + { FL2FXCONST_SGL(-0.68883758192426f / 8.0), FL2FXCONST_SGL( 0.91338958840772f / 8.0) }, + { FL2FXCONST_SGL(-0.34875585502238f / 8.0), FL2FXCONST_SGL( 0.71472290693300f / 8.0) }, + { FL2FXCONST_SGL( 0.91980081243087f / 8.0), FL2FXCONST_SGL( 0.66507455644919f / 8.0) }, + { FL2FXCONST_SGL(-0.99009048343881f / 8.0), FL2FXCONST_SGL( 0.85868021604848f / 8.0) }, + { FL2FXCONST_SGL( 0.68865791458395f / 8.0), FL2FXCONST_SGL( 0.55660316809678f / 8.0) }, + { FL2FXCONST_SGL(-0.99484402129368f / 8.0), FL2FXCONST_SGL(-0.20052559254934f / 8.0) }, + { FL2FXCONST_SGL( 0.94214511408023f / 8.0), FL2FXCONST_SGL(-0.99696425367461f / 8.0) }, + { FL2FXCONST_SGL(-0.67414626793544f / 8.0), FL2FXCONST_SGL( 0.49548221180078f / 8.0) }, + { FL2FXCONST_SGL(-0.47339353684664f / 8.0), FL2FXCONST_SGL(-0.85904328834047f / 8.0) }, + { FL2FXCONST_SGL( 0.14323651387360f / 8.0), FL2FXCONST_SGL(-0.94145598222488f / 8.0) }, + { FL2FXCONST_SGL(-0.29268293575672f / 8.0), FL2FXCONST_SGL( 0.05759224927952f / 8.0) }, + { FL2FXCONST_SGL( 0.43793861458754f / 8.0), FL2FXCONST_SGL(-0.78904969892724f / 8.0) }, + { FL2FXCONST_SGL(-0.36345126374441f / 8.0), FL2FXCONST_SGL( 0.64874435357162f / 8.0) }, + { FL2FXCONST_SGL(-0.08750604656825f / 8.0), FL2FXCONST_SGL( 0.97686944362527f / 8.0) }, + { FL2FXCONST_SGL(-0.96495267812511f / 8.0), FL2FXCONST_SGL(-0.53960305946511f / 8.0) }, + { FL2FXCONST_SGL( 0.55526940659947f / 8.0), FL2FXCONST_SGL( 0.78891523734774f / 8.0) }, + { FL2FXCONST_SGL( 0.73538215752630f / 8.0), FL2FXCONST_SGL( 0.96452072373404f / 8.0) }, + { FL2FXCONST_SGL(-0.30889773919437f / 8.0), FL2FXCONST_SGL(-0.80664389776860f / 8.0) }, + { FL2FXCONST_SGL( 0.03574995626194f / 8.0), FL2FXCONST_SGL(-0.97325616900959f / 8.0) }, + { FL2FXCONST_SGL( 0.98720684660488f / 8.0), FL2FXCONST_SGL( 0.48409133691962f / 8.0) }, + { FL2FXCONST_SGL(-0.81689296271203f / 8.0), FL2FXCONST_SGL(-0.90827703628298f / 8.0) }, + { FL2FXCONST_SGL( 0.67866860118215f / 8.0), FL2FXCONST_SGL( 0.81284503870856f / 8.0) }, + { FL2FXCONST_SGL(-0.15808569732583f / 8.0), FL2FXCONST_SGL( 0.85279555024382f / 8.0) }, + { FL2FXCONST_SGL( 0.80723395114371f / 8.0), FL2FXCONST_SGL(-0.24717418514605f / 8.0) }, + { FL2FXCONST_SGL( 0.47788757329038f / 8.0), FL2FXCONST_SGL(-0.46333147839295f / 8.0) }, + { FL2FXCONST_SGL( 0.96367554763201f / 8.0), FL2FXCONST_SGL( 0.38486749303242f / 8.0) }, + { FL2FXCONST_SGL(-0.99143875716818f / 8.0), FL2FXCONST_SGL(-0.24945277239809f / 8.0) }, + { FL2FXCONST_SGL( 0.83081876925833f / 8.0), FL2FXCONST_SGL(-0.94780851414763f / 8.0) }, + { FL2FXCONST_SGL(-0.58753191905341f / 8.0), FL2FXCONST_SGL( 0.01290772389163f / 8.0) }, + { FL2FXCONST_SGL( 0.95538108220960f / 8.0), FL2FXCONST_SGL(-0.85557052096538f / 8.0) }, + { FL2FXCONST_SGL(-0.96490920476211f / 8.0), FL2FXCONST_SGL(-0.64020970923102f / 8.0) }, + { FL2FXCONST_SGL(-0.97327101028521f / 8.0), FL2FXCONST_SGL( 0.12378128133110f / 8.0) }, + { FL2FXCONST_SGL( 0.91400366022124f / 8.0), FL2FXCONST_SGL( 0.57972471346930f / 8.0) }, + { FL2FXCONST_SGL(-0.99925837363824f / 8.0), FL2FXCONST_SGL( 0.71084847864067f / 8.0) }, + { FL2FXCONST_SGL(-0.86875903507313f / 8.0), FL2FXCONST_SGL(-0.20291699203564f / 8.0) }, + { FL2FXCONST_SGL(-0.26240034795124f / 8.0), FL2FXCONST_SGL(-0.68264554369108f / 8.0) }, + { FL2FXCONST_SGL(-0.24664412953388f / 8.0), FL2FXCONST_SGL(-0.87642273115183f / 8.0) }, + { FL2FXCONST_SGL( 0.02416275806869f / 8.0), FL2FXCONST_SGL( 0.27192914288905f / 8.0) }, + { FL2FXCONST_SGL( 0.82068619590515f / 8.0), FL2FXCONST_SGL(-0.85087787994476f / 8.0) }, + { FL2FXCONST_SGL( 0.88547373760759f / 8.0), FL2FXCONST_SGL(-0.89636802901469f / 8.0) }, + { FL2FXCONST_SGL(-0.18173078152226f / 8.0), FL2FXCONST_SGL(-0.26152145156800f / 8.0) }, + { FL2FXCONST_SGL( 0.09355476558534f / 8.0), FL2FXCONST_SGL( 0.54845123045604f / 8.0) }, + { FL2FXCONST_SGL(-0.54668414224090f / 8.0), FL2FXCONST_SGL( 0.95980774020221f / 8.0) }, + { FL2FXCONST_SGL( 0.37050990604091f / 8.0), FL2FXCONST_SGL(-0.59910140383171f / 8.0) }, + { FL2FXCONST_SGL(-0.70373594262891f / 8.0), FL2FXCONST_SGL( 0.91227665827081f / 8.0) }, + { FL2FXCONST_SGL(-0.34600785879594f / 8.0), FL2FXCONST_SGL(-0.99441426144200f / 8.0) }, + { FL2FXCONST_SGL(-0.68774481731008f / 8.0), FL2FXCONST_SGL(-0.30238837956299f / 8.0) }, + { FL2FXCONST_SGL(-0.26843291251234f / 8.0), FL2FXCONST_SGL( 0.83115668004362f / 8.0) }, + { FL2FXCONST_SGL( 0.49072334613242f / 8.0), FL2FXCONST_SGL(-0.45359708737775f / 8.0) }, + { FL2FXCONST_SGL( 0.38975993093975f / 8.0), FL2FXCONST_SGL( 0.95515358099121f / 8.0) }, + { FL2FXCONST_SGL(-0.97757125224150f / 8.0), FL2FXCONST_SGL( 0.05305894580606f / 8.0) }, + { FL2FXCONST_SGL(-0.17325552859616f / 8.0), FL2FXCONST_SGL(-0.92770672250494f / 8.0) }, + { FL2FXCONST_SGL( 0.99948035025744f / 8.0), FL2FXCONST_SGL( 0.58285545563426f / 8.0) }, + { FL2FXCONST_SGL(-0.64946246527458f / 8.0), FL2FXCONST_SGL( 0.68645507104960f / 8.0) }, + { FL2FXCONST_SGL(-0.12016920576437f / 8.0), FL2FXCONST_SGL(-0.57147322153312f / 8.0) }, + { FL2FXCONST_SGL(-0.58947456517751f / 8.0), FL2FXCONST_SGL(-0.34847132454388f / 8.0) }, + { FL2FXCONST_SGL(-0.41815140454465f / 8.0), FL2FXCONST_SGL( 0.16276422358861f / 8.0) }, + { FL2FXCONST_SGL( 0.99885650204884f / 8.0), FL2FXCONST_SGL( 0.11136095490444f / 8.0) }, + { FL2FXCONST_SGL(-0.56649614128386f / 8.0), FL2FXCONST_SGL(-0.90494866361587f / 8.0) }, + { FL2FXCONST_SGL( 0.94138021032330f / 8.0), FL2FXCONST_SGL( 0.35281916733018f / 8.0) }, + { FL2FXCONST_SGL(-0.75725076534641f / 8.0), FL2FXCONST_SGL( 0.53650549640587f / 8.0) }, + { FL2FXCONST_SGL( 0.20541973692630f / 8.0), FL2FXCONST_SGL(-0.94435144369918f / 8.0) }, + { FL2FXCONST_SGL( 0.99980371023351f / 8.0), FL2FXCONST_SGL( 0.79835913565599f / 8.0) }, + { FL2FXCONST_SGL( 0.29078277605775f / 8.0), FL2FXCONST_SGL( 0.35393777921520f / 8.0) }, + { FL2FXCONST_SGL(-0.62858772103030f / 8.0), FL2FXCONST_SGL( 0.38765693387102f / 8.0) }, + { FL2FXCONST_SGL( 0.43440904467688f / 8.0), FL2FXCONST_SGL(-0.98546330463232f / 8.0) }, + { FL2FXCONST_SGL(-0.98298583762390f / 8.0), FL2FXCONST_SGL( 0.21021524625209f / 8.0) }, + { FL2FXCONST_SGL( 0.19513029146934f / 8.0), FL2FXCONST_SGL(-0.94239832251867f / 8.0) }, + { FL2FXCONST_SGL(-0.95476662400101f / 8.0), FL2FXCONST_SGL( 0.98364554179143f / 8.0) }, + { FL2FXCONST_SGL( 0.93379635304810f / 8.0), FL2FXCONST_SGL(-0.70881994583682f / 8.0) }, + { FL2FXCONST_SGL(-0.85235410573336f / 8.0), FL2FXCONST_SGL(-0.08342347966410f / 8.0) }, + { FL2FXCONST_SGL(-0.86425093011245f / 8.0), FL2FXCONST_SGL(-0.45795025029466f / 8.0) }, + { FL2FXCONST_SGL( 0.38879779059045f / 8.0), FL2FXCONST_SGL( 0.97274429344593f / 8.0) }, + { FL2FXCONST_SGL( 0.92045124735495f / 8.0), FL2FXCONST_SGL(-0.62433652524220f / 8.0) }, + { FL2FXCONST_SGL( 0.89162532251878f / 8.0), FL2FXCONST_SGL( 0.54950955570563f / 8.0) }, + { FL2FXCONST_SGL(-0.36834336949252f / 8.0), FL2FXCONST_SGL( 0.96458298020975f / 8.0) }, + { FL2FXCONST_SGL( 0.93891760988045f / 8.0), FL2FXCONST_SGL(-0.89968353740388f / 8.0) }, + { FL2FXCONST_SGL( 0.99267657565094f / 8.0), FL2FXCONST_SGL(-0.03757034316958f / 8.0) }, + { FL2FXCONST_SGL(-0.94063471614176f / 8.0), FL2FXCONST_SGL( 0.41332338538963f / 8.0) }, + { FL2FXCONST_SGL( 0.99740224117019f / 8.0), FL2FXCONST_SGL(-0.16830494996370f / 8.0) }, + { FL2FXCONST_SGL(-0.35899413170555f / 8.0), FL2FXCONST_SGL(-0.46633226649613f / 8.0) }, + { FL2FXCONST_SGL( 0.05237237274947f / 8.0), FL2FXCONST_SGL(-0.25640361602661f / 8.0) }, + { FL2FXCONST_SGL( 0.36703583957424f / 8.0), FL2FXCONST_SGL(-0.38653265641875f / 8.0) }, + { FL2FXCONST_SGL( 0.91653180367913f / 8.0), FL2FXCONST_SGL(-0.30587628726597f / 8.0) }, + { FL2FXCONST_SGL( 0.69000803499316f / 8.0), FL2FXCONST_SGL( 0.90952171386132f / 8.0) }, + { FL2FXCONST_SGL(-0.38658751133527f / 8.0), FL2FXCONST_SGL( 0.99501571208985f / 8.0) }, + { FL2FXCONST_SGL(-0.29250814029851f / 8.0), FL2FXCONST_SGL( 0.37444994344615f / 8.0) }, + { FL2FXCONST_SGL(-0.60182204677608f / 8.0), FL2FXCONST_SGL( 0.86779651036123f / 8.0) }, + { FL2FXCONST_SGL(-0.97418588163217f / 8.0), FL2FXCONST_SGL( 0.96468523666475f / 8.0) }, + { FL2FXCONST_SGL( 0.88461574003963f / 8.0), FL2FXCONST_SGL( 0.57508405276414f / 8.0) }, + { FL2FXCONST_SGL( 0.05198933055162f / 8.0), FL2FXCONST_SGL( 0.21269661669964f / 8.0) }, + { FL2FXCONST_SGL(-0.53499621979720f / 8.0), FL2FXCONST_SGL( 0.97241553731237f / 8.0) }, + { FL2FXCONST_SGL(-0.49429560226497f / 8.0), FL2FXCONST_SGL( 0.98183865291903f / 8.0) }, + { FL2FXCONST_SGL(-0.98935142339139f / 8.0), FL2FXCONST_SGL(-0.40249159006933f / 8.0) }, + { FL2FXCONST_SGL(-0.98081380091130f / 8.0), FL2FXCONST_SGL(-0.72856895534041f / 8.0) }, + { FL2FXCONST_SGL(-0.27338148835532f / 8.0), FL2FXCONST_SGL( 0.99950922447209f / 8.0) }, + { FL2FXCONST_SGL( 0.06310802338302f / 8.0), FL2FXCONST_SGL(-0.54539587529618f / 8.0) }, + { FL2FXCONST_SGL(-0.20461677199539f / 8.0), FL2FXCONST_SGL(-0.14209977628489f / 8.0) }, + { FL2FXCONST_SGL( 0.66223843141647f / 8.0), FL2FXCONST_SGL( 0.72528579940326f / 8.0) }, + { FL2FXCONST_SGL(-0.84764345483665f / 8.0), FL2FXCONST_SGL( 0.02372316801261f / 8.0) }, + { FL2FXCONST_SGL(-0.89039863483811f / 8.0), FL2FXCONST_SGL( 0.88866581484602f / 8.0) }, + { FL2FXCONST_SGL( 0.95903308477986f / 8.0), FL2FXCONST_SGL( 0.76744927173873f / 8.0) }, + { FL2FXCONST_SGL( 0.73504123909879f / 8.0), FL2FXCONST_SGL(-0.03747203173192f / 8.0) }, + { FL2FXCONST_SGL(-0.31744434966056f / 8.0), FL2FXCONST_SGL(-0.36834111883652f / 8.0) }, + { FL2FXCONST_SGL(-0.34110827591623f / 8.0), FL2FXCONST_SGL( 0.40211222807691f / 8.0) }, + { FL2FXCONST_SGL( 0.47803883714199f / 8.0), FL2FXCONST_SGL(-0.39423219786288f / 8.0) }, + { FL2FXCONST_SGL( 0.98299195879514f / 8.0), FL2FXCONST_SGL( 0.01989791390047f / 8.0) }, + { FL2FXCONST_SGL(-0.30963073129751f / 8.0), FL2FXCONST_SGL(-0.18076720599336f / 8.0) }, + { FL2FXCONST_SGL( 0.99992588229018f / 8.0), FL2FXCONST_SGL(-0.26281872094289f / 8.0) }, + { FL2FXCONST_SGL(-0.93149731080767f / 8.0), FL2FXCONST_SGL(-0.98313162570490f / 8.0) }, + { FL2FXCONST_SGL( 0.99923472302773f / 8.0), FL2FXCONST_SGL(-0.80142993767554f / 8.0) }, + { FL2FXCONST_SGL(-0.26024169633417f / 8.0), FL2FXCONST_SGL(-0.75999759855752f / 8.0) }, + { FL2FXCONST_SGL(-0.35712514743563f / 8.0), FL2FXCONST_SGL( 0.19298963768574f / 8.0) }, + { FL2FXCONST_SGL(-0.99899084509530f / 8.0), FL2FXCONST_SGL( 0.74645156992493f / 8.0) }, + { FL2FXCONST_SGL( 0.86557171579452f / 8.0), FL2FXCONST_SGL( 0.55593866696299f / 8.0) }, + { FL2FXCONST_SGL( 0.33408042438752f / 8.0), FL2FXCONST_SGL( 0.86185953874709f / 8.0) }, + { FL2FXCONST_SGL( 0.99010736374716f / 8.0), FL2FXCONST_SGL( 0.04602397576623f / 8.0) }, + { FL2FXCONST_SGL(-0.66694269691195f / 8.0), FL2FXCONST_SGL(-0.91643611810148f / 8.0) }, + { FL2FXCONST_SGL( 0.64016792079480f / 8.0), FL2FXCONST_SGL( 0.15649530836856f / 8.0) }, + { FL2FXCONST_SGL( 0.99570534804836f / 8.0), FL2FXCONST_SGL( 0.45844586038111f / 8.0) }, + { FL2FXCONST_SGL(-0.63431466947340f / 8.0), FL2FXCONST_SGL( 0.21079116459234f / 8.0) }, + { FL2FXCONST_SGL(-0.07706847005931f / 8.0), FL2FXCONST_SGL(-0.89581437101329f / 8.0) }, + { FL2FXCONST_SGL( 0.98590090577724f / 8.0), FL2FXCONST_SGL( 0.88241721133981f / 8.0) }, + { FL2FXCONST_SGL( 0.80099335254678f / 8.0), FL2FXCONST_SGL(-0.36851896710853f / 8.0) }, + { FL2FXCONST_SGL( 0.78368131392666f / 8.0), FL2FXCONST_SGL( 0.45506999802597f / 8.0) }, + { FL2FXCONST_SGL( 0.08707806671691f / 8.0), FL2FXCONST_SGL( 0.80938994918745f / 8.0) }, + { FL2FXCONST_SGL(-0.86811883080712f / 8.0), FL2FXCONST_SGL( 0.39347308654705f / 8.0) }, + { FL2FXCONST_SGL(-0.39466529740375f / 8.0), FL2FXCONST_SGL(-0.66809432114456f / 8.0) }, + { FL2FXCONST_SGL( 0.97875325649683f / 8.0), FL2FXCONST_SGL(-0.72467840967746f / 8.0) }, + { FL2FXCONST_SGL(-0.95038560288864f / 8.0), FL2FXCONST_SGL( 0.89563219587625f / 8.0) }, + { FL2FXCONST_SGL( 0.17005239424212f / 8.0), FL2FXCONST_SGL( 0.54683053962658f / 8.0) }, + { FL2FXCONST_SGL(-0.76910792026848f / 8.0), FL2FXCONST_SGL(-0.96226617549298f / 8.0) }, + { FL2FXCONST_SGL( 0.99743281016846f / 8.0), FL2FXCONST_SGL( 0.42697157037567f / 8.0) }, + { FL2FXCONST_SGL( 0.95437383549973f / 8.0), FL2FXCONST_SGL( 0.97002324109952f / 8.0) }, + { FL2FXCONST_SGL( 0.99578905365569f / 8.0), FL2FXCONST_SGL(-0.54106826257356f / 8.0) }, + { FL2FXCONST_SGL( 0.28058259829990f / 8.0), FL2FXCONST_SGL(-0.85361420634036f / 8.0) }, + { FL2FXCONST_SGL( 0.85256524470573f / 8.0), FL2FXCONST_SGL(-0.64567607735589f / 8.0) }, + { FL2FXCONST_SGL(-0.50608540105128f / 8.0), FL2FXCONST_SGL(-0.65846015480300f / 8.0) }, + { FL2FXCONST_SGL(-0.97210735183243f / 8.0), FL2FXCONST_SGL(-0.23095213067791f / 8.0) }, + { FL2FXCONST_SGL( 0.95424048234441f / 8.0), FL2FXCONST_SGL(-0.99240147091219f / 8.0) }, + { FL2FXCONST_SGL(-0.96926570524023f / 8.0), FL2FXCONST_SGL( 0.73775654896574f / 8.0) }, + { FL2FXCONST_SGL( 0.30872163214726f / 8.0), FL2FXCONST_SGL( 0.41514960556126f / 8.0) }, + { FL2FXCONST_SGL(-0.24523839572639f / 8.0), FL2FXCONST_SGL( 0.63206633394807f / 8.0) }, + { FL2FXCONST_SGL(-0.33813265086024f / 8.0), FL2FXCONST_SGL(-0.38661779441897f / 8.0) }, + { FL2FXCONST_SGL(-0.05826828420146f / 8.0), FL2FXCONST_SGL(-0.06940774188029f / 8.0) }, + { FL2FXCONST_SGL(-0.22898461455054f / 8.0), FL2FXCONST_SGL( 0.97054853316316f / 8.0) }, + { FL2FXCONST_SGL(-0.18509915019881f / 8.0), FL2FXCONST_SGL( 0.47565762892084f / 8.0) }, + { FL2FXCONST_SGL(-0.10488238045009f / 8.0), FL2FXCONST_SGL(-0.87769947402394f / 8.0) }, + { FL2FXCONST_SGL(-0.71886586182037f / 8.0), FL2FXCONST_SGL( 0.78030982480538f / 8.0) }, + { FL2FXCONST_SGL( 0.99793873738654f / 8.0), FL2FXCONST_SGL( 0.90041310491497f / 8.0) }, + { FL2FXCONST_SGL( 0.57563307626120f / 8.0), FL2FXCONST_SGL(-0.91034337352097f / 8.0) }, + { FL2FXCONST_SGL( 0.28909646383717f / 8.0), FL2FXCONST_SGL( 0.96307783970534f / 8.0) }, + { FL2FXCONST_SGL( 0.42188998312520f / 8.0), FL2FXCONST_SGL( 0.48148651230437f / 8.0) }, + { FL2FXCONST_SGL( 0.93335049681047f / 8.0), FL2FXCONST_SGL(-0.43537023883588f / 8.0) }, + { FL2FXCONST_SGL(-0.97087374418267f / 8.0), FL2FXCONST_SGL( 0.86636445711364f / 8.0) }, + { FL2FXCONST_SGL( 0.36722871286923f / 8.0), FL2FXCONST_SGL( 0.65291654172961f / 8.0) }, + { FL2FXCONST_SGL(-0.81093025665696f / 8.0), FL2FXCONST_SGL( 0.08778370229363f / 8.0) }, + { FL2FXCONST_SGL(-0.26240603062237f / 8.0), FL2FXCONST_SGL(-0.92774095379098f / 8.0) }, + { FL2FXCONST_SGL( 0.83996497984604f / 8.0), FL2FXCONST_SGL( 0.55839849139647f / 8.0) }, + { FL2FXCONST_SGL(-0.99909615720225f / 8.0), FL2FXCONST_SGL(-0.96024605713970f / 8.0) }, + { FL2FXCONST_SGL( 0.74649464155061f / 8.0), FL2FXCONST_SGL( 0.12144893606462f / 8.0) }, + { FL2FXCONST_SGL(-0.74774595569805f / 8.0), FL2FXCONST_SGL(-0.26898062008959f / 8.0) }, + { FL2FXCONST_SGL( 0.95781667469567f / 8.0), FL2FXCONST_SGL(-0.79047927052628f / 8.0) }, + { FL2FXCONST_SGL( 0.95472308713099f / 8.0), FL2FXCONST_SGL(-0.08588776019550f / 8.0) }, + { FL2FXCONST_SGL( 0.48708332746299f / 8.0), FL2FXCONST_SGL( 0.99999041579432f / 8.0) }, + { FL2FXCONST_SGL( 0.46332038247497f / 8.0), FL2FXCONST_SGL( 0.10964126185063f / 8.0) }, + { FL2FXCONST_SGL(-0.76497004940162f / 8.0), FL2FXCONST_SGL( 0.89210929242238f / 8.0) }, + { FL2FXCONST_SGL( 0.57397389364339f / 8.0), FL2FXCONST_SGL( 0.35289703373760f / 8.0) }, + { FL2FXCONST_SGL( 0.75374316974495f / 8.0), FL2FXCONST_SGL( 0.96705214651335f / 8.0) }, + { FL2FXCONST_SGL(-0.59174397685714f / 8.0), FL2FXCONST_SGL(-0.89405370422752f / 8.0) }, + { FL2FXCONST_SGL( 0.75087906691890f / 8.0), FL2FXCONST_SGL(-0.29612672982396f / 8.0) }, + { FL2FXCONST_SGL(-0.98607857336230f / 8.0), FL2FXCONST_SGL( 0.25034911730023f / 8.0) }, + { FL2FXCONST_SGL(-0.40761056640505f / 8.0), FL2FXCONST_SGL(-0.90045573444695f / 8.0) }, + { FL2FXCONST_SGL( 0.66929266740477f / 8.0), FL2FXCONST_SGL( 0.98629493401748f / 8.0) }, + { FL2FXCONST_SGL(-0.97463695257310f / 8.0), FL2FXCONST_SGL(-0.00190223301301f / 8.0) }, + { FL2FXCONST_SGL( 0.90145509409859f / 8.0), FL2FXCONST_SGL( 0.99781390365446f / 8.0) }, + { FL2FXCONST_SGL(-0.87259289048043f / 8.0), FL2FXCONST_SGL( 0.99233587353666f / 8.0) }, + { FL2FXCONST_SGL(-0.91529461447692f / 8.0), FL2FXCONST_SGL(-0.15698707534206f / 8.0) }, + { FL2FXCONST_SGL(-0.03305738840705f / 8.0), FL2FXCONST_SGL(-0.37205262859764f / 8.0) }, + { FL2FXCONST_SGL( 0.07223051368337f / 8.0), FL2FXCONST_SGL(-0.88805001733626f / 8.0) }, + { FL2FXCONST_SGL( 0.99498012188353f / 8.0), FL2FXCONST_SGL( 0.97094358113387f / 8.0) }, + { FL2FXCONST_SGL(-0.74904939500519f / 8.0), FL2FXCONST_SGL( 0.99985483641521f / 8.0) }, + { FL2FXCONST_SGL( 0.04585228574211f / 8.0), FL2FXCONST_SGL( 0.99812337444082f / 8.0) }, + { FL2FXCONST_SGL(-0.89054954257993f / 8.0), FL2FXCONST_SGL(-0.31791913188064f / 8.0) }, + { FL2FXCONST_SGL(-0.83782144651251f / 8.0), FL2FXCONST_SGL( 0.97637632547466f / 8.0) }, + { FL2FXCONST_SGL( 0.33454804933804f / 8.0), FL2FXCONST_SGL(-0.86231516800408f / 8.0) }, + { FL2FXCONST_SGL(-0.99707579362824f / 8.0), FL2FXCONST_SGL( 0.93237990079441f / 8.0) }, + { FL2FXCONST_SGL(-0.22827527843994f / 8.0), FL2FXCONST_SGL( 0.18874759397997f / 8.0) }, + { FL2FXCONST_SGL( 0.67248046289143f / 8.0), FL2FXCONST_SGL(-0.03646211390569f / 8.0) }, + { FL2FXCONST_SGL(-0.05146538187944f / 8.0), FL2FXCONST_SGL(-0.92599700120679f / 8.0) }, + { FL2FXCONST_SGL( 0.99947295749905f / 8.0), FL2FXCONST_SGL( 0.93625229707912f / 8.0) }, + { FL2FXCONST_SGL( 0.66951124390363f / 8.0), FL2FXCONST_SGL( 0.98905825623893f / 8.0) }, + { FL2FXCONST_SGL(-0.99602956559179f / 8.0), FL2FXCONST_SGL(-0.44654715757688f / 8.0) }, + { FL2FXCONST_SGL( 0.82104905483590f / 8.0), FL2FXCONST_SGL( 0.99540741724928f / 8.0) }, + { FL2FXCONST_SGL( 0.99186510988782f / 8.0), FL2FXCONST_SGL( 0.72023001312947f / 8.0) }, + { FL2FXCONST_SGL(-0.65284592392918f / 8.0), FL2FXCONST_SGL( 0.52186723253637f / 8.0) }, + { FL2FXCONST_SGL( 0.93885443798188f / 8.0), FL2FXCONST_SGL(-0.74895312615259f / 8.0) }, + { FL2FXCONST_SGL( 0.96735248738388f / 8.0), FL2FXCONST_SGL( 0.90891816978629f / 8.0) }, + { FL2FXCONST_SGL(-0.22225968841114f / 8.0), FL2FXCONST_SGL( 0.57124029781228f / 8.0) }, + { FL2FXCONST_SGL(-0.44132783753414f / 8.0), FL2FXCONST_SGL(-0.92688840659280f / 8.0) }, + { FL2FXCONST_SGL(-0.85694974219574f / 8.0), FL2FXCONST_SGL( 0.88844532719844f / 8.0) }, + { FL2FXCONST_SGL( 0.91783042091762f / 8.0), FL2FXCONST_SGL(-0.46356892383970f / 8.0) }, + { FL2FXCONST_SGL( 0.72556974415690f / 8.0), FL2FXCONST_SGL(-0.99899555770747f / 8.0) }, + { FL2FXCONST_SGL(-0.99711581834508f / 8.0), FL2FXCONST_SGL( 0.58211560180426f / 8.0) }, + { FL2FXCONST_SGL( 0.77638976371966f / 8.0), FL2FXCONST_SGL( 0.94321834873819f / 8.0) }, + { FL2FXCONST_SGL( 0.07717324253925f / 8.0), FL2FXCONST_SGL( 0.58638399856595f / 8.0) }, + { FL2FXCONST_SGL(-0.56049829194163f / 8.0), FL2FXCONST_SGL( 0.82522301569036f / 8.0) }, + { FL2FXCONST_SGL( 0.98398893639988f / 8.0), FL2FXCONST_SGL( 0.39467440420569f / 8.0) }, + { FL2FXCONST_SGL( 0.47546946844938f / 8.0), FL2FXCONST_SGL( 0.68613044836811f / 8.0) }, + { FL2FXCONST_SGL( 0.65675089314631f / 8.0), FL2FXCONST_SGL( 0.18331637134880f / 8.0) }, + { FL2FXCONST_SGL( 0.03273375457980f / 8.0), FL2FXCONST_SGL(-0.74933109564108f / 8.0) }, + { FL2FXCONST_SGL(-0.38684144784738f / 8.0), FL2FXCONST_SGL( 0.51337349030406f / 8.0) }, + { FL2FXCONST_SGL(-0.97346267944545f / 8.0), FL2FXCONST_SGL(-0.96549364384098f / 8.0) }, + { FL2FXCONST_SGL(-0.53282156061942f / 8.0), FL2FXCONST_SGL(-0.91423265091354f / 8.0) }, + { FL2FXCONST_SGL( 0.99817310731176f / 8.0), FL2FXCONST_SGL( 0.61133572482148f / 8.0) }, + { FL2FXCONST_SGL(-0.50254500772635f / 8.0), FL2FXCONST_SGL(-0.88829338134294f / 8.0) }, + { FL2FXCONST_SGL( 0.01995873238855f / 8.0), FL2FXCONST_SGL( 0.85223515096765f / 8.0) }, + { FL2FXCONST_SGL( 0.99930381973804f / 8.0), FL2FXCONST_SGL( 0.94578896296649f / 8.0) }, + { FL2FXCONST_SGL( 0.82907767600783f / 8.0), FL2FXCONST_SGL(-0.06323442598128f / 8.0) }, + { FL2FXCONST_SGL(-0.58660709669728f / 8.0), FL2FXCONST_SGL( 0.96840773806582f / 8.0) }, + { FL2FXCONST_SGL(-0.17573736667267f / 8.0), FL2FXCONST_SGL(-0.48166920859485f / 8.0) }, + { FL2FXCONST_SGL( 0.83434292401346f / 8.0), FL2FXCONST_SGL(-0.13023450646997f / 8.0) }, + { FL2FXCONST_SGL( 0.05946491307025f / 8.0), FL2FXCONST_SGL( 0.20511047074866f / 8.0) }, + { FL2FXCONST_SGL( 0.81505484574602f / 8.0), FL2FXCONST_SGL(-0.94685947861369f / 8.0) }, + { FL2FXCONST_SGL(-0.44976380954860f / 8.0), FL2FXCONST_SGL( 0.40894572671545f / 8.0) }, + { FL2FXCONST_SGL(-0.89746474625671f / 8.0), FL2FXCONST_SGL( 0.99846578838537f / 8.0) }, + { FL2FXCONST_SGL( 0.39677256130792f / 8.0), FL2FXCONST_SGL(-0.74854668609359f / 8.0) }, + { FL2FXCONST_SGL(-0.07588948563079f / 8.0), FL2FXCONST_SGL( 0.74096214084170f / 8.0) }, + { FL2FXCONST_SGL( 0.76343198951445f / 8.0), FL2FXCONST_SGL( 0.41746629422634f / 8.0) }, + { FL2FXCONST_SGL(-0.74490104699626f / 8.0), FL2FXCONST_SGL( 0.94725911744610f / 8.0) }, + { FL2FXCONST_SGL( 0.64880119792759f / 8.0), FL2FXCONST_SGL( 0.41336660830571f / 8.0) }, + { FL2FXCONST_SGL( 0.62319537462542f / 8.0), FL2FXCONST_SGL(-0.93098313552599f / 8.0) }, + { FL2FXCONST_SGL( 0.42215817594807f / 8.0), FL2FXCONST_SGL(-0.07712787385208f / 8.0) }, + { FL2FXCONST_SGL( 0.02704554141885f / 8.0), FL2FXCONST_SGL(-0.05417518053666f / 8.0) }, + { FL2FXCONST_SGL( 0.80001773566818f / 8.0), FL2FXCONST_SGL( 0.91542195141039f / 8.0) }, + { FL2FXCONST_SGL(-0.79351832348816f / 8.0), FL2FXCONST_SGL(-0.36208897989136f / 8.0) }, + { FL2FXCONST_SGL( 0.63872359151636f / 8.0), FL2FXCONST_SGL( 0.08128252493444f / 8.0) }, + { FL2FXCONST_SGL( 0.52890520960295f / 8.0), FL2FXCONST_SGL( 0.60048872455592f / 8.0) }, + { FL2FXCONST_SGL( 0.74238552914587f / 8.0), FL2FXCONST_SGL( 0.04491915291044f / 8.0) }, + { FL2FXCONST_SGL( 0.99096131449250f / 8.0), FL2FXCONST_SGL(-0.19451182854402f / 8.0) }, + { FL2FXCONST_SGL(-0.80412329643109f / 8.0), FL2FXCONST_SGL(-0.88513818199457f / 8.0) }, + { FL2FXCONST_SGL(-0.64612616129736f / 8.0), FL2FXCONST_SGL( 0.72198674804544f / 8.0) }, + { FL2FXCONST_SGL( 0.11657770663191f / 8.0), FL2FXCONST_SGL(-0.83662833815041f / 8.0) }, + { FL2FXCONST_SGL(-0.95053182488101f / 8.0), FL2FXCONST_SGL(-0.96939905138082f / 8.0) }, + { FL2FXCONST_SGL(-0.62228872928622f / 8.0), FL2FXCONST_SGL( 0.82767262846661f / 8.0) }, + { FL2FXCONST_SGL( 0.03004475787316f / 8.0), FL2FXCONST_SGL(-0.99738896333384f / 8.0) }, + { FL2FXCONST_SGL(-0.97987214341034f / 8.0), FL2FXCONST_SGL( 0.36526129686425f / 8.0) }, + { FL2FXCONST_SGL(-0.99986980746200f / 8.0), FL2FXCONST_SGL(-0.36021610299715f / 8.0) }, + { FL2FXCONST_SGL( 0.89110648599879f / 8.0), FL2FXCONST_SGL(-0.97894250343044f / 8.0) }, + { FL2FXCONST_SGL( 0.10407960510582f / 8.0), FL2FXCONST_SGL( 0.77357793811619f / 8.0) }, + { FL2FXCONST_SGL( 0.95964737821728f / 8.0), FL2FXCONST_SGL(-0.35435818285502f / 8.0) }, + { FL2FXCONST_SGL( 0.50843233159162f / 8.0), FL2FXCONST_SGL( 0.96107691266205f / 8.0) }, + { FL2FXCONST_SGL( 0.17006334670615f / 8.0), FL2FXCONST_SGL(-0.76854025314829f / 8.0) }, + { FL2FXCONST_SGL( 0.25872675063360f / 8.0), FL2FXCONST_SGL( 0.99893303933816f / 8.0) }, + { FL2FXCONST_SGL(-0.01115998681937f / 8.0), FL2FXCONST_SGL( 0.98496019742444f / 8.0) }, + { FL2FXCONST_SGL(-0.79598702973261f / 8.0), FL2FXCONST_SGL( 0.97138411318894f / 8.0) }, + { FL2FXCONST_SGL(-0.99264708948101f / 8.0), FL2FXCONST_SGL(-0.99542822402536f / 8.0) }, + { FL2FXCONST_SGL(-0.99829663752818f / 8.0), FL2FXCONST_SGL( 0.01877138824311f / 8.0) }, + { FL2FXCONST_SGL(-0.70801016548184f / 8.0), FL2FXCONST_SGL( 0.33680685948117f / 8.0) }, + { FL2FXCONST_SGL(-0.70467057786826f / 8.0), FL2FXCONST_SGL( 0.93272777501857f / 8.0) }, + { FL2FXCONST_SGL( 0.99846021905254f / 8.0), FL2FXCONST_SGL(-0.98725746254433f / 8.0) }, + { FL2FXCONST_SGL(-0.63364968534650f / 8.0), FL2FXCONST_SGL(-0.16473594423746f / 8.0) }, + { FL2FXCONST_SGL(-0.16258217500792f / 8.0), FL2FXCONST_SGL(-0.95939125400802f / 8.0) }, + { FL2FXCONST_SGL(-0.43645594360633f / 8.0), FL2FXCONST_SGL(-0.94805030113284f / 8.0) }, + { FL2FXCONST_SGL(-0.99848471702976f / 8.0), FL2FXCONST_SGL( 0.96245166923809f / 8.0) }, + { FL2FXCONST_SGL(-0.16796458968998f / 8.0), FL2FXCONST_SGL(-0.98987511890470f / 8.0) }, + { FL2FXCONST_SGL(-0.87979225745213f / 8.0), FL2FXCONST_SGL(-0.71725725041680f / 8.0) }, + { FL2FXCONST_SGL( 0.44183099021786f / 8.0), FL2FXCONST_SGL(-0.93568974498761f / 8.0) }, + { FL2FXCONST_SGL( 0.93310180125532f / 8.0), FL2FXCONST_SGL(-0.99913308068246f / 8.0) }, + { FL2FXCONST_SGL(-0.93941931782002f / 8.0), FL2FXCONST_SGL(-0.56409379640356f / 8.0) }, + { FL2FXCONST_SGL(-0.88590003188677f / 8.0), FL2FXCONST_SGL( 0.47624600491382f / 8.0) }, + { FL2FXCONST_SGL( 0.99971463703691f / 8.0), FL2FXCONST_SGL(-0.83889954253462f / 8.0) }, + { FL2FXCONST_SGL(-0.75376385639978f / 8.0), FL2FXCONST_SGL( 0.00814643438625f / 8.0) }, + { FL2FXCONST_SGL( 0.93887685615875f / 8.0), FL2FXCONST_SGL(-0.11284528204636f / 8.0) }, + { FL2FXCONST_SGL( 0.85126435782309f / 8.0), FL2FXCONST_SGL( 0.52349251543547f / 8.0) }, + { FL2FXCONST_SGL( 0.39701421446381f / 8.0), FL2FXCONST_SGL( 0.81779634174316f / 8.0) }, + { FL2FXCONST_SGL(-0.37024464187437f / 8.0), FL2FXCONST_SGL(-0.87071656222959f / 8.0) }, + { FL2FXCONST_SGL(-0.36024828242896f / 8.0), FL2FXCONST_SGL( 0.34655735648287f / 8.0) }, + { FL2FXCONST_SGL(-0.93388812549209f / 8.0), FL2FXCONST_SGL(-0.84476541096429f / 8.0) }, + { FL2FXCONST_SGL(-0.65298804552119f / 8.0), FL2FXCONST_SGL(-0.18439575450921f / 8.0) }, + { FL2FXCONST_SGL( 0.11960319006843f / 8.0), FL2FXCONST_SGL( 0.99899346780168f / 8.0) }, + { FL2FXCONST_SGL( 0.94292565553160f / 8.0), FL2FXCONST_SGL( 0.83163906518293f / 8.0) }, + { FL2FXCONST_SGL( 0.75081145286948f / 8.0), FL2FXCONST_SGL(-0.35533223142265f / 8.0) }, + { FL2FXCONST_SGL( 0.56721979748394f / 8.0), FL2FXCONST_SGL(-0.24076836414499f / 8.0) }, + { FL2FXCONST_SGL( 0.46857766746029f / 8.0), FL2FXCONST_SGL(-0.30140233457198f / 8.0) }, + { FL2FXCONST_SGL( 0.97312313923635f / 8.0), FL2FXCONST_SGL(-0.99548191630031f / 8.0) }, + { FL2FXCONST_SGL(-0.38299976567017f / 8.0), FL2FXCONST_SGL( 0.98516909715427f / 8.0) }, + { FL2FXCONST_SGL( 0.41025800019463f / 8.0), FL2FXCONST_SGL( 0.02116736935734f / 8.0) }, + { FL2FXCONST_SGL( 0.09638062008048f / 8.0), FL2FXCONST_SGL( 0.04411984381457f / 8.0) }, + { FL2FXCONST_SGL(-0.85283249275397f / 8.0), FL2FXCONST_SGL( 0.91475563922421f / 8.0) }, + { FL2FXCONST_SGL( 0.88866808958124f / 8.0), FL2FXCONST_SGL(-0.99735267083226f / 8.0) }, + { FL2FXCONST_SGL(-0.48202429536989f / 8.0), FL2FXCONST_SGL(-0.96805608884164f / 8.0) }, + { FL2FXCONST_SGL( 0.27572582416567f / 8.0), FL2FXCONST_SGL( 0.58634753335832f / 8.0) }, + { FL2FXCONST_SGL(-0.65889129659168f / 8.0), FL2FXCONST_SGL( 0.58835634138583f / 8.0) }, + { FL2FXCONST_SGL( 0.98838086953732f / 8.0), FL2FXCONST_SGL( 0.99994349600236f / 8.0) }, + { FL2FXCONST_SGL(-0.20651349620689f / 8.0), FL2FXCONST_SGL( 0.54593044066355f / 8.0) }, + { FL2FXCONST_SGL(-0.62126416356920f / 8.0), FL2FXCONST_SGL(-0.59893681700392f / 8.0) }, + { FL2FXCONST_SGL( 0.20320105410437f / 8.0), FL2FXCONST_SGL(-0.86879180355289f / 8.0) }, + { FL2FXCONST_SGL(-0.97790548600584f / 8.0), FL2FXCONST_SGL( 0.96290806999242f / 8.0) }, + { FL2FXCONST_SGL( 0.11112534735126f / 8.0), FL2FXCONST_SGL( 0.21484763313301f / 8.0) }, + { FL2FXCONST_SGL(-0.41368337314182f / 8.0), FL2FXCONST_SGL( 0.28216837680365f / 8.0) }, + { FL2FXCONST_SGL( 0.24133038992960f / 8.0), FL2FXCONST_SGL( 0.51294362630238f / 8.0) }, + { FL2FXCONST_SGL(-0.66393410674885f / 8.0), FL2FXCONST_SGL(-0.08249679629081f / 8.0) }, + { FL2FXCONST_SGL(-0.53697829178752f / 8.0), FL2FXCONST_SGL(-0.97649903936228f / 8.0) }, + { FL2FXCONST_SGL(-0.97224737889348f / 8.0), FL2FXCONST_SGL( 0.22081333579837f / 8.0) }, + { FL2FXCONST_SGL( 0.87392477144549f / 8.0), FL2FXCONST_SGL(-0.12796173740361f / 8.0) }, + { FL2FXCONST_SGL( 0.19050361015753f / 8.0), FL2FXCONST_SGL( 0.01602615387195f / 8.0) }, + { FL2FXCONST_SGL(-0.46353441212724f / 8.0), FL2FXCONST_SGL(-0.95249041539006f / 8.0) }, + { FL2FXCONST_SGL(-0.07064096339021f / 8.0), FL2FXCONST_SGL(-0.94479803205886f / 8.0) }, + { FL2FXCONST_SGL(-0.92444085484466f / 8.0), FL2FXCONST_SGL(-0.10457590187436f / 8.0) }, + { FL2FXCONST_SGL(-0.83822593578728f / 8.0), FL2FXCONST_SGL(-0.01695043208885f / 8.0) }, + { FL2FXCONST_SGL( 0.75214681811150f / 8.0), FL2FXCONST_SGL(-0.99955681042665f / 8.0) }, + { FL2FXCONST_SGL(-0.42102998829339f / 8.0), FL2FXCONST_SGL( 0.99720941999394f / 8.0) }, + { FL2FXCONST_SGL(-0.72094786237696f / 8.0), FL2FXCONST_SGL(-0.35008961934255f / 8.0) }, + { FL2FXCONST_SGL( 0.78843311019251f / 8.0), FL2FXCONST_SGL( 0.52851398958271f / 8.0) }, + { FL2FXCONST_SGL( 0.97394027897442f / 8.0), FL2FXCONST_SGL(-0.26695944086561f / 8.0) }, + { FL2FXCONST_SGL( 0.99206463477946f / 8.0), FL2FXCONST_SGL(-0.57010120849429f / 8.0) }, + { FL2FXCONST_SGL( 0.76789609461795f / 8.0), FL2FXCONST_SGL(-0.76519356730966f / 8.0) }, + { FL2FXCONST_SGL(-0.82002421836409f / 8.0), FL2FXCONST_SGL(-0.73530179553767f / 8.0) }, + { FL2FXCONST_SGL( 0.81924990025724f / 8.0), FL2FXCONST_SGL( 0.99698425250579f / 8.0) }, + { FL2FXCONST_SGL(-0.26719850873357f / 8.0), FL2FXCONST_SGL( 0.68903369776193f / 8.0) }, + { FL2FXCONST_SGL(-0.43311260380975f / 8.0), FL2FXCONST_SGL( 0.85321815947490f / 8.0) }, + { FL2FXCONST_SGL( 0.99194979673836f / 8.0), FL2FXCONST_SGL( 0.91876249766422f / 8.0) }, + { FL2FXCONST_SGL(-0.80692001248487f / 8.0), FL2FXCONST_SGL(-0.32627540663214f / 8.0) }, + { FL2FXCONST_SGL( 0.43080003649976f / 8.0), FL2FXCONST_SGL(-0.21919095636638f / 8.0) }, + { FL2FXCONST_SGL( 0.67709491937357f / 8.0), FL2FXCONST_SGL(-0.95478075822906f / 8.0) }, + { FL2FXCONST_SGL( 0.56151770568316f / 8.0), FL2FXCONST_SGL(-0.70693811747778f / 8.0) }, + { FL2FXCONST_SGL( 0.10831862810749f / 8.0), FL2FXCONST_SGL(-0.08628837174592f / 8.0) }, + { FL2FXCONST_SGL( 0.91229417540436f / 8.0), FL2FXCONST_SGL(-0.65987351408410f / 8.0) }, + { FL2FXCONST_SGL(-0.48972893932274f / 8.0), FL2FXCONST_SGL( 0.56289246362686f / 8.0) }, + { FL2FXCONST_SGL(-0.89033658689697f / 8.0), FL2FXCONST_SGL(-0.71656563987082f / 8.0) }, + { FL2FXCONST_SGL( 0.65269447475094f / 8.0), FL2FXCONST_SGL( 0.65916004833932f / 8.0) }, + { FL2FXCONST_SGL( 0.67439478141121f / 8.0), FL2FXCONST_SGL(-0.81684380846796f / 8.0) }, + { FL2FXCONST_SGL(-0.47770832416973f / 8.0), FL2FXCONST_SGL(-0.16789556203025f / 8.0) }, + { FL2FXCONST_SGL(-0.99715979260878f / 8.0), FL2FXCONST_SGL(-0.93565784007648f / 8.0) }, + { FL2FXCONST_SGL(-0.90889593602546f / 8.0), FL2FXCONST_SGL( 0.62034397054380f / 8.0) }, + { FL2FXCONST_SGL(-0.06618622548177f / 8.0), FL2FXCONST_SGL(-0.23812217221359f / 8.0) }, + { FL2FXCONST_SGL( 0.99430266919728f / 8.0), FL2FXCONST_SGL( 0.18812555317553f / 8.0) }, + { FL2FXCONST_SGL( 0.97686402381843f / 8.0), FL2FXCONST_SGL(-0.28664534366620f / 8.0) }, + { FL2FXCONST_SGL( 0.94813650221268f / 8.0), FL2FXCONST_SGL(-0.97506640027128f / 8.0) }, + { FL2FXCONST_SGL(-0.95434497492853f / 8.0), FL2FXCONST_SGL(-0.79607978501983f / 8.0) }, + { FL2FXCONST_SGL(-0.49104783137150f / 8.0), FL2FXCONST_SGL( 0.32895214359663f / 8.0) }, + { FL2FXCONST_SGL( 0.99881175120751f / 8.0), FL2FXCONST_SGL( 0.88993983831354f / 8.0) }, + { FL2FXCONST_SGL( 0.50449166760303f / 8.0), FL2FXCONST_SGL(-0.85995072408434f / 8.0) }, + { FL2FXCONST_SGL( 0.47162891065108f / 8.0), FL2FXCONST_SGL(-0.18680204049569f / 8.0) }, + { FL2FXCONST_SGL(-0.62081581361840f / 8.0), FL2FXCONST_SGL( 0.75000676218956f / 8.0) }, + { FL2FXCONST_SGL(-0.43867015250812f / 8.0), FL2FXCONST_SGL( 0.99998069244322f / 8.0) }, + { FL2FXCONST_SGL( 0.98630563232075f / 8.0), FL2FXCONST_SGL(-0.53578899600662f / 8.0) }, + { FL2FXCONST_SGL(-0.61510362277374f / 8.0), FL2FXCONST_SGL(-0.89515019899997f / 8.0) }, + { FL2FXCONST_SGL(-0.03841517601843f / 8.0), FL2FXCONST_SGL(-0.69888815681179f / 8.0) }, + { FL2FXCONST_SGL(-0.30102157304644f / 8.0), FL2FXCONST_SGL(-0.07667808922205f / 8.0) }, + { FL2FXCONST_SGL( 0.41881284182683f / 8.0), FL2FXCONST_SGL( 0.02188098922282f / 8.0) }, + { FL2FXCONST_SGL(-0.86135454941237f / 8.0), FL2FXCONST_SGL( 0.98947480909359f / 8.0) }, + { FL2FXCONST_SGL( 0.67226861393788f / 8.0), FL2FXCONST_SGL(-0.13494389011014f / 8.0) }, + { FL2FXCONST_SGL(-0.70737398842068f / 8.0), FL2FXCONST_SGL(-0.76547349325992f / 8.0) }, + { FL2FXCONST_SGL( 0.94044946687963f / 8.0), FL2FXCONST_SGL( 0.09026201157416f / 8.0) }, + { FL2FXCONST_SGL(-0.82386352534327f / 8.0), FL2FXCONST_SGL( 0.08924768823676f / 8.0) }, + { FL2FXCONST_SGL(-0.32070666698656f / 8.0), FL2FXCONST_SGL( 0.50143421908753f / 8.0) }, + { FL2FXCONST_SGL( 0.57593163224487f / 8.0), FL2FXCONST_SGL(-0.98966422921509f / 8.0) }, + { FL2FXCONST_SGL(-0.36326018419965f / 8.0), FL2FXCONST_SGL( 0.07440243123228f / 8.0) }, + { FL2FXCONST_SGL( 0.99979044674350f / 8.0), FL2FXCONST_SGL(-0.14130287347405f / 8.0) }, + { FL2FXCONST_SGL(-0.92366023326932f / 8.0), FL2FXCONST_SGL(-0.97979298068180f / 8.0) }, + { FL2FXCONST_SGL(-0.44607178518598f / 8.0), FL2FXCONST_SGL(-0.54233252016394f / 8.0) }, + { FL2FXCONST_SGL( 0.44226800932956f / 8.0), FL2FXCONST_SGL( 0.71326756742752f / 8.0) }, + { FL2FXCONST_SGL( 0.03671907158312f / 8.0), FL2FXCONST_SGL( 0.63606389366675f / 8.0) }, + { FL2FXCONST_SGL( 0.52175424682195f / 8.0), FL2FXCONST_SGL(-0.85396826735705f / 8.0) }, + { FL2FXCONST_SGL(-0.94701139690956f / 8.0), FL2FXCONST_SGL(-0.01826348194255f / 8.0) }, + { FL2FXCONST_SGL(-0.98759606946049f / 8.0), FL2FXCONST_SGL( 0.82288714303073f / 8.0) }, + { FL2FXCONST_SGL( 0.87434794743625f / 8.0), FL2FXCONST_SGL( 0.89399495655433f / 8.0) }, + { FL2FXCONST_SGL(-0.93412041758744f / 8.0), FL2FXCONST_SGL( 0.41374052024363f / 8.0) }, + { FL2FXCONST_SGL( 0.96063943315511f / 8.0), FL2FXCONST_SGL( 0.93116709541280f / 8.0) }, + { FL2FXCONST_SGL( 0.97534253457837f / 8.0), FL2FXCONST_SGL( 0.86150930812689f / 8.0) }, + { FL2FXCONST_SGL( 0.99642466504163f / 8.0), FL2FXCONST_SGL( 0.70190043427512f / 8.0) }, + { FL2FXCONST_SGL(-0.94705089665984f / 8.0), FL2FXCONST_SGL(-0.29580042814306f / 8.0) }, + { FL2FXCONST_SGL( 0.91599807087376f / 8.0), FL2FXCONST_SGL(-0.98147830385781f / 8.0) } +}; +//@} + +/* +static const FIXP_SGL harmonicPhase [2][4] = { + { 1.0, 0.0, -1.0, 0.0}, + { 0.0, 1.0, 0.0, -1.0} +}; +*/ + + +/* The CLDFB-80 is not linear phase (unsymmetric), but the exact + phase difference between adjacent bands, at exact positions + (in this case exactly in the frequency band centre), can of + course be determined anyway. While the standard symmetric QMF + bank has a phase difference of 0.5*pi, the CLDFB-80 + bank has the difference 0.2337*pi. */ +const FIXP_SGL harmonicPhaseX [2][4] = { + { FL2FXCONST_SGL( 7.423735494778151e-001), FL2FXCONST_SGL(-6.699862036159475e-001), + FL2FXCONST_SGL(-7.423735494778152e-001), FL2FXCONST_SGL( 6.699862036159474e-001) }, + { FL2FXCONST_SGL( 7.423735494778151e-001), FL2FXCONST_SGL( 6.699862036159476e-001), + FL2FXCONST_SGL(-7.423735494778151e-001), FL2FXCONST_SGL(-6.699862036159476e-001) } +}; + +/* tables for SBR and AAC LD */ +/* table for 8 time slot index */ +const int FDK_sbrDecoder_envelopeTable_8 [8][5] = { +/* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */ +/* borders from left to right side; -1 = not in use */ + /*[|T-|------]*/ { 2, 0, 0, 1, -1 }, + /*[|-T-|-----]*/ { 2, 0, 0, 2, -1 }, + /*[--|T-|----]*/ { 3, 1, 1, 2, 4 }, + /*[---|T-|---]*/ { 3, 1, 1, 3, 5 }, + /*[----|T-|--]*/ { 3, 1, 1, 4, 6 }, + /*[-----|T--|]*/ { 2, 1, 1, 5, -1 }, + /*[------|T-|]*/ { 2, 1, 1, 6, -1 }, + /*[-------|T|]*/ { 2, 1, 1, 7, -1 }, +}; + +/* table for 15 time slot index */ +const int FDK_sbrDecoder_envelopeTable_15 [15][6] = { + /* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */ + /* length from left to right side; -1 = not in use */ + /*[|T---|------------]*/ { 2, 0, 0, 4, -1, -1}, + /*[|-T---|-----------]*/ { 2, 0, 0, 5, -1, -1}, + /*[|--|T---|---------]*/ { 3, 1, 1, 2, 6, -1}, + /*[|---|T---|--------]*/ { 3, 1, 1, 3, 7, -1}, + /*[|----|T---|-------]*/ { 3, 1, 1, 4, 8, -1}, + /*[|-----|T---|------]*/ { 3, 1, 1, 5, 9, -1}, + /*[|------|T---|-----]*/ { 3, 1, 1, 6, 10, -1}, + /*[|-------|T---|----]*/ { 3, 1, 1, 7, 11, -1}, + /*[|--------|T---|---]*/ { 3, 1, 1, 8, 12, -1}, + /*[|---------|T---|--]*/ { 3, 1, 1, 9, 13, -1}, + /*[|----------|T----|]*/ { 2, 1, 1,10, -1, -1}, + /*[|-----------|T---|]*/ { 2, 1, 1,11, -1, -1}, + /*[|------------|T--|]*/ { 2, 1, 1,12, -1, -1}, + /*[|-------------|T-|]*/ { 2, 1, 1,13, -1, -1}, + /*[|--------------|T|]*/ { 2, 1, 1,14, -1, -1}, +}; + +/* table for 16 time slot index */ +const int FDK_sbrDecoder_envelopeTable_16 [16][6] = { + /* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */ + /* length from left to right side; -1 = not in use */ + /*[|T---|------------|]*/ { 2, 0, 0, 4, -1, -1}, + /*[|-T---|-----------|]*/ { 2, 0, 0, 5, -1, -1}, + /*[|--|T---|----------]*/ { 3, 1, 1, 2, 6, -1}, + /*[|---|T---|---------]*/ { 3, 1, 1, 3, 7, -1}, + /*[|----|T---|--------]*/ { 3, 1, 1, 4, 8, -1}, + /*[|-----|T---|-------]*/ { 3, 1, 1, 5, 9, -1}, + /*[|------|T---|------]*/ { 3, 1, 1, 6, 10, -1}, + /*[|-------|T---|-----]*/ { 3, 1, 1, 7, 11, -1}, + /*[|--------|T---|----]*/ { 3, 1, 1, 8, 12, -1}, + /*[|---------|T---|---]*/ { 3, 1, 1, 9, 13, -1}, + /*[|----------|T---|--]*/ { 3, 1, 1,10, 14, -1}, + /*[|-----------|T----|]*/ { 2, 1, 1,11, -1, -1}, + /*[|------------|T---|]*/ { 2, 1, 1,12, -1, -1}, + /*[|-------------|T--|]*/ { 2, 1, 1,13, -1, -1}, + /*[|--------------|T-|]*/ { 2, 1, 1,14, -1, -1}, + /*[|---------------|T|]*/ { 2, 1, 1,15, -1, -1}, +}; + +/*! + \name FrameInfoDefaults + + Predefined envelope positions for the FIX-FIX case (static framing) +*/ +//@{ +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info1_15 = { 0, 1, {0, 15, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, -1, 1, {0, 15, 0} }; +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info2_15 = { 0, 2, {0, 8, 15, 0, 0, 0}, {1, 1, 0, 0, 0}, -1, 2, {0, 8, 15} }; +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info4_15 = { 0, 4, {0, 4, 8, 12, 15, 0}, {1, 1, 1, 1, 0}, -1, 2, {0, 8, 15} }; +#if (MAX_ENVELOPES >= 8) +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info8_15 = { 0, 8, {0, 2, 4, 6, 8, 10, 12, 14, 15}, {1, 1, 1, 1, 1, 1, 1, 1}, -1, 2, {0, 8, 15} }; +#endif + +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info1_16 = { 0, 1, {0, 16, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, -1, 1, {0, 16, 0} }; +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info2_16 = { 0, 2, {0, 8, 16, 0, 0, 0}, {1, 1, 0, 0, 0}, -1, 2, {0, 8, 16} }; +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info4_16 = { 0, 4, {0, 4, 8, 12, 16, 0}, {1, 1, 1, 1, 0}, -1, 2, {0, 8, 16} }; + +#if (MAX_ENVELOPES >= 8) +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info8_16 = { 0, 8, {0, 2, 4, 6, 8, 10, 12, 14, 16}, {1, 1, 1, 1, 1, 1, 1, 1}, -1, 2, {0, 8, 16} }; +#endif + + +//@} + +/*! + \name SBR_HuffmanTables + + SBR Huffman Table Overview: \n + \n + o envelope level, 1.5 dB: \n + 1) sbr_huffBook_EnvLevel10T[120][2] \n + 2) sbr_huffBook_EnvLevel10F[120][2] \n + \n + o envelope balance, 1.5 dB: \n + 3) sbr_huffBook_EnvBalance10T[48][2] \n + 4) sbr_huffBook_EnvBalance10F[48][2] \n + \n + o envelope level, 3.0 dB: \n + 5) sbr_huffBook_EnvLevel11T[62][2] \n + 6) sbr_huffBook_EnvLevel11F[62][2] \n + \n + o envelope balance, 3.0 dB: \n + 7) sbr_huffBook_EnvBalance11T[24][2] \n + 8) sbr_huffBook_EnvBalance11F[24][2] \n + \n + o noise level, 3.0 dB: \n + 9) sbr_huffBook_NoiseLevel11T[62][2] \n + -) (sbr_huffBook_EnvLevel11F[62][2] is used for freq dir)\n + \n + o noise balance, 3.0 dB: \n + 10) sbr_huffBook_NoiseBalance11T[24][2]\n + -) (sbr_huffBook_EnvBalance11F[24][2] is used for freq dir)\n + \n + (1.5 dB is never used for noise) + +*/ +//@{ +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel10T[120][2] = { + { 1, 2 }, { -64, -65 }, { 3, 4 }, { -63, -66 }, + { 5, 6 }, { -62, -67 }, { 7, 8 }, { -61, -68 }, + { 9, 10 }, { -60, -69 }, { 11, 12 }, { -59, -70 }, + { 13, 14 }, { -58, -71 }, { 15, 16 }, { -57, -72 }, + { 17, 18 }, { -73, -56 }, { 19, 21 }, { -74, 20 }, + { -55, -75 }, { 22, 26 }, { 23, 24 }, { -54, -76 }, + { -77, 25 }, { -53, -78 }, { 27, 34 }, { 28, 29 }, + { -52, -79 }, { 30, 31 }, { -80, -51 }, { 32, 33 }, + { -83, -82 }, { -81, -50 }, { 35, 57 }, { 36, 40 }, + { 37, 38 }, { -88, -84 }, { -48, 39 }, { -90, -85 }, + { 41, 46 }, { 42, 43 }, { -49, -87 }, { 44, 45 }, + { -89, -86 }, {-124,-123 }, { 47, 50 }, { 48, 49 }, + {-122,-121 }, {-120,-119 }, { 51, 54 }, { 52, 53 }, + {-118,-117 }, {-116,-115 }, { 55, 56 }, {-114,-113 }, + {-112,-111 }, { 58, 89 }, { 59, 74 }, { 60, 67 }, + { 61, 64 }, { 62, 63 }, {-110,-109 }, {-108,-107 }, + { 65, 66 }, {-106,-105 }, {-104,-103 }, { 68, 71 }, + { 69, 70 }, {-102,-101 }, {-100, -99 }, { 72, 73 }, + { -98, -97 }, { -96, -95 }, { 75, 82 }, { 76, 79 }, + { 77, 78 }, { -94, -93 }, { -92, -91 }, { 80, 81 }, + { -47, -46 }, { -45, -44 }, { 83, 86 }, { 84, 85 }, + { -43, -42 }, { -41, -40 }, { 87, 88 }, { -39, -38 }, + { -37, -36 }, { 90, 105 }, { 91, 98 }, { 92, 95 }, + { 93, 94 }, { -35, -34 }, { -33, -32 }, { 96, 97 }, + { -31, -30 }, { -29, -28 }, { 99, 102 }, { 100, 101 }, + { -27, -26 }, { -25, -24 }, { 103, 104 }, { -23, -22 }, + { -21, -20 }, { 106, 113 }, { 107, 110 }, { 108, 109 }, + { -19, -18 }, { -17, -16 }, { 111, 112 }, { -15, -14 }, + { -13, -12 }, { 114, 117 }, { 115, 116 }, { -11, -10 }, + { -9, -8 }, { 118, 119 }, { -7, -6 }, { -5, -4 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel10F[120][2] = { + { 1, 2 }, { -64, -65 }, { 3, 4 }, { -63, -66 }, + { 5, 6 }, { -67, -62 }, { 7, 8 }, { -68, -61 }, + { 9, 10 }, { -69, -60 }, { 11, 13 }, { -70, 12 }, + { -59, -71 }, { 14, 16 }, { -58, 15 }, { -72, -57 }, + { 17, 19 }, { -73, 18 }, { -56, -74 }, { 20, 23 }, + { 21, 22 }, { -55, -75 }, { -54, -53 }, { 24, 27 }, + { 25, 26 }, { -76, -52 }, { -77, -51 }, { 28, 31 }, + { 29, 30 }, { -50, -78 }, { -79, -49 }, { 32, 36 }, + { 33, 34 }, { -48, -47 }, { -80, 35 }, { -81, -82 }, + { 37, 47 }, { 38, 41 }, { 39, 40 }, { -83, -46 }, + { -45, -84 }, { 42, 44 }, { -85, 43 }, { -44, -43 }, + { 45, 46 }, { -88, -87 }, { -86, -90 }, { 48, 66 }, + { 49, 56 }, { 50, 53 }, { 51, 52 }, { -92, -42 }, + { -41, -39 }, { 54, 55 }, {-105, -89 }, { -38, -37 }, + { 57, 60 }, { 58, 59 }, { -94, -91 }, { -40, -36 }, + { 61, 63 }, { -20, 62 }, {-115,-110 }, { 64, 65 }, + {-108,-107 }, {-101, -97 }, { 67, 89 }, { 68, 75 }, + { 69, 72 }, { 70, 71 }, { -95, -93 }, { -34, -27 }, + { 73, 74 }, { -22, -17 }, { -16,-124 }, { 76, 82 }, + { 77, 79 }, {-123, 78 }, {-122,-121 }, { 80, 81 }, + {-120,-119 }, {-118,-117 }, { 83, 86 }, { 84, 85 }, + {-116,-114 }, {-113,-112 }, { 87, 88 }, {-111,-109 }, + {-106,-104 }, { 90, 105 }, { 91, 98 }, { 92, 95 }, + { 93, 94 }, {-103,-102 }, {-100, -99 }, { 96, 97 }, + { -98, -96 }, { -35, -33 }, { 99, 102 }, { 100, 101 }, + { -32, -31 }, { -30, -29 }, { 103, 104 }, { -28, -26 }, + { -25, -24 }, { 106, 113 }, { 107, 110 }, { 108, 109 }, + { -23, -21 }, { -19, -18 }, { 111, 112 }, { -15, -14 }, + { -13, -12 }, { 114, 117 }, { 115, 116 }, { -11, -10 }, + { -9, -8 }, { 118, 119 }, { -7, -6 }, { -5, -4 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance10T[48][2] = { + { -64, 1 }, { -63, 2 }, { -65, 3 }, { -62, 4 }, + { -66, 5 }, { -61, 6 }, { -67, 7 }, { -60, 8 }, + { -68, 9 }, { 10, 11 }, { -69, -59 }, { 12, 13 }, + { -70, -58 }, { 14, 28 }, { 15, 21 }, { 16, 18 }, + { -57, 17 }, { -71, -56 }, { 19, 20 }, { -88, -87 }, + { -86, -85 }, { 22, 25 }, { 23, 24 }, { -84, -83 }, + { -82, -81 }, { 26, 27 }, { -80, -79 }, { -78, -77 }, + { 29, 36 }, { 30, 33 }, { 31, 32 }, { -76, -75 }, + { -74, -73 }, { 34, 35 }, { -72, -55 }, { -54, -53 }, + { 37, 41 }, { 38, 39 }, { -52, -51 }, { -50, 40 }, + { -49, -48 }, { 42, 45 }, { 43, 44 }, { -47, -46 }, + { -45, -44 }, { 46, 47 }, { -43, -42 }, { -41, -40 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance10F[48][2] = { + { -64, 1 }, { -65, 2 }, { -63, 3 }, { -66, 4 }, + { -62, 5 }, { -61, 6 }, { -67, 7 }, { -68, 8 }, + { -60, 9 }, { 10, 11 }, { -69, -59 }, { -70, 12 }, + { -58, 13 }, { 14, 17 }, { -71, 15 }, { -57, 16 }, + { -56, -73 }, { 18, 32 }, { 19, 25 }, { 20, 22 }, + { -72, 21 }, { -88, -87 }, { 23, 24 }, { -86, -85 }, + { -84, -83 }, { 26, 29 }, { 27, 28 }, { -82, -81 }, + { -80, -79 }, { 30, 31 }, { -78, -77 }, { -76, -75 }, + { 33, 40 }, { 34, 37 }, { 35, 36 }, { -74, -55 }, + { -54, -53 }, { 38, 39 }, { -52, -51 }, { -50, -49 }, + { 41, 44 }, { 42, 43 }, { -48, -47 }, { -46, -45 }, + { 45, 46 }, { -44, -43 }, { -42, 47 }, { -41, -40 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel11T[62][2] = { + { -64, 1 }, { -65, 2 }, { -63, 3 }, { -66, 4 }, + { -62, 5 }, { -67, 6 }, { -61, 7 }, { -68, 8 }, + { -60, 9 }, { 10, 11 }, { -69, -59 }, { 12, 14 }, + { -70, 13 }, { -71, -58 }, { 15, 18 }, { 16, 17 }, + { -72, -57 }, { -73, -74 }, { 19, 22 }, { -56, 20 }, + { -55, 21 }, { -54, -77 }, { 23, 31 }, { 24, 25 }, + { -75, -76 }, { 26, 27 }, { -78, -53 }, { 28, 29 }, + { -52, -95 }, { -94, 30 }, { -93, -92 }, { 32, 47 }, + { 33, 40 }, { 34, 37 }, { 35, 36 }, { -91, -90 }, + { -89, -88 }, { 38, 39 }, { -87, -86 }, { -85, -84 }, + { 41, 44 }, { 42, 43 }, { -83, -82 }, { -81, -80 }, + { 45, 46 }, { -79, -51 }, { -50, -49 }, { 48, 55 }, + { 49, 52 }, { 50, 51 }, { -48, -47 }, { -46, -45 }, + { 53, 54 }, { -44, -43 }, { -42, -41 }, { 56, 59 }, + { 57, 58 }, { -40, -39 }, { -38, -37 }, { 60, 61 }, + { -36, -35 }, { -34, -33 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel11F[62][2] = { + { -64, 1 }, { -65, 2 }, { -63, 3 }, { -66, 4 }, + { -62, 5 }, { -67, 6 }, { 7, 8 }, { -61, -68 }, + { 9, 10 }, { -60, -69 }, { 11, 12 }, { -59, -70 }, + { 13, 14 }, { -58, -71 }, { 15, 16 }, { -57, -72 }, + { 17, 19 }, { -56, 18 }, { -55, -73 }, { 20, 24 }, + { 21, 22 }, { -74, -54 }, { -53, 23 }, { -75, -76 }, + { 25, 30 }, { 26, 27 }, { -52, -51 }, { 28, 29 }, + { -77, -79 }, { -50, -49 }, { 31, 39 }, { 32, 35 }, + { 33, 34 }, { -78, -46 }, { -82, -88 }, { 36, 37 }, + { -83, -48 }, { -47, 38 }, { -86, -85 }, { 40, 47 }, + { 41, 44 }, { 42, 43 }, { -80, -44 }, { -43, -42 }, + { 45, 46 }, { -39, -87 }, { -84, -40 }, { 48, 55 }, + { 49, 52 }, { 50, 51 }, { -95, -94 }, { -93, -92 }, + { 53, 54 }, { -91, -90 }, { -89, -81 }, { 56, 59 }, + { 57, 58 }, { -45, -41 }, { -38, -37 }, { 60, 61 }, + { -36, -35 }, { -34, -33 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance11T[24][2] = { + { -64, 1 }, { -63, 2 }, { -65, 3 }, { -66, 4 }, + { -62, 5 }, { -61, 6 }, { -67, 7 }, { -68, 8 }, + { -60, 9 }, { 10, 16 }, { 11, 13 }, { -69, 12 }, + { -76, -75 }, { 14, 15 }, { -74, -73 }, { -72, -71 }, + { 17, 20 }, { 18, 19 }, { -70, -59 }, { -58, -57 }, + { 21, 22 }, { -56, -55 }, { -54, 23 }, { -53, -52 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance11F[24][2] = { + { -64, 1 }, { -65, 2 }, { -63, 3 }, { -66, 4 }, + { -62, 5 }, { -61, 6 }, { -67, 7 }, { -68, 8 }, + { -60, 9 }, { 10, 13 }, { -69, 11 }, { -59, 12 }, + { -58, -76 }, { 14, 17 }, { 15, 16 }, { -75, -74 }, + { -73, -72 }, { 18, 21 }, { 19, 20 }, { -71, -70 }, + { -57, -56 }, { 22, 23 }, { -55, -54 }, { -53, -52 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_NoiseLevel11T[62][2] = { + { -64, 1 }, { -63, 2 }, { -65, 3 }, { -66, 4 }, + { -62, 5 }, { -67, 6 }, { 7, 8 }, { -61, -68 }, + { 9, 30 }, { 10, 15 }, { -60, 11 }, { -69, 12 }, + { 13, 14 }, { -59, -53 }, { -95, -94 }, { 16, 23 }, + { 17, 20 }, { 18, 19 }, { -93, -92 }, { -91, -90 }, + { 21, 22 }, { -89, -88 }, { -87, -86 }, { 24, 27 }, + { 25, 26 }, { -85, -84 }, { -83, -82 }, { 28, 29 }, + { -81, -80 }, { -79, -78 }, { 31, 46 }, { 32, 39 }, + { 33, 36 }, { 34, 35 }, { -77, -76 }, { -75, -74 }, + { 37, 38 }, { -73, -72 }, { -71, -70 }, { 40, 43 }, + { 41, 42 }, { -58, -57 }, { -56, -55 }, { 44, 45 }, + { -54, -52 }, { -51, -50 }, { 47, 54 }, { 48, 51 }, + { 49, 50 }, { -49, -48 }, { -47, -46 }, { 52, 53 }, + { -45, -44 }, { -43, -42 }, { 55, 58 }, { 56, 57 }, + { -41, -40 }, { -39, -38 }, { 59, 60 }, { -37, -36 }, + { -35, 61 }, { -34, -33 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_NoiseBalance11T[24][2] = { + { -64, 1 }, { -65, 2 }, { -63, 3 }, { 4, 9 }, + { -66, 5 }, { -62, 6 }, { 7, 8 }, { -76, -75 }, + { -74, -73 }, { 10, 17 }, { 11, 14 }, { 12, 13 }, + { -72, -71 }, { -70, -69 }, { 15, 16 }, { -68, -67 }, + { -61, -60 }, { 18, 21 }, { 19, 20 }, { -59, -58 }, + { -57, -56 }, { 22, 23 }, { -55, -54 }, { -53, -52 } +}; +//@} + + + + +/*! + \name parametric stereo + \brief constants used by the parametric stereo part of the decoder + +*/ + + +/* constants used in psbitdec.cpp */ + +/* FIX_BORDER can have 0, 1, 2, 4 envelopes */ +const UCHAR FDK_sbrDecoder_aFixNoEnvDecode[4] = {0, 1, 2, 4}; + + +/* IID & ICC Huffman codebooks */ +const SCHAR aBookPsIidTimeDecode[28][2] = { + { -64, 1 }, { -65, 2 }, { -63, 3 }, { -66, 4 }, + { -62, 5 }, { -67, 6 }, { -61, 7 }, { -68, 8 }, + { -60, 9 }, { -69, 10 }, { -59, 11 }, { -70, 12 }, + { -58, 13 }, { -57, 14 }, { -71, 15 }, { 16, 17 }, + { -56, -72 }, { 18, 21 }, { 19, 20 }, { -55, -78 }, + { -77, -76 }, { 22, 25 }, { 23, 24 }, { -75, -74 }, + { -73, -54 }, { 26, 27 }, { -53, -52 }, { -51, -50 } +}; + +const SCHAR aBookPsIidFreqDecode[28][2] = { + { -64, 1 }, { 2, 3 }, { -63, -65 }, { 4, 5 }, + { -62, -66 }, { 6, 7 }, { -61, -67 }, { 8, 9 }, + { -68, -60 }, { -59, 10 }, { -69, 11 }, { -58, 12 }, + { -70, 13 }, { -71, 14 }, { -57, 15 }, { 16, 17 }, + { -56, -72 }, { 18, 19 }, { -55, -54 }, { 20, 21 }, + { -73, -53 }, { 22, 24 }, { -74, 23 }, { -75, -78 }, + { 25, 26 }, { -77, -76 }, { -52, 27 }, { -51, -50 } +}; + +const SCHAR aBookPsIccTimeDecode[14][2] = { + { -64, 1 }, { -63, 2 }, { -65, 3 }, { -62, 4 }, + { -66, 5 }, { -61, 6 }, { -67, 7 }, { -60, 8 }, + { -68, 9 }, { -59, 10 }, { -69, 11 }, { -58, 12 }, + { -70, 13 }, { -71, -57 } +}; + +const SCHAR aBookPsIccFreqDecode[14][2] = { + { -64, 1 }, { -63, 2 }, { -65, 3 }, { -62, 4 }, + { -66, 5 }, { -61, 6 }, { -67, 7 }, { -60, 8 }, + { -59, 9 }, { -68, 10 }, { -58, 11 }, { -69, 12 }, + { -57, 13 }, { -70, -71 } +}; + +/* IID-fine Huffman codebooks */ + +const SCHAR aBookPsIidFineTimeDecode[60][2] = { + { 1, -64 }, { -63, 2 }, { 3, -65 }, { 4, 59 }, + { 5, 7 }, { 6, -67 }, { -68, -60 }, { -61, 8 }, + { 9, 11 }, { -59, 10 }, { -70, -58 }, { 12, 41 }, + { 13, 20 }, { 14, -71 }, { -55, 15 }, { -53, 16 }, + { 17, -77 }, { 18, 19 }, { -85, -84 }, { -46, -45 }, + { -57, 21 }, { 22, 40 }, { 23, 29 }, { -51, 24 }, + { 25, 26 }, { -83, -82 }, { 27, 28 }, { -90, -38 }, + { -92, -91 }, { 30, 37 }, { 31, 34 }, { 32, 33 }, + { -35, -34 }, { -37, -36 }, { 35, 36 }, { -94, -93 }, + { -89, -39 }, { 38, -79 }, { 39, -81 }, { -88, -40 }, + { -74, -54 }, { 42, -69 }, { 43, 44 }, { -72, -56 }, + { 45, 52 }, { 46, 50 }, { 47, -76 }, { -49, 48 }, + { -47, 49 }, { -87, -41 }, { -52, 51 }, { -78, -50 }, + { 53, -73 }, { 54, -75 }, { 55, 57 }, { 56, -80 }, + { -86, -42 }, { -48, 58 }, { -44, -43 }, { -66, -62 } +}; + + +const SCHAR aBookPsIidFineFreqDecode[60][2] = { + { 1, -64 }, { 2, 4 }, { 3, -65 }, { -66, -62 }, + { -63, 5 }, { 6, 7 }, { -67, -61 }, { 8, 9 }, + { -68, -60 }, { 10, 11 }, { -69, -59 }, { 12, 13 }, + { -70, -58 }, { 14, 18 }, { -57, 15 }, { 16, -72 }, + { -54, 17 }, { -75, -53 }, { 19, 37 }, { -56, 20 }, + { 21, -73 }, { 22, 29 }, { 23, -76 }, { 24, -78 }, + { 25, 28 }, { 26, 27 }, { -85, -43 }, { -83, -45 }, + { -81, -47 }, { -52, 30 }, { -50, 31 }, { 32, -79 }, + { 33, 34 }, { -82, -46 }, { 35, 36 }, { -90, -89 }, + { -92, -91 }, { 38, -71 }, { -55, 39 }, { 40, -74 }, + { 41, 50 }, { 42, -77 }, { -49, 43 }, { 44, 47 }, + { 45, 46 }, { -86, -42 }, { -88, -87 }, { 48, 49 }, + { -39, -38 }, { -41, -40 }, { -51, 51 }, { 52, 59 }, + { 53, 56 }, { 54, 55 }, { -35, -34 }, { -37, -36 }, + { 57, 58 }, { -94, -93 }, { -84, -44 }, { -80, -48 } +}; + +/* constants used in psdec.cpp */ + +const FIXP_DBL decayScaleFactTable[64] = { + + FL2FXCONST_DBL(1.000000), FL2FXCONST_DBL(1.000000), FL2FXCONST_DBL(1.000000), FL2FXCONST_DBL(1.000000), + FL2FXCONST_DBL(0.950000), FL2FXCONST_DBL(0.900000), FL2FXCONST_DBL(0.850000), FL2FXCONST_DBL(0.800000), + FL2FXCONST_DBL(0.750000), FL2FXCONST_DBL(0.700000), FL2FXCONST_DBL(0.650000), FL2FXCONST_DBL(0.600000), + FL2FXCONST_DBL(0.550000), FL2FXCONST_DBL(0.500000), FL2FXCONST_DBL(0.450000), FL2FXCONST_DBL(0.400000), + FL2FXCONST_DBL(0.350000), FL2FXCONST_DBL(0.300000), FL2FXCONST_DBL(0.250000), FL2FXCONST_DBL(0.200000), + FL2FXCONST_DBL(0.150000), FL2FXCONST_DBL(0.100000), FL2FXCONST_DBL(0.050000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000) }; + +/* the values of the following 3 tables are shiftet right by 1 ! */ +const FIXP_DBL ScaleFactors[NO_IID_LEVELS] = { + + 0x5a5ded00, 0x59cd0400, 0x58c29680, 0x564c2e80, 0x52a3d480, + 0x4c8be080, 0x46df3080, 0x40000000, 0x384ba5c0, 0x304c2980, + 0x24e9f640, 0x1b4a2940, 0x11b5c0a0, 0x0b4e2540, 0x0514ea90 +}; + +const FIXP_DBL ScaleFactorsFine[NO_IID_LEVELS_FINE] = { + + 0x5a825c00, 0x5a821c00, 0x5a815100, 0x5a7ed000, 0x5a76e600, + 0x5a5ded00, 0x5a39b880, 0x59f1fd00, 0x5964d680, 0x5852ca00, + 0x564c2e80, 0x54174480, 0x50ea7500, 0x4c8be080, 0x46df3080, + 0x40000000, 0x384ba5c0, 0x304c2980, 0x288dd240, 0x217a2900, + 0x1b4a2940, 0x13c5ece0, 0x0e2b0090, 0x0a178ef0, 0x072ab798, + 0x0514ea90, 0x02dc5944, 0x019bf87c, 0x00e7b173, 0x00824b8b, + 0x00494568 +}; +const FIXP_DBL Alphas[NO_ICC_LEVELS] = { + + 0x00000000, 0x0b6b5be0, 0x12485f80, 0x1da2fa40, + 0x2637ebc0, 0x3243f6c0, 0x466b7480, 0x6487ed80 +}; + +#if defined(ARCH_PREFER_MULT_32x16) +#define FIXP_PS FIXP_SGL +#define FXP_CAST(a) FX_DBL2FX_SGL((FIXP_DBL)a) +#define FL2FXCONST_PS FL2FXCONST_SGL +#else +#define FIXP_PS FIXP_DBL +#define FXP_CAST +#define FL2FXCONST_PS FL2FXCONST_DBL +#endif + +const FIXP_PS aAllpassLinkDecaySer[NO_SERIAL_ALLPASS_LINKS] = { +FXP_CAST(0x53625b00), FXP_CAST(0x4848af00), FXP_CAST(0x3ea94d00) }; + +const FIXP_PS aaFractDelayPhaseFactorReQmf[NO_QMF_CHANNELS] = { +FXP_CAST(0x68b92180), FXP_CAST(0xde396900), FXP_CAST(0x80650380), FXP_CAST(0xcb537e40), FXP_CAST(0x5beb8f00), FXP_CAST(0x72f29200), FXP_CAST(0xf1f43c50), FXP_CAST(0x83896280), +FXP_CAST(0xb9b99c00), FXP_CAST(0x4cda8f00), FXP_CAST(0x7a576e00), FXP_CAST(0x060799e0), FXP_CAST(0x89be5280), FXP_CAST(0xa9dab600), FXP_CAST(0x3be51b00), FXP_CAST(0x7eb91900), +FXP_CAST(0x19f4f540), FXP_CAST(0x92dcb380), FXP_CAST(0x9c1ad700), FXP_CAST(0x29761940), FXP_CAST(0x7ffbf500), FXP_CAST(0x2d3eb180), FXP_CAST(0x9eab0a00), FXP_CAST(0x90d0aa80), +FXP_CAST(0x1601bcc0), FXP_CAST(0x7e180e80), FXP_CAST(0x3f6b3940), FXP_CAST(0xacdeeb00), FXP_CAST(0x88435b00), FXP_CAST(0x0202a768), FXP_CAST(0x79194f80), FXP_CAST(0x5007fd00), +FXP_CAST(0xbd1ecf00), FXP_CAST(0x82a8d100), FXP_CAST(0xedf6e5e0), FXP_CAST(0x711f3500), FXP_CAST(0x5eac4480), FXP_CAST(0xcf0447c0), FXP_CAST(0x80245f80), FXP_CAST(0xda5cd4c0), +FXP_CAST(0x665c0800), FXP_CAST(0x6afbc500), FXP_CAST(0xe21e85e0), FXP_CAST(0x80c5e500), FXP_CAST(0xc7b003c0), FXP_CAST(0x59139f80), FXP_CAST(0x74a8e400), FXP_CAST(0xf5f51f40), +FXP_CAST(0x84896680), FXP_CAST(0xb6662b00), FXP_CAST(0x4999b600), FXP_CAST(0x7b76a300), FXP_CAST(0x0a0b0650), FXP_CAST(0x8b572b80), FXP_CAST(0xa6ec4580), FXP_CAST(0x384fda80), +FXP_CAST(0x7f3a1f00), FXP_CAST(0x1de19ec0), FXP_CAST(0x95045000), FXP_CAST(0x99a3e180), FXP_CAST(0x25a30740), FXP_CAST(0x7fdb9e80), FXP_CAST(0x30fbdb00), FXP_CAST(0xa153d500) }; + +const FIXP_PS aaFractDelayPhaseFactorImQmf[NO_QMF_CHANNELS] = { +FXP_CAST(0xb6663a80), FXP_CAST(0x84896200), FXP_CAST(0xf5f50c70), FXP_CAST(0x74a8dc80), FXP_CAST(0x5913ad00), FXP_CAST(0xc7b01480), FXP_CAST(0x80c5e300), FXP_CAST(0xe21e73a0), +FXP_CAST(0x6afbba80), FXP_CAST(0x665c1380), FXP_CAST(0xda5ce6c0), FXP_CAST(0x80246080), FXP_CAST(0xcf043640), FXP_CAST(0x5eac3800), FXP_CAST(0x711f3e00), FXP_CAST(0xedf6f8a0), +FXP_CAST(0x82a8d500), FXP_CAST(0xbd1ebe80), FXP_CAST(0x5007ee00), FXP_CAST(0x79195580), FXP_CAST(0x0202ba40), FXP_CAST(0x88436180), FXP_CAST(0xacdedc80), FXP_CAST(0x3f6b28c0), +FXP_CAST(0x7e181180), FXP_CAST(0x1601cf40), FXP_CAST(0x90d0b380), FXP_CAST(0x9eaafd80), FXP_CAST(0x2d3e9fc0), FXP_CAST(0x7ffbf580), FXP_CAST(0x29762b00), FXP_CAST(0x9c1ae280), +FXP_CAST(0x92dca980), FXP_CAST(0x19f4e2c0), FXP_CAST(0x7eb91680), FXP_CAST(0x3be52b80), FXP_CAST(0xa9dac400), FXP_CAST(0x89be4b80), FXP_CAST(0x06078710), FXP_CAST(0x7a576880), +FXP_CAST(0x4cda9e00), FXP_CAST(0xb9b9ac00), FXP_CAST(0x83895e00), FXP_CAST(0xf1f42990), FXP_CAST(0x72f28a00), FXP_CAST(0x5beb9c00), FXP_CAST(0xcb538f40), FXP_CAST(0x80650200), +FXP_CAST(0xde3956c0), FXP_CAST(0x68b91680), FXP_CAST(0x68b92c00), FXP_CAST(0xde397b40), FXP_CAST(0x80650500), FXP_CAST(0xcb536d00), FXP_CAST(0x5beb8180), FXP_CAST(0x72f29a80), +FXP_CAST(0xf1f44f10), FXP_CAST(0x83896700), FXP_CAST(0xb9b98c80), FXP_CAST(0x4cda8000), FXP_CAST(0x7a577380), FXP_CAST(0x0607acb8), FXP_CAST(0x89be5a00), FXP_CAST(0xa9daa800) }; + +const FIXP_PS aaFractDelayPhaseFactorReSubQmf20[NO_SUB_QMF_CHANNELS] = { +FXP_CAST(0x7e807380), FXP_CAST(0x72b9bb00), FXP_CAST(0x5c44ee80), FXP_CAST(0x3d3938c0), FXP_CAST(0x80000000), FXP_CAST(0x80000000), +FXP_CAST(0x72b9bb00), FXP_CAST(0x7e807380), FXP_CAST(0xba914700), FXP_CAST(0x050677b0), FXP_CAST(0x895cc380), FXP_CAST(0x834e4900) }; + +const FIXP_PS aaFractDelayPhaseFactorImSubQmf20[NO_SUB_QMF_CHANNELS] = { +FXP_CAST(0xec791720), FXP_CAST(0xc73ca080), FXP_CAST(0xa748ea00), FXP_CAST(0x8f976980), FXP_CAST(0x00000000), FXP_CAST(0x00000000), +FXP_CAST(0x38c35f80), FXP_CAST(0x1386e8e0), FXP_CAST(0x9477d000), FXP_CAST(0x80194380), FXP_CAST(0xcff26140), FXP_CAST(0x1ce70d40) }; + +const FIXP_PS aaFractDelayPhaseFactorSerReQmf[NO_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS] = { +{FXP_CAST(0x63e52480), FXP_CAST(0x30fbc540), FXP_CAST(0x6d73af00)}, {FXP_CAST(0xc7b01280), FXP_CAST(0x89be5100), FXP_CAST(0xf7c31cb0)}, {FXP_CAST(0x83896200), FXP_CAST(0x7641af00), FXP_CAST(0x8aee2700)}, +{FXP_CAST(0x0202b330), FXP_CAST(0xcf043ac0), FXP_CAST(0x9bfab500)}, {FXP_CAST(0x7d572c80), FXP_CAST(0xcf043ac0), FXP_CAST(0x1893b960)}, {FXP_CAST(0x34ac7fc0), FXP_CAST(0x7641af00), FXP_CAST(0x7abf7980)}, +{FXP_CAST(0x99a3ee00), FXP_CAST(0x89be5100), FXP_CAST(0x58eead80)}, {FXP_CAST(0x9eab0580), FXP_CAST(0x30fbc540), FXP_CAST(0xd77dae40)}, {FXP_CAST(0x3be52140), FXP_CAST(0x30fbc540), FXP_CAST(0x819b8500)}, +{FXP_CAST(0x7b769d80), FXP_CAST(0x89be5100), FXP_CAST(0xb3a12280)}, {FXP_CAST(0xf9f86878), FXP_CAST(0x7641af00), FXP_CAST(0x37c519c0)}, {FXP_CAST(0x81e7ef80), FXP_CAST(0xcf043ac0), FXP_CAST(0x7ff16880)}, +{FXP_CAST(0xcf043cc0), FXP_CAST(0xcf043ac0), FXP_CAST(0x3e8b2340)}, {FXP_CAST(0x68b92280), FXP_CAST(0x7641af00), FXP_CAST(0xb9e4a900)}, {FXP_CAST(0x5eac3980), FXP_CAST(0x89be5100), FXP_CAST(0x80a05200)}, +{FXP_CAST(0xc094cd00), FXP_CAST(0x30fbc540), FXP_CAST(0xd051dc80)}, {FXP_CAST(0x85a89400), FXP_CAST(0x30fbc540), FXP_CAST(0x53483b00)}, {FXP_CAST(0x0a0af5e0), FXP_CAST(0x89be5100), FXP_CAST(0x7cb1b680)}, +{FXP_CAST(0x7eb91900), FXP_CAST(0x7641af00), FXP_CAST(0x2006e8c0)}, {FXP_CAST(0x2d3ea680), FXP_CAST(0xcf043ac0), FXP_CAST(0xa0ec1c00)}, {FXP_CAST(0x95044180), FXP_CAST(0xcf043ac0), FXP_CAST(0x880d2180)}, +{FXP_CAST(0xa4147300), FXP_CAST(0x7641af00), FXP_CAST(0xf0282870)}, {FXP_CAST(0x42e13f80), FXP_CAST(0x89be5100), FXP_CAST(0x694c4a00)}, {FXP_CAST(0x79195200), FXP_CAST(0x30fbc540), FXP_CAST(0x71374780)}, +{FXP_CAST(0xf1f43550), FXP_CAST(0x30fbc540), FXP_CAST(0xff6593ea)}, {FXP_CAST(0x80c5e280), FXP_CAST(0x89be5100), FXP_CAST(0x8e39ec00)}, {FXP_CAST(0xd689e480), FXP_CAST(0x7641af00), FXP_CAST(0x97648100)}, +{FXP_CAST(0x6d235300), FXP_CAST(0xcf043ac0), FXP_CAST(0x110a20c0)}, {FXP_CAST(0x5913a800), FXP_CAST(0xcf043ac0), FXP_CAST(0x785d4f80)}, {FXP_CAST(0xb9b99a00), FXP_CAST(0x7641af00), FXP_CAST(0x5e440880)}, +{FXP_CAST(0x88436100), FXP_CAST(0x89be5100), FXP_CAST(0xdece7000)}, {FXP_CAST(0x12091320), FXP_CAST(0x30fbc540), FXP_CAST(0x8309f800)}, {FXP_CAST(0x7f9afd00), FXP_CAST(0x30fbc540), FXP_CAST(0xada33f00)}, +{FXP_CAST(0x25a31700), FXP_CAST(0x89be5100), FXP_CAST(0x30cc3600)}, {FXP_CAST(0x90d0ab80), FXP_CAST(0x7641af00), FXP_CAST(0x7f7cbe80)}, {FXP_CAST(0xa9dabf00), FXP_CAST(0xcf043ac0), FXP_CAST(0x45182580)}, +{FXP_CAST(0x4999cb80), FXP_CAST(0xcf043ac0), FXP_CAST(0xc0681c80)}, {FXP_CAST(0x7641ac80), FXP_CAST(0x7641af00), FXP_CAST(0x80194380)}, {FXP_CAST(0xe9fe3300), FXP_CAST(0x89be5100), FXP_CAST(0xc95184c0)}, +{FXP_CAST(0x80246000), FXP_CAST(0x30fbc540), FXP_CAST(0x4d55d800)}, {FXP_CAST(0xde396fc0), FXP_CAST(0x30fbc540), FXP_CAST(0x7e324000)}, {FXP_CAST(0x711f3f00), FXP_CAST(0x89be5100), FXP_CAST(0x275ce480)}, +{FXP_CAST(0x53211700), FXP_CAST(0x7641af00), FXP_CAST(0xa6343580)}, {FXP_CAST(0xb3256780), FXP_CAST(0xcf043ac0), FXP_CAST(0x85997b80)}, {FXP_CAST(0x8b572680), FXP_CAST(0xcf043ac0), FXP_CAST(0xe89ba660)}, +{FXP_CAST(0x19f4f780), FXP_CAST(0x7641af00), FXP_CAST(0x64c4e100)}, {FXP_CAST(0x7ffbf580), FXP_CAST(0x89be5100), FXP_CAST(0x7493a380)}, {FXP_CAST(0x1de18100), FXP_CAST(0x30fbc540), FXP_CAST(0x070897f0)}, +{FXP_CAST(0x8d0d6a80), FXP_CAST(0x30fbc540), FXP_CAST(0x91ed6f00)}, {FXP_CAST(0xaff81380), FXP_CAST(0x89be5100), FXP_CAST(0x932db000)}, {FXP_CAST(0x5007fb00), FXP_CAST(0x7641af00), FXP_CAST(0x0970feb0)}, +{FXP_CAST(0x72f28d00), FXP_CAST(0xcf043ac0), FXP_CAST(0x758d6500)}, {FXP_CAST(0xe21e6cc0), FXP_CAST(0xcf043ac0), FXP_CAST(0x63436f80)}, {FXP_CAST(0x80040b00), FXP_CAST(0x7641af00), FXP_CAST(0xe63d7600)}, +{FXP_CAST(0xe60b1ae0), FXP_CAST(0x89be5100), FXP_CAST(0x84ea5c80)}, {FXP_CAST(0x74a8e100), FXP_CAST(0x30fbc540), FXP_CAST(0xa7f07500)}, {FXP_CAST(0x4cda8980), FXP_CAST(0x30fbc540), FXP_CAST(0x29a6d340)}, +{FXP_CAST(0xacdeda80), FXP_CAST(0x89be5100), FXP_CAST(0x7e93d600)}, {FXP_CAST(0x8ee0c980), FXP_CAST(0x7641af00), FXP_CAST(0x4b662680)}, {FXP_CAST(0x21c6a280), FXP_CAST(0xcf043ac0), FXP_CAST(0xc7258c80)}, +{FXP_CAST(0x7fdb9f00), FXP_CAST(0xcf043ac0), FXP_CAST(0x8006d500)}, {FXP_CAST(0x1601ba60), FXP_CAST(0x7641af00), FXP_CAST(0xc2830940)}, {FXP_CAST(0x89be4c80), FXP_CAST(0x89be5100), FXP_CAST(0x471cf100)}, +{FXP_CAST(0xb6664400), FXP_CAST(0x30fbc540), FXP_CAST(0x7f3fb800)}}; + +const FIXP_PS aaFractDelayPhaseFactorSerImQmf[NO_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS] = { +{FXP_CAST(0xaff80c80), FXP_CAST(0x89be5100), FXP_CAST(0xbda29e00)}, {FXP_CAST(0x8d0d6f00), FXP_CAST(0x30fbc540), FXP_CAST(0x8043ee80)}, {FXP_CAST(0x1de18a20), FXP_CAST(0x30fbc540), FXP_CAST(0xcc3e7840)}, +{FXP_CAST(0x7ffbf500), FXP_CAST(0x89be5100), FXP_CAST(0x4fdfc180)}, {FXP_CAST(0x19f4ee40), FXP_CAST(0x7641af00), FXP_CAST(0x7d9e4c00)}, {FXP_CAST(0x8b572300), FXP_CAST(0xcf043ac0), FXP_CAST(0x244a2940)}, +{FXP_CAST(0xb3256f00), FXP_CAST(0xcf043ac0), FXP_CAST(0xa3f0a500)}, {FXP_CAST(0x53211e00), FXP_CAST(0x7641af00), FXP_CAST(0x86944500)}, {FXP_CAST(0x711f3a80), FXP_CAST(0x89be5100), FXP_CAST(0xebc72040)}, +{FXP_CAST(0xde3966c0), FXP_CAST(0x30fbc540), FXP_CAST(0x66b87e00)}, {FXP_CAST(0x80246080), FXP_CAST(0x30fbc540), FXP_CAST(0x73362c00)}, {FXP_CAST(0xe9fe3c40), FXP_CAST(0x89be5100), FXP_CAST(0x03d1d110)}, +{FXP_CAST(0x7641b000), FXP_CAST(0x7641af00), FXP_CAST(0x90520c80)}, {FXP_CAST(0x4999c380), FXP_CAST(0xcf043ac0), FXP_CAST(0x94e80a80)}, {FXP_CAST(0xa9dab800), FXP_CAST(0xcf043ac0), FXP_CAST(0x0ca570e0)}, +{FXP_CAST(0x90d0b000), FXP_CAST(0x7641af00), FXP_CAST(0x76c9bc80)}, {FXP_CAST(0x25a32000), FXP_CAST(0x89be5100), FXP_CAST(0x61338500)}, {FXP_CAST(0x7f9afc80), FXP_CAST(0x30fbc540), FXP_CAST(0xe318f060)}, +{FXP_CAST(0x120909c0), FXP_CAST(0x30fbc540), FXP_CAST(0x84124e00)}, {FXP_CAST(0x88435d80), FXP_CAST(0x89be5100), FXP_CAST(0xaa4d2f80)}, {FXP_CAST(0xb9b9a200), FXP_CAST(0x7641af00), FXP_CAST(0x2cae1800)}, +{FXP_CAST(0x5913ae80), FXP_CAST(0xcf043ac0), FXP_CAST(0x7f040680)}, {FXP_CAST(0x6d234e00), FXP_CAST(0xcf043ac0), FXP_CAST(0x48c6a100)}, {FXP_CAST(0xd689db80), FXP_CAST(0x7641af00), FXP_CAST(0xc44860c0)}, +{FXP_CAST(0x80c5e380), FXP_CAST(0x89be5100), FXP_CAST(0x80005d00)}, {FXP_CAST(0xf1f43eb0), FXP_CAST(0x30fbc540), FXP_CAST(0xc55a3a00)}, {FXP_CAST(0x79195500), FXP_CAST(0x30fbc540), FXP_CAST(0x49c3de00)}, +{FXP_CAST(0x42e13700), FXP_CAST(0x89be5100), FXP_CAST(0x7edc5b00)}, {FXP_CAST(0xa4146c80), FXP_CAST(0x7641af00), FXP_CAST(0x2b8c2c00)}, {FXP_CAST(0x95044680), FXP_CAST(0xcf043ac0), FXP_CAST(0xa968c100)}, +{FXP_CAST(0x2d3eaf40), FXP_CAST(0xcf043ac0), FXP_CAST(0x8460fd80)}, {FXP_CAST(0x7eb91780), FXP_CAST(0x7641af00), FXP_CAST(0xe44621e0)}, {FXP_CAST(0x0a0aec80), FXP_CAST(0x89be5100), FXP_CAST(0x61fb5c00)}, +{FXP_CAST(0x85a89100), FXP_CAST(0x30fbc540), FXP_CAST(0x76555780)}, {FXP_CAST(0xc094d500), FXP_CAST(0x30fbc540), FXP_CAST(0x0b71f790)}, {FXP_CAST(0x5eac4000), FXP_CAST(0x89be5100), FXP_CAST(0x94401a80)}, +{FXP_CAST(0x68b91d80), FXP_CAST(0x7641af00), FXP_CAST(0x90ea3980)}, {FXP_CAST(0xcf043440), FXP_CAST(0xcf043ac0), FXP_CAST(0x05067a08)}, {FXP_CAST(0x81e7f180), FXP_CAST(0xcf043ac0), FXP_CAST(0x73bb6d00)}, +{FXP_CAST(0xf9f871e0), FXP_CAST(0x7641af00), FXP_CAST(0x65ff0e00)}, {FXP_CAST(0x7b76a000), FXP_CAST(0x89be5100), FXP_CAST(0xea9664c0)}, {FXP_CAST(0x3be518c0), FXP_CAST(0x30fbc540), FXP_CAST(0x8633e880)}, +{FXP_CAST(0x9eaaff00), FXP_CAST(0x30fbc540), FXP_CAST(0xa4c84500)}, {FXP_CAST(0x99a3f400), FXP_CAST(0x89be5100), FXP_CAST(0x2571eac0)}, {FXP_CAST(0x34ac8840), FXP_CAST(0x7641af00), FXP_CAST(0x7dd82b00)}, +{FXP_CAST(0x7d572a80), FXP_CAST(0xcf043ac0), FXP_CAST(0x4eed8400)}, {FXP_CAST(0x0202a9c4), FXP_CAST(0xcf043ac0), FXP_CAST(0xcb249700)}, {FXP_CAST(0x83896000), FXP_CAST(0x7641af00), FXP_CAST(0x80318200)}, +{FXP_CAST(0xc7b01b00), FXP_CAST(0x89be5100), FXP_CAST(0xbeab7580)}, {FXP_CAST(0x63e52a80), FXP_CAST(0x30fbc540), FXP_CAST(0x4364b700)}, {FXP_CAST(0x63e51f00), FXP_CAST(0x30fbc540), FXP_CAST(0x7fa6bd00)}, +{FXP_CAST(0xc7b00a00), FXP_CAST(0x89be5100), FXP_CAST(0x32a67940)}, {FXP_CAST(0x83896400), FXP_CAST(0x7641af00), FXP_CAST(0xaf2fd200)}, {FXP_CAST(0x0202bc9c), FXP_CAST(0xcf043ac0), FXP_CAST(0x829e6e80)}, +{FXP_CAST(0x7d572e80), FXP_CAST(0xcf043ac0), FXP_CAST(0xdcde6b80)}, {FXP_CAST(0x34ac7700), FXP_CAST(0x7641af00), FXP_CAST(0x5ce4e280)}, {FXP_CAST(0x99a3e880), FXP_CAST(0x89be5100), FXP_CAST(0x79089c00)}, +{FXP_CAST(0x9eab0b80), FXP_CAST(0x30fbc540), FXP_CAST(0x1307ae80)}, {FXP_CAST(0x3be52980), FXP_CAST(0x30fbc540), FXP_CAST(0x98906880)}, {FXP_CAST(0x7b769b00), FXP_CAST(0x89be5100), FXP_CAST(0x8d51b300)}, +{FXP_CAST(0xf9f85f10), FXP_CAST(0x7641af00), FXP_CAST(0xfd62ee24)}, {FXP_CAST(0x81e7ee00), FXP_CAST(0xcf043ac0), FXP_CAST(0x70439680)}, {FXP_CAST(0xcf044580), FXP_CAST(0xcf043ac0), FXP_CAST(0x6a6d9600)}, +{FXP_CAST(0x68b92800), FXP_CAST(0x7641af00), FXP_CAST(0xf2275f80)}}; + +const FIXP_PS aaFractDelayPhaseFactorSerReSubQmf20[NO_SUB_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS] = { +{FXP_CAST(0x7e2df000), FXP_CAST(0x7a7d0580), FXP_CAST(0x7ed03e00)}, {FXP_CAST(0x6fec9a80), FXP_CAST(0x5133cc80), FXP_CAST(0x7573df00)}, {FXP_CAST(0x55063900), FXP_CAST(0x0c8bd360), FXP_CAST(0x636c0400)}, +{FXP_CAST(0x3084ca00), FXP_CAST(0xc3a94580), FXP_CAST(0x4a0d6700)}, {FXP_CAST(0x80000000), FXP_CAST(0x80000000), FXP_CAST(0x80000000)}, {FXP_CAST(0x80000000), FXP_CAST(0x80000000), FXP_CAST(0x80000000)}, +{FXP_CAST(0x6fec9a80), FXP_CAST(0x5133cc80), FXP_CAST(0x7573df00)}, {FXP_CAST(0x7e2df000), FXP_CAST(0x7a7d0580), FXP_CAST(0x7ed03e00)}, {FXP_CAST(0xa4c84280), FXP_CAST(0xb8e31300), FXP_CAST(0xd5af0140)}, +{FXP_CAST(0xf0f488a0), FXP_CAST(0x8275a100), FXP_CAST(0x1a72e360)}, {FXP_CAST(0x80aaa680), FXP_CAST(0x471ced00), FXP_CAST(0x9d2ead80)}, {FXP_CAST(0x9477d100), FXP_CAST(0x7d8a5f00), FXP_CAST(0x8151df80)}}; + +const FIXP_PS aaFractDelayPhaseFactorSerImSubQmf20[NO_SUB_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS] = { +{FXP_CAST(0xea7d08a0), FXP_CAST(0xdad7f3c0), FXP_CAST(0xee9c9f60)}, {FXP_CAST(0xc1e54140), FXP_CAST(0x9d0dfe80), FXP_CAST(0xcd1e7300)}, {FXP_CAST(0xa051a580), FXP_CAST(0x809dc980), FXP_CAST(0xaf61c400)}, +{FXP_CAST(0x898d4e00), FXP_CAST(0x8f1d3400), FXP_CAST(0x97988280)}, {FXP_CAST(0x00000000), FXP_CAST(0x00000000), FXP_CAST(0x00000000)}, {FXP_CAST(0x00000000), FXP_CAST(0x00000000), FXP_CAST(0x00000000)}, +{FXP_CAST(0x3e1abec0), FXP_CAST(0x62f20180), FXP_CAST(0x32e18d00)}, {FXP_CAST(0x1582f760), FXP_CAST(0x25280c40), FXP_CAST(0x116360a0)}, {FXP_CAST(0xa6343800), FXP_CAST(0x6a6d9880), FXP_CAST(0x87327a00)}, +{FXP_CAST(0x80e32200), FXP_CAST(0xe70747c0), FXP_CAST(0x82c32b00)}, {FXP_CAST(0xf2f42420), FXP_CAST(0x6a6d9880), FXP_CAST(0xaea47080)}, {FXP_CAST(0x456eba00), FXP_CAST(0xe70747c0), FXP_CAST(0xedaa8640)}}; + +const FIXP_PS p8_13_20[13] = +{ + FL2FXCONST_PS(0.00746082949812f), FL2FXCONST_PS(0.02270420949825f), FL2FXCONST_PS(0.04546865930473f), FL2FXCONST_PS(0.07266113929591f), + FL2FXCONST_PS(0.09885108575264f), FL2FXCONST_PS(0.11793710567217f), FL2FXCONST_PS(0.125f ), FL2FXCONST_PS(0.11793710567217f), + FL2FXCONST_PS(0.09885108575264f), FL2FXCONST_PS(0.07266113929591f), FL2FXCONST_PS(0.04546865930473f), FL2FXCONST_PS(0.02270420949825f), + FL2FXCONST_PS(0.00746082949812f) +}; + +const FIXP_PS p2_13_20[13] = +{ + FL2FXCONST_PS(0.0f), FL2FXCONST_PS( 0.01899487526049f), FL2FXCONST_PS(0.0f), FL2FXCONST_PS(-0.07293139167538f), + FL2FXCONST_PS(0.0f), FL2FXCONST_PS( 0.30596630545168f), FL2FXCONST_PS(0.5f), FL2FXCONST_PS( 0.30596630545168f), + FL2FXCONST_PS(0.0f), FL2FXCONST_PS(-0.07293139167538f), FL2FXCONST_PS(0.0f), FL2FXCONST_PS( 0.01899487526049f), + FL2FXCONST_PS(0.0f) +}; + + + +const UCHAR aAllpassLinkDelaySer[] = { 3, 4, 5}; + +const UCHAR delayIndexQmf[NO_QMF_CHANNELS] = { + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +}; + +const UCHAR groupBorders20[NO_IID_GROUPS + 1] = +{ + 6, 7, 0, 1, 2, 3, /* 6 subqmf subbands - 0th qmf subband */ + 9, 8, /* 2 subqmf subbands - 1st qmf subband */ + 10, 11, /* 2 subqmf subbands - 2nd qmf subband */ + 3, 4, 5, 6, 7, 8, + 9, 11, 14, 18, 23, 35, 64 +}; + +const UCHAR groupBorders34[NO_IID_GROUPS_HI_RES + 1] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, /* 12 subqmf subbands - 0th qmf subband */ + 12, 13, 14, 15, 16, 17, 18, 19, /* 8 subqmf subbands - 1st qmf subband */ + 20, 21, 22, 23, /* 4 subqmf subbands - 2nd qmf subband */ + 24, 25, 26, 27, /* 4 subqmf subbands - 3nd qmf subband */ + 28, 29, 30, 31, /* 4 subqmf subbands - 4nd qmf subband */ + 32-27, 33-27, 34-27, 35-27, 36-27, 37-27, 38-27, + 40-27, 42-27, 44-27, 46-27, 48-27, 51-27, 54-27, + 57-27, 60-27, 64-27, 68-27, 91-27 +}; + +const UCHAR bins2groupMap20[NO_IID_GROUPS] = +{ + 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 +}; + +const UCHAR quantizedIIDs[NO_IID_STEPS] = +{ + 2, 4, 7, 10, 14, 18, 25 +}; +const UCHAR quantizedIIDsFine[NO_IID_STEPS_FINE] = +{ + 2, 4, 6, 8, 10, 13, 16, 19, 22, 25, 30, 35, 40, 45, 50 +}; + +const UCHAR FDK_sbrDecoder_aNoIidBins[3] = {NO_LOW_RES_IID_BINS, + NO_MID_RES_IID_BINS, + NO_HI_RES_IID_BINS}; + +const UCHAR FDK_sbrDecoder_aNoIccBins[3] = {NO_LOW_RES_ICC_BINS, + NO_MID_RES_ICC_BINS, + NO_HI_RES_ICC_BINS}; + + + +/************************************************************************/ +/*! + \brief Create lookup tables for some arithmetic functions + + The tables would normally be defined as const arrays, + but initialization at run time allows to specify their accuracy. +*/ +/************************************************************************/ + +/* 1/x-table: (example for INV_TABLE_BITS 8) + + The table covers an input range from 0.5 to 1.0 with a step size of 1/512, + starting at 0.5 + 1/512. + Each table entry corresponds to an input interval starting 1/1024 below the + exact value and ending 1/1024 above it. + + The table is actually a 0.5/x-table, so that the output range is again + 0.5...1.0 and the exponent of the result must be increased by 1. + + Input range Index in table result + ------------------------------------------------------------------- + 0.500000...0.500976 - 0.5 / 0.500000 = 1.000000 + 0.500976...0.502930 0 0.5 / 0.501953 = 0.996109 + 0.502930...0.500488 1 0.5 / 0.503906 = 0.992248 + ... + 0.999023...1.000000 255 0.5 / 1.000000 = 0.500000 + + for (i=0; i=0.5 + FRACT_BITS-1 zero e.g |max| = 0 +\endverbatim + + Dynamic scaling is used to achieve sufficient accuracy even when the signal + energy is low. The dynamic framing of SBR produces a variable overlap area + where samples from the previous QMF-Analysis are stored. Depending on the + start position and stop position of the current SBR envelopes, the processing + buffer consists of differently scaled regions like illustrated in the below + figure. + + \image html scales.png Scale +*/ + + +#endif diff --git a/libSBRdec/src/sbrdec_drc.cpp b/libSBRdec/src/sbrdec_drc.cpp new file mode 100644 index 0000000..a07f8fe --- /dev/null +++ b/libSBRdec/src/sbrdec_drc.cpp @@ -0,0 +1,450 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Christian Griebel + Description: Dynamic range control (DRC) decoder tool for SBR + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "sbrdec_drc.h" + + +/* DRC - Offset table for QMF interpolation. */ +static const int offsetTab[2][16] = +{ + { 0, 4, 8, 12, 16, 20, 24, 28, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 1024 framing */ + { 0, 4, 8, 12, 16, 19, 22, 26, 0, 0, 0, 0, 0, 0, 0, 0 } /* 960 framing */ +}; + +/*! + \brief Initialize DRC QMF factors + + \hDrcData Handle to DRC channel data. + + \return none +*/ +void sbrDecoder_drcInitChannel ( + HANDLE_SBR_DRC_CHANNEL hDrcData ) +{ + int band; + + if (hDrcData == NULL) { + return; + } + + for (band = 0; band < (64); band++) { + hDrcData->prevFact_mag[band] = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/; + } + + for (band = 0; band < SBRDEC_MAX_DRC_BANDS; band++) { + hDrcData->currFact_mag[band] = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/; + hDrcData->nextFact_mag[band] = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/; + } + + hDrcData->prevFact_exp = 0; + hDrcData->currFact_exp = 0; + hDrcData->nextFact_exp = 0; + + hDrcData->numBandsCurr = 0; + hDrcData->numBandsNext = 0; + + hDrcData->winSequenceCurr = 0; + hDrcData->winSequenceNext = 0; + + hDrcData->drcInterpolationSchemeCurr = 0; + hDrcData->drcInterpolationSchemeNext = 0; + + hDrcData->enable = 0; +} + + +/*! + \brief Swap DRC QMF scaling factors after they have been applied. + + \hDrcData Handle to DRC channel data. + + \return none +*/ +void sbrDecoder_drcUpdateChannel ( + HANDLE_SBR_DRC_CHANNEL hDrcData ) +{ + if (hDrcData == NULL) { + return; + } + if (hDrcData->enable != 1) { + return; + } + + /* swap previous data */ + FDKmemcpy( hDrcData->currFact_mag, + hDrcData->nextFact_mag, + SBRDEC_MAX_DRC_BANDS * sizeof(FIXP_DBL) ); + + hDrcData->currFact_exp = hDrcData->nextFact_exp; + + hDrcData->numBandsCurr = hDrcData->numBandsNext; + + FDKmemcpy( hDrcData->bandTopCurr, + hDrcData->bandTopNext, + SBRDEC_MAX_DRC_BANDS * sizeof(USHORT) ); + + hDrcData->drcInterpolationSchemeCurr = hDrcData->drcInterpolationSchemeNext; + + hDrcData->winSequenceCurr = hDrcData->winSequenceNext; +} + + +/*! + \brief Apply DRC factors slot based. + + \hDrcData Handle to DRC channel data. + \qmfRealSlot Pointer to real valued QMF data of one time slot. + \qmfImagSlot Pointer to the imaginary QMF data of one time slot. + \col Number of the time slot. + \numQmfSubSamples Total number of time slots for one frame. + \scaleFactor Pointer to the out scale factor of the time slot. + + \return None. +*/ +void sbrDecoder_drcApplySlot ( + HANDLE_SBR_DRC_CHANNEL hDrcData, + FIXP_DBL *qmfRealSlot, + FIXP_DBL *qmfImagSlot, + int col, + int numQmfSubSamples, + int maxShift + ) +{ + const int *offset; + + int band, bottomMdct, topMdct, bin, useLP; + int indx = numQmfSubSamples - (numQmfSubSamples >> 1) - 10; /* l_border */ + int frameLenFlag = (numQmfSubSamples == 30) ? 1 : 0; + + const FIXP_DBL *fact_mag = NULL; + INT fact_exp = 0; + UINT numBands = 0; + USHORT *bandTop = NULL; + int shortDrc = 0; + + FIXP_DBL alphaValue = FL2FXCONST_DBL(0.0f); + + if (hDrcData == NULL) { + return; + } + if (hDrcData->enable != 1) { + return; + } + + offset = offsetTab[frameLenFlag]; + + useLP = (qmfImagSlot == NULL) ? 1 : 0; + + col += indx; + bottomMdct = 0; + bin = 0; + + /* get respective data and calc interpolation factor */ + if (col < (numQmfSubSamples>>1)) { /* first half of current frame */ + if (hDrcData->winSequenceCurr != 2) { /* long window */ + int j = col + (numQmfSubSamples>>1); + + if (hDrcData->drcInterpolationSchemeCurr == 0) { + INT k = (frameLenFlag) ? 0x4444444 : 0x4000000; + + alphaValue = (FIXP_DBL)(j * k); + } + else { + if (j >= offset[hDrcData->drcInterpolationSchemeCurr - 1]) { + alphaValue = FL2FXCONST_DBL(1.0f); + } + } + } + else { /* short windows */ + shortDrc = 1; + } + + fact_mag = hDrcData->currFact_mag; + fact_exp = hDrcData->currFact_exp; + numBands = hDrcData->numBandsCurr; + bandTop = hDrcData->bandTopCurr; + } + else if (col < numQmfSubSamples) { /* second half of current frame */ + if (hDrcData->winSequenceNext != 2) { /* next: long window */ + int j = col - (numQmfSubSamples>>1); + + if (hDrcData->drcInterpolationSchemeNext == 0) { + INT k = (frameLenFlag) ? 0x4444444 : 0x4000000; + + alphaValue = (FIXP_DBL)(j * k); + } + else { + if (j >= offset[hDrcData->drcInterpolationSchemeNext - 1]) { + alphaValue = FL2FXCONST_DBL(1.0f); + } + } + + fact_mag = hDrcData->nextFact_mag; + fact_exp = hDrcData->nextFact_exp; + numBands = hDrcData->numBandsNext; + bandTop = hDrcData->bandTopNext; + } + else { /* next: short windows */ + if (hDrcData->winSequenceCurr != 2) { /* current: long window */ + alphaValue = (FIXP_DBL)0; + + fact_mag = hDrcData->nextFact_mag; + fact_exp = hDrcData->nextFact_exp; + numBands = hDrcData->numBandsNext; + bandTop = hDrcData->bandTopNext; + } + else { /* current: short windows */ + shortDrc = 1; + + fact_mag = hDrcData->currFact_mag; + fact_exp = hDrcData->currFact_exp; + numBands = hDrcData->numBandsCurr; + bandTop = hDrcData->bandTopCurr; + } + } + } + else { /* first half of next frame */ + if (hDrcData->winSequenceNext != 2) { /* long window */ + int j = col - (numQmfSubSamples>>1); + + if (hDrcData->drcInterpolationSchemeNext == 0) { + INT k = (frameLenFlag) ? 0x4444444 : 0x4000000; + + alphaValue = (FIXP_DBL)(j * k); + } + else { + if (j >= offset[hDrcData->drcInterpolationSchemeNext - 1]) { + alphaValue = FL2FXCONST_DBL(1.0f); + } + } + } + else { /* short windows */ + shortDrc = 1; + } + + fact_mag = hDrcData->nextFact_mag; + fact_exp = hDrcData->nextFact_exp; + numBands = hDrcData->numBandsNext; + bandTop = hDrcData->bandTopNext; + + col -= numQmfSubSamples; + } + + + /* process bands */ + for (band = 0; band < (int)numBands; band++) { + int bottomQmf, topQmf; + + FIXP_DBL drcFact_mag = FL2FXCONST_DBL(1.0f); + + topMdct = (bandTop[band]+1) << 2; + + if (!shortDrc) { /* long window */ + if (frameLenFlag) { + /* 960 framing */ + bottomMdct = 30 * (bottomMdct / 30); + topMdct = 30 * (topMdct / 30); + + bottomQmf = fMultIfloor((FIXP_DBL)0x4444444, bottomMdct); + topQmf = fMultIfloor((FIXP_DBL)0x4444444, topMdct); + } + else { + /* 1024 framing */ + bottomMdct &= ~0x1f; + topMdct &= ~0x1f; + + bottomQmf = bottomMdct >> 5; + topQmf = topMdct >> 5; + } + + if (band == ((int)numBands-1)) { + topQmf = (64); + } + + for (bin = bottomQmf; bin < topQmf; bin++) { + FIXP_DBL drcFact1_mag = hDrcData->prevFact_mag[bin]; + FIXP_DBL drcFact2_mag = fact_mag[band]; + + /* normalize scale factors */ + if (hDrcData->prevFact_exp < maxShift) { + drcFact1_mag >>= maxShift - hDrcData->prevFact_exp; + } + if (fact_exp < maxShift) { + drcFact2_mag >>= maxShift - fact_exp; + } + + /* interpolate */ + drcFact_mag = fMult(alphaValue, drcFact2_mag) + fMult((FL2FXCONST_DBL(1.0f) - alphaValue), drcFact1_mag); + + /* apply scaling */ + qmfRealSlot[bin] = fMult(qmfRealSlot[bin], drcFact_mag); + if (!useLP) { + qmfImagSlot[bin] = fMult(qmfImagSlot[bin], drcFact_mag); + } + + /* save previous factors */ + if (col == (numQmfSubSamples>>1)-1) { + hDrcData->prevFact_mag[bin] = fact_mag[band]; + } + } + } + else { /* short windows */ + int startSample, stopSample; + FIXP_DBL invFrameSizeDiv8 = (frameLenFlag) ? (FIXP_DBL)0x1111111 : (FIXP_DBL)0x1000000; + + if (frameLenFlag) { + /* 960 framing */ + bottomMdct = 30/8 * (bottomMdct*8/30); + topMdct = 30/8 * (topMdct*8/30); + } + else { + /* 1024 framing */ + bottomMdct &= ~0x03; + topMdct &= ~0x03; + } + + /* startSample is truncated to the nearest corresponding start subsample in + the QMF of the short window bottom is present in:*/ + startSample = ((fMultIfloor( invFrameSizeDiv8, bottomMdct ) & 0x7) * numQmfSubSamples) >> 3; + + /* stopSample is rounded upwards to the nearest corresponding stop subsample + in the QMF of the short window top is present in. */ + stopSample = ((fMultIceil( invFrameSizeDiv8, topMdct ) & 0xf) * numQmfSubSamples) >> 3; + + bottomQmf = fMultIfloor( invFrameSizeDiv8, ((bottomMdct%(numQmfSubSamples<<2)) << 5) ); + topQmf = fMultIfloor( invFrameSizeDiv8, ((topMdct%(numQmfSubSamples<<2)) << 5) ); + + /* extend last band */ + if (band == ((int)numBands-1)) { + topQmf = (64); + stopSample = numQmfSubSamples; + } + + if (topQmf == 0) { + topQmf = (64); + } + + /* save previous factors */ + if (stopSample == numQmfSubSamples) { + int tmpBottom = bottomQmf; + + if (((numQmfSubSamples-1) & ~0x03) > startSample) { + tmpBottom = 0; /* band starts in previous short window */ + } + + for (bin = tmpBottom; bin < topQmf; bin++) { + hDrcData->prevFact_mag[bin] = fact_mag[band]; + } + } + + /* apply */ + if ((col >= startSample) && (col < stopSample)) { + if ((col & ~0x03) > startSample) { + bottomQmf = 0; /* band starts in previous short window */ + } + if (col < ((stopSample-1) & ~0x03)) { + topQmf = (64); /* band ends in next short window */ + } + + drcFact_mag = fact_mag[band]; + + /* normalize scale factor */ + if (fact_exp < maxShift) { + drcFact_mag >>= maxShift - fact_exp; + } + + /* apply scaling */ + for (bin = bottomQmf; bin < topQmf; bin++) { + qmfRealSlot[bin] = fMult(qmfRealSlot[bin], drcFact_mag); + if (!useLP) { + qmfImagSlot[bin] = fMult(qmfImagSlot[bin], drcFact_mag); + } + } + } + } + + bottomMdct = topMdct; + } /* end of bands loop */ + + if (col == (numQmfSubSamples>>1)-1) { + hDrcData->prevFact_exp = fact_exp; + } +} + + +/*! + \brief Apply DRC factors frame based. + + \hDrcData Handle to DRC channel data. + \qmfRealSlot Pointer to real valued QMF data of the whole frame. + \qmfImagSlot Pointer to the imaginary QMF data of the whole frame. + \numQmfSubSamples Total number of time slots for one frame. + \scaleFactor Pointer to the out scale factor of the frame. + + \return None. +*/ +void sbrDecoder_drcApply ( + HANDLE_SBR_DRC_CHANNEL hDrcData, + FIXP_DBL **QmfBufferReal, + FIXP_DBL **QmfBufferImag, + int numQmfSubSamples, + int *scaleFactor + ) +{ + int col; + int maxShift = 0; + + /* get max scale factor */ + if (hDrcData->prevFact_exp > maxShift) { + maxShift = hDrcData->prevFact_exp; + } + if (hDrcData->currFact_exp > maxShift) { + maxShift = hDrcData->currFact_exp; + } + if (hDrcData->nextFact_exp > maxShift) { + maxShift = hDrcData->nextFact_exp; + } + + for (col = 0; col < numQmfSubSamples; col++) + { + FIXP_DBL *qmfSlotReal = QmfBufferReal[col]; + FIXP_DBL *qmfSlotImag = (QmfBufferImag == NULL) ? NULL : QmfBufferImag[col]; + + sbrDecoder_drcApplySlot ( + hDrcData, + qmfSlotReal, + qmfSlotImag, + col, + numQmfSubSamples, + maxShift + ); + } + + *scaleFactor += maxShift; +} + diff --git a/libSBRdec/src/sbrdec_drc.h b/libSBRdec/src/sbrdec_drc.h new file mode 100644 index 0000000..a200c47 --- /dev/null +++ b/libSBRdec/src/sbrdec_drc.h @@ -0,0 +1,88 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Christian Griebel + Description: Dynamic range control (DRC) decoder tool for SBR + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef _SBRDEC_DRC_H_ +#define _SBRDEC_DRC_H_ + +#include "sbrdecoder.h" + + +#define SBRDEC_MAX_DRC_CHANNELS (6) +#define SBRDEC_MAX_DRC_BANDS ( 16 ) + +typedef struct +{ + FIXP_DBL prevFact_mag[(64)]; + INT prevFact_exp; + + FIXP_DBL currFact_mag[SBRDEC_MAX_DRC_BANDS]; + FIXP_DBL nextFact_mag[SBRDEC_MAX_DRC_BANDS]; + INT currFact_exp; + INT nextFact_exp; + + UINT numBandsCurr; + UINT numBandsNext; + USHORT bandTopCurr[SBRDEC_MAX_DRC_BANDS]; + USHORT bandTopNext[SBRDEC_MAX_DRC_BANDS]; + + SHORT drcInterpolationSchemeCurr; + SHORT drcInterpolationSchemeNext; + + SHORT enable; + + UCHAR winSequenceCurr; + UCHAR winSequenceNext; + +} SBRDEC_DRC_CHANNEL; + +typedef SBRDEC_DRC_CHANNEL * HANDLE_SBR_DRC_CHANNEL; + + +void sbrDecoder_drcInitChannel ( + HANDLE_SBR_DRC_CHANNEL hDrcData ); + +void sbrDecoder_drcUpdateChannel ( + HANDLE_SBR_DRC_CHANNEL hDrcData ); + +void sbrDecoder_drcApplySlot ( + HANDLE_SBR_DRC_CHANNEL hDrcData, + FIXP_DBL *qmfRealSlot, + FIXP_DBL *qmfImagSlot, + int col, + int numQmfSubSamples, + int maxShift ); + +void sbrDecoder_drcApply ( + HANDLE_SBR_DRC_CHANNEL hDrcData, + FIXP_DBL **QmfBufferReal, + FIXP_DBL **QmfBufferImag, + int numQmfSubSamples, + int *scaleFactor ); + + +#endif /* _SBRDEC_DRC_H_ */ diff --git a/libSBRdec/src/sbrdec_freq_sca.cpp b/libSBRdec/src/sbrdec_freq_sca.cpp new file mode 100644 index 0000000..f48c7d0 --- /dev/null +++ b/libSBRdec/src/sbrdec_freq_sca.cpp @@ -0,0 +1,749 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Frequency scale calculation $Revision: 36841 $ +*/ + +#include "sbrdec_freq_sca.h" + +#include "transcendent.h" +#include "sbr_rom.h" +#include "env_extr.h" + +#include "genericStds.h" /* need log() for debug-code only */ + +#define MAX_OCTAVE 29 +#define MAX_SECOND_REGION 50 + + +static int numberOfBands(FIXP_SGL bpo_div16, int start, int stop, int warpFlag); +static void CalcBands(UCHAR * diff, UCHAR start, UCHAR stop, UCHAR num_bands); +static SBR_ERROR modifyBands(UCHAR max_band, UCHAR * diff, UCHAR length); +static void cumSum(UCHAR start_value, UCHAR* diff, UCHAR length, UCHAR *start_adress); + + + +/*! + \brief Retrieve QMF-band where the SBR range starts + + Convert startFreq which was read from the bitstream into a + QMF-channel number. + + \return Number of start band +*/ +static UCHAR +getStartBand(UINT fs, /*!< Output sampling frequency */ + UCHAR startFreq, /*!< Index to table of possible start bands */ + UINT headerDataFlags) /*!< Info to SBR mode */ +{ + INT band; + UINT fsMapped; + + fsMapped = fs; + + switch (fsMapped) { + case 48000: + band = FDK_sbrDecoder_sbr_start_freq_48[startFreq]; + break; + case 44100: + band = FDK_sbrDecoder_sbr_start_freq_44[startFreq]; + break; + case 32000: + band = FDK_sbrDecoder_sbr_start_freq_32[startFreq]; + break; + case 24000: + band = FDK_sbrDecoder_sbr_start_freq_24[startFreq]; + break; + case 22050: + band = FDK_sbrDecoder_sbr_start_freq_22[startFreq]; + break; + case 16000: + band = FDK_sbrDecoder_sbr_start_freq_16[startFreq]; + break; + default: + band = 255; + } + + return band; +} + + +/*! + \brief Retrieve QMF-band where the SBR range starts + + Convert startFreq which was read from the bitstream into a + QMF-channel number. + + \return Number of start band +*/ +static UCHAR +getStopBand(UINT fs, /*!< Output sampling frequency */ + UCHAR stopFreq, /*!< Index to table of possible start bands */ + UINT headerDataFlags, /*!< Info to SBR mode */ + UCHAR k0) /*!< Start freq index */ +{ + UCHAR k2; + + if (stopFreq < 14) { + INT stopMin; + UCHAR diff_tot[MAX_OCTAVE + MAX_SECOND_REGION]; + UCHAR *diff0 = diff_tot; + UCHAR *diff1 = diff_tot+MAX_OCTAVE; + + if (fs < 32000) { + stopMin = (((2*6000*2*(64)) / fs) + 1) >> 1; + } + else { + if (fs < 64000) { + stopMin = (((2*8000*2*(64)) / fs) + 1) >> 1; + } + else { + stopMin = (((2*10000*2*(64)) / fs) + 1) >> 1; + } + } + + /* + Choose a stop band between k1 and 64 depending on stopFreq (0..13), + based on a logarithmic scale. + The vectors diff0 and diff1 are used temporarily here. + */ + CalcBands( diff0, stopMin, 64, 13); + shellsort( diff0, 13); + cumSum(stopMin, diff0, 13, diff1); + k2 = diff1[stopFreq]; + } + else if (stopFreq==14) + k2 = 2*k0; + else + k2 = 3*k0; + + /* Limit to Nyquist */ + if (k2 > (64)) + k2 = (64); + + + /* Range checks */ + /* 1 <= difference <= 48; 1 <= fs <= 96000 */ + if ( ((k2 - k0) > MAX_FREQ_COEFFS) || (k2 <= k0) ) { + return 255; + } + + if (headerDataFlags & (SBRDEC_SYNTAX_USAC|SBRDEC_SYNTAX_RSVD50)) { + /* 1 <= difference <= 35; 42000 <= fs <= 96000 */ + if ( (fs >= 42000) && ( (k2 - k0) > MAX_FREQ_COEFFS_FS44100 ) ) { + return 255; + } + /* 1 <= difference <= 32; 46009 <= fs <= 96000 */ + if ( (fs >= 46009) && ( (k2 - k0) > MAX_FREQ_COEFFS_FS48000 ) ) { + return 255; + } + } + else { + /* 1 <= difference <= 35; fs == 44100 */ + if ( (fs == 44100) && ( (k2 - k0) > MAX_FREQ_COEFFS_FS44100 ) ) { + return 255; + } + /* 1 <= difference <= 32; 48000 <= fs <= 96000 */ + if ( (fs >= 48000) && ( (k2 - k0) > MAX_FREQ_COEFFS_FS48000 ) ) { + return 255; + } + } + + return k2; +} + + +/*! + \brief Generates master frequency tables + + Frequency tables are calculated according to the selected domain + (linear/logarithmic) and granularity. + IEC 14496-3 4.6.18.3.2.1 + + \return errorCode, 0 if successful +*/ +SBR_ERROR +sbrdecUpdateFreqScale(UCHAR * v_k_master, /*!< Master table to be created */ + UCHAR *numMaster, /*!< Number of entries in master table */ + UINT fs, /*!< SBR working sampling rate */ + HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Control data from bitstream */ + UINT flags) +{ + FIXP_SGL bpo_div16; /* bands_per_octave divided by 16 */ + INT dk=0; + + /* Internal variables */ + UCHAR k0, k2, i; + UCHAR num_bands0 = 0; + UCHAR num_bands1 = 0; + UCHAR diff_tot[MAX_OCTAVE + MAX_SECOND_REGION]; + UCHAR *diff0 = diff_tot; + UCHAR *diff1 = diff_tot+MAX_OCTAVE; + INT k2_achived; + INT k2_diff; + INT incr=0; + + /* + Determine start band + */ + k0 = getStartBand(fs, hHeaderData->bs_data.startFreq, flags); + if (k0 == 255) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + /* + Determine stop band + */ + k2 = getStopBand(fs, hHeaderData->bs_data.stopFreq, flags, k0); + if (k2 == 255) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + if(hHeaderData->bs_data.freqScale>0) { /* Bark */ + INT k1; + + if(hHeaderData->bs_data.freqScale==1) { + bpo_div16 = FL2FXCONST_SGL(12.0f/16.0f); + } + else if(hHeaderData->bs_data.freqScale==2) { + bpo_div16 = FL2FXCONST_SGL(10.0f/16.0f); + } + else { + bpo_div16 = FL2FXCONST_SGL(8.0f/16.0f); + } + + + if( 1000 * k2 > 2245 * k0 ) { /* Two or more regions */ + k1 = 2*k0; + + num_bands0 = numberOfBands(bpo_div16, k0, k1, 0); + num_bands1 = numberOfBands(bpo_div16, k1, k2, hHeaderData->bs_data.alterScale ); + if ( num_bands0 < 1) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + if ( num_bands1 < 1 ) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + CalcBands(diff0, k0, k1, num_bands0); + shellsort( diff0, num_bands0); + if (diff0[0] == 0) { +#ifdef DEBUG_TOOLS +#endif + return SBRDEC_UNSUPPORTED_CONFIG; + } + + cumSum(k0, diff0, num_bands0, v_k_master); + + CalcBands(diff1, k1, k2, num_bands1); + shellsort( diff1, num_bands1); + if(diff0[num_bands0-1] > diff1[0]) { + SBR_ERROR err; + + err = modifyBands(diff0[num_bands0-1],diff1, num_bands1); + if (err) + return SBRDEC_UNSUPPORTED_CONFIG; + } + + /* Add 2nd region */ + cumSum(k1, diff1, num_bands1, &v_k_master[num_bands0]); + *numMaster = num_bands0 + num_bands1; /* Output nr of bands */ + + } + else { /* Only one region */ + k1=k2; + + num_bands0 = numberOfBands(bpo_div16, k0, k1, 0); + if ( num_bands0 < 1) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + CalcBands(diff0, k0, k1, num_bands0); + shellsort(diff0, num_bands0); + if (diff0[0] == 0) { +#ifdef DEBUG_TOOLS +#endif + return SBRDEC_UNSUPPORTED_CONFIG; + } + + cumSum(k0, diff0, num_bands0, v_k_master); + *numMaster = num_bands0; /* Output nr of bands */ + + } + } + else { /* Linear mode */ + if (hHeaderData->bs_data.alterScale==0) { + dk = 1; + /* FLOOR to get to few number of bands (next lower even number) */ + num_bands0 = (k2 - k0) & 254; + } else { + dk = 2; + num_bands0 = ( ((k2 - k0) >> 1) + 1 ) & 254; /* ROUND to the closest fit */ + } + + if (num_bands0 < 1) { + return SBRDEC_UNSUPPORTED_CONFIG; + /* We must return already here because 'i' can become negative below. */ + } + + k2_achived = k0 + num_bands0*dk; + k2_diff = k2 - k2_achived; + + for(i=0;i 0) { + incr = -1; + i = num_bands0-1; + } + + /* Adjust diff vector to get sepc. SBR range */ + while (k2_diff != 0) { + diff_tot[i] = diff_tot[i] - incr; + i = i + incr; + k2_diff = k2_diff + incr; + } + + cumSum(k0, diff_tot, num_bands0, v_k_master);/* cumsum */ + *numMaster = num_bands0; /* Output nr of bands */ + } + + if (*numMaster < 1) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + + /* + Print out the calculated table + */ + + return SBRDEC_OK; +} + + +/*! + \brief Calculate frequency ratio of one SBR band + + All SBR bands should span a constant frequency range in the logarithmic + domain. This function calculates the ratio of any SBR band's upper and lower + frequency. + + \return num_band-th root of k_start/k_stop +*/ +static FIXP_SGL calcFactorPerBand(int k_start, int k_stop, int num_bands) +{ +/* Changes CT fract class -> IIS fract class: + * scaled bandfactor and step 1 bit right to avoid overflow + * use CTdbouble data type */ + FIXP_DBL bandfactor = FL2FXCONST_DBL(0.25f); /* Start value */ + FIXP_DBL step = FL2FXCONST_DBL(0.125f); /* Initial increment for factor */ + + int direction = 1; + +/* Changes CT fract class -> IIS fract class: + * because saturation can't be done in INT IIS, + * changed start and stop data type from FIXP_SGL to FIXP_DBL */ + FIXP_DBL start = k_start << (DFRACT_BITS-8); + FIXP_DBL stop = k_stop << (DFRACT_BITS-8); + + FIXP_DBL temp; + + int j, i=0; + + while ( step > FL2FXCONST_DBL(0.0f)) { + i++; + temp = stop; + + /* Calculate temp^num_bands: */ + for (j=0; j> 1); + direction = 1; + bandfactor = bandfactor + step; + } + else { /* Factor is too weak: make it stronger */ + if (direction == 1) + step = (FIXP_DBL)((LONG)step >> 1); + direction = 0; + bandfactor = bandfactor - step; + } + + if (i>100) { + step = FL2FXCONST_DBL(0.0f); + } + } + return FX_DBL2FX_SGL(bandfactor<<1); +} + + +/*! + \brief Calculate number of SBR bands between start and stop band + + Given the number of bands per octave, this function calculates how many + bands fit in the given frequency range. + When the warpFlag is set, the 'band density' is decreased by a factor + of 1/1.3 + + \return number of bands +*/ +static int +numberOfBands(FIXP_SGL bpo_div16, /*!< Input: number of bands per octave divided by 16 */ + int start, /*!< First QMF band of SBR frequency range */ + int stop, /*!< Last QMF band of SBR frequency range + 1 */ + int warpFlag) /*!< Stretching flag */ +{ + FIXP_SGL num_bands_div128; + int num_bands; + + num_bands_div128 = FX_DBL2FX_SGL(fMult(FDK_getNumOctavesDiv8(start,stop),bpo_div16)); + + if (warpFlag) { + /* Apply the warp factor of 1.3 to get wider bands. We use a value + of 32768/25200 instead of the exact value to avoid critical cases + of rounding. + */ + num_bands_div128 = FX_DBL2FX_SGL(fMult(num_bands_div128, FL2FXCONST_SGL(25200.0/32768.0))); + } + + /* add scaled 1 for rounding to even numbers: */ + num_bands_div128 = num_bands_div128 + FL2FXCONST_SGL( 1.0f/128.0f ); + /* scale back to right aligned integer and double the value: */ + num_bands = 2 * ((LONG)num_bands_div128 >> (FRACT_BITS - 7)); + + return(num_bands); +} + + +/*! + \brief Calculate width of SBR bands + + Given the desired number of bands within the SBR frequency range, + this function calculates the width of each SBR band in QMF channels. + The bands get wider from start to stop (bark scale). +*/ +static void +CalcBands(UCHAR * diff, /*!< Vector of widths to be calculated */ + UCHAR start, /*!< Lower end of subband range */ + UCHAR stop, /*!< Upper end of subband range */ + UCHAR num_bands) /*!< Desired number of bands */ +{ + int i; + int previous; + int current; + FIXP_SGL exact, temp; + FIXP_SGL bandfactor = calcFactorPerBand(start, stop, num_bands); + + previous = stop; /* Start with highest QMF channel */ + exact = (FIXP_SGL)(stop << (FRACT_BITS-8)); /* Shift left to gain some accuracy */ + + for(i=num_bands-1; i>=0; i--) { + /* Calculate border of next lower sbr band */ + exact = FX_DBL2FX_SGL(fMult(exact,bandfactor)); + + /* Add scaled 0.5 for rounding: + We use a value 128/256 instead of 0.5 to avoid some critical cases of rounding. */ + temp = exact + FL2FXCONST_SGL(128.0/32768.0); + + /* scale back to right alinged integer: */ + current = (LONG)temp >> (FRACT_BITS-8); + + /* Save width of band i */ + diff[i] = previous - current; + previous = current; + } +} + + +/*! + \brief Calculate cumulated sum vector from delta vector +*/ +static void +cumSum(UCHAR start_value, UCHAR* diff, UCHAR length, UCHAR *start_adress) +{ + int i; + start_adress[0]=start_value; + for(i=1; i<=length; i++) + start_adress[i] = start_adress[i-1] + diff[i-1]; +} + + +/*! + \brief Adapt width of frequency bands in the second region + + If SBR spans more than 2 octaves, the upper part of a bark-frequency-scale + is calculated separately. This function tries to avoid that the second region + starts with a band smaller than the highest band of the first region. +*/ +static SBR_ERROR +modifyBands(UCHAR max_band_previous, UCHAR * diff, UCHAR length) +{ + int change = max_band_previous - diff[0]; + + /* Limit the change so that the last band cannot get narrower than the first one */ + if ( change > (diff[length-1]-diff[0])>>1 ) + change = (diff[length-1]-diff[0])>>1; + + diff[0] += change; + diff[length-1] -= change; + shellsort(diff, length); + + return SBRDEC_OK; +} + + +/*! + \brief Update high resolution frequency band table +*/ +static void +sbrdecUpdateHiRes(UCHAR * h_hires, + UCHAR * num_hires, + UCHAR * v_k_master, + UCHAR num_bands, + UCHAR xover_band) +{ + UCHAR i; + + *num_hires = num_bands-xover_band; + + for(i=xover_band; i<=num_bands; i++) { + h_hires[i-xover_band] = v_k_master[i]; + } +} + + +/*! + \brief Build low resolution table out of high resolution table +*/ +static void +sbrdecUpdateLoRes(UCHAR * h_lores, + UCHAR * num_lores, + UCHAR * h_hires, + UCHAR num_hires) +{ + UCHAR i; + + if( (num_hires & 1) == 0) { + /* If even number of hires bands */ + *num_lores = num_hires >> 1; + /* Use every second lores=hires[0,2,4...] */ + for(i=0; i<=*num_lores; i++) + h_lores[i] = h_hires[i*2]; + } + else { + /* Odd number of hires, which means xover is odd */ + *num_lores = (num_hires+1) >> 1; + /* Use lores=hires[0,1,3,5 ...] */ + h_lores[0] = h_hires[0]; + for(i=1; i<=*num_lores; i++) { + h_lores[i] = h_hires[i*2-1]; + } + } +} + + +/*! + \brief Derive a low-resolution frequency-table from the master frequency table +*/ +void +sbrdecDownSampleLoRes(UCHAR *v_result, + UCHAR num_result, + UCHAR *freqBandTableRef, + UCHAR num_Ref) +{ + int step; + int i,j; + int org_length,result_length; + int v_index[MAX_FREQ_COEFFS>>1]; + + /* init */ + org_length = num_Ref; + result_length = num_result; + + v_index[0] = 0; /* Always use left border */ + i=0; + while(org_length > 0) { + /* Create downsample vector */ + i++; + step = org_length / result_length; + org_length = org_length - step; + result_length--; + v_index[i] = v_index[i-1] + step; + } + + for(j=0;j<=i;j++) { + /* Use downsample vector to index LoResolution vector */ + v_result[j]=freqBandTableRef[v_index[j]]; + } + +} + + +/*! + \brief Sorting routine +*/ +void shellsort(UCHAR *in, UCHAR n) +{ + + int i, j, v, w; + int inc = 1; + + do + inc = 3 * inc + 1; + while (inc <= n); + + do { + inc = inc / 3; + for (i = inc; i < n; i++) { + v = in[i]; + j = i; + while ((w=in[j-inc]) > v) { + in[j] = w; + j -= inc; + if (j < inc) + break; + } + in[j] = v; + } + } while (inc > 1); + +} + + + +/*! + \brief Reset frequency band tables + \return errorCode, 0 if successful +*/ +SBR_ERROR +resetFreqBandTables(HANDLE_SBR_HEADER_DATA hHeaderData, const UINT flags) +{ + SBR_ERROR err = SBRDEC_OK; + int k2,kx, lsb, usb; + int intTemp; + UCHAR nBandsLo, nBandsHi; + HANDLE_FREQ_BAND_DATA hFreq = &hHeaderData->freqBandData; + + /* Calculate master frequency function */ + err = sbrdecUpdateFreqScale(hFreq->v_k_master, + &hFreq->numMaster, + hHeaderData->sbrProcSmplRate, + hHeaderData, + flags); + + if ( err || (hHeaderData->bs_info.xover_band > hFreq->numMaster) ) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + /* Derive Hiresolution from master frequency function */ + sbrdecUpdateHiRes(hFreq->freqBandTable[1], &nBandsHi, hFreq->v_k_master, hFreq->numMaster, hHeaderData->bs_info.xover_band ); + /* Derive Loresolution from Hiresolution */ + sbrdecUpdateLoRes(hFreq->freqBandTable[0], &nBandsLo, hFreq->freqBandTable[1], nBandsHi); + + + hFreq->nSfb[0] = nBandsLo; + hFreq->nSfb[1] = nBandsHi; + + /* Check index to freqBandTable[0] */ + if ( !(nBandsLo > 0) || (nBandsLo > (MAX_FREQ_COEFFS>>1)) ) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + lsb = hFreq->freqBandTable[0][0]; + usb = hFreq->freqBandTable[0][nBandsLo]; + + /* Additional check for lsb */ + if ( (lsb > (32)) || (lsb >= usb) ) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + + /* Calculate number of noise bands */ + + k2 = hFreq->freqBandTable[1][nBandsHi]; + kx = hFreq->freqBandTable[1][0]; + + if (hHeaderData->bs_data.noise_bands == 0) + { + hFreq->nNfb = 1; + } + else /* Calculate no of noise bands 1,2 or 3 bands/octave */ + { + /* Fetch number of octaves divided by 32 */ + intTemp = (LONG)FDK_getNumOctavesDiv8(kx,k2) >> 2; + + /* Integer-Multiplication with number of bands: */ + intTemp = intTemp * hHeaderData->bs_data.noise_bands; + + /* Add scaled 0.5 for rounding: */ + intTemp = intTemp + (LONG)FL2FXCONST_SGL(0.5f/32.0f); + + /* Convert to right-aligned integer: */ + intTemp = intTemp >> (FRACT_BITS - 1 /*sign*/ - 5 /* rescale */); + + /* Compare with float calculation */ + FDK_ASSERT( intTemp == (int)((hHeaderData->bs_data.noise_bands * FDKlog( (float)k2/kx) / (float)(FDKlog(2.0)))+0.5) ); + + if( intTemp==0) + intTemp=1; + + hFreq->nNfb = intTemp; + } + + hFreq->nInvfBands = hFreq->nNfb; + + if( hFreq->nNfb > MAX_NOISE_COEFFS ) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + /* Get noise bands */ + sbrdecDownSampleLoRes(hFreq->freqBandTableNoise, + hFreq->nNfb, + hFreq->freqBandTable[0], + nBandsLo); + + + + + hFreq->lowSubband = lsb; + hFreq->highSubband = usb; + + return SBRDEC_OK; +} diff --git a/libSBRdec/src/sbrdec_freq_sca.h b/libSBRdec/src/sbrdec_freq_sca.h new file mode 100644 index 0000000..9df6777 --- /dev/null +++ b/libSBRdec/src/sbrdec_freq_sca.h @@ -0,0 +1,48 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ +****************************************************************************/ +/*! + \file + \brief Frequency scale prototypes $Revision: 36841 $ +*/ +#ifndef __FREQ_SCA_H +#define __FREQ_SCA_H + +#include "sbrdecoder.h" +#include "env_extr.h" + +int +sbrdecUpdateFreqScale(UCHAR * v_k_master, + UCHAR *numMaster, + HANDLE_SBR_HEADER_DATA headerData); + +void sbrdecDownSampleLoRes(UCHAR *v_result, UCHAR num_result, + UCHAR *freqBandTableRef, UCHAR num_Ref); + +void shellsort(UCHAR *in, UCHAR n); + +SBR_ERROR +resetFreqBandTables(HANDLE_SBR_HEADER_DATA hHeaderData, const UINT flags); + +#endif diff --git a/libSBRdec/src/sbrdecoder.cpp b/libSBRdec/src/sbrdecoder.cpp new file mode 100644 index 0000000..dc824cb --- /dev/null +++ b/libSBRdec/src/sbrdecoder.cpp @@ -0,0 +1,1448 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief SBR decoder frontend $Revision: 36841 $ + This module provides a frontend to the SBR decoder. The function openSBR() is called for + initialization. The function sbrDecoder_Apply() is called for each frame. sbr_Apply() will call the + required functions to decode the raw SBR data (provided by env_extr.cpp), to decode the envelope data and noise floor levels [decodeSbrData()], + and to finally apply SBR to the current frame [sbr_dec()]. + + \sa sbrDecoder_Apply(), \ref documentationOverview +*/ + +/*! + \page documentationOverview Overview of important information resources and source code documentation + + The primary source code documentation is based on generated and cross-referenced HTML files using + doxygen. As part of this documentation + you can find more extensive descriptions about key concepts and algorithms at the following locations: + +

Programming

+ + \li Buffer management: sbrDecoder_Apply() and sbr_dec() + \li Internal scale factors to maximize SNR on fixed point processors: #QMF_SCALE_FACTOR + \li Special mantissa-exponent format: Created in requantizeEnvelopeData() and used in calculateSbrEnvelope() + +

Algorithmic details

+ \li About the SBR data format: \ref SBR_HEADER_ELEMENT and \ref SBR_STANDARD_ELEMENT + \li Details about the bitstream decoder: env_extr.cpp + \li Details about the QMF filterbank and the provided polyphase implementation: qmf_dec.cpp + \li Details about the transposer: lpp_tran.cpp + \li Details about the envelope adjuster: env_calc.cpp + +*/ + +#include "sbrdecoder.h" + +#include "FDK_bitstream.h" + +#include "sbrdec_freq_sca.h" +#include "env_extr.h" +#include "sbr_dec.h" +#include "env_dec.h" +#include "sbr_crc.h" +#include "sbr_ram.h" +#include "sbr_rom.h" +#include "lpp_tran.h" +#include "transcendent.h" + + +#include "sbrdec_drc.h" + +#include "psbitdec.h" + + +/* Decoder library info */ +#define SBRDECODER_LIB_VL0 2 +#define SBRDECODER_LIB_VL1 1 +#define SBRDECODER_LIB_VL2 0 +#define SBRDECODER_LIB_TITLE "SBR Decoder" +#define SBRDECODER_LIB_BUILD_DATE __DATE__ +#define SBRDECODER_LIB_BUILD_TIME __TIME__ + + + + +static UCHAR getHeaderSlot( UCHAR currentSlot, UCHAR hdrSlotUsage[(1)+1] ) +{ + UINT occupied = 0; + int s; + UCHAR slot = hdrSlotUsage[currentSlot]; + + FDK_ASSERT((1)+1 < 32); + + for (s = 0; s < (1)+1; s++) { + if ( (hdrSlotUsage[s] == slot) + && (s != slot) ) { + occupied = 1; + break; + } + } + + if (occupied) { + occupied = 0; + + for (s = 0; s < (1)+1; s++) { + occupied |= 1 << hdrSlotUsage[s]; + } + for (s = 0; s < (1)+1; s++) { + if ( !(occupied & 0x1) ) { + slot = s; + break; + } + occupied >>= 1; + } + } + + return slot; +} + +static void copySbrHeader( HANDLE_SBR_HEADER_DATA hDst, const HANDLE_SBR_HEADER_DATA hSrc ) +{ + /* copy the whole header memory (including pointers) */ + FDKmemcpy( hDst, hSrc, sizeof(SBR_HEADER_DATA) ); + + /* update pointers */ + hDst->freqBandData.freqBandTable[0] = hDst->freqBandData.freqBandTableLo; + hDst->freqBandData.freqBandTable[1] = hDst->freqBandData.freqBandTableHi; +} + + +/*! + \brief Reset SBR decoder. + + Reset should only be called if SBR has been sucessfully detected by + an appropriate checkForPayload() function. + + \return Error code. +*/ +static +SBR_ERROR sbrDecoder_ResetElement ( + HANDLE_SBRDECODER self, + int sampleRateIn, + int sampleRateOut, + int samplesPerFrame, + const MP4_ELEMENT_ID elementID, + const int elementIndex, + const int overlap + ) +{ + SBR_ERROR sbrError = SBRDEC_OK; + HANDLE_SBR_HEADER_DATA hSbrHeader; + UINT qmfFlags = 0; + + int i, synDownsampleFac; + + /* Check in/out samplerates */ + if ( sampleRateIn < 6400 + || sampleRateIn > 24000 + ) + { + sbrError = SBRDEC_UNSUPPORTED_CONFIG; + goto bail; + } + + if ( sampleRateOut > 48000 ) + { + sbrError = SBRDEC_UNSUPPORTED_CONFIG; + goto bail; + } + + /* Set QMF mode flags */ + if (self->flags & SBRDEC_LOW_POWER) + qmfFlags |= QMF_FLAG_LP; + + if (self->coreCodec == AOT_ER_AAC_ELD) { + if (self->flags & SBRDEC_LD_MPS_QMF) { + qmfFlags |= QMF_FLAG_MPSLDFB; + } else { + qmfFlags |= QMF_FLAG_CLDFB; + } + } + + /* Set downsampling factor for synthesis filter bank */ + if (sampleRateOut == 0) + { + /* no single rate mode */ + sampleRateOut = sampleRateIn<<1; /* In case of implicit signalling, assume dual rate SBR */ + } + + if ( sampleRateIn == sampleRateOut ) { + synDownsampleFac = 2; + } else { + synDownsampleFac = 1; + } + + self->synDownsampleFac = synDownsampleFac; + self->sampleRateOut = sampleRateOut; + + { + int i; + + for (i = 0; i < (1)+1; i++) + { + hSbrHeader = &(self->sbrHeader[elementIndex][i]); + + /* init a default header such that we can at least do upsampling later */ + sbrError = initHeaderData( + hSbrHeader, + sampleRateIn, + sampleRateOut, + samplesPerFrame, + self->flags + ); + } + } + + if (sbrError != SBRDEC_OK) { + goto bail; + } + + /* Init SBR channels going to be assigned to a SBR element */ + { + int ch; + + for (ch=0; chpSbrElement[elementIndex]->nChannels; ch++) + { + /* and create sbrDec */ + sbrError = createSbrDec (self->pSbrElement[elementIndex]->pSbrChannel[ch], + hSbrHeader, + &self->pSbrElement[elementIndex]->transposerSettings, + synDownsampleFac, + qmfFlags, + self->flags, + overlap, + ch ); + + if (sbrError != SBRDEC_OK) { + goto bail; + } + } + } + + //FDKmemclear(sbr_OverlapBuffer, sizeof(sbr_OverlapBuffer)); + + if (self->numSbrElements == 1) { + switch ( self->coreCodec ) { + case AOT_AAC_LC: + case AOT_SBR: + case AOT_PS: + case AOT_ER_AAC_SCAL: + case AOT_DRM_AAC: + case AOT_DRM_SURROUND: + if (CreatePsDec ( &self->hParametricStereoDec, samplesPerFrame )) { + sbrError = SBRDEC_CREATE_ERROR; + goto bail; + } + break; + default: + break; + } + } + + /* Init frame delay slot handling */ + self->pSbrElement[elementIndex]->useFrameSlot = 0; + for (i = 0; i < ((1)+1); i++) { + self->pSbrElement[elementIndex]->useHeaderSlot[i] = i; + } + +bail: + + return sbrError; +} + + +SBR_ERROR sbrDecoder_Open ( HANDLE_SBRDECODER * pSelf ) +{ + HANDLE_SBRDECODER self = NULL; + SBR_ERROR sbrError = SBRDEC_OK; + + /* Get memory for this instance */ + self = GetRam_SbrDecoder(); + if (self == NULL) { + sbrError = SBRDEC_MEM_ALLOC_FAILED; + goto bail; + } + + self->workBuffer1 = GetRam_SbrDecWorkBuffer1(); + self->workBuffer2 = GetRam_SbrDecWorkBuffer2(); + + if ( self->workBuffer1 == NULL + || self->workBuffer2 == NULL ) + { + sbrError = SBRDEC_MEM_ALLOC_FAILED; + goto bail; + } + + /* + Already zero because of calloc + self->numSbrElements = 0; + self->numSbrChannels = 0; + self->codecFrameSize = 0; + */ + + self->numDelayFrames = (1); /* set to the max value by default */ + + *pSelf = self; + +bail: + return sbrError; +} + +/** + * \brief determine if the given core codec AOT can be processed or not. + * \param coreCodec core codec audio object type. + * \return 1 if SBR can be processed, 0 if SBR cannot be processed/applied. + */ +static +int sbrDecoder_isCoreCodecValid(AUDIO_OBJECT_TYPE coreCodec) +{ + switch (coreCodec) { + case AOT_AAC_LC: + case AOT_SBR: + case AOT_PS: + case AOT_ER_AAC_SCAL: + case AOT_ER_AAC_ELD: + return 1; + default: + return 0; + } +} + +static +void sbrDecoder_DestroyElement ( + HANDLE_SBRDECODER self, + const int elementIndex + ) +{ + if (self->pSbrElement[elementIndex] != NULL) { + int ch; + + for (ch=0; chpSbrElement[elementIndex]->pSbrChannel[ch] != NULL) { + deleteSbrDec( self->pSbrElement[elementIndex]->pSbrChannel[ch] ); + FreeRam_SbrDecChannel( &self->pSbrElement[elementIndex]->pSbrChannel[ch] ); + self->numSbrChannels -= 1; + } + } + FreeRam_SbrDecElement( &self->pSbrElement[elementIndex] ); + self->numSbrElements -= 1; + } +} + + +SBR_ERROR sbrDecoder_InitElement ( + HANDLE_SBRDECODER self, + const int sampleRateIn, + const int sampleRateOut, + const int samplesPerFrame, + const AUDIO_OBJECT_TYPE coreCodec, + const MP4_ELEMENT_ID elementID, + const int elementIndex + ) +{ + SBR_ERROR sbrError = SBRDEC_OK; + int chCnt=0; + + /* Check core codec AOT */ + if (! sbrDecoder_isCoreCodecValid(coreCodec) || elementIndex >= (4)) { + sbrError = SBRDEC_UNSUPPORTED_CONFIG; + goto bail; + } + + if ( elementID != ID_SCE && elementID != ID_CPE && elementID != ID_LFE ) + { + sbrError = SBRDEC_UNSUPPORTED_CONFIG; + goto bail; + } + + if ( self->sampleRateIn == sampleRateIn + && self->codecFrameSize == samplesPerFrame + && self->coreCodec == coreCodec + && self->pSbrElement[elementIndex] != NULL + && self->pSbrElement[elementIndex]->elementID == elementID + ) + { + /* Nothing to do */ + return SBRDEC_OK; + } + + self->sampleRateIn = sampleRateIn; + self->codecFrameSize = samplesPerFrame; + self->coreCodec = coreCodec; + + self->flags = 0; + self->flags |= (coreCodec == AOT_ER_AAC_ELD) ? SBRDEC_ELD_GRID : 0; + + /* Init SBR elements */ + { + int elChannels, ch; + + if (self->pSbrElement[elementIndex] == NULL) { + self->pSbrElement[elementIndex] = GetRam_SbrDecElement(elementIndex); + if (self->pSbrElement[elementIndex] == NULL) { + sbrError = SBRDEC_MEM_ALLOC_FAILED; + goto bail; + } + self->numSbrElements ++; + } else { + self->numSbrChannels -= self->pSbrElement[elementIndex]->nChannels; + } + + /* Save element ID for sanity checks and to have a fallback for concealment. */ + self->pSbrElement[elementIndex]->elementID = elementID; + + /* Determine amount of channels for this element */ + switch (elementID) { + case ID_NONE: + case ID_CPE: elChannels=2; + break; + case ID_LFE: + case ID_SCE: elChannels=1; + break; + default: elChannels=0; + break; + } + + /* Handle case of Parametric Stereo */ + if ( elementIndex == 0 && elementID == ID_SCE ) { + switch (coreCodec) { + case AOT_AAC_LC: + case AOT_SBR: + case AOT_PS: + case AOT_ER_AAC_SCAL: + case AOT_DRM_AAC: + case AOT_DRM_SURROUND: + elChannels = 2; + break; + default: + break; + } + } + + self->pSbrElement[elementIndex]->nChannels = elChannels; + + for (ch=0; chpSbrElement[elementIndex]->pSbrChannel[ch] == NULL) { + self->pSbrElement[elementIndex]->pSbrChannel[ch] = GetRam_SbrDecChannel(chCnt); + if (self->pSbrElement[elementIndex]->pSbrChannel[ch] == NULL) { + sbrError = SBRDEC_MEM_ALLOC_FAILED; + goto bail; + } + } + self->numSbrChannels ++; + + sbrDecoder_drcInitChannel( &self->pSbrElement[elementIndex]->pSbrChannel[ch]->SbrDec.sbrDrcChannel ); + + /* Add reference pointer to workbuffers. */ + self->pSbrElement[elementIndex]->pSbrChannel[ch]->SbrDec.WorkBuffer1 = self->workBuffer1; + self->pSbrElement[elementIndex]->pSbrChannel[ch]->SbrDec.WorkBuffer2 = self->workBuffer2; + chCnt++; + } + if (elChannels == 1 && self->pSbrElement[elementIndex]->pSbrChannel[ch] != NULL) { + deleteSbrDec( self->pSbrElement[elementIndex]->pSbrChannel[ch] ); + FreeRam_SbrDecChannel( &self->pSbrElement[elementIndex]->pSbrChannel[ch] ); + } + } + + /* clear error flags for all delay slots */ + FDKmemclear(self->pSbrElement[elementIndex]->frameErrorFlag, ((1)+1)*sizeof(UCHAR)); + + /* Initialize this instance */ + sbrError = sbrDecoder_ResetElement( + self, + sampleRateIn, + sampleRateOut, + samplesPerFrame, + elementID, + elementIndex, + (coreCodec == AOT_ER_AAC_ELD) ? 0 : (6) + ); + + + +bail: + if (sbrError != SBRDEC_OK) { + /* Free the memory allocated for this element */ + sbrDecoder_DestroyElement( self, elementIndex ); + } + + return sbrError; +} + +/** + * \brief Apply decoded SBR header for one element. + * \param self SBR decoder instance handle + * \param hSbrHeader SBR header handle to be processed. + * \param hSbrChannel pointer array to the SBR element channels corresponding to the SBR header. + * \param headerStatus header status value returned from SBR header parser. + * \param numElementChannels amount of channels for the SBR element whos header is to be processed. + */ +static +SBR_ERROR sbrDecoder_HeaderUpdate( + HANDLE_SBRDECODER self, + HANDLE_SBR_HEADER_DATA hSbrHeader, + SBR_HEADER_STATUS headerStatus, + HANDLE_SBR_CHANNEL hSbrChannel[], + const int numElementChannels + ) +{ + SBR_ERROR errorStatus = SBRDEC_OK; + + /* + change of control data, reset decoder + */ + errorStatus = resetFreqBandTables(hSbrHeader, self->flags); + + if (errorStatus == SBRDEC_OK) { + if (hSbrHeader->syncState == UPSAMPLING && headerStatus != HEADER_RESET) + { + /* As the default header would limit the frequency range, + lowSubband and highSubband must be patched. */ + hSbrHeader->freqBandData.lowSubband = hSbrHeader->numberOfAnalysisBands; + hSbrHeader->freqBandData.highSubband = hSbrHeader->numberOfAnalysisBands; + } + + /* Trigger a reset before processing this slot */ + hSbrHeader->status |= SBRDEC_HDR_STAT_RESET; + } + + return errorStatus; +} + +INT sbrDecoder_Header ( + HANDLE_SBRDECODER self, + HANDLE_FDK_BITSTREAM hBs, + const INT sampleRateIn, + const INT sampleRateOut, + const INT samplesPerFrame, + const AUDIO_OBJECT_TYPE coreCodec, + const MP4_ELEMENT_ID elementID, + const INT elementIndex + ) +{ + SBR_HEADER_STATUS headerStatus; + HANDLE_SBR_HEADER_DATA hSbrHeader; + SBR_ERROR sbrError = SBRDEC_OK; + int headerIndex; + + if ( self == NULL || elementIndex > (4) ) + { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + if (! sbrDecoder_isCoreCodecValid(coreCodec)) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + sbrError = sbrDecoder_InitElement( + self, + sampleRateIn, + sampleRateOut, + samplesPerFrame, + coreCodec, + elementID, + elementIndex + ); + + if (sbrError != SBRDEC_OK) { + goto bail; + } + + headerIndex = getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot, + self->pSbrElement[elementIndex]->useHeaderSlot); + hSbrHeader = &(self->sbrHeader[elementIndex][headerIndex]); + + headerStatus = sbrGetHeaderData ( hSbrHeader, + hBs, + self->flags, + 0); + + + { + SBR_DECODER_ELEMENT *pSbrElement; + + pSbrElement = self->pSbrElement[elementIndex]; + + /* Sanity check */ + if (pSbrElement != NULL) { + if ( (elementID == ID_CPE && pSbrElement->nChannels != 2) + || (elementID != ID_CPE && pSbrElement->nChannels != 1) ) + { + return SBRDEC_UNSUPPORTED_CONFIG; + } + if ( headerStatus == HEADER_RESET ) { + + sbrError = sbrDecoder_HeaderUpdate( + self, + hSbrHeader, + headerStatus, + pSbrElement->pSbrChannel, + pSbrElement->nChannels + ); + + if (sbrError == SBRDEC_OK) { + hSbrHeader->syncState = SBR_HEADER; + hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE; + } + /* else { + Since we already have overwritten the old SBR header the only way out is UPSAMPLING! + This will be prepared in the next step. + } */ + } + } + } +bail: + return sbrError; +} + + +SBR_ERROR sbrDecoder_SetParam (HANDLE_SBRDECODER self, + const SBRDEC_PARAM param, + const INT value ) +{ + SBR_ERROR errorStatus = SBRDEC_OK; + + /* configure the subsystems */ + switch (param) + { + case SBR_SYSTEM_BITSTREAM_DELAY: + if (value < 0 || value > (1)) { + errorStatus = SBRDEC_SET_PARAM_FAIL; + break; + } + if (self == NULL) { + errorStatus = SBRDEC_NOT_INITIALIZED; + } else { + self->numDelayFrames = (UCHAR)value; + } + break; + case SBR_QMF_MODE: + if (self == NULL) { + errorStatus = SBRDEC_NOT_INITIALIZED; + } else { + if (value == 1) { + self->flags |= SBRDEC_LOW_POWER; + } else { + self->flags &= ~SBRDEC_LOW_POWER; + } + } + break; + case SBR_LD_QMF_TIME_ALIGN: + if (self == NULL) { + errorStatus = SBRDEC_NOT_INITIALIZED; + } else { + if (value == 1) { + self->flags |= SBRDEC_LD_MPS_QMF; + } else { + self->flags &= ~SBRDEC_LD_MPS_QMF; + } + } + break; + case SBR_BS_INTERRUPTION: + { + int elementIndex; + /* Loop over SBR elements */ + for (elementIndex = 0; elementIndex < self->numSbrElements; elementIndex++) + { + HANDLE_SBR_HEADER_DATA hSbrHeader; + int headerIndex = getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot, + self->pSbrElement[elementIndex]->useHeaderSlot); + + hSbrHeader = &(self->sbrHeader[elementIndex][headerIndex]); + + /* Set sync state UPSAMPLING for the corresponding slot. + This switches off bitstream parsing until a new header arrives. */ + hSbrHeader->syncState = UPSAMPLING; + hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE; + } + } + break; + default: + errorStatus = SBRDEC_SET_PARAM_FAIL; + break; + } /* switch(param) */ + + return (errorStatus); +} + +static +SBRDEC_DRC_CHANNEL * sbrDecoder_drcGetChannel( const HANDLE_SBRDECODER self, const INT channel ) +{ + SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL; + int elementIndex, elChanIdx=0, numCh=0; + + for (elementIndex = 0; (elementIndex < (4)) && (numCh <= channel); elementIndex++) + { + SBR_DECODER_ELEMENT *pSbrElement = self->pSbrElement[elementIndex]; + int c, elChannels; + + elChanIdx = 0; + if (pSbrElement == NULL) break; + + /* Determine amount of channels for this element */ + switch (pSbrElement->elementID) { + case ID_CPE: elChannels = 2; + break; + case ID_LFE: + case ID_SCE: elChannels = 1; + break; + case ID_NONE: + default: elChannels = 0; + break; + } + + /* Limit with actual allocated element channels */ + elChannels = FDKmin(elChannels, pSbrElement->nChannels); + + for (c = 0; (c < elChannels) && (numCh <= channel); c++) { + if (pSbrElement->pSbrChannel[elChanIdx] != NULL) { + numCh++; + elChanIdx++; + } + } + } + elementIndex -= 1; + elChanIdx -= 1; + + if (elChanIdx < 0 || elementIndex < 0) { + return NULL; + } + + if ( self->pSbrElement[elementIndex] != NULL ) { + if ( self->pSbrElement[elementIndex]->pSbrChannel[elChanIdx] != NULL ) + { + pSbrDrcChannelData = &self->pSbrElement[elementIndex]->pSbrChannel[elChanIdx]->SbrDec.sbrDrcChannel; + } + } + + return (pSbrDrcChannelData); +} + +SBR_ERROR sbrDecoder_drcFeedChannel ( HANDLE_SBRDECODER self, + INT ch, + UINT numBands, + FIXP_DBL *pNextFact_mag, + INT nextFact_exp, + SHORT drcInterpolationScheme, + UCHAR winSequence, + USHORT *pBandTop ) +{ + SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL; + + if (self == NULL) { + return SBRDEC_NOT_INITIALIZED; + } + if (ch > (6) || pNextFact_mag == NULL) { + return SBRDEC_SET_PARAM_FAIL; + } + + /* Find the right SBR channel */ + pSbrDrcChannelData = sbrDecoder_drcGetChannel( self, ch ); + + if ( pSbrDrcChannelData != NULL ) { + int i; + + pSbrDrcChannelData->enable = 1; + pSbrDrcChannelData->numBandsNext = numBands; + + pSbrDrcChannelData->winSequenceNext = winSequence; + pSbrDrcChannelData->drcInterpolationSchemeNext = drcInterpolationScheme; + pSbrDrcChannelData->nextFact_exp = nextFact_exp; + + for (i = 0; i < (int)numBands; i++) { + pSbrDrcChannelData->bandTopNext[i] = pBandTop[i]; + pSbrDrcChannelData->nextFact_mag[i] = pNextFact_mag[i]; + } + } + + return SBRDEC_OK; +} + + +void sbrDecoder_drcDisable ( HANDLE_SBRDECODER self, + INT ch ) +{ + SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL; + + if ( (self == NULL) + || (ch > (6)) + || (self->numSbrElements == 0) + || (self->numSbrChannels == 0) ) { + return; + } + + /* Find the right SBR channel */ + pSbrDrcChannelData = sbrDecoder_drcGetChannel( self, ch ); + + if ( pSbrDrcChannelData != NULL ) { + pSbrDrcChannelData->enable = 0; + } +} + + + +SBR_ERROR sbrDecoder_Parse( + HANDLE_SBRDECODER self, + HANDLE_FDK_BITSTREAM hBs, + int *count, + int bsPayLen, + int crcFlag, + MP4_ELEMENT_ID prevElement, + int elementIndex, + int fGlobalIndependencyFlag + ) +{ + SBR_DECODER_ELEMENT *hSbrElement; + HANDLE_SBR_HEADER_DATA hSbrHeader; + HANDLE_SBR_CHANNEL *pSbrChannel; + + SBR_FRAME_DATA *hFrameDataLeft; + SBR_FRAME_DATA *hFrameDataRight; + + SBR_ERROR errorStatus = SBRDEC_OK; + SBR_SYNC_STATE initialSyncState; + SBR_HEADER_STATUS headerStatus = HEADER_NOT_PRESENT; + + INT startPos; + INT CRCLen = 0; + + int stereo; + int fDoDecodeSbrData = 1; + + int lastSlot, lastHdrSlot = 0, thisHdrSlot; + + /* Remember start position of SBR element */ + startPos = FDKgetValidBits(hBs); + + /* SBR sanity checks */ + if ( self == NULL || self->pSbrElement[elementIndex] == NULL ) { + errorStatus = SBRDEC_NOT_INITIALIZED; + goto bail; + } + + hSbrElement = self->pSbrElement[elementIndex]; + + lastSlot = (hSbrElement->useFrameSlot > 0) ? hSbrElement->useFrameSlot-1 : self->numDelayFrames; + lastHdrSlot = hSbrElement->useHeaderSlot[lastSlot]; + thisHdrSlot = getHeaderSlot( hSbrElement->useFrameSlot, hSbrElement->useHeaderSlot ); /* Get a free header slot not used by frames not processed yet. */ + + /* Assign the free slot to store a new header if there is one. */ + hSbrHeader = &self->sbrHeader[elementIndex][thisHdrSlot]; + + pSbrChannel = hSbrElement->pSbrChannel; + stereo = (hSbrElement->elementID == ID_CPE) ? 1 : 0; + + hFrameDataLeft = &self->pSbrElement[elementIndex]->pSbrChannel[0]->frameData[hSbrElement->useFrameSlot]; + hFrameDataRight = &self->pSbrElement[elementIndex]->pSbrChannel[1]->frameData[hSbrElement->useFrameSlot]; + + initialSyncState = hSbrHeader->syncState; + + /* reset PS flag; will be set after PS was found */ + self->flags &= ~SBRDEC_PS_DECODED; + + if (hSbrHeader->status & SBRDEC_HDR_STAT_UPDATE) { + /* Got a new header from extern (e.g. from an ASC) */ + headerStatus = HEADER_OK; + hSbrHeader->status &= ~SBRDEC_HDR_STAT_UPDATE; + } + else if (thisHdrSlot != lastHdrSlot) { + /* Copy the last header into this slot otherwise the + header compare will trigger more HEADER_RESETs than needed. */ + copySbrHeader( hSbrHeader, &self->sbrHeader[elementIndex][lastHdrSlot] ); + } + + /* + Check if bit stream data is valid and matches the element context + */ + if ( ((prevElement != ID_SCE) && (prevElement != ID_CPE)) || prevElement != hSbrElement->elementID) { + /* In case of LFE we also land here, since there is no LFE SBR element (do upsampling only) */ + fDoDecodeSbrData = 0; + } + + if (fDoDecodeSbrData) + { + if ((INT)FDKgetValidBits(hBs) <= 0) { + fDoDecodeSbrData = 0; + } + } + + /* + SBR CRC-check + */ + if (fDoDecodeSbrData) + { + if (crcFlag == 1) { + switch (self->coreCodec) { + case AOT_ER_AAC_ELD: + FDKpushFor (hBs, 10); + /* check sbrcrc later: we don't know the payload length now */ + break; + default: + CRCLen = bsPayLen - 10; /* change: 0 => i */ + if (CRCLen < 0) { + fDoDecodeSbrData = 0; + } else { + fDoDecodeSbrData = SbrCrcCheck (hBs, CRCLen); + } + break; + } + } + } /* if (fDoDecodeSbrData) */ + + /* + Read in the header data and issue a reset if change occured + */ + if (fDoDecodeSbrData) + { + int sbrHeaderPresent; + + { + sbrHeaderPresent = FDKreadBit(hBs); + } + + if ( sbrHeaderPresent ) { + headerStatus = sbrGetHeaderData (hSbrHeader, + hBs, + self->flags, + 1); + } + + if (headerStatus == HEADER_RESET) { + errorStatus = sbrDecoder_HeaderUpdate( + self, + hSbrHeader, + headerStatus, + pSbrChannel, + hSbrElement->nChannels + ); + + if (errorStatus == SBRDEC_OK) { + hSbrHeader->syncState = SBR_HEADER; + } else { + hSbrHeader->syncState = SBR_NOT_INITIALIZED; + } + } + + if (errorStatus != SBRDEC_OK) { + fDoDecodeSbrData = 0; + } + } /* if (fDoDecodeSbrData) */ + + /* + Print debugging output only if state has changed + */ + + /* read frame data */ + if ((hSbrHeader->syncState >= SBR_HEADER) && fDoDecodeSbrData) { + int sbrFrameOk; + /* read the SBR element data */ + if (stereo) { + sbrFrameOk = sbrGetChannelPairElement(hSbrHeader, + hFrameDataLeft, + hFrameDataRight, + hBs, + self->flags, + self->pSbrElement[elementIndex]->transposerSettings.overlap); + } + else { + if (self->hParametricStereoDec != NULL) { + /* update slot index for PS bitstream parsing */ + self->hParametricStereoDec->bsLastSlot = self->hParametricStereoDec->bsReadSlot; + self->hParametricStereoDec->bsReadSlot = hSbrElement->useFrameSlot; + } + sbrFrameOk = sbrGetSingleChannelElement(hSbrHeader, + hFrameDataLeft, + hBs, + self->hParametricStereoDec, + self->flags, + self->pSbrElement[elementIndex]->transposerSettings.overlap); + } + if (!sbrFrameOk) { + fDoDecodeSbrData = 0; + } + else { + INT valBits; + + if (bsPayLen > 0) { + valBits = bsPayLen - ((INT)startPos - (INT)FDKgetValidBits(hBs)); + } else { + valBits = (INT)FDKgetValidBits(hBs); + } + + if ( crcFlag == 1 ) { + switch (self->coreCodec) { + case AOT_ER_AAC_ELD: + { + /* late crc check for eld */ + INT payloadbits = (INT)startPos - (INT)FDKgetValidBits(hBs) - startPos; + INT crcLen = payloadbits - 10; + FDKpushBack(hBs, payloadbits); + fDoDecodeSbrData = SbrCrcCheck (hBs, crcLen); + FDKpushFor(hBs, crcLen); + } + break; + default: + break; + } + } + + /* sanity check of remaining bits */ + if (valBits < 0) { + fDoDecodeSbrData = 0; + } else { + switch (self->coreCodec) { + case AOT_SBR: + case AOT_PS: + case AOT_AAC_LC: + { + /* This sanity check is only meaningful with General Audio bitstreams */ + int alignBits = valBits & 0x7; + + if (valBits > alignBits) { + fDoDecodeSbrData = 0; + } + } + break; + default: + /* No sanity check available */ + break; + } + } + } + } + + if (!fDoDecodeSbrData) { + /* Set error flag for this slot to trigger concealment */ + self->pSbrElement[elementIndex]->frameErrorFlag[hSbrElement->useFrameSlot] = 1; + errorStatus = SBRDEC_PARSE_ERROR; + } else { + /* Everything seems to be ok so clear the error flag */ + self->pSbrElement[elementIndex]->frameErrorFlag[hSbrElement->useFrameSlot] = 0; + } + + if (!stereo) { + /* Turn coupling off explicitely to avoid access to absent right frame data + that might occur with corrupt bitstreams. */ + hFrameDataLeft->coupling = COUPLING_OFF; + } + +bail: + if (errorStatus == SBRDEC_OK) { + if (headerStatus == HEADER_NOT_PRESENT) { + /* Use the old header for this frame */ + hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot] = lastHdrSlot; + } else { + /* Use the new header for this frame */ + hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot] = thisHdrSlot; + } + + /* Move frame pointer to the next slot which is up to be decoded/applied next */ + hSbrElement->useFrameSlot = (hSbrElement->useFrameSlot+1) % (self->numDelayFrames+1); + } + + *count -= startPos - FDKgetValidBits(hBs); + + return errorStatus; +} + + +/** + * \brief Render one SBR element into time domain signal. + * \param self SBR decoder handle + * \param timeData pointer to output buffer + * \param interleaved flag indicating interleaved channel output + * \param channelMapping pointer to UCHAR array where next 2 channel offsets are stored. + * \param elementIndex enumerating index of the SBR element to render. + * \param numInChannels number of channels from core coder (reading stride). + * \param numOutChannels pointer to a location to return number of output channels. + * \param psPossible flag indicating if PS is possible or not. + * \return SBRDEC_OK if successfull, else error code + */ +static SBR_ERROR +sbrDecoder_DecodeElement ( + HANDLE_SBRDECODER self, + INT_PCM *timeData, + const int interleaved, + const UCHAR *channelMapping, + const int elementIndex, + const int numInChannels, + int *numOutChannels, + const int psPossible + ) +{ + SBR_DECODER_ELEMENT *hSbrElement = self->pSbrElement[elementIndex]; + HANDLE_SBR_CHANNEL *pSbrChannel = self->pSbrElement[elementIndex]->pSbrChannel; + HANDLE_SBR_HEADER_DATA hSbrHeader = &self->sbrHeader[elementIndex][hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot]]; + HANDLE_PS_DEC h_ps_d = self->hParametricStereoDec; + + /* get memory for frame data from scratch */ + SBR_FRAME_DATA *hFrameDataLeft = &hSbrElement->pSbrChannel[0]->frameData[hSbrElement->useFrameSlot]; + SBR_FRAME_DATA *hFrameDataRight = &hSbrElement->pSbrChannel[1]->frameData[hSbrElement->useFrameSlot]; + + SBR_ERROR errorStatus = SBRDEC_OK; + + + INT strideIn, strideOut, offset0, offset1; + INT codecFrameSize = self->codecFrameSize; + + int stereo = (hSbrElement->elementID == ID_CPE) ? 1 : 0; + int numElementChannels = hSbrElement->nChannels; /* Number of channels of the current SBR element */ + + /* Update the header error flag */ + hSbrHeader->frameErrorFlag = hSbrElement->frameErrorFlag[hSbrElement->useFrameSlot]; + + /* + Prepare filterbank for upsampling if no valid bit stream data is available. + */ + if ( hSbrHeader->syncState == SBR_NOT_INITIALIZED ) + { + errorStatus = initHeaderData( + hSbrHeader, + self->sampleRateIn, + self->sampleRateOut, + codecFrameSize, + self->flags + ); + + hSbrHeader->syncState = UPSAMPLING; + + errorStatus = sbrDecoder_HeaderUpdate( + self, + hSbrHeader, + HEADER_NOT_PRESENT, + pSbrChannel, + hSbrElement->nChannels + ); + } + + /* reset */ + if (hSbrHeader->status & SBRDEC_HDR_STAT_RESET) { + int ch; + for (ch = 0 ; ch < numElementChannels; ch++) { + SBR_ERROR errorStatusTmp = SBRDEC_OK; + + errorStatusTmp = resetSbrDec ( + &pSbrChannel[ch]->SbrDec, + hSbrHeader, + &pSbrChannel[ch]->prevFrameData, + self->flags & SBRDEC_LOW_POWER, + self->synDownsampleFac + ); + + if (errorStatusTmp != SBRDEC_OK) { + errorStatus = errorStatusTmp; + } + } + hSbrHeader->status &= ~SBRDEC_HDR_STAT_RESET; + } + + /* decoding */ + if ( (hSbrHeader->syncState == SBR_ACTIVE) + || ((hSbrHeader->syncState == SBR_HEADER) && (hSbrHeader->frameErrorFlag == 0)) ) + { + errorStatus = SBRDEC_OK; + + decodeSbrData (hSbrHeader, + hFrameDataLeft, + &pSbrChannel[0]->prevFrameData, + (stereo) ? hFrameDataRight : NULL, + (stereo) ? &pSbrChannel[1]->prevFrameData : NULL); + + + /* Now we have a full parameter set and can do parameter + based concealment instead of plain upsampling. */ + hSbrHeader->syncState = SBR_ACTIVE; + } + + /* decode PS data if available */ + if (h_ps_d != NULL && psPossible) { + int applyPs = 1; + + /* define which frame delay line slot to process */ + h_ps_d->processSlot = hSbrElement->useFrameSlot; + + applyPs = DecodePs(h_ps_d, hSbrHeader->frameErrorFlag); + self->flags |= (applyPs) ? SBRDEC_PS_DECODED : 0; + } + + /* Set strides for reading and writing */ + if (interleaved) { + strideIn = numInChannels; + if ( psPossible ) + strideOut = (numInChannels < 2) ? 2 : numInChannels; + else + strideOut = numInChannels; + offset0 = channelMapping[0]; + offset1 = channelMapping[1]; + } else { + strideIn = 1; + strideOut = 1; + offset0 = channelMapping[0]*2*codecFrameSize; + offset1 = channelMapping[1]*2*codecFrameSize; + } + + /* use same buffers for left and right channel and apply PS per timeslot */ + /* Process left channel */ +//FDKprintf("self->codecFrameSize %d\t%d\n",self->codecFrameSize,self->sampleRateIn); + sbr_dec (&pSbrChannel[0]->SbrDec, + timeData + offset0, + timeData + offset0, + &pSbrChannel[1]->SbrDec, + timeData + offset1, + strideIn, + strideOut, + hSbrHeader, + hFrameDataLeft, + &pSbrChannel[0]->prevFrameData, + (hSbrHeader->syncState == SBR_ACTIVE), + h_ps_d, + self->flags + ); + + if (stereo) { + /* Process right channel */ + sbr_dec (&pSbrChannel[1]->SbrDec, + timeData + offset1, + timeData + offset1, + NULL, + NULL, + strideIn, + strideOut, + hSbrHeader, + hFrameDataRight, + &pSbrChannel[1]->prevFrameData, + (hSbrHeader->syncState == SBR_ACTIVE), + NULL, + self->flags + ); + } + + if (h_ps_d != NULL) { + /* save PS status for next run */ + h_ps_d->psDecodedPrv = (self->flags & SBRDEC_PS_DECODED) ? 1 : 0 ; + } + + if ( psPossible + ) + { + FDK_ASSERT(strideOut > 1); + if ( !(self->flags & SBRDEC_PS_DECODED) ) { + /* A decoder which is able to decode PS has to produce a stereo output even if no PS data is availble. */ + /* So copy left channel to right channel. */ + if (interleaved) { + INT_PCM *ptr; + INT i; + FDK_ASSERT(strideOut == 2); + + ptr = timeData; + for (i = codecFrameSize; i--; ) + { + INT_PCM tmp; /* This temporal variable is required because some compilers can't do *ptr++ = *ptr++ correctly. */ + tmp = *ptr++; *ptr++ = tmp; + tmp = *ptr++; *ptr++ = tmp; + } + } else { + FDKmemcpy( timeData+2*codecFrameSize, timeData, 2*codecFrameSize*sizeof(INT_PCM) ); + } + } + *numOutChannels = 2; /* Output minimum two channels when PS is enabled. */ + } + + return errorStatus; +} + + +SBR_ERROR sbrDecoder_Apply ( HANDLE_SBRDECODER self, + INT_PCM *timeData, + int *numChannels, + int *sampleRate, + const UCHAR channelMapping[(6)], + const int interleaved, + const int coreDecodedOk, + UCHAR *psDecoded ) +{ + SBR_ERROR errorStatus = SBRDEC_OK; + + int psPossible = 0; + int sbrElementNum; + int numCoreChannels = *numChannels; + int numSbrChannels = 0; + + psPossible = *psDecoded; + + /* Sanity check of allocated SBR elements. */ + for (sbrElementNum=0; sbrElementNumnumSbrElements; sbrElementNum++) { + if (self->pSbrElement[sbrElementNum] == NULL) { + return SBRDEC_CREATE_ERROR; + } + } + + if (self->numSbrElements != 1 || self->pSbrElement[0]->elementID != ID_SCE) { + psPossible = 0; + } + + + /* In case of non-interleaved time domain data and upsampling, make room for bigger SBR output. */ + if (self->synDownsampleFac == 1 && interleaved == 0) { + int c, outputFrameSize; + + outputFrameSize = + self->pSbrElement[0]->pSbrChannel[0]->SbrDec.SynthesisQMF.no_channels + * self->pSbrElement[0]->pSbrChannel[0]->SbrDec.SynthesisQMF.no_col; + + for (c=numCoreChannels-1; c>0; c--) { + FDKmemmove(timeData + c*outputFrameSize, timeData + c*self->codecFrameSize , self->codecFrameSize*sizeof(INT_PCM)); + } + } + + + /* Make sure that even if no SBR data was found/parsed *psDecoded is returned 1 if psPossible was 0. */ + if (psPossible == 0) { + self->flags &= ~SBRDEC_PS_DECODED; + } + + /* Loop over SBR elements */ + for (sbrElementNum = 0; sbrElementNumnumSbrElements; sbrElementNum++) + { + int numElementChan; + + if (psPossible && self->pSbrElement[sbrElementNum]->pSbrChannel[1] == NULL) { + errorStatus = SBRDEC_UNSUPPORTED_CONFIG; + goto bail; + } + + numElementChan = (self->pSbrElement[sbrElementNum]->elementID == ID_CPE) ? 2 : 1; + + /* If core signal is bad then force upsampling */ + if ( ! coreDecodedOk ) { + self->pSbrElement[sbrElementNum]->frameErrorFlag[self->pSbrElement[sbrElementNum]->useFrameSlot] = 1; + } + + errorStatus = sbrDecoder_DecodeElement ( + self, + timeData, + interleaved, + channelMapping, + sbrElementNum, + numCoreChannels, + &numElementChan, + psPossible + ); + + if (errorStatus != SBRDEC_OK) { + goto bail; + } + + numSbrChannels += numElementChan; + channelMapping += numElementChan; + + if (numSbrChannels >= numCoreChannels) { + break; + } + } + + /* Update numChannels and samplerate */ + *numChannels = numSbrChannels; + *sampleRate = self->sampleRateOut; + *psDecoded = (self->flags & SBRDEC_PS_DECODED) ? 1 : 0; + + + +bail: + + return errorStatus; +} + + +SBR_ERROR sbrDecoder_Close ( HANDLE_SBRDECODER *pSelf ) +{ + HANDLE_SBRDECODER self = *pSelf; + int i; + + if (self != NULL) + { + if (self->hParametricStereoDec != NULL) { + DeletePsDec ( &self->hParametricStereoDec ); + } + + if (self->workBuffer1 != NULL) { + FreeRam_SbrDecWorkBuffer1(&self->workBuffer1); + } + if (self->workBuffer2 != NULL) { + FreeRam_SbrDecWorkBuffer2(&self->workBuffer2); + } + + for (i = 0; i < (4); i++) { + sbrDecoder_DestroyElement( self, i ); + } + + FreeRam_SbrDecoder(pSelf); + } + + return SBRDEC_OK; +} + + +INT sbrDecoder_GetLibInfo( LIB_INFO *info ) +{ + int i; + + if (info == NULL) { + return -1; + } + + /* search for next free tab */ + for (i = 0; i < FDK_MODULE_LAST; i++) { + if (info[i].module_id == FDK_NONE) + break; + } + if (i == FDK_MODULE_LAST) + return -1; + info += i; + + info->module_id = FDK_SBRDEC; + info->version = LIB_VERSION(SBRDECODER_LIB_VL0, SBRDECODER_LIB_VL1, SBRDECODER_LIB_VL2); + LIB_VERSION_STRING(info); + info->build_date = (char *)SBRDECODER_LIB_BUILD_DATE; + info->build_time = (char *)SBRDECODER_LIB_BUILD_TIME; + info->title = (char *)SBRDECODER_LIB_TITLE; + + /* Set flags */ + info->flags = 0 + | CAPF_SBR_HQ + | CAPF_SBR_LP + | CAPF_SBR_PS_MPEG + | CAPF_SBR_CONCEALMENT + | CAPF_SBR_DRC + ; + /* End of flags */ + + return 0; +} + diff --git a/libSBRdec/src/transcendent.h b/libSBRdec/src/transcendent.h new file mode 100644 index 0000000..fae36d6 --- /dev/null +++ b/libSBRdec/src/transcendent.h @@ -0,0 +1,313 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief FDK Fixed Point Arithmetic Library Interface $Revision: 36841 $ +*/ + +/*! + \mainpage Fixed Point Arithmetic Library Documentation + + Information in this SDK is subject to change without notice. Companies, + names, and data used in examples herein are fictitious unless otherwise + noted. + + Product and corporate names may be trademarks or registered trademarks + of other companies. They are used for explanation only, with no intent + to infringe. + + No part of this publication may be reproduced or utilized in any form or + by any means, electronic or mechanical, including photocopying and + microfilm, without permission in writing from the publisher. +*/ + +#ifndef __TRANSCENDENT_H +#define __TRANSCENDENT_H + +#include "sbrdecoder.h" +#include "sbr_rom.h" + +/************************************************************************/ +/*! + \brief Get number of octaves between frequencies a and b + + The Result is scaled with 1/8. + The valid range for a and b is 1 to LOG_DUALIS_TABLE_SIZE. + + \return ld(a/b) / 8 +*/ +/************************************************************************/ +static inline FIXP_SGL FDK_getNumOctavesDiv8(INT a, /*!< lower band */ + INT b) /*!< upper band */ +{ + return ( (SHORT)((LONG)(CalcLdInt(b) - CalcLdInt(a))>>(FRACT_BITS-3)) ); +} + + +/************************************************************************/ +/*! + \brief Add two values given by mantissa and exponent. + + Mantissas are in fract format with values between 0 and 1.
+ The base for exponents is 2. Example: \f$ a = a\_m * 2^{a\_e} \f$
+*/ +/************************************************************************/ +inline void FDK_add_MantExp(FIXP_SGL a_m, /*!< Mantissa of 1st operand a */ + SCHAR a_e, /*!< Exponent of 1st operand a */ + FIXP_SGL b_m, /*!< Mantissa of 2nd operand b */ + SCHAR b_e, /*!< Exponent of 2nd operand b */ + FIXP_SGL *ptrSum_m, /*!< Mantissa of result */ + SCHAR *ptrSum_e) /*!< Exponent of result */ +{ + FIXP_DBL accu; + int shift; + int shiftAbs; + + FIXP_DBL shiftedMantissa; + FIXP_DBL otherMantissa; + + /* Equalize exponents of the summands. + For the smaller summand, the exponent is adapted and + for compensation, the mantissa is shifted right. */ + + shift = (int)(a_e - b_e); + + shiftAbs = (shift>0)? shift : -shift; + shiftAbs = (shiftAbs < DFRACT_BITS-1)? shiftAbs : DFRACT_BITS-1; + shiftedMantissa = (shift>0)? (FX_SGL2FX_DBL(b_m) >> shiftAbs) : (FX_SGL2FX_DBL(a_m) >> shiftAbs); + otherMantissa = (shift>0)? FX_SGL2FX_DBL(a_m) : FX_SGL2FX_DBL(b_m); + *ptrSum_e = (shift>0)? a_e : b_e; + + accu = (shiftedMantissa >> 1) + (otherMantissa >> 1); + /* shift by 1 bit to avoid overflow */ + + if ( (accu >= (FL2FXCONST_DBL(0.5f) - (FIXP_DBL)1)) || (accu <= FL2FXCONST_DBL(-0.5f)) ) + *ptrSum_e += 1; + else + accu = (shiftedMantissa + otherMantissa); + + *ptrSum_m = FX_DBL2FX_SGL(accu); + +} + +inline void FDK_add_MantExp(FIXP_DBL a, /*!< Mantissa of 1st operand a */ + SCHAR a_e, /*!< Exponent of 1st operand a */ + FIXP_DBL b, /*!< Mantissa of 2nd operand b */ + SCHAR b_e, /*!< Exponent of 2nd operand b */ + FIXP_DBL *ptrSum, /*!< Mantissa of result */ + SCHAR *ptrSum_e) /*!< Exponent of result */ +{ + FIXP_DBL accu; + int shift; + int shiftAbs; + + FIXP_DBL shiftedMantissa; + FIXP_DBL otherMantissa; + + /* Equalize exponents of the summands. + For the smaller summand, the exponent is adapted and + for compensation, the mantissa is shifted right. */ + + shift = (int)(a_e - b_e); + + shiftAbs = (shift>0)? shift : -shift; + shiftAbs = (shiftAbs < DFRACT_BITS-1)? shiftAbs : DFRACT_BITS-1; + shiftedMantissa = (shift>0)? (b >> shiftAbs) : (a >> shiftAbs); + otherMantissa = (shift>0)? a : b; + *ptrSum_e = (shift>0)? a_e : b_e; + + accu = (shiftedMantissa >> 1) + (otherMantissa >> 1); + /* shift by 1 bit to avoid overflow */ + + if ( (accu >= (FL2FXCONST_DBL(0.5f) - (FIXP_DBL)1)) || (accu <= FL2FXCONST_DBL(-0.5f)) ) + *ptrSum_e += 1; + else + accu = (shiftedMantissa + otherMantissa); + + *ptrSum = accu; + +} + +/************************************************************************/ +/*! + \brief Divide two values given by mantissa and exponent. + + Mantissas are in fract format with values between 0 and 1.
+ The base for exponents is 2. Example: \f$ a = a\_m * 2^{a\_e} \f$
+ + For performance reasons, the division is based on a table lookup + which limits accuracy. +*/ +/************************************************************************/ +static inline void FDK_divide_MantExp(FIXP_SGL a_m, /*!< Mantissa of dividend a */ + SCHAR a_e, /*!< Exponent of dividend a */ + FIXP_SGL b_m, /*!< Mantissa of divisor b */ + SCHAR b_e, /*!< Exponent of divisor b */ + FIXP_SGL *ptrResult_m, /*!< Mantissa of quotient a/b */ + SCHAR *ptrResult_e) /*!< Exponent of quotient a/b */ + +{ + int preShift, postShift, index, shift; + FIXP_DBL ratio_m; + FIXP_SGL bInv_m = FL2FXCONST_SGL(0.0f); + + preShift = CntLeadingZeros(FX_SGL2FX_DBL(b_m)); + + /* + Shift b into the range from 0..INV_TABLE_SIZE-1, + + E.g. 10 bits must be skipped for INV_TABLE_BITS 8: + - leave 8 bits as index for table + - skip sign bit, + - skip first bit of mantissa, because this is always the same (>0.5) + + We are dealing with energies, so we need not care + about negative numbers + */ + + /* + The first interval has half width so the lowest bit of the index is + needed for a doubled resolution. + */ + shift = (FRACT_BITS - 2 - INV_TABLE_BITS - preShift); + + index = (shift<0)? (LONG)b_m << (-shift) : (LONG)b_m >> shift; + + + /* The index has INV_TABLE_BITS +1 valid bits here. Clear the other bits. */ + index &= (1 << (INV_TABLE_BITS+1)) - 1; + + /* Remove offset of half an interval */ + index--; + + /* Now the lowest bit is shifted out */ + index = index >> 1; + + /* Fetch inversed mantissa from table: */ + bInv_m = (index<0)? bInv_m : FDK_sbrDecoder_invTable[index]; + + /* Multiply a with the inverse of b: */ + ratio_m = (index<0)? FX_SGL2FX_DBL(a_m >> 1) : fMultDiv2(bInv_m,a_m); + + postShift = CntLeadingZeros(ratio_m)-1; + + *ptrResult_m = FX_DBL2FX_SGL(ratio_m << postShift); + *ptrResult_e = a_e - b_e + 1 + preShift - postShift; +} + +static inline void FDK_divide_MantExp(FIXP_DBL a_m, /*!< Mantissa of dividend a */ + SCHAR a_e, /*!< Exponent of dividend a */ + FIXP_DBL b_m, /*!< Mantissa of divisor b */ + SCHAR b_e, /*!< Exponent of divisor b */ + FIXP_DBL *ptrResult_m, /*!< Mantissa of quotient a/b */ + SCHAR *ptrResult_e) /*!< Exponent of quotient a/b */ + +{ + int preShift, postShift, index, shift; + FIXP_DBL ratio_m; + FIXP_SGL bInv_m = FL2FXCONST_SGL(0.0f); + + preShift = CntLeadingZeros(b_m); + + /* + Shift b into the range from 0..INV_TABLE_SIZE-1, + + E.g. 10 bits must be skipped for INV_TABLE_BITS 8: + - leave 8 bits as index for table + - skip sign bit, + - skip first bit of mantissa, because this is always the same (>0.5) + + We are dealing with energies, so we need not care + about negative numbers + */ + + /* + The first interval has half width so the lowest bit of the index is + needed for a doubled resolution. + */ + shift = (DFRACT_BITS - 2 - INV_TABLE_BITS - preShift); + + index = (shift<0)? (LONG)b_m << (-shift) : (LONG)b_m >> shift; + + + /* The index has INV_TABLE_BITS +1 valid bits here. Clear the other bits. */ + index &= (1 << (INV_TABLE_BITS+1)) - 1; + + /* Remove offset of half an interval */ + index--; + + /* Now the lowest bit is shifted out */ + index = index >> 1; + + /* Fetch inversed mantissa from table: */ + bInv_m = (index<0)? bInv_m : FDK_sbrDecoder_invTable[index]; + + /* Multiply a with the inverse of b: */ + ratio_m = (index<0)? (a_m >> 1) : fMultDiv2(bInv_m,a_m); + + postShift = CntLeadingZeros(ratio_m)-1; + + *ptrResult_m = ratio_m << postShift; + *ptrResult_e = a_e - b_e + 1 + preShift - postShift; +} + +/*! + \brief Calculate the squareroot of a number given by mantissa and exponent + + Mantissa is in fract format with values between 0 and 1.
+ The base for the exponent is 2. Example: \f$ a = a\_m * 2^{a\_e} \f$
+ The operand is addressed via pointers and will be overwritten with the result. + + For performance reasons, the square root is based on a table lookup + which limits accuracy. +*/ +static inline void FDK_sqrt_MantExp(FIXP_DBL *mantissa, /*!< Pointer to mantissa */ + SCHAR *exponent, + const SCHAR *destScale) +{ + FIXP_DBL input_m = *mantissa; + int input_e = (int) *exponent; + FIXP_DBL result = FL2FXCONST_DBL(0.0f); + int result_e = -FRACT_BITS; + + /* Call lookup square root, which does internally normalization. */ + result = sqrtFixp_lookup(input_m, &input_e); + result_e = input_e; + + /* Write result */ + if (exponent==destScale) { + *mantissa = result; + *exponent = result_e; + } else { + int shift = result_e - *destScale; + *mantissa = (shift>=0) ? result << (INT)fixMin(DFRACT_BITS-1,shift) + : result >> (INT)fixMin(DFRACT_BITS-1,-shift); + *exponent = *destScale; + } +} + + +#endif diff --git a/libSBRenc/Android.mk b/libSBRenc/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/libSBRenc/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/libSBRenc/include/sbr_encoder.h b/libSBRenc/include/sbr_encoder.h new file mode 100644 index 0000000..d54582d --- /dev/null +++ b/libSBRenc/include/sbr_encoder.h @@ -0,0 +1,322 @@ +/*************************** Fraunhofer IIS *********************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: SBR encoder top level processing prototype + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef __SBR_ENCODER_H +#define __SBR_ENCODER_H + +#include "common_fix.h" +#include "FDK_audio.h" + +#include "FDK_bitstream.h" + +/* core coder helpers */ +#define MAX_TRANS_FAC 8 +#define MAX_CODEC_FRAME_RATIO 2 +#define MAX_PAYLOAD_SIZE 256 + +typedef struct +{ + INT bitRate; + INT nChannels; + INT sampleFreq; + INT transFac; + INT standardBitrate; +} CODEC_PARAM; + +typedef enum +{ + SBR_MONO, + SBR_LEFT_RIGHT, + SBR_COUPLING, + SBR_SWITCH_LRC +} SBR_STEREO_MODE; + +/* bitstream syntax flags */ +enum +{ + SBR_SYNTAX_LOW_DELAY = 0x0001, + SBR_SYNTAX_SCALABLE = 0x0002, + SBR_SYNTAX_CRC = 0x0004, + SBR_SYNTAX_DRM_CRC = 0x0008 +}; + +typedef struct +{ + UINT bitrateFrom; /*!< inclusive */ + UINT bitrateTo; /*!< exclusive */ + + USHORT sampleRate; /*!< */ + UCHAR numChannels; /*!< */ + + UCHAR startFreq; /*!< bs_start_freq */ + UCHAR startFreqSpeech; /*!< bs_start_freq for speech config flag */ + UCHAR stopFreq; /*!< bs_stop_freq */ + UCHAR stopFreqSpeech; /*!< bs_stop_freq for speech config flag */ + + UCHAR numNoiseBands; /*!< */ + UCHAR noiseFloorOffset; /*!< */ + SCHAR noiseMaxLevel; /*!< */ + SBR_STEREO_MODE stereoMode; /*!< */ + UCHAR freqScale; /*!< */ +} sbrTuningTable_t; + +typedef struct sbrConfiguration +{ + /* + core coder dependent configurations + */ + CODEC_PARAM codecSettings; /*!< Core coder settings. To be set from core coder. */ + INT SendHeaderDataTime; /*!< SBR header send update frequency in ms. */ + INT useWaveCoding; /*!< Flag: usage of wavecoding tool. */ + INT crcSbr; /*!< Flag: usage of SBR-CRC. */ + INT dynBwSupported; /*!< Flag: support for dynamic bandwidth in this combination. */ + INT parametricCoding; /*!< Flag: usage of parametric coding tool. */ + int freq_res_fixfix[3]; /*!< Frequency resolution of envelopes in frame class FIXFIX + 0=1 Env; 1=2 Env; 2=4 Env; */ + /* + core coder dependent tuning parameters + */ + INT tran_thr; /*!< SBR transient detector threshold (* 100). */ + INT noiseFloorOffset; /*!< Noise floor offset. */ + UINT useSpeechConfig; /*!< Flag: adapt tuning parameters according to speech. */ + + + + /* + core coder independent configurations + */ + INT sbrFrameSize; /*!< SBR frame size in samples. Will be calculated from core coder settings. */ + INT sbr_data_extra; /*!< Flag usage of data extra. */ + INT amp_res; /*!< Amplitude resolution. */ + INT ana_max_level; /*!< Noise insertion maximum level. */ + INT tran_fc; /*!< Transient detector start frequency. */ + INT tran_det_mode; /*!< Transient detector mode. */ + INT spread; /*!< Flag: usage of SBR spread. */ + INT stat; /*!< Flag: usage of static framing. */ + INT e; /*!< Number of envelopes when static framing is chosen. */ + SBR_STEREO_MODE stereoMode; /*!< SBR stereo mode. */ + INT deltaTAcrossFrames; /*!< Flag: allow time-delta coding. */ + FIXP_DBL dF_edge_1stEnv; /*!< Extra fraction delta-F coding is allowed to be more expensive. */ + FIXP_DBL dF_edge_incr; /*!< Increment dF_edge_1stEnv this much if dT-coding was used this frame. */ + INT sbr_invf_mode; /*!< Inverse filtering mode. */ + INT sbr_xpos_mode; /*!< Transposer mode. */ + INT sbr_xpos_ctrl; /*!< Transposer control. */ + INT sbr_xpos_level; /*!< Transposer 3rd order level. */ + INT startFreq; /*!< The start frequency table index. */ + INT stopFreq; /*!< The stop frequency table index. */ + INT useSaPan; /*!< Flag: usage of SAPAN stereo. */ + INT dynBwEnabled; /*!< Flag: usage of dynamic bandwidth. */ + INT bParametricStereo; /*!< Flag: usage of parametric stereo coding tool. */ + INT bDownSampledSbr; /*!< Signal downsampled SBR is used. */ + + /* + header_extra1 configuration + */ + UCHAR freqScale; /*!< Frequency grouping. */ + INT alterScale; /*!< Scale resolution. */ + INT sbr_noise_bands; /*!< Number of noise bands. */ + + + /* + header_extra2 configuration + */ + INT sbr_limiter_bands; /*!< Number of limiter bands. */ + INT sbr_limiter_gains; /*!< Gain of limiter. */ + INT sbr_interpol_freq; /*!< Flag: use interpolation in freq. direction. */ + INT sbr_smoothing_length; /*!< Flag: choose length 4 or 0 (=on, off). */ + UCHAR init_amp_res_FF; +} sbrConfiguration, *sbrConfigurationPtr ; + +typedef struct +{ + UINT sbrSyntaxFlags; /**< SBR syntax flags derived from AOT. */ + INT nChannels; /**< Number of channels. */ + + INT nSfb[2]; /**< Number of SBR scalefactor bands for LO_RES and HI_RES (?) */ + INT num_Master; /**< Number of elements in v_k_master. */ + INT sampleFreq; /**< SBR sampling frequency. */ + INT frameSize; + INT xOverFreq; /**< The SBR start frequency. */ + INT dynXOverFreq; /**< Used crossover frequency when dynamic bandwidth is enabled. */ + INT noQmfBands; /**< Number of QMF frequency bands. */ + INT noQmfSlots; /**< Number of QMF slots. */ + + UCHAR *freqBandTable[2]; /**< Frequency table for low and hires, only MAX_FREQ_COEFFS/2 +1 coeefs actually needed for lowres. */ + UCHAR *v_k_master; /**< Master BandTable where freqBandTable is derived from. */ + + + SBR_STEREO_MODE stereoMode; + INT noEnvChannels; /**< Number of envelope channels. */ + + INT useWaveCoding; /**< Flag indicates whether to use wave coding at all. */ + INT useParametricCoding; /**< Flag indicates whether to use para coding at all. */ + INT xposCtrlSwitch; /**< Flag indicates whether to switch xpos ctrl on the fly. */ + INT switchTransposers; /**< Flag indicates whether to switch xpos on the fly . */ + UCHAR initAmpResFF; +} SBR_CONFIG_DATA; + +typedef SBR_CONFIG_DATA *HANDLE_SBR_CONFIG_DATA; + +typedef struct { + MP4_ELEMENT_ID elType; + INT bitRate; + int instanceTag; + UCHAR fParametricStereo; + UCHAR nChannelsInEl; + UCHAR ChannelIndex[2]; +} SBR_ELEMENT_INFO; + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct SBR_ENCODER *HANDLE_SBR_ENCODER; + +/** + * \brief Get the max required input buffer size including delay balancing space + * for N audio channels. + * \param noChannels Number of audio channels. + * \return Max required input buffer size in bytes. + */ +INT sbrEncoder_GetInBufferSize(int noChannels); + +INT sbrEncoder_Open( + HANDLE_SBR_ENCODER *phSbrEncoder, + INT nElements, + INT nChannels, + INT supportPS + ); + +/** + * \brief Initialize SBR Encoder instance. + * \param phSbrEncoder Pointer to a SBR Encoder instance. + * \param elInfo Structure that describes the element/channel arrangement. + * \param noElements Amount of elements described in elInfo. + * \param inputBuffer Pointer to the encoder audio buffer + * \param bandwidth Returns the core audio encoder bandwidth (output) + * \param bufferOffset Returns the offset for the audio input data in order to do delay balancing. + * \param numChannels Input: Encoder input channels. output: core encoder channels. + * \param sampleRate Input: Encoder samplerate. output core encoder samplerate. + * \param frameLength Input: Encoder frameLength. output core encoder frameLength. + * \param aot Input: Desired AOT. output AOT to be used after parameter checking. + * \param delay Input: core encoder delay. Output: total delay because of SBR. + * \param transformFactor The core encoder transform factor (blockswitching). + * \return 0 on success, and non-zero if failed. + */ +INT sbrEncoder_Init( HANDLE_SBR_ENCODER hSbrEncoder, + SBR_ELEMENT_INFO elInfo[(6)], + int noElements, + INT_PCM *inputBuffer, + INT *bandwidth, + INT *bufferOffset, + INT *numChannels, + INT *sampleRate, + INT *frameLength, + AUDIO_OBJECT_TYPE *aot, + int *delay, + int transformFactor, + ULONG statesInitFlag + ); + +/** + * \brief Do delay line buffers housekeeping. To be called after each encoded audio frame. + * \param hEnvEnc SBR Encoder handle. + * \param timeBuffer Pointer to the encoder audio buffer. + * \return 0 on success, and non-zero if failed. + */ +INT sbrEncoder_UpdateBuffers(HANDLE_SBR_ENCODER hEnvEnc, + INT_PCM *timeBuffer + ); + +/** + * \brief Close SBR encoder instance. + * \param phEbrEncoder Handle of SBR encoder instance to be closed. + * \return void + */ +void sbrEncoder_Close(HANDLE_SBR_ENCODER *phEbrEncoder); + +/** + * \brief Encode SBR data of one complete audio frame. + * \param hEnvEncoder Handle of SBR encoder instance. + * \param samples Time samples, always interleaved. + * \param timeInStride Channel stride factor of samples buffer. + * \param sbrDataBits Size of SBR payload in bits. + * \param sbrData SBR payload. + * \return 0 on success, and non-zero if failed. + */ +INT sbrEncoder_EncodeFrame(HANDLE_SBR_ENCODER hEnvEncoder, + INT_PCM *samples, + UINT timeInStride, + UINT sbrDataBits[(6)], + UCHAR sbrData[(6)][MAX_PAYLOAD_SIZE] + ); + +/** + * \brief Write SBR headers of one SBR element. + * \param sbrEncoder Handle of the SBR encoder instance. + * \param hBs Handle of bit stream handle to write SBR header to. + * \param element_index Index of the SBR element which header should be written. + * \param fSendHeaders Flag indicating that the SBR encoder should send more headers in the SBR payload or not. + * \return void + */ +void sbrEncoder_GetHeader(SBR_ENCODER *sbrEncoder, + HANDLE_FDK_BITSTREAM hBs, + INT element_index, + int fSendHeaders); + +/** + * \brief SBR encoder bitrate estimation. + * \param hSbrEncoder SBR encoder handle. + * \return Estimated bitrate. + */ +INT sbrEncoder_GetEstimateBitrate(HANDLE_SBR_ENCODER hSbrEncoder); + + +/** + * \brief Delay between input data and downsampled output data. + * \param hSbrEncoder SBR encoder handle. + * \return Delay. + */ +INT sbrEncoder_GetInputDataDelay(HANDLE_SBR_ENCODER hSbrEncoder); + +/** + * \brief Get decoder library version info. + * \param info Pointer to an allocated LIB_INFO struct, where library info is written to. + * \return 0 on sucess. + */ +INT sbrEncoder_GetLibInfo(LIB_INFO *info); + +void sbrPrintRAM(void); + +void sbrPrintROM(void); + +#ifdef __cplusplus + } +#endif + +#endif /* ifndef __SBR_MAIN_H */ diff --git a/libSBRenc/src/Android.mk b/libSBRenc/src/Android.mk new file mode 100644 index 0000000..55d5d4e --- /dev/null +++ b/libSBRenc/src/Android.mk @@ -0,0 +1,36 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + bit_sbr.cpp \ + env_bit.cpp \ + fram_gen.cpp \ + mh_det.cpp \ + ps_bitenc.cpp \ + ps_encode.cpp \ + resampler.cpp \ + sbr_encoder.cpp \ + sbr_ram.cpp \ + ton_corr.cpp \ + code_env.cpp \ + env_est.cpp \ + invf_est.cpp \ + nf_est.cpp \ + psenc_hybrid.cpp \ + ps_main.cpp \ + sbrenc_freq_sca.cpp \ + sbr_misc.cpp \ + sbr_rom.cpp \ + tran_det.cpp + +LOCAL_CFLAGS := -DANDROID + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../../libFDK/include \ + $(LOCAL_PATH)/../../libSYS/include + +LOCAL_MODULE:= libSBRenc + +include $(BUILD_STATIC_LIBRARY) diff --git a/libSBRenc/src/bit_sbr.cpp b/libSBRenc/src/bit_sbr.cpp new file mode 100644 index 0000000..4088c35 --- /dev/null +++ b/libSBRenc/src/bit_sbr.cpp @@ -0,0 +1,1001 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief SBR bit writing routines $Revision: 36867 $ +*/ + + +#include "bit_sbr.h" + +#include "code_env.h" +#include "cmondata.h" +#include "sbr.h" + +#include "ps_main.h" + +typedef enum { + SBR_ID_SCE = 1, + SBR_ID_CPE +} SBR_ELEMENT_TYPE; + + +static INT encodeSbrData (HANDLE_SBR_ENV_DATA sbrEnvDataLeft, + HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_COMMON_DATA cmonData, + SBR_ELEMENT_TYPE sbrElem, + INT coupling, + UINT sbrSyntaxFlags); + +static INT encodeSbrHeader (HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_COMMON_DATA cmonData); + + +static INT encodeSbrHeaderData (HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_FDK_BITSTREAM hBitStream); + +static INT encodeSbrSingleChannelElement (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream + ,HANDLE_PARAMETRIC_STEREO hParametricStereo + ,UINT sbrSyntaxFlags + ); + + + +static INT encodeSbrChannelPairElement (HANDLE_SBR_ENV_DATA sbrEnvDataLeft, + HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_FDK_BITSTREAM hBitStream, + INT coupling); + + +static INT encodeSbrGrid (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream); + +static int encodeLowDelaySbrGrid ( HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream, + int transmitFreqs); + +static INT encodeSbrDtdf (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream); + +static INT writeNoiseLevelData (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream, + INT coupling); + +static INT writeEnvelopeData (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream, + INT coupling); + +static INT writeSyntheticCodingData (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream); + + +static INT encodeExtendedData (HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_FDK_BITSTREAM hBitStream); + + + +static INT getSbrExtendedDataSize (HANDLE_PARAMETRIC_STEREO hParametricStereo); + +/***************************************************************************** + + functionname: FDKsbrEnc_WriteEnvSingleChannelElement + description: writes pure SBR single channel data element + returns: number of bits written + input: + output: + +*****************************************************************************/ +INT +FDKsbrEnc_WriteEnvSingleChannelElement( + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_COMMON_DATA cmonData, + UINT sbrSyntaxFlags + ) + +{ + INT payloadBits = 0; + + cmonData->sbrHdrBits = 0; + cmonData->sbrDataBits = 0; + + /* write pure sbr data */ + if (sbrEnvData != NULL) { + + /* write header */ + payloadBits += encodeSbrHeader (sbrHeaderData, + sbrBitstreamData, + cmonData); + + + /* write data */ + payloadBits += encodeSbrData (sbrEnvData, + NULL, + hParametricStereo, + cmonData, + SBR_ID_SCE, + 0, + sbrSyntaxFlags); + + } + return payloadBits; +} + +/***************************************************************************** + + functionname: FDKsbrEnc_WriteEnvChannelPairElement + description: writes pure SBR channel pair data element + returns: number of bits written + input: + output: + +*****************************************************************************/ +INT +FDKsbrEnc_WriteEnvChannelPairElement (HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_SBR_ENV_DATA sbrEnvDataLeft, + HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_COMMON_DATA cmonData, + UINT sbrSyntaxFlags) + +{ + INT payloadBits = 0; + cmonData->sbrHdrBits = 0; + cmonData->sbrDataBits = 0; + + /* write pure sbr data */ + if ((sbrEnvDataLeft != NULL) && (sbrEnvDataRight != NULL)) { + + /* write header */ + payloadBits += encodeSbrHeader (sbrHeaderData, + sbrBitstreamData, + cmonData); + + /* write data */ + payloadBits += encodeSbrData (sbrEnvDataLeft, + sbrEnvDataRight, + hParametricStereo, + cmonData, + SBR_ID_CPE, + sbrHeaderData->coupling, + sbrSyntaxFlags); + + } + return payloadBits; +} + +INT +FDKsbrEnc_CountSbrChannelPairElement (HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_SBR_ENV_DATA sbrEnvDataLeft, + HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_COMMON_DATA cmonData, + UINT sbrSyntaxFlags) +{ + INT payloadBits; + INT bitPos = FDKgetValidBits(&cmonData->sbrBitbuf); + + payloadBits = FDKsbrEnc_WriteEnvChannelPairElement(sbrHeaderData, + hParametricStereo, + sbrBitstreamData, + sbrEnvDataLeft, + sbrEnvDataRight, + cmonData, + sbrSyntaxFlags); + + FDKpushBack(&cmonData->sbrBitbuf, (FDKgetValidBits(&cmonData->sbrBitbuf) - bitPos) ); + + return payloadBits; +} + + +void sbrEncoder_GetHeader(SBR_ENCODER *sbrEncoder, + HANDLE_FDK_BITSTREAM hBs, + INT element_index, + int fSendHeaders) +{ + int bits; + + bits = encodeSbrHeaderData (&sbrEncoder->sbrElement[element_index]->sbrHeaderData, hBs); + + if (fSendHeaders == 0) { + /* Prevent header being embedded into the SBR payload. */ + sbrEncoder->sbrElement[element_index]->sbrBitstreamData.NrSendHeaderData = -1; + sbrEncoder->sbrElement[element_index]->sbrBitstreamData.HeaderActive = 0; + sbrEncoder->sbrElement[element_index]->sbrBitstreamData.CountSendHeaderData = -1; + } +} + + +/***************************************************************************** + + functionname: encodeSbrHeader + description: encodes SBR Header information + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT +encodeSbrHeader (HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_COMMON_DATA cmonData) +{ + INT payloadBits = 0; + + if (sbrBitstreamData->HeaderActive) { + payloadBits += FDKwriteBits (&cmonData->sbrBitbuf, 1, 1); + payloadBits += encodeSbrHeaderData (sbrHeaderData, + &cmonData->sbrBitbuf); + } + else { + payloadBits += FDKwriteBits (&cmonData->sbrBitbuf, 0, 1); + } + + cmonData->sbrHdrBits = payloadBits; + + return payloadBits; +} + + + +/***************************************************************************** + + functionname: encodeSbrHeaderData + description: writes sbr_header() + bs_protocol_version through bs_header_extra_2 + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT +encodeSbrHeaderData (HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_FDK_BITSTREAM hBitStream) + +{ + INT payloadBits = 0; + if (sbrHeaderData != NULL) { + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_amp_res, + SI_SBR_AMP_RES_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_start_frequency, + SI_SBR_START_FREQ_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_stop_frequency, + SI_SBR_STOP_FREQ_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_xover_band, + SI_SBR_XOVER_BAND_BITS); + + payloadBits += FDKwriteBits (hBitStream, 0, + SI_SBR_RESERVED_BITS); + + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->header_extra_1, + SI_SBR_HEADER_EXTRA_1_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->header_extra_2, + SI_SBR_HEADER_EXTRA_2_BITS); + + + if (sbrHeaderData->header_extra_1) { + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->freqScale, + SI_SBR_FREQ_SCALE_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->alterScale, + SI_SBR_ALTER_SCALE_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_noise_bands, + SI_SBR_NOISE_BANDS_BITS); + } /* sbrHeaderData->header_extra_1 */ + + if (sbrHeaderData->header_extra_2) { + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_limiter_bands, + SI_SBR_LIMITER_BANDS_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_limiter_gains, + SI_SBR_LIMITER_GAINS_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_interpol_freq, + SI_SBR_INTERPOL_FREQ_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_smoothing_length, + SI_SBR_SMOOTHING_LENGTH_BITS); + + } /* sbrHeaderData->header_extra_2 */ + } /* sbrHeaderData != NULL */ + + return payloadBits; +} + + +/***************************************************************************** + + functionname: encodeSbrData + description: encodes sbr Data information + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT +encodeSbrData (HANDLE_SBR_ENV_DATA sbrEnvDataLeft, + HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_COMMON_DATA cmonData, + SBR_ELEMENT_TYPE sbrElem, + INT coupling, + UINT sbrSyntaxFlags) +{ + INT payloadBits = 0; + + switch (sbrElem) { + case SBR_ID_SCE: + payloadBits += encodeSbrSingleChannelElement (sbrEnvDataLeft, &cmonData->sbrBitbuf, hParametricStereo, sbrSyntaxFlags); + break; + case SBR_ID_CPE: + payloadBits += encodeSbrChannelPairElement (sbrEnvDataLeft, sbrEnvDataRight, hParametricStereo, &cmonData->sbrBitbuf, coupling); + break; + default: + /* we never should apply SBR to any other element type */ + FDK_ASSERT (0); + } + + cmonData->sbrDataBits = payloadBits; + + return payloadBits; +} + +#define MODE_FREQ_TANS 1 +#define MODE_NO_FREQ_TRAN 0 +#define LD_TRANSMISSION MODE_FREQ_TANS +static int encodeFreqs (int mode) { + return ((mode & MODE_FREQ_TANS) ? 1 : 0); +} + + +/***************************************************************************** + + functionname: encodeSbrSingleChannelElement + description: encodes sbr SCE information + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT +encodeSbrSingleChannelElement (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream + ,HANDLE_PARAMETRIC_STEREO hParametricStereo + ,UINT sbrSyntaxFlags + ) +{ + INT i, payloadBits = 0; + + payloadBits += FDKwriteBits (hBitStream, 0, SI_SBR_DATA_EXTRA_BITS); /* no reserved bits */ + + if (sbrEnvData->ldGrid) { + if ( sbrEnvData->hSbrBSGrid->frameClass != FIXFIXonly ) { + /* encode normal SbrGrid */ + payloadBits += encodeSbrGrid (sbrEnvData, hBitStream); + } else { + /* use FIXFIXonly frame Grid */ + payloadBits += encodeLowDelaySbrGrid ( sbrEnvData, hBitStream, encodeFreqs(LD_TRANSMISSION)); + } + } + else + { + if (sbrSyntaxFlags & SBR_SYNTAX_SCALABLE) { + payloadBits += FDKwriteBits (hBitStream, 1, SI_SBR_COUPLING_BITS); + } + payloadBits += encodeSbrGrid (sbrEnvData, hBitStream); + } + + payloadBits += encodeSbrDtdf (sbrEnvData, hBitStream); + + for (i = 0; i < sbrEnvData->noOfnoisebands; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->sbr_invf_mode_vec[i], SI_SBR_INVF_MODE_BITS); + } + + payloadBits += writeEnvelopeData (sbrEnvData, hBitStream, 0); + payloadBits += writeNoiseLevelData (sbrEnvData, hBitStream, 0); + + payloadBits += writeSyntheticCodingData (sbrEnvData,hBitStream); + + payloadBits += encodeExtendedData(hParametricStereo, hBitStream); + + return payloadBits; +} + + +/***************************************************************************** + + functionname: encodeSbrChannelPairElement + description: encodes sbr CPE information + returns: + input: + output: + +*****************************************************************************/ +static INT +encodeSbrChannelPairElement (HANDLE_SBR_ENV_DATA sbrEnvDataLeft, + HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_FDK_BITSTREAM hBitStream, + INT coupling) +{ + INT payloadBits = 0; + INT i = 0; + + payloadBits += FDKwriteBits (hBitStream, 0, SI_SBR_DATA_EXTRA_BITS); /* no reserved bits */ + + payloadBits += FDKwriteBits (hBitStream, coupling, SI_SBR_COUPLING_BITS); + + if (coupling) { + if (sbrEnvDataLeft->ldGrid) { + if ( sbrEnvDataLeft->hSbrBSGrid->frameClass != FIXFIXonly ) { + /* normal SbrGrid */ + payloadBits += encodeSbrGrid (sbrEnvDataLeft, hBitStream); + + } else { + /* FIXFIXonly frame Grid */ + payloadBits += encodeLowDelaySbrGrid ( sbrEnvDataLeft, hBitStream, encodeFreqs(LD_TRANSMISSION)); + } + } else + payloadBits += encodeSbrGrid (sbrEnvDataLeft, hBitStream); + + payloadBits += encodeSbrDtdf (sbrEnvDataLeft, hBitStream); + payloadBits += encodeSbrDtdf (sbrEnvDataRight, hBitStream); + + for (i = 0; i < sbrEnvDataLeft->noOfnoisebands; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvDataLeft->sbr_invf_mode_vec[i], SI_SBR_INVF_MODE_BITS); + } + + payloadBits += writeEnvelopeData (sbrEnvDataLeft, hBitStream,1); + payloadBits += writeNoiseLevelData (sbrEnvDataLeft, hBitStream,1); + payloadBits += writeEnvelopeData (sbrEnvDataRight, hBitStream,1); + payloadBits += writeNoiseLevelData (sbrEnvDataRight, hBitStream,1); + + payloadBits += writeSyntheticCodingData (sbrEnvDataLeft,hBitStream); + payloadBits += writeSyntheticCodingData (sbrEnvDataRight,hBitStream); + + } else { /* no coupling */ + FDK_ASSERT(sbrEnvDataLeft->ldGrid == sbrEnvDataRight->ldGrid); + + if (sbrEnvDataLeft->ldGrid || sbrEnvDataRight->ldGrid) { + /* sbrEnvDataLeft (left channel) */ + if ( sbrEnvDataLeft->hSbrBSGrid->frameClass != FIXFIXonly) { + /* no FIXFIXonly Frame so we dont need encodeLowDelaySbrGrid */ + /* normal SbrGrid */ + payloadBits += encodeSbrGrid (sbrEnvDataLeft, hBitStream); + + } else { + /* FIXFIXonly frame Grid */ + payloadBits += encodeLowDelaySbrGrid ( sbrEnvDataLeft, hBitStream, encodeFreqs(LD_TRANSMISSION)); + } + + /* sbrEnvDataRight (right channel) */ + if ( sbrEnvDataRight->hSbrBSGrid->frameClass != FIXFIXonly) { + /* no FIXFIXonly Frame so we dont need encodeLowDelaySbrGrid */ + /* normal SbrGrid */ + payloadBits += encodeSbrGrid (sbrEnvDataRight, hBitStream); + + } else { + /* FIXFIXonly frame Grid */ + payloadBits += encodeLowDelaySbrGrid ( sbrEnvDataRight, hBitStream, encodeFreqs(LD_TRANSMISSION)); + } + } else + { + payloadBits += encodeSbrGrid (sbrEnvDataLeft, hBitStream); + payloadBits += encodeSbrGrid (sbrEnvDataRight, hBitStream); + } + payloadBits += encodeSbrDtdf (sbrEnvDataLeft, hBitStream); + payloadBits += encodeSbrDtdf (sbrEnvDataRight, hBitStream); + + for (i = 0; i < sbrEnvDataLeft->noOfnoisebands; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvDataLeft->sbr_invf_mode_vec[i], + SI_SBR_INVF_MODE_BITS); + } + for (i = 0; i < sbrEnvDataRight->noOfnoisebands; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvDataRight->sbr_invf_mode_vec[i], + SI_SBR_INVF_MODE_BITS); + } + + payloadBits += writeEnvelopeData (sbrEnvDataLeft, hBitStream,0); + payloadBits += writeEnvelopeData (sbrEnvDataRight, hBitStream,0); + payloadBits += writeNoiseLevelData (sbrEnvDataLeft, hBitStream,0); + payloadBits += writeNoiseLevelData (sbrEnvDataRight, hBitStream,0); + + payloadBits += writeSyntheticCodingData (sbrEnvDataLeft,hBitStream); + payloadBits += writeSyntheticCodingData (sbrEnvDataRight,hBitStream); + + } /* coupling */ + + payloadBits += encodeExtendedData(hParametricStereo, hBitStream); + + return payloadBits; +} + +static INT ceil_ln2(INT x) +{ + INT tmp=-1; + while((1<<++tmp) < x); + return(tmp); +} + + +/***************************************************************************** + + functionname: encodeSbrGrid + description: if hBitStream != NULL writes bits that describes the + time/frequency grouping of a frame; else counts them only + returns: number of bits written or counted + input: + output: + +*****************************************************************************/ +static INT +encodeSbrGrid (HANDLE_SBR_ENV_DATA sbrEnvData, HANDLE_FDK_BITSTREAM hBitStream) +{ + INT payloadBits = 0; + INT i, temp; + INT bufferFrameStart = sbrEnvData->hSbrBSGrid->bufferFrameStart; + INT numberTimeSlots = sbrEnvData->hSbrBSGrid->numberTimeSlots; + + if (sbrEnvData->ldGrid) + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hSbrBSGrid->frameClass, + SBR_CLA_BITS_LD); + else + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hSbrBSGrid->frameClass, + SBR_CLA_BITS); + + switch (sbrEnvData->hSbrBSGrid->frameClass) { + case FIXFIXonly: + FDK_ASSERT(0 /* Fatal error in encodeSbrGrid! */); + break; + case FIXFIX: + temp = ceil_ln2(sbrEnvData->hSbrBSGrid->bs_num_env); + payloadBits += FDKwriteBits (hBitStream, temp, SBR_ENV_BITS); + if ((sbrEnvData->ldGrid) && (sbrEnvData->hSbrBSGrid->bs_num_env==1)) + payloadBits += FDKwriteBits(hBitStream, sbrEnvData->currentAmpResFF, SI_SBR_AMP_RES_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->v_f[0], SBR_RES_BITS); + + break; + + case FIXVAR: + case VARFIX: + if (sbrEnvData->hSbrBSGrid->frameClass == FIXVAR) + temp = sbrEnvData->hSbrBSGrid->bs_abs_bord - (bufferFrameStart + numberTimeSlots); + else + temp = sbrEnvData->hSbrBSGrid->bs_abs_bord - bufferFrameStart; + + payloadBits += FDKwriteBits (hBitStream, temp, SBR_ABS_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->n, SBR_NUM_BITS); + + for (i = 0; i < sbrEnvData->hSbrBSGrid->n; i++) { + temp = (sbrEnvData->hSbrBSGrid->bs_rel_bord[i] - 2) >> 1; + payloadBits += FDKwriteBits (hBitStream, temp, SBR_REL_BITS); + } + + temp = ceil_ln2(sbrEnvData->hSbrBSGrid->n + 2); + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->p, temp); + + for (i = 0; i < sbrEnvData->hSbrBSGrid->n + 1; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->v_f[i], + SBR_RES_BITS); + } + break; + + case VARVAR: + temp = sbrEnvData->hSbrBSGrid->bs_abs_bord_0 - bufferFrameStart; + payloadBits += FDKwriteBits (hBitStream, temp, SBR_ABS_BITS); + temp = sbrEnvData->hSbrBSGrid->bs_abs_bord_1 - (bufferFrameStart + numberTimeSlots); + payloadBits += FDKwriteBits (hBitStream, temp, SBR_ABS_BITS); + + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->bs_num_rel_0, SBR_NUM_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->bs_num_rel_1, SBR_NUM_BITS); + + for (i = 0; i < sbrEnvData->hSbrBSGrid->bs_num_rel_0; i++) { + temp = (sbrEnvData->hSbrBSGrid->bs_rel_bord_0[i] - 2) >> 1; + payloadBits += FDKwriteBits (hBitStream, temp, SBR_REL_BITS); + } + + for (i = 0; i < sbrEnvData->hSbrBSGrid->bs_num_rel_1; i++) { + temp = (sbrEnvData->hSbrBSGrid->bs_rel_bord_1[i] - 2) >> 1; + payloadBits += FDKwriteBits (hBitStream, temp, SBR_REL_BITS); + } + + temp = ceil_ln2(sbrEnvData->hSbrBSGrid->bs_num_rel_0 + + sbrEnvData->hSbrBSGrid->bs_num_rel_1 + 2); + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->p, temp); + + temp = sbrEnvData->hSbrBSGrid->bs_num_rel_0 + + sbrEnvData->hSbrBSGrid->bs_num_rel_1 + 1; + + for (i = 0; i < temp; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->v_fLR[i], + SBR_RES_BITS); + } + break; + } + + return payloadBits; +} + +#define SBR_CLA_BITS_LD 1 +/***************************************************************************** + + functionname: encodeLowDelaySbrGrid + description: if hBitStream != NULL writes bits that describes the + time/frequency grouping of a frame; + else counts them only + (this function only write the FIXFIXonly Bitstream data) + returns: number of bits written or counted + input: + output: + +*****************************************************************************/ +static int +encodeLowDelaySbrGrid ( HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream, + int transmitFreqs + ) +{ + int payloadBits = 0; + int i; + + /* write FIXFIXonly Grid */ + /* write frameClass [1 bit] for FIXFIXonly Grid */ + payloadBits += FDKwriteBits(hBitStream, 1, SBR_CLA_BITS_LD); + + /* absolute Borders are fix: 0,X,X,X,nTimeSlots; so we dont have to transmit them */ + /* only transmit the transient position! */ + /* with this info (b1) we can reconstruct the Frame on Decoder side : */ + /* border[0] = 0; border[1] = b1; border[2]=b1+2; border[3] = nrTimeSlots */ + + /* use 3 or 4bits for transient border (border) */ + if (sbrEnvData->hSbrBSGrid->numberTimeSlots == 8) + payloadBits += FDKwriteBits ( hBitStream, sbrEnvData->hSbrBSGrid->bs_abs_bord, 3); + else + payloadBits += FDKwriteBits ( hBitStream, sbrEnvData->hSbrBSGrid->bs_abs_bord, 4); + + if (transmitFreqs) { + /* write FreqRes grid */ + for (i = 0; i < sbrEnvData->hSbrBSGrid->bs_num_env; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->v_f[i], SBR_RES_BITS); + } + } + + return payloadBits; +} + +/***************************************************************************** + + functionname: encodeSbrDtdf + description: writes bits that describes the direction of the envelopes of a frame + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT +encodeSbrDtdf (HANDLE_SBR_ENV_DATA sbrEnvData, HANDLE_FDK_BITSTREAM hBitStream) +{ + INT i, payloadBits = 0, noOfNoiseEnvelopes; + + noOfNoiseEnvelopes = sbrEnvData->noOfEnvelopes > 1 ? 2 : 1; + + for (i = 0; i < sbrEnvData->noOfEnvelopes; ++i) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->domain_vec[i], SBR_DIR_BITS); + } + for (i = 0; i < noOfNoiseEnvelopes; ++i) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->domain_vec_noise[i], SBR_DIR_BITS); + } + + return payloadBits; +} + + +/***************************************************************************** + + functionname: writeNoiseLevelData + description: writes bits corresponding to the noise-floor-level + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT +writeNoiseLevelData (HANDLE_SBR_ENV_DATA sbrEnvData, HANDLE_FDK_BITSTREAM hBitStream, INT coupling) +{ + INT j, i, payloadBits = 0; + INT nNoiseEnvelopes = sbrEnvData->noOfEnvelopes > 1 ? 2 : 1; + + for (i = 0; i < nNoiseEnvelopes; i++) { + switch (sbrEnvData->domain_vec_noise[i]) { + case FREQ: + if (coupling && sbrEnvData->balance) { + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->sbr_noise_levels[i * sbrEnvData->noOfnoisebands], + sbrEnvData->si_sbr_start_noise_bits_balance); + } else { + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->sbr_noise_levels[i * sbrEnvData->noOfnoisebands], + sbrEnvData->si_sbr_start_noise_bits); + } + + for (j = 1 + i * sbrEnvData->noOfnoisebands; j < (sbrEnvData->noOfnoisebands * (1 + i)); j++) { + if (coupling) { + if (sbrEnvData->balance) { + /* coupling && balance */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableNoiseBalanceFreqC[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV_BALANCE11], + sbrEnvData->hufftableNoiseBalanceFreqL[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV_BALANCE11]); + } else { + /* coupling && !balance */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableNoiseLevelFreqC[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11], + sbrEnvData->hufftableNoiseLevelFreqL[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11]); + } + } else { + /* !coupling */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableNoiseFreqC[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11], + sbrEnvData->hufftableNoiseFreqL[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11]); + } + } + break; + + case TIME: + for (j = i * sbrEnvData->noOfnoisebands; j < (sbrEnvData->noOfnoisebands * (1 + i)); j++) { + if (coupling) { + if (sbrEnvData->balance) { + /* coupling && balance */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableNoiseBalanceTimeC[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV_BALANCE11], + sbrEnvData->hufftableNoiseBalanceTimeL[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV_BALANCE11]); + } else { + /* coupling && !balance */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableNoiseLevelTimeC[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11], + sbrEnvData->hufftableNoiseLevelTimeL[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11]); + } + } else { + /* !coupling */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableNoiseLevelTimeC[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11], + sbrEnvData->hufftableNoiseLevelTimeL[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11]); + } + } + break; + } + } + return payloadBits; +} + + +/***************************************************************************** + + functionname: writeEnvelopeData + description: writes bits corresponding to the envelope + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT +writeEnvelopeData (HANDLE_SBR_ENV_DATA sbrEnvData, HANDLE_FDK_BITSTREAM hBitStream, INT coupling) +{ + INT payloadBits = 0, j, i, delta; + + for (j = 0; j < sbrEnvData->noOfEnvelopes; j++) { /* loop over all envelopes */ + if (sbrEnvData->domain_vec[j] == FREQ) { + if (coupling && sbrEnvData->balance) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->ienvelope[j][0], sbrEnvData->si_sbr_start_env_bits_balance); + } else { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->ienvelope[j][0], sbrEnvData->si_sbr_start_env_bits); + } + } + + for (i = 1 - sbrEnvData->domain_vec[j]; i < sbrEnvData->noScfBands[j]; i++) { + delta = sbrEnvData->ienvelope[j][i]; + if (coupling && sbrEnvData->balance) { + FDK_ASSERT (fixp_abs (delta) <= sbrEnvData->codeBookScfLavBalance); + } else { + FDK_ASSERT (fixp_abs (delta) <= sbrEnvData->codeBookScfLav); + } + if (coupling) { + if (sbrEnvData->balance) { + if (sbrEnvData->domain_vec[j]) { + /* coupling && balance && TIME */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableBalanceTimeC[delta + sbrEnvData->codeBookScfLavBalance], + sbrEnvData->hufftableBalanceTimeL[delta + sbrEnvData->codeBookScfLavBalance]); + } else { + /* coupling && balance && FREQ */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableBalanceFreqC[delta + sbrEnvData->codeBookScfLavBalance], + sbrEnvData->hufftableBalanceFreqL[delta + sbrEnvData->codeBookScfLavBalance]); + } + } else { + if (sbrEnvData->domain_vec[j]) { + /* coupling && !balance && TIME */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableLevelTimeC[delta + sbrEnvData->codeBookScfLav], + sbrEnvData->hufftableLevelTimeL[delta + sbrEnvData->codeBookScfLav]); + } else { + /* coupling && !balance && FREQ */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableLevelFreqC[delta + sbrEnvData->codeBookScfLav], + sbrEnvData->hufftableLevelFreqL[delta + sbrEnvData->codeBookScfLav]); + } + } + } else { + if (sbrEnvData->domain_vec[j]) { + /* !coupling && TIME */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableTimeC[delta + sbrEnvData->codeBookScfLav], + sbrEnvData->hufftableTimeL[delta + sbrEnvData->codeBookScfLav]); + } else { + /* !coupling && FREQ */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableFreqC[delta + sbrEnvData->codeBookScfLav], + sbrEnvData->hufftableFreqL[delta + sbrEnvData->codeBookScfLav]); + } + } + } + } + return payloadBits; +} + + +/***************************************************************************** + + functionname: encodeExtendedData + description: writes bits corresponding to the extended data + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT encodeExtendedData (HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_FDK_BITSTREAM hBitStream) +{ + INT extDataSize; + INT payloadBits = 0; + + extDataSize = getSbrExtendedDataSize(hParametricStereo); + + + if (extDataSize != 0) { + INT maxExtSize = (1<addHarmonicFlag, 1); + + if (sbrEnvData->addHarmonicFlag) { + for (i = 0; i < sbrEnvData->noHarmonics; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->addHarmonic[i], 1); + } + } + + return payloadBits; +} + +/***************************************************************************** + + functionname: getSbrExtendedDataSize + description: counts the number of bits needed for encoding the + extended data (including extension id) + + returns: number of bits needed for the extended data + input: + output: + +*****************************************************************************/ +static INT +getSbrExtendedDataSize (HANDLE_PARAMETRIC_STEREO hParametricStereo) +{ + INT extDataBits = 0; + + /* add your new extended data counting methods here */ + + /* + no extended data + */ + + if(hParametricStereo){ + /* PS extended data */ + extDataBits += SI_SBR_EXTENSION_ID_BITS; + extDataBits += FDKsbrEnc_PSEnc_WritePSData(hParametricStereo, NULL); + } + + return (extDataBits+7) >> 3; +} + + + + + diff --git a/libSBRenc/src/bit_sbr.h b/libSBRenc/src/bit_sbr.h new file mode 100644 index 0000000..1cda60b --- /dev/null +++ b/libSBRenc/src/bit_sbr.h @@ -0,0 +1,203 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief SBR bit writing $Revision: 36867 $ +*/ +#ifndef __BIT_SBR_H +#define __BIT_SBR_H + +#include "sbr_def.h" +#include "cmondata.h" +#include "fram_gen.h" + +struct SBR_ENV_DATA; + +struct SBR_BITSTREAM_DATA +{ + INT TotalBits; + INT PayloadBits; + INT FillBits; + INT HeaderActive; + INT NrSendHeaderData; /**< input from commandline */ + INT CountSendHeaderData; /**< modulo count. If < 0 then no counting is done (no SBR headers) */ +}; + +typedef struct SBR_BITSTREAM_DATA *HANDLE_SBR_BITSTREAM_DATA; + +struct SBR_HEADER_DATA +{ + AMP_RES sbr_amp_res; + INT sbr_start_frequency; + INT sbr_stop_frequency; + INT sbr_xover_band; + INT sbr_noise_bands; + INT sbr_data_extra; + INT header_extra_1; + INT header_extra_2; + INT sbr_lc_stereo_mode; + INT sbr_limiter_bands; + INT sbr_limiter_gains; + INT sbr_interpol_freq; + INT sbr_smoothing_length; + INT alterScale; + INT freqScale; + + /* + element of sbrdata + */ + SR_MODE sampleRateMode; + + /* + element of channelpairelement + */ + INT coupling; + INT prev_coupling; + + /* + element of singlechannelelement + */ + +}; +typedef struct SBR_HEADER_DATA *HANDLE_SBR_HEADER_DATA; + +struct SBR_ENV_DATA +{ + + INT sbr_xpos_ctrl; + INT freq_res_fixfix; + + + INVF_MODE sbr_invf_mode; + INVF_MODE sbr_invf_mode_vec[MAX_NUM_NOISE_VALUES]; + + XPOS_MODE sbr_xpos_mode; + + INT ienvelope[MAX_ENVELOPES][MAX_FREQ_COEFFS]; + + INT codeBookScfLavBalance; + INT codeBookScfLav; + const INT *hufftableTimeC; + const INT *hufftableFreqC; + const UCHAR *hufftableTimeL; + const UCHAR *hufftableFreqL; + + const INT *hufftableLevelTimeC; + const INT *hufftableBalanceTimeC; + const INT *hufftableLevelFreqC; + const INT *hufftableBalanceFreqC; + const UCHAR *hufftableLevelTimeL; + const UCHAR *hufftableBalanceTimeL; + const UCHAR *hufftableLevelFreqL; + const UCHAR *hufftableBalanceFreqL; + + + const UCHAR *hufftableNoiseTimeL; + const INT *hufftableNoiseTimeC; + const UCHAR *hufftableNoiseFreqL; + const INT *hufftableNoiseFreqC; + + const UCHAR *hufftableNoiseLevelTimeL; + const INT *hufftableNoiseLevelTimeC; + const UCHAR *hufftableNoiseBalanceTimeL; + const INT *hufftableNoiseBalanceTimeC; + const UCHAR *hufftableNoiseLevelFreqL; + const INT *hufftableNoiseLevelFreqC; + const UCHAR *hufftableNoiseBalanceFreqL; + const INT *hufftableNoiseBalanceFreqC; + + HANDLE_SBR_GRID hSbrBSGrid; + + INT noHarmonics; + INT addHarmonicFlag; + UCHAR addHarmonic[MAX_FREQ_COEFFS]; + + + /* calculated helper vars */ + INT si_sbr_start_env_bits_balance; + INT si_sbr_start_env_bits; + INT si_sbr_start_noise_bits_balance; + INT si_sbr_start_noise_bits; + + INT noOfEnvelopes; + INT noScfBands[MAX_ENVELOPES]; + INT domain_vec[MAX_ENVELOPES]; + INT domain_vec_noise[MAX_ENVELOPES]; + SCHAR sbr_noise_levels[MAX_FREQ_COEFFS]; + INT noOfnoisebands; + + INT balance; + AMP_RES init_sbr_amp_res; + AMP_RES currentAmpResFF; + + /* extended data */ + INT extended_data; + INT extension_size; + INT extension_id; + UCHAR extended_data_buffer[SBR_EXTENDED_DATA_MAX_CNT]; + + UCHAR ldGrid; +}; +typedef struct SBR_ENV_DATA *HANDLE_SBR_ENV_DATA; + + + +INT FDKsbrEnc_WriteEnvSingleChannelElement(struct SBR_HEADER_DATA *sbrHeaderData, + struct T_PARAMETRIC_STEREO *hParametricStereo, + struct SBR_BITSTREAM_DATA *sbrBitstreamData, + struct SBR_ENV_DATA *sbrEnvData, + struct COMMON_DATA *cmonData, + UINT sbrSyntaxFlags); + + +INT FDKsbrEnc_WriteEnvChannelPairElement(struct SBR_HEADER_DATA *sbrHeaderData, + struct T_PARAMETRIC_STEREO *hParametricStereo, + struct SBR_BITSTREAM_DATA *sbrBitstreamData, + struct SBR_ENV_DATA *sbrEnvDataLeft, + struct SBR_ENV_DATA *sbrEnvDataRight, + struct COMMON_DATA *cmonData, + UINT sbrSyntaxFlags); + + + +INT FDKsbrEnc_CountSbrChannelPairElement (struct SBR_HEADER_DATA *sbrHeaderData, + struct T_PARAMETRIC_STEREO *hParametricStereo, + struct SBR_BITSTREAM_DATA *sbrBitstreamData, + struct SBR_ENV_DATA *sbrEnvDataLeft, + struct SBR_ENV_DATA *sbrEnvDataRight, + struct COMMON_DATA *cmonData, + UINT sbrSyntaxFlags); + + + +/* debugging and tuning functions */ + +/*#define SBR_ENV_STATISTICS */ + + +/*#define SBR_PAYLOAD_MONITOR*/ + +#endif diff --git a/libSBRenc/src/cmondata.h b/libSBRenc/src/cmondata.h new file mode 100644 index 0000000..b5f1c85 --- /dev/null +++ b/libSBRenc/src/cmondata.h @@ -0,0 +1,52 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +****************************************************************************/ +/*! + \file + \brief Core Coder's and SBR's shared data structure definition $Revision: 36847 $ +*/ +#ifndef __SBR_CMONDATA_H +#define __SBR_CMONDATA_H + +#include "FDK_bitstream.h" + + +struct COMMON_DATA { + INT sbrHdrBits; /**< number of SBR header bits */ + INT sbrDataBits; /**< number of SBR data bits */ + INT sbrFillBits; /**< number of SBR fill bits */ + FDK_BITSTREAM sbrBitbuf; /**< the SBR data bitbuffer */ + FDK_BITSTREAM tmpWriteBitbuf; /**< helper var for writing header*/ + INT xOverFreq; /**< the SBR crossover frequency */ + INT dynBwEnabled; /**< indicates if dynamic bandwidth is enabled */ + INT sbrNumChannels; /**< number of channels (meaning mono or stereo) */ + INT dynXOverFreqEnc; /**< encoder dynamic crossover frequency */ +}; + +typedef struct COMMON_DATA *HANDLE_COMMON_DATA; + + + +#endif diff --git a/libSBRenc/src/code_env.cpp b/libSBRenc/src/code_env.cpp new file mode 100644 index 0000000..430b868 --- /dev/null +++ b/libSBRenc/src/code_env.cpp @@ -0,0 +1,584 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +#include "code_env.h" +#include "sbr_rom.h" + +/***************************************************************************** + + functionname: FDKsbrEnc_InitSbrHuffmanTables + description: initializes Huffman Tables dependent on chosen amp_res + returns: error handle + input: + output: + +*****************************************************************************/ +INT +FDKsbrEnc_InitSbrHuffmanTables (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_SBR_CODE_ENVELOPE henv, + HANDLE_SBR_CODE_ENVELOPE hnoise, + AMP_RES amp_res) +{ + if ( (!henv) || (!hnoise) || (!sbrEnvData) ) + return (1); /* not init. */ + + sbrEnvData->init_sbr_amp_res = amp_res; + + switch (amp_res) { + case SBR_AMP_RES_3_0: + /*envelope data*/ + + /*Level/Pan - coding */ + sbrEnvData->hufftableLevelTimeC = v_Huff_envelopeLevelC11T; + sbrEnvData->hufftableLevelTimeL = v_Huff_envelopeLevelL11T; + sbrEnvData->hufftableBalanceTimeC = bookSbrEnvBalanceC11T; + sbrEnvData->hufftableBalanceTimeL = bookSbrEnvBalanceL11T; + + sbrEnvData->hufftableLevelFreqC = v_Huff_envelopeLevelC11F; + sbrEnvData->hufftableLevelFreqL = v_Huff_envelopeLevelL11F; + sbrEnvData->hufftableBalanceFreqC = bookSbrEnvBalanceC11F; + sbrEnvData->hufftableBalanceFreqL = bookSbrEnvBalanceL11F; + + /*Right/Left - coding */ + sbrEnvData->hufftableTimeC = v_Huff_envelopeLevelC11T; + sbrEnvData->hufftableTimeL = v_Huff_envelopeLevelL11T; + sbrEnvData->hufftableFreqC = v_Huff_envelopeLevelC11F; + sbrEnvData->hufftableFreqL = v_Huff_envelopeLevelL11F; + + sbrEnvData->codeBookScfLavBalance = CODE_BOOK_SCF_LAV_BALANCE11; + sbrEnvData->codeBookScfLav = CODE_BOOK_SCF_LAV11; + + sbrEnvData->si_sbr_start_env_bits = SI_SBR_START_ENV_BITS_AMP_RES_3_0; + sbrEnvData->si_sbr_start_env_bits_balance = SI_SBR_START_ENV_BITS_BALANCE_AMP_RES_3_0; + break; + + case SBR_AMP_RES_1_5: + /*envelope data*/ + + /*Level/Pan - coding */ + sbrEnvData->hufftableLevelTimeC = v_Huff_envelopeLevelC10T; + sbrEnvData->hufftableLevelTimeL = v_Huff_envelopeLevelL10T; + sbrEnvData->hufftableBalanceTimeC = bookSbrEnvBalanceC10T; + sbrEnvData->hufftableBalanceTimeL = bookSbrEnvBalanceL10T; + + sbrEnvData->hufftableLevelFreqC = v_Huff_envelopeLevelC10F; + sbrEnvData->hufftableLevelFreqL = v_Huff_envelopeLevelL10F; + sbrEnvData->hufftableBalanceFreqC = bookSbrEnvBalanceC10F; + sbrEnvData->hufftableBalanceFreqL = bookSbrEnvBalanceL10F; + + /*Right/Left - coding */ + sbrEnvData->hufftableTimeC = v_Huff_envelopeLevelC10T; + sbrEnvData->hufftableTimeL = v_Huff_envelopeLevelL10T; + sbrEnvData->hufftableFreqC = v_Huff_envelopeLevelC10F; + sbrEnvData->hufftableFreqL = v_Huff_envelopeLevelL10F; + + sbrEnvData->codeBookScfLavBalance = CODE_BOOK_SCF_LAV_BALANCE10; + sbrEnvData->codeBookScfLav = CODE_BOOK_SCF_LAV10; + + sbrEnvData->si_sbr_start_env_bits = SI_SBR_START_ENV_BITS_AMP_RES_1_5; + sbrEnvData->si_sbr_start_env_bits_balance = SI_SBR_START_ENV_BITS_BALANCE_AMP_RES_1_5; + break; + + default: + return (1); /* undefined amp_res mode */ + } + + /* these are common to both amp_res values */ + /*Noise data*/ + + /*Level/Pan - coding */ + sbrEnvData->hufftableNoiseLevelTimeC = v_Huff_NoiseLevelC11T; + sbrEnvData->hufftableNoiseLevelTimeL = v_Huff_NoiseLevelL11T; + sbrEnvData->hufftableNoiseBalanceTimeC = bookSbrNoiseBalanceC11T; + sbrEnvData->hufftableNoiseBalanceTimeL = bookSbrNoiseBalanceL11T; + + sbrEnvData->hufftableNoiseLevelFreqC = v_Huff_envelopeLevelC11F; + sbrEnvData->hufftableNoiseLevelFreqL = v_Huff_envelopeLevelL11F; + sbrEnvData->hufftableNoiseBalanceFreqC = bookSbrEnvBalanceC11F; + sbrEnvData->hufftableNoiseBalanceFreqL = bookSbrEnvBalanceL11F; + + + /*Right/Left - coding */ + sbrEnvData->hufftableNoiseTimeC = v_Huff_NoiseLevelC11T; + sbrEnvData->hufftableNoiseTimeL = v_Huff_NoiseLevelL11T; + sbrEnvData->hufftableNoiseFreqC = v_Huff_envelopeLevelC11F; + sbrEnvData->hufftableNoiseFreqL = v_Huff_envelopeLevelL11F; + + sbrEnvData->si_sbr_start_noise_bits = SI_SBR_START_NOISE_BITS_AMP_RES_3_0; + sbrEnvData->si_sbr_start_noise_bits_balance = SI_SBR_START_NOISE_BITS_BALANCE_AMP_RES_3_0; + + + /* init envelope tables and codebooks */ + henv->codeBookScfLavBalanceTime = sbrEnvData->codeBookScfLavBalance; + henv->codeBookScfLavBalanceFreq = sbrEnvData->codeBookScfLavBalance; + henv->codeBookScfLavLevelTime = sbrEnvData->codeBookScfLav; + henv->codeBookScfLavLevelFreq = sbrEnvData->codeBookScfLav; + henv->codeBookScfLavTime = sbrEnvData->codeBookScfLav; + henv->codeBookScfLavFreq = sbrEnvData->codeBookScfLav; + + henv->hufftableLevelTimeL = sbrEnvData->hufftableLevelTimeL; + henv->hufftableBalanceTimeL = sbrEnvData->hufftableBalanceTimeL; + henv->hufftableTimeL = sbrEnvData->hufftableTimeL; + henv->hufftableLevelFreqL = sbrEnvData->hufftableLevelFreqL; + henv->hufftableBalanceFreqL = sbrEnvData->hufftableBalanceFreqL; + henv->hufftableFreqL = sbrEnvData->hufftableFreqL; + + henv->codeBookScfLavFreq = sbrEnvData->codeBookScfLav; + henv->codeBookScfLavTime = sbrEnvData->codeBookScfLav; + + henv->start_bits = sbrEnvData->si_sbr_start_env_bits; + henv->start_bits_balance = sbrEnvData->si_sbr_start_env_bits_balance; + + + /* init noise tables and codebooks */ + + hnoise->codeBookScfLavBalanceTime = CODE_BOOK_SCF_LAV_BALANCE11; + hnoise->codeBookScfLavBalanceFreq = CODE_BOOK_SCF_LAV_BALANCE11; + hnoise->codeBookScfLavLevelTime = CODE_BOOK_SCF_LAV11; + hnoise->codeBookScfLavLevelFreq = CODE_BOOK_SCF_LAV11; + hnoise->codeBookScfLavTime = CODE_BOOK_SCF_LAV11; + hnoise->codeBookScfLavFreq = CODE_BOOK_SCF_LAV11; + + hnoise->hufftableLevelTimeL = sbrEnvData->hufftableNoiseLevelTimeL; + hnoise->hufftableBalanceTimeL = sbrEnvData->hufftableNoiseBalanceTimeL; + hnoise->hufftableTimeL = sbrEnvData->hufftableNoiseTimeL; + hnoise->hufftableLevelFreqL = sbrEnvData->hufftableNoiseLevelFreqL; + hnoise->hufftableBalanceFreqL = sbrEnvData->hufftableNoiseBalanceFreqL; + hnoise->hufftableFreqL = sbrEnvData->hufftableNoiseFreqL; + + + hnoise->start_bits = sbrEnvData->si_sbr_start_noise_bits; + hnoise->start_bits_balance = sbrEnvData->si_sbr_start_noise_bits_balance; + + /* No delta coding in time from the previous frame due to 1.5dB FIx-FIX rule */ + henv->upDate = 0; + hnoise->upDate = 0; + return (0); +} + +/******************************************************************************* + Functionname: indexLow2High + ******************************************************************************* + + Description: Nice small patch-functions in order to cope with non-factor-2 + ratios between high-res and low-res + + Arguments: INT offset, INT index, FREQ_RES res + + Return: INT + +*******************************************************************************/ +static INT indexLow2High(INT offset, INT index, FREQ_RES res) +{ + + if(res == FREQ_RES_LOW) + { + if (offset >= 0) + { + if (index < offset) + return(index); + else + return(2*index - offset); + } + else + { + offset = -offset; + if (index < offset) + return(2*index+index); + else + return(2*index + offset); + } + } + else + return(index); +} + + + +/******************************************************************************* + Functionname: mapLowResEnergyVal + ******************************************************************************* + + Description: + + Arguments: INT currVal,INT* prevData, INT offset, INT index, FREQ_RES res + + Return: none + +*******************************************************************************/ +static void mapLowResEnergyVal(SCHAR currVal, SCHAR* prevData, INT offset, INT index, FREQ_RES res) +{ + + if(res == FREQ_RES_LOW) + { + if (offset >= 0) + { + if(index < offset) + prevData[index] = currVal; + else + { + prevData[2*index - offset] = currVal; + prevData[2*index+1 - offset] = currVal; + } + } + else + { + offset = -offset; + if (index < offset) + { + prevData[3*index] = currVal; + prevData[3*index+1] = currVal; + prevData[3*index+2] = currVal; + } + else + { + prevData[2*index + offset] = currVal; + prevData[2*index + 1 + offset] = currVal; + } + } + } + else + prevData[index] = currVal; +} + + + +/******************************************************************************* + Functionname: computeBits + ******************************************************************************* + + Description: + + Arguments: INT delta, + INT codeBookScfLavLevel, + INT codeBookScfLavBalance, + const UCHAR * hufftableLevel, + const UCHAR * hufftableBalance, INT coupling, INT channel) + + Return: INT + +*******************************************************************************/ +static INT +computeBits (SCHAR *delta, + INT codeBookScfLavLevel, + INT codeBookScfLavBalance, + const UCHAR * hufftableLevel, + const UCHAR * hufftableBalance, INT coupling, INT channel) +{ + INT index; + INT delta_bits = 0; + + if (coupling) { + if (channel == 1) + { + if (*delta < 0) + index = fixMax(*delta, -codeBookScfLavBalance); + else + index = fixMin(*delta, codeBookScfLavBalance); + + if (index != *delta) { + *delta = index; + return (10000); + } + + delta_bits = hufftableBalance[index + codeBookScfLavBalance]; + } + else { + if (*delta < 0) + index = fixMax(*delta, -codeBookScfLavLevel); + else + index = fixMin(*delta, codeBookScfLavLevel); + + if (index != *delta) { + *delta = index; + return (10000); + } + delta_bits = hufftableLevel[index + codeBookScfLavLevel]; + } + } + else { + if (*delta < 0) + index = fixMax(*delta, -codeBookScfLavLevel); + else + index = fixMin(*delta, codeBookScfLavLevel); + + if (index != *delta) { + *delta = index; + return (10000); + } + delta_bits = hufftableLevel[index + codeBookScfLavLevel]; + } + + return (delta_bits); +} + + + + +/******************************************************************************* + Functionname: FDKsbrEnc_codeEnvelope + ******************************************************************************* + + Description: + + Arguments: INT *sfb_nrg, + const FREQ_RES *freq_res, + SBR_CODE_ENVELOPE * h_sbrCodeEnvelope, + INT *directionVec, INT scalable, INT nEnvelopes, INT channel, + INT headerActive) + + Return: none + h_sbrCodeEnvelope->sfb_nrg_prev is modified ! + sfb_nrg is modified + h_sbrCodeEnvelope->update is modfied ! + *directionVec is modified + +*******************************************************************************/ +void +FDKsbrEnc_codeEnvelope(SCHAR *sfb_nrg, + const FREQ_RES *freq_res, + SBR_CODE_ENVELOPE *h_sbrCodeEnvelope, + INT *directionVec, + INT coupling, + INT nEnvelopes, + INT channel, + INT headerActive) +{ + INT i, no_of_bands, band; + FIXP_DBL tmp1,tmp2,tmp3,dF_edge_1stEnv; + SCHAR *ptr_nrg; + + INT codeBookScfLavLevelTime; + INT codeBookScfLavLevelFreq; + INT codeBookScfLavBalanceTime; + INT codeBookScfLavBalanceFreq; + const UCHAR *hufftableLevelTimeL; + const UCHAR *hufftableBalanceTimeL; + const UCHAR *hufftableLevelFreqL; + const UCHAR *hufftableBalanceFreqL; + + INT offset = h_sbrCodeEnvelope->offset; + INT envDataTableCompFactor; + + INT delta_F_bits = 0, delta_T_bits = 0; + INT use_dT; + + SCHAR delta_F[MAX_FREQ_COEFFS]; + SCHAR delta_T[MAX_FREQ_COEFFS]; + SCHAR last_nrg, curr_nrg; + + tmp1 = FL2FXCONST_DBL(0.5f) >> (DFRACT_BITS-16-1); + tmp2 = h_sbrCodeEnvelope->dF_edge_1stEnv >> (DFRACT_BITS-16); + tmp3 = (FIXP_DBL)(((INT)(LONG)h_sbrCodeEnvelope->dF_edge_incr*h_sbrCodeEnvelope->dF_edge_incr_fac) >> (DFRACT_BITS-16)); + + dF_edge_1stEnv = tmp1 + tmp2 + tmp3; + + if (coupling) { + codeBookScfLavLevelTime = h_sbrCodeEnvelope->codeBookScfLavLevelTime; + codeBookScfLavLevelFreq = h_sbrCodeEnvelope->codeBookScfLavLevelFreq; + codeBookScfLavBalanceTime = h_sbrCodeEnvelope->codeBookScfLavBalanceTime; + codeBookScfLavBalanceFreq = h_sbrCodeEnvelope->codeBookScfLavBalanceFreq; + hufftableLevelTimeL = h_sbrCodeEnvelope->hufftableLevelTimeL; + hufftableBalanceTimeL = h_sbrCodeEnvelope->hufftableBalanceTimeL; + hufftableLevelFreqL = h_sbrCodeEnvelope->hufftableLevelFreqL; + hufftableBalanceFreqL = h_sbrCodeEnvelope->hufftableBalanceFreqL; + } + else { + codeBookScfLavLevelTime = h_sbrCodeEnvelope->codeBookScfLavTime; + codeBookScfLavLevelFreq = h_sbrCodeEnvelope->codeBookScfLavFreq; + codeBookScfLavBalanceTime = h_sbrCodeEnvelope->codeBookScfLavTime; + codeBookScfLavBalanceFreq = h_sbrCodeEnvelope->codeBookScfLavFreq; + hufftableLevelTimeL = h_sbrCodeEnvelope->hufftableTimeL; + hufftableBalanceTimeL = h_sbrCodeEnvelope->hufftableTimeL; + hufftableLevelFreqL = h_sbrCodeEnvelope->hufftableFreqL; + hufftableBalanceFreqL = h_sbrCodeEnvelope->hufftableFreqL; + } + + if(coupling == 1 && channel == 1) + envDataTableCompFactor = 1; /*should be one when the new huffman-tables are ready*/ + else + envDataTableCompFactor = 0; + + + if (h_sbrCodeEnvelope->deltaTAcrossFrames == 0) + h_sbrCodeEnvelope->upDate = 0; + + /* no delta coding in time in case of a header */ + if (headerActive) + h_sbrCodeEnvelope->upDate = 0; + + + for (i = 0; i < nEnvelopes; i++) + { + if (freq_res[i] == FREQ_RES_HIGH) + no_of_bands = h_sbrCodeEnvelope->nSfb[FREQ_RES_HIGH]; + else + no_of_bands = h_sbrCodeEnvelope->nSfb[FREQ_RES_LOW]; + + + ptr_nrg = sfb_nrg; + curr_nrg = *ptr_nrg; + + delta_F[0] = curr_nrg >> envDataTableCompFactor; + + if (coupling && channel == 1) + delta_F_bits = h_sbrCodeEnvelope->start_bits_balance; + else + delta_F_bits = h_sbrCodeEnvelope->start_bits; + + + if(h_sbrCodeEnvelope->upDate != 0) + { + delta_T[0] = (curr_nrg - h_sbrCodeEnvelope->sfb_nrg_prev[0]) >> envDataTableCompFactor; + + delta_T_bits = computeBits (&delta_T[0], + codeBookScfLavLevelTime, + codeBookScfLavBalanceTime, + hufftableLevelTimeL, + hufftableBalanceTimeL, coupling, channel); + } + + + mapLowResEnergyVal(curr_nrg, h_sbrCodeEnvelope->sfb_nrg_prev, offset, 0, freq_res[i]); + + /* ensure that nrg difference is not higher than codeBookScfLavXXXFreq */ + if ( coupling && channel == 1 ) { + for (band = no_of_bands - 1; band > 0; band--) { + if ( ptr_nrg[band] - ptr_nrg[band-1] > codeBookScfLavBalanceFreq ) { + ptr_nrg[band-1] = ptr_nrg[band] - codeBookScfLavBalanceFreq; + } + } + for (band = 1; band < no_of_bands; band++) { + if ( ptr_nrg[band-1] - ptr_nrg[band] > codeBookScfLavBalanceFreq ) { + ptr_nrg[band] = ptr_nrg[band-1] - codeBookScfLavBalanceFreq; + } + } + } + else { + for (band = no_of_bands - 1; band > 0; band--) { + if ( ptr_nrg[band] - ptr_nrg[band-1] > codeBookScfLavLevelFreq ) { + ptr_nrg[band-1] = ptr_nrg[band] - codeBookScfLavLevelFreq; + } + } + for (band = 1; band < no_of_bands; band++) { + if ( ptr_nrg[band-1] - ptr_nrg[band] > codeBookScfLavLevelFreq ) { + ptr_nrg[band] = ptr_nrg[band-1] - codeBookScfLavLevelFreq; + } + } + } + + + /* Coding loop*/ + for (band = 1; band < no_of_bands; band++) + { + last_nrg = (*ptr_nrg); + ptr_nrg++; + curr_nrg = (*ptr_nrg); + + delta_F[band] = (curr_nrg - last_nrg) >> envDataTableCompFactor; + + delta_F_bits += computeBits (&delta_F[band], + codeBookScfLavLevelFreq, + codeBookScfLavBalanceFreq, + hufftableLevelFreqL, + hufftableBalanceFreqL, coupling, channel); + + if(h_sbrCodeEnvelope->upDate != 0) + { + delta_T[band] = curr_nrg - h_sbrCodeEnvelope->sfb_nrg_prev[indexLow2High(offset, band, freq_res[i])]; + delta_T[band] = delta_T[band] >> envDataTableCompFactor; + } + + mapLowResEnergyVal(curr_nrg, h_sbrCodeEnvelope->sfb_nrg_prev, offset, band, freq_res[i]); + + if(h_sbrCodeEnvelope->upDate != 0) + { + delta_T_bits += computeBits (&delta_T[band], + codeBookScfLavLevelTime, + codeBookScfLavBalanceTime, + hufftableLevelTimeL, + hufftableBalanceTimeL, coupling, channel); + } + } + + /* Replace sfb_nrg with deltacoded samples and set flag */ + if (i == 0) { + INT tmp_bits; + tmp_bits = (((delta_T_bits * dF_edge_1stEnv) >> (DFRACT_BITS-18)) + (FIXP_DBL)1) >> 1; + use_dT = (h_sbrCodeEnvelope->upDate != 0 && (delta_F_bits > tmp_bits)); + } + else + use_dT = (delta_T_bits < delta_F_bits && h_sbrCodeEnvelope->upDate != 0); + + if (use_dT) + { + directionVec[i] = TIME; + FDKmemcpy (sfb_nrg, delta_T, no_of_bands * sizeof (SCHAR)); + } + else { + h_sbrCodeEnvelope->upDate = 0; + directionVec[i] = FREQ; + FDKmemcpy (sfb_nrg, delta_F, no_of_bands * sizeof (SCHAR)); + } + sfb_nrg += no_of_bands; + h_sbrCodeEnvelope->upDate = 1; + } + +} + + +/******************************************************************************* + Functionname: FDKsbrEnc_InitSbrCodeEnvelope + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ +INT +FDKsbrEnc_InitSbrCodeEnvelope (HANDLE_SBR_CODE_ENVELOPE h_sbrCodeEnvelope, + INT *nSfb, + INT deltaTAcrossFrames, + FIXP_DBL dF_edge_1stEnv, + FIXP_DBL dF_edge_incr) +{ + + FDKmemclear(h_sbrCodeEnvelope,sizeof(SBR_CODE_ENVELOPE)); + + h_sbrCodeEnvelope->deltaTAcrossFrames = deltaTAcrossFrames; + h_sbrCodeEnvelope->dF_edge_1stEnv = dF_edge_1stEnv; + h_sbrCodeEnvelope->dF_edge_incr = dF_edge_incr; + h_sbrCodeEnvelope->dF_edge_incr_fac = 0; + h_sbrCodeEnvelope->upDate = 0; + h_sbrCodeEnvelope->nSfb[FREQ_RES_LOW] = nSfb[FREQ_RES_LOW]; + h_sbrCodeEnvelope->nSfb[FREQ_RES_HIGH] = nSfb[FREQ_RES_HIGH]; + h_sbrCodeEnvelope->offset = 2*h_sbrCodeEnvelope->nSfb[FREQ_RES_LOW] - h_sbrCodeEnvelope->nSfb[FREQ_RES_HIGH]; + + return (0); +} diff --git a/libSBRenc/src/code_env.h b/libSBRenc/src/code_env.h new file mode 100644 index 0000000..debcd65 --- /dev/null +++ b/libSBRenc/src/code_env.h @@ -0,0 +1,97 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief DPCM Envelope coding $Revision: 36867 $ +*/ + +#ifndef __CODE_ENV_H +#define __CODE_ENV_H + +#include "sbr_def.h" +#include "bit_sbr.h" +#include "fram_gen.h" + +typedef struct +{ + INT offset; + INT upDate; + INT nSfb[2]; + SCHAR sfb_nrg_prev[MAX_FREQ_COEFFS]; + INT deltaTAcrossFrames; + FIXP_DBL dF_edge_1stEnv; + FIXP_DBL dF_edge_incr; + INT dF_edge_incr_fac; + + + INT codeBookScfLavTime; + INT codeBookScfLavFreq; + + INT codeBookScfLavLevelTime; + INT codeBookScfLavLevelFreq; + INT codeBookScfLavBalanceTime; + INT codeBookScfLavBalanceFreq; + + INT start_bits; + INT start_bits_balance; + + + const UCHAR *hufftableTimeL; + const UCHAR *hufftableFreqL; + + const UCHAR *hufftableLevelTimeL; + const UCHAR *hufftableBalanceTimeL; + const UCHAR *hufftableLevelFreqL; + const UCHAR *hufftableBalanceFreqL; +} +SBR_CODE_ENVELOPE; +typedef SBR_CODE_ENVELOPE *HANDLE_SBR_CODE_ENVELOPE; + + + +void +FDKsbrEnc_codeEnvelope (SCHAR *sfb_nrg, + const FREQ_RES *freq_res, + SBR_CODE_ENVELOPE * h_sbrCodeEnvelope, + INT *directionVec, INT coupling, INT nEnvelopes, INT channel, + INT headerActive); + +INT +FDKsbrEnc_InitSbrCodeEnvelope (HANDLE_SBR_CODE_ENVELOPE h_sbrCodeEnvelope, + INT *nSfb, + INT deltaTAcrossFrames, + FIXP_DBL dF_edge_1stEnv, + FIXP_DBL dF_edge_incr); + +/* void deleteSbrCodeEnvelope (HANDLE_SBR_CODE_ENVELOPE h_sbrCodeEnvelope); */ + +INT +FDKsbrEnc_InitSbrHuffmanTables (struct SBR_ENV_DATA* sbrEnvData, + HANDLE_SBR_CODE_ENVELOPE henv, + HANDLE_SBR_CODE_ENVELOPE hnoise, + AMP_RES amp_res); + +#endif diff --git a/libSBRenc/src/env_bit.cpp b/libSBRenc/src/env_bit.cpp new file mode 100644 index 0000000..1f8c48f --- /dev/null +++ b/libSBRenc/src/env_bit.cpp @@ -0,0 +1,192 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Remaining SBR Bit Writing Routines +*/ + +#include "env_bit.h" +#include "cmondata.h" + + +#ifndef min +#define min(a,b) ( a < b ? a:b) +#endif + +#ifndef max +#define max(a,b) ( a > b ? a:b) +#endif + +/* ***************************** crcAdvance **********************************/ +/** + * @fn + * @brief updates crc data register + * @return none + * + * This function updates the crc register + * + */ +static void crcAdvance(USHORT crcPoly, + USHORT crcMask, + USHORT *crc, + ULONG bValue, + INT bBits + ) +{ + INT i; + USHORT flag; + + for (i=bBits-1; i>=0; i--) { + flag = ((*crc) & crcMask) ? (1) : (0) ; + flag ^= (bValue & (1<sbrBitbuf, BS_WRITER); + + FDKinitBitStream(&hCmonData->tmpWriteBitbuf, memoryBase, + memorySize, 0, BS_WRITER); + + if (sbrSyntaxFlags & SBR_SYNTAX_CRC) { + if (sbrSyntaxFlags & SBR_SYNTAX_DRM_CRC) + { /* Init and start CRC region */ + FDKwriteBits (&hCmonData->sbrBitbuf, 0x0, SI_SBR_DRM_CRC_BITS); + FDKcrcInit( hCrcInfo, 0x001d, 0xFFFF, SI_SBR_DRM_CRC_BITS ); + crcRegion = FDKcrcStartReg( hCrcInfo, &hCmonData->sbrBitbuf, 0 ); + } else { + FDKwriteBits (&hCmonData->sbrBitbuf, 0x0, SI_SBR_CRC_BITS); + } + } + + return (crcRegion); +} + + +/* ************************** FDKsbrEnc_AssembleSbrBitstream *******************************/ +/** + * @fn + * @brief Formats the SBR payload + * @return nothing + * + * Also the CRC will be calculated here. + * + */ + +void +FDKsbrEnc_AssembleSbrBitstream( HANDLE_COMMON_DATA hCmonData, + HANDLE_FDK_CRCINFO hCrcInfo, + INT crcRegion, + UINT sbrSyntaxFlags) +{ + USHORT crcReg = SBR_CRCINIT; + INT numCrcBits,i; + + /* check if SBR is present */ + if ( hCmonData==NULL ) + return; + + hCmonData->sbrFillBits = 0; /* Fill bits are written only for GA streams */ + + if ( sbrSyntaxFlags & SBR_SYNTAX_DRM_CRC ) + { + /* + * Calculate and write DRM CRC + */ + FDKcrcEndReg( hCrcInfo, &hCmonData->sbrBitbuf, crcRegion ); + FDKwriteBits( &hCmonData->tmpWriteBitbuf, FDKcrcGetCRC(hCrcInfo)^0xFF, SI_SBR_DRM_CRC_BITS ); + } + else + { + if ( !(sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) ) + { + /* Do alignment here, because its defined as part of the sbr_extension_data */ + int sbrLoad = hCmonData->sbrHdrBits + hCmonData->sbrDataBits; + + if ( sbrSyntaxFlags & SBR_SYNTAX_CRC ) { + sbrLoad += SI_SBR_CRC_BITS; + } + + sbrLoad += 4; /* Do byte Align with 4 bit offset. ISO/IEC 14496-3:2005(E) page 39. */ + + hCmonData->sbrFillBits = (8 - (sbrLoad % 8)) % 8; + + /* + append fill bits + */ + FDKwriteBits(&hCmonData->sbrBitbuf, 0, hCmonData->sbrFillBits ); + + FDK_ASSERT(FDKgetValidBits(&hCmonData->sbrBitbuf) % 8 == 4); + } + + /* + calculate crc + */ + if ( sbrSyntaxFlags & SBR_SYNTAX_CRC ) { + FDK_BITSTREAM tmpCRCBuf = hCmonData->sbrBitbuf; + FDKresetBitbuffer( &tmpCRCBuf, BS_READER ); + + numCrcBits = hCmonData->sbrHdrBits + hCmonData->sbrDataBits + hCmonData->sbrFillBits; + + for(i=0;itmpWriteBitbuf, crcReg, SI_SBR_CRC_BITS); + } + } + + FDKsyncCache(&hCmonData->tmpWriteBitbuf); +} + diff --git a/libSBRenc/src/env_bit.h b/libSBRenc/src/env_bit.h new file mode 100644 index 0000000..60d9990 --- /dev/null +++ b/libSBRenc/src/env_bit.h @@ -0,0 +1,68 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Remaining SBR Bit Writing Routines +*/ + +#ifndef BIT_ENV_H +#define BIT_ENV_H + +#include "sbr_encoder.h" +#include "FDK_crc.h" + +/* G(x) = x^10 + x^9 + x^5 + x^4 + x + 1 */ +#define SBR_CRC_POLY (0x0233) +#define SBR_CRC_MASK (0x0200) +#define SBR_CRC_RANGE (0x03FF) +#define SBR_CRC_MAXREGS 1 +#define SBR_CRCINIT (0x0) + + +#define SI_SBR_CRC_ENABLE_BITS 0 +#define SI_SBR_CRC_BITS 10 +#define SI_SBR_DRM_CRC_BITS 8 + + +struct COMMON_DATA; + +INT FDKsbrEnc_InitSbrBitstream(struct COMMON_DATA *hCmonData, + UCHAR *memoryBase, + INT memorySize, + HANDLE_FDK_CRCINFO hCrcInfo, + UINT sbrSyntaxFlags); + +void +FDKsbrEnc_AssembleSbrBitstream (struct COMMON_DATA *hCmonData, + HANDLE_FDK_CRCINFO hCrcInfo, + INT crcReg, + UINT sbrSyntaxFlags); + + + + + +#endif /* #ifndef BIT_ENV_H */ diff --git a/libSBRenc/src/env_est.cpp b/libSBRenc/src/env_est.cpp new file mode 100644 index 0000000..0b7f7b0 --- /dev/null +++ b/libSBRenc/src/env_est.cpp @@ -0,0 +1,1834 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +#include "env_est.h" +#include "tran_det.h" + +#include "qmf.h" + +#include "fram_gen.h" +#include "bit_sbr.h" +#include "cmondata.h" +#include "sbr_ram.h" + + +#include "genericStds.h" + +#define QUANT_ERROR_THRES 200 +#define Y_NRG_SCALE 5 /* noCols = 32 -> shift(5) */ + + +static const UCHAR panTable[2][10] = { { 0, 2, 4, 6, 8,12,16,20,24}, + { 0, 2, 4, 8,12, 0, 0, 0, 0 } }; +static const UCHAR maxIndex[2] = {9, 5}; + + +/***************************************************************************/ +/*! + + \brief Calculates energy form real and imaginary part of + the QMF subsamples + + \return none + +****************************************************************************/ +LNK_SECTION_CODE_L1 +static void +FDKsbrEnc_getEnergyFromCplxQmfData(FIXP_DBL **RESTRICT energyValues,/*!< the result of the operation */ + FIXP_DBL **RESTRICT realValues, /*!< the real part of the QMF subsamples */ + FIXP_DBL **RESTRICT imagValues, /*!< the imaginary part of the QMF subsamples */ + INT numberBands, /*!< number of QMF bands */ + INT numberCols, /*!< number of QMF subsamples */ + INT *qmfScale, /*!< sclefactor of QMF subsamples */ + INT *energyScale) /*!< scalefactor of energies */ +{ + int j, k; + int scale; + FIXP_DBL max_val = FL2FXCONST_DBL(0.0f); + + /* Get Scratch buffer */ + C_ALLOC_SCRATCH_START(tmpNrg, FIXP_DBL, QMF_CHANNELS*QMF_MAX_TIME_SLOTS/2); + + FDK_ASSERT(numberBands <= QMF_CHANNELS); + FDK_ASSERT(numberCols <= QMF_MAX_TIME_SLOTS); + + /* Get max possible scaling of QMF data */ + scale = DFRACT_BITS; + for (k=0; k= DFRACT_BITS-1) { + scale = (FRACT_BITS-1-*qmfScale); + } + /* prevent scaling of QFM values to -1.f */ + scale = fixMax(0,scale-1); + + /* Update QMF scale */ + *qmfScale += scale; + + /* + Calculate energy of each time slot pair, max energy + and shift QMF values as far as possible to the left. + */ + { + FIXP_DBL *nrgValues = tmpNrg; + for (k=0; k> 1; + + tr1 <<= scale; + ti1 <<= scale; + energy += fPow2AddDiv2(fPow2Div2(tr1), ti1) >> 1; + + /* Write timeslot pair energy to scratch */ + *nrgValues++ = energy; + max_val = fixMax(max_val, energy); + + /* Write back scaled QMF values */ + r0[j] = tr0; r1[j] = tr1; i0[j] = ti0; i1[j] = ti1; + } + } + } + /* energyScale: scalefactor energies of current frame */ + *energyScale = 2*(*qmfScale)-1; /* if qmfScale > 0: nr of right shifts otherwise nr of left shifts */ + + /* Scale timeslot pair energies and write to output buffer */ + scale = CountLeadingBits(max_val); + { + FIXP_DBL *nrgValues = tmpNrg; + for (k=0; k>1; k++) { + scaleValues(energyValues[k], nrgValues, numberBands, scale); + nrgValues += numberBands; + } + *energyScale += scale; + } + + /* Free Scratch buffer */ + C_ALLOC_SCRATCH_END(tmpNrg, FIXP_DBL, QMF_CHANNELS*QMF_MAX_TIME_SLOTS/2); +} + +LNK_SECTION_CODE_L1 +static void +FDKsbrEnc_getEnergyFromCplxQmfDataFull(FIXP_DBL **RESTRICT energyValues,/*!< the result of the operation */ + FIXP_DBL **RESTRICT realValues, /*!< the real part of the QMF subsamples */ + FIXP_DBL **RESTRICT imagValues, /*!< the imaginary part of the QMF subsamples */ + int numberBands, /*!< number of QMF bands */ + int numberCols, /*!< number of QMF subsamples */ + int *qmfScale, /*!< sclefactor of QMF subsamples */ + int *energyScale) /*!< scalefactor of energies */ +{ + int j, k; + int scale; + FIXP_DBL max_val = FL2FXCONST_DBL(0.0f); + + /* Get Scratch buffer */ + C_ALLOC_SCRATCH_START(tmpNrg, FIXP_DBL, QMF_MAX_TIME_SLOTS*QMF_CHANNELS/2); + + FDK_ASSERT(numberBands <= QMF_CHANNELS); + FDK_ASSERT(numberCols <= QMF_MAX_TIME_SLOTS/2); + + /* Get max possible scaling of QMF data */ + scale = DFRACT_BITS; + for (k=0; k= DFRACT_BITS-1) { + scale = (FRACT_BITS-1-*qmfScale); + } + /* prevent scaling of QFM values to -1.f */ + scale = fixMax(0,scale-1); + + /* Update QMF scale */ + *qmfScale += scale; + + /* + Calculate energy of each time slot pair, max energy + and shift QMF values as far as possible to the left. + */ + { + FIXP_DBL *nrgValues = tmpNrg; + for (k=0; k 0: nr of right shifts otherwise nr of left shifts */ + + /* Scale timeslot pair energies and write to output buffer */ + scale = CountLeadingBits(max_val); + { + FIXP_DBL *nrgValues = tmpNrg; + for (k=0; k 0 ? 1 : -1; + + nrgVal *= sign; + + min_val = FDK_INT_MAX; + panIndex = 0; + for (i = 0; i < maxIndex[ampRes]; i++) { + val = fixp_abs ((nrgVal - (INT)panTable[ampRes][i])); + + if (val < min_val) { + min_val = val; + panIndex = i; + } + } + + *quantError=min_val; + + return panTable[ampRes][maxIndex[ampRes]-1] + sign * panTable[ampRes][panIndex]; +} + + +/***************************************************************************/ +/*! + + \brief Quantisation of the noise floor levels + + \return void + +****************************************************************************/ +static void +sbrNoiseFloorLevelsQuantisation(SCHAR *RESTRICT iNoiseLevels, /*! quantized noise levels */ + FIXP_DBL *RESTRICT NoiseLevels, /*! the noise levels */ + INT coupling /*! the coupling flag */ + ) +{ + INT i; + INT tmp, dummy; + + /* Quantisation, similar to sfb quant... */ + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) { + /* tmp = NoiseLevels[i] > (PFLOAT)30.0f ? 30: (INT) (NoiseLevels[i] + (PFLOAT)0.5); */ + /* 30>>6 = 0.46875 */ + if ((FIXP_DBL)NoiseLevels[i] > FL2FXCONST_DBL(0.46875f)) { + tmp = 30; + } + else { + /* tmp = (INT)((FIXP_DBL)NoiseLevels[i] + (FL2FXCONST_DBL(0.5f)>>(*/ /* FRACT_BITS+ */ /* 6-1)));*/ + /* tmp = tmp >> (DFRACT_BITS-1-6); */ /* conversion to integer happens here */ + /* rounding is done by shifting one bit less than necessary to the right, adding '1' and then shifting the final bit */ + tmp = ((((INT)NoiseLevels[i])>>(DFRACT_BITS-1-LD_DATA_SHIFT)) ); /* conversion to integer */ + if (tmp != 0) + tmp += 1; + } + + if (coupling) { + tmp = tmp < -30 ? -30 : tmp; + tmp = mapPanorama (tmp,1,&dummy); + } + iNoiseLevels[i] = tmp; + } +} + +/***************************************************************************/ +/*! + + \brief Calculation of noise floor for coupling + + \return void + +****************************************************************************/ +static void +coupleNoiseFloor(FIXP_DBL *RESTRICT noise_level_left, /*! noise level left (modified)*/ + FIXP_DBL *RESTRICT noise_level_right /*! noise level right (modified)*/ + ) +{ + FIXP_DBL cmpValLeft,cmpValRight; + INT i; + FIXP_DBL temp1,temp2; + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) { + + /* Calculation of the power function using ld64: + z = x^y; + z' = CalcLd64(z) = y*CalcLd64(x)/64; + z = CalcInvLd64(z'); + */ + cmpValLeft = NOISE_FLOOR_OFFSET_64 - noise_level_left[i]; + cmpValRight = NOISE_FLOOR_OFFSET_64 - noise_level_right[i]; + + if (cmpValRight < FL2FXCONST_DBL(0.0f)) { + temp1 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_right[i]); + } + else { + temp1 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_right[i]); + temp1 = temp1 << (DFRACT_BITS-1-LD_DATA_SHIFT-1); /* INT to fract conversion of result, if input of CalcInvLdData is positiv */ + } + + if (cmpValLeft < FL2FXCONST_DBL(0.0f)) { + temp2 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_left[i]); + } + else { + temp2 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_left[i]); + temp2 = temp2 << (DFRACT_BITS-1-LD_DATA_SHIFT-1); /* INT to fract conversion of result, if input of CalcInvLdData is positiv */ + } + + + if ((cmpValLeft < FL2FXCONST_DBL(0.0f)) && (cmpValRight < FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - (CalcLdData(((temp1>>1) + (temp2>>1)))); /* no scaling needed! both values are dfract */ + noise_level_right[i] = CalcLdData(temp2) - CalcLdData(temp1); + } + + if ((cmpValLeft >= FL2FXCONST_DBL(0.0f)) && (cmpValRight >= FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - (CalcLdData(((temp1>>1) + (temp2>>1))) + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + noise_level_right[i] = CalcLdData(temp2) - CalcLdData(temp1); + } + + if ((cmpValLeft >= FL2FXCONST_DBL(0.0f)) && (cmpValRight < FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - (CalcLdData(((temp1>>(7+1)) + (temp2>>1))) + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + noise_level_right[i] = (CalcLdData(temp2) + FL2FXCONST_DBL(0.109375f)) - CalcLdData(temp1); + } + + if ((cmpValLeft < FL2FXCONST_DBL(0.0f)) && (cmpValRight >= FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - (CalcLdData(((temp1>>1) + (temp2>>(7+1)))) + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + noise_level_right[i] = CalcLdData(temp2) - (CalcLdData(temp1) + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + } + } +} + +/***************************************************************************/ +/*! + + \brief Calculation of energy starting in lower band (li) up to upper band (ui) + over slots (start_pos) to (stop_pos) + + \return void + +****************************************************************************/ +static FIXP_DBL +getEnvSfbEnergy(INT li, /*! lower band */ + INT ui, /*! upper band */ + INT start_pos, /*! start slot */ + INT stop_pos, /*! stop slot */ + INT border_pos, /*! slots scaling border */ + FIXP_DBL **YBuffer, /*! sfb energy buffer */ + INT YBufferSzShift, /*! Energy buffer index scale */ + INT scaleNrg0, /*! scaling of lower slots */ + INT scaleNrg1) /*! scaling of upper slots */ +{ + /* use dynamic scaling for outer energy loop; + energies are critical and every bit is important */ + int sc0, sc1, k, l; + + FIXP_DBL nrgSum, nrg1, nrg2, accu1, accu2; + INT dynScale, dynScale1, dynScale2; + if(ui-li==0) dynScale = DFRACT_BITS-1; + else + dynScale = CalcLdInt(ui-li)>>(DFRACT_BITS-1-LD_DATA_SHIFT); + + sc0 = fixMin(scaleNrg0,Y_NRG_SCALE); sc1 = fixMin(scaleNrg1,Y_NRG_SCALE); + /* dynScale{1,2} is set such that the right shift below is positive */ + dynScale1 = fixMin((scaleNrg0-sc0),dynScale); + dynScale2 = fixMin((scaleNrg1-sc1),dynScale); + nrgSum = accu1 = accu2 = (FIXP_DBL)0; + + for (k = li; k < ui; k++) { + nrg1 = nrg2 = (FIXP_DBL)0; + for (l = start_pos; l < border_pos; l++) { + nrg1 += YBuffer[l>>YBufferSzShift][k] >> sc0; + } + for (; l < stop_pos; l++) { + nrg2 += YBuffer[l>>YBufferSzShift][k] >> sc1; + } + accu1 += (nrg1>>dynScale1); + accu2 += (nrg2>>dynScale2); + } + /* This shift factor is always positive. See comment above. */ + nrgSum += ( accu1 >> fixMin((scaleNrg0-sc0-dynScale1),(DFRACT_BITS-1)) ) + + ( accu2 >> fixMin((scaleNrg1-sc1-dynScale2),(DFRACT_BITS-1)) ); + + return nrgSum; +} + +/***************************************************************************/ +/*! + + \brief Energy compensation in missing harmonic mode + + \return void + +****************************************************************************/ +static FIXP_DBL +mhLoweringEnergy(FIXP_DBL nrg, INT M) +{ + /* + Compensating for the fact that we in the decoder map the "average energy to every QMF + band, and use this when we calculate the boost-factor. Since the mapped energy isn't + the average energy but the maximum energy in case of missing harmonic creation, we will + in the boost function calculate that too much limiting has been applied and hence we will + boost the signal although it isn't called for. Hence we need to compensate for this by + lowering the transmitted energy values for the sines so they will get the correct level + after the boost is applied. + */ + if(M > 2){ + INT tmpScale; + tmpScale = CountLeadingBits(nrg); + nrg <<= tmpScale; + nrg = fMult(nrg, FL2FXCONST_DBL(0.398107267f)); /* The maximum boost is 1.584893, so the maximum attenuation should be square(1/1.584893) = 0.398107267 */ + nrg >>= tmpScale; + } + else{ + if(M > 1){ + nrg >>= 1; + } + } + + return nrg; +} + +/***************************************************************************/ +/*! + + \brief Energy compensation in none missing harmonic mode + + \return void + +****************************************************************************/ +static FIXP_DBL +nmhLoweringEnergy(FIXP_DBL nrg, FIXP_DBL nrgSum, INT M) +{ + if (nrg>FL2FXCONST_DBL(0)) { + int sc=0; + /* gain = nrgSum / (nrg*(M+1)) */ + FIXP_DBL gain = fMult(fDivNorm(nrgSum, nrg, &sc), GetInvInt(M+1)); + + /* reduce nrg if gain smaller 1.f */ + if ( !((sc>=0) && ( gain > ((FIXP_DBL)MAXVAL_DBL>>sc) )) ) { + nrg = fMult(scaleValue(gain,sc), nrg); + } + } + return nrg; +} + +/***************************************************************************/ +/*! + + \brief calculates the envelope values from the energies, depending on + framing and stereo mode + + \return void + +****************************************************************************/ +static void +calculateSbrEnvelope (FIXP_DBL **RESTRICT YBufferLeft, /*! energy buffer left */ + FIXP_DBL **RESTRICT YBufferRight, /*! energy buffer right */ + int *RESTRICT YBufferScaleLeft, /*! scale energy buffer left */ + int *RESTRICT YBufferScaleRight, /*! scale energy buffer right */ + const SBR_FRAME_INFO *frame_info, /*! frame info vector */ + SCHAR *RESTRICT sfb_nrgLeft, /*! sfb energy buffer left */ + SCHAR *RESTRICT sfb_nrgRight, /*! sfb energy buffer right */ + HANDLE_SBR_CONFIG_DATA h_con, /*! handle to config data */ + HANDLE_ENV_CHANNEL h_sbr, /*! envelope channel handle */ + SBR_STEREO_MODE stereoMode, /*! stereo coding mode */ + INT* maxQuantError, /*! maximum quantization error, for panorama. */ + int YBufferSzShift) /*! Energy buffer index scale */ + +{ + int i, j, m = 0; + INT no_of_bands, start_pos, stop_pos, li, ui; + FREQ_RES freq_res; + + INT ca = 2 - h_sbr->encEnvData.init_sbr_amp_res; + INT oneBitLess = 0; + if (ca == 2) + oneBitLess = 1; /* LD_DATA_SHIFT => ld64 scaling; one bit less for rounding */ + + INT quantError; + INT nEnvelopes = frame_info->nEnvelopes; + INT short_env = frame_info->shortEnv - 1; + INT timeStep = h_sbr->sbrExtractEnvelope.time_step; + INT commonScale,scaleLeft0,scaleLeft1; + INT scaleRight0=0,scaleRight1=0; + + commonScale = fixMin(YBufferScaleLeft[0],YBufferScaleLeft[1]); + + if (stereoMode == SBR_COUPLING) { + commonScale = fixMin(commonScale,YBufferScaleRight[0]); + commonScale = fixMin(commonScale,YBufferScaleRight[1]); + } + + commonScale = commonScale - 7; + + scaleLeft0 = YBufferScaleLeft[0] - commonScale; + scaleLeft1 = YBufferScaleLeft[1] - commonScale ; + FDK_ASSERT ((scaleLeft0 >= 0) && (scaleLeft1 >= 0)); + + if (stereoMode == SBR_COUPLING) { + scaleRight0 = YBufferScaleRight[0] - commonScale; + scaleRight1 = YBufferScaleRight[1] - commonScale; + FDK_ASSERT ((scaleRight0 >= 0) && (scaleRight1 >= 0)); + *maxQuantError = 0; + } + + for (i = 0; i < nEnvelopes; i++) { + + FIXP_DBL pNrgLeft[QMF_MAX_TIME_SLOTS]; + FIXP_DBL pNrgRight[QMF_MAX_TIME_SLOTS]; + FIXP_DBL envNrgLeft = FL2FXCONST_DBL(0.0f); + FIXP_DBL envNrgRight = FL2FXCONST_DBL(0.0f); + int missingHarmonic[QMF_MAX_TIME_SLOTS]; + int count[QMF_MAX_TIME_SLOTS]; + + start_pos = timeStep * frame_info->borders[i]; + stop_pos = timeStep * frame_info->borders[i + 1]; + freq_res = frame_info->freqRes[i]; + no_of_bands = h_con->nSfb[freq_res]; + + if (i == short_env) { + stop_pos -= fixMax(2, timeStep); /* consider at least 2 QMF slots less for short envelopes (envelopes just before transients) */ + } + + for (j = 0; j < no_of_bands; j++) { + FIXP_DBL nrgLeft = FL2FXCONST_DBL(0.0f); + FIXP_DBL nrgRight = FL2FXCONST_DBL(0.0f); + + li = h_con->freqBandTable[freq_res][j]; + ui = h_con->freqBandTable[freq_res][j + 1]; + + if(freq_res == FREQ_RES_HIGH){ + if(j == 0 && ui-li > 1){ + li++; + } + } + else{ + if(j == 0 && ui-li > 2){ + li++; + } + } + + /* + Find out whether a sine will be missing in the scale-factor + band that we're currently processing. + */ + missingHarmonic[j] = 0; + + if(h_sbr->encEnvData.addHarmonicFlag){ + + if(freq_res == FREQ_RES_HIGH){ + if(h_sbr->encEnvData.addHarmonic[j]){ /*A missing sine in the current band*/ + missingHarmonic[j] = 1; + } + } + else{ + INT i; + INT startBandHigh = 0; + INT stopBandHigh = 0; + + while(h_con->freqBandTable[FREQ_RES_HIGH][startBandHigh] < h_con->freqBandTable[FREQ_RES_LOW][j]) + startBandHigh++; + while(h_con->freqBandTable[FREQ_RES_HIGH][stopBandHigh] < h_con->freqBandTable[FREQ_RES_LOW][j + 1]) + stopBandHigh++; + + for(i = startBandHigh; iencEnvData.addHarmonic[i]){ + missingHarmonic[j] = 1; + } + } + } + } + + /* + If a sine is missing in a scalefactorband, with more than one qmf channel + use the nrg from the channel with the largest nrg rather than the mean. + Compensate for the boost calculation in the decdoder. + */ + int border_pos = fixMin(stop_pos, h_sbr->sbrExtractEnvelope.YBufferWriteOffset<fLevelProtect) { + /* in case of missing energy in base band, + reduce reference energy to prevent overflows in decoder output */ + nrgLeft = nmhLoweringEnergy(nrgLeft, envNrgLeft, no_of_bands); + if (stereoMode == SBR_COUPLING) { + nrgRight = nmhLoweringEnergy(nrgRight, envNrgRight, no_of_bands); + } + } + + if (stereoMode == SBR_COUPLING) { + /* calc operation later with log */ + nrgLeft2 = nrgLeft; + nrgLeft = (nrgRight + nrgLeft) >> 1; + } + + /* nrgLeft = f20_log2(nrgLeft / (PFLOAT)(count * h_sbr->sbrQmf.no_channels))+(PFLOAT)44; */ + /* If nrgLeft == 0 then the Log calculations below do fail. */ + if (nrgLeft > FL2FXCONST_DBL(0.0f)) + { + FIXP_DBL tmp0,tmp1,tmp2,tmp3; + INT tmpScale; + + tmpScale = CountLeadingBits(nrgLeft); + nrgLeft = nrgLeft << tmpScale; + + tmp0 = CalcLdData(nrgLeft); /* scaled by 1/64 */ + tmp1 = ((FIXP_DBL) (commonScale+tmpScale)) << (DFRACT_BITS-1-LD_DATA_SHIFT-1); /* scaled by 1/64 */ + tmp2 = ((FIXP_DBL)(count[j]*h_con->noQmfBands)) << (DFRACT_BITS-1-14-1); + tmp2 = CalcLdData(tmp2); /* scaled by 1/64 */ + tmp3 = FL2FXCONST_DBL(0.6875f-0.21875f-0.015625f)>>1; /* scaled by 1/64 */ + + nrgLeft = ((tmp0-tmp2)>>1) + (tmp3 - tmp1); + } else { + nrgLeft = FL2FXCONST_DBL(-1.0f); + } + + /* ld64 to integer conversion */ + nrgLeft = fixMin(fixMax(nrgLeft,FL2FXCONST_DBL(0.0f)),FL2FXCONST_DBL(0.5f)); + nrgLeft = (FIXP_DBL)(LONG)nrgLeft >> (DFRACT_BITS-1-LD_DATA_SHIFT-1-oneBitLess-1); + sfb_nrgLeft[m] = ((INT)nrgLeft+1)>>1; /* rounding */ + + if (stereoMode == SBR_COUPLING) { + FIXP_DBL scaleFract; + + if (nrgRight != FL2FXCONST_DBL(0.0f)) { + int sc0 = CountLeadingBits(nrgLeft2); + int sc1 = CountLeadingBits(nrgRight); + + scaleFract = ((FIXP_DBL)(sc0-sc1)) << (DFRACT_BITS-1-LD_DATA_SHIFT); /* scale value in ld64 representation */ + nrgRight = CalcLdData(nrgLeft2<> (DFRACT_BITS-1-LD_DATA_SHIFT-1-oneBitLess); + nrgRight = (nrgRight+(FIXP_DBL)1)>>1; /* rounding */ + + sfb_nrgRight[m] = mapPanorama (nrgRight,h_sbr->encEnvData.init_sbr_amp_res,&quantError); + + *maxQuantError = fixMax(quantError, *maxQuantError); + } + + m++; + } /* j */ + + /* Do energy compensation for sines that are present in two + QMF-bands in the original, but will only occur in one band in + the decoder due to the synthetic sine coding.*/ + if (h_con->useParametricCoding) { + m-=no_of_bands; + for (j = 0; j < no_of_bands; j++) { + if (freq_res==FREQ_RES_HIGH && h_sbr->sbrExtractEnvelope.envelopeCompensation[j]){ + sfb_nrgLeft[m] -= (ca * fixp_abs((INT)h_sbr->sbrExtractEnvelope.envelopeCompensation[j])); + } + sfb_nrgLeft[m] = fixMax(0, sfb_nrgLeft[m]); + m++; + } + } /* useParametricCoding */ + + } /* i*/ +} + +/* + * Update QMF buffers + */ +static void FDKsbrEnc_updateRIBuffers(HANDLE_ENV_CHANNEL h_envChan) +{ + int i; + + /* rBufferWriteOffset ist always 0, do we need this ? */ + for (i = 0; i < h_envChan->sbrExtractEnvelope.rBufferWriteOffset; i++) { + FIXP_DBL *temp; + + temp = h_envChan->sbrExtractEnvelope.rBuffer[i]; + h_envChan->sbrExtractEnvelope.rBuffer[i] = h_envChan->sbrExtractEnvelope.rBuffer[i + h_envChan->sbrExtractEnvelope.no_cols]; + h_envChan->sbrExtractEnvelope.rBuffer[i + h_envChan->sbrExtractEnvelope.no_cols] = temp; + + temp = h_envChan->sbrExtractEnvelope.iBuffer[i]; + h_envChan->sbrExtractEnvelope.iBuffer[i] = h_envChan->sbrExtractEnvelope.iBuffer[i + h_envChan->sbrExtractEnvelope.no_cols]; + h_envChan->sbrExtractEnvelope.iBuffer[i + h_envChan->sbrExtractEnvelope.no_cols] = temp; + } +} + +/***************************************************************************/ +/*! + + \brief calculates the noise floor and the envelope values from the + energies, depending on framing and stereo mode + + FDKsbrEnc_extractSbrEnvelope is the main function for encoding and writing the + envelope and the noise floor. The function includes the following processes: + + -Analysis subband filtering. + -Encoding SA and pan parameters (if enabled). + -Transient detection. + +****************************************************************************/ + +LNK_SECTION_CODE_L1 +void +FDKsbrEnc_extractSbrEnvelope1 ( + HANDLE_SBR_CONFIG_DATA h_con, /*! handle to config data */ + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_ENV_CHANNEL hEnvChan, + HANDLE_COMMON_DATA hCmonData, + SBR_ENV_TEMP_DATA *eData, + SBR_FRAME_TEMP_DATA *fData + ) +{ + + HANDLE_SBR_EXTRACT_ENVELOPE sbrExtrEnv = &hEnvChan->sbrExtractEnvelope; + + if (sbrExtrEnv->YBufferSzShift == 0) + FDKsbrEnc_getEnergyFromCplxQmfDataFull(&sbrExtrEnv->YBuffer[sbrExtrEnv->YBufferWriteOffset], + sbrExtrEnv->rBuffer + sbrExtrEnv->rBufferReadOffset, + sbrExtrEnv->iBuffer + sbrExtrEnv->rBufferReadOffset, + h_con->noQmfBands, + sbrExtrEnv->no_cols, + &hEnvChan->qmfScale, + &sbrExtrEnv->YBufferScale[1]); + else + FDKsbrEnc_getEnergyFromCplxQmfData(&sbrExtrEnv->YBuffer[sbrExtrEnv->YBufferWriteOffset], + sbrExtrEnv->rBuffer + sbrExtrEnv->rBufferReadOffset, + sbrExtrEnv->iBuffer + sbrExtrEnv->rBufferReadOffset, + h_con->noQmfBands, + sbrExtrEnv->no_cols, + &hEnvChan->qmfScale, + &sbrExtrEnv->YBufferScale[1]); + + + + /* + Precalculation of Tonality Quotas COEFF Transform OK + */ + FDKsbrEnc_CalculateTonalityQuotas(&hEnvChan->TonCorr, + sbrExtrEnv->rBuffer+ sbrExtrEnv->rBufferWriteOffset, + sbrExtrEnv->iBuffer+ sbrExtrEnv->rBufferWriteOffset, + h_con->freqBandTable[HI][h_con->nSfb[HI]], + hEnvChan->qmfScale); + + + + /* + Transient detection COEFF Transform OK + */ + FDKsbrEnc_transientDetect(&hEnvChan->sbrTransientDetector, + sbrExtrEnv->YBuffer, + sbrExtrEnv->YBufferScale, + eData->transient_info, + sbrExtrEnv->YBufferWriteOffset, + sbrExtrEnv->YBufferSzShift, + sbrExtrEnv->time_step, + hEnvChan->SbrEnvFrame.frameMiddleSlot); + + + + /* + Generate flags for 2 env in a FIXFIX-frame. + Remove this function to get always 1 env per FIXFIX-frame. + */ + + /* + frame Splitter COEFF Transform OK + */ + FDKsbrEnc_frameSplitter(sbrExtrEnv->YBuffer, + sbrExtrEnv->YBufferScale, + &hEnvChan->sbrTransientDetector, + h_con->freqBandTable[1], + eData->transient_info, + sbrExtrEnv->YBufferWriteOffset, + sbrExtrEnv->YBufferSzShift, + h_con->nSfb[1], + sbrExtrEnv->time_step, + sbrExtrEnv->no_cols); + + + + FDKsbrEnc_updateRIBuffers(hEnvChan); +} + +/***************************************************************************/ +/*! + + \brief calculates the noise floor and the envelope values from the + energies, depending on framing and stereo mode + + FDKsbrEnc_extractSbrEnvelope is the main function for encoding and writing the + envelope and the noise floor. The function includes the following processes: + + -Determine time/frequency division of current granule. + -Sending transient info to bitstream. + -Set amp_res to 1.5 dB if the current frame contains only one envelope. + -Lock dynamic bandwidth frequency change if the next envelope not starts on a + frame boundary. + -MDCT transposer (needed to detect where harmonics will be missing). + -Spectrum Estimation (used for pulse train and missing harmonics detection). + -Pulse train detection. + -Inverse Filtering detection. + -Waveform Coding. + -Missing Harmonics detection. + -Extract envelope of current frame. + -Noise floor estimation. + -Noise floor quantisation and coding. + -Encode envelope of current frame. + -Send the encoded data to the bitstream. + -Write to bitstream. + +****************************************************************************/ + +LNK_SECTION_CODE_L1 +void +FDKsbrEnc_extractSbrEnvelope2 ( + HANDLE_SBR_CONFIG_DATA h_con, /*! handle to config data */ + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_ENV_CHANNEL h_envChan0, + HANDLE_ENV_CHANNEL h_envChan1, + HANDLE_COMMON_DATA hCmonData, + SBR_ENV_TEMP_DATA *eData, + SBR_FRAME_TEMP_DATA *fData, + int clearOutput + ) +{ + HANDLE_ENV_CHANNEL h_envChan[MAX_NUM_CHANNELS] = {h_envChan0, h_envChan1}; + int ch, i, j, c, YSzShift = h_envChan[0]->sbrExtractEnvelope.YBufferSzShift; + + SBR_STEREO_MODE stereoMode = h_con->stereoMode; + int nChannels = h_con->nChannels; + const int *v_tuning; + static const int v_tuningHEAAC[6] = { 0, 2, 4, 0, 0, 0 }; + + static const int v_tuningELD[6] = { 0, 2, 3, 0, 0, 0 }; + + if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) + v_tuning = v_tuningELD; + else + v_tuning = v_tuningHEAAC; + + + /* + Select stereo mode. + */ + if (stereoMode == SBR_COUPLING) { + if (eData[0].transient_info[1] && eData[1].transient_info[1]) { + eData[0].transient_info[0] = fixMin(eData[1].transient_info[0], eData[0].transient_info[0]); + eData[1].transient_info[0] = eData[0].transient_info[0]; + } + else { + if (eData[0].transient_info[1] && !eData[1].transient_info[1]) { + eData[1].transient_info[0] = eData[0].transient_info[0]; + } + else { + if (!eData[0].transient_info[1] && eData[1].transient_info[1]) + eData[0].transient_info[0] = eData[1].transient_info[0]; + else { + eData[0].transient_info[0] = fixMax(eData[1].transient_info[0], eData[0].transient_info[0]); + eData[1].transient_info[0] = eData[0].transient_info[0]; + } + } + } + } + + /* + Determine time/frequency division of current granule + */ + eData[0].frame_info = FDKsbrEnc_frameInfoGenerator(&h_envChan[0]->SbrEnvFrame, + eData[0].transient_info, + h_envChan[0]->sbrExtractEnvelope.pre_transient_info, + h_envChan[0]->encEnvData.ldGrid, + v_tuning); + + h_envChan[0]->encEnvData.hSbrBSGrid = &h_envChan[0]->SbrEnvFrame.SbrGrid; + + /* AAC LD patch for transient prediction */ + if (h_envChan[0]->encEnvData.ldGrid && eData[0].transient_info[2]) { + /* if next frame will start with transient, set shortEnv to numEnvelopes(shortend Envelope = shortEnv-1)*/ + h_envChan[0]->SbrEnvFrame.SbrFrameInfo.shortEnv = h_envChan[0]->SbrEnvFrame.SbrFrameInfo.nEnvelopes; + } + + + switch (stereoMode) { + case SBR_LEFT_RIGHT: + case SBR_SWITCH_LRC: + eData[1].frame_info = FDKsbrEnc_frameInfoGenerator(&h_envChan[1]->SbrEnvFrame, + eData[1].transient_info, + h_envChan[1]->sbrExtractEnvelope.pre_transient_info, + h_envChan[1]->encEnvData.ldGrid, + v_tuning); + + h_envChan[1]->encEnvData.hSbrBSGrid = &h_envChan[1]->SbrEnvFrame.SbrGrid; + + if (h_envChan[1]->encEnvData.ldGrid && eData[1].transient_info[2]) { + /* if next frame will start with transient, set shortEnv to numEnvelopes(shortend Envelope = shortEnv-1)*/ + h_envChan[1]->SbrEnvFrame.SbrFrameInfo.shortEnv = h_envChan[1]->SbrEnvFrame.SbrFrameInfo.nEnvelopes; + } + + /* compare left and right frame_infos */ + if (eData[0].frame_info->nEnvelopes != eData[1].frame_info->nEnvelopes) { + stereoMode = SBR_LEFT_RIGHT; + } else { + for (i = 0; i < eData[0].frame_info->nEnvelopes + 1; i++) { + if (eData[0].frame_info->borders[i] != eData[1].frame_info->borders[i]) { + stereoMode = SBR_LEFT_RIGHT; + break; + } + } + for (i = 0; i < eData[0].frame_info->nEnvelopes; i++) { + if (eData[0].frame_info->freqRes[i] != eData[1].frame_info->freqRes[i]) { + stereoMode = SBR_LEFT_RIGHT; + break; + } + } + if (eData[0].frame_info->shortEnv != eData[1].frame_info->shortEnv) { + stereoMode = SBR_LEFT_RIGHT; + } + } + break; + case SBR_COUPLING: + eData[1].frame_info = eData[0].frame_info; + h_envChan[1]->encEnvData.hSbrBSGrid = &h_envChan[0]->SbrEnvFrame.SbrGrid; + break; + case SBR_MONO: + /* nothing to do */ + break; + default: + FDK_ASSERT (0); + } + + + for (ch = 0; ch < nChannels;ch++) + { + HANDLE_ENV_CHANNEL hEnvChan = h_envChan[ch]; + HANDLE_SBR_EXTRACT_ENVELOPE sbrExtrEnv = &hEnvChan->sbrExtractEnvelope; + SBR_ENV_TEMP_DATA *ed = &eData[ch]; + + + /* + Send transient info to bitstream and store for next call + */ + sbrExtrEnv->pre_transient_info[0] = ed->transient_info[0];/* tran_pos */ + sbrExtrEnv->pre_transient_info[1] = ed->transient_info[1];/* tran_flag */ + hEnvChan->encEnvData.noOfEnvelopes = ed->nEnvelopes = ed->frame_info->nEnvelopes; /* number of envelopes of current frame */ + + /* + Check if the current frame is divided into one envelope only. If so, set the amplitude + resolution to 1.5 dB, otherwise may set back to chosen value + */ + if( ( hEnvChan->encEnvData.hSbrBSGrid->frameClass == FIXFIX ) + && ( ed->nEnvelopes == 1 ) ) + { + + if (hEnvChan->encEnvData.ldGrid) + hEnvChan->encEnvData.currentAmpResFF = (AMP_RES)h_con->initAmpResFF; + else + hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_1_5; + + if ( hEnvChan->encEnvData.currentAmpResFF != hEnvChan->encEnvData.init_sbr_amp_res) { + + FDKsbrEnc_InitSbrHuffmanTables(&hEnvChan->encEnvData, + &hEnvChan->sbrCodeEnvelope, + &hEnvChan->sbrCodeNoiseFloor, + hEnvChan->encEnvData.currentAmpResFF); + } + } + else { + if(sbrHeaderData->sbr_amp_res != hEnvChan->encEnvData.init_sbr_amp_res ) { + + FDKsbrEnc_InitSbrHuffmanTables(&hEnvChan->encEnvData, + &hEnvChan->sbrCodeEnvelope, + &hEnvChan->sbrCodeNoiseFloor, + sbrHeaderData->sbr_amp_res); + } + } + + if (!clearOutput) { + + /* + Tonality correction parameter extraction (inverse filtering level, noise floor additional sines). + */ + FDKsbrEnc_TonCorrParamExtr(&hEnvChan->TonCorr, + hEnvChan->encEnvData.sbr_invf_mode_vec, + ed->noiseFloor, + &hEnvChan->encEnvData.addHarmonicFlag, + hEnvChan->encEnvData.addHarmonic, + sbrExtrEnv->envelopeCompensation, + ed->frame_info, + ed->transient_info, + h_con->freqBandTable[HI], + h_con->nSfb[HI], + hEnvChan->encEnvData.sbr_xpos_mode, + h_con->sbrSyntaxFlags); + + } + + /* Low energy in low band fix */ + if ( hEnvChan->sbrTransientDetector.prevLowBandEnergy < hEnvChan->sbrTransientDetector.prevHighBandEnergy && hEnvChan->sbrTransientDetector.prevHighBandEnergy > FL2FX_DBL(0.03)) + { + int i; + + hEnvChan->fLevelProtect = 1; + + for (i=0; iencEnvData.sbr_invf_mode_vec[i] = INVF_HIGH_LEVEL; + } else { + hEnvChan->fLevelProtect = 0; + } + + hEnvChan->encEnvData.sbr_invf_mode = hEnvChan->encEnvData.sbr_invf_mode_vec[0]; + + hEnvChan->encEnvData.noOfnoisebands = hEnvChan->TonCorr.sbrNoiseFloorEstimate.noNoiseBands; + + + } /* ch */ + + + + /* + Save number of scf bands per envelope + */ + for (ch = 0; ch < nChannels;ch++) { + for (i = 0; i < eData[ch].nEnvelopes; i++){ + h_envChan[ch]->encEnvData.noScfBands[i] = + (eData[ch].frame_info->freqRes[i] == FREQ_RES_HIGH ? h_con->nSfb[FREQ_RES_HIGH] : h_con->nSfb[FREQ_RES_LOW]); + } + } + + /* + Extract envelope of current frame. + */ + switch (stereoMode) { + case SBR_MONO: + calculateSbrEnvelope (h_envChan[0]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, NULL, + eData[0].frame_info, eData[0].sfb_nrg, NULL, + h_con, h_envChan[0], SBR_MONO, NULL, YSzShift); + break; + case SBR_LEFT_RIGHT: + calculateSbrEnvelope (h_envChan[0]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, NULL, + eData[0].frame_info, eData[0].sfb_nrg, NULL, + h_con, h_envChan[0], SBR_MONO, NULL, YSzShift); + calculateSbrEnvelope (h_envChan[1]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[1]->sbrExtractEnvelope.YBufferScale, NULL, + eData[1].frame_info,eData[1].sfb_nrg, NULL, + h_con, h_envChan[1], SBR_MONO, NULL, YSzShift); + break; + case SBR_COUPLING: + calculateSbrEnvelope (h_envChan[0]->sbrExtractEnvelope.YBuffer, h_envChan[1]->sbrExtractEnvelope.YBuffer, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, h_envChan[1]->sbrExtractEnvelope.YBufferScale, + eData[0].frame_info, eData[0].sfb_nrg, eData[1].sfb_nrg, + h_con, h_envChan[0], SBR_COUPLING, &fData->maxQuantError, YSzShift); + break; + case SBR_SWITCH_LRC: + calculateSbrEnvelope (h_envChan[0]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, NULL, + eData[0].frame_info, eData[0].sfb_nrg, NULL, + h_con, h_envChan[0], SBR_MONO, NULL, YSzShift); + calculateSbrEnvelope (h_envChan[1]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[1]->sbrExtractEnvelope.YBufferScale, NULL, + eData[1].frame_info, eData[1].sfb_nrg, NULL, + h_con, h_envChan[1], SBR_MONO,NULL, YSzShift); + calculateSbrEnvelope (h_envChan[0]->sbrExtractEnvelope.YBuffer, h_envChan[1]->sbrExtractEnvelope.YBuffer, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, h_envChan[1]->sbrExtractEnvelope.YBufferScale, + eData[0].frame_info, eData[0].sfb_nrg_coupling, eData[1].sfb_nrg_coupling, + h_con, h_envChan[0], SBR_COUPLING, &fData->maxQuantError, YSzShift); + break; + } + + + + /* + Noise floor quantisation and coding. + */ + + switch (stereoMode) { + case SBR_MONO: + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level, eData[0].noiseFloor, 0); + + FDKsbrEnc_codeEnvelope(eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 0, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + break; + case SBR_LEFT_RIGHT: + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level,eData[0].noiseFloor, 0); + + FDKsbrEnc_codeEnvelope (eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 0, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level,eData[1].noiseFloor, 0); + + FDKsbrEnc_codeEnvelope (eData[1].noise_level, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 0, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + break; + + case SBR_COUPLING: + coupleNoiseFloor(eData[0].noiseFloor,eData[1].noiseFloor); + + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level,eData[0].noiseFloor, 0); + + FDKsbrEnc_codeEnvelope (eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 1, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level,eData[1].noiseFloor, 1); + + FDKsbrEnc_codeEnvelope (eData[1].noise_level, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 1, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 1, + sbrBitstreamData->HeaderActive); + + break; + case SBR_SWITCH_LRC: + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level,eData[0].noiseFloor, 0); + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level,eData[1].noiseFloor, 0); + coupleNoiseFloor(eData[0].noiseFloor,eData[1].noiseFloor); + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level_coupling,eData[0].noiseFloor, 0); + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level_coupling,eData[1].noiseFloor, 1); + break; + } + + + + /* + Encode envelope of current frame. + */ + switch (stereoMode) { + case SBR_MONO: + sbrHeaderData->coupling = 0; + h_envChan[0]->encEnvData.balance = 0; + FDKsbrEnc_codeEnvelope (eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, + h_envChan[0]->encEnvData.domain_vec, + sbrHeaderData->coupling, + eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + break; + case SBR_LEFT_RIGHT: + sbrHeaderData->coupling = 0; + + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 0; + + + FDKsbrEnc_codeEnvelope (eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, + h_envChan[0]->encEnvData.domain_vec, + sbrHeaderData->coupling, + eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + FDKsbrEnc_codeEnvelope (eData[1].sfb_nrg, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, + h_envChan[1]->encEnvData.domain_vec, + sbrHeaderData->coupling, + eData[1].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + break; + case SBR_COUPLING: + sbrHeaderData->coupling = 1; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 1; + + FDKsbrEnc_codeEnvelope (eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, + h_envChan[0]->encEnvData.domain_vec, + sbrHeaderData->coupling, + eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + FDKsbrEnc_codeEnvelope (eData[1].sfb_nrg, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, + h_envChan[1]->encEnvData.domain_vec, + sbrHeaderData->coupling, + eData[1].frame_info->nEnvelopes, 1, + sbrBitstreamData->HeaderActive); + break; + case SBR_SWITCH_LRC: + { + INT payloadbitsLR; + INT payloadbitsCOUPLING; + + SCHAR sfbNrgPrevTemp[MAX_NUM_CHANNELS][MAX_FREQ_COEFFS]; + SCHAR noisePrevTemp[MAX_NUM_CHANNELS][MAX_NUM_NOISE_COEFFS]; + INT upDateNrgTemp[MAX_NUM_CHANNELS]; + INT upDateNoiseTemp[MAX_NUM_CHANNELS]; + INT domainVecTemp[MAX_NUM_CHANNELS][MAX_ENVELOPES]; + INT domainVecNoiseTemp[MAX_NUM_CHANNELS][MAX_ENVELOPES]; + + INT tempFlagRight = 0; + INT tempFlagLeft = 0; + + /* + Store previous values, in order to be able to "undo" what is being done. + */ + + for(ch = 0; ch < nChannels;ch++){ + FDKmemcpy (sfbNrgPrevTemp[ch], h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev, + MAX_FREQ_COEFFS * sizeof (SCHAR)); + + FDKmemcpy (noisePrevTemp[ch], h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev, + MAX_NUM_NOISE_COEFFS * sizeof (SCHAR)); + + upDateNrgTemp[ch] = h_envChan[ch]->sbrCodeEnvelope.upDate; + upDateNoiseTemp[ch] = h_envChan[ch]->sbrCodeNoiseFloor.upDate; + + /* + forbid time coding in the first envelope in case of a different + previous stereomode + */ + if(sbrHeaderData->prev_coupling){ + h_envChan[ch]->sbrCodeEnvelope.upDate = 0; + h_envChan[ch]->sbrCodeNoiseFloor.upDate = 0; + } + } /* ch */ + + + /* + Code ordinary Left/Right stereo + */ + FDKsbrEnc_codeEnvelope (eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, + h_envChan[0]->encEnvData.domain_vec, 0, + eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + FDKsbrEnc_codeEnvelope (eData[1].sfb_nrg, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, + h_envChan[1]->encEnvData.domain_vec, 0, + eData[1].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + + c = 0; + for (i = 0; i < eData[0].nEnvelopes; i++) { + for (j = 0; j < h_envChan[0]->encEnvData.noScfBands[i]; j++) + { + h_envChan[0]->encEnvData.ienvelope[i][j] = eData[0].sfb_nrg[c]; + h_envChan[1]->encEnvData.ienvelope[i][j] = eData[1].sfb_nrg[c]; + c++; + } + } + + + + FDKsbrEnc_codeEnvelope (eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 0, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[0]->encEnvData.sbr_noise_levels[i] = eData[0].noise_level[i]; + + + FDKsbrEnc_codeEnvelope (eData[1].noise_level, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 0, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[1]->encEnvData.sbr_noise_levels[i] = eData[1].noise_level[i]; + + + sbrHeaderData->coupling = 0; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 0; + + payloadbitsLR = FDKsbrEnc_CountSbrChannelPairElement (sbrHeaderData, + hParametricStereo, + sbrBitstreamData, + &h_envChan[0]->encEnvData, + &h_envChan[1]->encEnvData, + hCmonData, + h_con->sbrSyntaxFlags); + + /* + swap saved stored with current values + */ + for(ch = 0; ch < nChannels;ch++){ + INT itmp; + for(i=0;isbrCodeEnvelope.sfb_nrg_prev[i]; + h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev[i]=sfbNrgPrevTemp[ch][i]; + sfbNrgPrevTemp[ch][i]=itmp; + } + for(i=0;isbrCodeNoiseFloor.sfb_nrg_prev[i]; + h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev[i]=noisePrevTemp[ch][i]; + noisePrevTemp[ch][i]=itmp; + } + /* swap update flags */ + itmp = h_envChan[ch]->sbrCodeEnvelope.upDate; + h_envChan[ch]->sbrCodeEnvelope.upDate=upDateNrgTemp[ch]; + upDateNrgTemp[ch] = itmp; + + itmp = h_envChan[ch]->sbrCodeNoiseFloor.upDate; + h_envChan[ch]->sbrCodeNoiseFloor.upDate=upDateNoiseTemp[ch]; + upDateNoiseTemp[ch]=itmp; + + /* + save domain vecs + */ + FDKmemcpy(domainVecTemp[ch],h_envChan[ch]->encEnvData.domain_vec,sizeof(INT)*MAX_ENVELOPES); + FDKmemcpy(domainVecNoiseTemp[ch],h_envChan[ch]->encEnvData.domain_vec_noise,sizeof(INT)*MAX_ENVELOPES); + + /* + forbid time coding in the first envelope in case of a different + previous stereomode + */ + + if(!sbrHeaderData->prev_coupling){ + h_envChan[ch]->sbrCodeEnvelope.upDate = 0; + h_envChan[ch]->sbrCodeNoiseFloor.upDate = 0; + } + } /* ch */ + + + /* + Coupling + */ + + FDKsbrEnc_codeEnvelope (eData[0].sfb_nrg_coupling, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, + h_envChan[0]->encEnvData.domain_vec, 1, + eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + + FDKsbrEnc_codeEnvelope (eData[1].sfb_nrg_coupling, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, + h_envChan[1]->encEnvData.domain_vec, 1, + eData[1].frame_info->nEnvelopes, 1, + sbrBitstreamData->HeaderActive); + + + c = 0; + for (i = 0; i < eData[0].nEnvelopes; i++) { + for (j = 0; j < h_envChan[0]->encEnvData.noScfBands[i]; j++) { + h_envChan[0]->encEnvData.ienvelope[i][j] = eData[0].sfb_nrg_coupling[c]; + h_envChan[1]->encEnvData.ienvelope[i][j] = eData[1].sfb_nrg_coupling[c]; + c++; + } + } + + FDKsbrEnc_codeEnvelope (eData[0].noise_level_coupling, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 1, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[0]->encEnvData.sbr_noise_levels[i] = eData[0].noise_level_coupling[i]; + + + FDKsbrEnc_codeEnvelope (eData[1].noise_level_coupling, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 1, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 1, + sbrBitstreamData->HeaderActive); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[1]->encEnvData.sbr_noise_levels[i] = eData[1].noise_level_coupling[i]; + + sbrHeaderData->coupling = 1; + + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 1; + + tempFlagLeft = h_envChan[0]->encEnvData.addHarmonicFlag; + tempFlagRight = h_envChan[1]->encEnvData.addHarmonicFlag; + + payloadbitsCOUPLING = + FDKsbrEnc_CountSbrChannelPairElement (sbrHeaderData, + hParametricStereo, + sbrBitstreamData, + &h_envChan[0]->encEnvData, + &h_envChan[1]->encEnvData, + hCmonData, + h_con->sbrSyntaxFlags); + + + h_envChan[0]->encEnvData.addHarmonicFlag = tempFlagLeft; + h_envChan[1]->encEnvData.addHarmonicFlag = tempFlagRight; + + if (payloadbitsCOUPLING < payloadbitsLR) { + + /* + copy coded coupling envelope and noise data to l/r + */ + for(ch = 0; ch < nChannels;ch++){ + SBR_ENV_TEMP_DATA *ed = &eData[ch]; + FDKmemcpy (ed->sfb_nrg, ed->sfb_nrg_coupling, + MAX_NUM_ENVELOPE_VALUES * sizeof (SCHAR)); + FDKmemcpy (ed->noise_level, ed->noise_level_coupling, + MAX_NUM_NOISE_VALUES * sizeof (SCHAR)); + } + + sbrHeaderData->coupling = 1; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 1; + } + else{ + /* + restore saved l/r items + */ + for(ch = 0; ch < nChannels;ch++){ + + FDKmemcpy (h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev, + sfbNrgPrevTemp[ch], MAX_FREQ_COEFFS * sizeof (SCHAR)); + + h_envChan[ch]->sbrCodeEnvelope.upDate = upDateNrgTemp[ch]; + + FDKmemcpy (h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev, + noisePrevTemp[ch], MAX_NUM_NOISE_COEFFS * sizeof (SCHAR)); + + FDKmemcpy (h_envChan[ch]->encEnvData.domain_vec,domainVecTemp[ch],sizeof(INT)*MAX_ENVELOPES); + FDKmemcpy (h_envChan[ch]->encEnvData.domain_vec_noise,domainVecNoiseTemp[ch],sizeof(INT)*MAX_ENVELOPES); + + h_envChan[ch]->sbrCodeNoiseFloor.upDate = upDateNoiseTemp[ch]; + } + + sbrHeaderData->coupling = 0; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 0; + } + } + break; + } /* switch */ + + + /* tell the envelope encoders how long it has been, since we last sent + a frame starting with a dF-coded envelope */ + if (stereoMode == SBR_MONO ) { + if (h_envChan[0]->encEnvData.domain_vec[0] == TIME) + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac++; + else + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac = 0; + } + else { + if (h_envChan[0]->encEnvData.domain_vec[0] == TIME || + h_envChan[1]->encEnvData.domain_vec[0] == TIME) { + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac++; + h_envChan[1]->sbrCodeEnvelope.dF_edge_incr_fac++; + } + else { + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac = 0; + h_envChan[1]->sbrCodeEnvelope.dF_edge_incr_fac = 0; + } + } + + /* + Send the encoded data to the bitstream + */ + for(ch = 0; ch < nChannels;ch++){ + SBR_ENV_TEMP_DATA *ed = &eData[ch]; + c = 0; + for (i = 0; i < ed->nEnvelopes; i++) { + for (j = 0; j < h_envChan[ch]->encEnvData.noScfBands[i]; j++) { + h_envChan[ch]->encEnvData.ienvelope[i][j] = ed->sfb_nrg[c]; + + c++; + } + } + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++){ + h_envChan[ch]->encEnvData.sbr_noise_levels[i] = ed->noise_level[i]; + } + }/* ch */ + + + /* + Write bitstream + */ + if (nChannels == 2) { + FDKsbrEnc_WriteEnvChannelPairElement(sbrHeaderData, + hParametricStereo, + sbrBitstreamData, + &h_envChan[0]->encEnvData, + &h_envChan[1]->encEnvData, + hCmonData, + h_con->sbrSyntaxFlags); + } + else { + FDKsbrEnc_WriteEnvSingleChannelElement(sbrHeaderData, + hParametricStereo, + sbrBitstreamData, + &h_envChan[0]->encEnvData, + hCmonData, + h_con->sbrSyntaxFlags); + } + + /* + * Update buffers. + */ + for (ch=0; chsbrExtractEnvelope.no_cols >> h_envChan[ch]->sbrExtractEnvelope.YBufferSzShift; + for (i = 0; i < h_envChan[ch]->sbrExtractEnvelope.YBufferWriteOffset; i++) { + FDKmemcpy(h_envChan[ch]->sbrExtractEnvelope.YBuffer[i], + h_envChan[ch]->sbrExtractEnvelope.YBuffer[i + YBufferLength], + sizeof(FIXP_DBL)*QMF_CHANNELS); + } + h_envChan[ch]->sbrExtractEnvelope.YBufferScale[0] = h_envChan[ch]->sbrExtractEnvelope.YBufferScale[1]; + } + + sbrHeaderData->prev_coupling = sbrHeaderData->coupling; +} + +/***************************************************************************/ +/*! + + \brief creates an envelope extractor handle + + \return error status + +****************************************************************************/ +INT +FDKsbrEnc_CreateExtractSbrEnvelope (HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut, + INT channel + ,INT chInEl + ,UCHAR* dynamic_RAM + ) +{ + INT i; + FIXP_DBL* YBuffer = GetRam_Sbr_envYBuffer(channel); + + FDKmemclear(hSbrCut,sizeof(SBR_EXTRACT_ENVELOPE)); + hSbrCut->p_YBuffer = YBuffer; + + + for (i = 0; i < (QMF_MAX_TIME_SLOTS>>1); i++) { + hSbrCut->YBuffer[i] = YBuffer + (i*QMF_CHANNELS); + } + FIXP_DBL *YBufferDyn = GetRam_Sbr_envYBuffer(chInEl, dynamic_RAM); + INT n=0; + for (; i < QMF_MAX_TIME_SLOTS; i++,n++) { + hSbrCut->YBuffer[i] = YBufferDyn + (n*QMF_CHANNELS); + } + + FIXP_DBL* rBuffer = GetRam_Sbr_envRBuffer(0, dynamic_RAM); + FIXP_DBL* iBuffer = GetRam_Sbr_envIBuffer(0, dynamic_RAM); + + for (i = 0; i < QMF_MAX_TIME_SLOTS; i++) { + hSbrCut->rBuffer[i] = rBuffer + (i*QMF_CHANNELS); + hSbrCut->iBuffer[i] = iBuffer + (i*QMF_CHANNELS); + } + + return 0; +} + + +/***************************************************************************/ +/*! + + \brief Initialize an envelope extractor instance. + + \return error status + +****************************************************************************/ +INT +FDKsbrEnc_InitExtractSbrEnvelope (HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut, + int no_cols, + int no_rows, + int start_index, + int time_slots, + int time_step, + int tran_off, + ULONG statesInitFlag + ,int chInEl + ,UCHAR* dynamic_RAM + ,UINT sbrSyntaxFlags + ) +{ + int YBufferLength, rBufferLength; + int i; + + if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + int off = TRANSIENT_OFFSET_LD; +#ifndef FULL_DELAY + hSbrCut->YBufferWriteOffset = (no_cols>>1)+off*time_step; +#else + hSbrCut->YBufferWriteOffset = no_cols+off*time_step; +#endif + } else + { + hSbrCut->YBufferWriteOffset = tran_off*time_step; + } + hSbrCut->rBufferWriteOffset = 0; + hSbrCut->rBufferReadOffset = 0; + + + YBufferLength = hSbrCut->YBufferWriteOffset + no_cols; + rBufferLength = hSbrCut->rBufferWriteOffset + no_cols; + + hSbrCut->pre_transient_info[0] = 0; + hSbrCut->pre_transient_info[1] = 0; + + + hSbrCut->no_cols = no_cols; + hSbrCut->no_rows = no_rows; + hSbrCut->start_index = start_index; + + hSbrCut->time_slots = time_slots; + hSbrCut->time_step = time_step; + + //FDK_ASSERT(rBufferLength == no_cols); + //FDK_ASSERT(YBufferLength == 2*no_cols); + FDK_ASSERT(no_rows <= QMF_CHANNELS); + + /* Use half the Energy values if time step is 2 or greater */ + if (time_step >= 2) + hSbrCut->YBufferSzShift = 1; + else + hSbrCut->YBufferSzShift = 0; + + YBufferLength >>= hSbrCut->YBufferSzShift; + hSbrCut->YBufferWriteOffset >>= hSbrCut->YBufferSzShift; + + FDK_ASSERT(YBufferLength<=QMF_MAX_TIME_SLOTS); + + FIXP_DBL *YBufferDyn = GetRam_Sbr_envYBuffer(chInEl, dynamic_RAM); + INT n=0; + for (i=(QMF_MAX_TIME_SLOTS>>1); i < QMF_MAX_TIME_SLOTS; i++,n++) { + hSbrCut->YBuffer[i] = YBufferDyn + (n*QMF_CHANNELS); + } + + if(statesInitFlag) { + for (i=0; iYBuffer[i],QMF_CHANNELS*sizeof(FIXP_DBL)); + } + } + + for (i = 0; i < rBufferLength; i++) { + FDKmemclear( hSbrCut->rBuffer[i],QMF_CHANNELS*sizeof(FIXP_DBL)); + FDKmemclear( hSbrCut->iBuffer[i],QMF_CHANNELS*sizeof(FIXP_DBL)); + } + + FDKmemclear (hSbrCut->envelopeCompensation,sizeof(UCHAR)*MAX_FREQ_COEFFS); + + if(statesInitFlag) { + hSbrCut->YBufferScale[0] = hSbrCut->YBufferScale[1] = FRACT_BITS-1; + } + + return (0); +} + + + + +/***************************************************************************/ +/*! + + \brief deinitializes an envelope extractor handle + + \return void + +****************************************************************************/ + +void +FDKsbrEnc_deleteExtractSbrEnvelope (HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut) +{ + + if (hSbrCut) { + FreeRam_Sbr_envYBuffer(&hSbrCut->p_YBuffer); + } +} + +INT +FDKsbrEnc_GetEnvEstDelay(HANDLE_SBR_EXTRACT_ENVELOPE hSbr) +{ + return hSbr->no_rows*((hSbr->YBufferWriteOffset)*2 + /* mult 2 because nrg's are grouped half */ + hSbr->rBufferWriteOffset - hSbr->rBufferReadOffset ); /* in reference hold half spec and calc nrg's on overlapped spec */ + +} + + + + diff --git a/libSBRenc/src/env_est.h b/libSBRenc/src/env_est.h new file mode 100644 index 0000000..5aa66ee --- /dev/null +++ b/libSBRenc/src/env_est.h @@ -0,0 +1,167 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +****************************************************************************/ +/*! + \file + \brief Envelope estimation structs and prototypes $Revision: 36847 $ +*/ +#ifndef __ENV_EST_H +#define __ENV_EST_H + +#include "sbr_def.h" +#include "sbr_encoder.h" /* SBR econfig structs */ +#include "ps_main.h" +#include "bit_sbr.h" +#include "fram_gen.h" +#include "tran_det.h" +#include "code_env.h" +#include "ton_corr.h" + +typedef struct +{ + FIXP_DBL *rBuffer[QMF_MAX_TIME_SLOTS]; + FIXP_DBL *iBuffer[QMF_MAX_TIME_SLOTS]; + + FIXP_DBL *p_YBuffer; + + FIXP_DBL *YBuffer[QMF_MAX_TIME_SLOTS]; + int YBufferScale[2]; + + UCHAR envelopeCompensation[MAX_FREQ_COEFFS]; + UCHAR pre_transient_info[2]; + + + int YBufferWriteOffset; + int YBufferSzShift; + int rBufferReadOffset; + int rBufferWriteOffset; + + int no_cols; + int no_rows; + int start_index; + + int time_slots; + int time_step; +} +SBR_EXTRACT_ENVELOPE; +typedef SBR_EXTRACT_ENVELOPE *HANDLE_SBR_EXTRACT_ENVELOPE; + +struct ENV_CHANNEL +{ + SBR_TRANSIENT_DETECTOR sbrTransientDetector; + SBR_CODE_ENVELOPE sbrCodeEnvelope; + SBR_CODE_ENVELOPE sbrCodeNoiseFloor; + SBR_EXTRACT_ENVELOPE sbrExtractEnvelope; + + + SBR_ENVELOPE_FRAME SbrEnvFrame; + SBR_TON_CORR_EST TonCorr; + + struct SBR_ENV_DATA encEnvData; + + int qmfScale; + UCHAR fLevelProtect; +}; +typedef struct ENV_CHANNEL *HANDLE_ENV_CHANNEL; + +/************ Function Declarations ***************/ + +INT +FDKsbrEnc_CreateExtractSbrEnvelope (HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut, + INT channel + ,INT chInEl + ,UCHAR* dynamic_RAM + ); + + +INT +FDKsbrEnc_InitExtractSbrEnvelope ( + HANDLE_SBR_EXTRACT_ENVELOPE hSbr, + int no_cols, + int no_rows, + int start_index, + int time_slots, int time_step, int tran_off, + ULONG statesInitFlag + ,int chInEl + ,UCHAR* dynamic_RAM + ,UINT sbrSyntaxFlags + ); + +void FDKsbrEnc_deleteExtractSbrEnvelope (HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut); + +typedef struct { + FREQ_RES res[MAX_NUM_NOISE_VALUES]; + int maxQuantError; + +} SBR_FRAME_TEMP_DATA; + +typedef struct { + const SBR_FRAME_INFO *frame_info; + FIXP_DBL noiseFloor[MAX_NUM_NOISE_VALUES]; + SCHAR sfb_nrg_coupling[MAX_NUM_ENVELOPE_VALUES]; /* only used if stereomode = SWITCH_L_R_C */ + SCHAR sfb_nrg[MAX_NUM_ENVELOPE_VALUES]; + SCHAR noise_level_coupling[MAX_NUM_NOISE_VALUES]; /* only used if stereomode = SWITCH_L_R_C */ + SCHAR noise_level[MAX_NUM_NOISE_VALUES]; + UCHAR transient_info[3]; + UCHAR nEnvelopes; +} SBR_ENV_TEMP_DATA; + +/* + * Extract features from QMF data. Afterwards, the QMF data is not required anymore. + */ +void +FDKsbrEnc_extractSbrEnvelope1( + HANDLE_SBR_CONFIG_DATA h_con, + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_ENV_CHANNEL h_envChan, + HANDLE_COMMON_DATA cmonData, + SBR_ENV_TEMP_DATA *eData, + SBR_FRAME_TEMP_DATA *fData + ); + + +/* + * Process the previously features extracted by FDKsbrEnc_extractSbrEnvelope1 + * and create/encode SBR envelopes. + */ +void +FDKsbrEnc_extractSbrEnvelope2( + HANDLE_SBR_CONFIG_DATA h_con, + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_ENV_CHANNEL sbrEnvChannel0, + HANDLE_ENV_CHANNEL sbrEnvChannel1, + HANDLE_COMMON_DATA cmonData, + SBR_ENV_TEMP_DATA *eData, + SBR_FRAME_TEMP_DATA *fData, + int clearOutput + ); + +INT +FDKsbrEnc_GetEnvEstDelay(HANDLE_SBR_EXTRACT_ENVELOPE hSbr); + +#endif diff --git a/libSBRenc/src/fram_gen.cpp b/libSBRenc/src/fram_gen.cpp new file mode 100644 index 0000000..710b13e --- /dev/null +++ b/libSBRenc/src/fram_gen.cpp @@ -0,0 +1,2015 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +#include "fram_gen.h" +#include "sbr_misc.h" + +#include "genericStds.h" + +static const SBR_FRAME_INFO frameInfo1_2048 = { + 1, + { 0, 16}, + {FREQ_RES_HIGH}, + 0, + 1, + {0, 16} }; + +static const SBR_FRAME_INFO frameInfo2_2048 = { + 2, + { 0, 8, 16}, + {FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 8, 16} }; + +static const SBR_FRAME_INFO frameInfo4_2048 = { + 4, + { 0, 4, 8, 12, 16}, + {FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 8, 16} }; + +static const SBR_FRAME_INFO frameInfo1_2304 = { + 1, + { 0, 18}, + {FREQ_RES_HIGH}, + 0, + 1, + { 0, 18} }; + +static const SBR_FRAME_INFO frameInfo2_2304 = { + 2, + { 0, 9, 18}, + {FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 9, 18} }; + +static const SBR_FRAME_INFO frameInfo4_2304 = { + 4, + { 0, 5, 9, 14, 18}, + {FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 9, 18} }; + +static const SBR_FRAME_INFO frameInfo1_1920 = { + 1, + { 0, 15}, + {FREQ_RES_HIGH}, + 0, + 1, + { 0, 15} }; + +static const SBR_FRAME_INFO frameInfo2_1920 = { + 2, + { 0, 8, 15}, + {FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 8, 15} }; + +static const SBR_FRAME_INFO frameInfo4_1920 = { + 4, + { 0, 4, 8, 12, 15}, + {FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 8, 15} }; + +static const SBR_FRAME_INFO frameInfo1_1152 = { + 1, + { 0, 9}, + {FREQ_RES_HIGH}, + 0, + 1, + { 0, 9} }; + +static const SBR_FRAME_INFO frameInfo2_1152 = { + 2, + { 0, 5, 9}, + {FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 5, 9} }; + +static const SBR_FRAME_INFO frameInfo4_1152 = { + 4, + { 0, 2, 5, + 7, 9}, + {FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 5, 9} }; + + +/* AACLD frame info */ +static const SBR_FRAME_INFO frameInfo1_512LD = { + 1, + {0, 8}, + {FREQ_RES_HIGH}, + 0, + 1, + {0, 8}}; + +static const SBR_FRAME_INFO frameInfo2_512LD = { + 2, + {0, 4, 8}, + {FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + {0, 4, 8}}; + +static const SBR_FRAME_INFO frameInfo4_512LD = { + 4, + {0, 2, 4, 6, 8}, + {FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + {0, 4, 8}}; + +static int +calcFillLengthMax (int tranPos, /*!< input : transient position (ref: tran det) */ + int numberTimeSlots /*!< input : number of timeslots */ + ); + +static void +fillFrameTran (const int *v_tuningSegm, /*!< tuning: desired segment lengths */ + const int *v_tuningFreq, /*!< tuning: desired frequency resolutions */ + int tran, /*!< input : position of transient */ + int *v_bord, /*!< memNew: borders */ + int *length_v_bord, /*!< memNew: # borders */ + int *v_freq, /*!< memNew: frequency resolutions */ + int *length_v_freq, /*!< memNew: # frequency resolutions */ + int *bmin, /*!< hlpNew: first mandatory border */ + int *bmax /*!< hlpNew: last mandatory border */ + ); + +static void fillFramePre (INT dmax, INT *v_bord, INT *length_v_bord, + INT *v_freq, INT *length_v_freq, INT bmin, + INT rest); + +static void fillFramePost (INT *parts, INT *d, INT dmax, INT *v_bord, + INT *length_v_bord, INT *v_freq, + INT *length_v_freq, INT bmax, + INT bufferFrameStart, INT numberTimeSlots, INT fmax); + +static void fillFrameInter (INT *nL, const int *v_tuningSegm, INT *v_bord, + INT *length_v_bord, INT bmin, INT *v_freq, + INT *length_v_freq, INT *v_bordFollow, + INT *length_v_bordFollow, INT *v_freqFollow, + INT *length_v_freqFollow, INT i_fillFollow, + INT dmin, INT dmax, INT numberTimeSlots); + +static void calcFrameClass (FRAME_CLASS *frameClass, FRAME_CLASS *frameClassOld, INT tranFlag, + INT *spreadFlag); + +static void specialCase (INT *spreadFlag, INT allowSpread, INT *v_bord, + INT *length_v_bord, INT *v_freq, INT *length_v_freq, + INT *parts, INT d); + +static void calcCmonBorder (INT *i_cmon, INT *i_tran, INT *v_bord, + INT *length_v_bord, INT tran, + INT bufferFrameStart, INT numberTimeSlots); + +static void keepForFollowUp (INT *v_bordFollow, INT *length_v_bordFollow, + INT *v_freqFollow, INT *length_v_freqFollow, + INT *i_tranFollow, INT *i_fillFollow, + INT *v_bord, INT *length_v_bord, INT *v_freq, + INT i_cmon, INT i_tran, INT parts, INT numberTimeSlots); + +static void calcCtrlSignal (HANDLE_SBR_GRID hSbrGrid, FRAME_CLASS frameClass, + INT *v_bord, INT length_v_bord, INT *v_freq, + INT length_v_freq, INT i_cmon, INT i_tran, + INT spreadFlag, INT nL); + +static void ctrlSignal2FrameInfo (HANDLE_SBR_GRID hSbrGrid, + HANDLE_SBR_FRAME_INFO hFrameInfo, + INT freq_res_fixfix); + + +/* table for 8 time slot index */ +static const int envelopeTable_8 [8][5] = { +/* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */ +/* borders from left to right side; -1 = not in use */ + /*[|T-|------]*/ { 2, 0, 0, 1, -1 }, + /*[|-T-|-----]*/ { 2, 0, 0, 2, -1 }, + /*[--|T-|----]*/ { 3, 1, 1, 2, 4 }, + /*[---|T-|---]*/ { 3, 1, 1, 3, 5 }, + /*[----|T-|--]*/ { 3, 1, 1, 4, 6 }, + /*[-----|T--|]*/ { 2, 1, 1, 5, -1 }, + /*[------|T-|]*/ { 2, 1, 1, 6, -1 }, + /*[-------|T|]*/ { 2, 1, 1, 7, -1 }, +}; + +/* table for 16 time slot index */ +static const int envelopeTable_16 [16][6] = { + /* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */ + /* length from left to right side; -1 = not in use */ + /*[|T---|------------|]*/ { 2, 0, 0, 4, -1, -1}, + /*[|-T---|-----------|]*/ { 2, 0, 0, 5, -1, -1}, + /*[|--|T---|----------]*/ { 3, 1, 1, 2, 6, -1}, + /*[|---|T---|---------]*/ { 3, 1, 1, 3, 7, -1}, + /*[|----|T---|--------]*/ { 3, 1, 1, 4, 8, -1}, + /*[|-----|T---|-------]*/ { 3, 1, 1, 5, 9, -1}, + /*[|------|T---|------]*/ { 3, 1, 1, 6, 10, -1}, + /*[|-------|T---|-----]*/ { 3, 1, 1, 7, 11, -1}, + /*[|--------|T---|----]*/ { 3, 1, 1, 8, 12, -1}, + /*[|---------|T---|---]*/ { 3, 1, 1, 9, 13, -1}, + /*[|----------|T---|--]*/ { 3, 1, 1,10, 14, -1}, + /*[|-----------|T----|]*/ { 2, 1, 1,11, -1, -1}, + /*[|------------|T---|]*/ { 2, 1, 1,12, -1, -1}, + /*[|-------------|T--|]*/ { 2, 1, 1,13, -1, -1}, + /*[|--------------|T-|]*/ { 2, 1, 1,14, -1, -1}, + /*[|---------------|T|]*/ { 2, 1, 1,15, -1, -1}, +}; + +/* table for 15 time slot index */ +static const int envelopeTable_15 [15][6] = { + /* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */ + /* length from left to right side; -1 = not in use */ + /*[|T---|------------]*/ { 2, 0, 0, 4, -1, -1}, + /*[|-T---|-----------]*/ { 2, 0, 0, 5, -1, -1}, + /*[|--|T---|---------]*/ { 3, 1, 1, 2, 6, -1}, + /*[|---|T---|--------]*/ { 3, 1, 1, 3, 7, -1}, + /*[|----|T---|-------]*/ { 3, 1, 1, 4, 8, -1}, + /*[|-----|T---|------]*/ { 3, 1, 1, 5, 9, -1}, + /*[|------|T---|-----]*/ { 3, 1, 1, 6, 10, -1}, + /*[|-------|T---|----]*/ { 3, 1, 1, 7, 11, -1}, + /*[|--------|T---|---]*/ { 3, 1, 1, 8, 12, -1}, + /*[|---------|T---|--]*/ { 3, 1, 1, 9, 13, -1}, + /*[|----------|T----|]*/ { 2, 1, 1,10, -1, -1}, + /*[|-----------|T---|]*/ { 2, 1, 1,11, -1, -1}, + /*[|------------|T--|]*/ { 2, 1, 1,12, -1, -1}, + /*[|-------------|T-|]*/ { 2, 1, 1,13, -1, -1}, + /*[|--------------|T|]*/ { 2, 1, 1,14, -1, -1}, +}; + +static const int minFrameTranDistance = 4; + +static const FREQ_RES freqRes_table_8[] = {FREQ_RES_LOW, FREQ_RES_LOW, FREQ_RES_LOW, FREQ_RES_LOW, FREQ_RES_LOW, + FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}; + +static const FREQ_RES freqRes_table_16[16] = { + /* size of envelope */ +/* 0-4 */ FREQ_RES_LOW, FREQ_RES_LOW, FREQ_RES_LOW, FREQ_RES_LOW, FREQ_RES_LOW, +/* 5-9 */ FREQ_RES_LOW, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, +/* 10-16 */ FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, + FREQ_RES_HIGH }; + +static void generateFixFixOnly ( HANDLE_SBR_FRAME_INFO hSbrFrameInfo, + HANDLE_SBR_GRID hSbrGrid, + int tranPosInternal, + int numberTimeSlots + ); + + +/*! + Functionname: FDKsbrEnc_frameInfoGenerator + + Description: produces the FRAME_INFO struct for the current frame + + Arguments: hSbrEnvFrame - pointer to sbr envelope handle + v_pre_transient_info - pointer to transient info vector + v_transient_info - pointer to previous transient info vector + v_tuning - pointer to tuning vector + + Return: frame_info - pointer to SBR_FRAME_INFO struct + +*******************************************************************************/ +HANDLE_SBR_FRAME_INFO +FDKsbrEnc_frameInfoGenerator (HANDLE_SBR_ENVELOPE_FRAME hSbrEnvFrame, + UCHAR *v_transient_info, + UCHAR *v_transient_info_pre, + int ldGrid, + const int *v_tuning) +{ + INT numEnv, tranPosInternal=0, bmin=0, bmax=0, parts, d, i_cmon=0, i_tran=0, nL; + INT fmax = 0; + + INT *v_bord = hSbrEnvFrame->v_bord; + INT *v_freq = hSbrEnvFrame->v_freq; + INT *v_bordFollow = hSbrEnvFrame->v_bordFollow; + INT *v_freqFollow = hSbrEnvFrame->v_freqFollow; + + + INT *length_v_bordFollow = &hSbrEnvFrame->length_v_bordFollow; + INT *length_v_freqFollow = &hSbrEnvFrame->length_v_freqFollow; + INT *length_v_bord = &hSbrEnvFrame->length_v_bord; + INT *length_v_freq = &hSbrEnvFrame->length_v_freq; + INT *spreadFlag = &hSbrEnvFrame->spreadFlag; + INT *i_tranFollow = &hSbrEnvFrame->i_tranFollow; + INT *i_fillFollow = &hSbrEnvFrame->i_fillFollow; + FRAME_CLASS *frameClassOld = &hSbrEnvFrame->frameClassOld; + FRAME_CLASS frameClass = FIXFIX; + + + INT allowSpread = hSbrEnvFrame->allowSpread; + INT numEnvStatic = hSbrEnvFrame->numEnvStatic; + INT staticFraming = hSbrEnvFrame->staticFraming; + INT dmin = hSbrEnvFrame->dmin; + INT dmax = hSbrEnvFrame->dmax; + + INT bufferFrameStart = hSbrEnvFrame->SbrGrid.bufferFrameStart; + INT numberTimeSlots = hSbrEnvFrame->SbrGrid.numberTimeSlots; + INT frameMiddleSlot = hSbrEnvFrame->frameMiddleSlot; + + INT tranPos = v_transient_info[0]; + INT tranFlag = v_transient_info[1]; + + const int *v_tuningSegm = v_tuning; + const int *v_tuningFreq = v_tuning + 3; + + hSbrEnvFrame->v_tuningSegm = v_tuningSegm; + INT freq_res_fixfix = hSbrEnvFrame->freq_res_fixfix; + + if (ldGrid) { + /* in case there was a transient at the very end of the previous frame, start with a transient envelope */ + if(v_transient_info_pre[1] && (numberTimeSlots - v_transient_info_pre[0] < minFrameTranDistance)){ + tranFlag = 1; + tranPos = 0; + } + } + + /* + * Synopsis: + * + * The frame generator creates the time-/frequency-grid for one SBR frame. + * Input signals are provided by the transient detector and the frame + * splitter (transientDetectNew() & FrameSplitter() in tran_det.c). The + * framing is controlled by adjusting tuning parameters stored in + * FRAME_GEN_TUNING. The parameter values are dependent on frame lengths + * and bitrates, and may in the future be signal dependent. + * + * The envelope borders are stored for frame generator internal use in + * aBorders. The contents of aBorders represent positions along the time + * axis given in the figures in fram_gen.h (the "frame-generator" rows). + * The unit is "time slot". The figures in fram_gen.h also define the + * detection ranges for the transient detector. For every border in + * aBorders, there is a corresponding entry in aFreqRes, which defines the + * frequency resolution of the envelope following (delimited by) the + * border. + * + * When no transients are present, FIXFIX class frames are used. The + * frame splitter decides whether to use one or two envelopes in the + * FIXFIX frame. "Sparse transients" (separated by a few frames without + * transients) are handeled by [FIXVAR, VARFIX] pairs or (depending on + * tuning and transient position relative the nominal frame boundaries) + * by [FIXVAR, VARVAR, VARFIX] triples. "Tight transients" (in + * consecutive frames) are handeled by [..., VARVAR, VARVAR, ...] + * sequences. + * + * The generator assumes that transients are "sparse", and designs + * borders for [FIXVAR, VARFIX] pairs right away, where the first frame + * corresponds to the present frame. At the next call of the generator + * it is known whether the transient actually is "sparse" or not. If + * 'yes', the already calculated VARFIX borders are used. If 'no', new + * borders, meeting the requirements of the "tight" transient, are + * calculated. + * + * The generator produces two outputs: A "clear-text bitstream" stored in + * SBR_GRID, and a straight-forward representation of the grid stored in + * SBR_FRAME_INFO. The former is subsequently converted to the actual + * bitstream sbr_grid() (encodeSbrGrid() in bit_sbr.c). The latter is + * used by other encoder functions, such as the envelope estimator + * (calculateSbrEnvelope() in env_est.c) and the noise floor and missing + * harmonics detector (TonCorrParamExtr() in nf_est.c). + */ + + if (staticFraming) { + /*-------------------------------------------------------------------------- + Ignore transient detector + ---------------------------------------------------------------------------*/ + + frameClass = FIXFIX; + numEnv = numEnvStatic; /* {1,2,4,8} */ + *frameClassOld = FIXFIX; /* for change to dyn */ + hSbrEnvFrame->SbrGrid.bs_num_env = numEnv; + hSbrEnvFrame->SbrGrid.frameClass = frameClass; + } + else { + /*-------------------------------------------------------------------------- + Calculate frame class to use + ---------------------------------------------------------------------------*/ + calcFrameClass (&frameClass, frameClassOld, tranFlag, spreadFlag); + + /* patch for new frame class FIXFIXonly for AAC LD */ + if (tranFlag && ldGrid) { + frameClass = FIXFIXonly; + *frameClassOld = FIXFIX; + } + + /* + * every transient is processed below by inserting + * + * - one border at the onset of the transient + * - one or more "decay borders" (after the onset of the transient) + * - optionally one "attack border" (before the onset of the transient) + * + * those borders are referred to as "mandatory borders" and are + * defined by the 'segmentLength' array in FRAME_GEN_TUNING + * + * the frequency resolutions of the corresponding envelopes are + * defined by the 'segmentRes' array in FRAME_GEN_TUNING + */ + + /*-------------------------------------------------------------------------- + Design frame (or follow-up old design) + ---------------------------------------------------------------------------*/ + if (tranFlag) { /* Always for FixVar, often but not always for VarVar */ + /*-------------------------------------------------------------------------- + Design part of T/F-grid around the new transient + ---------------------------------------------------------------------------*/ + + tranPosInternal = frameMiddleSlot + tranPos + bufferFrameStart ; /* FH 00-06-26 */ + /* + add mandatory borders around transient + */ + + fillFrameTran ( v_tuningSegm, + v_tuningFreq, + tranPosInternal, + v_bord, + length_v_bord, + v_freq, + length_v_freq, + &bmin, + &bmax ); + + /* make sure we stay within the maximum SBR frame overlap */ + fmax = calcFillLengthMax(tranPos, numberTimeSlots); + } + + switch (frameClass) { + + case FIXFIXonly: + FDK_ASSERT(ldGrid); + tranPosInternal = tranPos; + generateFixFixOnly ( &(hSbrEnvFrame->SbrFrameInfo), + &(hSbrEnvFrame->SbrGrid), + tranPosInternal, + numberTimeSlots + ); + + return &(hSbrEnvFrame->SbrFrameInfo); + + case FIXVAR: + + /*-------------------------------------------------------------------------- + Design remaining parts of T/F-grid (assuming next frame is VarFix) + ---------------------------------------------------------------------------*/ + + /*-------------------------------------------------------------------------- + Fill region before new transient: + ---------------------------------------------------------------------------*/ + fillFramePre (dmax, v_bord, length_v_bord, v_freq, length_v_freq, + bmin, bmin - bufferFrameStart); /* FH 00-06-26 */ + + /*-------------------------------------------------------------------------- + Fill region after new transient: + ---------------------------------------------------------------------------*/ + fillFramePost (&parts, &d, dmax, v_bord, length_v_bord, v_freq, + length_v_freq, bmax, bufferFrameStart, numberTimeSlots, fmax); + + /*-------------------------------------------------------------------------- + Take care of special case: + ---------------------------------------------------------------------------*/ + if (parts == 1 && d < dmin) /* no fill, short last envelope */ + specialCase (spreadFlag, allowSpread, v_bord, length_v_bord, + v_freq, length_v_freq, &parts, d); + + /*-------------------------------------------------------------------------- + Calculate common border (split-point) + ---------------------------------------------------------------------------*/ + calcCmonBorder (&i_cmon, &i_tran, v_bord, length_v_bord, tranPosInternal, + bufferFrameStart, numberTimeSlots); /* FH 00-06-26 */ + + /*-------------------------------------------------------------------------- + Extract data for proper follow-up in next frame + ---------------------------------------------------------------------------*/ + keepForFollowUp (v_bordFollow, length_v_bordFollow, v_freqFollow, + length_v_freqFollow, i_tranFollow, i_fillFollow, + v_bord, length_v_bord, v_freq, i_cmon, i_tran, parts, numberTimeSlots); /* FH 00-06-26 */ + + /*-------------------------------------------------------------------------- + Calculate control signal + ---------------------------------------------------------------------------*/ + calcCtrlSignal (&hSbrEnvFrame->SbrGrid, frameClass, + v_bord, *length_v_bord, v_freq, *length_v_freq, + i_cmon, i_tran, *spreadFlag, DC); + break; + case VARFIX: + /*-------------------------------------------------------------------------- + Follow-up old transient - calculate control signal + ---------------------------------------------------------------------------*/ + calcCtrlSignal (&hSbrEnvFrame->SbrGrid, frameClass, + v_bordFollow, *length_v_bordFollow, v_freqFollow, + *length_v_freqFollow, DC, *i_tranFollow, + *spreadFlag, DC); + break; + case VARVAR: + if (*spreadFlag) { /* spread across three frames */ + /*-------------------------------------------------------------------------- + Follow-up old transient - calculate control signal + ---------------------------------------------------------------------------*/ + calcCtrlSignal (&hSbrEnvFrame->SbrGrid, + frameClass, v_bordFollow, *length_v_bordFollow, + v_freqFollow, *length_v_freqFollow, DC, + *i_tranFollow, *spreadFlag, DC); + + *spreadFlag = 0; + + /*-------------------------------------------------------------------------- + Extract data for proper follow-up in next frame + ---------------------------------------------------------------------------*/ + v_bordFollow[0] = hSbrEnvFrame->SbrGrid.bs_abs_bord_1 - numberTimeSlots; /* FH 00-06-26 */ + v_freqFollow[0] = 1; + *length_v_bordFollow = 1; + *length_v_freqFollow = 1; + + *i_tranFollow = -DC; + *i_fillFollow = -DC; + } + else { + /*-------------------------------------------------------------------------- + Design remaining parts of T/F-grid (assuming next frame is VarFix) + adapt or fill region before new transient: + ---------------------------------------------------------------------------*/ + fillFrameInter (&nL, v_tuningSegm, v_bord, length_v_bord, bmin, + v_freq, length_v_freq, v_bordFollow, + length_v_bordFollow, v_freqFollow, + length_v_freqFollow, *i_fillFollow, dmin, dmax, + numberTimeSlots); + + /*-------------------------------------------------------------------------- + Fill after transient: + ---------------------------------------------------------------------------*/ + fillFramePost (&parts, &d, dmax, v_bord, length_v_bord, v_freq, + length_v_freq, bmax, bufferFrameStart, numberTimeSlots, fmax); + + /*-------------------------------------------------------------------------- + Take care of special case: + ---------------------------------------------------------------------------*/ + if (parts == 1 && d < dmin) /*% no fill, short last envelope */ + specialCase (spreadFlag, allowSpread, v_bord, length_v_bord, + v_freq, length_v_freq, &parts, d); + + /*-------------------------------------------------------------------------- + Calculate common border (split-point) + ---------------------------------------------------------------------------*/ + calcCmonBorder (&i_cmon, &i_tran, v_bord, length_v_bord, tranPosInternal, + bufferFrameStart, numberTimeSlots); + + /*-------------------------------------------------------------------------- + Extract data for proper follow-up in next frame + ---------------------------------------------------------------------------*/ + keepForFollowUp (v_bordFollow, length_v_bordFollow, + v_freqFollow, length_v_freqFollow, + i_tranFollow, i_fillFollow, v_bord, + length_v_bord, v_freq, i_cmon, i_tran, parts, numberTimeSlots); + + /*-------------------------------------------------------------------------- + Calculate control signal + ---------------------------------------------------------------------------*/ + calcCtrlSignal (&hSbrEnvFrame->SbrGrid, + frameClass, v_bord, *length_v_bord, v_freq, + *length_v_freq, i_cmon, i_tran, 0, nL); + } + break; + case FIXFIX: + if (tranPos == 0) + numEnv = 1; + else + numEnv = 2; + + hSbrEnvFrame->SbrGrid.bs_num_env = numEnv; + hSbrEnvFrame->SbrGrid.frameClass = frameClass; + + break; + default: + FDK_ASSERT(0); + } + } + + /*------------------------------------------------------------------------- + Convert control signal to frame info struct + ---------------------------------------------------------------------------*/ + ctrlSignal2FrameInfo (&hSbrEnvFrame->SbrGrid, + &hSbrEnvFrame->SbrFrameInfo, + freq_res_fixfix); + + return &hSbrEnvFrame->SbrFrameInfo; +} + + +/***************************************************************************/ +/*! + \brief Gnerates frame info for FIXFIXonly frame class used for low delay version + + \return nothing + ****************************************************************************/ +static void generateFixFixOnly ( HANDLE_SBR_FRAME_INFO hSbrFrameInfo, + HANDLE_SBR_GRID hSbrGrid, + int tranPosInternal, + int numberTimeSlots + ) +{ + int nEnv, i, k=0, tranIdx; + const int *pTable = NULL; + const FREQ_RES *freqResTable = NULL; + + switch (numberTimeSlots) { + case 8: + pTable = envelopeTable_8[tranPosInternal]; + freqResTable = freqRes_table_8; + break; + case 15: + pTable = envelopeTable_15[tranPosInternal]; + freqResTable = freqRes_table_16; + break; + case 16: + pTable = envelopeTable_16[tranPosInternal]; + freqResTable = freqRes_table_16; + break; + } + + /* look number of envolpes in table */ + nEnv = pTable[0]; + /* look up envolpe distribution in table */ + for (i=1; iborders[i] = pTable[i+2]; + + /* open and close frame border */ + hSbrFrameInfo->borders[0] = 0; + hSbrFrameInfo->borders[nEnv] = numberTimeSlots; + + /* adjust segment-frequency-resolution according to the segment-length */ + for (i=0; iborders[i+1] - hSbrFrameInfo->borders[i]; + hSbrFrameInfo->freqRes[i] = freqResTable[k]; + //hSbrFrameInfo->freqRes[i] = (k < tuning.minEnvSize4highRes) ? FREQ_RES_LOW : FREQ_RES_HIGH; + hSbrGrid->v_f[i] = freqResTable[k]; + } + + hSbrFrameInfo->nEnvelopes = nEnv; + hSbrFrameInfo->shortEnv = pTable[2]; + /* transient idx */ + tranIdx = pTable[1]; + + /* add noise floors */ + hSbrFrameInfo->bordersNoise[0] = 0; + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[tranIdx?tranIdx:1]; + hSbrFrameInfo->bordersNoise[2] = numberTimeSlots; + hSbrFrameInfo->nNoiseEnvelopes = 2; + + hSbrGrid->frameClass = FIXFIXonly; + hSbrGrid->bs_abs_bord = tranPosInternal; + hSbrGrid->bs_num_env = nEnv; + +} + + + +/******************************************************************************* + Functionname: FDKsbrEnc_initFrameInfoGenerator + ******************************************************************************* + + Description: + + Arguments: hSbrEnvFrame - pointer to sbr envelope handle + allowSpread - commandline parameter + numEnvStatic - commandline parameter + staticFraming - commandline parameter + + Return: none + +*******************************************************************************/ +void +FDKsbrEnc_initFrameInfoGenerator (HANDLE_SBR_ENVELOPE_FRAME hSbrEnvFrame, + INT allowSpread, + INT numEnvStatic, + INT staticFraming, + INT timeSlots, + INT freq_res_fixfix + ,int ldGrid + ) + +{ /* FH 00-06-26 */ + + FDKmemclear(hSbrEnvFrame,sizeof(SBR_ENVELOPE_FRAME )); + + + /* Initialisation */ + hSbrEnvFrame->frameClassOld = FIXFIX; + hSbrEnvFrame->spreadFlag = 0; + + hSbrEnvFrame->allowSpread = allowSpread; + hSbrEnvFrame->numEnvStatic = numEnvStatic; + hSbrEnvFrame->staticFraming = staticFraming; + hSbrEnvFrame->freq_res_fixfix = freq_res_fixfix; + + hSbrEnvFrame->length_v_bord = 0; + hSbrEnvFrame->length_v_bordFollow = 0; + + hSbrEnvFrame->length_v_freq = 0; + hSbrEnvFrame->length_v_freqFollow = 0; + + hSbrEnvFrame->i_tranFollow = 0; + hSbrEnvFrame->i_fillFollow = 0; + + hSbrEnvFrame->SbrGrid.numberTimeSlots = timeSlots; + + if (ldGrid) { + /*case CODEC_AACLD:*/ + hSbrEnvFrame->dmin = 2; + hSbrEnvFrame->dmax = 16; + hSbrEnvFrame->frameMiddleSlot = FRAME_MIDDLE_SLOT_512LD; + /* + hSbrEnvFrame->v_tuningSegm[0] = 0; + hSbrEnvFrame->v_tuningSegm[1] = 2; + hSbrEnvFrame->v_tuningSegm[2] = 3; + */ + /*break;*/ + } else + switch(timeSlots){ + case NUMBER_TIME_SLOTS_1920: + hSbrEnvFrame->dmin = 4; + hSbrEnvFrame->dmax = 12; + hSbrEnvFrame->SbrGrid.bufferFrameStart = 0; + hSbrEnvFrame->frameMiddleSlot = FRAME_MIDDLE_SLOT_1920; + break; + case NUMBER_TIME_SLOTS_2048: + hSbrEnvFrame->dmin = 4; + hSbrEnvFrame->dmax = 12; + hSbrEnvFrame->SbrGrid.bufferFrameStart = 0; + hSbrEnvFrame->frameMiddleSlot = FRAME_MIDDLE_SLOT_2048; + break; + case NUMBER_TIME_SLOTS_1152: + hSbrEnvFrame->dmin = 2; + hSbrEnvFrame->dmax = 8; + hSbrEnvFrame->SbrGrid.bufferFrameStart = 0; + hSbrEnvFrame->frameMiddleSlot = FRAME_MIDDLE_SLOT_1152; + break; + case NUMBER_TIME_SLOTS_2304: + hSbrEnvFrame->dmin = 4; + hSbrEnvFrame->dmax = 15; + hSbrEnvFrame->SbrGrid.bufferFrameStart = 0; + hSbrEnvFrame->frameMiddleSlot = FRAME_MIDDLE_SLOT_2304; + break; + default: + FDK_ASSERT(0); + } + +} + + +/******************************************************************************* + Functionname: deleteFrameInfoGenerator + ******************************************************************************* + + Description: + + Arguments: hSbrEnvFrame - HANDLE_SBR_ENVELOPE_FRAME + + Return: none + +*******************************************************************************/ + + +/******************************************************************************* + Functionname: fillFrameTran + ******************************************************************************* + + Description: Add mandatory borders, as described by the tuning vector + and the current transient position + + Arguments: + modified: + v_bord - int pointer to v_bord vector + length_v_bord - length of v_bord vector + v_freq - int pointer to v_freq vector + length_v_freq - length of v_freq vector + bmin - int pointer to bmin (call by reference) + bmax - int pointer to bmax (call by reference) + not modified: + tran - position of transient + v_tuningSegm - int pointer to v_tuningSegm vector + v_tuningFreq - int pointer to v_tuningFreq vector + + Return: none + +*******************************************************************************/ +static void +fillFrameTran (const int *v_tuningSegm, /*!< tuning: desired segment lengths */ + const int *v_tuningFreq, /*!< tuning: desired frequency resolutions */ + int tran, /*!< input : position of transient */ + int *v_bord, /*!< memNew: borders */ + int *length_v_bord, /*!< memNew: # borders */ + int *v_freq, /*!< memNew: frequency resolutions */ + int *length_v_freq, /*!< memNew: # frequency resolutions */ + int *bmin, /*!< hlpNew: first mandatory border */ + int *bmax /*!< hlpNew: last mandatory border */ + ) +{ + int bord, i; + + *length_v_bord = 0; + *length_v_freq = 0; + + /* add attack env leading border (optional) */ + if (v_tuningSegm[0]) { + /* v_bord = [(Ba)] start of attack env */ + FDKsbrEnc_AddRight (v_bord, length_v_bord, (tran - v_tuningSegm[0])); + + /* v_freq = [(Fa)] res of attack env */ + FDKsbrEnc_AddRight (v_freq, length_v_freq, v_tuningFreq[0]); + } + + /* add attack env trailing border/first decay env leading border */ + bord = tran; + FDKsbrEnc_AddRight (v_bord, length_v_bord, tran); /* v_bord = [(Ba),Bd1] */ + + /* add first decay env trailing border/2:nd decay env leading border */ + if (v_tuningSegm[1]) { + bord += v_tuningSegm[1]; + + /* v_bord = [(Ba),Bd1,Bd2] */ + FDKsbrEnc_AddRight (v_bord, length_v_bord, bord); + + /* v_freq = [(Fa),Fd1] */ + FDKsbrEnc_AddRight (v_freq, length_v_freq, v_tuningFreq[1]); + } + + /* add 2:nd decay env trailing border (optional) */ + if (v_tuningSegm[2] != 0) { + bord += v_tuningSegm[2]; + + /* v_bord = [(Ba),Bd1, Bd2,(Bd3)] */ + FDKsbrEnc_AddRight (v_bord, length_v_bord, bord); + + /* v_freq = [(Fa),Fd1,(Fd2)] */ + FDKsbrEnc_AddRight (v_freq, length_v_freq, v_tuningFreq[2]); + } + + /* v_freq = [(Fa),Fd1,(Fd2),1] */ + FDKsbrEnc_AddRight (v_freq, length_v_freq, 1); + + + /* calc min and max values of mandatory borders */ + *bmin = v_bord[0]; + for (i = 0; i < *length_v_bord; i++) + if (v_bord[i] < *bmin) + *bmin = v_bord[i]; + + *bmax = v_bord[0]; + for (i = 0; i < *length_v_bord; i++) + if (v_bord[i] > *bmax) + *bmax = v_bord[i]; + +} + + + +/******************************************************************************* + Functionname: fillFramePre + ******************************************************************************* + + Description: Add borders before mandatory borders, if needed + + Arguments: + modified: + v_bord - int pointer to v_bord vector + length_v_bord - length of v_bord vector + v_freq - int pointer to v_freq vector + length_v_freq - length of v_freq vector + not modified: + dmax - int value + bmin - int value + rest - int value + + Return: none + +*******************************************************************************/ +static void +fillFramePre (INT dmax, + INT *v_bord, INT *length_v_bord, + INT *v_freq, INT *length_v_freq, + INT bmin, INT rest) +{ + /* + input state: + v_bord = [(Ba),Bd1, Bd2 ,(Bd3)] + v_freq = [(Fa),Fd1,(Fd2),1 ] + */ + + INT parts, d, j, S, s = 0, segm, bord; + + /* + start with one envelope + */ + + parts = 1; + d = rest; + + /* + calc # of additional envelopes and corresponding lengths + */ + + while (d > dmax) { + parts++; + + segm = rest / parts; + S = (segm - 2)>>1; + s = fixMin (8, 2 * S + 2); + d = rest - (parts - 1) * s; + } + + /* + add borders before mandatory borders + */ + + bord = bmin; + + for (j = 0; j <= parts - 2; j++) { + bord = bord - s; + + /* v_bord = [...,(Bf),(Ba),Bd1, Bd2 ,(Bd3)] */ + FDKsbrEnc_AddLeft (v_bord, length_v_bord, bord); + + /* v_freq = [...,(1 ),(Fa),Fd1,(Fd2), 1 ] */ + FDKsbrEnc_AddLeft (v_freq, length_v_freq, 1); + } +} + +/***************************************************************************/ +/*! + \brief Overlap control + + Calculate max length of trailing fill segments, such that we always get a + border within the frame overlap region + + \return void + +****************************************************************************/ +static int +calcFillLengthMax (int tranPos, /*!< input : transient position (ref: tran det) */ + int numberTimeSlots /*!< input : number of timeslots */ + ) +{ + int fmax; + + /* + calculate transient position within envelope buffer + */ + switch (numberTimeSlots) + { + case NUMBER_TIME_SLOTS_2048: + if (tranPos < 4) + fmax = 6; + else if (tranPos == 4 || tranPos == 5) + fmax = 4; + else + fmax = 8; + break; + + case NUMBER_TIME_SLOTS_1920: + if (tranPos < 4) + fmax = 5; + else if (tranPos == 4 || tranPos == 5) + fmax = 3; + else + fmax = 7; + break; + + default: + fmax = 8; + break; + } + + return fmax; +} + +/******************************************************************************* + Functionname: fillFramePost + ******************************************************************************* + + Description: -Add borders after mandatory borders, if needed + Make a preliminary design of next frame, + assuming no transient is present there + + Arguments: + modified: + parts - int pointer to parts (call by reference) + d - int pointer to d (call by reference) + v_bord - int pointer to v_bord vector + length_v_bord - length of v_bord vector + v_freq - int pointer to v_freq vector + length_v_freq - length of v_freq vector + not modified: + bmax - int value + dmax - int value + + Return: none + +*******************************************************************************/ +static void +fillFramePost (INT *parts, INT *d, INT dmax, INT *v_bord, INT *length_v_bord, + INT *v_freq, INT *length_v_freq, INT bmax, + INT bufferFrameStart, INT numberTimeSlots, INT fmax) +{ + INT j, rest, segm, S, s = 0, bord; + + /* + input state: + v_bord = [...,(Bf),(Ba),Bd1, Bd2 ,(Bd3)] + v_freq = [...,(1 ),(Fa),Fd1,(Fd2),1 ] + */ + + rest = bufferFrameStart + 2 * numberTimeSlots - bmax; + *d = rest; + + if (*d > 0) { + *parts = 1; /* start with one envelope */ + + /* calc # of additional envelopes and corresponding lengths */ + + while (*d > dmax) { + *parts = *parts + 1; + + segm = rest / (*parts); + S = (segm - 2)>>1; + s = fixMin (fmax, 2 * S + 2); + *d = rest - (*parts - 1) * s; + } + + /* add borders after mandatory borders */ + + bord = bmax; + for (j = 0; j <= *parts - 2; j++) { + bord += s; + + /* v_bord = [...,(Bf),(Ba),Bd1, Bd2 ,(Bd3),(Bf)] */ + FDKsbrEnc_AddRight (v_bord, length_v_bord, bord); + + /* v_freq = [...,(1 ),(Fa),Fd1,(Fd2), 1 , 1! ,1] */ + FDKsbrEnc_AddRight (v_freq, length_v_freq, 1); + } + } + else { + *parts = 1; + + /* remove last element from v_bord and v_freq */ + + *length_v_bord = *length_v_bord - 1; + *length_v_freq = *length_v_freq - 1; + + } +} + + + +/******************************************************************************* + Functionname: fillFrameInter + ******************************************************************************* + + Description: + + Arguments: nL - + v_tuningSegm - + v_bord - + length_v_bord - + bmin - + v_freq - + length_v_freq - + v_bordFollow - + length_v_bordFollow - + v_freqFollow - + length_v_freqFollow - + i_fillFollow - + dmin - + dmax - + + Return: none + +*******************************************************************************/ +static void +fillFrameInter (INT *nL, const int *v_tuningSegm, INT *v_bord, INT *length_v_bord, + INT bmin, INT *v_freq, INT *length_v_freq, INT *v_bordFollow, + INT *length_v_bordFollow, INT *v_freqFollow, + INT *length_v_freqFollow, INT i_fillFollow, INT dmin, + INT dmax, INT numberTimeSlots) +{ + INT middle, b_new, numBordFollow, bordMaxFollow, i; + + if (numberTimeSlots != NUMBER_TIME_SLOTS_1152) { + + /* % remove fill borders: */ + if (i_fillFollow >= 1) { + *length_v_bordFollow = i_fillFollow; + *length_v_freqFollow = i_fillFollow; + } + + numBordFollow = *length_v_bordFollow; + bordMaxFollow = v_bordFollow[numBordFollow - 1]; + + /* remove even more borders if needed */ + middle = bmin - bordMaxFollow; + while (middle < 0) { + numBordFollow--; + bordMaxFollow = v_bordFollow[numBordFollow - 1]; + middle = bmin - bordMaxFollow; + } + + *length_v_bordFollow = numBordFollow; + *length_v_freqFollow = numBordFollow; + *nL = numBordFollow - 1; + + b_new = *length_v_bord; + + + if (middle <= dmax) { + if (middle >= dmin) { /* concatenate */ + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, *length_v_bordFollow); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, *length_v_freqFollow); + } + + else { + if (v_tuningSegm[0] != 0) { /* remove one new border and concatenate */ + *length_v_bord = b_new - 1; + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + + *length_v_freq = b_new - 1; + FDKsbrEnc_AddVecLeft (v_freq + 1, length_v_freq, v_freqFollow, + *length_v_freqFollow); + } + else { + if (*length_v_bordFollow > 1) { /* remove one old border and concatenate */ + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow - 1); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, + *length_v_bordFollow - 1); + + *nL = *nL - 1; + } + else { /* remove new "transient" border and concatenate */ + + for (i = 0; i < *length_v_bord - 1; i++) + v_bord[i] = v_bord[i + 1]; + + for (i = 0; i < *length_v_freq - 1; i++) + v_freq[i] = v_freq[i + 1]; + + *length_v_bord = b_new - 1; + *length_v_freq = b_new - 1; + + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, + *length_v_freqFollow); + } + } + } + } + else { /* middle > dmax */ + + fillFramePre (dmax, v_bord, length_v_bord, v_freq, length_v_freq, bmin, + middle); + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, *length_v_bordFollow); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, *length_v_freqFollow); + } + + + } + else { /* numberTimeSlots==NUMBER_TIME_SLOTS_1152 */ + + INT l,m; + + + /*------------------------------------------------------------------------ + remove fill borders + ------------------------------------------------------------------------*/ + if (i_fillFollow >= 1) { + *length_v_bordFollow = i_fillFollow; + *length_v_freqFollow = i_fillFollow; + } + + numBordFollow = *length_v_bordFollow; + bordMaxFollow = v_bordFollow[numBordFollow - 1]; + + /*------------------------------------------------------------------------ + remove more borders if necessary to eliminate overlap + ------------------------------------------------------------------------*/ + + /* check for overlap */ + middle = bmin - bordMaxFollow; + + /* intervals: + i) middle < 0 : overlap, must remove borders + ii) 0 <= middle < dmin : no overlap but too tight, must remove borders + iii) dmin <= middle <= dmax : ok, just concatenate + iv) dmax <= middle : too wide, must add borders + */ + + /* first remove old non-fill-borders... */ + while (middle < 0) { + + /* ...but don't remove all of them */ + if (numBordFollow == 1) + break; + + numBordFollow--; + bordMaxFollow = v_bordFollow[numBordFollow - 1]; + middle = bmin - bordMaxFollow; + } + + /* if this isn't enough, remove new non-fill borders */ + if (middle < 0) + { + for (l = 0, m = 0 ; l < *length_v_bord ; l++) + { + if(v_bord[l]> bordMaxFollow) + { + v_bord[m] = v_bord[l]; + v_freq[m] = v_freq[l]; + m++; + } + } + + *length_v_bord = l; + *length_v_freq = l; + + bmin = v_bord[0]; + + } + + /*------------------------------------------------------------------------ + update modified follow-up data + ------------------------------------------------------------------------*/ + + *length_v_bordFollow = numBordFollow; + *length_v_freqFollow = numBordFollow; + + /* left relative borders correspond to follow-up */ + *nL = numBordFollow - 1; + + /*------------------------------------------------------------------------ + take care of intervals ii through iv + ------------------------------------------------------------------------*/ + + /* now middle should be >= 0 */ + middle = bmin - bordMaxFollow; + + if (middle <= dmin) /* (ii) */ + { + b_new = *length_v_bord; + + if (v_tuningSegm[0] != 0) + { + /* remove new "luxury" border and concatenate */ + *length_v_bord = b_new - 1; + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + + *length_v_freq = b_new - 1; + FDKsbrEnc_AddVecLeft (v_freq + 1, length_v_freq, v_freqFollow, + *length_v_freqFollow); + + } + else if (*length_v_bordFollow > 1) + { + /* remove old border and concatenate */ + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow - 1); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, + *length_v_bordFollow - 1); + + *nL = *nL - 1; + } + else + { + /* remove new border and concatenate */ + for (i = 0; i < *length_v_bord - 1; i++) + v_bord[i] = v_bord[i + 1]; + + for (i = 0; i < *length_v_freq - 1; i++) + v_freq[i] = v_freq[i + 1]; + + *length_v_bord = b_new - 1; + *length_v_freq = b_new - 1; + + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, + *length_v_freqFollow); + } + } + else if ((middle >= dmin) && (middle <= dmax)) /* (iii) */ + { + /* concatenate */ + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, *length_v_bordFollow); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, *length_v_freqFollow); + + } + else /* (iv) */ + { + fillFramePre (dmax, v_bord, length_v_bord, v_freq, length_v_freq, bmin, + middle); + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, *length_v_bordFollow); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, *length_v_freqFollow); + } + } +} + + + +/******************************************************************************* + Functionname: calcFrameClass + ******************************************************************************* + + Description: + + Arguments: INT* frameClass, INT* frameClassOld, INT tranFlag, INT* spreadFlag) + + Return: none + +*******************************************************************************/ +static void +calcFrameClass (FRAME_CLASS *frameClass, FRAME_CLASS *frameClassOld, INT tranFlag, + INT *spreadFlag) +{ + + switch (*frameClassOld) { + case FIXFIXonly: + case FIXFIX: + if (tranFlag) *frameClass = FIXVAR; + else *frameClass = FIXFIX; + break; + case FIXVAR: + if (tranFlag) { *frameClass = VARVAR; *spreadFlag = 0; } + else { + if (*spreadFlag) *frameClass = VARVAR; + else *frameClass = VARFIX; + } + break; + case VARFIX: + if (tranFlag) *frameClass = FIXVAR; + else *frameClass = FIXFIX; + break; + case VARVAR: + if (tranFlag) { *frameClass = VARVAR; *spreadFlag = 0; } + else { + if (*spreadFlag) *frameClass = VARVAR; + else *frameClass = VARFIX; + } + break; + }; + + *frameClassOld = *frameClass; +} + + + +/******************************************************************************* + Functionname: specialCase + ******************************************************************************* + + Description: + + Arguments: spreadFlag + allowSpread + v_bord + length_v_bord + v_freq + length_v_freq + parts + d + + Return: none + +*******************************************************************************/ +static void +specialCase (INT *spreadFlag, INT allowSpread, INT *v_bord, + INT *length_v_bord, INT *v_freq, INT *length_v_freq, INT *parts, + INT d) +{ + INT L; + + L = *length_v_bord; + + if (allowSpread) { /* add one "step 8" */ + *spreadFlag = 1; + FDKsbrEnc_AddRight (v_bord, length_v_bord, v_bord[L - 1] + 8); + FDKsbrEnc_AddRight (v_freq, length_v_freq, 1); + (*parts)++; + } + else { + if (d == 1) { /* stretch one slot */ + *length_v_bord = L - 1; + *length_v_freq = L - 1; + } + else { + if ((v_bord[L - 1] - v_bord[L - 2]) > 2) { /* compress one quant step */ + v_bord[L - 1] = v_bord[L - 1] - 2; + v_freq[*length_v_freq - 1] = 0; /* use low res for short segment */ + } + } + } +} + + + +/******************************************************************************* + Functionname: calcCmonBorder + ******************************************************************************* + + Description: + + Arguments: i_cmon + i_tran + v_bord + length_v_bord + tran + + Return: none + +*******************************************************************************/ +static void +calcCmonBorder (INT *i_cmon, INT *i_tran, INT *v_bord, INT *length_v_bord, + INT tran, INT bufferFrameStart, INT numberTimeSlots) +{ /* FH 00-06-26 */ + INT i; + + for (i = 0; i < *length_v_bord; i++) + if (v_bord[i] >= bufferFrameStart + numberTimeSlots) { /* FH 00-06-26 */ + *i_cmon = i; + break; + } + + /* keep track of transient: */ + for (i = 0; i < *length_v_bord; i++) + if (v_bord[i] >= tran) { + *i_tran = i; + break; + } + else + *i_tran = EMPTY; +} + +/******************************************************************************* + Functionname: keepForFollowUp + ******************************************************************************* + + Description: + + Arguments: v_bordFollow + length_v_bordFollow + v_freqFollow + length_v_freqFollow + i_tranFollow + i_fillFollow + v_bord + length_v_bord + v_freq + i_cmon + i_tran + parts) + + Return: none + +*******************************************************************************/ +static void +keepForFollowUp (INT *v_bordFollow, INT *length_v_bordFollow, + INT *v_freqFollow, INT *length_v_freqFollow, + INT *i_tranFollow, INT *i_fillFollow, INT *v_bord, + INT *length_v_bord, INT *v_freq, INT i_cmon, INT i_tran, + INT parts, INT numberTimeSlots) +{ /* FH 00-06-26 */ + INT L, i, j; + + L = *length_v_bord; + + (*length_v_bordFollow) = 0; + (*length_v_freqFollow) = 0; + + for (j = 0, i = i_cmon; i < L; i++, j++) { + v_bordFollow[j] = v_bord[i] - numberTimeSlots; /* FH 00-06-26 */ + v_freqFollow[j] = v_freq[i]; + (*length_v_bordFollow)++; + (*length_v_freqFollow)++; + } + if (i_tran != EMPTY) + *i_tranFollow = i_tran - i_cmon; + else + *i_tranFollow = EMPTY; + *i_fillFollow = L - (parts - 1) - i_cmon; + +} + +/******************************************************************************* + Functionname: calcCtrlSignal + ******************************************************************************* + + Description: + + Arguments: hSbrGrid + frameClass + v_bord + length_v_bord + v_freq + length_v_freq + i_cmon + i_tran + spreadFlag + nL + + Return: none + +*******************************************************************************/ +static void +calcCtrlSignal (HANDLE_SBR_GRID hSbrGrid, + FRAME_CLASS frameClass, INT *v_bord, INT length_v_bord, INT *v_freq, + INT length_v_freq, INT i_cmon, INT i_tran, INT spreadFlag, + INT nL) +{ + + + INT i, r, a, n, p, b, aL, aR, ntot, nmax, nR; + + INT *v_f = hSbrGrid->v_f; + INT *v_fLR = hSbrGrid->v_fLR; + INT *v_r = hSbrGrid->bs_rel_bord; + INT *v_rL = hSbrGrid->bs_rel_bord_0; + INT *v_rR = hSbrGrid->bs_rel_bord_1; + + INT length_v_r = 0; + INT length_v_rR = 0; + INT length_v_rL = 0; + + switch (frameClass) { + case FIXVAR: + /* absolute border: */ + + a = v_bord[i_cmon]; + + /* relative borders: */ + length_v_r = 0; + i = i_cmon; + + while (i >= 1) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight (v_r, &length_v_r, r); + i--; + } + + + /* number of relative borders: */ + n = length_v_r; + + + /* freq res: */ + for (i = 0; i < i_cmon; i++) + v_f[i] = v_freq[i_cmon - 1 - i]; + v_f[i_cmon] = 1; + + /* pointer: */ + p = (i_cmon >= i_tran && i_tran != EMPTY) ? (i_cmon - i_tran + 1) : (0) ; + + hSbrGrid->frameClass = frameClass; + hSbrGrid->bs_abs_bord = a; + hSbrGrid->n = n; + hSbrGrid->p = p; + + break; + case VARFIX: + /* absolute border: */ + a = v_bord[0]; + + /* relative borders: */ + length_v_r = 0; + + for (i = 1; i < length_v_bord; i++) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight (v_r, &length_v_r, r); + } + + /* number of relative borders: */ + n = length_v_r; + + /* freq res: */ + FDKmemcpy (v_f, v_freq, length_v_freq * sizeof (INT)); + + + /* pointer: */ + p = (i_tran >= 0 && i_tran != EMPTY) ? (i_tran + 1) : (0) ; + + hSbrGrid->frameClass = frameClass; + hSbrGrid->bs_abs_bord = a; + hSbrGrid->n = n; + hSbrGrid->p = p; + + break; + case VARVAR: + if (spreadFlag) { + /* absolute borders: */ + b = length_v_bord; + + aL = v_bord[0]; + aR = v_bord[b - 1]; + + + /* number of relative borders: */ + ntot = b - 2; + + nmax = 2; /* n: {0,1,2} */ + if (ntot > nmax) { + nL = nmax; + nR = ntot - nmax; + } + else { + nL = ntot; + nR = 0; + } + + /* relative borders: */ + length_v_rL = 0; + for (i = 1; i <= nL; i++) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight (v_rL, &length_v_rL, r); + } + + length_v_rR = 0; + i = b - 1; + while (i >= b - nR) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight (v_rR, &length_v_rR, r); + i--; + } + + /* pointer (only one due to constraint in frame info): */ + p = (i_tran > 0 && i_tran != EMPTY) ? (b - i_tran) : (0) ; + + /* freq res: */ + + for (i = 0; i < b - 1; i++) + v_fLR[i] = v_freq[i]; + } + else { + + length_v_bord = i_cmon + 1; + length_v_freq = i_cmon + 1; + + + /* absolute borders: */ + b = length_v_bord; + + aL = v_bord[0]; + aR = v_bord[b - 1]; + + /* number of relative borders: */ + ntot = b - 2; + nR = ntot - nL; + + /* relative borders: */ + length_v_rL = 0; + for (i = 1; i <= nL; i++) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight (v_rL, &length_v_rL, r); + } + + length_v_rR = 0; + i = b - 1; + while (i >= b - nR) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight (v_rR, &length_v_rR, r); + i--; + } + + /* pointer (only one due to constraint in frame info): */ + p = (i_cmon >= i_tran && i_tran != EMPTY) ? (i_cmon - i_tran + 1) : (0) ; + + /* freq res: */ + for (i = 0; i < b - 1; i++) + v_fLR[i] = v_freq[i]; + } + + hSbrGrid->frameClass = frameClass; + hSbrGrid->bs_abs_bord_0 = aL; + hSbrGrid->bs_abs_bord_1 = aR; + hSbrGrid->bs_num_rel_0 = nL; + hSbrGrid->bs_num_rel_1 = nR; + hSbrGrid->p = p; + + break; + + default: + /* do nothing */ + break; + } +} + +/******************************************************************************* + Functionname: createDefFrameInfo + ******************************************************************************* + + Description: Copies the default (static) frameInfo structs to the frameInfo + passed by reference; only used for FIXFIX frames + + Arguments: hFrameInfo - HANLDE_SBR_FRAME_INFO + nEnv - INT + nTimeSlots - INT + + Return: none; hSbrFrameInfo contains a copy of the default frameInfo + + Written: 2002/02/05 Andreas Schneider, CT + Revised: +*******************************************************************************/ +static void +createDefFrameInfo(HANDLE_SBR_FRAME_INFO hSbrFrameInfo, INT nEnv, INT nTimeSlots) +{ + switch (nEnv) { + case 1: + switch (nTimeSlots) { + case NUMBER_TIME_SLOTS_1920: + FDKmemcpy (hSbrFrameInfo, &frameInfo1_1920, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2048: + FDKmemcpy (hSbrFrameInfo, &frameInfo1_2048, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_1152: + FDKmemcpy (hSbrFrameInfo, &frameInfo1_1152, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2304: + FDKmemcpy (hSbrFrameInfo, &frameInfo1_2304, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_512LD: + FDKmemcpy (hSbrFrameInfo, &frameInfo1_512LD, sizeof (SBR_FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; + case 2: + switch (nTimeSlots) { + case NUMBER_TIME_SLOTS_1920: + FDKmemcpy (hSbrFrameInfo, &frameInfo2_1920, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2048: + FDKmemcpy (hSbrFrameInfo, &frameInfo2_2048, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_1152: + FDKmemcpy (hSbrFrameInfo, &frameInfo2_1152, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2304: + FDKmemcpy (hSbrFrameInfo, &frameInfo2_2304, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_512LD: + FDKmemcpy (hSbrFrameInfo, &frameInfo2_512LD, sizeof (SBR_FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; + case 4: + switch (nTimeSlots) { + case NUMBER_TIME_SLOTS_1920: + FDKmemcpy (hSbrFrameInfo, &frameInfo4_1920, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2048: + FDKmemcpy (hSbrFrameInfo, &frameInfo4_2048, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_1152: + FDKmemcpy (hSbrFrameInfo, &frameInfo4_1152, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2304: + FDKmemcpy (hSbrFrameInfo, &frameInfo4_2304, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_512LD: + FDKmemcpy (hSbrFrameInfo, &frameInfo4_512LD, sizeof (SBR_FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; + default: + FDK_ASSERT(0); + } +} + + +/******************************************************************************* + Functionname: ctrlSignal2FrameInfo + ******************************************************************************* + + Description: Calculates frame_info struct from control signal. + + Arguments: hSbrGrid - source + hSbrFrameInfo - destination + + Return: void; hSbrFrameInfo contains the updated FRAME_INFO struct + +*******************************************************************************/ +static void +ctrlSignal2FrameInfo (HANDLE_SBR_GRID hSbrGrid, + HANDLE_SBR_FRAME_INFO hSbrFrameInfo, + INT freq_res_fixfix) +{ + INT nEnv = 0, border = 0, i, k, p /*?*/; + INT *v_r = hSbrGrid->bs_rel_bord; + INT *v_f = hSbrGrid->v_f; + + FRAME_CLASS frameClass = hSbrGrid->frameClass; + INT bufferFrameStart = hSbrGrid->bufferFrameStart; + INT numberTimeSlots = hSbrGrid->numberTimeSlots; + + switch (frameClass) { + case FIXFIX: + createDefFrameInfo(hSbrFrameInfo, hSbrGrid->bs_num_env, numberTimeSlots); + + /* At this point all frequency resolutions are set to FREQ_RES_HIGH, so + * only if freq_res_fixfix is set to FREQ_RES_LOW, they all have to be + * changed. + * snd */ + if (freq_res_fixfix == FREQ_RES_LOW) { + for (i = 0; i < hSbrFrameInfo->nEnvelopes; i++) { + hSbrFrameInfo->freqRes[i] = FREQ_RES_LOW; + } + } + /* ELD: store current frequency resolution */ + hSbrGrid->v_f[0] = hSbrFrameInfo->freqRes[0]; + break; + + case FIXVAR: + case VARFIX: + nEnv = hSbrGrid->n + 1; /* read n [SBR_NUM_BITS bits] */ /*? snd*/ + FDK_ASSERT(nEnv <= MAX_ENVELOPES_FIXVAR_VARFIX); + + hSbrFrameInfo->nEnvelopes = nEnv; + + border = hSbrGrid->bs_abs_bord; /* read the absolute border */ + + if (nEnv == 1) + hSbrFrameInfo->nNoiseEnvelopes = 1; + else + hSbrFrameInfo->nNoiseEnvelopes = 2; + + break; + + default: + /* do nothing */ + break; + } + + switch (frameClass) { + case FIXVAR: + hSbrFrameInfo->borders[0] = bufferFrameStart; /* start-position of 1st envelope */ + + hSbrFrameInfo->borders[nEnv] = border; + + for (k = 0, i = nEnv - 1; k < nEnv - 1; k++, i--) { + border -= v_r[k]; + hSbrFrameInfo->borders[i] = border; + } + + /* make either envelope nr. nEnv + 1 - p short; or don't shorten if p == 0 */ + p = hSbrGrid->p; + if (p == 0) { + hSbrFrameInfo->shortEnv = 0; + } else { + hSbrFrameInfo->shortEnv = nEnv + 1 - p; + } + + for (k = 0, i = nEnv - 1; k < nEnv; k++, i--) { + hSbrFrameInfo->freqRes[i] = (FREQ_RES)v_f[k]; + } + + /* if either there is no short envelope or the last envelope is short... */ + if (p == 0 || p == 1) { + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[nEnv - 1]; + } else { + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[hSbrFrameInfo->shortEnv]; + } + + break; + + case VARFIX: + /* in this case 'border' indicates the start of the 1st envelope */ + hSbrFrameInfo->borders[0] = border; + + for (k = 0; k < nEnv - 1; k++) { + border += v_r[k]; + hSbrFrameInfo->borders[k + 1] = border; + } + + hSbrFrameInfo->borders[nEnv] = bufferFrameStart + numberTimeSlots; + + p = hSbrGrid->p; + if (p == 0 || p == 1) { + hSbrFrameInfo->shortEnv = 0; + } else { + hSbrFrameInfo->shortEnv = p - 1; + } + + for (k = 0; k < nEnv; k++) { + hSbrFrameInfo->freqRes[k] = (FREQ_RES)v_f[k]; + } + + switch (p) { + case 0: + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[1]; + break; + case 1: + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[nEnv - 1]; + break; + default: + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[hSbrFrameInfo->shortEnv]; + break; + } + break; + + case VARVAR: + nEnv = hSbrGrid->bs_num_rel_0 + hSbrGrid->bs_num_rel_1 + 1; + FDK_ASSERT(nEnv <= MAX_ENVELOPES_VARVAR); /* just to be sure */ + hSbrFrameInfo->nEnvelopes = nEnv; + + hSbrFrameInfo->borders[0] = border = hSbrGrid->bs_abs_bord_0; + + for (k = 0, i = 1; k < hSbrGrid->bs_num_rel_0; k++, i++) { + border += hSbrGrid->bs_rel_bord_0[k]; + hSbrFrameInfo->borders[i] = border; + } + + border = hSbrGrid->bs_abs_bord_1; + hSbrFrameInfo->borders[nEnv] = border; + + for (k = 0, i = nEnv - 1; k < hSbrGrid->bs_num_rel_1; k++, i--) { + border -= hSbrGrid->bs_rel_bord_1[k]; + hSbrFrameInfo->borders[i] = border; + } + + p = hSbrGrid->p; + if (p == 0) { + hSbrFrameInfo->shortEnv = 0; + } else { + hSbrFrameInfo->shortEnv = nEnv + 1 - p; + } + + for (k = 0; k < nEnv; k++) { + hSbrFrameInfo->freqRes[k] = (FREQ_RES)hSbrGrid->v_fLR[k]; + } + + if (nEnv == 1) { + hSbrFrameInfo->nNoiseEnvelopes = 1; + hSbrFrameInfo->bordersNoise[0] = hSbrGrid->bs_abs_bord_0; + hSbrFrameInfo->bordersNoise[1] = hSbrGrid->bs_abs_bord_1; + } else { + hSbrFrameInfo->nNoiseEnvelopes = 2; + hSbrFrameInfo->bordersNoise[0] = hSbrGrid->bs_abs_bord_0; + + if (p == 0 || p == 1) { + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[nEnv - 1]; + } else { + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[hSbrFrameInfo->shortEnv]; + } + hSbrFrameInfo->bordersNoise[2] = hSbrGrid->bs_abs_bord_1; + } + break; + + default: + /* do nothing */ + break; + } + + if (frameClass == VARFIX || frameClass == FIXVAR) { + hSbrFrameInfo->bordersNoise[0] = hSbrFrameInfo->borders[0]; + if (nEnv == 1) { + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[nEnv]; + } else { + hSbrFrameInfo->bordersNoise[2] = hSbrFrameInfo->borders[nEnv]; + } + } +} + diff --git a/libSBRenc/src/fram_gen.h b/libSBRenc/src/fram_gen.h new file mode 100644 index 0000000..3301e77 --- /dev/null +++ b/libSBRenc/src/fram_gen.h @@ -0,0 +1,249 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Framing generator prototypes and structs $Revision: 36847 $ +*/ +#ifndef _FRAM_GEN_H +#define _FRAM_GEN_H + +#include "sbr_def.h" /* for MAX_ENVELOPES and MAX_NOISE_ENVELOPES in struct FRAME_INFO and CODEC_TYPE */ + +#define MAX_ENVELOPES_VARVAR MAX_ENVELOPES /*!< worst case number of envelopes in a VARVAR frame */ +#define MAX_ENVELOPES_FIXVAR_VARFIX 4 /*!< worst case number of envelopes in VARFIX and FIXVAR frames */ +#define MAX_NUM_REL 3 /*!< maximum number of relative borders in any VAR frame */ + +/* SBR frame class definitions */ +typedef enum { + FIXFIX = 0, /*!< bs_frame_class: leading and trailing frame borders are fixed */ + FIXVAR, /*!< bs_frame_class: leading frame border is fixed, trailing frame border is variable */ + VARFIX, /*!< bs_frame_class: leading frame border is variable, trailing frame border is fixed */ + VARVAR /*!< bs_frame_class: leading and trailing frame borders are variable */ + ,FIXFIXonly /*!< bs_frame_class: leading border fixed (0), trailing border fixed (nrTimeSlots) and encased borders are dynamically derived from the tranPos */ +}FRAME_CLASS; + + +/* helper constants */ +#define DC 4711 /*!< helper constant: don't care */ +#define EMPTY (-99) /*!< helper constant: empty */ + + +/* system constants: AAC+SBR, DRM Frame-Length */ +#define FRAME_MIDDLE_SLOT_1920 4 +#define NUMBER_TIME_SLOTS_1920 15 + +#define LD_PRETRAN_OFF 3 +#define FRAME_MIDDLE_SLOT_512LD 0 +#define NUMBER_TIME_SLOTS_512LD 8 +#define TRANSIENT_OFFSET_LD 0 + + + +/* +system constants: AAC+SBR or aacPRO (hybrid format), Standard Frame-Length, Multi-Rate +--------------------------------------------------------------------------- +Number of slots (numberTimeSlots): 16 (NUMBER_TIME_SLOTS_2048) +Detector-offset (frameMiddleSlot): 4 +Overlap : 3 +Buffer-offset : 8 (BUFFER_FRAME_START_2048 = 0) + + + |<------------tranPos---------->| + |c|d|e|f|0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f| + FixFix | | + FixVar | :<- ->: + VarFix :<- ->: | + VarVar :<- ->: :<- ->: + 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 +................................................................................ + +|-|-|-|-|-|-|-|-B-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-B-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-| + +frame-generator:0 16 24 32 +analysis-buffer:8 24 32 40 +*/ +#define FRAME_MIDDLE_SLOT_2048 4 +#define NUMBER_TIME_SLOTS_2048 16 + + +/* +system constants: mp3PRO, Multi-Rate & Single-Rate +-------------------------------------------------- +Number of slots (numberTimeSlots): 9 (NUMBER_TIME_SLOTS_1152) +Detector-offset (frameMiddleSlot): 4 (FRAME_MIDDLE_SLOT_1152) +Overlap : 3 +Buffer-offset : 4.5 (BUFFER_FRAME_START_1152 = 0) + + + |<----tranPos---->| + |5|6|7|8|0|1|2|3|4|5|6|7|8| + FixFix | | + FixVar | :<- ->: + VarFix :<- ->: | + VarVar :<- ->: :<- ->: + 0 1 2 3 4 5 6 7 8 0 1 2 3 + ............................................. + + -|-|-|-|-B-|-|-|-|-|-|-|-|-B-|-|-|-|-|-|-|-|-| + +frame-generator: 0 9 13 18 +analysis-buffer: 4.5 13.5 22.5 +*/ +#define FRAME_MIDDLE_SLOT_1152 4 +#define NUMBER_TIME_SLOTS_1152 9 + + +/* system constants: Layer2+SBR */ +#define FRAME_MIDDLE_SLOT_2304 8 +#define NUMBER_TIME_SLOTS_2304 18 + + +/*! + \struct SBR_GRID + \brief sbr_grid() signals to be converted to bitstream elements + + The variables hold the signals (e.g. lengths and numbers) in "clear text" +*/ + +typedef struct +{ + /* system constants */ + INT bufferFrameStart; /*!< frame generator vs analysis buffer time alignment (currently set to 0, offset added elsewhere) */ + INT numberTimeSlots; /*!< number of SBR timeslots per frame */ + + /* will be adjusted for every frame */ + FRAME_CLASS frameClass; /*!< SBR frame class */ + INT bs_num_env; /*!< bs_num_env, number of envelopes for FIXFIX */ + INT bs_abs_bord; /*!< bs_abs_bord, absolute border for VARFIX and FIXVAR */ + INT n; /*!< number of relative borders for VARFIX and FIXVAR */ + INT p; /*!< pointer-to-transient-border */ + INT bs_rel_bord[MAX_NUM_REL]; /*!< bs_rel_bord, relative borders for all VAR */ + INT v_f[MAX_ENVELOPES_FIXVAR_VARFIX]; /*!< envelope frequency resolutions for FIXVAR and VARFIX */ + + INT bs_abs_bord_0; /*!< bs_abs_bord_0, leading absolute border for VARVAR */ + INT bs_abs_bord_1; /*!< bs_abs_bord_1, trailing absolute border for VARVAR */ + INT bs_num_rel_0; /*!< bs_num_rel_0, number of relative borders associated with leading absolute border for VARVAR */ + INT bs_num_rel_1; /*!< bs_num_rel_1, number of relative borders associated with trailing absolute border for VARVAR */ + INT bs_rel_bord_0[MAX_NUM_REL]; /*!< bs_rel_bord_0, relative borders associated with leading absolute border for VARVAR */ + INT bs_rel_bord_1[MAX_NUM_REL]; /*!< bs_rel_bord_1, relative borders associated with trailing absolute border for VARVAR */ + INT v_fLR[MAX_ENVELOPES_VARVAR]; /*!< envelope frequency resolutions for VARVAR */ + +} +SBR_GRID; +typedef SBR_GRID *HANDLE_SBR_GRID; + + + +/*! + \struct SBR_FRAME_INFO + \brief time/frequency grid description for one frame +*/ +typedef struct +{ + INT nEnvelopes; /*!< number of envelopes */ + INT borders[MAX_ENVELOPES+1]; /*!< envelope borders in SBR timeslots */ + FREQ_RES freqRes[MAX_ENVELOPES]; /*!< frequency resolution of each envelope */ + INT shortEnv; /*!< number of an envelope to be shortened (starting at 1) or 0 for no shortened envelope */ + INT nNoiseEnvelopes; /*!< number of noise floors */ + INT bordersNoise[MAX_NOISE_ENVELOPES+1];/*!< noise floor borders in SBR timeslots */ +} +SBR_FRAME_INFO; +/* WARNING: When rearranging the elements of this struct keep in mind that the static + * initializations in the corresponding C-file have to be rearranged as well! + * snd 2002/01/23 + */ +typedef SBR_FRAME_INFO *HANDLE_SBR_FRAME_INFO; + + +/*! + \struct SBR_ENVELOPE_FRAME + \brief frame generator main struct + + Contains tuning parameters, time/frequency grid description, sbr_grid() bitstream elements, and generator internal signals +*/ +typedef struct +{ + /* system constants */ + INT frameMiddleSlot; /*!< transient detector offset in SBR timeslots */ + + /* basic tuning parameters */ + INT staticFraming; /*!< 1: run static framing in time, i.e. exclusive use of bs_frame_class = FIXFIX */ + INT numEnvStatic; /*!< number of envelopes per frame for static framing */ + INT freq_res_fixfix; /*!< envelope frequency resolution to use for bs_frame_class = FIXFIX */ + + /* expert tuning parameters */ + const int *v_tuningSegm; /*!< segment lengths to use around transient */ + const int *v_tuningFreq; /*!< frequency resolutions to use around transient */ + INT dmin; /*!< minimum length of dependent segments */ + INT dmax; /*!< maximum length of dependent segments */ + INT allowSpread; /*!< 1: allow isolated transient to influence grid of 3 consecutive frames */ + + /* internally used signals */ + FRAME_CLASS frameClassOld; /*!< frame class used for previous frame */ + INT spreadFlag; /*!< 1: use VARVAR instead of VARFIX to follow up old transient */ + + INT v_bord[2 * MAX_ENVELOPES_VARVAR + 1]; /*!< borders for current frame and preliminary borders for next frame (fixed borders excluded) */ + INT length_v_bord; /*!< helper variable: length of v_bord */ + INT v_freq[2 * MAX_ENVELOPES_VARVAR + 1]; /*!< frequency resolutions for current frame and preliminary resolutions for next frame */ + INT length_v_freq; /*!< helper variable: length of v_freq */ + + INT v_bordFollow[MAX_ENVELOPES_VARVAR]; /*!< preliminary borders for current frame (calculated during previous frame) */ + INT length_v_bordFollow; /*!< helper variable: length of v_bordFollow */ + INT i_tranFollow; /*!< points to transient border in v_bordFollow (may be negative, see keepForFollowUp()) */ + INT i_fillFollow; /*!< points to first fill border in v_bordFollow */ + INT v_freqFollow[MAX_ENVELOPES_VARVAR]; /*!< preliminary frequency resolutions for current frame (calculated during previous frame) */ + INT length_v_freqFollow; /*!< helper variable: length of v_freqFollow */ + + + /* externally needed signals */ + SBR_GRID SbrGrid; /*!< sbr_grid() signals to be converted to bitstream elements */ + SBR_FRAME_INFO SbrFrameInfo; /*!< time/frequency grid description for one frame */ +} +SBR_ENVELOPE_FRAME; +typedef SBR_ENVELOPE_FRAME *HANDLE_SBR_ENVELOPE_FRAME; + + + +void +FDKsbrEnc_initFrameInfoGenerator (HANDLE_SBR_ENVELOPE_FRAME hSbrEnvFrame, + INT allowSpread, + INT numEnvStatic, + INT staticFraming, + INT timeSlots, + INT freq_res_fixfix + ,int ldGrid + ); + +/* void deleteFrameInfoGenerator (HANDLE_SBR_ENVELOPE_FRAME hSbrEnvFrame); */ + +HANDLE_SBR_FRAME_INFO +FDKsbrEnc_frameInfoGenerator (HANDLE_SBR_ENVELOPE_FRAME hSbrEnvFrame, + UCHAR *v_transient_info, + UCHAR *v_transient_info_pre, + int ldGrid, + const int *v_tuning); + +#endif diff --git a/libSBRenc/src/invf_est.cpp b/libSBRenc/src/invf_est.cpp new file mode 100644 index 0000000..4f4670c --- /dev/null +++ b/libSBRenc/src/invf_est.cpp @@ -0,0 +1,472 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +#include "invf_est.h" +#include "sbr_misc.h" + +#include "genericStds.h" + +#define MAX_NUM_REGIONS 10 +#define SCALE_FAC_QUO 512.0f +#define SCALE_FAC_NRG 256.0f + +#ifndef min +#define min(a,b) ( a < b ? a:b) +#endif + +#ifndef max +#define max(a,b) ( a > b ? a:b) +#endif + +static const FIXP_DBL quantStepsSbr[4] = { 0x00400000, 0x02800000, 0x03800000, 0x04c00000 } ; /* table scaled with SCALE_FAC_QUO */ +static const FIXP_DBL quantStepsOrig[4] = { 0x00000000, 0x00c00000, 0x01c00000, 0x02800000 } ; /* table scaled with SCALE_FAC_QUO */ +static const FIXP_DBL nrgBorders[4] = { 0x0c800000, 0x0f000000, 0x11800000, 0x14000000 } ; /* table scaled with SCALE_FAC_NRG */ + +static const DETECTOR_PARAMETERS detectorParamsAAC = { + quantStepsSbr, + quantStepsOrig, + nrgBorders, + 4, /* Number of borders SBR. */ + 4, /* Number of borders orig. */ + 4, /* Number of borders Nrg. */ + { /* Region space. */ + {INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF, INVF_OFF}, /* | */ + {INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* regionSbr */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF} /* | */ + },/*------------------------ regionOrig ---------------------------------*/ + { /* Region space transient. */ + {INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* regionSbr */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF} /* | */ + },/*------------------------ regionOrig ---------------------------------*/ + {-4, -3, -2, -1, 0} /* Reduction factor of the inverse filtering for low energies.*/ +}; + +static const FIXP_DBL hysteresis = 0x00400000 ; /* Delta value for hysteresis. scaled with SCALE_FAC_QUO */ + +/* + * AAC+SBR PARAMETERS for Speech + *********************************/ +static const DETECTOR_PARAMETERS detectorParamsAACSpeech = { + quantStepsSbr, + quantStepsOrig, + nrgBorders, + 4, /* Number of borders SBR. */ + 4, /* Number of borders orig. */ + 4, /* Number of borders Nrg. */ + { /* Region space. */ + {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* regionSbr */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF} /* | */ + },/*------------------------ regionOrig ---------------------------------*/ + { /* Region space transient. */ + {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* regionSbr */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF} /* | */ + },/*------------------------ regionOrig ---------------------------------*/ + {-4, -3, -2, -1, 0} /* Reduction factor of the inverse filtering for low energies.*/ +}; + +/* + * Smoothing filters. + ************************/ +typedef const FIXP_DBL FIR_FILTER[5]; + +static const FIR_FILTER fir_0 = { 0x7fffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } ; +static const FIR_FILTER fir_1 = { 0x2aaaaa80, 0x555554ff, 0x00000000, 0x00000000, 0x00000000 } ; +static const FIR_FILTER fir_2 = { 0x10000000, 0x30000000, 0x40000000, 0x00000000, 0x00000000 } ; +static const FIR_FILTER fir_3 = { 0x077f80e8, 0x199999a0, 0x2bb3b240, 0x33333340, 0x00000000 } ; +static const FIR_FILTER fir_4 = { 0x04130598, 0x0ebdb000, 0x1becfa60, 0x2697a4c0, 0x2aaaaa80 } ; + + +static const FIR_FILTER *const fir_table[5] = { + &fir_0, + &fir_1, + &fir_2, + &fir_3, + &fir_4 +}; + +/**************************************************************************/ +/*! + \brief Calculates the values used for the detector. + + + \return none + +*/ +/**************************************************************************/ +static void +calculateDetectorValues(FIXP_DBL **quotaMatrixOrig, /*!< Matrix holding the tonality values of the original. */ + SCHAR *indexVector, /*!< Index vector to obtain the patched data. */ + FIXP_DBL *nrgVector, /*!< Energy vector. */ + DETECTOR_VALUES *detectorValues, /*!< pointer to DETECTOR_VALUES struct. */ + INT startChannel, /*!< Start channel. */ + INT stopChannel, /*!< Stop channel. */ + INT startIndex, /*!< Start index. */ + INT stopIndex, /*!< Stop index. */ + INT numberOfStrongest /*!< The number of sorted tonal components to be considered. */ + ) +{ + INT i,temp, j; + + const FIXP_DBL* filter = *fir_table[INVF_SMOOTHING_LENGTH]; + FIXP_DBL origQuotaMeanStrongest, sbrQuotaMeanStrongest; + FIXP_DBL origQuota, sbrQuota; + FIXP_DBL invIndex, invChannel, invTemp; + FIXP_DBL quotaVecOrig[64], quotaVecSbr[64]; + + FDKmemclear(quotaVecOrig,64*sizeof(FIXP_DBL)); + FDKmemclear(quotaVecSbr,64*sizeof(FIXP_DBL)); + + invIndex = GetInvInt(stopIndex-startIndex); + invChannel = GetInvInt(stopChannel-startChannel); + + /* + Calculate the mean value, over the current time segment, for the original, the HFR + and the difference, over all channels in the current frequency range. + NOTE: the averaging is done on the values quota/(1 - quota + RELAXATION). + */ + + /* The original, the sbr signal and the total energy */ + detectorValues->avgNrg = FL2FXCONST_DBL(0.0f); + for(j=startIndex; javgNrg += fMult(nrgVector[j], invIndex); + } + + /* + Calculate the mean value, over the current frequency range, for the original, the HFR + and the difference. Also calculate the same mean values for the three vectors, but only + includeing the x strongest copmponents. + */ + + origQuota = FL2FXCONST_DBL(0.0f); + sbrQuota = FL2FXCONST_DBL(0.0f); + for(i=startChannel; iorigQuotaMax = quotaVecOrig[stopChannel - 1]; + detectorValues->sbrQuotaMax = quotaVecSbr[stopChannel - 1]; + + /* + Buffer values + */ + FDKmemmove(detectorValues->origQuotaMean, detectorValues->origQuotaMean + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL)); + FDKmemmove(detectorValues->sbrQuotaMean, detectorValues->sbrQuotaMean + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL)); + FDKmemmove(detectorValues->origQuotaMeanStrongest, detectorValues->origQuotaMeanStrongest + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL)); + FDKmemmove(detectorValues->sbrQuotaMeanStrongest, detectorValues->sbrQuotaMeanStrongest + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL)); + + detectorValues->origQuotaMean[INVF_SMOOTHING_LENGTH] = origQuota<<1; + detectorValues->sbrQuotaMean[INVF_SMOOTHING_LENGTH] = sbrQuota<<1; + detectorValues->origQuotaMeanStrongest[INVF_SMOOTHING_LENGTH] = origQuotaMeanStrongest<<1; + detectorValues->sbrQuotaMeanStrongest[INVF_SMOOTHING_LENGTH] = sbrQuotaMeanStrongest<<1; + + /* + Filter values + */ + detectorValues->origQuotaMeanFilt = FL2FXCONST_DBL(0.0f); + detectorValues->sbrQuotaMeanFilt = FL2FXCONST_DBL(0.0f); + detectorValues->origQuotaMeanStrongestFilt = FL2FXCONST_DBL(0.0f); + detectorValues->sbrQuotaMeanStrongestFilt = FL2FXCONST_DBL(0.0f); + + for(i=0;iorigQuotaMeanFilt += fMult(detectorValues->origQuotaMean[i], filter[i]); + detectorValues->sbrQuotaMeanFilt += fMult(detectorValues->sbrQuotaMean[i], filter[i]); + detectorValues->origQuotaMeanStrongestFilt += fMult(detectorValues->origQuotaMeanStrongest[i], filter[i]); + detectorValues->sbrQuotaMeanStrongestFilt += fMult(detectorValues->sbrQuotaMeanStrongest[i], filter[i]); + } +} + +/**************************************************************************/ +/*! + \brief Returns the region in which the input value belongs. + + + + \return region. + +*/ +/**************************************************************************/ +static INT +findRegion(FIXP_DBL currVal, /*!< The current value. */ + const FIXP_DBL *borders, /*!< The border of the regions. */ + const INT numBorders /*!< The number of borders. */ + ) +{ + INT i; + + if(currVal < borders[0]){ + return 0; + } + + for(i = 1; i < numBorders; i++){ + if( currVal >= borders[i-1] && currVal < borders[i]){ + return i; + } + } + + if(currVal >= borders[numBorders-1]){ + return numBorders; + } + + return 0; /* We never get here, it's just to avoid compiler warnings.*/ +} + +/**************************************************************************/ +/*! + \brief Makes a clever decision based on the quota vector. + + + \return decision on which invf mode to use + +*/ +/**************************************************************************/ +static INVF_MODE +decisionAlgorithm(const DETECTOR_PARAMETERS *detectorParams, /*!< Struct with the detector parameters. */ + DETECTOR_VALUES *detectorValues, /*!< Struct with the detector values. */ + INT transientFlag, /*!< Flag indicating if there is a transient present.*/ + INT* prevRegionSbr, /*!< The previous region in which the Sbr value was. */ + INT* prevRegionOrig /*!< The previous region in which the Orig value was. */ + ) +{ + INT invFiltLevel, regionSbr, regionOrig, regionNrg; + + /* + Current thresholds. + */ + const FIXP_DBL *quantStepsSbr = detectorParams->quantStepsSbr; + const FIXP_DBL *quantStepsOrig = detectorParams->quantStepsOrig; + const FIXP_DBL *nrgBorders = detectorParams->nrgBorders; + const INT numRegionsSbr = detectorParams->numRegionsSbr; + const INT numRegionsOrig = detectorParams->numRegionsOrig; + const INT numRegionsNrg = detectorParams->numRegionsNrg; + + FIXP_DBL quantStepsSbrTmp[MAX_NUM_REGIONS]; + FIXP_DBL quantStepsOrigTmp[MAX_NUM_REGIONS]; + + /* + Current detector values. + */ + FIXP_DBL origQuotaMeanFilt; + FIXP_DBL sbrQuotaMeanFilt; + FIXP_DBL nrg; + + /* 0.375 = 3.0 / 8.0; 0.31143075889 = log2(RELAXATION)/64.0; 0.625 = log(16)/64.0; 0.6875 = 44/64.0 */ + origQuotaMeanFilt = (fMultDiv2(FL2FXCONST_DBL(2.f*0.375f), (FIXP_DBL)(CalcLdData(max(detectorValues->origQuotaMeanFilt,(FIXP_DBL)1)) + FL2FXCONST_DBL(0.31143075889f)))) << 0; /* scaled by 1/2^9 */ + sbrQuotaMeanFilt = (fMultDiv2(FL2FXCONST_DBL(2.f*0.375f), (FIXP_DBL)(CalcLdData(max(detectorValues->sbrQuotaMeanFilt,(FIXP_DBL)1)) + FL2FXCONST_DBL(0.31143075889f)))) << 0; /* scaled by 1/2^9 */ + /* If energy is zero then we will get different results for different word lengths. */ + nrg = (fMultDiv2(FL2FXCONST_DBL(2.f*0.375f), (FIXP_DBL)(CalcLdData(detectorValues->avgNrg+(FIXP_DBL)1) + FL2FXCONST_DBL(0.0625f) + FL2FXCONST_DBL(0.6875f)))) << 0; /* scaled by 1/2^8; 2^44 -> qmf energy scale */ + + FDKmemcpy(quantStepsSbrTmp,quantStepsSbr,numRegionsSbr*sizeof(FIXP_DBL)); + FDKmemcpy(quantStepsOrigTmp,quantStepsOrig,numRegionsOrig*sizeof(FIXP_DBL)); + + if(*prevRegionSbr < numRegionsSbr) + quantStepsSbrTmp[*prevRegionSbr] = quantStepsSbr[*prevRegionSbr] + hysteresis; + if(*prevRegionSbr > 0) + quantStepsSbrTmp[*prevRegionSbr - 1] = quantStepsSbr[*prevRegionSbr - 1] - hysteresis; + + if(*prevRegionOrig < numRegionsOrig) + quantStepsOrigTmp[*prevRegionOrig] = quantStepsOrig[*prevRegionOrig] + hysteresis; + if(*prevRegionOrig > 0) + quantStepsOrigTmp[*prevRegionOrig - 1] = quantStepsOrig[*prevRegionOrig - 1] - hysteresis; + + regionSbr = findRegion(sbrQuotaMeanFilt, quantStepsSbrTmp, numRegionsSbr); + regionOrig = findRegion(origQuotaMeanFilt, quantStepsOrigTmp, numRegionsOrig); + regionNrg = findRegion(nrg,nrgBorders,numRegionsNrg); + + *prevRegionSbr = regionSbr; + *prevRegionOrig = regionOrig; + + /* Use different settings if a transient is present*/ + invFiltLevel = (transientFlag == 1) ? detectorParams->regionSpaceTransient[regionSbr][regionOrig] + : detectorParams->regionSpace[regionSbr][regionOrig]; + + /* Compensate for low energy.*/ + invFiltLevel = max(invFiltLevel + detectorParams->EnergyCompFactor[regionNrg],0); + + return (INVF_MODE) (invFiltLevel); +} + +/**************************************************************************/ +/*! + \brief Estiamtion of the inverse filtering level required + in the decoder. + + A second order LPC is calculated for every filterbank channel, using + the covariance method. THe ratio between the energy of the predicted + signal and the energy of the non-predictable signal is calcualted. + + \return none. + +*/ +/**************************************************************************/ +void +FDKsbrEnc_qmfInverseFilteringDetector(HANDLE_SBR_INV_FILT_EST hInvFilt, /*!< Handle to the SBR_INV_FILT_EST struct. */ + FIXP_DBL **quotaMatrix, /*!< The matrix holding the tonality values of the original. */ + FIXP_DBL *nrgVector, /*!< The energy vector. */ + SCHAR *indexVector, /*!< Index vector to obtain the patched data. */ + INT startIndex, /*!< Start index. */ + INT stopIndex, /*!< Stop index. */ + INT transientFlag, /*!< Flag indicating if a transient is present or not.*/ + INVF_MODE* infVec /*!< Vector holding the inverse filtering levels. */ + ) +{ + INT band; + + /* + * Do the inverse filtering level estimation. + *****************************************************/ + for(band = 0 ; band < hInvFilt->noDetectorBands; band++){ + INT startChannel = hInvFilt->freqBandTableInvFilt[band]; + INT stopChannel = hInvFilt->freqBandTableInvFilt[band+1]; + + + calculateDetectorValues( quotaMatrix, + indexVector, + nrgVector, + &hInvFilt->detectorValues[band], + startChannel, + stopChannel, + startIndex, + stopIndex, + hInvFilt->numberOfStrongest); + + infVec[band]= decisionAlgorithm( hInvFilt->detectorParams, + &hInvFilt->detectorValues[band], + transientFlag, + &hInvFilt->prevRegionSbr[band], + &hInvFilt->prevRegionOrig[band]); + } + +} + + +/**************************************************************************/ +/*! + \brief Initialize an instance of the inverse filtering level estimator. + + + \return errorCode, noError if successful. + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_initInvFiltDetector (HANDLE_SBR_INV_FILT_EST hInvFilt, /*!< Pointer to a handle to the SBR_INV_FILT_EST struct. */ + INT* freqBandTableDetector, /*!< Frequency band table for the inverse filtering. */ + INT numDetectorBands, /*!< Number of inverse filtering bands. */ + UINT useSpeechConfig /*!< Flag: adapt tuning parameters according to speech*/ + ) +{ + INT i; + + FDKmemclear( hInvFilt,sizeof(SBR_INV_FILT_EST)); + + hInvFilt->detectorParams = (useSpeechConfig) ? &detectorParamsAACSpeech + : &detectorParamsAAC ; + + hInvFilt->noDetectorBandsMax = numDetectorBands; + + /* + Memory initialisation + */ + for(i=0;inoDetectorBandsMax;i++){ + FDKmemclear(&hInvFilt->detectorValues[i], sizeof(DETECTOR_VALUES)); + hInvFilt->prevInvfMode[i] = INVF_OFF; + hInvFilt->prevRegionOrig[i] = 0; + hInvFilt->prevRegionSbr[i] = 0; + } + + /* + Reset the inverse fltering detector. + */ + FDKsbrEnc_resetInvFiltDetector(hInvFilt, + freqBandTableDetector, + hInvFilt->noDetectorBandsMax); + + return (0); +} + + +/**************************************************************************/ +/*! + \brief resets sbr inverse filtering structure. + + + + \return errorCode, noError if successful. + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_resetInvFiltDetector(HANDLE_SBR_INV_FILT_EST hInvFilt, /*!< Handle to the SBR_INV_FILT_EST struct. */ + INT* freqBandTableDetector, /*!< Frequency band table for the inverse filtering. */ + INT numDetectorBands) /*!< Number of inverse filtering bands. */ +{ + + hInvFilt->numberOfStrongest = 1; + FDKmemcpy(hInvFilt->freqBandTableInvFilt,freqBandTableDetector,(numDetectorBands+1)*sizeof(INT)); + hInvFilt->noDetectorBands = numDetectorBands; + + return (0); +} + + diff --git a/libSBRenc/src/invf_est.h b/libSBRenc/src/invf_est.h new file mode 100644 index 0000000..da020f5 --- /dev/null +++ b/libSBRenc/src/invf_est.h @@ -0,0 +1,119 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Inverse Filtering detection prototypes $Revision: 36847 $ +*/ +#ifndef _INV_FILT_DET_H +#define _INV_FILT_DET_H + +#include "sbr_encoder.h" +#include "sbr_def.h" + +#define INVF_SMOOTHING_LENGTH 2 + +typedef struct +{ + const FIXP_DBL *quantStepsSbr; + const FIXP_DBL *quantStepsOrig; + const FIXP_DBL *nrgBorders; + INT numRegionsSbr; + INT numRegionsOrig; + INT numRegionsNrg; + INVF_MODE regionSpace[5][5]; + INVF_MODE regionSpaceTransient[5][5]; + INT EnergyCompFactor[5]; + +}DETECTOR_PARAMETERS; + +typedef struct +{ + FIXP_DBL origQuotaMean[INVF_SMOOTHING_LENGTH+1]; + FIXP_DBL sbrQuotaMean[INVF_SMOOTHING_LENGTH+1]; + FIXP_DBL origQuotaMeanStrongest[INVF_SMOOTHING_LENGTH+1]; + FIXP_DBL sbrQuotaMeanStrongest[INVF_SMOOTHING_LENGTH+1]; + + FIXP_DBL origQuotaMeanFilt; + FIXP_DBL sbrQuotaMeanFilt; + FIXP_DBL origQuotaMeanStrongestFilt; + FIXP_DBL sbrQuotaMeanStrongestFilt; + + FIXP_DBL origQuotaMax; + FIXP_DBL sbrQuotaMax; + + FIXP_DBL avgNrg; +}DETECTOR_VALUES; + + + +typedef struct +{ + INT numberOfStrongest; + + INT prevRegionSbr[MAX_NUM_NOISE_VALUES]; + INT prevRegionOrig[MAX_NUM_NOISE_VALUES]; + + INT freqBandTableInvFilt[MAX_NUM_NOISE_VALUES]; + INT noDetectorBands; + INT noDetectorBandsMax; + + const DETECTOR_PARAMETERS *detectorParams; + + INVF_MODE prevInvfMode[MAX_NUM_NOISE_VALUES]; + DETECTOR_VALUES detectorValues[MAX_NUM_NOISE_VALUES]; + + FIXP_DBL nrgAvg; + FIXP_DBL wmQmf[MAX_NUM_NOISE_VALUES]; +} +SBR_INV_FILT_EST; + +typedef SBR_INV_FILT_EST *HANDLE_SBR_INV_FILT_EST; + +void +FDKsbrEnc_qmfInverseFilteringDetector(HANDLE_SBR_INV_FILT_EST hInvFilt, + FIXP_DBL ** quotaMatrix, + FIXP_DBL *nrgVector, + SCHAR *indexVector, + INT startIndex, + INT stopIndex, + INT transientFlag, + INVF_MODE* infVec); + +INT +FDKsbrEnc_initInvFiltDetector (HANDLE_SBR_INV_FILT_EST hInvFilt, + INT* freqBandTableDetector, + INT numDetectorBands, + UINT useSpeechConfig); + +/* void deleteInvFiltDetector (HANDLE_SBR_INV_FILT_EST hInvFilt); */ + +INT +FDKsbrEnc_resetInvFiltDetector(HANDLE_SBR_INV_FILT_EST hInvFilt, + INT* freqBandTableDetector, + INT numDetectorBands); + +#endif /* _QMF_INV_FILT_H */ + diff --git a/libSBRenc/src/mh_det.cpp b/libSBRenc/src/mh_det.cpp new file mode 100644 index 0000000..8b6c1a0 --- /dev/null +++ b/libSBRenc/src/mh_det.cpp @@ -0,0 +1,1381 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +#include "mh_det.h" + +#include "sbr_ram.h" +#include "sbr_misc.h" + + +#include "genericStds.h" + +#define SFM_SHIFT 2 /* Attention: SFM_SCALE depends on SFM_SHIFT */ +#define SFM_SCALE (MAXVAL_DBL >> SFM_SHIFT) /* 1.0 >> SFM_SHIFT */ + + +/*!< Detector Parameters for AAC core codec. */ +static const DETECTOR_PARAMETERS_MH paramsAac = { +9, /*!< deltaTime */ +{ +FL2FXCONST_DBL(20.0f*RELAXATION_FLOAT), /*!< thresHoldDiff */ +FL2FXCONST_DBL(1.26f*RELAXATION_FLOAT), /*!< thresHoldDiffGuide */ +FL2FXCONST_DBL(15.0f*RELAXATION_FLOAT), /*!< thresHoldTone */ +FL2FXCONST_DBL((1.0f/15.0f)*RELAXATION_FLOAT), /*!< invThresHoldTone */ +FL2FXCONST_DBL(1.26f*RELAXATION_FLOAT), /*!< thresHoldToneGuide */ +FL2FXCONST_DBL(0.3f)>>SFM_SHIFT, /*!< sfmThresSbr */ +FL2FXCONST_DBL(0.1f)>>SFM_SHIFT, /*!< sfmThresOrig */ +FL2FXCONST_DBL(0.3f), /*!< decayGuideOrig */ +FL2FXCONST_DBL(0.5f), /*!< decayGuideDiff */ +FL2FXCONST_DBL(-0.000112993269), /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresMaxLD64 */ +FL2FXCONST_DBL(-0.000112993269), /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresBelowLD64 */ +FL2FXCONST_DBL(-0.005030126483f) /* LD64(FL2FXCONST_DBL(0.8f)) */ /*!< derivThresAboveLD64 */ +}, +50 /*!< maxComp */ +}; + +/*!< Detector Parameters for AAC LD core codec. */ +static const DETECTOR_PARAMETERS_MH paramsAacLd = { +16, /*!< Delta time. */ +{ +FL2FXCONST_DBL(25.0f*RELAXATION_FLOAT), /*!< thresHoldDiff */ +FL2FXCONST_DBL(1.26f*RELAXATION_FLOAT), /*!< tresHoldDiffGuide */ +FL2FXCONST_DBL(15.0f*RELAXATION_FLOAT), /*!< thresHoldTone */ +FL2FXCONST_DBL((1.0f/15.0f)*RELAXATION_FLOAT), /*!< invThresHoldTone */ +FL2FXCONST_DBL(1.26f*RELAXATION_FLOAT), /*!< thresHoldToneGuide */ +FL2FXCONST_DBL(0.3f)>>SFM_SHIFT, /*!< sfmThresSbr */ +FL2FXCONST_DBL(0.1f)>>SFM_SHIFT, /*!< sfmThresOrig */ +FL2FXCONST_DBL(0.3f), /*!< decayGuideOrig */ +FL2FXCONST_DBL(0.2f), /*!< decayGuideDiff */ +FL2FXCONST_DBL(-0.000112993269), /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresMaxLD64 */ +FL2FXCONST_DBL(-0.000112993269), /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresBelowLD64 */ +FL2FXCONST_DBL(-0.005030126483f) /* LD64(FL2FXCONST_DBL(0.8f)) */ /*!< derivThresAboveLD64 */ +}, +50 /*!< maxComp */ +}; + + +/**************************************************************************/ +/*! + \brief Calculates the difference in tonality between original and SBR + for a given time and frequency region. + + The values for pDiffMapped2Scfb are scaled by RELAXATION + + \return none. + +*/ +/**************************************************************************/ +static void diff(FIXP_DBL *RESTRICT pTonalityOrig, + FIXP_DBL *pDiffMapped2Scfb, + const UCHAR *RESTRICT pFreqBandTable, + INT nScfb, + SCHAR *indexVector) +{ + UCHAR i, ll, lu, k; + FIXP_DBL maxValOrig, maxValSbr, tmp; + INT scale; + + for(i=0; i < nScfb; i++){ + ll = pFreqBandTable[i]; + lu = pFreqBandTable[i+1]; + + maxValOrig = FL2FXCONST_DBL(0.0f); + maxValSbr = FL2FXCONST_DBL(0.0f); + + for(k=ll;k= RELAXATION)) { + tmp = fDivNorm(maxValOrig, maxValSbr, &scale); + pDiffMapped2Scfb[i] = scaleValue(fMult(tmp,RELAXATION_FRACT), fixMax(-(DFRACT_BITS-1),(scale-RELAXATION_SHIFT))); + } + else { + pDiffMapped2Scfb[i] = maxValOrig; + } + } +} + + +/**************************************************************************/ +/*! + \brief Calculates a flatness measure of the tonality measures. + + Calculation of the power function and using scalefactor for basis: + Using log2: + z = (2^k * x)^y; + z' = CalcLd(z) = y*CalcLd(x) + y*k; + z = CalcInvLd(z'); + + Using ld64: + z = (2^k * x)^y; + z' = CalcLd64(z) = y*CalcLd64(x)/64 + y*k/64; + z = CalcInvLd64(z'); + + The values pSfmOrigVec and pSfmSbrVec are scaled by the factor 1/4.0 + + \return none. + +*/ +/**************************************************************************/ +static void calculateFlatnessMeasure(FIXP_DBL *pQuotaBuffer, + SCHAR *indexVector, + FIXP_DBL *pSfmOrigVec, + FIXP_DBL *pSfmSbrVec, + const UCHAR *pFreqBandTable, + INT nSfb) +{ + INT i,j; + FIXP_DBL invBands,tmp1,tmp2; + INT shiftFac0,shiftFacSum0; + INT shiftFac1,shiftFacSum1; + FIXP_DBL accu; + + for(i=0;i>2); + pSfmSbrVec[i] = (FIXP_DBL)(MAXVAL_DBL>>2); + + if(lu - ll > 1){ + FIXP_DBL amOrig,amTransp,gmOrig,gmTransp,sfmOrig,sfmTransp; + invBands = GetInvInt(lu-ll); + shiftFacSum0 = 0; + shiftFacSum1 = 0; + amOrig = amTransp = FL2FXCONST_DBL(0.0f); + gmOrig = gmTransp = (FIXP_DBL)MAXVAL_DBL; + + for(j= ll; j FL2FXCONST_DBL(0.0f)) { + + tmp1 = CalcLdData(gmOrig); /* CalcLd64(x)/64 */ + tmp1 = fMult(invBands, tmp1); /* y*CalcLd64(x)/64 */ + + /* y*k/64 */ + accu = (FIXP_DBL)-shiftFacSum0 << (DFRACT_BITS-1-8); + tmp2 = fMultDiv2(invBands, accu) << (2+1); + + tmp2 = tmp1 + tmp2; /* y*CalcLd64(x)/64 + y*k/64 */ + gmOrig = CalcInvLdData(tmp2); /* CalcInvLd64(z'); */ + } + else { + gmOrig = FL2FXCONST_DBL(0.0f); + } + + if (gmTransp > FL2FXCONST_DBL(0.0f)) { + + tmp1 = CalcLdData(gmTransp); /* CalcLd64(x)/64 */ + tmp1 = fMult(invBands, tmp1); /* y*CalcLd64(x)/64 */ + + /* y*k/64 */ + accu = (FIXP_DBL)-shiftFacSum1 << (DFRACT_BITS-1-8); + tmp2 = fMultDiv2(invBands, accu) << (2+1); + + tmp2 = tmp1 + tmp2; /* y*CalcLd64(x)/64 + y*k/64 */ + gmTransp = CalcInvLdData(tmp2); /* CalcInvLd64(z'); */ + } + else { + gmTransp = FL2FXCONST_DBL(0.0f); + } + if ( amOrig != FL2FXCONST_DBL(0.0f) ) + pSfmOrigVec[i] = FDKsbrEnc_LSI_divide_scale_fract(gmOrig,amOrig,SFM_SCALE); + + if ( amTransp != FL2FXCONST_DBL(0.0f) ) + pSfmSbrVec[i] = FDKsbrEnc_LSI_divide_scale_fract(gmTransp,amTransp,SFM_SCALE); + } + } +} + +/**************************************************************************/ +/*! + \brief Calculates the input to the missing harmonics detection. + + + \return none. + +*/ +/**************************************************************************/ +static void calculateDetectorInput(FIXP_DBL **RESTRICT pQuotaBuffer, /*!< Pointer to tonality matrix. */ + SCHAR *RESTRICT indexVector, + FIXP_DBL **RESTRICT tonalityDiff, + FIXP_DBL **RESTRICT pSfmOrig, + FIXP_DBL **RESTRICT pSfmSbr, + const UCHAR *freqBandTable, + INT nSfb, + INT noEstPerFrame, + INT move) +{ + INT est; + + /* + New estimate. + */ + for (est=0; est < noEstPerFrame; est++) { + + diff(pQuotaBuffer[est+move], + tonalityDiff[est+move], + freqBandTable, + nSfb, + indexVector); + + calculateFlatnessMeasure(pQuotaBuffer[est+ move], + indexVector, + pSfmOrig[est + move], + pSfmSbr[est + move], + freqBandTable, + nSfb); + } +} + + +/**************************************************************************/ +/*! + \brief Checks that the detection is not due to a LP filter + + This function determines if a newly detected missing harmonics is not + in fact just a low-pass filtere input signal. If so, the detection is + removed. + + \return none. + +*/ +/**************************************************************************/ +static void removeLowPassDetection(UCHAR *RESTRICT pAddHarmSfb, + UCHAR **RESTRICT pDetectionVectors, + INT start, + INT stop, + INT nSfb, + const UCHAR *RESTRICT pFreqBandTable, + FIXP_DBL *RESTRICT pNrgVector, + THRES_HOLDS mhThresh) + +{ + INT i,est; + INT maxDerivPos = pFreqBandTable[nSfb]; + INT numBands = pFreqBandTable[nSfb]; + FIXP_DBL nrgLow,nrgHigh; + FIXP_DBL nrgLD64,nrgLowLD64,nrgHighLD64,nrgDiffLD64; + FIXP_DBL valLD64,maxValLD64,maxValAboveLD64; + INT bLPsignal = 0; + + maxValLD64 = FL2FXCONST_DBL(-1.0f); + for(i = numBands - 1 - 2; i > pFreqBandTable[0];i--){ + nrgLow = pNrgVector[i]; + nrgHigh = pNrgVector[i + 2]; + + if(nrgLow != FL2FXCONST_DBL(0.0f) && nrgLow > nrgHigh){ + nrgLowLD64 = CalcLdData(nrgLow>>1); + nrgDiffLD64 = CalcLdData((nrgLow>>1)-(nrgHigh>>1)); + valLD64 = nrgDiffLD64-nrgLowLD64; + if(valLD64 > maxValLD64){ + maxDerivPos = i; + maxValLD64 = valLD64; + } + if(maxValLD64 > mhThresh.derivThresMaxLD64) { + break; + } + } + } + + /* Find the largest "gradient" above. (should be relatively flat, hence we expect a low value + if the signal is LP.*/ + maxValAboveLD64 = FL2FXCONST_DBL(-1.0f); + for(i = numBands - 1 - 2; i > maxDerivPos + 2;i--){ + nrgLow = pNrgVector[i]; + nrgHigh = pNrgVector[i + 2]; + + if(nrgLow != FL2FXCONST_DBL(0.0f) && nrgLow > nrgHigh){ + nrgLowLD64 = CalcLdData(nrgLow>>1); + nrgDiffLD64 = CalcLdData((nrgLow>>1)-(nrgHigh>>1)); + valLD64 = nrgDiffLD64-nrgLowLD64; + if(valLD64 > maxValAboveLD64){ + maxValAboveLD64 = valLD64; + } + } + else { + if(nrgHigh != FL2FXCONST_DBL(0.0f) && nrgHigh > nrgLow){ + nrgHighLD64 = CalcLdData(nrgHigh>>1); + nrgDiffLD64 = CalcLdData((nrgHigh>>1)-(nrgLow>>1)); + valLD64 = nrgDiffLD64-nrgHighLD64; + if(valLD64 > maxValAboveLD64){ + maxValAboveLD64 = valLD64; + } + } + } + } + + if(maxValLD64 > mhThresh.derivThresMaxLD64 && maxValAboveLD64 < mhThresh.derivThresAboveLD64){ + bLPsignal = 1; + + for(i = maxDerivPos - 1; i > maxDerivPos - 5 && i >= 0 ; i--){ + if(pNrgVector[i] != FL2FXCONST_DBL(0.0f) && pNrgVector[i] > pNrgVector[maxDerivPos + 2]){ + nrgDiffLD64 = CalcLdData((pNrgVector[i]>>1)-(pNrgVector[maxDerivPos + 2]>>1)); + nrgLD64 = CalcLdData(pNrgVector[i]>>1); + valLD64 = nrgDiffLD64-nrgLD64; + if(valLD64 < mhThresh.derivThresBelowLD64) { + bLPsignal = 0; + break; + } + } + else{ + bLPsignal = 0; + break; + } + } + } + + if(bLPsignal){ + for(i=0;i= pFreqBandTable[i] && maxDerivPos < pFreqBandTable[i+1]) + break; + } + + if(pAddHarmSfb[i]){ + pAddHarmSfb[i] = 0; + for(est = start; est < stop ; est++){ + pDetectionVectors[est][i] = 0; + } + } + } +} + +/**************************************************************************/ +/*! + \brief Checks if it is allowed to detect a missing tone, that wasn't + detected previously. + + + \return newDetectionAllowed flag. + +*/ +/**************************************************************************/ +static INT isDetectionOfNewToneAllowed(const SBR_FRAME_INFO *pFrameInfo, + INT *pDetectionStartPos, + INT noEstPerFrame, + INT prevTransientFrame, + INT prevTransientPos, + INT prevTransientFlag, + INT transientPosOffset, + INT transientFlag, + INT transientPos, + INT deltaTime, + HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMissingHarmonicsDetector) +{ + INT transientFrame, newDetectionAllowed; + + + /* Determine if this is a frame where a transient starts... + * If the transient flag was set the previous frame but not the + * transient frame flag, the transient frame flag is set in the current frame. + *****************************************************************************/ + transientFrame = 0; + if(transientFlag){ + if(transientPos + transientPosOffset < pFrameInfo->borders[pFrameInfo->nEnvelopes]) + transientFrame = 1; + if(noEstPerFrame > 1){ + if(transientPos + transientPosOffset > h_sbrMissingHarmonicsDetector->timeSlots >> 1){ + *pDetectionStartPos = noEstPerFrame; + } + else{ + *pDetectionStartPos = noEstPerFrame >> 1; + } + + } + else{ + *pDetectionStartPos = noEstPerFrame; + } + } + else{ + if(prevTransientFlag && !prevTransientFrame){ + transientFrame = 1; + *pDetectionStartPos = 0; + } + } + + /* + * Determine if detection of new missing harmonics are allowed. + * If the frame contains a transient it's ok. If the previous + * frame contained a transient it needs to be sufficiently close + * to the start of the current frame. + ****************************************************************/ + newDetectionAllowed = 0; + if(transientFrame){ + newDetectionAllowed = 1; + } + else { + if(prevTransientFrame && + fixp_abs(pFrameInfo->borders[0] - (prevTransientPos + transientPosOffset - + h_sbrMissingHarmonicsDetector->timeSlots)) < deltaTime) + newDetectionAllowed = 1; + *pDetectionStartPos = 0; + } + + h_sbrMissingHarmonicsDetector->previousTransientFlag = transientFlag; + h_sbrMissingHarmonicsDetector->previousTransientFrame = transientFrame; + h_sbrMissingHarmonicsDetector->previousTransientPos = transientPos; + + return (newDetectionAllowed); +} + + +/**************************************************************************/ +/*! + \brief Cleans up the detection after a transient. + + + \return none. + +*/ +/**************************************************************************/ +static void transientCleanUp(FIXP_DBL **quotaBuffer, + INT nSfb, + UCHAR **detectionVectors, + UCHAR *pAddHarmSfb, + UCHAR *pPrevAddHarmSfb, + INT ** signBuffer, + const UCHAR *pFreqBandTable, + INT start, + INT stop, + INT newDetectionAllowed, + FIXP_DBL *pNrgVector, + THRES_HOLDS mhThresh) +{ + INT i,j,li, ui,est; + + for(est=start; est < stop; est++) { + for(i=0; i maxVal1){ + maxVal1 = quotaBuffer[est][j]; + maxPos1 = j; + maxPosTime1 = est; + } + } + } + + li = pFreqBandTable[i+1]; + ui = pFreqBandTable[i+2]; + + /* Find maximum tonality in the the two scf bands.*/ + maxPosTime2 = start; + maxPos2 = li; + maxVal2 = quotaBuffer[start][li]; + for(est = start; est < stop; est++){ + for(j = li; j maxVal2){ + maxVal2 = quotaBuffer[est][j]; + maxPos2 = j; + maxPosTime2 = est; + } + } + } + + /* If the maximum values are in adjacent QMF-channels, we need to remove + the lowest of the two.*/ + if(maxPos2-maxPos1 < 2){ + + if(pPrevAddHarmSfb[i] == 1 && pPrevAddHarmSfb[i+1] == 0){ + /* Keep the lower, remove the upper.*/ + pAddHarmSfb[i+1] = 0; + for(est=start; est maxVal2){ + if(signBuffer[maxPosTime1][maxPos2] < 0 && signBuffer[maxPosTime1][maxPos1] > 0){ + /* Keep the lower, remove the upper.*/ + pAddHarmSfb[i+1] = 0; + for(est=start; est 0){ + /* Keep the upper, remove the lower.*/ + pAddHarmSfb[i] = 0; + for(est=start; est 0) + pAddHarmSfb[i] = 0; + } + } +} + + +/**************************************************************************/ +/*! + \brief Do detection for one tonality estimate. + + + \return none. + +*/ +/**************************************************************************/ +static void detection(FIXP_DBL *quotaBuffer, + FIXP_DBL *pDiffVecScfb, + INT nSfb, + UCHAR *pHarmVec, + const UCHAR *pFreqBandTable, + FIXP_DBL *sfmOrig, + FIXP_DBL *sfmSbr, + GUIDE_VECTORS guideVectors, + GUIDE_VECTORS newGuideVectors, + THRES_HOLDS mhThresh) +{ + + INT i,j,ll, lu; + FIXP_DBL thresTemp,thresOrig; + + /* + * Do detection on the difference vector, i.e. the difference between + * the original and the transposed. + *********************************************************************/ + for(i=0;i thresTemp){ + pHarmVec[i] = 1; + newGuideVectors.guideVectorDiff[i] = pDiffVecScfb[i]; + } + else{ + /* If the guide wasn't zero, but the current level is to low, + start tracking the decay on the tone in the original rather + than the difference.*/ + if(guideVectors.guideVectorDiff[i] != FL2FXCONST_DBL(0.0f)){ + guideVectors.guideVectorOrig[i] = mhThresh.thresHoldToneGuide; + } + } + } + + /* + * Trace tones in the original signal that at one point + * have been detected because they will be replaced by + * multiple tones in the sbr signal. + ****************************************************/ + + for(i=0;i thresOrig){ + pHarmVec[i] = 1; + newGuideVectors.guideVectorOrig[i] = quotaBuffer[j]; + } + } + } + } + + /* + * Check for multiple sines in the transposed signal, + * where there is only one in the original. + ****************************************************/ + thresOrig = mhThresh.thresHoldTone; + + for(i=0;i 1){ + for(j= ll;j thresOrig && (sfmSbr[i] > mhThresh.sfmThresSbr && sfmOrig[i] < mhThresh.sfmThresOrig)){ + pHarmVec[i] = 1; + newGuideVectors.guideVectorOrig[i] = quotaBuffer[j]; + } + } + } + else{ + if(i < nSfb -1){ + ll = pFreqBandTable[i]; + + if(i>0){ + if(quotaBuffer[ll] > mhThresh.thresHoldTone && (pDiffVecScfb[i+1] < mhThresh.invThresHoldTone || pDiffVecScfb[i-1] < mhThresh.invThresHoldTone)){ + pHarmVec[i] = 1; + newGuideVectors.guideVectorOrig[i] = quotaBuffer[ll]; + } + } + else{ + if(quotaBuffer[ll] > mhThresh.thresHoldTone && pDiffVecScfb[i+1] < mhThresh.invThresHoldTone){ + pHarmVec[i] = 1; + newGuideVectors.guideVectorOrig[i] = quotaBuffer[ll]; + } + } + } + } + } + } +} + + +/**************************************************************************/ +/*! + \brief Do detection for every tonality estimate, using forward prediction. + + + \return none. + +*/ +/**************************************************************************/ +static void detectionWithPrediction(FIXP_DBL **quotaBuffer, + FIXP_DBL **pDiffVecScfb, + INT ** signBuffer, + INT nSfb, + const UCHAR* pFreqBandTable, + FIXP_DBL **sfmOrig, + FIXP_DBL **sfmSbr, + UCHAR **detectionVectors, + UCHAR *pPrevAddHarmSfb, + GUIDE_VECTORS *guideVectors, + INT noEstPerFrame, + INT detectionStart, + INT totNoEst, + INT newDetectionAllowed, + INT *pAddHarmFlag, + UCHAR *pAddHarmSfb, + FIXP_DBL *pNrgVector, + const DETECTOR_PARAMETERS_MH *mhParams) +{ + INT est = 0,i; + INT start; + + FDKmemclear(pAddHarmSfb,nSfb*sizeof(UCHAR)); + + if(newDetectionAllowed){ + + if(totNoEst > 1){ + start = detectionStart; + + if (start != 0) { + FDKmemcpy(guideVectors[start].guideVectorDiff,guideVectors[0].guideVectorDiff,nSfb*sizeof(FIXP_DBL)); + FDKmemcpy(guideVectors[start].guideVectorOrig,guideVectors[0].guideVectorOrig,nSfb*sizeof(FIXP_DBL)); + FDKmemclear(guideVectors[start-1].guideVectorDetected,nSfb*sizeof(UCHAR)); + } + } + else{ + start = 0; + } + } + else{ + start = 0; + } + + + for(est = start; est < totNoEst; est++){ + + /* + * Do detection on the current frame using + * guide-info from the previous. + *******************************************/ + if(est > 0){ + FDKmemcpy(guideVectors[est].guideVectorDetected,detectionVectors[est-1],nSfb*sizeof(UCHAR)); + } + + FDKmemclear(detectionVectors[est], nSfb*sizeof(UCHAR)); + + if(est < totNoEst-1){ + FDKmemclear(guideVectors[est+1].guideVectorDiff,nSfb*sizeof(FIXP_DBL)); + FDKmemclear(guideVectors[est+1].guideVectorOrig,nSfb*sizeof(FIXP_DBL)); + FDKmemclear(guideVectors[est+1].guideVectorDetected,nSfb*sizeof(UCHAR)); + + detection(quotaBuffer[est], + pDiffVecScfb[est], + nSfb, + detectionVectors[est], + pFreqBandTable, + sfmOrig[est], + sfmSbr[est], + guideVectors[est], + guideVectors[est+1], + mhParams->thresHolds); + } + else{ + FDKmemclear(guideVectors[est].guideVectorDiff,nSfb*sizeof(FIXP_DBL)); + FDKmemclear(guideVectors[est].guideVectorOrig,nSfb*sizeof(FIXP_DBL)); + FDKmemclear(guideVectors[est].guideVectorDetected,nSfb*sizeof(UCHAR)); + + detection(quotaBuffer[est], + pDiffVecScfb[est], + nSfb, + detectionVectors[est], + pFreqBandTable, + sfmOrig[est], + sfmSbr[est], + guideVectors[est], + guideVectors[est], + mhParams->thresHolds); + } + } + + + /* Clean up the detection.*/ + transientCleanUp(quotaBuffer, + nSfb, + detectionVectors, + pAddHarmSfb, + pPrevAddHarmSfb, + signBuffer, + pFreqBandTable, + start, + totNoEst, + newDetectionAllowed, + pNrgVector, + mhParams->thresHolds); + + + /* Set flag... */ + *pAddHarmFlag = 0; + for(i=0; i maxVal){ + maxVal = pTonalityMatrix[est][l]; + maxPosF = l; + maxPosT = est; + } + } + } + + /* + * If the maximum tonality is at the lower border of the + * scalefactor band, we check the sign of the adjacent channels + * to see if this sine is shared by the lower channel. If so, the + * energy of the single sine will be present in two scalefactor bands + * in the SBR data, which will cause problems in the decoder, when we + * add a sine to just one of the channels. + *********************************************************************/ + if(maxPosF == ll && scfBand){ + if(!pAddHarmSfb[scfBand - 1]) { /* No detection below*/ + if (pSignMatrix[maxPosT][maxPosF - 1] > 0 && pSignMatrix[maxPosT][maxPosF] < 0) { + /* The comp value is calulated as the tonallity value, i.e we want to + reduce the envelope data for this channel with as much as the tonality + that is spread from the channel above. (ld64(RELAXATION) = 0.31143075889) */ + tmp = fixp_abs((FIXP_DBL)CalcLdData(pTonalityMatrix[maxPosT][maxPosF - 1]) + RELAXATION_LD64); + tmp = (tmp >> (DFRACT_BITS-1-LD_DATA_SHIFT-1)) + (FIXP_DBL)1; /* shift one bit less for rounding */ + compValue = ((INT)(LONG)tmp) >> 1; + + /* limit the comp-value*/ + if (compValue > maxComp) + compValue = maxComp; + + pEnvComp[scfBand-1] = compValue; + } + } + } + + /* + * Same as above, but for the upper end of the scalefactor-band. + ***************************************************************/ + if(maxPosF == lu-1 && scfBand+1 < nSfb){ /* Upper border*/ + if(!pAddHarmSfb[scfBand + 1]) { + if (pSignMatrix[maxPosT][maxPosF] > 0 && pSignMatrix[maxPosT][maxPosF + 1] < 0) { + tmp = fixp_abs((FIXP_DBL)CalcLdData(pTonalityMatrix[maxPosT][maxPosF + 1]) + RELAXATION_LD64); + tmp = (tmp >> (DFRACT_BITS-1-LD_DATA_SHIFT-1)) + (FIXP_DBL)1; /* shift one bit less for rounding */ + compValue = ((INT)(LONG)tmp) >> 1; + + if (compValue > maxComp) + compValue = maxComp; + + pEnvComp[scfBand+1] = compValue; + } + } + } + } + } + + if(newDetectionAllowed == 0){ + for(scfBand=0;scfBanddetectionVectors; + INT move = h_sbrMHDet->move; + INT noEstPerFrame = h_sbrMHDet->noEstPerFrame; + INT totNoEst = h_sbrMHDet->totNoEst; + INT prevTransientFlag = h_sbrMHDet->previousTransientFlag; + INT prevTransientFrame = h_sbrMHDet->previousTransientFrame; + INT transientPosOffset = h_sbrMHDet->transientPosOffset; + INT prevTransientPos = h_sbrMHDet->previousTransientPos; + GUIDE_VECTORS* guideVectors = h_sbrMHDet->guideVectors; + INT deltaTime = h_sbrMHDet->mhParams->deltaTime; + INT maxComp = h_sbrMHDet->mhParams->maxComp; + + int est; + + /* + Buffer values. + */ + FDK_ASSERT(move<=(MAX_NO_OF_ESTIMATES>>1)); + FDK_ASSERT(noEstPerFrame<=(MAX_NO_OF_ESTIMATES>>1)); + + FIXP_DBL *sfmSbr[MAX_NO_OF_ESTIMATES]; + FIXP_DBL *sfmOrig[MAX_NO_OF_ESTIMATES]; + FIXP_DBL *tonalityDiff[MAX_NO_OF_ESTIMATES]; + + for (est=0; est < MAX_NO_OF_ESTIMATES/2; est++) { + sfmSbr[est] = h_sbrMHDet->sfmSbr[est]; + sfmOrig[est] = h_sbrMHDet->sfmOrig[est]; + tonalityDiff[est] = h_sbrMHDet->tonalityDiff[est]; + } + + C_ALLOC_SCRATCH_START(scratch_mem, FIXP_DBL, (3*MAX_NO_OF_ESTIMATES/2*MAX_FREQ_COEFFS)); + FIXP_DBL *scratch = scratch_mem; + for (; est < MAX_NO_OF_ESTIMATES; est++) { + sfmSbr[est] = scratch; scratch+=MAX_FREQ_COEFFS; + sfmOrig[est] = scratch; scratch+=MAX_FREQ_COEFFS; + tonalityDiff[est] = scratch; scratch+=MAX_FREQ_COEFFS; + } + + + + /* Determine if we're allowed to detect "missing harmonics" that wasn't detected before. + In order to be allowed to do new detection, there must be a transient in the current + frame, or a transient in the previous frame sufficiently close to the current frame. */ + newDetectionAllowed = isDetectionOfNewToneAllowed(pFrameInfo, + &transientDetStart, + noEstPerFrame, + prevTransientFrame, + prevTransientPos, + prevTransientFlag, + transientPosOffset, + transientFlag, + transientPos, + deltaTime, + h_sbrMHDet); + + /* Calulate the variables that will be used subsequently for the actual detection */ + calculateDetectorInput(pQuotaBuffer, + indexVector, + tonalityDiff, + sfmOrig, + sfmSbr, + freqBandTable, + nSfb, + noEstPerFrame, + move); + + /* Do the actual detection using information from previous detections */ + detectionWithPrediction(pQuotaBuffer, + tonalityDiff, + pSignBuffer, + nSfb, + freqBandTable, + sfmOrig, + sfmSbr, + detectionVectors, + h_sbrMHDet->guideScfb, + guideVectors, + noEstPerFrame, + transientDetStart, + totNoEst, + newDetectionAllowed, + pAddHarmonicsFlag, + pAddHarmonicsScaleFactorBands, + pNrgVector, + h_sbrMHDet->mhParams); + + /* Calculate the comp vector, so that the energy can be + compensated for a sine between two QMF-bands. */ + calculateCompVector(pAddHarmonicsScaleFactorBands, + pQuotaBuffer, + pSignBuffer, + envelopeCompensation, + nSfb, + freqBandTable, + totNoEst, + maxComp, + h_sbrMHDet->prevEnvelopeCompensation, + newDetectionAllowed); + + for (est=0; est < move; est++) { + FDKmemcpy(tonalityDiff[est], tonalityDiff[est + noEstPerFrame], sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + FDKmemcpy(sfmOrig[est], sfmOrig[est + noEstPerFrame], sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + FDKmemcpy(sfmSbr[est], sfmSbr[est + noEstPerFrame], sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + } + C_ALLOC_SCRATCH_END(scratch, FIXP_DBL, (3*MAX_NO_OF_ESTIMATES/2*MAX_FREQ_COEFFS)); + + +} + +/**************************************************************************/ +/*! + \brief Initialize an instance of the missing harmonics detector. + + + \return errorCode, noError if OK. + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_CreateSbrMissingHarmonicsDetector ( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet, + INT chan) +{ + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hs = hSbrMHDet; + INT i; + + UCHAR* detectionVectors = GetRam_Sbr_detectionVectors(chan); + UCHAR* guideVectorDetected = GetRam_Sbr_guideVectorDetected(chan); + FIXP_DBL* guideVectorDiff = GetRam_Sbr_guideVectorDiff(chan); + FIXP_DBL* guideVectorOrig = GetRam_Sbr_guideVectorOrig(chan); + + FDKmemclear (hs,sizeof(SBR_MISSING_HARMONICS_DETECTOR)); + + hs->prevEnvelopeCompensation = GetRam_Sbr_prevEnvelopeCompensation(chan); + hs->guideScfb = GetRam_Sbr_guideScfb(chan); + + for(i=0; iguideVectors[i].guideVectorDiff = guideVectorDiff + (i*MAX_FREQ_COEFFS); + hs->guideVectors[i].guideVectorOrig = guideVectorOrig + (i*MAX_FREQ_COEFFS); + hs->detectionVectors[i] = detectionVectors + (i*MAX_FREQ_COEFFS); + hs->guideVectors[i].guideVectorDetected = guideVectorDetected + (i*MAX_FREQ_COEFFS); + } + + return 0; +} + + +/**************************************************************************/ +/*! + \brief Initialize an instance of the missing harmonics detector. + + + \return errorCode, noError if OK. + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_InitSbrMissingHarmonicsDetector ( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet, + INT sampleFreq, + INT frameSize, + INT nSfb, + INT qmfNoChannels, + INT totNoEst, + INT move, + INT noEstPerFrame, + UINT sbrSyntaxFlags + ) +{ + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hs = hSbrMHDet; + int i; + + FDK_ASSERT(totNoEst <= MAX_NO_OF_ESTIMATES); + + switch(frameSize){ + case 2048: + hs->transientPosOffset = FRAME_MIDDLE_SLOT_2048; + hs->timeSlots = NUMBER_TIME_SLOTS_2048; + break; + case 1920: + hs->transientPosOffset = FRAME_MIDDLE_SLOT_1920; + hs->timeSlots = NUMBER_TIME_SLOTS_1920; + break; + case 1024: + hs->transientPosOffset = FRAME_MIDDLE_SLOT_512LD; + hs->timeSlots = 16; + break; + case 960: + hs->transientPosOffset = FRAME_MIDDLE_SLOT_512LD; + hs->timeSlots = 15; + break; + default: + return -1; + } + + if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + hs->mhParams = ¶msAacLd; + } else + hs->mhParams = ¶msAac; + + hs->qmfNoChannels = qmfNoChannels; + hs->sampleFreq = sampleFreq; + hs->nSfb = nSfb; + + hs->totNoEst = totNoEst; + hs->move = move; + hs->noEstPerFrame = noEstPerFrame; + + for(i=0; iguideVectors[i].guideVectorDiff,sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + FDKmemclear (hs->guideVectors[i].guideVectorOrig,sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + FDKmemclear (hs->detectionVectors[i],sizeof(UCHAR)*MAX_FREQ_COEFFS); + FDKmemclear (hs->guideVectors[i].guideVectorDetected,sizeof(UCHAR)*MAX_FREQ_COEFFS); + } + + //for(i=0; itonalityDiff[i],sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + FDKmemclear (hs->sfmOrig[i],sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + FDKmemclear (hs->sfmSbr[i],sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + } + + FDKmemclear ( hs->prevEnvelopeCompensation, sizeof(UCHAR)*MAX_FREQ_COEFFS); + FDKmemclear ( hs->guideScfb, sizeof(UCHAR)*MAX_FREQ_COEFFS); + + hs->previousTransientFlag = 0; + hs->previousTransientFrame = 0; + hs->previousTransientPos = 0; + + return (0); +} + +/**************************************************************************/ +/*! + \brief Deletes an instance of the missing harmonics detector. + + + \return none. + +*/ +/**************************************************************************/ +void +FDKsbrEnc_DeleteSbrMissingHarmonicsDetector(HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet) +{ + if (hSbrMHDet) { + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hs = hSbrMHDet; + + FreeRam_Sbr_detectionVectors(&hs->detectionVectors[0]); + FreeRam_Sbr_guideVectorDetected(&hs->guideVectors[0].guideVectorDetected); + FreeRam_Sbr_guideVectorDiff(&hs->guideVectors[0].guideVectorDiff); + FreeRam_Sbr_guideVectorOrig(&hs->guideVectors[0].guideVectorOrig); + FreeRam_Sbr_prevEnvelopeCompensation(&hs->prevEnvelopeCompensation); + FreeRam_Sbr_guideScfb(&hs->guideScfb); + + } +} + +/**************************************************************************/ +/*! + \brief Resets an instance of the missing harmonics detector. + + + \return error code, noError if OK. + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_ResetSbrMissingHarmonicsDetector (HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMissingHarmonicsDetector, + INT nSfb) +{ + int i; + FIXP_DBL tempGuide[MAX_FREQ_COEFFS]; + UCHAR tempGuideInt[MAX_FREQ_COEFFS]; + INT nSfbPrev; + + nSfbPrev = hSbrMissingHarmonicsDetector->nSfb; + hSbrMissingHarmonicsDetector->nSfb = nSfb; + + FDKmemcpy( tempGuideInt, hSbrMissingHarmonicsDetector->guideScfb, nSfbPrev * sizeof(UCHAR) ); + + if ( nSfb > nSfbPrev ) { + for ( i = 0; i < (nSfb - nSfbPrev); i++ ) { + hSbrMissingHarmonicsDetector->guideScfb[i] = 0; + } + + for ( i = 0; i < nSfbPrev; i++ ) { + hSbrMissingHarmonicsDetector->guideScfb[i + (nSfb - nSfbPrev)] = tempGuideInt[i]; + } + } + else { + for ( i = 0; i < nSfb; i++ ) { + hSbrMissingHarmonicsDetector->guideScfb[i] = tempGuideInt[i + (nSfbPrev-nSfb)]; + } + } + + FDKmemcpy ( tempGuide, hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff, nSfbPrev * sizeof(FIXP_DBL) ); + + if (nSfb > nSfbPrev ) { + for ( i = 0; i < (nSfb - nSfbPrev); i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff[i] = FL2FXCONST_DBL(0.0f); + } + + for ( i = 0; i < nSfbPrev; i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff[i + (nSfb - nSfbPrev)] = tempGuide[i]; + } + } + else { + for ( i = 0; i < nSfb; i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff[i] = tempGuide[i + (nSfbPrev-nSfb)]; + } + } + + FDKmemcpy ( tempGuide, hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig, nSfbPrev * sizeof(FIXP_DBL) ); + + if ( nSfb > nSfbPrev ) { + for ( i = 0; i< (nSfb - nSfbPrev); i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig[i] = FL2FXCONST_DBL(0.0f); + } + + for ( i = 0; i < nSfbPrev; i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig[i + (nSfb - nSfbPrev)] = tempGuide[i]; + } + } + else { + for ( i = 0; i < nSfb; i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig[i] = tempGuide[i + (nSfbPrev-nSfb)]; + } + } + + FDKmemcpy ( tempGuideInt, hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected, nSfbPrev * sizeof(UCHAR) ); + + if ( nSfb > nSfbPrev ) { + for ( i = 0; i < (nSfb - nSfbPrev); i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected[i] = 0; + } + + for ( i = 0; i < nSfbPrev; i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected[i + (nSfb - nSfbPrev)] = tempGuideInt[i]; + } + } + else { + for ( i = 0; i < nSfb; i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected[i] = tempGuideInt[i + (nSfbPrev-nSfb)]; + } + } + + FDKmemcpy ( tempGuideInt, hSbrMissingHarmonicsDetector->prevEnvelopeCompensation, nSfbPrev * sizeof(UCHAR) ); + + if ( nSfb > nSfbPrev ) { + for ( i = 0; i < (nSfb - nSfbPrev); i++ ) { + hSbrMissingHarmonicsDetector->prevEnvelopeCompensation[i] = 0; + } + + for ( i = 0; i < nSfbPrev; i++ ) { + hSbrMissingHarmonicsDetector->prevEnvelopeCompensation[i + (nSfb - nSfbPrev)] = tempGuideInt[i]; + } + } + else { + for ( i = 0; i < nSfb; i++ ) { + hSbrMissingHarmonicsDetector->prevEnvelopeCompensation[i] = tempGuideInt[i + (nSfbPrev-nSfb)]; + } + } + + return 0; +} + diff --git a/libSBRenc/src/mh_det.h b/libSBRenc/src/mh_det.h new file mode 100644 index 0000000..3c4ca7d --- /dev/null +++ b/libSBRenc/src/mh_det.h @@ -0,0 +1,138 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief missing harmonics detection header file $Revision: 36847 $ +*/ + +#ifndef __MH_DETECT_H +#define __MH_DETECT_H + +#include "sbr_encoder.h" +#include "fram_gen.h" + +typedef struct +{ + FIXP_DBL thresHoldDiff; /*!< threshold for tonality difference */ + FIXP_DBL thresHoldDiffGuide; /*!< threshold for tonality difference for the guide */ + FIXP_DBL thresHoldTone; /*!< threshold for tonality for a sine */ + FIXP_DBL invThresHoldTone; + FIXP_DBL thresHoldToneGuide; /*!< threshold for tonality for a sine for the guide */ + FIXP_DBL sfmThresSbr; /*!< tonality flatness measure threshold for the SBR signal.*/ + FIXP_DBL sfmThresOrig; /*!< tonality flatness measure threshold for the original signal.*/ + FIXP_DBL decayGuideOrig; /*!< decay value of the tonality value of the guide for the tone. */ + FIXP_DBL decayGuideDiff; /*!< decay value of the tonality value of the guide for the tonality difference. */ + FIXP_DBL derivThresMaxLD64; /*!< threshold for detecting LP character in a signal. */ + FIXP_DBL derivThresBelowLD64; /*!< threshold for detecting LP character in a signal. */ + FIXP_DBL derivThresAboveLD64; /*!< threshold for detecting LP character in a signal. */ +}THRES_HOLDS; + +typedef struct +{ + INT deltaTime; /*!< maximum allowed transient distance (from frame border in number of qmf subband sample) + for a frame to be considered a transient frame.*/ + THRES_HOLDS thresHolds; /*!< the thresholds used for detection. */ + INT maxComp; /*!< maximum alllowed compensation factor for the envelope data. */ +}DETECTOR_PARAMETERS_MH; + +typedef struct +{ + FIXP_DBL *guideVectorDiff; + FIXP_DBL *guideVectorOrig; + UCHAR* guideVectorDetected; +}GUIDE_VECTORS; + + +typedef struct +{ + INT qmfNoChannels; + INT nSfb; + INT sampleFreq; + INT previousTransientFlag; + INT previousTransientFrame; + INT previousTransientPos; + + INT noVecPerFrame; + INT transientPosOffset; + + INT move; + INT totNoEst; + INT noEstPerFrame; + INT timeSlots; + + UCHAR *guideScfb; + UCHAR *prevEnvelopeCompensation; + UCHAR *detectionVectors[MAX_NO_OF_ESTIMATES]; + FIXP_DBL tonalityDiff[MAX_NO_OF_ESTIMATES/2][MAX_FREQ_COEFFS]; + FIXP_DBL sfmOrig[MAX_NO_OF_ESTIMATES/2][MAX_FREQ_COEFFS]; + FIXP_DBL sfmSbr[MAX_NO_OF_ESTIMATES/2][MAX_FREQ_COEFFS]; + const DETECTOR_PARAMETERS_MH *mhParams; + GUIDE_VECTORS guideVectors[MAX_NO_OF_ESTIMATES]; +} +SBR_MISSING_HARMONICS_DETECTOR; + +typedef SBR_MISSING_HARMONICS_DETECTOR *HANDLE_SBR_MISSING_HARMONICS_DETECTOR; + +void +FDKsbrEnc_SbrMissingHarmonicsDetectorQmf(HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMissingHarmonicsDetector, + FIXP_DBL ** pQuotaBuffer, + INT ** pSignBuffer, + SCHAR *indexVector, + const SBR_FRAME_INFO *pFrameInfo, + const UCHAR* pTranInfo, + INT* pAddHarmonicsFlag, + UCHAR* pAddHarmonicsScaleFactorBands, + const UCHAR* freqBandTable, + INT nSfb, + UCHAR * envelopeCompensation, + FIXP_DBL *pNrgVector); + +INT +FDKsbrEnc_CreateSbrMissingHarmonicsDetector ( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet, + INT chan); + +INT +FDKsbrEnc_InitSbrMissingHarmonicsDetector( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMissingHarmonicsDetector, + INT sampleFreq, + INT frameSize, + INT nSfb, + INT qmfNoChannels, + INT totNoEst, + INT move, + INT noEstPerFrame, + UINT sbrSyntaxFlags); + +void +FDKsbrEnc_DeleteSbrMissingHarmonicsDetector (HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMissingHarmonicsDetector); + + +INT +FDKsbrEnc_ResetSbrMissingHarmonicsDetector (HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMissingHarmonicsDetector, + INT nSfb); + +#endif diff --git a/libSBRenc/src/nf_est.cpp b/libSBRenc/src/nf_est.cpp new file mode 100644 index 0000000..168698d --- /dev/null +++ b/libSBRenc/src/nf_est.cpp @@ -0,0 +1,518 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +#include "nf_est.h" + +#include "sbr_misc.h" + +#include "genericStds.h" + +/* smoothFilter[4] = {0.05857864376269f, 0.2f, 0.34142135623731f, 0.4f}; */ +static const FIXP_DBL smoothFilter[4] = { 0x077f813d, 0x19999995, 0x2bb3b1f5, 0x33333335 }; + +/* static const INT smoothFilterLength = 4; */ + +static const FIXP_DBL QuantOffset = (INT)0xfc000000; /* ld64(0.25) */ + +#ifndef min +#define min(a,b) ( a < b ? a:b) +#endif + +#ifndef max +#define max(a,b) ( a > b ? a:b) +#endif + +#define NOISE_FLOOR_OFFSET_SCALING (3) + + + +/**************************************************************************/ +/*! + \brief The function applies smoothing to the noise levels. + + + + \return none + +*/ +/**************************************************************************/ +static void +smoothingOfNoiseLevels(FIXP_DBL *NoiseLevels, /*!< pointer to noise-floor levels.*/ + INT nEnvelopes, /*!< Number of noise floor envelopes.*/ + INT noNoiseBands, /*!< Number of noise bands for every noise floor envelope. */ + FIXP_DBL prevNoiseLevels[NF_SMOOTHING_LENGTH][MAX_NUM_NOISE_VALUES],/*!< Previous noise floor envelopes. */ + const FIXP_DBL *smoothFilter, /*!< filter used for smoothing the noise floor levels. */ + INT transientFlag) /*!< flag indicating if a transient is present*/ + +{ + INT i,band,env; + FIXP_DBL accu; + + for(env = 0; env < nEnvelopes; env++){ + if(transientFlag){ + for (i = 0; i < NF_SMOOTHING_LENGTH; i++){ + FDKmemcpy(prevNoiseLevels[i],NoiseLevels+env*noNoiseBands,noNoiseBands*sizeof(FIXP_DBL)); + } + } + else { + for (i = 1; i < NF_SMOOTHING_LENGTH; i++){ + FDKmemcpy(prevNoiseLevels[i - 1],prevNoiseLevels[i],noNoiseBands*sizeof(FIXP_DBL)); + } + FDKmemcpy(prevNoiseLevels[NF_SMOOTHING_LENGTH - 1],NoiseLevels+env*noNoiseBands,noNoiseBands*sizeof(FIXP_DBL)); + } + + for (band = 0; band < noNoiseBands; band++){ + accu = FL2FXCONST_DBL(0.0f); + for (i = 0; i < NF_SMOOTHING_LENGTH; i++){ + accu += fMultDiv2(smoothFilter[i], prevNoiseLevels[i][band]); + } + FDK_ASSERT( (band + env*noNoiseBands) < MAX_NUM_NOISE_VALUES); + NoiseLevels[band+ env*noNoiseBands] = accu<<1; + } + } +} + +/**************************************************************************/ +/*! + \brief Does the noise floor level estiamtion. + + The noiseLevel samples are scaled by the factor 0.25 + + \return none + +*/ +/**************************************************************************/ +static void +qmfBasedNoiseFloorDetection(FIXP_DBL *noiseLevel, /*!< Pointer to vector to store the noise levels in.*/ + FIXP_DBL ** quotaMatrixOrig, /*!< Matrix holding the quota values of the original. */ + SCHAR *indexVector, /*!< Index vector to obtain the patched data. */ + INT startIndex, /*!< Start index. */ + INT stopIndex, /*!< Stop index. */ + INT startChannel, /*!< Start channel of the current noise floor band.*/ + INT stopChannel, /*!< Stop channel of the current noise floor band. */ + FIXP_DBL ana_max_level, /*!< Maximum level of the adaptive noise.*/ + FIXP_DBL noiseFloorOffset, /*!< Noise floor offset. */ + INT missingHarmonicFlag, /*!< Flag indicating if a strong tonal component is missing.*/ + FIXP_DBL weightFac, /*!< Weightening factor for the difference between orig and sbr. */ + INVF_MODE diffThres, /*!< Threshold value to control the inverse filtering decision.*/ + INVF_MODE inverseFilteringLevel) /*!< Inverse filtering level of the current band.*/ +{ + INT scale, l, k; + FIXP_DBL meanOrig=FL2FXCONST_DBL(0.0f), meanSbr=FL2FXCONST_DBL(0.0f), diff; + FIXP_DBL invIndex = GetInvInt(stopIndex-startIndex); + FIXP_DBL invChannel = GetInvInt(stopChannel-startChannel); + FIXP_DBL accu; + + /* + Calculate the mean value, over the current time segment, for the original, the HFR + and the difference, over all channels in the current frequency range. + */ + + if(missingHarmonicFlag == 1){ + for(l = startChannel; l < stopChannel;l++){ + /* tonalityOrig */ + accu = FL2FXCONST_DBL(0.0f); + for(k = startIndex ; k < stopIndex; k++){ + accu += fMultDiv2(quotaMatrixOrig[k][l], invIndex); + } + meanOrig = fixMax(meanOrig,(accu<<1)); + + /* tonalitySbr */ + accu = FL2FXCONST_DBL(0.0f); + for(k = startIndex ; k < stopIndex; k++){ + accu += fMultDiv2(quotaMatrixOrig[k][indexVector[l]], invIndex); + } + meanSbr = fixMax(meanSbr,(accu<<1)); + + } + } + else{ + for(l = startChannel; l < stopChannel;l++){ + /* tonalityOrig */ + accu = FL2FXCONST_DBL(0.0f); + for(k = startIndex ; k < stopIndex; k++){ + accu += fMultDiv2(quotaMatrixOrig[k][l], invIndex); + } + meanOrig += fMult((accu<<1), invChannel); + + /* tonalitySbr */ + accu = FL2FXCONST_DBL(0.0f); + for(k = startIndex ; k < stopIndex; k++){ + accu += fMultDiv2(quotaMatrixOrig[k][indexVector[l]], invIndex); + } + meanSbr += fMult((accu<<1), invChannel); + } + } + + /* Small fix to avoid noise during silent passages.*/ + if( meanOrig <= FL2FXCONST_DBL(0.000976562f*RELAXATION_FLOAT) && + meanSbr <= FL2FXCONST_DBL(0.000976562f*RELAXATION_FLOAT) ) + { + meanOrig = FL2FXCONST_DBL(101.5936673f*RELAXATION_FLOAT); + meanSbr = FL2FXCONST_DBL(101.5936673f*RELAXATION_FLOAT); + } + + meanOrig = fixMax(meanOrig,RELAXATION); + meanSbr = fixMax(meanSbr,RELAXATION); + + if (missingHarmonicFlag == 1 || + inverseFilteringLevel == INVF_MID_LEVEL || + inverseFilteringLevel == INVF_LOW_LEVEL || + inverseFilteringLevel == INVF_OFF || + inverseFilteringLevel <= diffThres) + { + diff = RELAXATION; + } + else { + accu = fDivNorm(meanSbr, meanOrig, &scale); + + diff = fixMax( RELAXATION, + fMult(RELAXATION_FRACT,fMult(weightFac,accu)) >>( RELAXATION_SHIFT-scale ) ) ; + } + + /* + * noise Level is now a positive value, i.e. + * the more harmonic the signal is the higher noise level, + * this makes no sense so we change the sign. + *********************************************************/ + accu = fDivNorm(diff, meanOrig, &scale); + scale -= 2; + + if ( (scale>0) && (accu > ((FIXP_DBL)MAXVAL_DBL)>>scale) ) { + *noiseLevel = (FIXP_DBL)MAXVAL_DBL; + } + else { + *noiseLevel = scaleValue(accu, scale); + } + + /* + * Add a noise floor offset to compensate for bias in the detector + *****************************************************************/ + if(!missingHarmonicFlag) + *noiseLevel = fMult(*noiseLevel, noiseFloorOffset)<<(NOISE_FLOOR_OFFSET_SCALING); + + /* + * check to see that we don't exceed the maximum allowed level + **************************************************************/ + *noiseLevel = fixMin(*noiseLevel, ana_max_level); /* ana_max_level is scaled with factor 0.25 */ +} + +/**************************************************************************/ +/*! + \brief Does the noise floor level estiamtion. + The function calls the Noisefloor estimation function + for the time segments decided based upon the transient + information. The block is always divided into one or two segments. + + + \return none + +*/ +/**************************************************************************/ +void +FDKsbrEnc_sbrNoiseFloorEstimateQmf(HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ + const SBR_FRAME_INFO *frame_info, /*!< Time frequency grid of the current frame. */ + FIXP_DBL *noiseLevels, /*!< Pointer to vector to store the noise levels in.*/ + FIXP_DBL **quotaMatrixOrig, /*!< Matrix holding the quota values of the original. */ + SCHAR *indexVector, /*!< Index vector to obtain the patched data. */ + INT missingHarmonicsFlag, /*!< Flag indicating if a strong tonal component will be missing. */ + INT startIndex, /*!< Start index. */ + int numberOfEstimatesPerFrame, /*!< The number of tonality estimates per frame. */ + int transientFrame, /*!< A flag indicating if a transient is present. */ + INVF_MODE* pInvFiltLevels, /*!< Pointer to the vector holding the inverse filtering levels. */ + UINT sbrSyntaxFlags + ) + +{ + + INT nNoiseEnvelopes, startPos[2], stopPos[2], env, band; + + INT noNoiseBands = h_sbrNoiseFloorEstimate->noNoiseBands; + INT *freqBandTable = h_sbrNoiseFloorEstimate->freqBandTableQmf; + + nNoiseEnvelopes = frame_info->nNoiseEnvelopes; + + if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + nNoiseEnvelopes = 1; + startPos[0] = startIndex; + stopPos[0] = startIndex + min(numberOfEstimatesPerFrame,2); + } else + if(nNoiseEnvelopes == 1){ + startPos[0] = startIndex; + stopPos[0] = startIndex + 2; + } + else{ + startPos[0] = startIndex; + stopPos[0] = startIndex + 1; + startPos[1] = startIndex + 1; + stopPos[1] = startIndex + 2; + } + + /* + * Estimate the noise floor. + **************************************/ + for(env = 0; env < nNoiseEnvelopes; env++){ + for(band = 0; band < noNoiseBands; band++){ + FDK_ASSERT( (band + env*noNoiseBands) < MAX_NUM_NOISE_VALUES); + qmfBasedNoiseFloorDetection(&noiseLevels[band + env*noNoiseBands], + quotaMatrixOrig, + indexVector, + startPos[env], + stopPos[env], + freqBandTable[band], + freqBandTable[band+1], + h_sbrNoiseFloorEstimate->ana_max_level, + h_sbrNoiseFloorEstimate->noiseFloorOffset[band], + missingHarmonicsFlag, + h_sbrNoiseFloorEstimate->weightFac, + h_sbrNoiseFloorEstimate->diffThres, + pInvFiltLevels[band]); + } + } + + + /* + * Smoothing of the values. + **************************/ + smoothingOfNoiseLevels(noiseLevels, + nNoiseEnvelopes, + h_sbrNoiseFloorEstimate->noNoiseBands, + h_sbrNoiseFloorEstimate->prevNoiseLevels, + h_sbrNoiseFloorEstimate->smoothFilter, + transientFrame); + + + /* quantisation*/ + for(env = 0; env < nNoiseEnvelopes; env++){ + for(band = 0; band < noNoiseBands; band++){ + FDK_ASSERT( (band + env*noNoiseBands) < MAX_NUM_NOISE_VALUES); + noiseLevels[band + env*noNoiseBands] = + (FIXP_DBL)NOISE_FLOOR_OFFSET_64 - (FIXP_DBL)CalcLdData(noiseLevels[band + env*noNoiseBands]+(FIXP_DBL)1) + QuantOffset; + } + } +} + +/**************************************************************************/ +/*! + \brief + + + \return errorCode, noError if successful + +*/ +/**************************************************************************/ +static INT +downSampleLoRes(INT *v_result, /*!< */ + INT num_result, /*!< */ + const UCHAR *freqBandTableRef,/*!< */ + INT num_Ref) /*!< */ +{ + INT step; + INT i,j; + INT org_length,result_length; + INT v_index[MAX_FREQ_COEFFS/2]; + + /* init */ + org_length=num_Ref; + result_length=num_result; + + v_index[0]=0; /* Always use left border */ + i=0; + while(org_length > 0) /* Create downsample vector */ + { + i++; + step=org_length/result_length; /* floor; */ + org_length=org_length - step; + result_length--; + v_index[i]=v_index[i-1]+step; + } + + if(i != num_result ) /* Should never happen */ + return (1);/* error downsampling */ + + for(j=0;j<=i;j++) /* Use downsample vector to index LoResolution vector. */ + { + v_result[j]=freqBandTableRef[v_index[j]]; + } + + return (0); +} + +/**************************************************************************/ +/*! + \brief Initialize an instance of the noise floor level estimation module. + + + \return errorCode, noError if successful + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_InitSbrNoiseFloorEstimate (HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ + INT ana_max_level, /*!< Maximum level of the adaptive noise. */ + const UCHAR *freqBandTable, /*!< Frequany band table. */ + INT nSfb, /*!< Number of frequency bands. */ + INT noiseBands, /*!< Number of noise bands per octave. */ + INT noiseFloorOffset, /*!< Noise floor offset. */ + INT timeSlots, /*!< Number of time slots in a frame. */ + UINT useSpeechConfig /*!< Flag: adapt tuning parameters according to speech */ + ) +{ + INT i, qexp, qtmp; + FIXP_DBL tmp, exp; + + FDKmemclear(h_sbrNoiseFloorEstimate,sizeof(SBR_NOISE_FLOOR_ESTIMATE)); + + h_sbrNoiseFloorEstimate->smoothFilter = smoothFilter; + if (useSpeechConfig) { + h_sbrNoiseFloorEstimate->weightFac = (FIXP_DBL)MAXVAL_DBL; + h_sbrNoiseFloorEstimate->diffThres = INVF_LOW_LEVEL; + } + else { + h_sbrNoiseFloorEstimate->weightFac = FL2FXCONST_DBL(0.25f); + h_sbrNoiseFloorEstimate->diffThres = INVF_MID_LEVEL; + } + + h_sbrNoiseFloorEstimate->timeSlots = timeSlots; + h_sbrNoiseFloorEstimate->noiseBands = noiseBands; + + /* h_sbrNoiseFloorEstimate->ana_max_level is scaled by 0.25 */ + switch(ana_max_level) + { + case 6: + h_sbrNoiseFloorEstimate->ana_max_level = (FIXP_DBL)MAXVAL_DBL; + break; + case 3: + h_sbrNoiseFloorEstimate->ana_max_level = FL2FXCONST_DBL(0.5); + break; + case -3: + h_sbrNoiseFloorEstimate->ana_max_level = FL2FXCONST_DBL(0.125); + break; + default: + /* Should not enter here */ + h_sbrNoiseFloorEstimate->ana_max_level = (FIXP_DBL)MAXVAL_DBL; + break; + } + + /* + calculate number of noise bands and allocate + */ + if(FDKsbrEnc_resetSbrNoiseFloorEstimate(h_sbrNoiseFloorEstimate,freqBandTable,nSfb)) + return(1); + + if(noiseFloorOffset == 0) { + tmp = ((FIXP_DBL)MAXVAL_DBL)>>NOISE_FLOOR_OFFSET_SCALING; + } + else { + FDK_ASSERT(noiseFloorOffset<=8); /* because of NOISE_FLOOR_OFFSET_SCALING */ + + /* Assumes the noise floor offset in tuning table are in q31 */ + /* Currently the table contains only 0 for noise floor offset */ + /* Change the qformat here when non-zero values would be filled */ + exp = fDivNorm((FIXP_DBL)noiseFloorOffset, 3, &qexp); + tmp = fPow(2, DFRACT_BITS-1, exp, qexp, &qtmp); + tmp = scaleValue(tmp, qtmp-NOISE_FLOOR_OFFSET_SCALING); + } + + for(i=0;inoNoiseBands;i++) { + h_sbrNoiseFloorEstimate->noiseFloorOffset[i] = tmp; + } + + return (0); +} + +/**************************************************************************/ +/*! + \brief Resets the current instance of the noise floor estiamtion + module. + + + \return errorCode, noError if successful + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_resetSbrNoiseFloorEstimate (HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ + const UCHAR *freqBandTable, /*!< Frequany band table. */ + INT nSfb) /*!< Number of bands in the frequency band table. */ +{ + INT k2,kx; + + /* + * Calculate number of noise bands + ***********************************/ + k2=freqBandTable[nSfb]; + kx=freqBandTable[0]; + if(h_sbrNoiseFloorEstimate->noiseBands == 0){ + h_sbrNoiseFloorEstimate->noNoiseBands = 1; + } + else{ + /* + * Calculate number of noise bands 1,2 or 3 bands/octave + ********************************************************/ + FIXP_DBL tmp, ratio, lg2; + INT ratio_e, qlg2; + + ratio = fDivNorm(k2, kx, &ratio_e); + lg2 = fLog2(ratio, ratio_e, &qlg2); + tmp = fMult((FIXP_DBL)(h_sbrNoiseFloorEstimate->noiseBands<<24), lg2); + tmp = scaleValue(tmp, qlg2-23); + + h_sbrNoiseFloorEstimate->noNoiseBands = (INT)((tmp + (FIXP_DBL)1) >> 1); + + if (h_sbrNoiseFloorEstimate->noNoiseBands > MAX_NUM_NOISE_COEFFS) + h_sbrNoiseFloorEstimate->noNoiseBands = MAX_NUM_NOISE_COEFFS; + + if( h_sbrNoiseFloorEstimate->noNoiseBands==0) + h_sbrNoiseFloorEstimate->noNoiseBands=1; + } + + + return(downSampleLoRes(h_sbrNoiseFloorEstimate->freqBandTableQmf, + h_sbrNoiseFloorEstimate->noNoiseBands, + freqBandTable,nSfb)); +} + +/**************************************************************************/ +/*! + \brief Deletes the current instancce of the noise floor level + estimation module. + + + \return none + +*/ +/**************************************************************************/ +void +FDKsbrEnc_deleteSbrNoiseFloorEstimate (HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate) /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ +{ + + if (h_sbrNoiseFloorEstimate) { + /* + nothing to do + */ + } +} diff --git a/libSBRenc/src/nf_est.h b/libSBRenc/src/nf_est.h new file mode 100644 index 0000000..ba9fb86 --- /dev/null +++ b/libSBRenc/src/nf_est.h @@ -0,0 +1,89 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +****************************************************************************/ +/*! + \file + \brief Noise floor estimation structs and prototypes $Revision: 36867 $ +*/ + +#ifndef __NF_EST_H +#define __NF_EST_H + +#include "sbr_encoder.h" +#include "fram_gen.h" + +#define NF_SMOOTHING_LENGTH 4 /*!< Smoothing length of the noise floors. */ + +typedef struct +{ + FIXP_DBL prevNoiseLevels[NF_SMOOTHING_LENGTH][MAX_NUM_NOISE_VALUES]; /*!< The previous noise levels. */ + FIXP_DBL noiseFloorOffset[MAX_NUM_NOISE_VALUES]; /*!< Noise floor offset, scaled with NOISE_FLOOR_OFFSET_SCALING */ + const FIXP_DBL *smoothFilter; /*!< Smoothing filter to use. */ + FIXP_DBL ana_max_level; /*!< Max level allowed. */ + FIXP_DBL weightFac; /*!< Weightening factor for the difference between orig and sbr. */ + INT freqBandTableQmf[MAX_NUM_NOISE_VALUES + 1]; /*!< Frequncy band table for the noise floor bands.*/ + INT noNoiseBands; /*!< Number of noisebands. */ + INT noiseBands; /*!< NoiseBands switch 4 bit.*/ + INT timeSlots; /*!< Number of timeslots in a frame. */ + INVF_MODE diffThres; /*!< Threshold value to control the inverse filtering decision */ +} +SBR_NOISE_FLOOR_ESTIMATE; + +typedef SBR_NOISE_FLOOR_ESTIMATE *HANDLE_SBR_NOISE_FLOOR_ESTIMATE; + +void +FDKsbrEnc_sbrNoiseFloorEstimateQmf(HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ + const SBR_FRAME_INFO *frame_info, /*!< Time frequency grid of the current frame. */ + FIXP_DBL *noiseLevels, /*!< Pointer to vector to store the noise levels in.*/ + FIXP_DBL **quotaMatrixOrig, /*!< Matrix holding the quota values of the original. */ + SCHAR* indexVector, /*!< Index vector to obtain the patched data. */ + INT missingHarmonicsFlag, /*!< Flag indicating if a strong tonal component will be missing. */ + INT startIndex, /*!< Start index. */ + int numberOfEstimatesPerFrame, /*!< The number of tonality estimates per frame. */ + INT transientFrame, /*!< A flag indicating if a transient is present. */ + INVF_MODE* pInvFiltLevels, /*!< Pointer to the vector holding the inverse filtering levels. */ + UINT sbrSyntaxFlags + ); + +INT +FDKsbrEnc_InitSbrNoiseFloorEstimate (HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ + INT ana_max_level, /*!< Maximum level of the adaptive noise. */ + const UCHAR *freqBandTable, /*!< Frequany band table. */ + INT nSfb, /*!< Number of frequency bands. */ + INT noiseBands, /*!< Number of noise bands per octave. */ + INT noiseFloorOffset, /*!< Noise floor offset. */ + INT timeSlots, /*!< Number of time slots in a frame. */ + UINT useSpeechConfig /*!< Flag: adapt tuning parameters according to speech */ + ); + +INT +FDKsbrEnc_resetSbrNoiseFloorEstimate (HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ + const UCHAR *freqBandTable, /*!< Frequany band table. */ + INT nSfb); /*!< Number of bands in the frequency band table. */ + +void +FDKsbrEnc_deleteSbrNoiseFloorEstimate (HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate); /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ + +#endif diff --git a/libSBRenc/src/ps_bitenc.cpp b/libSBRenc/src/ps_bitenc.cpp new file mode 100644 index 0000000..960229b --- /dev/null +++ b/libSBRenc/src/ps_bitenc.cpp @@ -0,0 +1,635 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: N. Rettelbach + contents/description: Parametric Stereo bitstream encoder + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "ps_main.h" + + +#include "ps_const.h" +#include "ps_bitenc.h" + +static +inline UCHAR FDKsbrEnc_WriteBits_ps(HANDLE_FDK_BITSTREAM hBitStream, UINT value, + const UINT numberOfBits) +{ + /* hBitStream == NULL happens here intentionally */ + if(hBitStream!=NULL){ + FDKwriteBits(hBitStream, value, numberOfBits); + } + return numberOfBits; +} + +#define SI_SBR_EXTENSION_SIZE_BITS 4 +#define SI_SBR_EXTENSION_ESC_COUNT_BITS 8 +#define SI_SBR_EXTENSION_ID_BITS 2 +#define EXTENSION_ID_PS_CODING 2 +#define PS_EXT_ID_V0 0 + +static const INT iidDeltaCoarse_Offset = 14; +static const INT iidDeltaCoarse_MaxVal = 28; +static const INT iidDeltaFine_Offset = 30; +static const INT iidDeltaFine_MaxVal = 60; + +/* PS Stereo Huffmantable: iidDeltaFreqCoarse */ +static const UINT iidDeltaFreqCoarse_Length[] = +{ + 17, 17, 17, 17, 16, 15, 13, 10, 9, 7, + 6, 5, 4, 3, 1, 3, 4, 5, 6, 6, + 8, 11, 13, 14, 14, 15, 17, 18, 18 +}; +static const UINT iidDeltaFreqCoarse_Code[] = +{ + 0x0001fffb, 0x0001fffc, 0x0001fffd, 0x0001fffa, 0x0000fffc, 0x00007ffc, 0x00001ffd, 0x000003fe, 0x000001fe, 0x0000007e, + 0x0000003c, 0x0000001d, 0x0000000d, 0x00000005, 0000000000, 0x00000004, 0x0000000c, 0x0000001c, 0x0000003d, 0x0000003e, + 0x000000fe, 0x000007fe, 0x00001ffc, 0x00003ffc, 0x00003ffd, 0x00007ffd, 0x0001fffe, 0x0003fffe, 0x0003ffff +}; + +/* PS Stereo Huffmantable: iidDeltaFreqFine */ +static const UINT iidDeltaFreqFine_Length[] = +{ + 18, 18, 18, 18, 18, 18, 18, 18, 18, 17, + 18, 17, 17, 16, 16, 15, 14, 14, 13, 12, + 12, 11, 10, 10, 8, 7, 6, 5, 4, 3, + 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 11, 12, 13, 14, 14, 15, 16, 16, 17, 17, + 18, 17, 18, 18, 18, 18, 18, 18, 18, 18, + 18 +}; +static const UINT iidDeltaFreqFine_Code[] = +{ + 0x0001feb4, 0x0001feb5, 0x0001fd76, 0x0001fd77, 0x0001fd74, 0x0001fd75, 0x0001fe8a, 0x0001fe8b, 0x0001fe88, 0x0000fe80, + 0x0001feb6, 0x0000fe82, 0x0000feb8, 0x00007f42, 0x00007fae, 0x00003faf, 0x00001fd1, 0x00001fe9, 0x00000fe9, 0x000007ea, + 0x000007fb, 0x000003fb, 0x000001fb, 0x000001ff, 0x0000007c, 0x0000003c, 0x0000001c, 0x0000000c, 0000000000, 0x00000001, + 0x00000001, 0x00000002, 0x00000001, 0x0000000d, 0x0000001d, 0x0000003d, 0x0000007d, 0x000000fc, 0x000001fc, 0x000003fc, + 0x000003f4, 0x000007eb, 0x00000fea, 0x00001fea, 0x00001fd6, 0x00003fd0, 0x00007faf, 0x00007f43, 0x0000feb9, 0x0000fe83, + 0x0001feb7, 0x0000fe81, 0x0001fe89, 0x0001fe8e, 0x0001fe8f, 0x0001fe8c, 0x0001fe8d, 0x0001feb2, 0x0001feb3, 0x0001feb0, + 0x0001feb1 +}; + +/* PS Stereo Huffmantable: iidDeltaTimeCoarse */ +static const UINT iidDeltaTimeCoarse_Length[] = +{ + 19, 19, 19, 20, 20, 20, 17, 15, 12, 10, + 8, 6, 4, 2, 1, 3, 5, 7, 9, 11, + 13, 14, 17, 19, 20, 20, 20, 20, 20 +}; +static const UINT iidDeltaTimeCoarse_Code[] = +{ + 0x0007fff9, 0x0007fffa, 0x0007fffb, 0x000ffff8, 0x000ffff9, 0x000ffffa, 0x0001fffd, 0x00007ffe, 0x00000ffe, 0x000003fe, + 0x000000fe, 0x0000003e, 0x0000000e, 0x00000002, 0000000000, 0x00000006, 0x0000001e, 0x0000007e, 0x000001fe, 0x000007fe, + 0x00001ffe, 0x00003ffe, 0x0001fffc, 0x0007fff8, 0x000ffffb, 0x000ffffc, 0x000ffffd, 0x000ffffe, 0x000fffff +}; + +/* PS Stereo Huffmantable: iidDeltaTimeFine */ +static const UINT iidDeltaTimeFine_Length[] = +{ + 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, + 15, 15, 15, 15, 15, 14, 14, 13, 13, 13, + 12, 12, 11, 10, 9, 9, 7, 6, 5, 3, + 1, 2, 5, 6, 7, 8, 9, 10, 11, 11, + 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16 +}; +static const UINT iidDeltaTimeFine_Code[] = +{ + 0x00004ed4, 0x00004ed5, 0x00004ece, 0x00004ecf, 0x00004ecc, 0x00004ed6, 0x00004ed8, 0x00004f46, 0x00004f60, 0x00002718, + 0x00002719, 0x00002764, 0x00002765, 0x0000276d, 0x000027b1, 0x000013b7, 0x000013d6, 0x000009c7, 0x000009e9, 0x000009ed, + 0x000004ee, 0x000004f7, 0x00000278, 0x00000139, 0x0000009a, 0x0000009f, 0x00000020, 0x00000011, 0x0000000a, 0x00000003, + 0x00000001, 0000000000, 0x0000000b, 0x00000012, 0x00000021, 0x0000004c, 0x0000009b, 0x0000013a, 0x00000279, 0x00000270, + 0x000004ef, 0x000004e2, 0x000009ea, 0x000009d8, 0x000013d7, 0x000013d0, 0x000027b2, 0x000027a2, 0x0000271a, 0x0000271b, + 0x00004f66, 0x00004f67, 0x00004f61, 0x00004f47, 0x00004ed9, 0x00004ed7, 0x00004ecd, 0x00004ed2, 0x00004ed3, 0x00004ed0, + 0x00004ed1 +}; + +static const INT iccDelta_Offset = 7; +static const INT iccDelta_MaxVal = 14; +/* PS Stereo Huffmantable: iccDeltaFreq */ +static const UINT iccDeltaFreq_Length[] = +{ + 14, 14, 12, 10, 7, 5, 3, 1, 2, 4, + 6, 8, 9, 11, 13 +}; +static const UINT iccDeltaFreq_Code[] = +{ + 0x00003fff, 0x00003ffe, 0x00000ffe, 0x000003fe, 0x0000007e, 0x0000001e, 0x00000006, 0000000000, 0x00000002, 0x0000000e, + 0x0000003e, 0x000000fe, 0x000001fe, 0x000007fe, 0x00001ffe +}; + +/* PS Stereo Huffmantable: iccDeltaTime */ +static const UINT iccDeltaTime_Length[] = +{ + 14, 13, 11, 9, 7, 5, 3, 1, 2, 4, + 6, 8, 10, 12, 14 +}; +static const UINT iccDeltaTime_Code[] = +{ + 0x00003ffe, 0x00001ffe, 0x000007fe, 0x000001fe, 0x0000007e, 0x0000001e, 0x00000006, 0000000000, 0x00000002, 0x0000000e, + 0x0000003e, 0x000000fe, 0x000003fe, 0x00000ffe, 0x00003fff +}; + + + +static const INT ipdDelta_Offset = 0; +static const INT ipdDelta_MaxVal = 7; +/* PS Stereo Huffmantable: ipdDeltaFreq */ +static const UINT ipdDeltaFreq_Length[] = +{ + 1, 3, 4, 4, 4, 4, 4, 4 +}; +static const UINT ipdDeltaFreq_Code[] = +{ + 0x00000001, 0000000000, 0x00000006, 0x00000004, 0x00000002, 0x00000003, 0x00000005, 0x00000007 +}; + +/* PS Stereo Huffmantable: ipdDeltaTime */ +static const UINT ipdDeltaTime_Length[] = +{ + 1, 3, 4, 5, 5, 4, 4, 3 +}; +static const UINT ipdDeltaTime_Code[] = +{ + 0x00000001, 0x00000002, 0x00000002, 0x00000003, 0x00000002, 0000000000, 0x00000003, 0x00000003 +}; + + +static const INT opdDelta_Offset = 0; +static const INT opdDelta_MaxVal = 7; +/* PS Stereo Huffmantable: opdDeltaFreq */ +static const UINT opdDeltaFreq_Length[] = +{ + 1, 3, 4, 4, 5, 5, 4, 3 +}; +static const UINT opdDeltaFreq_Code[] = +{ + 0x00000001, 0x00000001, 0x00000006, 0x00000004, 0x0000000f, 0x0000000e, 0x00000005, 0000000000, +}; + +/* PS Stereo Huffmantable: opdDeltaTime */ +static const UINT opdDeltaTime_Length[] = +{ + 1, 3, 4, 5, 5, 4, 4, 3 +}; +static const UINT opdDeltaTime_Code[] = +{ + 0x00000001, 0x00000002, 0x00000001, 0x00000007, 0x00000006, 0000000000, 0x00000002, 0x00000003 +}; + +static const INT psBands[] = +{ + PS_BANDS_COARSE, + PS_BANDS_MID, + PS_BANDS_FINE +}; + +static INT getNoBands(PS_RESOLUTION mode) +{ + if(mode>=6) + return 0; + + if(mode>=3) + mode = (PS_RESOLUTION)(mode-3); + + return psBands[mode]; +} + +static INT getIIDRes(INT iidMode) +{ + if(iidMode<3) + return PS_IID_RES_COARSE; + else + return PS_IID_RES_FINE; +} + +static INT +encodeDeltaFreq(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *val, + const INT nBands, + const UINT *codeTable, + const UINT *lengthTable, + const INT tableOffset, + const INT maxVal, + INT *error) +{ + INT bitCnt = 0; + INT lastVal = 0; + INT band; + + for(band=0;bandmaxVal) || (delta<0) ) { + *error = 1; + delta = delta>0?maxVal:0; + } + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, codeTable[delta], lengthTable[delta]); + } + + return bitCnt; +} + +static INT +encodeDeltaTime(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *val, + const INT *valLast, + const INT nBands, + const UINT *codeTable, + const UINT *lengthTable, + const INT tableOffset, + const INT maxVal, + INT *error) +{ + INT bitCnt = 0; + INT band; + + for(band=0;bandmaxVal) || (delta<0) ) { + *error = 1; + delta = delta>0?maxVal:0; + } + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, codeTable[delta], lengthTable[delta]); + } + + return bitCnt; +} + +INT FDKsbrEnc_EncodeIid(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *iidVal, + const INT *iidValLast, + const INT nBands, + const PS_IID_RESOLUTION res, + const PS_DELTA mode, + INT *error) +{ + const UINT *codeTable; + const UINT *lengthTable; + INT bitCnt = 0; + + bitCnt = 0; + + switch(mode) { + case PS_DELTA_FREQ: + switch(res) { + case PS_IID_RES_COARSE: + codeTable = iidDeltaFreqCoarse_Code; + lengthTable = iidDeltaFreqCoarse_Length; + bitCnt += encodeDeltaFreq(hBitBuf, iidVal, nBands, codeTable, + lengthTable, iidDeltaCoarse_Offset, + iidDeltaCoarse_MaxVal, error); + break; + case PS_IID_RES_FINE: + codeTable = iidDeltaFreqFine_Code; + lengthTable = iidDeltaFreqFine_Length; + bitCnt += encodeDeltaFreq(hBitBuf, iidVal, nBands, codeTable, + lengthTable, iidDeltaFine_Offset, + iidDeltaFine_MaxVal, error); + break; + default: + *error = 1; + } + break; + + case PS_DELTA_TIME: + switch(res) { + case PS_IID_RES_COARSE: + codeTable = iidDeltaTimeCoarse_Code; + lengthTable = iidDeltaTimeCoarse_Length; + bitCnt += encodeDeltaTime(hBitBuf, iidVal, iidValLast, nBands, codeTable, + lengthTable, iidDeltaCoarse_Offset, + iidDeltaCoarse_MaxVal, error); + break; + case PS_IID_RES_FINE: + codeTable = iidDeltaTimeFine_Code; + lengthTable = iidDeltaTimeFine_Length; + bitCnt += encodeDeltaTime(hBitBuf, iidVal, iidValLast, nBands, codeTable, + lengthTable, iidDeltaFine_Offset, + iidDeltaFine_MaxVal, error); + break; + default: + *error = 1; + } + break; + + default: + *error = 1; + } + + return bitCnt; +} + + +INT FDKsbrEnc_EncodeIcc(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *iccVal, + const INT *iccValLast, + const INT nBands, + const PS_DELTA mode, + INT *error) +{ + const UINT *codeTable; + const UINT *lengthTable; + INT bitCnt = 0; + + switch(mode) { + case PS_DELTA_FREQ: + codeTable = iccDeltaFreq_Code; + lengthTable = iccDeltaFreq_Length; + bitCnt += encodeDeltaFreq(hBitBuf, iccVal, nBands, codeTable, + lengthTable, iccDelta_Offset, iccDelta_MaxVal, error); + break; + + case PS_DELTA_TIME: + codeTable = iccDeltaTime_Code; + lengthTable = iccDeltaTime_Length; + + bitCnt += encodeDeltaTime(hBitBuf, iccVal, iccValLast, nBands, codeTable, + lengthTable, iccDelta_Offset, iccDelta_MaxVal, error); + break; + + default: + *error = 1; + } + + return bitCnt; +} + +INT FDKsbrEnc_EncodeIpd(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *ipdVal, + const INT *ipdValLast, + const INT nBands, + const PS_DELTA mode, + INT *error) +{ + const UINT *codeTable; + const UINT *lengthTable; + INT bitCnt = 0; + + switch(mode) { + case PS_DELTA_FREQ: + codeTable = ipdDeltaFreq_Code; + lengthTable = ipdDeltaFreq_Length; + bitCnt += encodeDeltaFreq(hBitBuf, ipdVal, nBands, codeTable, + lengthTable, ipdDelta_Offset, ipdDelta_MaxVal, error); + break; + + case PS_DELTA_TIME: + codeTable = ipdDeltaTime_Code; + lengthTable = ipdDeltaTime_Length; + + bitCnt += encodeDeltaTime(hBitBuf, ipdVal, ipdValLast, nBands, codeTable, + lengthTable, ipdDelta_Offset, ipdDelta_MaxVal, error); + break; + + default: + *error = 1; + } + + return bitCnt; +} + +INT FDKsbrEnc_EncodeOpd(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *opdVal, + const INT *opdValLast, + const INT nBands, + const PS_DELTA mode, + INT *error) +{ + const UINT *codeTable; + const UINT *lengthTable; + INT bitCnt = 0; + + switch(mode) { + case PS_DELTA_FREQ: + codeTable = opdDeltaFreq_Code; + lengthTable = opdDeltaFreq_Length; + bitCnt += encodeDeltaFreq(hBitBuf, opdVal, nBands, codeTable, + lengthTable, opdDelta_Offset, opdDelta_MaxVal, error); + break; + + case PS_DELTA_TIME: + codeTable = opdDeltaTime_Code; + lengthTable = opdDeltaTime_Length; + + bitCnt += encodeDeltaTime(hBitBuf, opdVal, opdValLast, nBands, codeTable, + lengthTable, opdDelta_Offset, opdDelta_MaxVal, error); + break; + + default: + *error = 1; + } + + return bitCnt; +} + +static INT encodeIpdOpd(HANDLE_PS_OUT psOut, + HANDLE_FDK_BITSTREAM hBitBuf ) +{ + INT bitCnt = 0; + INT error = 0; + INT env; + + FDKsbrEnc_WriteBits_ps(hBitBuf, psOut->enableIpdOpd, 1); + + if(psOut->enableIpdOpd==1) { + INT *ipdLast = psOut->ipdLast; + INT *opdLast = psOut->opdLast; + + for(env=0; envnEnvelopes; env++) { + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->deltaIPD[env], 1); + bitCnt += FDKsbrEnc_EncodeIpd( hBitBuf, + psOut->ipd[env], + ipdLast, + getNoBands((PS_RESOLUTION)psOut->iidMode), + psOut->deltaIPD[env], + &error); + + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->deltaOPD[env], 1); + bitCnt += FDKsbrEnc_EncodeOpd( hBitBuf, + psOut->opd[env], + opdLast, + getNoBands((PS_RESOLUTION)psOut->iidMode), + psOut->deltaOPD[env], + &error ); + } + /* reserved bit */ + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, 0, 1); + } + + + return bitCnt; +} + +static INT getEnvIdx(const INT nEnvelopes, const INT frameClass) +{ + INT envIdx = 0; + + switch(nEnvelopes) { + case 0: + envIdx = 0; + break; + + case 1: + if (frameClass==0) + envIdx = 1; + else + envIdx = 0; + break; + + case 2: + if (frameClass==0) + envIdx = 2; + else + envIdx = 1; + break; + + case 3: + envIdx = 2; + break; + + case 4: + envIdx = 3; + break; + + default: + /* unsupported number of envelopes */ + envIdx = 0; + } + + return envIdx; +} + + +static INT encodePSExtension(const HANDLE_PS_OUT psOut, + HANDLE_FDK_BITSTREAM hBitBuf ) +{ + INT bitCnt = 0; + + if(psOut->enableIpdOpd==1) { + INT ipdOpdBits = 0; + INT extSize = (2 + encodeIpdOpd(psOut,NULL)+7)>>3; + + if(extSize<15) { + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, extSize, 4); + } + else { + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, 15 , 4); + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, (extSize-15), 8); + } + + /* write ipd opd data */ + ipdOpdBits += FDKsbrEnc_WriteBits_ps(hBitBuf, PS_EXT_ID_V0, 2); + ipdOpdBits += encodeIpdOpd(psOut, hBitBuf ); + + /* byte align the ipd opd data */ + if(ipdOpdBits%8) + ipdOpdBits += FDKsbrEnc_WriteBits_ps(hBitBuf, 0, (8-(ipdOpdBits%8)) ); + + bitCnt += ipdOpdBits; + } + + return (bitCnt); +} + +INT FDKsbrEnc_WritePSBitstream(const HANDLE_PS_OUT psOut, + HANDLE_FDK_BITSTREAM hBitBuf ) +{ + INT psExtEnable = 0; + INT bitCnt = 0; + INT error = 0; + INT env; + + if(psOut != NULL){ + + /* PS HEADER */ + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->enablePSHeader, 1); + + if(psOut->enablePSHeader) { + + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->enableIID, 1); + if(psOut->enableIID) { + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->iidMode, 3); + } + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->enableICC, 1); + if(psOut->enableICC) { + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->iccMode, 3); + } + if(psOut->enableIpdOpd) { + psExtEnable = 1; + } + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psExtEnable, 1); + } + + /* Frame class, number of envelopes */ + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->frameClass, 1); + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, getEnvIdx(psOut->nEnvelopes, psOut->frameClass), 2); + + if(psOut->frameClass==1) { + for(env=0; envnEnvelopes; env++) { + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->frameBorder[env], 5); + } + } + + if(psOut->enableIID==1) { + INT *iidLast = psOut->iidLast; + for(env=0; envnEnvelopes; env++) { + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->deltaIID[env], 1); + bitCnt += FDKsbrEnc_EncodeIid( hBitBuf, + psOut->iid[env], + iidLast, + getNoBands((PS_RESOLUTION)psOut->iidMode), + (PS_IID_RESOLUTION)getIIDRes(psOut->iidMode), + psOut->deltaIID[env], + &error ); + + iidLast = psOut->iid[env]; + } + } + + if(psOut->enableICC==1) { + INT *iccLast = psOut->iccLast; + for(env=0; envnEnvelopes; env++) { + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->deltaICC[env], 1); + bitCnt += FDKsbrEnc_EncodeIcc( hBitBuf, + psOut->icc[env], + iccLast, + getNoBands((PS_RESOLUTION)psOut->iccMode), + psOut->deltaICC[env], + &error); + + iccLast = psOut->icc[env]; + } + } + + if(psExtEnable!=0) { + bitCnt += encodePSExtension(psOut, hBitBuf); + } + + } /* if(psOut != NULL) */ + + return bitCnt; +} + diff --git a/libSBRenc/src/ps_bitenc.h b/libSBRenc/src/ps_bitenc.h new file mode 100644 index 0000000..f91eb57 --- /dev/null +++ b/libSBRenc/src/ps_bitenc.h @@ -0,0 +1,115 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: N. Rettelbach + contents/description: Parametric Stereo bitstream encoder + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "ps_main.h" +#include "ps_const.h" +#include "FDK_bitstream.h" + +#ifndef PS_BITENC_H +#define PS_BITENC_H + +typedef struct T_PS_OUT { + + INT enablePSHeader; + INT enableIID; + INT iidMode; + INT enableICC; + INT iccMode; + INT enableIpdOpd; + + INT frameClass; + INT nEnvelopes; + /* ENV data */ + INT frameBorder[PS_MAX_ENVELOPES]; + + /* iid data */ + PS_DELTA deltaIID[PS_MAX_ENVELOPES]; + INT iid[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT iidLast[PS_MAX_BANDS]; + + /* icc data */ + PS_DELTA deltaICC[PS_MAX_ENVELOPES]; + INT icc[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT iccLast[PS_MAX_BANDS]; + + /* ipd data */ + PS_DELTA deltaIPD[PS_MAX_ENVELOPES]; + INT ipd[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT ipdLast[PS_MAX_BANDS]; + + /* opd data */ + PS_DELTA deltaOPD[PS_MAX_ENVELOPES]; + INT opd[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT opdLast[PS_MAX_BANDS]; + +} PS_OUT, *HANDLE_PS_OUT; + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +INT FDKsbrEnc_EncodeIid(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *iidVal, + const INT *iidValLast, + const INT nBands, + const PS_IID_RESOLUTION res, + const PS_DELTA mode, + INT *error); + +INT FDKsbrEnc_EncodeIcc(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *iccVal, + const INT *iccValLast, + const INT nBands, + const PS_DELTA mode, + INT *error); + +INT FDKsbrEnc_EncodeIpd(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *ipdVal, + const INT *ipdValLast, + const INT nBands, + const PS_DELTA mode, + INT *error); + +INT FDKsbrEnc_EncodeOpd(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *opdVal, + const INT *opdValLast, + const INT nBands, + const PS_DELTA mode, + INT *error); + +INT FDKsbrEnc_WritePSBitstream(const HANDLE_PS_OUT psOut, + HANDLE_FDK_BITSTREAM hBitBuf); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* #ifndef PS_BITENC_H */ diff --git a/libSBRenc/src/ps_const.h b/libSBRenc/src/ps_const.h new file mode 100644 index 0000000..20fcc88 --- /dev/null +++ b/libSBRenc/src/ps_const.h @@ -0,0 +1,65 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: N. Rettelbach + contents/description: Parametric Stereo constants + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#ifndef PS_CONST_H +#define PS_CONST_H + +typedef enum { + PS_RES_COARSE = 0, + PS_RES_MID = 1, + PS_RES_FINE = 2 +} PS_RESOLUTION; + +typedef enum { + PS_BANDS_COARSE = 10, + PS_BANDS_MID = 20, + PS_BANDS_FINE = 34, + PS_MAX_BANDS = PS_BANDS_FINE +} PS_BANDS; + +typedef enum { + PS_IID_RES_COARSE=0, + PS_IID_RES_FINE +} PS_IID_RESOLUTION; + +typedef enum { + PS_ICC_ROT_A=0, + PS_ICC_ROT_B +} PS_ICC_ROTATION_MODE; + +typedef enum { + PS_DELTA_FREQ, + PS_DELTA_TIME +} PS_DELTA; + + +typedef enum { + PS_MAX_ENVELOPES = 4 + +} PS_CONSTS; + +#endif diff --git a/libSBRenc/src/ps_encode.cpp b/libSBRenc/src/ps_encode.cpp new file mode 100644 index 0000000..1f78d66 --- /dev/null +++ b/libSBRenc/src/ps_encode.cpp @@ -0,0 +1,1068 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial Authors: M. Neuendorf, N. Rettelbach, M. Multrus + Contents/Description: PS parameter extraction, encoding + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +/*! + \file + \brief PS parameter extraction, encoding functions $Revision: 36847 $ +*/ + +#include "ps_main.h" + + +#include "sbr_ram.h" +#include "ps_encode.h" + +#include "qmf.h" + +#include "ps_const.h" +#include "sbr_misc.h" + +#include "genericStds.h" + + +inline void FDKsbrEnc_addFIXP_DBL(const FIXP_DBL *X, const FIXP_DBL *Y, FIXP_DBL *Z, INT n) +{ + for (INT i=0; i>1) + (Y[i]>>1); +} + +#define LOG10_2_10 3.01029995664f /* 10.0f*log10(2.f) */ + +static const INT iidGroupBordersLoRes[QMF_GROUPS_LO_RES + SUBQMF_GROUPS_LO_RES + 1] = +{ + 0, 1, 2, 3, 4, 5, /* 6 subqmf subbands - 0th qmf subband */ + 6, 7, /* 2 subqmf subbands - 1st qmf subband */ + 8, 9, /* 2 subqmf subbands - 2nd qmf subband */ + 10, 11, 12, 13, 14, 15, 16, 18, 21, 25, 30, 42, 71 +}; + +static const UCHAR iidGroupWidthLdLoRes[QMF_GROUPS_LO_RES + SUBQMF_GROUPS_LO_RES] = +{ + 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, + 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 4, 5 +}; + + +static const INT subband2parameter20[QMF_GROUPS_LO_RES + SUBQMF_GROUPS_LO_RES] = +{ + 1, 0, 0, 1, 2, 3, /* 6 subqmf subbands - 0th qmf subband */ + 4, 5, /* 2 subqmf subbands - 1st qmf subband */ + 6, 7, /* 2 subqmf subbands - 2nd qmf subband */ + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 +}; + + + +typedef enum { + MAX_TIME_DIFF_FRAMES = 20, + MAX_PS_NOHEADER_CNT = 10, + MAX_NOENV_CNT = 10, + DO_NOT_USE_THIS_MODE = 0x7FFFFF +} __PS_CONSTANTS; + + + +static const FIXP_DBL iidQuant_fx[15] = { + 0xce000000, 0xdc000000, 0xe4000000, 0xec000000, 0xf2000000, 0xf8000000, 0xfc000000, 0x00000000, + 0x04000000, 0x08000000, 0x0e000000, 0x14000000, 0x1c000000, 0x24000000, 0x32000000 +}; + +static const FIXP_DBL iidQuantFine_fx[31] = { + 0x9c000001, 0xa6000001, 0xb0000001, 0xba000001, 0xc4000000, 0xce000000, 0xd4000000, 0xda000000, + 0xe0000000, 0xe6000000, 0xec000000, 0xf0000000, 0xf4000000, 0xf8000000, 0xfc000000, 0x00000000, + 0x04000000, 0x08000000, 0x0c000000, 0x10000000, 0x14000000, 0x1a000000, 0x20000000, 0x26000000, + 0x2c000000, 0x32000000, 0x3c000000, 0x45ffffff, 0x4fffffff, 0x59ffffff, 0x63ffffff +}; + + + +static const FIXP_DBL iccQuant[8] = { + 0x7fffffff, 0x77ef9d7f, 0x6babc97f, 0x4ceaf27f, 0x2f0ed3c0, 0x00000000, 0xb49ba601, 0x80000000 +}; + + + + +/* + name: static HANDLE_ERROR_INFO CreatePSData() + description: Creates struct (buffer) to store ps data + returns: error code of type HANDLE_ERROR_INFO + input: none + output: - HANDLE_PS_DATA *hPsData: according handle +*/ +static HANDLE_ERROR_INFO CreatePSData(HANDLE_PS_DATA *hPsData) +{ + HANDLE_ERROR_INFO error = noError; + + *hPsData = GetRam_PsData(); + if (*hPsData==NULL) { + error = 1; + goto bail; + } + FDKmemclear(*hPsData,sizeof(PS_DATA)); + +bail: + return error; +} + + +/* + name: static HANDLE_ERROR_INFO DestroyPSData() + description: frees according data handle + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PS_DATA *hPsData + output: none +*/ +static HANDLE_ERROR_INFO DestroyPSData(HANDLE_PS_DATA *phPsData) +{ + FreeRam_PsData(phPsData); + + return noError; +} + + +static HANDLE_ERROR_INFO InitPSData(HANDLE_PS_DATA hPsData) +{ + INT i, env; + HANDLE_ERROR_INFO error = noError; + + if(hPsData != NULL){ + + FDKmemclear(hPsData,sizeof(PS_DATA)); + + for (i=0; iiidIdxLast[i] = 0; + hPsData->iccIdxLast[i] = 0; + } + + hPsData->iidEnable = hPsData->iidEnableLast = 0; + hPsData->iccEnable = hPsData->iccEnableLast = 0; + hPsData->iidQuantMode = hPsData->iidQuantModeLast = PS_IID_RES_COARSE; + hPsData->iccQuantMode = hPsData->iccQuantModeLast = PS_ICC_ROT_A; + + for(env=0; enviccDiffMode[env] = PS_DELTA_FREQ; + hPsData->iccDiffMode[env] = PS_DELTA_FREQ; + + for (i=0; iiidIdx[env][i] = 0; + hPsData->iccIdx[env][i] = 0; + } + } + + hPsData->nEnvelopesLast = 0; + + hPsData->headerCnt = MAX_PS_NOHEADER_CNT; + hPsData->iidTimeCnt = MAX_TIME_DIFF_FRAMES; + hPsData->iccTimeCnt = MAX_TIME_DIFF_FRAMES; + hPsData->noEnvCnt = MAX_NOENV_CNT; + } else { + error = ERROR(CDI, "Unable to write to hPsData."); + } + + return error; +} + +static FIXP_DBL quantizeCoef( const FIXP_DBL *RESTRICT input, + const INT nBands, + const FIXP_DBL *RESTRICT quantTable, + const INT idxOffset, + const INT nQuantSteps, + INT *RESTRICT quantOut) +{ + INT idx, band; + FIXP_DBL quantErr = FL2FXCONST_DBL(0.f); + + for (band=0; band>1)-(quantTable[idx+1]>>1)) > + fixp_abs((input[band]>>1)-(quantTable[idx]>>1)) ) + { + break; + } + } + quantErr += (fixp_abs(input[band]-quantTable[idx])>>PS_QUANT_SCALE); /* don't scale before subtraction; diff smaller (64-25)/64 */ + quantOut[band] = idx - idxOffset; + } + + return quantErr; +} + +static INT getICCMode(const INT nBands, + const INT rotType) +{ + INT mode = 0; + + switch(nBands) { + case PS_BANDS_COARSE: + mode = PS_RES_COARSE; + break; + case PS_BANDS_MID: + mode = PS_RES_MID; + break; + case PS_BANDS_FINE: + mode = PS_RES_FINE; + break; + default: + mode = 0; + } + if(rotType==PS_ICC_ROT_B){ + mode += 3; + } + + return mode; +} + + +static INT getIIDMode(const INT nBands, + const INT iidRes) +{ + INT mode = 0; + + switch(nBands) { + case PS_BANDS_COARSE: + mode = PS_RES_COARSE; + break; + case PS_BANDS_MID: + mode = PS_RES_MID; + break; + case PS_BANDS_FINE: + mode = PS_RES_FINE; + break; + default: + mode = 0; + break; + } + + if(iidRes == PS_IID_RES_FINE){ + mode += 3; + } + + return mode; +} + + +static INT envelopeReducible(FIXP_DBL iid[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL icc[PS_MAX_ENVELOPES][PS_MAX_BANDS], + INT psBands, + INT nEnvelopes) +{ + #define THRESH_SCALE 7 + + INT reducible = 1; /* true */ + INT e = 0, b = 0; + FIXP_DBL dIid = FL2FXCONST_DBL(0.f); + FIXP_DBL dIcc = FL2FXCONST_DBL(0.f); + + FIXP_DBL iidErrThreshold, iccErrThreshold; + FIXP_DBL iidMeanError, iccMeanError; + + /* square values to prevent sqrt, + multiply bands to prevent division; bands shifted DFRACT_BITS instead (DFRACT_BITS-1) because fMultDiv2 used*/ + iidErrThreshold = fMultDiv2 ( FL2FXCONST_DBL(6.5f*6.5f/(IID_SCALE_FT*IID_SCALE_FT)), (FIXP_DBL)(psBands<<((DFRACT_BITS)-THRESH_SCALE)) ); + iccErrThreshold = fMultDiv2 ( FL2FXCONST_DBL(0.75f*0.75f), (FIXP_DBL)(psBands<<((DFRACT_BITS)-THRESH_SCALE)) ); + + if (nEnvelopes <= 1) { + reducible = 0; + } else { + + /* mean error criterion */ + for (e=0; (e < nEnvelopes/2) && (reducible!=0 ) ; e++) { + iidMeanError = iccMeanError = FL2FXCONST_DBL(0.f); + for(b=0; b>1) - (iid[2*e+1][b]>>1); /* scale 1 bit; squared -> 2 bit */ + dIcc = (icc[2*e][b]>>1) - (icc[2*e+1][b]>>1); + iidMeanError += fPow2Div2(dIid)>>(5-1); /* + (bands=20) scale = 5 */ + iccMeanError += fPow2Div2(dIcc)>>(5-1); + } /* --> scaling = 7 bit = THRESH_SCALE !! */ + + /* instead sqrt values are squared! + instead of division, multiply threshold with psBands + scaling necessary!! */ + + /* quit as soon as threshold is reached */ + if ( (iidMeanError > (iidErrThreshold)) || + (iccMeanError > (iccErrThreshold)) ) { + reducible = 0; + } + } + } /* nEnvelopes != 1 */ + + return reducible; +} + + +static void processIidData(PS_DATA *psData, + FIXP_DBL iid[PS_MAX_ENVELOPES][PS_MAX_BANDS], + const INT psBands, + const INT nEnvelopes, + const FIXP_DBL quantErrorThreshold) +{ + INT iidIdxFine [PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT iidIdxCoarse[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + + FIXP_DBL errIID = FL2FXCONST_DBL(0.f); + FIXP_DBL errIIDFine = FL2FXCONST_DBL(0.f); + INT bitsIidFreq = 0; + INT bitsIidTime = 0; + INT bitsFineTot = 0; + INT bitsCoarseTot = 0; + INT error = 0; + INT env, band; + INT diffMode[PS_MAX_ENVELOPES], diffModeFine[PS_MAX_ENVELOPES]; + INT loudnDiff = 0; + INT iidTransmit = 0; + + + bitsIidFreq = bitsIidTime = 0; + + /* Quantize IID coefficients */ + for(env=0;enviidEnable = 0; + for(env=0;env fMultI(FL2FXCONST_DBL(0.7f),iidTransmit)){ /* 0.7f empiric value */ + psData->iidEnable = 1; + } + + /* if iid not active -> RESET data */ + if(psData->iidEnable==0) { + psData->iidTimeCnt = MAX_TIME_DIFF_FRAMES; + for(env=0;enviidDiffMode[env] = PS_DELTA_FREQ; + FDKmemclear(psData->iidIdx[env], sizeof(INT)*psBands); + } + return; + } + + /* count COARSE quantization bits for first envelope*/ + bitsIidFreq = FDKsbrEnc_EncodeIid(NULL, iidIdxCoarse[0], NULL, psBands, PS_IID_RES_COARSE, PS_DELTA_FREQ, &error); + + if( (psData->iidTimeCnt>=MAX_TIME_DIFF_FRAMES) || (psData->iidQuantModeLast==PS_IID_RES_FINE) ) { + bitsIidTime = DO_NOT_USE_THIS_MODE; + } + else { + bitsIidTime = FDKsbrEnc_EncodeIid(NULL, iidIdxCoarse[0], psData->iidIdxLast, psBands, PS_IID_RES_COARSE, PS_DELTA_TIME, &error); + } + + /* decision DELTA_FREQ vs DELTA_TIME */ + if(bitsIidTime>bitsIidFreq) { + diffMode[0] = PS_DELTA_FREQ; + bitsCoarseTot = bitsIidFreq; + } + else { + diffMode[0] = PS_DELTA_TIME; + bitsCoarseTot = bitsIidTime; + } + + /* count COARSE quantization bits for following envelopes*/ + for(env=1;envbitsIidFreq) { + diffMode[env] = PS_DELTA_FREQ; + bitsCoarseTot += bitsIidFreq; + } + else { + diffMode[env] = PS_DELTA_TIME; + bitsCoarseTot += bitsIidTime; + } + } + + + /* count FINE quantization bits for first envelope*/ + bitsIidFreq = FDKsbrEnc_EncodeIid(NULL, iidIdxFine[0], NULL, psBands, PS_IID_RES_FINE, PS_DELTA_FREQ, &error); + + if( (psData->iidTimeCnt>=MAX_TIME_DIFF_FRAMES) || (psData->iidQuantModeLast==PS_IID_RES_COARSE) ) { + bitsIidTime = DO_NOT_USE_THIS_MODE; + } + else { + bitsIidTime = FDKsbrEnc_EncodeIid(NULL, iidIdxFine[0], psData->iidIdxLast, psBands, PS_IID_RES_FINE, PS_DELTA_TIME, &error); + } + + /* decision DELTA_FREQ vs DELTA_TIME */ + if(bitsIidTime>bitsIidFreq) { + diffModeFine[0] = PS_DELTA_FREQ; + bitsFineTot = bitsIidFreq; + } + else { + diffModeFine[0] = PS_DELTA_TIME; + bitsFineTot = bitsIidTime; + } + + /* count FINE quantization bits for following envelopes*/ + for(env=1;envbitsIidFreq) { + diffModeFine[env] = PS_DELTA_FREQ; + bitsFineTot += bitsIidFreq; + } + else { + diffModeFine[env] = PS_DELTA_TIME; + bitsFineTot += bitsIidTime; + } + } + + if(bitsFineTot == bitsCoarseTot){ + /* if same number of bits is needed, use the quantization with lower error */ + if(errIIDFine < errIID){ + bitsCoarseTot = DO_NOT_USE_THIS_MODE; + } else { + bitsFineTot = DO_NOT_USE_THIS_MODE; + } + } else { + /* const FIXP_DBL minThreshold = FL2FXCONST_DBL(0.2f/(IID_SCALE_FT*PS_QUANT_SCALE_FT)*(psBands*nEnvelopes)); */ + const FIXP_DBL minThreshold = (FIXP_DBL)((LONG)0x00019999 * (psBands*nEnvelopes)); + + /* decision RES_FINE vs RES_COARSE */ + /* test if errIIDFine*quantErrorThreshold < errIID */ + /* shiftVal 2 comes from scaling of quantErrorThreshold */ + if(fixMax(((errIIDFine>>1)+(minThreshold>>1))>>1, fMult(quantErrorThreshold,errIIDFine)) < (errIID>>2) ) { + bitsCoarseTot = DO_NOT_USE_THIS_MODE; + } + else if(fixMax(((errIID>>1)+(minThreshold>>1))>>1, fMult(quantErrorThreshold,errIID)) < (errIIDFine>>2) ) { + bitsFineTot = DO_NOT_USE_THIS_MODE; + } + } + + /* decision RES_FINE vs RES_COARSE */ + if(bitsFineTotiidQuantMode = PS_IID_RES_FINE; + for(env=0;enviidDiffMode[env] = diffModeFine[env]; + FDKmemcpy(psData->iidIdx[env], iidIdxFine[env], psBands*sizeof(INT)); + } + } + else { + psData->iidQuantMode = PS_IID_RES_COARSE; + for(env=0;enviidDiffMode[env] = diffMode[env]; + FDKmemcpy(psData->iidIdx[env], iidIdxCoarse[env], psBands*sizeof(INT)); + } + } + + /* Count DELTA_TIME encoding streaks */ + for(env=0;enviidDiffMode[env]==PS_DELTA_TIME) + psData->iidTimeCnt++; + else + psData->iidTimeCnt=0; + } +} + + +static INT similarIid(PS_DATA *psData, + const INT psBands, + const INT nEnvelopes) +{ + const INT diffThr = (psData->iidQuantMode == PS_IID_RES_COARSE) ? 2 : 3; + const INT sumDiffThr = diffThr * psBands/4; + INT similar = 0; + INT diff = 0; + INT sumDiff = 0; + INT env = 0; + INT b = 0; + if ((nEnvelopes == psData->nEnvelopesLast) && (nEnvelopes==1)) { + similar = 1; + for (env=0; enviidIdx[env][b] - psData->iidIdxLast[b]); + sumDiff += diff; + if ( (diff > diffThr) /* more than x quantization steps in any band */ + || (sumDiff > sumDiffThr) ) { /* more than x quantisations steps overall difference */ + similar = 0; + } + b++; + } while ((b0)); + } + } /* nEnvelopes==1 */ + + return similar; +} + + +static INT similarIcc(PS_DATA *psData, + const INT psBands, + const INT nEnvelopes) +{ + const INT diffThr = 2; + const INT sumDiffThr = diffThr * psBands/4; + INT similar = 0; + INT diff = 0; + INT sumDiff = 0; + INT env = 0; + INT b = 0; + if ((nEnvelopes == psData->nEnvelopesLast) && (nEnvelopes==1)) { + similar = 1; + for (env=0; enviccIdx[env][b] - psData->iccIdxLast[b]); + sumDiff += diff; + if ( (diff > diffThr) /* more than x quantisation step in any band */ + || (sumDiff > sumDiffThr) ) { /* more than x quantisations steps overall difference */ + similar = 0; + } + b++; + } while ((b0)); + } + } /* nEnvelopes==1 */ + + return similar; +} + +static void processIccData(PS_DATA *psData, + FIXP_DBL icc[PS_MAX_ENVELOPES][PS_MAX_BANDS], /* const input values: unable to declare as const, since it does not poINT to const memory */ + const INT psBands, + const INT nEnvelopes) +{ + FIXP_DBL errICC = FL2FXCONST_DBL(0.f); + INT env, band; + INT bitsIccFreq, bitsIccTime; + INT error = 0; + INT inCoherence=0, iccTransmit=0; + INT *iccIdxLast; + + iccIdxLast = psData->iccIdxLast; + + /* Quantize ICC coefficients */ + for(env=0;enviccIdx[env]); + } + + /* Check if ICC coefficients should be used */ + psData->iccEnable = 0; + for(env=0;enviccIdx[env][band]; + iccTransmit ++; + } + } + if(inCoherence > fMultI(FL2FXCONST_DBL(0.5f),iccTransmit)){ /* 0.5f empiric value */ + psData->iccEnable = 1; + } + + if(psData->iccEnable==0) { + psData->iccTimeCnt = MAX_TIME_DIFF_FRAMES; + for(env=0;enviccDiffMode[env] = PS_DELTA_FREQ; + FDKmemclear(psData->iccIdx[env], sizeof(INT)*psBands); + } + return; + } + + for(env=0;enviccIdx[env], NULL, psBands, PS_DELTA_FREQ, &error); + + if(psData->iccTimeCnticcIdx[env], iccIdxLast, psBands, PS_DELTA_TIME, &error); + } + else { + bitsIccTime = DO_NOT_USE_THIS_MODE; + } + + if(bitsIccFreq>bitsIccTime) { + psData->iccDiffMode[env] = PS_DELTA_TIME; + psData->iccTimeCnt++; + } + else { + psData->iccDiffMode[env] = PS_DELTA_FREQ; + psData->iccTimeCnt=0; + } + iccIdxLast = psData->iccIdx[env]; + } +} + +static void calculateIID(FIXP_DBL ldPwrL[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL ldPwrR[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL iid[PS_MAX_ENVELOPES][PS_MAX_BANDS], + INT nEnvelopes, + INT psBands) +{ + INT i=0; + INT env=0; + for(env=0; env>(LD_DATA_SHIFT+1)) ); + IID = fixMax( IID, (FIXP_DBL)(FL2FXCONST_DBL(-1.f)>>(LD_DATA_SHIFT+1)) ); + iid[env][i] = IID << (LD_DATA_SHIFT+1); + } + } +} + +static void calculateICC(FIXP_DBL ldPwrL[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL ldPwrR[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL pwrCr[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL pwrCi[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL icc[PS_MAX_ENVELOPES][PS_MAX_BANDS], + INT nEnvelopes, + INT psBands) +{ + INT i = 0; + INT env = 0; + INT border = psBands; + + switch (psBands) { + case PS_BANDS_COARSE: + border = 5; + break; + case PS_BANDS_MID: + border = 11; + break; + case PS_BANDS_FINE: + border = 16; + break; + default: + break; + } + + /* :TRICKY: ndf 20041012 It is unclear which formula should be used here. + The first one does not quite correspond to the scientific formula for coherence. + The second formula is correct mathematically speaking but returns values in the range of [0 1], + where the MPEG standard allows quantization down to -1. This then doesnt seem to make sense. */ + /* ndf 20041119 According to rtb/hrr the 1. formula will interpret small time + delays as incoherence whereas the 2. formula will consider only truly + uncorrelated signals as incoherent. */ + + for(env=0; env>1) + (ldPwrR[env][i]>>1) + (FIXP_DBL)1) ); + INT scale, invScale = CountLeadingBits(invNrg); + + scale = (DFRACT_BITS-1) - invScale; + ICC = fMult(pwrCr[env][i], invNrg<>1)>>1) - (FIXP_DBL)((sc1-1)<<(DFRACT_BITS-1-LD_DATA_SHIFT)) ); + + FIXP_DBL invNrg = CalcInvLdData ( -((ldPwrL[env][i]>>1) + (ldPwrR[env][i]>>1) + (FIXP_DBL)1) ); + sc1 = CountLeadingBits(invNrg); + invNrg <<= sc1; + + sc2 = CountLeadingBits(ICC); + ICC = fMult(ICC<>= -sc1; + } + else { + if (ICC >= ((FIXP_DBL)MAXVAL_DBL>>sc1) ) + ICC = (FIXP_DBL)MAXVAL_DBL; + else + ICC <<= sc1; + } + + icc[env][i] = ICC; + } + } +} + +void FDKsbrEnc_initPsBandNrgScale(HANDLE_PS_ENCODE hPsEncode) +{ + INT group, bin; + INT nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups; + + FDKmemclear(hPsEncode->psBandNrgScale, PS_MAX_BANDS*sizeof(SCHAR)); + + for (group=0; group < nIidGroups; group++) { + /* Translate group to bin */ + bin = hPsEncode->subband2parameterIndex[group]; + + /* Translate from 20 bins to 10 bins */ + if (hPsEncode->psEncMode == PS_BANDS_COARSE) { + bin = bin>>1; + } + + hPsEncode->psBandNrgScale[bin] = (hPsEncode->psBandNrgScale[bin]==0) + ? (hPsEncode->iidGroupWidthLd[group] + 5) + : (fixMax(hPsEncode->iidGroupWidthLd[group],hPsEncode->psBandNrgScale[bin]) + 1) ; + + } +} + +HANDLE_ERROR_INFO FDKsbrEnc_CreatePSEncode(HANDLE_PS_ENCODE *phPsEncode){ + + HANDLE_ERROR_INFO error = noError; + + HANDLE_PS_ENCODE hPsEncode = GetRam_PsEncode(); + FDKmemclear(hPsEncode,sizeof(PS_ENCODE)); + + if(error == noError){ + if(noError != (error = CreatePSData(&hPsEncode->hPsData))){ + error = handBack(error); + } + } + + *phPsEncode = hPsEncode; + + return error; +} + +HANDLE_ERROR_INFO FDKsbrEnc_InitPSEncode(HANDLE_PS_ENCODE hPsEncode, const PS_BANDS psEncMode, const FIXP_DBL iidQuantErrorThreshold){ + + HANDLE_ERROR_INFO error = noError; + + if(error == noError){ + if(noError != (InitPSData(hPsEncode->hPsData))){ + error = handBack(error); + } + } + + if(error == noError){ + switch(psEncMode){ + case PS_BANDS_COARSE: + case PS_BANDS_MID: + hPsEncode->nQmfIidGroups = QMF_GROUPS_LO_RES; + hPsEncode->nSubQmfIidGroups = SUBQMF_GROUPS_LO_RES; + FDKmemcpy(hPsEncode->iidGroupBorders, iidGroupBordersLoRes, (hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups + 1)*sizeof(INT)); + FDKmemcpy(hPsEncode->subband2parameterIndex, subband2parameter20, (hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups) *sizeof(INT)); + FDKmemcpy(hPsEncode->iidGroupWidthLd, iidGroupWidthLdLoRes, (hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups) *sizeof(UCHAR)); + break; + case PS_BANDS_FINE: + FDK_ASSERT(0); /* we don't support this mode! */ + + break; + default: + error = ERROR(CDI, "Invalid stereo band configuration."); + break; + } + } + + if(error == noError){ + hPsEncode->psEncMode = psEncMode; + hPsEncode->iidQuantErrorThreshold = iidQuantErrorThreshold; + FDKsbrEnc_initPsBandNrgScale(hPsEncode); + } + + return error; +} + + +HANDLE_ERROR_INFO FDKsbrEnc_DestroyPSEncode(HANDLE_PS_ENCODE *phPsEncode){ + + HANDLE_ERROR_INFO error = noError; + + if(error == noError){ + DestroyPSData(&(*phPsEncode)->hPsData); + FreeRam_PsEncode(phPsEncode); + } + + return error; +} + +typedef struct { + FIXP_DBL pwrL[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL pwrR[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL ldPwrL[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL ldPwrR[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL pwrCr[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL pwrCi[PS_MAX_ENVELOPES][PS_MAX_BANDS]; +} PS_PWR_DATA; + +HANDLE_ERROR_INFO FDKsbrEnc_PSEncode(HANDLE_PS_ENCODE RESTRICT hPsEncode, + HANDLE_PS_OUT RESTRICT hPsOut, + HANDLE_PS_CHANNEL_DATA RESTRICT hChanDatal, + HANDLE_PS_CHANNEL_DATA RESTRICT hChanDatar, + UCHAR *RESTRICT dynBandScale, + UINT maxEnvelopes, + const int sendHeader) +{ + HANDLE_ERROR_INFO error = noError; + HANDLE_PS_DATA hPsData = hPsEncode->hPsData; + HANDLE_PS_HYBRID_DATA hHybDatal = hChanDatal->hHybData; + HANDLE_PS_HYBRID_DATA hHybDatar = hChanDatar->hHybData; + FIXP_QMF **RESTRICT lr = NULL, **RESTRICT li = NULL, **RESTRICT rr = NULL, **RESTRICT ri = NULL; + FIXP_DBL iid [PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL icc [PS_MAX_ENVELOPES][PS_MAX_BANDS]; + int envBorder[PS_MAX_ENVELOPES+1]; + + int group, bin, border, col, subband, band; + int i = 0; + + int env = 0; + int psBands = (int) hPsEncode->psEncMode; + int frameSize = FDKsbrEnc_GetHybridFrameSize(hHybDatal); /* same as FDKsbrEnc_GetHybridFrameSize(hHybDatar) */ + int nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups; + int nEnvelopes = fixMin(maxEnvelopes, (UINT)PS_MAX_ENVELOPES); + + C_ALLOC_SCRATCH_START(pwrData, PS_PWR_DATA, 1); + + + for(env=0; envpwrL[env][band] = pwrData->pwrR[env][band] = pwrData->pwrCr[env][band] = pwrData->pwrCi[env][band] = FIXP_DBL(1); + } + + /**** calculate energies and correlation ****/ + + /* start with hybrid data */ + lr = hHybDatal->rHybData; li = hHybDatal->iHybData; + rr = hHybDatar->rHybData; ri = hHybDatar->iHybData; + UCHAR switched = 0; + + for (group=0; group < nIidGroups; group++) { + /* Translate group to bin */ + bin = hPsEncode->subband2parameterIndex[group]; + + /* Translate from 20 bins to 10 bins */ + if (hPsEncode->psEncMode == PS_BANDS_COARSE) { + bin >>= 1; + } + + if (!switched && group == hPsEncode->nSubQmfIidGroups) { + /* switch to qmf data */ + lr = hChanDatal->hPsQmfData->rQmfData; li = hChanDatal->hPsQmfData->iQmfData; + rr = hChanDatar->hPsQmfData->rQmfData; ri = hChanDatar->hPsQmfData->iQmfData; + /* calc offset between hybrid subsubbands and qmf bands */ + nHybridQmfOffset = FDKsbrEnc_GetNumberHybridQmfBands(hHybDatal) - FDKsbrEnc_GetNumberHybridBands(hHybDatal); + switched = 1; + } + + /* determine group border */ + int bScale = 2*descale + hPsEncode->psBandNrgScale[bin]; + border = hPsEncode->iidGroupBorders[group+1]; + + FIXP_DBL pwrL_env_bin = pwrData->pwrL[env][bin]; + FIXP_DBL pwrR_env_bin = pwrData->pwrR[env][bin]; + FIXP_DBL pwrCr_env_bin = pwrData->pwrCr[env][bin]; + FIXP_DBL pwrCi_env_bin = pwrData->pwrCi[env][bin]; + int scale = (int)dynBandScale[bin]; + for (col=envBorder[env]; coliidGroupBorders[group]; subband < border; subband++) { + FIXP_QMF l_real = (lr[col][subband + nHybridQmfOffset]) << scale; + FIXP_QMF l_imag = (li[col][subband + nHybridQmfOffset]) << scale; + FIXP_QMF r_real = (rr[col][subband + nHybridQmfOffset]) << scale; + FIXP_QMF r_imag = (ri[col][subband + nHybridQmfOffset]) << scale; + + pwrL_env_bin += (fPow2Div2(l_real) + fPow2Div2(l_imag)) >> bScale; + pwrR_env_bin += (fPow2Div2(r_real) + fPow2Div2(r_imag)) >> bScale; + pwrCr_env_bin += (fMultDiv2(l_real, r_real) + fMultDiv2(l_imag, r_imag)) >> bScale; + pwrCi_env_bin += (fMultDiv2(r_real, l_imag) - fMultDiv2(l_real, r_imag)) >> bScale; + } + } + /* assure, nrg's of left and right channel are not negative; necessary on 16 bit multiply units */ + pwrData->pwrL[env][bin] = fixMax((FIXP_DBL)0,pwrL_env_bin); + pwrData->pwrR[env][bin] = fixMax((FIXP_DBL)0,pwrR_env_bin); + + pwrData->pwrCr[env][bin] = pwrCr_env_bin; + pwrData->pwrCi[env][bin] = pwrCi_env_bin; + + } /* nIidGroups */ + + /* calc logarithmic energy */ + LdDataVector(pwrData->pwrL[env], pwrData->ldPwrL[env], psBands); + LdDataVector(pwrData->pwrR[env], pwrData->ldPwrR[env], psBands); + + } /* nEnvelopes */ + + + /* calculate iid and icc */ + calculateIID(pwrData->ldPwrL, pwrData->ldPwrR, iid, nEnvelopes, psBands); + calculateICC(pwrData->ldPwrL, pwrData->ldPwrR, pwrData->pwrCr, pwrData->pwrCi, icc, nEnvelopes, psBands); + + + + /*** Envelope Reduction ***/ + while (envelopeReducible(iid,icc,psBands,nEnvelopes)) { + int e=0; + /* sum energies of two neighboring envelopes */ + nEnvelopes >>= 1; + for (e=0; epwrL[2*e], pwrData->pwrL[2*e+1], pwrData->pwrL[e], psBands); + FDKsbrEnc_addFIXP_DBL(pwrData->pwrR[2*e], pwrData->pwrR[2*e+1], pwrData->pwrR[e], psBands); + FDKsbrEnc_addFIXP_DBL(pwrData->pwrCr[2*e],pwrData->pwrCr[2*e+1],pwrData->pwrCr[e],psBands); + FDKsbrEnc_addFIXP_DBL(pwrData->pwrCi[2*e],pwrData->pwrCi[2*e+1],pwrData->pwrCi[e],psBands); + + /* calc logarithmic energy */ + LdDataVector(pwrData->pwrL[e], pwrData->ldPwrL[e], psBands); + LdDataVector(pwrData->pwrR[e], pwrData->ldPwrR[e], psBands); + + /* reduce number of envelopes and adjust borders */ + envBorder[e] = envBorder[2*e]; + } + envBorder[nEnvelopes] = envBorder[2*nEnvelopes]; + + /* re-calculate iid and icc */ + calculateIID(pwrData->ldPwrL, pwrData->ldPwrR, iid, nEnvelopes, psBands); + calculateICC(pwrData->ldPwrL, pwrData->ldPwrR, pwrData->pwrCr, pwrData->pwrCi, icc, nEnvelopes, psBands); + } + + + /* */ + if(sendHeader) { + hPsData->headerCnt = MAX_PS_NOHEADER_CNT; + hPsData->iidTimeCnt = MAX_TIME_DIFF_FRAMES; + hPsData->iccTimeCnt = MAX_TIME_DIFF_FRAMES; + hPsData->noEnvCnt = MAX_NOENV_CNT; + } + + /*** Parameter processing, quantisation etc ***/ + processIidData(hPsData, iid, psBands, nEnvelopes, hPsEncode->iidQuantErrorThreshold); + processIccData(hPsData, icc, psBands, nEnvelopes); + + + /*** Initialize output struct ***/ + + /* PS Header on/off ? */ + if( (hPsData->headerCntiidQuantMode == hPsData->iidQuantModeLast) && (hPsData->iccQuantMode == hPsData->iccQuantModeLast) ) + && ( (hPsData->iidEnable == hPsData->iidEnableLast) && (hPsData->iccEnable == hPsData->iccEnableLast) ) ) { + hPsOut->enablePSHeader = 0; + } + else { + hPsOut->enablePSHeader = 1; + hPsData->headerCnt = 0; + } + + /* nEnvelopes = 0 ? */ + if ( (hPsData->noEnvCnt < MAX_NOENV_CNT) + && (similarIid(hPsData, psBands, nEnvelopes)) + && (similarIcc(hPsData, psBands, nEnvelopes)) ) { + hPsOut->nEnvelopes = nEnvelopes = 0; + hPsData->noEnvCnt++; + } else { + hPsData->noEnvCnt = 0; + } + + + + if (nEnvelopes>0) { + + hPsOut->enableIID = hPsData->iidEnable; + hPsOut->iidMode = getIIDMode(psBands, hPsData->iidQuantMode); + + hPsOut->enableICC = hPsData->iccEnable; + hPsOut->iccMode = getICCMode(psBands, hPsData->iccQuantMode); + + hPsOut->enableIpdOpd = 0; + hPsOut->frameClass = 0; + hPsOut->nEnvelopes = nEnvelopes; + + for(env=0; envframeBorder[env] = envBorder[env+1]; + } + + for(env=0; envnEnvelopes; env++) { + hPsOut->deltaIID[env] = (PS_DELTA)hPsData->iidDiffMode[env]; + + for(band=0; bandiid[env][band] = hPsData->iidIdx[env][band]; + } + } + + for(env=0; envnEnvelopes; env++) { + hPsOut->deltaICC[env] = (PS_DELTA)hPsData->iccDiffMode[env]; + for(band=0; bandicc[env][band] = hPsData->iccIdx[env][band]; + } + } + + /* IPD OPD not supported right now */ + FDKmemclear(hPsOut->ipd, PS_MAX_ENVELOPES*PS_MAX_BANDS*sizeof(PS_DELTA)); + for(env=0; envdeltaIPD[env] = PS_DELTA_FREQ; + hPsOut->deltaOPD[env] = PS_DELTA_FREQ; + } + + FDKmemclear(hPsOut->ipdLast, PS_MAX_BANDS*sizeof(INT)); + FDKmemclear(hPsOut->opdLast, PS_MAX_BANDS*sizeof(INT)); + + for(band=0; bandiidLast[band] = hPsData->iidIdxLast[band]; + hPsOut->iccLast[band] = hPsData->iccIdxLast[band]; + } + + /* save iids and iccs for differential time coding in the next frame */ + hPsData->nEnvelopesLast = nEnvelopes; + hPsData->iidEnableLast = hPsData->iidEnable; + hPsData->iccEnableLast = hPsData->iccEnable; + hPsData->iidQuantModeLast = hPsData->iidQuantMode; + hPsData->iccQuantModeLast = hPsData->iccQuantMode; + for (i=0; iiidIdxLast[i] = hPsData->iidIdx[nEnvelopes-1][i]; + hPsData->iccIdxLast[i] = hPsData->iccIdx[nEnvelopes-1][i]; + } + } /* Envelope > 0 */ + + + C_ALLOC_SCRATCH_END(pwrData, PS_PWR_DATA, 1) + + return error; +} + diff --git a/libSBRenc/src/ps_encode.h b/libSBRenc/src/ps_encode.h new file mode 100644 index 0000000..6ce9d1f --- /dev/null +++ b/libSBRenc/src/ps_encode.h @@ -0,0 +1,117 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: M. Neuendorf, N. Rettelbach, M. Multrus + contents/description: PS Parameter extraction, encoding + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +/*! + \file + \brief PS parameter extraction, encoding functions $Revision: 36847 $ +*/ + +#ifndef __INCLUDED_PS_ENCODE_H +#define __INCLUDED_PS_ENCODE_H + +#include "ps_const.h" +#include "ps_bitenc.h" +#include "psenc_hybrid.h" + +#define IID_SCALE_FT (64.f) /* maxVal in Quant tab is +/- 50 */ +#define IID_SCALE 6 /* maxVal in Quant tab is +/- 50 */ +#define IID_MAXVAL (1< QuantScale 64 */ +#define PS_QUANT_SCALE 6 /* error smaller (64-25)/64 * 20 bands * 4 env -> QuantScale 6 bit */ + + +#define QMF_GROUPS_LO_RES 12 +#define SUBQMF_GROUPS_LO_RES 10 +#define QMF_GROUPS_HI_RES 18 +#define SUBQMF_GROUPS_HI_RES 30 + + +typedef struct T_PS_DATA { + + INT iidEnable; + INT iidEnableLast; + INT iidQuantMode; + INT iidQuantModeLast; + INT iidDiffMode[PS_MAX_ENVELOPES]; + INT iidIdx [PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT iidIdxLast [PS_MAX_BANDS]; + + INT iccEnable; + INT iccEnableLast; + INT iccQuantMode; + INT iccQuantModeLast; + INT iccDiffMode[PS_MAX_ENVELOPES]; + INT iccIdx [PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT iccIdxLast [PS_MAX_BANDS]; + + INT nEnvelopesLast; + + INT headerCnt; + INT iidTimeCnt; + INT iccTimeCnt; + INT noEnvCnt; + +} PS_DATA, *HANDLE_PS_DATA; + + +typedef struct T_PS_ENCODE{ + + HANDLE_PS_DATA hPsData; + + PS_BANDS psEncMode; + INT nQmfIidGroups; + INT nSubQmfIidGroups; + INT iidGroupBorders[QMF_GROUPS_HI_RES + SUBQMF_GROUPS_HI_RES + 1]; + INT subband2parameterIndex[QMF_GROUPS_HI_RES + SUBQMF_GROUPS_HI_RES]; + UCHAR iidGroupWidthLd[QMF_GROUPS_HI_RES + SUBQMF_GROUPS_HI_RES]; + FIXP_DBL iidQuantErrorThreshold; + + UCHAR psBandNrgScale [PS_MAX_BANDS]; + +} PS_ENCODE; + + +typedef struct T_PS_ENCODE *HANDLE_PS_ENCODE; +typedef struct T_PS_CHANNEL_DATA *HANDLE_PS_CHANNEL_DATA; + +HANDLE_ERROR_INFO FDKsbrEnc_CreatePSEncode(HANDLE_PS_ENCODE *phPsEncode); + +HANDLE_ERROR_INFO FDKsbrEnc_InitPSEncode(HANDLE_PS_ENCODE hPsEncode, const PS_BANDS psEncMode, const FIXP_DBL iidQuantErrorThreshold); + +HANDLE_ERROR_INFO FDKsbrEnc_DestroyPSEncode(HANDLE_PS_ENCODE *phPsEncode); + + +HANDLE_ERROR_INFO FDKsbrEnc_PSEncode(HANDLE_PS_ENCODE hPsEncode, + HANDLE_PS_OUT hPsOut, + HANDLE_PS_CHANNEL_DATA hChanDatal, + HANDLE_PS_CHANNEL_DATA hChanDatar, + UCHAR *dynBandScale, + UINT maxEnvelopes, + const int sendHeader); + +#endif diff --git a/libSBRenc/src/ps_main.cpp b/libSBRenc/src/ps_main.cpp new file mode 100644 index 0000000..c2b19d8 --- /dev/null +++ b/libSBRenc/src/ps_main.cpp @@ -0,0 +1,1079 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial Authors: M. Multrus + Contents/Description: PS Wrapper, Downmix + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "ps_main.h" + + +/* Includes ******************************************************************/ + +#include "ps_const.h" +#include "ps_bitenc.h" + +#include "sbr_ram.h" + + + +/* Function declarations ****************************************************/ +static void psFindBestScaling(HANDLE_PARAMETRIC_STEREO hParametricStereo, + UCHAR *dynBandScale, + FIXP_QMF *maxBandValue, + SCHAR *dmxScale); + +/* + name: static HANDLE_ERROR_INFO CreatePSQmf() + description: Creates struct (buffer) to store qmf data + returns: error code of type HANDLE_ERROR_INFO + input: - INT nCols: number of qmf samples stored in regular qmf buffer + - INT nRows: number qmf channels + - INT hybridFilterDelay: delay in qmf samples of hybrid filter + output: - HANDLE_PS_QMF_DATA *hPsQmfData: according handle +*/ +static HANDLE_ERROR_INFO CreatePSQmf(HANDLE_PS_QMF_DATA *phPsQmfData, INT ch) +{ + HANDLE_ERROR_INFO error = noError; + HANDLE_PS_QMF_DATA hPsQmfData = GetRam_PsQmfData(ch); + if (hPsQmfData==NULL) { + error = 1; + goto bail; + } + FDKmemclear(hPsQmfData, sizeof(PS_QMF_DATA)); + + hPsQmfData->rQmfData[0] = GetRam_PsRqmf(ch); + hPsQmfData->iQmfData[0] = GetRam_PsIqmf(ch); + + if ( (hPsQmfData->rQmfData[0]==NULL) || (hPsQmfData->iQmfData[0]==NULL) ) { + error = 1; + goto bail; + } + + +bail: + *phPsQmfData = hPsQmfData; + return error; +} + +static HANDLE_ERROR_INFO InitPSQmf(HANDLE_PS_QMF_DATA hPsQmfData, INT nCols, INT nRows, INT hybridFilterDelay, INT ch, UCHAR *dynamic_RAM) +{ + INT i, bufferLength = 0; + + hPsQmfData->nCols = nCols; + hPsQmfData->nRows = nRows; + hPsQmfData->bufferReadOffset = QMF_READ_OFFSET; + hPsQmfData->bufferReadOffsetHybrid = HYBRID_READ_OFFSET; /* calc read offset for hybrid analysis in qmf samples */ + hPsQmfData->bufferWriteOffset = hPsQmfData->bufferReadOffsetHybrid + hybridFilterDelay; + hPsQmfData->bufferLength = bufferLength = hPsQmfData->bufferWriteOffset + nCols; + + FDK_ASSERT(PSENC_QMF_BUFFER_LENGTH>=bufferLength); + + for(i=0; irQmfData[i] = FDKsbrEnc_SliceRam_PsRqmf(hPsQmfData->rQmfData[0], dynamic_RAM, ch, i, nCols); + hPsQmfData->iQmfData[i] = FDKsbrEnc_SliceRam_PsIqmf(hPsQmfData->iQmfData[0], dynamic_RAM, ch, i, nCols); + } + + for(i=0; irQmfData[i], (sizeof(FIXP_QMF)*QMF_CHANNELS)); + FDKmemclear(hPsQmfData->iQmfData[i], (sizeof(FIXP_QMF)*QMF_CHANNELS)); + } + + return noError; +} + + +/* + name: static HANDLE_ERROR_INFO CreatePSChannel() + description: Creates PS channel struct + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PS_HYBRID_CONFIG hHybConfig: config structure for hybrid filter bank + output: - HANDLE_PS_CHANNEL_DATA *hPsChannelData +*/ +static HANDLE_ERROR_INFO CreatePSChannel(HANDLE_PS_CHANNEL_DATA *hPsChannelData, + INT ch + ) +{ + HANDLE_ERROR_INFO error = noError; + + (*hPsChannelData) = GetRam_PsChData(ch); + + if (*hPsChannelData==NULL) { + error = 1; + goto bail; + } + FDKmemclear(*hPsChannelData, sizeof(PS_CHANNEL_DATA)); + + + if (error == noError) { + if (noError != (error = FDKsbrEnc_CreateHybridFilterBank(&(*hPsChannelData)->hHybAna, + ch ))) + { + goto bail; + } + } + if (error == noError) { + if (noError != (error = FDKsbrEnc_CreateHybridData( &((*hPsChannelData)->hHybData), + ch))) { + goto bail; + } + } + if(error == noError){ + if(noError != (error = CreatePSQmf(&((*hPsChannelData)->hPsQmfData), ch))) + { + goto bail; + } + } +bail: + return error; +} + +static HANDLE_ERROR_INFO InitPSChannel(HANDLE_PS_CHANNEL_DATA hPsChannelData, + HANDLE_PS_HYBRID_CONFIG hHybConfig, + INT noQmfSlots, + INT noQmfBands + ,INT ch, + UCHAR *dynamic_RAM + ) +{ + HANDLE_ERROR_INFO error = noError; + INT hybridFilterDelay = 0; + + if (error == noError) { + if (noError != (error = FDKsbrEnc_InitHybridFilterBank(hPsChannelData->hHybAna, + hHybConfig, + noQmfSlots ))) + { + error = handBack(error); + } + } + + if(error == noError){ + hybridFilterDelay = FDKsbrEnc_GetHybridFilterDelay(hPsChannelData->hHybAna); + hPsChannelData->psChannelDelay = hybridFilterDelay * noQmfBands; + } + + if (error == noError) { + if (noError != (error = FDKsbrEnc_InitHybridData( hPsChannelData->hHybData, + hHybConfig, + noQmfSlots))) + { + error = handBack(error); + } + } + + if(error == noError){ + if(noError != (error = InitPSQmf(hPsChannelData->hPsQmfData, + noQmfSlots, + noQmfBands, + hybridFilterDelay + ,ch, + dynamic_RAM + ))) + { + error = handBack(error); + } + } + + return error; +} + + +/* + name: static HANDLE_ERROR_INFO PSEnc_Create() + description: Creates PS struct + returns: error code of type HANDLE_ERROR_INFO + input: HANDLE_PSENC_CONFIG hPsEncConfig: configuration + output: HANDLE_PARAMETRIC_STEREO *hParametricStereo + +*/ +HANDLE_ERROR_INFO +PSEnc_Create(HANDLE_PARAMETRIC_STEREO *phParametricStereo) +{ + HANDLE_ERROR_INFO error = noError; + INT i; + HANDLE_PARAMETRIC_STEREO hParametricStereo = GetRam_ParamStereo(); + + if (hParametricStereo==NULL) { + error = 1; + goto bail; + } + + FDKmemclear(hParametricStereo,sizeof(PARAMETRIC_STEREO)); + + hParametricStereo->qmfDelayRealRef = GetRam_PsEnvRBuffer(0); + hParametricStereo->qmfDelayImagRef = GetRam_PsEnvIBuffer(0); + + if ( (hParametricStereo->qmfDelayRealRef==NULL) || (hParametricStereo->qmfDelayImagRef==NULL) ) { + error = 1; + goto bail; + } + + for (i = 0; i < (QMF_MAX_TIME_SLOTS>>1); i++) { + hParametricStereo->qmfDelayReal[i] = hParametricStereo->qmfDelayRealRef + (i*QMF_CHANNELS); + hParametricStereo->qmfDelayImag[i] = hParametricStereo->qmfDelayImagRef + (i*QMF_CHANNELS); + } + + for(i=0; ihPsChannelData[i], + i + ))) + { + goto bail; + } + } + + + if(noError != (error = FDKsbrEnc_CreatePSEncode(&hParametricStereo->hPsEncode))) { + error = 1; + goto bail; + } + + hParametricStereo->hHybridConfig = GetRam_PsHybConfig(); /* allocate memory */ + + /* calc PS_OUT values and delay one frame ! */ + hParametricStereo->hPsOut[0] = GetRam_PsOut(0); + hParametricStereo->hPsOut[1] = GetRam_PsOut(1); + if ( (hParametricStereo->hHybridConfig==NULL) || (hParametricStereo->hPsOut[0]==NULL) || (hParametricStereo->hPsOut[1]==NULL) ) { + error = 1; + goto bail; + } + +bail: + *phParametricStereo = hParametricStereo; + return error; +} + +HANDLE_ERROR_INFO +PSEnc_Init(HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_PSENC_CONFIG hPsEncConfig, + INT noQmfSlots, + INT noQmfBands + ,UCHAR *dynamic_RAM + ) +{ + HANDLE_ERROR_INFO error = noError; + INT i; + INT tmpDelay = 0; + + if(error == noError){ + if(hPsEncConfig == NULL){ + error = ERROR(CDI, "Invalid configuration handle."); + } + } + + hParametricStereo->initPS = 1; + hParametricStereo->noQmfSlots = noQmfSlots; + hParametricStereo->noQmfBands = noQmfBands; + + for (i = 0; i < hParametricStereo->noQmfSlots>>1; i++) { + FDKmemclear( hParametricStereo->qmfDelayReal[i],QMF_CHANNELS*sizeof(FIXP_DBL)); + FDKmemclear( hParametricStereo->qmfDelayImag[i],QMF_CHANNELS*sizeof(FIXP_DBL)); + } + hParametricStereo->qmfDelayScale = FRACT_BITS-1; + + if(error == noError) { + PS_BANDS nHybridSubbands = (PS_BANDS)0; + + switch(hPsEncConfig->nStereoBands){ + case PSENC_STEREO_BANDS_10: + nHybridSubbands = PS_BANDS_COARSE; + break; + case PSENC_STEREO_BANDS_20: + nHybridSubbands = PS_BANDS_MID; + break; + case PSENC_STEREO_BANDS_34: + /* nHybridSubbands = PS_BANDS_FINE; */ + FDK_ASSERT(0); /* we don't support this mode! */ + break; + default: + nHybridSubbands = (PS_BANDS)0; + break; + } + /* create configuration for hybrid filter bank */ + FDKmemclear(hParametricStereo->hHybridConfig,sizeof(PS_HYBRID_CONFIG)); + if(noError != (error = FDKsbrEnc_CreateHybridConfig(&hParametricStereo->hHybridConfig, nHybridSubbands))) { + error = handBack(error); + } + } + + + tmpDelay = 0; + for(i=0; ihPsChannelData[i], + hParametricStereo->hHybridConfig, + hParametricStereo->noQmfSlots, + hParametricStereo->noQmfBands + ,i, + dynamic_RAM + ))) + { + error = handBack(error); + } + } + + if(error == noError){ + /* sum up delay in samples for all channels (should be the same for all channels) */ + tmpDelay += hParametricStereo->hPsChannelData[i]->psChannelDelay; + } + } + + if(error == noError){ + /* determine average delay */ + hParametricStereo->psDelay = tmpDelay/MAX_PS_CHANNELS; + } + + if(error == noError){ + if ( (hPsEncConfig->maxEnvelopes < PSENC_NENV_1) + || (hPsEncConfig->maxEnvelopes > PSENC_NENV_MAX) ) { + hPsEncConfig->maxEnvelopes = PSENC_NENV_DEFAULT; + } + hParametricStereo->maxEnvelopes = hPsEncConfig->maxEnvelopes; + } + + if(error == noError){ + if(noError != (error = FDKsbrEnc_InitPSEncode(hParametricStereo->hPsEncode, (PS_BANDS) hPsEncConfig->nStereoBands, hPsEncConfig->iidQuantErrorThreshold))){ + error = handBack(error); + } + } + + /* clear buffer */ + FDKmemclear(hParametricStereo->hPsOut[0], sizeof(PS_OUT)); + FDKmemclear(hParametricStereo->hPsOut[1], sizeof(PS_OUT)); + + /* clear scaling buffer */ + FDKmemclear(hParametricStereo->dynBandScale, sizeof(UCHAR)*PS_MAX_BANDS); + FDKmemclear(hParametricStereo->maxBandValue, sizeof(FIXP_QMF)*PS_MAX_BANDS); + + return error; +} + + + +/* + name: static HANDLE_ERROR_INFO DestroyPSQmf + description: destroy PS qmf buffers + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PS_QMF_DATA *hPsQmfData + output: none +*/ + +static HANDLE_ERROR_INFO DestroyPSQmf(HANDLE_PS_QMF_DATA* phPsQmfData) +{ + HANDLE_PS_QMF_DATA hPsQmfData = *phPsQmfData; + + if(hPsQmfData) { + FreeRam_PsRqmf(hPsQmfData->rQmfData); + FreeRam_PsIqmf(hPsQmfData->iQmfData); + FreeRam_PsQmfData(phPsQmfData); + } + + return noError; +} + + + +/* + name: static HANDLE_ERROR_INFO DestroyPSChannel + description: destroy PS channel data + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PS_CHANNEL_DATA *hPsChannelDAta + output: none +*/ + + +static HANDLE_ERROR_INFO DestroyPSChannel(HANDLE_PS_CHANNEL_DATA *phPsChannelData){ + + HANDLE_ERROR_INFO error = noError; + HANDLE_PS_CHANNEL_DATA hPsChannelData = *phPsChannelData; + + if(hPsChannelData != NULL){ + + DestroyPSQmf(&hPsChannelData->hPsQmfData); + + FDKsbrEnc_DeleteHybridFilterBank(&hPsChannelData->hHybAna); + + FDKsbrEnc_DestroyHybridData(&hPsChannelData->hHybData); + + FreeRam_PsChData(phPsChannelData); + } + + return error; +} + + +/* + name: static HANDLE_ERROR_INFO PSEnc_Destroy + description: destroy PS encoder handle + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PARAMETRIC_STEREO *hParametricStereo + output: none +*/ + +HANDLE_ERROR_INFO +PSEnc_Destroy(HANDLE_PARAMETRIC_STEREO *phParametricStereo){ + + HANDLE_ERROR_INFO error = noError; + HANDLE_PARAMETRIC_STEREO hParametricStereo = *phParametricStereo; + INT i; + + if(hParametricStereo != NULL){ + for(i=0; ihPsChannelData[i])); + } + FreeRam_PsEnvRBuffer(&hParametricStereo->qmfDelayRealRef); + FreeRam_PsEnvIBuffer(&hParametricStereo->qmfDelayImagRef); + + FDKsbrEnc_DestroyPSEncode(&hParametricStereo->hPsEncode); + + FreeRam_PsOut(&hParametricStereo->hPsOut[0]); + FreeRam_PsOut(&hParametricStereo->hPsOut[1]); + + FreeRam_PsHybConfig(&hParametricStereo->hHybridConfig); + FreeRam_ParamStereo(phParametricStereo); + } + + return error; +} + +/* + name: static HANDLE_ERROR_INFO UpdatePSQmfData + description: updates buffer containing qmf data first/second halve + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PARAMETRIC_STEREO hParametricStereo + output: - HANDLE_PARAMETRIC_STEREO hParametricStereo with updated qmf data +*/ + +static HANDLE_ERROR_INFO +UpdatePSQmfData_first(HANDLE_PARAMETRIC_STEREO hParametricStereo) +{ + HANDLE_ERROR_INFO error = noError; + int i, ch; + for (ch=0; chhPsChannelData[ch]->hPsQmfData->rQmfData + QMF_READ_OFFSET; + FIXP_QMF **RESTRICT imagQmfData = hParametricStereo->hPsChannelData[ch]->hPsQmfData->iQmfData + QMF_READ_OFFSET; + + /* get needed parameters */ + INT nCols = hParametricStereo->hPsChannelData[ch]->hPsQmfData->nCols; + INT nRows = hParametricStereo->hPsChannelData[ch]->hPsQmfData->nRows; + + /* move processed buffer data nCols qmf samples forward */ + for(i=0; ihPsChannelData[ch]->hPsQmfData->rQmfData + QMF_READ_OFFSET; + FIXP_QMF **RESTRICT imagQmfData = hParametricStereo->hPsChannelData[ch]->hPsQmfData->iQmfData + QMF_READ_OFFSET; + + /* get needed parameters */ + INT writeOffset = hParametricStereo->hPsChannelData[ch]->hPsQmfData->bufferWriteOffset; + INT nCols = hParametricStereo->hPsChannelData[ch]->hPsQmfData->nCols; + INT nRows = hParametricStereo->hPsChannelData[ch]->hPsQmfData->nRows; + + /* move processed buffer data nCols qmf samples forward */ + for(i=HYBRID_READ_OFFSET; ihPsChannelData[ch]->hHybData; + FIXP_QMF **realHybridData = hHybData->rHybData + HYBRID_DATA_READ_OFFSET; + FIXP_QMF **imagHybridData = hHybData->iHybData + HYBRID_DATA_READ_OFFSET; + INT writeOffset = hHybData->hybDataWriteOffset; + INT frameSize = hHybData->frameSize; + + for(i=0; iinitPS){ + *hParametricStereo->hPsOut[1] = *hParametricStereo->hPsOut[0]; + } + *hParametricStereo->hPsOut[0] = *hParametricStereo->hPsOut[1]; + + if(noError != (error = FDKsbrEnc_PSEncode(hParametricStereo->hPsEncode, + hParametricStereo->hPsOut[1], + hParametricStereo->hPsChannelData[0], + hParametricStereo->hPsChannelData[1], + hParametricStereo->dynBandScale, + hParametricStereo->maxEnvelopes, + sendHeader))){ + error = handBack(error); + } + if (hParametricStereo->initPS){ + *hParametricStereo->hPsOut[0] = *hParametricStereo->hPsOut[1]; + hParametricStereo->initPS = 0; + } + } + + return error; +} + + +/* + name: static HANDLE_ERROR_INFO DownmixPSQmfData + description: energy weighted downmix and hybrid synthesis + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PARAMETRIC_STEREO hParametricStereo containing left and right channel qmf data + output: - HANDLE_PARAMETRIC_STEREO with updated qmf data buffer, hybrid data buffer + - FIXP_QMF **mixRealQmfData: pointer to buffer containing downmixed (real) qmf data + - FIXP_QMF **mixImagQmfData: pointer to buffer containing downmixed (imag) qmf data +*/ + +static HANDLE_ERROR_INFO +DownmixPSQmfData(HANDLE_PARAMETRIC_STEREO hParametricStereo, FIXP_QMF **RESTRICT mixRealQmfData, + FIXP_QMF **RESTRICT mixImagQmfData, SCHAR *downmixScale) +{ + HANDLE_ERROR_INFO error = noError; + int n, k; + int dynQmfScale, adjQmfScale; + int nQmfSamples=0, nQmfBands=0, nHybridQmfBands=0; + FIXP_QMF **RESTRICT leftRealQmfData = NULL; + FIXP_QMF **RESTRICT leftImagQmfData = NULL; + FIXP_QMF **RESTRICT rightRealQmfData = NULL; + FIXP_QMF **RESTRICT rightImagQmfData = NULL; + FIXP_QMF **RESTRICT leftRealHybridQmfData = NULL; + FIXP_QMF **RESTRICT leftImagHybridQmfData = NULL; + FIXP_QMF **RESTRICT rightRealHybridQmfData = NULL; + FIXP_QMF **RESTRICT rightImagHybridQmfData = NULL; + + if(hParametricStereo == NULL){ + error = ERROR(CDI, "Invalid handle hParametricStereo."); + } + + if(error == noError){ + /* Update first part of qmf buffers... + no whole buffer update possible; downmix is inplace */ + if(noError != (error = UpdatePSQmfData_first(hParametricStereo))){ + error = handBack(error); + } + } + + if(error == noError){ + /* get buffers: synchronize QMF buffers and hybrid buffers to compensate hybrid filter delay */ + /* hybrid filter bank looks nHybridFilterDelay qmf samples forward */ + leftRealQmfData = hParametricStereo->hPsChannelData[0]->hPsQmfData->rQmfData + HYBRID_READ_OFFSET; + leftImagQmfData = hParametricStereo->hPsChannelData[0]->hPsQmfData->iQmfData + HYBRID_READ_OFFSET; + rightRealQmfData = hParametricStereo->hPsChannelData[1]->hPsQmfData->rQmfData + HYBRID_READ_OFFSET; + rightImagQmfData = hParametricStereo->hPsChannelData[1]->hPsQmfData->iQmfData + HYBRID_READ_OFFSET; + + leftRealHybridQmfData = hParametricStereo->hPsChannelData[0]->hHybData->rHybData + HYBRID_WRITE_OFFSET; + leftImagHybridQmfData = hParametricStereo->hPsChannelData[0]->hHybData->iHybData + HYBRID_WRITE_OFFSET; + rightRealHybridQmfData = hParametricStereo->hPsChannelData[1]->hHybData->rHybData + HYBRID_WRITE_OFFSET; + rightImagHybridQmfData = hParametricStereo->hPsChannelData[1]->hHybData->iHybData + HYBRID_WRITE_OFFSET; + + /* get number of needed parameters */ + nQmfSamples = hParametricStereo->hPsChannelData[0]->hPsQmfData->nCols; + nQmfBands = hParametricStereo->hPsChannelData[0]->hPsQmfData->nRows; + nHybridQmfBands = FDKsbrEnc_GetNumberHybridQmfBands(hParametricStereo->hPsChannelData[0]->hHybData); + + /* define scalings */ + adjQmfScale = hParametricStereo->hPsChannelData[0]->hHybData->sf_fixpHybrid + - hParametricStereo->hPsChannelData[0]->psQmfScale; + + dynQmfScale = fixMax(0, hParametricStereo->dmxScale-1); /* scale one bit more for addition of left and right */ + + *downmixScale = hParametricStereo->hPsChannelData[0]->hHybData->sf_fixpHybrid - dynQmfScale + 1; + + const FIXP_DBL maxStereoScaleFactor = FL2FXCONST_DBL(2.0f/2.f); + + for(n = 0; nhPsChannelData[0]->hHybData, k); + } else { + /* process qmf data */ + nHybridSubBands = 1; + } + + tmpMixReal = FL2FXCONST_DBL(0.f); + tmpMixImag = FL2FXCONST_DBL(0.f); + + for(l=0; l>1) < fMult(maxStereoScaleFactor,tmpScaleFactor) ) { + + int sc_num = CountLeadingBits(stereoScaleFactor) ; + int sc_denum = CountLeadingBits(tmpScaleFactor) ; + sc = -(sc_num-sc_denum); + + tmpScaleFactor = schur_div((stereoScaleFactor<<(sc_num))>>1, + tmpScaleFactor<>=1; + } + stereoScaleFactor = sqrtFixp(tmpScaleFactor); + stereoScaleFactor <<= (sc>>1); + } + else { + stereoScaleFactor = maxStereoScaleFactor; + } + + /* write data to output */ + tmpMixReal += fMultDiv2(stereoScaleFactor, (FIXP_QMF)(tmpLeftReal + tmpRightReal))>>dynScale; + tmpMixImag += fMultDiv2(stereoScaleFactor, (FIXP_QMF)(tmpLeftImag + tmpRightImag))>>dynScale; + } + + mixRealQmfData[n][k] = tmpMixReal; + mixImagQmfData[n][k] = tmpMixImag; + + hybridDataOffset += nHybridSubBands; + } + } + } /* if(error == noError) */ + + + if(error == noError){ + /* ... and update the hybrid data */ + if(noError != (error = UpdatePSHybridData(hParametricStereo))){ + error = handBack(error); + } + } + + return error; +} + + +/* + name: INT FDKsbrEnc_PSEnc_WritePSData() + description: writes ps_data() element to bitstream (hBitstream), returns number of written bits; + returns number of written bits only, if hBitstream == NULL + returns: number of bits in ps_data() + input: - HANDLE_PARAMETRIC_STEREO hParametricStereo containing extracted ps parameters + output: - HANDLE_FDK_BITSTREAM containing ps_data() element +*/ + +INT +FDKsbrEnc_PSEnc_WritePSData(HANDLE_PARAMETRIC_STEREO hParametricStereo, HANDLE_FDK_BITSTREAM hBitstream) +{ + + INT nBitsWritten = 0; + + if(hParametricStereo != NULL){ + nBitsWritten = FDKsbrEnc_WritePSBitstream(hParametricStereo->hPsOut[0], hBitstream); + } + + return nBitsWritten; +} + + +/* + name: static HANDLE_ERROR_INFO PSHybridAnalysis() + description: hybrid analysis filter bank of lowest qmf banks + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PARAMETRIC_STEREO hParametricStereo containing qmf samples + output: - HANDLE_PARAMETRIC STEREO hParametricStereo also containing hybrid data +*/ + +static HANDLE_ERROR_INFO +PSHybridAnalysis(HANDLE_PARAMETRIC_STEREO hParametricStereo){ + + HANDLE_ERROR_INFO error = noError; + int ch; + + if(hParametricStereo == NULL){ + error = ERROR(CDI, "Invalid handle hParametricStereo."); + } + + for (ch=0; chhPsChannelData[ch]->hHybAna, + hParametricStereo->hPsChannelData[ch]->hPsQmfData->rQmfData + HYBRID_READ_OFFSET, + hParametricStereo->hPsChannelData[ch]->hPsQmfData->iQmfData + HYBRID_READ_OFFSET, + hParametricStereo->hPsChannelData[ch]->psQmfScale, + hParametricStereo->hPsChannelData[ch]->hHybData->rHybData + HYBRID_WRITE_OFFSET, + hParametricStereo->hPsChannelData[ch]->hHybData->iHybData + HYBRID_WRITE_OFFSET, + &hParametricStereo->hPsChannelData[ch]->hHybData->sf_fixpHybrid))){ + error = handBack(error); + } + } + } + + return error; +} + +/* + name: HANDLE_ERROR_INFO FDKsbrEnc_PSEnc_ParametricStereoProcessing + description: Complete PS Processing: + qmf + hybrid analysis of time domain data (left and right channel), + PS parameter extraction + downmix of qmf data + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PARAMETRIC_STEREO hParametricStereo + output: - HANDLE_PARAMETRIC STEREO hParametricStereo containing extracted PS parameters + - FIXP_DBL **qmfDataReal: Pointer to buffer containing downmixed, real qmf data + - FIXP_DBL **qmfDataImag: Pointer to buffer containing downmixed, imag qmf data + - INT_PCM **downsampledOutSignal: Pointer to buffer containing downmixed time signal + - SCHAR *qmfScale: Updated scale value for the QMF downmix data + +*/ + +HANDLE_ERROR_INFO +FDKsbrEnc_PSEnc_ParametricStereoProcessing(HANDLE_PARAMETRIC_STEREO hParametricStereo, + FIXP_QMF **RESTRICT qmfDataReal, + FIXP_QMF **RESTRICT qmfDataImag, + INT qmfOffset, + INT_PCM *downsampledOutSignal, + HANDLE_QMF_FILTER_BANK sbrSynthQmf, + SCHAR *qmfScale, + const int sendHeader) +{ + HANDLE_ERROR_INFO error = noError; + FIXP_QMF **downmixedRealQmfData = qmfDataReal+qmfOffset; + FIXP_QMF **downmixedImagQmfData = qmfDataImag+qmfOffset; + SCHAR dmScale = 0; + INT noQmfBands = hParametricStereo->noQmfBands; + + + if (error == noError) { + /* do ps hybrid analysis */ + if(noError != (error = PSHybridAnalysis(hParametricStereo))){ + error = handBack(error); + } + } + + /* find best scaling in new QMF and Hybrid data */ + psFindBestScaling( hParametricStereo, + hParametricStereo->dynBandScale, + hParametricStereo->maxBandValue, + &hParametricStereo->dmxScale ) ; + + + if(error == noError){ + /* extract the ps parameters */ + if(noError != (error = ExtractPSParameters(hParametricStereo, sendHeader))){ + error = handBack(error); + } + } + + if(error == noError){ + /* downmix and hybrid synthesis */ + if(noError != (error = DownmixPSQmfData(hParametricStereo, downmixedRealQmfData, downmixedImagQmfData, &dmScale))){ + error = handBack(error); + } + } + + + if (error == noError) + { + C_ALLOC_SCRATCH_START(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2); + /* + + QMF synthesis including downsampling + + */ + QMF_SCALE_FACTOR tmpScale; + int scale = -dmScale; + tmpScale.lb_scale = scale; + tmpScale.ov_lb_scale = scale; + tmpScale.hb_scale = scale; + tmpScale.ov_hb_scale = 0; + + qmfSynthesisFiltering( sbrSynthQmf, + downmixedRealQmfData, + downmixedImagQmfData, + &tmpScale, + 0, + downsampledOutSignal, + 1, + qmfWorkBuffer ); + + C_ALLOC_SCRATCH_END(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2); + + + } + + /* scaling in sbr module differs -> scaling update */ + *qmfScale = -dmScale + 7; + + + /* + * Do PS to SBR QMF data transfer/scaling buffer shifting, delay lines etc. + */ + { + INT noQmfSlots2 = hParametricStereo->noQmfSlots>>1; + + FIXP_QMF r_tmp1; + FIXP_QMF i_tmp1; + FIXP_QMF **delayQmfReal = hParametricStereo->qmfDelayReal; + FIXP_QMF **delayQmfImag = hParametricStereo->qmfDelayImag; + INT scale, i, j; + + if (hParametricStereo->qmfDelayScale > *qmfScale) { + scale = hParametricStereo->qmfDelayScale - *qmfScale; + + for (i=0; i> scale; + qmfDataImag[i][j] = delayQmfImag[i][j] >> scale; + delayQmfReal[i][j] = qmfDataReal[i+noQmfSlots2][j]; + delayQmfImag[i][j] = qmfDataImag[i+noQmfSlots2][j]; + qmfDataReal[i+noQmfSlots2][j] = r_tmp1; + qmfDataImag[i+noQmfSlots2][j] = i_tmp1; + } + } + hParametricStereo->qmfDelayScale = *qmfScale; + } + else { + scale = *qmfScale - hParametricStereo->qmfDelayScale; + for (i=0; i> scale; + qmfDataImag[i+noQmfSlots2][j] = i_tmp1 >> scale; + } + } + scale = *qmfScale; + *qmfScale = hParametricStereo->qmfDelayScale; + hParametricStereo->qmfDelayScale = scale; + } + } + + return error; +} + +static void psFindBestScaling(HANDLE_PARAMETRIC_STEREO hParametricStereo, + UCHAR *RESTRICT dynBandScale, + FIXP_QMF *RESTRICT maxBandValue, + SCHAR *RESTRICT dmxScale) +{ + HANDLE_PS_ENCODE hPsEncode = hParametricStereo->hPsEncode; + HANDLE_PS_HYBRID_DATA hHybDatal = hParametricStereo->hPsChannelData[0]->hHybData; + + INT group, bin, border, col, band; + INT frameSize = FDKsbrEnc_GetHybridFrameSize(hHybDatal); /* same as FDKsbrEnc_GetHybridFrameSize(hHybDatar) */ + INT psBands = (INT) hPsEncode->psEncMode; + INT nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups; + + FIXP_QMF **lr = hParametricStereo->hPsChannelData[0]->hHybData->rHybData; + FIXP_QMF **li = hParametricStereo->hPsChannelData[0]->hHybData->iHybData; + FIXP_QMF **rr = hParametricStereo->hPsChannelData[1]->hHybData->rHybData; + FIXP_QMF **ri = hParametricStereo->hPsChannelData[1]->hHybData->iHybData; + FIXP_QMF **lrBuffer = hParametricStereo->hPsChannelData[0]->hPsQmfData->rQmfData; + FIXP_QMF **liBuffer = hParametricStereo->hPsChannelData[0]->hPsQmfData->iQmfData; + FIXP_QMF **rrBuffer = hParametricStereo->hPsChannelData[1]->hPsQmfData->rQmfData; + FIXP_QMF **riBuffer = hParametricStereo->hPsChannelData[1]->hPsQmfData->iQmfData; + + /* group wise scaling */ + FIXP_QMF maxVal [2][PS_MAX_BANDS]; + FIXP_QMF maxValue = FL2FXCONST_DBL(0.f); + + INT nHybridQmfOffset = 0; + + UCHAR switched = 0; + + FDKmemclear(maxVal, sizeof(maxVal)); + + /* start with hybrid data */ + for (group=0; group < nIidGroups; group++) { + /* Translate group to bin */ + bin = hPsEncode->subband2parameterIndex[group]; + + if (!switched && group == hPsEncode->nSubQmfIidGroups) { + /* switch to qmf data */ + lr = lrBuffer; li = liBuffer; + rr = rrBuffer; ri = riBuffer; + + /* calc offset between hybrid subsubbands and qmf bands */ + nHybridQmfOffset = FDKsbrEnc_GetNumberHybridQmfBands(hHybDatal) - FDKsbrEnc_GetNumberHybridBands(hHybDatal); + switched = 1; + } + + /* Translate from 20 bins to 10 bins */ + if (hPsEncode->psEncMode == PS_BANDS_COARSE) { + bin >>= 1; + } + + /* determine group border */ + border = hPsEncode->iidGroupBorders[group+1]; + + /* QMF downmix scaling */ + { + FIXP_QMF tmp = maxVal[0][bin]; + int i; + for (col=HYBRID_READ_OFFSET; coliidGroupBorders[group] + nHybridQmfOffset]; + FIXP_QMF *pLI = &li[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; + FIXP_QMF *pRR = &rr[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; + FIXP_QMF *pRI = &ri[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; + for (i = 0; iiidGroupBorders[group]; i++) { + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pLR++)); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pLI++)); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pRR++)); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pRI++)); + } + } + maxVal[0][bin] = tmp; + + tmp = maxVal[1][bin]; + for (col=frameSize; coliidGroupBorders[group] + nHybridQmfOffset]; + FIXP_QMF *pLI = &li[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; + FIXP_QMF *pRR = &rr[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; + FIXP_QMF *pRI = &ri[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; + for (i = 0; iiidGroupBorders[group]; i++) { + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pLR++)); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pLI++)); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pRR++)); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pRI++)); + } + } + maxVal[1][bin] = tmp; + } + } /* nIidGroups */ + + /* convert maxSpec to maxScaling, find scaling space */ + for (band=0; band>1]; + FIXP_QMF *qmfDelayImag[QMF_MAX_TIME_SLOTS>>1]; + FIXP_QMF *qmfDelayRealRef; + FIXP_QMF *qmfDelayImagRef; + int qmfDelayScale; + + INT psDelay; + UINT maxEnvelopes; + UCHAR dynBandScale[PS_MAX_BANDS]; + FIXP_DBL maxBandValue[PS_MAX_BANDS]; + SCHAR dmxScale; + INT initPS; + INT noQmfSlots; + INT noQmfBands; + +} PARAMETRIC_STEREO; + + + +typedef struct T_PSENC_CONFIG { + + INT frameSize; + INT qmfFilterMode; + INT sbrPsDelay; + PSENC_STEREO_BANDS_CONFIG nStereoBands; + PSENC_NENV_CONFIG maxEnvelopes; + FIXP_DBL iidQuantErrorThreshold; + +} PSENC_CONFIG, *HANDLE_PSENC_CONFIG; + +typedef struct T_PARAMETRIC_STEREO *HANDLE_PARAMETRIC_STEREO; + + +HANDLE_ERROR_INFO +PSEnc_Create(HANDLE_PARAMETRIC_STEREO *phParametricStereo); + +HANDLE_ERROR_INFO +PSEnc_Init(HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_PSENC_CONFIG hPsEncConfig, + INT noQmfSlots, + INT noQmfBands + ,UCHAR *dynamic_RAM + ); + +HANDLE_ERROR_INFO +UpdatePSQmfData_second(HANDLE_PARAMETRIC_STEREO hParametricStereo); + +HANDLE_ERROR_INFO +PSEnc_Destroy(HANDLE_PARAMETRIC_STEREO *hParametricStereo); + + +HANDLE_ERROR_INFO +FDKsbrEnc_PSEnc_ParametricStereoProcessing(HANDLE_PARAMETRIC_STEREO hParametricStereo, + FIXP_QMF **RESTRICT qmfRealData, + FIXP_QMF **RESTRICT qmfImagData, + INT qmfOffset, + INT_PCM *downsampledOutSignal, + HANDLE_QMF_FILTER_BANK sbrSynthQmf, + SCHAR *qmfScale, + const int sendHeader); + +INT +FDKsbrEnc_PSEnc_WritePSData(HANDLE_PARAMETRIC_STEREO hParametricStereo, HANDLE_FDK_BITSTREAM hBitstream); + +#endif /* __INCLUDED_PS_MAIN_H */ diff --git a/libSBRenc/src/psenc_hybrid.cpp b/libSBRenc/src/psenc_hybrid.cpp new file mode 100644 index 0000000..a314678 --- /dev/null +++ b/libSBRenc/src/psenc_hybrid.cpp @@ -0,0 +1,836 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: M. Neuendorf, M. Multrus + contents/description: hybrid analysis filter bank + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "psenc_hybrid.h" + + +/* Includes ******************************************************************/ + +#include "psenc_hybrid.h" +#include "sbr_ram.h" + +#include "fft.h" + +#include "genericStds.h" + +/* Defines *******************************************************************/ + +#define HYBRID_SCALE 4 + +/*//#define FAST_FILTER2 +#define FAST_FILTER4 +#define FAST_FILTER8 +#define FAST_FILTER12 +*/ +#define HYBRID_INVERSE_ORDER ( 0x0F000000 ) +#define HYBRID_INVERSE_MASK ( ~HYBRID_INVERSE_ORDER ) + +//#define REAL ( 0 ) +//#define CPLX ( 1 ) + +#define cos0Pi FL2FXCONST_DBL( 1.f) +#define sin0Pi FL2FXCONST_DBL( 0.f) +#define cos1Pi FL2FXCONST_DBL(-1.f) +#define sin1Pi FL2FXCONST_DBL( 0.f) +#define cos1Pi_2 FL2FXCONST_DBL( 0.f) +#define sin1Pi_2 FL2FXCONST_DBL( 1.f) +#define cos1Pi_3 FL2FXCONST_DBL( 0.5f) +#define sin1Pi_3 FL2FXCONST_DBL( 0.86602540378444f) + +#define cos0Pi_4 cos0Pi +#define cos1Pi_4 FL2FXCONST_DBL(0.70710678118655f) +#define cos2Pi_4 cos1Pi_2 +#define cos3Pi_4 (-cos1Pi_4) +#define cos4Pi_4 (-cos0Pi_4) +#define cos5Pi_4 cos3Pi_4 +#define cos6Pi_4 cos2Pi_4 + +#define sin0Pi_4 sin0Pi +#define sin1Pi_4 FL2FXCONST_DBL(0.70710678118655f) +#define sin2Pi_4 sin1Pi_2 +#define sin3Pi_4 sin1Pi_4 +#define sin4Pi_4 sin0Pi_4 +#define sin5Pi_4 (-sin3Pi_4) +#define sin6Pi_4 (-sin2Pi_4) + +#define cos0Pi_8 cos0Pi +#define cos1Pi_8 FL2FXCONST_DBL(0.92387953251129f) +#define cos2Pi_8 cos1Pi_4 +#define cos3Pi_8 FL2FXCONST_DBL(0.38268343236509f) +#define cos4Pi_8 cos2Pi_4 +#define cos5Pi_8 (-cos3Pi_8) +#define cos6Pi_8 (-cos2Pi_8) + +#define sin0Pi_8 sin0Pi +#define sin1Pi_8 cos3Pi_8 +#define sin2Pi_8 sin1Pi_4 +#define sin3Pi_8 cos1Pi_8 +#define sin4Pi_8 sin2Pi_4 +#define sin5Pi_8 sin3Pi_8 +#define sin6Pi_8 sin1Pi_4 + +#define cos0Pi_12 cos0Pi +#define cos1Pi_12 FL2FXCONST_DBL(0.96592582628906f) +#define cos2Pi_12 FL2FXCONST_DBL(0.86602540378444f) +#define cos3Pi_12 cos1Pi_4 +#define cos4Pi_12 cos1Pi_3 +#define cos5Pi_12 FL2FXCONST_DBL(0.25881904510252f) +#define cos6Pi_12 cos1Pi_2 + +#define sin0Pi_12 sin0Pi +#define sin1Pi_12 cos5Pi_12 +#define sin2Pi_12 cos4Pi_12 +#define sin3Pi_12 sin1Pi_4 +#define sin4Pi_12 sin1Pi_3 +#define sin5Pi_12 cos1Pi_12 +#define sin6Pi_12 sin1Pi_2 + +#define FFT_IDX_R(a) (2*a) +#define FFT_IDX_I(a) (2*a+1) + + +/* Constants *****************************************************************/ + +/* static const UINT noQmfBandsInHybrid34 = 5; */ + +static const INT aHybridResolution10[] = { HYBRID_6_CPLX, + HYBRID_2_REAL | HYBRID_INVERSE_ORDER, + HYBRID_2_REAL }; + +static const INT aHybridResolution20[] = { HYBRID_6_CPLX, + HYBRID_2_REAL | HYBRID_INVERSE_ORDER, + HYBRID_2_REAL }; + +/*static const INT aHybridResolution34[] = { HYBRID_12_CPLX, + HYBRID_8_CPLX, + HYBRID_4_CPLX, + HYBRID_4_CPLX, + HYBRID_4_CPLX };*/ + +static const FIXP_DBL p8_13_20[HYBRID_FILTER_LENGTH] = +{ + FL2FXCONST_DBL(0.00746082949812f), FL2FXCONST_DBL(0.02270420949825f), FL2FXCONST_DBL(0.04546865930473f), FL2FXCONST_DBL(0.07266113929591f), + FL2FXCONST_DBL(0.09885108575264f), FL2FXCONST_DBL(0.11793710567217f), FL2FXCONST_DBL(0.125f ), FL2FXCONST_DBL(0.11793710567217f), + FL2FXCONST_DBL(0.09885108575264f), FL2FXCONST_DBL(0.07266113929591f), FL2FXCONST_DBL(0.04546865930473f), FL2FXCONST_DBL(0.02270420949825f), + FL2FXCONST_DBL(0.00746082949812f) +}; + +static const FIXP_DBL p2_13_20[HYBRID_FILTER_LENGTH] = +{ + FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL( 0.01899487526049f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(-0.07293139167538f), + FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL( 0.30596630545168f), FL2FXCONST_DBL(0.5f), FL2FXCONST_DBL( 0.30596630545168f), + FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(-0.07293139167538f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL( 0.01899487526049f), + FL2FXCONST_DBL(0.0f) +}; + + +/*static const float p12_13_34[HYBRID_FILTER_LENGTH] = +{ + 0.04081179924692, 0.03812810994926, 0.05144908135699, 0.06399831151592, + 0.07428313801106, 0.08100347892914, 0.08333333333333, 0.08100347892914, + 0.07428313801106, 0.06399831151592, 0.05144908135699, 0.03812810994926, + 0.04081179924692 +}; + +static const float p8_13_34[HYBRID_FILTER_LENGTH] = +{ + 0.01565675600122, 0.03752716391991, 0.05417891378782, 0.08417044116767, + 0.10307344158036, 0.12222452249753, 0.12500000000000, 0.12222452249753, + 0.10307344158036, 0.08417044116767, 0.05417891378782, 0.03752716391991, + 0.01565675600122 +}; + +static const float p4_13_34[HYBRID_FILTER_LENGTH] = +{ + -0.05908211155639, -0.04871498374946, 0.0, 0.07778723915851, + 0.16486303567403, 0.23279856662996, 0.25, 0.23279856662996, + 0.16486303567403, 0.07778723915851, 0.0, -0.04871498374946, + -0.05908211155639 +};*/ + + +/* Function / Class Implementation *******************************************/ + + + +/*****************************************************************************/ +/* **** FILTERBANK CONFIG **** */ + +HANDLE_ERROR_INFO FDKsbrEnc_CreateHybridConfig(HANDLE_PS_HYBRID_CONFIG *phHybConfig, + PS_BANDS mode) +{ + HANDLE_ERROR_INFO error = noError; + HANDLE_PS_HYBRID_CONFIG h = NULL; + UINT k = 0; + + if (error == noError) { + h = *phHybConfig; /* Simplify your life */ + h->mode = mode; + + switch (mode) { + case PS_BANDS_MID: + h->noQmfBandsInHybrid = NO_QMF_BANDS_HYBRID_20; + for (k=0; knoQmfBandsInHybrid; k++) { + h->aHybridResolution[k] = aHybridResolution20[k]; + } + break; + + case PS_BANDS_FINE: + /*h->noQmfBandsInHybrid = noQmfBandsInHybrid34; + for (k=0; knoQmfBandsInHybrid; k++) { + h->aHybridResolution[k] = aHybridResolution34[k]; + }*/ + FDK_ASSERT(0); /* we don't support! */ + break; + + case PS_BANDS_COARSE: + h->noQmfBandsInHybrid = NO_QMF_BANDS_HYBRID_10; + for (k=0; knoQmfBandsInHybrid; k++) { + h->aHybridResolution[k] = aHybridResolution10[k]; + } + break; + + default: + error = ERROR(CDI, "Invalid hybrid filter bank configuration."); + break; + } + } + + return error; +} + +/*****************************************************************************/ +/* **** FILTERBANK DATA **** */ + +HANDLE_ERROR_INFO FDKsbrEnc_CreateHybridData(HANDLE_PS_HYBRID_DATA *phHybData, + INT ch) +{ + HANDLE_ERROR_INFO error = noError; + int k; + + HANDLE_PS_HYBRID_DATA hHybData = GetRam_HybData(ch); + if (hHybData==NULL) { + error = 1; + goto bail; + } + + FDKmemclear(hHybData, sizeof(PS_HYBRID_DATA)); + + hHybData->rHybData[0] = GetRam_PsRhyb(ch); + hHybData->iHybData[0] = GetRam_PsIhyb(ch); + if ( (hHybData->rHybData[0]==NULL) || (hHybData->iHybData[0]==NULL) ) { + error = 1; + goto bail; + } + + + + for (k=1; k<(HYBRID_FRAMESIZE+HYBRID_WRITEOFFSET); k++) { + hHybData->rHybData[k] = hHybData->rHybData[0] + (k*HYBRID_NUM_BANDS); + hHybData->iHybData[k] = hHybData->iHybData[0] + (k*HYBRID_NUM_BANDS); + } + +bail: + *phHybData = hHybData; + return error; +} + + +HANDLE_ERROR_INFO FDKsbrEnc_InitHybridData(HANDLE_PS_HYBRID_DATA hHybData, + HANDLE_PS_HYBRID_CONFIG hHybConfig, + INT frameSize) +{ + HANDLE_ERROR_INFO error = noError; + INT nHybridBands = 0; + INT k = 0; + INT noBands = 0; + const INT *hybridRes = NULL; + + if (hHybConfig != NULL) { + noBands = hHybConfig->noQmfBandsInHybrid; + hybridRes = hHybConfig->aHybridResolution; + } + + for (k=0; k=nHybridBands); + + hHybData->hybDataReadOffset = HYBRID_DATA_READ_OFFSET; + hHybData->hybDataWriteOffset = HYBRID_WRITEOFFSET; + + for (k=0; k<(HYBRID_FRAMESIZE+HYBRID_WRITEOFFSET); k++) { + FDKmemclear(hHybData->rHybData[k], sizeof(FIXP_QMF)*HYBRID_NUM_BANDS); + FDKmemclear(hHybData->iHybData[k], sizeof(FIXP_QMF)*HYBRID_NUM_BANDS); + } + + hHybData->frameSize = frameSize; + hHybData->nHybridBands = nHybridBands; + hHybData->nHybridQmfBands = noBands; + + /* store hybrid resoltion in hybrid data handle */ + FDK_ASSERT (HYBRID_MAX_QMF_BANDS>=hHybData->nHybridQmfBands); + for(k = 0; knHybridQmfBands; k++){ + hHybData->nHybridResolution[k] = (hybridRes[k] & HYBRID_INVERSE_MASK); + } + + return error; +} + +HANDLE_ERROR_INFO FDKsbrEnc_DestroyHybridData(HANDLE_PS_HYBRID_DATA* phHybData) +{ + HANDLE_PS_HYBRID_DATA hHybData = *phHybData; + + if (hHybData!=NULL) { + FreeRam_PsRhyb(&hHybData->rHybData[0]); + FreeRam_PsIhyb(&hHybData->iHybData[0]); + FreeRam_HybData(phHybData); + } + + return noError; +} + +/*** Access functions ***/ + +/* return hybrid band resolution of qmf band 'qmfBand' */ +INT FDKsbrEnc_GetHybridResolution(HANDLE_PS_HYBRID_DATA h, INT qmfBand){ + + INT nHybridResolution = 0; + + if(h->nHybridResolution){ + nHybridResolution = h->nHybridResolution[qmfBand]; + } + + return nHybridResolution; +} + +/*****************************************************************************/ +/* **** FILTERBANK **** */ + +/* + 2 channel filter + Filter Coefs: + 0.0, + 0.01899487526049, + 0.0, + -0.07293139167538, + 0.0, + 0.30596630545168, + 0.5, + 0.30596630545168, + 0.0, + -0.07293139167538, + 0.0, + 0.01899487526049, + 0.0 + + + Filter design: + h[q,n] = g[n] * cos(2pi/2 * q * (n-6) ); n = 0..12, q = 0,1; + + -> h[0,n] = g[n] * 1; + -> h[1,n] = g[n] * pow(-1,n); + +*/ + +static void dualChannelFiltering(const FIXP_QMF *RESTRICT pQmfReal, + const FIXP_QMF *RESTRICT pQmfImag, + FIXP_QMF **RESTRICT mHybridReal, + FIXP_QMF **RESTRICT mHybridImag, + INT nSamples) +{ + INT i; + + for(i = 0; i < nSamples; i++) { + FIXP_DBL r1, r3, r5, r6; + FIXP_DBL i1, i3, i5, i6; + + /* symmetric filter coefficients + scaleValue same as used in eightChannelFiltering (HYBRID_SCALE = 4) + */ + r1 = fMultDiv2(p2_13_20[1], (FIXP_QMF)((pQmfReal[1+i]>>1) + (pQmfReal[11+i]>>1)) ) >> 2; + r3 = fMultDiv2(p2_13_20[3], (FIXP_QMF)((pQmfReal[3+i]>>1) + (pQmfReal[ 9+i]>>1)) ) >> 2; + r5 = fMultDiv2(p2_13_20[5], (FIXP_QMF)((pQmfReal[5+i]>>1) + (pQmfReal[ 7+i]>>1)) ) >> 2; + r6 = fMultDiv2(p2_13_20[6], (FIXP_QMF) (pQmfReal[6+i]>>1) ) >> 2; + + i1 = fMultDiv2(p2_13_20[1], (FIXP_QMF)((pQmfImag[1+i]>>1) + (pQmfImag[11+i]>>1)) ) >> 2; + i3 = fMultDiv2(p2_13_20[3], (FIXP_QMF)((pQmfImag[3+i]>>1) + (pQmfImag[ 9+i]>>1)) ) >> 2; + i5 = fMultDiv2(p2_13_20[5], (FIXP_QMF)((pQmfImag[5+i]>>1) + (pQmfImag[ 7+i]>>1)) ) >> 2; + i6 = fMultDiv2(p2_13_20[6], (FIXP_QMF) (pQmfImag[6+i]>>1) ) >> 2; + + mHybridReal[i][0] = FX_DBL2FX_QMF(r1 + r3 + r5 + r6); + mHybridImag[i][0] = FX_DBL2FX_QMF(i1 + i3 + i5 + i6); + + mHybridReal[i][1] = FX_DBL2FX_QMF(- r1 - r3 - r5 + r6); + mHybridImag[i][1] = FX_DBL2FX_QMF(- i1 - i3 - i5 + i6); + } +} + +/* + 8 channel filter + + Implementation using a FFT of length 8 + + prototype filter coefficients: + 0.00746082949812 0.02270420949825 0.04546865930473 0.07266113929591 0.09885108575264 0.11793710567217 + 0.125 + 0.11793710567217 0.09885108575264 0.07266113929591 0.04546865930473 0.02270420949825 0.00746082949812 + + Filter design: + N = 13; Q = 8; + h[q,n] = g[n] * exp(j * 2 * pi / Q * (q + .5) * (n - 6)); n = 0..(N-1), q = 0..(Q-1); + + Time Signal: x[t]; + Filter Bank Output + y[q,t] = conv(x[t],h[q,t]) = conv(h[q,t],x[t]) = sum(x[k] * h[q, t - k] ) = sum(h[q, k] * x[t - k] ); k = 0..(N-1); + + y[q,t] = x[t - 12]*h[q, 12] + x[t - 11]*h[q, 11] + x[t - 10]*h[q, 10] + x[t - 9]*h[q, 9] + + x[t - 8]*h[q, 8] + x[t - 7]*h[q, 7] + + x[t - 6]*h[q, 6] + + x[t - 5]*h[q, 5] + x[t - 4]*h[q, 4] + + x[t - 3]*h[q, 3] + x[t - 2]*h[q, 2] + x[t - 1]*h[q, 1] + x[t - 0]*h[q, 0]; + + h'[q, n] = h[q,(N-1)-n] = g[n] * exp(j * 2 * pi / Q * (q + .5) * (6 - n)); n = 0..(N-1), q = 0..(Q-1); + + y[q,t] = x[t - 12]*h'[q, 0] + x[t - 11]*h'[q, 1] + x[t - 10]*h'[q, 2] + x[t - 9]*h'[q, 3] + + x[t - 8]*h'[q, 4] + x[t - 7]*h'[q, 5] + + x[t - 6]*h'[q, 6] + + x[t - 5]*h'[q, 7] + x[t - 4]*h'[q, 8] + + x[t - 3]*h'[q, 9] + x[t - 2]*h'[q, 10] + x[t - 1]*h'[q, 11] + x[t - 0]*h'[q, 12]; + + Try to split off FFT Modulation Term: + FFT(x[t], q) = sum(x[t+k]*exp(-j*2*pi/N *q * k)) + c m + Step 1: h'[q,n] = g[n] * ( exp(j * 2 * pi / 8 * .5 * (6 - n)) ) * ( exp (j * 2 * pi / 8 * q * (6 - n)) ); + + h'[q,n] = g[n] *c[n] * m[q,n]; (see above) + c[n] = exp( j * 2 * pi / 8 * .5 * (6 - n) ); + m[q,n] = exp( j * 2 * pi / 8 * q * (6 - n) ); + + y[q,t] = x[t - 0]*g[0]*c[0]*m[q,0] + x[t - 1]*g[1]*c[ 1]*m[q, 1] + ... + ... + x[t - 12]*g[2]*c[12]*m[q,12]; + + | + n m *exp(-j*2*pi) | n' fft +------------------------------------------------------------------------------------------------------------------------- + 0 exp( j * 2 * pi / 8 * q * 6) -> exp(-j * 2 * pi / 8 * q * 2) | 2 exp(-j * 2 * pi / 8 * q * 0) + 1 exp( j * 2 * pi / 8 * q * 5) -> exp(-j * 2 * pi / 8 * q * 3) | 3 exp(-j * 2 * pi / 8 * q * 1) + 2 exp( j * 2 * pi / 8 * q * 4) -> exp(-j * 2 * pi / 8 * q * 4) | 4 exp(-j * 2 * pi / 8 * q * 2) + 3 exp( j * 2 * pi / 8 * q * 3) -> exp(-j * 2 * pi / 8 * q * 5) | 5 exp(-j * 2 * pi / 8 * q * 3) + 4 exp( j * 2 * pi / 8 * q * 2) -> exp(-j * 2 * pi / 8 * q * 6) | 6 exp(-j * 2 * pi / 8 * q * 4) + 5 exp( j * 2 * pi / 8 * q * 1) -> exp(-j * 2 * pi / 8 * q * 7) | 7 exp(-j * 2 * pi / 8 * q * 5) + 6 exp( j * 2 * pi / 8 * q * 0) | 0 exp(-j * 2 * pi / 8 * q * 6) + 7 exp(-j * 2 * pi / 8 * q * 1) | 1 exp(-j * 2 * pi / 8 * q * 7) + 8 exp(-j * 2 * pi / 8 * q * 2) | 2 + 9 exp(-j * 2 * pi / 8 * q * 3) | 3 + 10 exp(-j * 2 * pi / 8 * q * 4) | 4 + 11 exp(-j * 2 * pi / 8 * q * 5) | 5 + 12 exp(-j * 2 * pi / 8 * q * 6) | 6 + + + now use fft modulation coefficients + m[6] = = fft[0] + m[7] = = fft[1] + m[8] = m[ 0] = fft[2] + m[9] = m[ 1] = fft[3] + m[10] = m[ 2] = fft[4] + m[11] = m[ 3] = fft[5] + m[12] = m[ 4] = fft[6] + m[ 5] = fft[7] + + y[q,t] = ( x[t- 6]*g[ 6]*c[ 6] ) * fft[q,0] + + ( x[t- 7]*g[ 7]*c[ 7] ) * fft[q,1] + + ( x[t- 0]*g[ 0]*c[ 0] + x[t- 8]*g[ 8]*c[ 8] ) * fft[q,2] + + ( x[t- 1]*g[ 1]*c[ 1] + x[t- 9]*g[ 9]*c[ 9] ) * fft[q,3] + + ( x[t- 2]*g[ 2]*c[ 2] + x[t-10]*g[10]*c[10] ) * fft[q,4] + + ( x[t- 3]*g[ 3]*c[ 3] + x[t-11]*g[11]*c[11] ) * fft[q,5] + + ( x[t- 4]*g[ 4]*c[ 4] + x[t-12]*g[12]*c[12] ) * fft[q,6] + + ( x[t- 5]*g[ 5]*c[ 5] ) * fft[q,7]; + + pre twiddle factors c[n] = exp(j * 2 * pi / 8 * .5 * (6 - n)); + n c] | n c[n] | n c[n] +--------------------------------------------------------------------------------------------------- + 0 exp( j * 6 * pi / 8) | 1 exp( j * 5 * pi / 8) | 2 exp( j * 4 * pi / 8) + 3 exp( j * 3 * pi / 8) | 4 exp( j * 2 * pi / 8) | 5 exp( j * 1 * pi / 8) + 6 exp( j * 0 * pi / 8) | 7 exp(-j * 1 * pi / 8) | 8 exp(-j * 2 * pi / 8) + 9 exp(-j * 3 * pi / 8) | 10 exp(-j * 4 * pi / 8) | 11 exp(-j * 5 * pi / 8) + 12 exp(-j * 6 * pi / 8) | | + +*/ + +static const FIXP_DBL cr[13] = +{ cos6Pi_8, cos5Pi_8, cos4Pi_8, + cos3Pi_8, cos2Pi_8, cos1Pi_8, + cos0Pi_8, + cos1Pi_8, cos2Pi_8, cos3Pi_8, + cos4Pi_8, cos5Pi_8, cos6Pi_8 +}; + +static const FIXP_DBL ci[13] = +{ + sin6Pi_8, sin5Pi_8, sin4Pi_8, + sin3Pi_8, sin2Pi_8, sin1Pi_8, + sin0Pi_8, + -sin1Pi_8, -sin2Pi_8, -sin3Pi_8, + -sin4Pi_8, -sin5Pi_8, -sin6Pi_8 +}; + + +static void eightChannelFiltering(const FIXP_QMF *pQmfReal, + const FIXP_QMF *pQmfImag, + FIXP_DBL *fft, + FIXP_QMF **mHybridReal, + FIXP_QMF **mHybridImag, + INT nSamples, + const FIXP_DBL *p) +{ + INT i, bin; + for(i = 0; i < nSamples; i++) { + /* pre twiddeling + scaling 4 = 2 (fMultDiv2) + 2 (dit_fft) scaling (HYBRID_SCALE = 4) + */ + fft[FFT_IDX_R(0)] = fMultDiv2(p[6], fMultSubDiv2(fMultDiv2(cr[6], pQmfReal[6+i]), ci[6], pQmfImag[6+i])); + fft[FFT_IDX_I(0)] = fMultDiv2(p[6], fMultAddDiv2(fMultDiv2(ci[6], pQmfReal[6+i]), cr[6], pQmfImag[6+i])); + + fft[FFT_IDX_R(1)] = fMultDiv2(p[7], fMultSubDiv2(fMultDiv2(cr[7], pQmfReal[7+i]), ci[7], pQmfImag[7+i])); + fft[FFT_IDX_I(1)] = fMultDiv2(p[7], fMultAddDiv2(fMultDiv2(ci[7], pQmfReal[7+i]), cr[7], pQmfImag[7+i])); + + fft[FFT_IDX_R(2)] = ( fMultDiv2(p[ 0], fMultSubDiv2(fMultDiv2(cr[0], pQmfReal[ 0+i]), ci[0], pQmfImag[ 0+i]))+ + fMultDiv2(p[ 8], fMultSubDiv2(fMultDiv2(cr[8], pQmfReal[ 8+i]), ci[8], pQmfImag[ 8+i])) ); + fft[FFT_IDX_I(2)] = ( fMultDiv2(p[ 0], fMultAddDiv2(fMultDiv2(ci[0], pQmfReal[ 0+i]), cr[0], pQmfImag[ 0+i]))+ + fMultDiv2(p[ 8], fMultAddDiv2(fMultDiv2(ci[8], pQmfReal[ 8+i]), cr[8], pQmfImag[ 8+i])) ); + + fft[FFT_IDX_R(3)] = ( fMultDiv2(p[ 1], fMultSubDiv2(fMultDiv2(cr[1], pQmfReal[ 1+i]), ci[1], pQmfImag[ 1+i]))+ + fMultDiv2(p[ 9], fMultSubDiv2(fMultDiv2(cr[9], pQmfReal[ 9+i]), ci[9], pQmfImag[ 9+i])) ); + fft[FFT_IDX_I(3)] = ( fMultDiv2(p[ 1], fMultAddDiv2(fMultDiv2(ci[1], pQmfReal[ 1+i]), cr[1], pQmfImag[ 1+i]))+ + fMultDiv2(p[ 9], fMultAddDiv2(fMultDiv2(ci[9], pQmfReal[ 9+i]), cr[9], pQmfImag[ 9+i])) ); + + fft[FFT_IDX_R(4)] = ( fMultDiv2(p[ 2], fMultSubDiv2( fMultDiv2(cr[2], pQmfReal[ 2+i]), ci[2], pQmfImag[ 2+i]))+ + fMultDiv2(p[10], fMultSubDiv2(fMultDiv2(cr[10], pQmfReal[10+i]), ci[10], pQmfImag[10+i])) ); + fft[FFT_IDX_I(4)] = ( fMultDiv2(p[ 2], fMultAddDiv2( fMultDiv2(ci[2], pQmfReal[ 2+i]), cr[2], pQmfImag[ 2+i]))+ + fMultDiv2(p[10], fMultAddDiv2(fMultDiv2(ci[10], pQmfReal[10+i]), cr[10], pQmfImag[10+i])) ); + + fft[FFT_IDX_R(5)] = ( fMultDiv2(p[ 3], fMultSubDiv2( fMultDiv2(cr[3], pQmfReal[ 3+i]), ci[3], pQmfImag[ 3+i]))+ + fMultDiv2(p[11], fMultSubDiv2(fMultDiv2(cr[11], pQmfReal[11+i]), ci[11], pQmfImag[11+i])) ); + fft[FFT_IDX_I(5)] = ( fMultDiv2(p[ 3], fMultAddDiv2( fMultDiv2(ci[3], pQmfReal[ 3+i]), cr[3], pQmfImag[ 3+i]))+ + fMultDiv2(p[11], fMultAddDiv2(fMultDiv2(ci[11], pQmfReal[11+i]), cr[11], pQmfImag[11+i])) ); + + fft[FFT_IDX_R(6)] = ( fMultDiv2(p[ 4], fMultSubDiv2( fMultDiv2(cr[4], pQmfReal[ 4+i]), ci[4], pQmfImag[ 4+i]))+ + fMultDiv2(p[12], fMultSubDiv2(fMultDiv2(cr[12], pQmfReal[12+i]), ci[12], pQmfImag[12+i])) ); + fft[FFT_IDX_I(6)] = ( fMultDiv2(p[ 4], fMultAddDiv2( fMultDiv2(ci[4], pQmfReal[ 4+i]), cr[4], pQmfImag[ 4+i]))+ + fMultDiv2(p[12], fMultAddDiv2(fMultDiv2(ci[12], pQmfReal[12+i]), cr[12], pQmfImag[12+i])) ); + + fft[FFT_IDX_R(7)] = fMultDiv2(p[5], fMultSubDiv2(fMultDiv2(cr[5], pQmfReal[5+i]), ci[5], pQmfImag[5+i])); + fft[FFT_IDX_I(7)] = fMultDiv2(p[5], fMultAddDiv2(fMultDiv2(ci[5], pQmfReal[5+i]), cr[5], pQmfImag[5+i])); + + /* fft modulation */ + fft_8(fft); + + /* resort fft data INTo output array*/ + for(bin=0; bin<8;bin++ ) { + mHybridReal[i][bin] = FX_DBL2FX_QMF(fft[FFT_IDX_R(bin)]); + mHybridImag[i][bin] = FX_DBL2FX_QMF(fft[FFT_IDX_I(bin)]); + } + } +} + +/**************************************************************************//** +HybridAnalysis +******************************************************************************/ + +HANDLE_ERROR_INFO +HybridAnalysis ( HANDLE_PS_HYBRID hHybrid, /*!< Handle to HYBRID struct. */ + FIXP_QMF *const *const mQmfReal, /*!< The real part of the QMF-matrix. */ + FIXP_QMF *const *const mQmfImag, /*!< The imaginary part of the QMF-matrix. */ + SCHAR sf_fixpQmf, /*!< Qmf scale factor */ + FIXP_QMF **mHybridReal, /*!< The real part of the hybrid-matrix. */ + FIXP_QMF **mHybridImag, /*!< The imaginary part of the hybrid-matrix. */ + SCHAR *sf_fixpHybrid) /*!< Hybrid scale factor */ +{ + HANDLE_ERROR_INFO error = noError; + INT n, band; + INT hybridRes; + INT chOffset = 0; + /* INT usedStereoBands = hHybrid->mode; */ /*!< indicates which 8 band filter to use */ + INT frameSize = hHybrid->frameSize; + INT hybridFilterDelay = hHybrid->hybridFilterDelay; + + for(band = 0; band < hHybrid->nQmfBands; band++) { /* loop all qmf bands */ + + if(error == noError){ + hybridRes = hHybrid->pResolution[band]; + + /* Create working buffer. */ + /* Copy stored samples to working buffer. */ + FDKmemcpy(hHybrid->pWorkReal, hHybrid->mQmfBufferReal[band], + hHybrid->qmfBufferMove * sizeof(FIXP_QMF)); + FDKmemcpy(hHybrid->pWorkImag, hHybrid->mQmfBufferImag[band], + hHybrid->qmfBufferMove * sizeof(FIXP_QMF)); + + /* Append new samples to working buffer. */ + for(n = 0; n < frameSize; n++) { + hHybrid->pWorkReal [hHybrid->qmfBufferMove + n] = mQmfReal [n + hybridFilterDelay] [band]; + hHybrid->pWorkImag [hHybrid->qmfBufferMove + n] = mQmfImag [n + hybridFilterDelay] [band]; + } + + /* Store samples for next frame. */ + FDKmemcpy(hHybrid->mQmfBufferReal[band], hHybrid->pWorkReal + frameSize, + hHybrid->qmfBufferMove * sizeof(FIXP_QMF)); + FDKmemcpy(hHybrid->mQmfBufferImag[band], hHybrid->pWorkImag + frameSize, + hHybrid->qmfBufferMove * sizeof(FIXP_QMF)); + + + switch(hybridRes) { + case HYBRID_2_REAL: + dualChannelFiltering( hHybrid->pWorkReal, + hHybrid->pWorkImag, + hHybrid->mTempReal, + hHybrid->mTempImag, + frameSize); + + /* copy data to output buffer */ + for(n = 0; n < frameSize; n++) { + FDKmemcpy(&mHybridReal[n][chOffset], hHybrid->mTempReal[n], + (INT)(hybridRes & HYBRID_INVERSE_MASK)*sizeof(FIXP_QMF)); + FDKmemcpy(&mHybridImag[n][chOffset], hHybrid->mTempImag[n], + (INT)(hybridRes & HYBRID_INVERSE_MASK)*sizeof(FIXP_QMF)); + } + break; + + case HYBRID_2_REAL | HYBRID_INVERSE_ORDER: + dualChannelFiltering( hHybrid->pWorkReal, + hHybrid->pWorkImag, + hHybrid->mTempReal, + hHybrid->mTempImag, + frameSize); + + /* copy and resort data */ + for ( n = 0; n < frameSize; n++ ) + { + mHybridReal[n][chOffset + 0] = hHybrid->mTempReal[n][1] ; + mHybridReal[n][chOffset + 1] = hHybrid->mTempReal[n][0] ; + mHybridImag[n][chOffset + 0] = hHybrid->mTempImag[n][1] ; + mHybridImag[n][chOffset + 1] = hHybrid->mTempImag[n][0] ; + } + break; + + case HYBRID_6_CPLX: + eightChannelFiltering( hHybrid->pWorkReal, + hHybrid->pWorkImag, + hHybrid->fft, + hHybrid->mTempReal, + hHybrid->mTempImag, + frameSize, + /*(usedStereoBands==PS_BANDS_FINE)?p8_13_34:*/p8_13_20); + + /* do the shuffle */ + for ( n = 0; n < frameSize; n++ ) + { + /* add data ... */ + hHybrid->mTempReal[n][2] += hHybrid->mTempReal[n][5]; + hHybrid->mTempImag[n][2] += hHybrid->mTempImag[n][5]; + hHybrid->mTempReal[n][3] += hHybrid->mTempReal[n][4]; + hHybrid->mTempImag[n][3] += hHybrid->mTempImag[n][4]; + + /* shuffle and copy to output buffer */ + mHybridReal[n][chOffset + 0] = hHybrid->mTempReal[n][6] ; + mHybridReal[n][chOffset + 1] = hHybrid->mTempReal[n][7] ; + mHybridReal[n][chOffset + 2] = hHybrid->mTempReal[n][0] ; + mHybridReal[n][chOffset + 3] = hHybrid->mTempReal[n][1] ; + mHybridReal[n][chOffset + 4] = hHybrid->mTempReal[n][2] ; + mHybridReal[n][chOffset + 5] = hHybrid->mTempReal[n][3] ; + + mHybridImag[n][chOffset + 0] = hHybrid->mTempImag[n][6] ; + mHybridImag[n][chOffset + 1] = hHybrid->mTempImag[n][7] ; + mHybridImag[n][chOffset + 2] = hHybrid->mTempImag[n][0] ; + mHybridImag[n][chOffset + 3] = hHybrid->mTempImag[n][1] ; + mHybridImag[n][chOffset + 4] = hHybrid->mTempImag[n][2] ; + mHybridImag[n][chOffset + 5] = hHybrid->mTempImag[n][3] ; + } + break; + + case HYBRID_8_CPLX: + eightChannelFiltering( hHybrid->pWorkReal, + hHybrid->pWorkImag, + hHybrid->fft, + hHybrid->mTempReal, + hHybrid->mTempImag, + frameSize, + /*(usedStereoBands==PS_BANDS_FINE)?p8_13_34:*/p8_13_20); + + /* copy data to output buffer */ + for(n = 0; n < frameSize; n++) { + FDKmemcpy(&mHybridReal[n][chOffset], hHybrid->mTempReal[n], + (INT)(hybridRes & HYBRID_INVERSE_MASK)*sizeof(FIXP_QMF)); + FDKmemcpy(&mHybridImag[n][chOffset], hHybrid->mTempImag[n], + (INT)(hybridRes & HYBRID_INVERSE_MASK)*sizeof(FIXP_QMF)); + } + break; + + default: + error = ERROR(CDI, "Invalid filter bank configuration."); + break; + } + /* prepare next run by incresing chOffset */ + chOffset += hybridRes & HYBRID_INVERSE_MASK; + } + } + + *sf_fixpHybrid = sf_fixpQmf + HYBRID_SCALE; + + return error; +} + +/**************************************************************************//** + FDKsbrEnc_CreateHybridFilterBank +******************************************************************************/ +HANDLE_ERROR_INFO +FDKsbrEnc_CreateHybridFilterBank ( HANDLE_PS_HYBRID *phHybrid, /*!< Pointer to handle to HYBRID struct. */ + INT ch) /*!< Current channel */ +{ + HANDLE_ERROR_INFO error = noError; + INT i; + HANDLE_PS_HYBRID hs = GetRam_PsHybrid(ch); /* allocate memory */ + if (hs==NULL) { + error = 1; + goto bail; + } + + hs->fft = GetRam_PsHybFFT(); + + /* alloc working memory */ + hs->pWorkReal = GetRam_PsHybWkReal(); + hs->pWorkImag = GetRam_PsHybWkImag(); + + if ( (hs->fft==NULL) || (hs->pWorkReal==NULL) || (hs->pWorkImag==NULL) ) { + error = 1; + goto bail; + } + + /* Allocate buffers */ + for (i = 0; i < HYBRID_FRAMESIZE; i++) { + hs->mTempReal[i] = GetRam_PsMtmpReal(i); + hs->mTempImag[i] = GetRam_PsMtmpImag(i); + if ( (hs->mTempReal[i]==NULL) || (hs->mTempImag[i]==NULL) ) { + error = 1; + goto bail; + } + } + +bail: + *phHybrid = hs; + return error; +} + +HANDLE_ERROR_INFO +FDKsbrEnc_InitHybridFilterBank ( HANDLE_PS_HYBRID hs, /*!< Handle to HYBRID struct. */ + HANDLE_PS_HYBRID_CONFIG hHybConfig, /*!< Configuration hanlde for filter bank */ + INT frameSize) /*!< Number of QMF slots */ +{ + HANDLE_ERROR_INFO error = noError; + INT i; + INT maxNoChannels = HYBRID_12_CPLX, noBands; + PS_BANDS mode; + const INT *RESTRICT pResolution; + + /* filter bank configuration */ + mode = hHybConfig->mode; + noBands = hHybConfig->noQmfBandsInHybrid; + pResolution = hHybConfig->aHybridResolution; + + /* assign resolution, check for valid values */ + for (i = 0; i < noBands; i++) { + if(error == noError){ + if( pResolution[i] != HYBRID_12_CPLX && + pResolution[i] != HYBRID_8_CPLX && + pResolution[i] != HYBRID_6_CPLX && + pResolution[i] != HYBRID_2_REAL && + pResolution[i] != (HYBRID_2_REAL | HYBRID_INVERSE_ORDER) && + pResolution[i] != HYBRID_4_CPLX ){ + error = ERROR(CDI, "Invalid filter bank resolution"); + } + } + hs->pResolution[i] = pResolution[i]; + if((pResolution[i] & HYBRID_INVERSE_MASK) > maxNoChannels){ + maxNoChannels = pResolution[i] & HYBRID_INVERSE_MASK; + } + } + FDK_ASSERT (MAX_HYBRID_RES>=maxNoChannels); /* check size of mTempReal/Imag */ + + /* assign parameters */ + hs->mode = mode; + hs->nQmfBands = noBands; + hs->frameSize = frameSize; + hs->frameSizeInit = frameSize; + hs->qmfBufferMove = HYBRID_FILTER_LENGTH - 1; + hs->hybridFilterDelay = HYBRID_FILTER_LENGTH/2; + + FDK_ASSERT (HYBRID_FRAMESIZE>=hs->frameSize); + FDK_ASSERT (QMF_BUFFER_MOVE>=hs->qmfBufferMove); + + return error; +} + + +/**************************************************************************//** + FDKsbrEnc_DeleteHybridFilterBank +******************************************************************************/ + +HANDLE_ERROR_INFO +FDKsbrEnc_DeleteHybridFilterBank ( HANDLE_PS_HYBRID* phHybrid ) /*!< Pointer to handle to HYBRID struct. */ +{ + int i; + HANDLE_PS_HYBRID hHybrid = *phHybrid; + + if (hHybrid!=NULL) { + if (hHybrid->fft) + FreeRam_PsHybFFT(&hHybrid->fft); + if (hHybrid->pWorkReal) + FreeRam_PsHybWkReal(&hHybrid->pWorkReal); + if (hHybrid->pWorkImag) + FreeRam_PsHybWkImag(&hHybrid->pWorkImag); + + for (i = 0; i < HYBRID_FRAMESIZE; i++) { + if (hHybrid->mTempReal[i]) + FreeRam_PsMtmpReal(&hHybrid->mTempReal[i]); + if (hHybrid->mTempImag[i]) + FreeRam_PsMtmpImag(&hHybrid->mTempImag[i]); + } + + FreeRam_PsHybrid(phHybrid); + } + + return noError; +} + +/*** Access functions ***/ +INT FDKsbrEnc_GetHybridFilterDelay(HANDLE_PS_HYBRID hHybrid){ + + return hHybrid->hybridFilterDelay; +} + diff --git a/libSBRenc/src/psenc_hybrid.h b/libSBRenc/src/psenc_hybrid.h new file mode 100644 index 0000000..79e600d --- /dev/null +++ b/libSBRenc/src/psenc_hybrid.h @@ -0,0 +1,182 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: M. Neuendorf, M. Multrus + contents/description: hypbrid filter bank (prototypes) + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#ifndef __hybrid_h +#define __hybrid_h + +/* Includes ******************************************************************/ +#include "sbr_def.h" +#include "ps_const.h" + +#include "qmf.h" + +/* Data Types ****************************************************************/ + +typedef enum { + HYBRID_2_REAL = 2, + HYBRID_4_CPLX = 4, + HYBRID_6_CPLX = 6, + HYBRID_8_CPLX = 8, + HYBRID_12_CPLX = 12 +} HYBRID_RES; + +#define MAX_HYBRID_RES (HYBRID_12_CPLX) + +/* Defines *******************************************************************/ +#define MAX_QMF_BANDS_IN_HYBRID (5) +#define MAX_IID_GROUPS (50) /* NO_IID_GROUPS_HI_RES */ + +#define HYBRID_FILTER_LENGTH ( 13 ) + +#define HYBRID_FRAMESIZE ( QMF_MAX_TIME_SLOTS ) +#define HYBRID_WRITEOFFSET ( 10 ) +#define HYBRID_NUM_BANDS ( 10 ) + +#define NO_QMF_BANDS_HYBRID_10 ( 3 ) +#define NO_QMF_BANDS_HYBRID_20 ( 3 ) +#define HYBRID_MAX_QMF_BANDS ( NO_QMF_BANDS_HYBRID_20 ) + +#define QMF_BUFFER_MOVE ( HYBRID_FILTER_LENGTH - 1 ) + + +/* Data Types ****************************************************************/ +typedef struct PS_HYBRID_CONFIG_tag { + PS_BANDS mode; + + UINT noQmfBandsInHybrid; + INT aHybridResolution[MAX_QMF_BANDS_IN_HYBRID]; /* valid entries from 0 to noQmfBandsInHybrid */ + +} PS_HYBRID_CONFIG, *HANDLE_PS_HYBRID_CONFIG; + +typedef struct PS_HYBRID_tag +{ + PS_BANDS mode; + INT nQmfBands; + INT frameSizeInit; + INT frameSize; + INT pResolution[HYBRID_MAX_QMF_BANDS]; + INT qmfBufferMove; + INT hybridFilterDelay; + + FIXP_DBL *fft; + + FIXP_QMF *pWorkReal; /**< Working arrays for Qmf samples. */ + FIXP_QMF *pWorkImag; + + FIXP_QMF mQmfBufferReal[HYBRID_MAX_QMF_BANDS][QMF_BUFFER_MOVE]; /**< Stores old Qmf samples. */ + FIXP_QMF mQmfBufferImag[HYBRID_MAX_QMF_BANDS][QMF_BUFFER_MOVE]; + FIXP_QMF *mTempReal[HYBRID_FRAMESIZE]; /**< Temporary matrices for filter bank output. */ + FIXP_QMF *mTempImag[HYBRID_FRAMESIZE]; + +} PS_HYBRID; + +typedef struct PS_HYBRID_DATA_tag { + INT frameSize; + INT nHybridBands; + INT nHybridQmfBands; + INT nHybridResolution [HYBRID_MAX_QMF_BANDS]; + + FIXP_QMF* rHybData [(HYBRID_FRAMESIZE + HYBRID_WRITEOFFSET)]; + FIXP_QMF* iHybData [(HYBRID_FRAMESIZE + HYBRID_WRITEOFFSET)]; + SCHAR sf_fixpHybrid; + + INT hybDataReadOffset; + INT hybDataWriteOffset; + +} PS_HYBRID_DATA; + + +typedef struct PS_HYBRID_DATA_tag *HANDLE_PS_HYBRID_DATA; +typedef struct PS_HYBRID_tag *HANDLE_PS_HYBRID; + + + +/* Function Declarations *********************************************/ + +/*****************************************************************************/ +/* **** FILTERBANK CONFIG **** */ + +HANDLE_ERROR_INFO FDKsbrEnc_CreateHybridConfig(HANDLE_PS_HYBRID_CONFIG *phHybConfig, + PS_BANDS mode); + +/*****************************************************************************/ +/* **** FILTERBANK DATA **** */ + +HANDLE_ERROR_INFO FDKsbrEnc_CreateHybridData(HANDLE_PS_HYBRID_DATA *phHybData, + INT ch); + +HANDLE_ERROR_INFO FDKsbrEnc_InitHybridData(HANDLE_PS_HYBRID_DATA hHybData, + HANDLE_PS_HYBRID_CONFIG hHybConfig, + INT frameSize); + +HANDLE_ERROR_INFO FDKsbrEnc_DestroyHybridData(HANDLE_PS_HYBRID_DATA* phHybData); + +inline INT FDKsbrEnc_GetHybridFrameSize(HANDLE_PS_HYBRID_DATA h) { + return h->frameSize; +} + +inline INT FDKsbrEnc_GetNumberHybridBands(HANDLE_PS_HYBRID_DATA h) { + return h->nHybridBands; +} + +inline INT FDKsbrEnc_GetNumberHybridQmfBands(HANDLE_PS_HYBRID_DATA h) { + return h->nHybridQmfBands; +} + +INT FDKsbrEnc_GetHybridResolution(HANDLE_PS_HYBRID_DATA h, INT qmfBand); + + + +/*****************************************************************************/ +/* **** FILTERBANK **** */ + +HANDLE_ERROR_INFO +FDKsbrEnc_CreateHybridFilterBank ( HANDLE_PS_HYBRID *phHybrid, + INT ch ); + +HANDLE_ERROR_INFO +FDKsbrEnc_InitHybridFilterBank ( HANDLE_PS_HYBRID hHybrid, + HANDLE_PS_HYBRID_CONFIG hHybConfig, + INT frameSize ); + +HANDLE_ERROR_INFO +FDKsbrEnc_DeleteHybridFilterBank ( HANDLE_PS_HYBRID* phHybrid ); + +HANDLE_ERROR_INFO +HybridAnalysis ( HANDLE_PS_HYBRID hHybrid, + FIXP_QMF *const * const mQmfReal, + FIXP_QMF *const * const mQmfImag, + SCHAR sf_fixpQmf, + FIXP_QMF **mHybridReal, + FIXP_QMF **mHybridImag, + SCHAR *sf_fixpHybrid); + + +INT +FDKsbrEnc_GetHybridFilterDelay(HANDLE_PS_HYBRID hHybrid); + +#endif /*__hybrid_h*/ diff --git a/libSBRenc/src/resampler.cpp b/libSBRenc/src/resampler.cpp new file mode 100644 index 0000000..0dacc0e --- /dev/null +++ b/libSBRenc/src/resampler.cpp @@ -0,0 +1,450 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +/*! + \file + \brief FDK resampler tool box:$Revision: 11752 $ + \author M. Werner +*/ + +#include "resampler.h" + +#include "genericStds.h" + + +/**************************************************************************/ +/* BIQUAD Filter Specifications */ +/**************************************************************************/ + +#define B1 0 +#define B2 1 +#define A1 2 +#define A2 3 + +#define BQC(x) FL2FXCONST_SGL(x/2) + + +struct FILTER_PARAM { + const FIXP_SGL *coeffa; /*! SOS matrix One row/section. Scaled using BQC(). Order of coefficients: B1,B2,A1,A2. B0=A0=1.0 */ + FIXP_DBL g; /*! overall gain */ + int Wc; /*! normalized passband bandwidth at input samplerate * 1000 */ + int noCoeffs; /*! number of filter coeffs */ + int delay; /*! delay in samples at input samplerate */ +}; + +#define BIQUAD_COEFSTEP 4 + +/** + *\brief Low Pass + Wc = 0,5, order 30, Stop Band -96dB. Wc criteria is "almost 0dB passband", not the usual -3db gain point. + [b,a]=cheby2(30,96,0.505) + [sos,g]=tf2sos(b,a) + bandwidth 0.48 + */ +static const FIXP_SGL sos48[] = { + BQC(1.98941075681938), BQC(0.999999996890811), BQC(0.863264527201963), BQC( 0.189553799960663), + BQC(1.90733804822445), BQC(1.00000001736189), BQC(0.836321575841691), BQC( 0.203505809266564), + BQC(1.75616665495325), BQC(0.999999946079721), BQC(0.784699225121588), BQC( 0.230471265506986), + BQC(1.55727745512726), BQC(1.00000011737815), BQC(0.712515423588351), BQC( 0.268752723900498), + BQC(1.33407591943643), BQC(0.999999795953228), BQC(0.625059117330989), BQC( 0.316194685288965), + BQC(1.10689898412458), BQC(1.00000035057114), BQC(0.52803514366398), BQC( 0.370517843224669), + BQC(0.89060371078454), BQC(0.999999343962822), BQC(0.426920462165257), BQC( 0.429608200207746), + BQC(0.694438261209433), BQC( 1.0000008629792), BQC(0.326530699561716), BQC( 0.491714450654174), + BQC(0.523237800935322), BQC(1.00000101349782), BQC(0.230829556274851), BQC( 0.555559034843281), + BQC(0.378631165929563), BQC(0.99998986482665), BQC(0.142906422036095), BQC( 0.620338874442411), + BQC(0.260786911308437), BQC(1.00003261460178), BQC(0.0651008576256505), BQC( 0.685759923926262), + BQC(0.168409429188098), BQC(0.999933049695828), BQC(-0.000790067789975562), BQC( 0.751905896602325), + BQC(0.100724533818628), BQC(1.00009472669872), BQC(-0.0533772830257041), BQC( 0.81930744384525), + BQC(0.0561434357867363), BQC(0.999911636304276), BQC(-0.0913550299236405), BQC( 0.88883625875915), + BQC(0.0341680678662057), BQC(1.00003667508676), BQC(-0.113405185536697), BQC( 0.961756638268446) +}; + +#ifdef RS_BIQUAD_SCATTERGAIN +static const FIXP_DBL g48 = FL2FXCONST_DBL(0.67436532061161992682404480717671 - 0.001); +#else +static const FIXP_DBL g48 = FL2FXCONST_DBL(0.002712866530047) - (FIXP_DBL)0x8000; +#endif + +static const struct FILTER_PARAM param_set48 = { + sos48, + g48, + 480, + 15, + 4 /* LF 2 */ +}; + +/** + *\brief Low Pass + Wc = 0,5, order 24, Stop Band -96dB. Wc criteria is "almost 0dB passband", not the usual -3db gain point. + [b,a]=cheby2(24,96,0.5) + [sos,g]=tf2sos(b,a) + bandwidth 0.45 + */ +static const FIXP_SGL sos45[] = { + BQC(1.982962601444), BQC(1.00000000007504), BQC(0.646113303737836), BQC( 0.10851149979981), + BQC(1.85334094281111), BQC(0.999999999677192), BQC(0.612073220102006), BQC( 0.130022141698044), + BQC(1.62541051415425), BQC(1.00000000080398), BQC(0.547879702855959), BQC( 0.171165825133192), + BQC(1.34554656923247), BQC(0.9999999980169), BQC(0.460373914508491), BQC( 0.228677463376354), + BQC(1.05656568503116), BQC(1.00000000569363), BQC(0.357891894038287), BQC( 0.298676843912185), + BQC(0.787967587877312), BQC(0.999999984415017), BQC(0.248826893211877), BQC( 0.377441803512978), + BQC(0.555480971120497), BQC(1.00000003583307), BQC(0.140614263345315), BQC( 0.461979302213679), + BQC(0.364986207070964), BQC(0.999999932084303), BQC(0.0392669446074516), BQC( 0.55033451180825), + BQC(0.216827267631558), BQC(1.00000010534682), BQC(-0.0506232228865103), BQC( 0.641691581560946), + BQC(0.108951672277119), BQC(0.999999871167516), BQC(-0.125584840183225), BQC( 0.736367748771803), + BQC(0.0387988607229035), BQC(1.00000011205574), BQC(-0.182814849097974), BQC( 0.835802108714964), + BQC(0.0042866175809225), BQC(0.999999954830813), BQC(-0.21965740617151), BQC( 0.942623047782363) +}; + +#ifdef RS_BIQUAD_SCATTERGAIN +static const FIXP_DBL g45 = FL2FXCONST_DBL(0.60547428891341319051142629706723 - 0.001); +#else +static const FIXP_DBL g45 = FL2FXCONST_DBL(0.00242743980909524) - (FIXP_DBL)0x8000; +#endif + +static const struct FILTER_PARAM param_set45 = { + sos45, + g45, + 450, + 12, + 4 /* LF 2 */ +}; + +/* + Created by Octave 2.1.73, Mon Oct 13 17:31:32 2008 CEST + Wc = 0,5, order 16, Stop Band -96dB damping. + [b,a]=cheby2(16,96,0.5) + [sos,g]=tf2sos(b,a) + bandwidth = 0.41 + */ + +static const FIXP_SGL sos41[] = +{ + BQC(1.96193625292), BQC(0.999999999999964), BQC(0.169266178786789), BQC(0.0128823300475907), + BQC(1.68913437662092), BQC(1.00000000000053), BQC(0.124751503206552), BQC(0.0537472273950989), + BQC(1.27274692366017), BQC(0.999999999995674), BQC(0.0433108625178357), BQC(0.131015753236317), + BQC(0.85214175088395), BQC(1.00000000001813), BQC(-0.0625658152550408), BQC(0.237763778993806), + BQC(0.503841579939009), BQC(0.999999999953223), BQC(-0.179176128722865), BQC(0.367475236424474), + BQC(0.249990711986162), BQC(1.00000000007952), BQC(-0.294425165824676), BQC(0.516594857170212), + BQC(0.087971668680286), BQC(0.999999999915528), BQC(-0.398956566777928), BQC(0.686417767801123), + BQC(0.00965373325350294), BQC(1.00000000003744), BQC(-0.48579173764817), BQC(0.884931534239068) +}; + +#ifdef RS_BIQUAD_SCATTERGAIN +static const FIXP_DBL g41 = FL2FXCONST_DBL(0.44578514476476679750811222123569); +#else +static const FIXP_DBL g41 = FL2FXCONST_DBL(0.00155956951169248); +#endif + +static const struct FILTER_PARAM param_set41 = { + sos41, + g41, + 410, + 8, + 5 /* LF 3 */ +}; + +/* + # Created by Octave 2.1.73, Mon Oct 13 17:55:33 2008 CEST + Wc = 0,5, order 12, Stop Band -96dB damping. + [b,a]=cheby2(12,96,0.5); + [sos,g]=tf2sos(b,a) +*/ +static const FIXP_SGL sos35[] = +{ + BQC(1.93299325235762), BQC(0.999999999999985), BQC(-0.140733187246596), BQC(0.0124139497836062), + BQC(1.4890416764109), BQC(1.00000000000011), BQC(-0.198215402588504), BQC(0.0746730616584138), + BQC(0.918450161309795), BQC(0.999999999999619), BQC(-0.30133912791941), BQC(0.192276468839529), + BQC(0.454877024246818), BQC(1.00000000000086), BQC(-0.432337328809815), BQC(0.356852933642815), + BQC(0.158017147118507), BQC(0.999999999998876), BQC(-0.574817494249777), BQC(0.566380436970833), + BQC(0.0171834649478749), BQC(1.00000000000055), BQC(-0.718581178041165), BQC(0.83367484487889) +}; + +#ifdef RS_BIQUAD_SCATTERGAIN +static const FIXP_DBL g35 = FL2FXCONST_DBL(0.34290853574973898694521267606792); +#else +static const FIXP_DBL g35 = FL2FXCONST_DBL(0.00162580994125131); +#endif + +static const struct FILTER_PARAM param_set35 = { + sos35, + g35, + 350, + 6, + 4 +}; + +/* + # Created by Octave 2.1.73, Mon Oct 13 18:15:38 2008 CEST + Wc = 0,5, order 8, Stop Band -96dB damping. + [b,a]=cheby2(8,96,0.5); + [sos,g]=tf2sos(b,a) +*/ +static const FIXP_SGL sos25[] = +{ + BQC(1.85334094301225), BQC(1.0), BQC(-0.702127214212663), BQC(0.132452403998767), + BQC(1.056565682167), BQC(0.999999999999997), BQC(-0.789503667880785), BQC(0.236328693569128), + BQC(0.364986307455489), BQC(0.999999999999996), BQC(-0.955191189843375), BQC(0.442966457936379), + BQC(0.0387985751642125), BQC(1.0), BQC(-1.19817786088084), BQC(0.770493895456328) +}; + +#ifdef RS_BIQUAD_SCATTERGAIN +static const FIXP_DBL g25 = FL2FXCONST_DBL(0.17533917408936346960080259950471); +#else +static const FIXP_DBL g25 = FL2FXCONST_DBL(0.000945182835294559); +#endif + +static const struct FILTER_PARAM param_set25 = { + sos25, + g25, + 250, + 4, + 5 +}; + +/* Must be sorted in descending order */ +static const struct FILTER_PARAM *const filter_paramSet[] = { + ¶m_set48, + ¶m_set45, + ¶m_set41, + ¶m_set35, + ¶m_set25 +}; + + +/**************************************************************************/ +/* Resampler Functions */ +/**************************************************************************/ + + +/*! + \brief Reset downsampler instance and clear delay lines + + \return success of operation +*/ + +INT FDKaacEnc_InitDownsampler(DOWNSAMPLER *DownSampler, /*!< pointer to downsampler instance */ + int Wc, /*!< normalized cutoff freq * 1000* */ + int ratio) /*!< downsampler ratio (only 2 supported at the momment) */ + +{ + UINT i; + const struct FILTER_PARAM *currentSet=NULL; + + FDK_ASSERT(ratio == 2); + FDKmemclear(DownSampler->downFilter.states, sizeof(DownSampler->downFilter.states)); + DownSampler->downFilter.ptr = 0; + + /* + find applicable parameter set + */ + currentSet = filter_paramSet[0]; + for(i=1;iWc <= Wc) { + break; + } + currentSet = filter_paramSet[i]; + } + + DownSampler->downFilter.coeffa = currentSet->coeffa; + + + DownSampler->downFilter.gain = currentSet->g; + FDK_ASSERT(currentSet->noCoeffs <= MAXNR_SECTIONS*2); + + DownSampler->downFilter.noCoeffs = currentSet->noCoeffs; + DownSampler->delay = currentSet->delay; + DownSampler->downFilter.Wc = currentSet->Wc; + + DownSampler->ratio = ratio; + DownSampler->pending = ratio-1; + return(1); +} + + +/*! + \brief faster simple folding operation + Filter: + H(z) = A(z)/B(z) + with + A(z) = a[0]*z^0 + a[1]*z^1 + a[2]*z^2 ... a[n]*z^n + + \return filtered value +*/ + +static inline INT_PCM AdvanceFilter(LP_FILTER *downFilter, /*!< pointer to iir filter instance */ + INT_PCM *pInput, /*!< input of filter */ + int downRatio, + int inStride) +{ + INT_PCM output; + int i, n; + + +#ifdef RS_BIQUAD_SCATTERGAIN +#define BIQUAD_SCALE 3 +#else +#define BIQUAD_SCALE 12 +#endif + + FIXP_DBL y = FL2FXCONST_DBL(0.0f); + FIXP_DBL input; + + for (n=0; nstates; + const FIXP_SGL *coeff = downFilter->coeffa; + int s1,s2; + + s1 = downFilter->ptr; + s2 = s1 ^ 1; + +#if (SAMPLE_BITS == 16) + input = ((FIXP_DBL)pInput[n*inStride]) << (DFRACT_BITS-SAMPLE_BITS-BIQUAD_SCALE); +#elif (SAMPLE_BITS == 32) + input = pInput[n*inStride] >> BIQUAD_SCALE; +#else +#error NOT IMPLEMENTED +#endif + +#ifndef RS_BIQUAD_SCATTERGAIN /* Merged Direct form I */ + + FIXP_BQS state1, state2, state1b, state2b; + + state1 = states[0][s1]; + state2 = states[0][s2]; + + /* Loop over sections */ + for (i=0; inoCoeffs; i++) + { + FIXP_DBL state0; + + /* Load merged states (from next section) */ + state1b = states[i+1][s1]; + state2b = states[i+1][s2]; + + state0 = input + fMult(state1, coeff[B1]) + fMult(state2, coeff[B2]); + y = state0 - fMult(state1b, coeff[A1]) - fMult(state2b, coeff[A2]); + + /* Store new feed forward merge state */ + states[i+1][s2] = y<<1; + /* Store new feed backward state */ + states[i][s2] = input<<1; + + /* Feedback output to next section. */ + input = y; + + /* Transfer merged states */ + state1 = state1b; + state2 = state2b; + + /* Step to next coef set */ + coeff += BIQUAD_COEFSTEP; + } + downFilter->ptr ^= 1; + } + /* Apply global gain */ + y = fMult(y, downFilter->gain); + +#else /* Direct form II */ + + /* Loop over sections */ + for (i=0; inoCoeffs; i++) + { + FIXP_BQS state1, state2; + FIXP_DBL state0; + + /* Load states */ + state1 = states[i][s1]; + state2 = states[i][s2]; + + state0 = input - fMult(state1, coeff[A1]) - fMult(state2, coeff[A2]); + y = state0 + fMult(state1, coeff[B1]) + fMult(state2, coeff[B2]); + /* Apply scattered gain */ + y = fMult(y, downFilter->gain); + + /* Store new state in normalized form */ +#ifdef RS_BIQUAD_STATES16 + /* Do not saturate any state value ! The result would be unacceptable. Rounding makes SNR around 10dB better. */ + states[i][s2] = (FIXP_BQS)(LONG)((state0 + (FIXP_DBL)(1<<(DFRACT_BITS-FRACT_BITS-2))) >> (DFRACT_BITS-FRACT_BITS-1)); +#else + states[i][s2] = state0<<1; +#endif + + /* Feedback output to next section. */ + input=y; + + /* Step to next coef set */ + coeff += BIQUAD_COEFSTEP; + } + downFilter->ptr ^= 1; + } + +#endif + + /* Apply final gain/scaling to output */ +#if (SAMPLE_BITS == 16) + output = (INT_PCM) SATURATE_RIGHT_SHIFT(y+(FIXP_DBL)(1<<(DFRACT_BITS-SAMPLE_BITS-BIQUAD_SCALE-1)), DFRACT_BITS-SAMPLE_BITS-BIQUAD_SCALE, SAMPLE_BITS); + //output = (INT_PCM) SATURATE_RIGHT_SHIFT(y, DFRACT_BITS-SAMPLE_BITS-BIQUAD_SCALE, SAMPLE_BITS); +#else + output = SATURATE_LEFT_SHIFT(y, BIQUAD_SCALE, SAMPLE_BITS); +#endif + + + return output; +} + + + + +/*! + \brief FDKaacEnc_Downsample numInSamples of type INT_PCM + Returns number of output samples in numOutSamples + + \return success of operation +*/ + +INT FDKaacEnc_Downsample(DOWNSAMPLER *DownSampler, /*!< pointer to downsampler instance */ + INT_PCM *inSamples, /*!< pointer to input samples */ + INT numInSamples, /*!< number of input samples */ + INT inStride, /*!< increment of input samples */ + INT_PCM *outSamples, /*!< pointer to output samples */ + INT *numOutSamples, /*!< pointer tp number of output samples */ + INT outStride /*!< increment of output samples */ + ) +{ + INT i; + *numOutSamples=0; + + for(i=0; iratio) + { + *outSamples = AdvanceFilter(&(DownSampler->downFilter), &inSamples[i*inStride], DownSampler->ratio, inStride); + outSamples += outStride; + } + *numOutSamples = numInSamples/DownSampler->ratio; + + return 0; +} + diff --git a/libSBRenc/src/resampler.h b/libSBRenc/src/resampler.h new file mode 100644 index 0000000..0815ba9 --- /dev/null +++ b/libSBRenc/src/resampler.h @@ -0,0 +1,109 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +#ifndef __RESAMPLER_H +#define __RESAMPLER_H +/*! + \file + \brief Fixed Point Resampler Tool Box $Revision: 11752 $ +*/ + +/*! + \mainpage Fixed Point Resampler Library Documentation + + Information in this SDK is subject to change without notice. Companies, + names, and data used in examples herein are fictitious unless otherwise + noted. + + Product and corporate names may be trademarks or registered trademarks + of other companies. They are used for explanation only, with no intent + to infringe. + + No part of this publication may be reproduced or utilized in any form or + by any means, electronic or mechanical, including photocopying and + microfilm, without permission in writing from the publisher. +*/ + +#include "common_fix.h" + + +/**************************************************************************/ +/* BIQUAD Filter Structure */ +/**************************************************************************/ + +#define MAXNR_SECTIONS (15) + +#ifdef RS_BIQUAD_STATES16 +typedef FIXP_SGL FIXP_BQS; +#else +typedef FIXP_DBL FIXP_BQS; +#endif + +typedef struct +{ + FIXP_BQS states[MAXNR_SECTIONS+1][2]; /*! state buffer */ + const FIXP_SGL *coeffa; /*! pointer to filter coeffs */ + FIXP_DBL gain; /*! overall gain factor */ + int Wc; /*! normalized cutoff freq * 1000 */ + int noCoeffs; /*! number of filter coeffs sets */ + int ptr; /*! index to rinbuffers */ +} LP_FILTER; + + +/**************************************************************************/ +/* Downsampler Structure */ +/**************************************************************************/ + +typedef struct +{ + LP_FILTER downFilter; /*! filter instance */ + int ratio; /*! downsampling ration */ + int delay; /*! downsampling delay (source fs) */ + int pending; /*! number of pending output samples */ +} DOWNSAMPLER; + + +/** + * \brief Initialized a given downsampler structure. + */ +INT FDKaacEnc_InitDownsampler(DOWNSAMPLER *DownSampler, /*!< pointer to downsampler instance */ + INT Wc, /*!< normalized cutoff freq * 1000 */ + INT ratio); /*!< downsampler ratio */ + +/** + * \brief Downsample a set of audio samples. numInSamples must be at least equal to the + * downsampler ratio. + */ +INT FDKaacEnc_Downsample(DOWNSAMPLER *DownSampler, /*!< pointer to downsampler instance */ + INT_PCM *inSamples, /*!< pointer to input samples */ + INT numInSamples, /*!< number of input samples */ + INT inStride, /*!< increment of input samples */ + INT_PCM *outSamples, /*!< pointer to output samples */ + INT *numOutSamples, /*!< pointer tp number of output samples */ + INT outstride); /*!< increment of output samples */ + + + +#endif /* __RESAMPLER_H */ diff --git a/libSBRenc/src/sbr.h b/libSBRenc/src/sbr.h new file mode 100644 index 0000000..40a3953 --- /dev/null +++ b/libSBRenc/src/sbr.h @@ -0,0 +1,107 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Main SBR structs definitions $Revision: 36847 $ +*/ + +#ifndef __SBR_H +#define __SBR_H + +#include "fram_gen.h" +#include "bit_sbr.h" +#include "tran_det.h" +#include "code_env.h" +#include "env_est.h" +#include "cmondata.h" + +#include "qmf.h" +#include "resampler.h" + +#include "ton_corr.h" + + +/* SBR bitstream delay */ + #define DELAY_FRAMES 2 + +typedef struct { + struct ENV_CHANNEL hEnvChannel; + //INT_PCM *pDSOutBuffer; /**< Pointer to downsampled audio output of SBR encoder */ + DOWNSAMPLER downSampler; + +} SBR_CHANNEL; +typedef SBR_CHANNEL* HANDLE_SBR_CHANNEL; + +typedef struct { + HANDLE_SBR_CHANNEL sbrChannel[2]; + QMF_FILTER_BANK *hQmfAnalysis[2]; + SBR_CONFIG_DATA sbrConfigData; + SBR_HEADER_DATA sbrHeaderData; + SBR_BITSTREAM_DATA sbrBitstreamData; + COMMON_DATA CmonData; + INT dynXOverFreqDelay[5]; /**< to delay a frame (I don't like it that much that way - hrc) */ + SBR_ELEMENT_INFO elInfo; + + UCHAR payloadDelayLine[1+DELAY_FRAMES][MAX_PAYLOAD_SIZE]; + UINT payloadDelayLineSize[1+DELAY_FRAMES]; /* Sizes in bits */ + +} SBR_ELEMENT; +typedef SBR_ELEMENT* HANDLE_SBR_ELEMENT; + +struct SBR_ENCODER +{ + HANDLE_SBR_ELEMENT sbrElement[(6)]; + HANDLE_SBR_CHANNEL pSbrChannel[(6)]; + QMF_FILTER_BANK QmfAnalysis[(6)]; + DOWNSAMPLER lfeDownSampler; + int lfeChIdx; /* -1 default for no lfe, else assign channel index */ + int noElements; /* Number of elements */ + int nChannels; /* Total channel count across all elements. */ + int frameSize; /* SBR framelength. */ + int bufferOffset; /* Offset for SBR parameter extraction in time domain input buffer. */ + int downsampledOffset; /* Offset of downsampled/mixed output for core encoder. */ + int downmixSize; /* Size in samples of downsampled/mixed output for core encoder. */ + int fTimeDomainDownsampling; /* Flag signalling time domain downsampling instead of QMF downsampling. */ + int nBitstrDelay; /* Amount of SBR frames to be delayed in bitstream domain. */ + INT estimateBitrate; /* estimate bitrate of SBR encoder */ + INT inputDataDelay; /* delay caused by downsampler, in/out buffer at sbrEncoder_EncodeFrame */ + + UCHAR* dynamicRam; + UCHAR* pSBRdynamic_RAM; + + HANDLE_PSENC_CONFIG hPsEncConfig; + HANDLE_PARAMETRIC_STEREO hParametricStereo; + QMF_FILTER_BANK qmfSynthesisPS; + + /* parameters describing allocation volume of present instance */ + INT maxElements; + INT maxChannels; + INT supportPS; + +} ; + + +#endif /* __SBR_H */ diff --git a/libSBRenc/src/sbr_def.h b/libSBRenc/src/sbr_def.h new file mode 100644 index 0000000..592c1e0 --- /dev/null +++ b/libSBRenc/src/sbr_def.h @@ -0,0 +1,228 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief SBR main definitions $Revision: 36847 $ +*/ +#ifndef __SBR_DEF_H +#define __SBR_DEF_H + +#include "common_fix.h" + +#define noError 0 +#define HANDLE_ERROR_INFO INT +#define ERROR(a,b) 1 +#define handBack + +/* #define SBR_ENV_STATISTICS_BITRATE */ +#undef SBR_ENV_STATISTICS_BITRATE + +/* #define SBR_ENV_STATISTICS */ +#undef SBR_ENV_STATISTICS + +/* #define SBR_PAYLOAD_MONITOR */ +#undef SBR_PAYLOAD_MONITOR + +#define SWAP(a,b) tempr=a, a=b, b=tempr +#define TRUE 1 +#define FALSE 0 + + +/* Constants */ +#define EPS 1e-12 +#define LOG2 0.69314718056f /* natural logarithm of 2 */ +#define ILOG2 1.442695041f /* 1/LOG2 */ +#define RELAXATION_FLOAT (1e-6f) +#define RELAXATION (FL2FXCONST_DBL(RELAXATION_FLOAT)) +#define RELAXATION_FRACT (FL2FXCONST_DBL(0.524288f)) /* 0.524288f is fractional part of RELAXATION */ +#define RELAXATION_SHIFT (19) +#define RELAXATION_LD64 (FL2FXCONST_DBL(0.31143075889f))/* (ld64(RELAXATION) */ + +/************ Definitions ***************/ +#define SBR_COMP_MODE_DELTA 0 +#define SBR_COMP_MODE_CTS 1 + +#define MAX_NUM_CHANNELS 2 + +#define MAX_NOISE_ENVELOPES 2 +#define MAX_NUM_NOISE_COEFFS 5 +#define MAX_NUM_NOISE_VALUES (MAX_NUM_NOISE_COEFFS*MAX_NOISE_ENVELOPES) + +#define MAX_NUM_ENVELOPE_VALUES (MAX_ENVELOPES * MAX_FREQ_COEFFS) +#define MAX_ENVELOPES 5 +#define MAX_FREQ_COEFFS 48 + +#define MAX_FREQ_COEFFS_FS44100 35 +#define MAX_FREQ_COEFFS_FS48000 32 + + +#define QMF_CHANNELS 64 +#define QMF_FILTER_LENGTH 640 +#define QMF_MAX_TIME_SLOTS 32 +#define NO_OF_ESTIMATES_LC 4 +#define NO_OF_ESTIMATES_LD 3 +#define MAX_NO_OF_ESTIMATES 4 + + +#define NOISE_FLOOR_OFFSET 6 +#define NOISE_FLOOR_OFFSET_64 (FL2FXCONST_DBL(0.09375f)) + +#define LOW_RES 0 +#define HIGH_RES 1 + +#define LO 0 +#define HI 1 + +#define LENGTH_SBR_FRAME_INFO 35 /* 19 */ + +#define SBR_NSFB_LOW_RES 9 /* 8 */ +#define SBR_NSFB_HIGH_RES 18 /* 16 */ + + +#define SBR_XPOS_CTRL_DEFAULT 2 + +#define SBR_FREQ_SCALE_DEFAULT 2 +#define SBR_ALTER_SCALE_DEFAULT 1 +#define SBR_NOISE_BANDS_DEFAULT 2 + +#define SBR_LIMITER_BANDS_DEFAULT 2 +#define SBR_LIMITER_GAINS_DEFAULT 2 +#define SBR_LIMITER_GAINS_INFINITE 3 +#define SBR_INTERPOL_FREQ_DEFAULT 1 +#define SBR_SMOOTHING_LENGTH_DEFAULT 0 + + +/* sbr_header */ +#define SI_SBR_AMP_RES_BITS 1 +#define SI_SBR_COUPLING_BITS 1 +#define SI_SBR_START_FREQ_BITS 4 +#define SI_SBR_STOP_FREQ_BITS 4 +#define SI_SBR_XOVER_BAND_BITS 3 +#define SI_SBR_RESERVED_BITS 2 +#define SI_SBR_DATA_EXTRA_BITS 1 +#define SI_SBR_HEADER_EXTRA_1_BITS 1 +#define SI_SBR_HEADER_EXTRA_2_BITS 1 + +/* sbr_header extra 1 */ +#define SI_SBR_FREQ_SCALE_BITS 2 +#define SI_SBR_ALTER_SCALE_BITS 1 +#define SI_SBR_NOISE_BANDS_BITS 2 + +/* sbr_header extra 2 */ +#define SI_SBR_LIMITER_BANDS_BITS 2 +#define SI_SBR_LIMITER_GAINS_BITS 2 +#define SI_SBR_INTERPOL_FREQ_BITS 1 +#define SI_SBR_SMOOTHING_LENGTH_BITS 1 + +/* sbr_grid */ +#define SBR_CLA_BITS 2 /*!< size of bs_frame_class */ +#define SBR_CLA_BITS_LD 1 /*!< size of bs_frame_class */ +#define SBR_ENV_BITS 2 /*!< size of bs_num_env_raw */ +#define SBR_ABS_BITS 2 /*!< size of bs_abs_bord_raw for HE-AAC */ +#define SBR_NUM_BITS 2 /*!< size of bs_num_rel */ +#define SBR_REL_BITS 2 /*!< size of bs_rel_bord_raw */ +#define SBR_RES_BITS 1 /*!< size of bs_freq_res_flag */ +#define SBR_DIR_BITS 1 /*!< size of bs_df_flag */ + + +/* sbr_data */ +#define SI_SBR_INVF_MODE_BITS 2 + + +#define SI_SBR_START_ENV_BITS_AMP_RES_3_0 6 +#define SI_SBR_START_ENV_BITS_BALANCE_AMP_RES_3_0 5 +#define SI_SBR_START_NOISE_BITS_AMP_RES_3_0 5 +#define SI_SBR_START_NOISE_BITS_BALANCE_AMP_RES_3_0 5 + +#define SI_SBR_START_ENV_BITS_AMP_RES_1_5 7 +#define SI_SBR_START_ENV_BITS_BALANCE_AMP_RES_1_5 6 + + +#define SI_SBR_EXTENDED_DATA_BITS 1 +#define SI_SBR_EXTENSION_SIZE_BITS 4 +#define SI_SBR_EXTENSION_ESC_COUNT_BITS 8 +#define SI_SBR_EXTENSION_ID_BITS 2 + +#define SBR_EXTENDED_DATA_MAX_CNT (15+255) + +#define EXTENSION_ID_PS_CODING 2 + +/* Envelope coding constants */ +#define FREQ 0 +#define TIME 1 + + +/* huffman tables */ +#define CODE_BOOK_SCF_LAV00 60 +#define CODE_BOOK_SCF_LAV01 31 +#define CODE_BOOK_SCF_LAV10 60 +#define CODE_BOOK_SCF_LAV11 31 +#define CODE_BOOK_SCF_LAV_BALANCE11 12 +#define CODE_BOOK_SCF_LAV_BALANCE10 24 + +typedef enum +{ + SBR_AMP_RES_1_5=0, + SBR_AMP_RES_3_0 +} +AMP_RES; + +typedef enum +{ + XPOS_MDCT, + XPOS_MDCT_CROSS, + XPOS_LC, + XPOS_RESERVED, + XPOS_SWITCHED /* not a real choice but used here to control behaviour */ +} +XPOS_MODE; + +typedef enum +{ + INVF_OFF = 0, + INVF_LOW_LEVEL, + INVF_MID_LEVEL, + INVF_HIGH_LEVEL, + INVF_SWITCHED /* not a real choice but used here to control behaviour */ +} +INVF_MODE; + +typedef enum +{ + SINGLE_RATE, + DUAL_RATE +} +SR_MODE; + +typedef enum +{ + FREQ_RES_LOW = 0, + FREQ_RES_HIGH +} +FREQ_RES; + + +#endif diff --git a/libSBRenc/src/sbr_encoder.cpp b/libSBRenc/src/sbr_encoder.cpp new file mode 100644 index 0000000..9c3cf37 --- /dev/null +++ b/libSBRenc/src/sbr_encoder.cpp @@ -0,0 +1,2109 @@ +/*************************** Fraunhofer IIS FDK Tools *********************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Andreas Ehret + Description: SBR encoder top level processing. + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#include "sbr_encoder.h" + +#include "sbr_ram.h" +#include "sbr_rom.h" +#include "sbrenc_freq_sca.h" +#include "env_bit.h" +#include "cmondata.h" +#include "sbr_misc.h" +#include "sbr.h" +#include "qmf.h" + +#include "ps_main.h" +#include "psenc_hybrid.h" + +#define SBRENCODER_LIB_VL0 3 +#define SBRENCODER_LIB_VL1 2 +#define SBRENCODER_LIB_VL2 0 + + + +/***************************************************************************/ +/* + * SBR Delay balancing definitions. + */ + +/* + input buffer (1ch) + + |------------ 1537 -------------|-----|---------- 2048 -------------| + (core2sbr delay ) ds (read, core and ds area) +*/ + +#define DOWN_SMPL_FAC (2) + +#define SFL(fl) (fl*DOWN_SMPL_FAC) /* SBR frame length (hardcoded to downsample factor of 2) */ +#define STS(fl) (SFL(fl)/64) /* SBR Time Slots */ + +#define DELAY_QMF_ANA (640 - 64) /* Full bandwidth */ +#define DELAY_QMF_ANAELD (32) +#define DELAY_HYB_ANA (10*64) /* + 0.5 */ +#define DELAY_HYB_SYN (6*64 - 32) +#define DELAY_QMF_SYNELD (32) +#define DELAY_DEC_QMF (6*64) /* Decoder QMF overlap */ +#define DELAY_QMF_SYN (2) /* NO_POLY/2 */ +#define DELAY_QMF_DS (32) /* QMF synthesis for downsampled time signal */ + +/* Delay in QMF paths */ +#define DELAY_SBR(fl) (DELAY_QMF_ANA + (64*STS(fl)-1) + DELAY_QMF_SYN) +#define DELAY_PS(fl) (DELAY_QMF_ANA + DELAY_HYB_ANA + DELAY_DEC_QMF + (64*STS(fl)-1) + DELAY_HYB_SYN + DELAY_QMF_SYN) +#define DELAY_ELDSBR(fl) (DELAY_QMF_ANAELD + (((fl)+((fl)/2))*2 - 1) + DELAY_QMF_SYNELD) + +/* Delay differences for SBR and SBR+PS */ + #define MAX_DS_FILTER_DELAY (34) /* the additional max downsampler filter delay (source fs) */ +#define DELAY_AAC2SBR(fl) ((/*RESAMPLER +*/ /*(DELAY_AAC(fl)*2) + */ DELAY_QMF_ANA + DELAY_DEC_QMF + DELAY_QMF_SYN) - DELAY_SBR(fl)) /* 1537 */ +#define DELAY_ELD2SBR(fl) ((/*RESAMPLER +*/ /*(DELAY_ELD(fl)*2) + */ DELAY_QMF_ANAELD + DELAY_QMF_SYNELD) - DELAY_ELDSBR(fl)) + +#define DELAY_AAC2PS(fl) ((DELAY_QMF_ANA + DELAY_QMF_DS + /*(DELAY_AAC(fl)*2)*/ + DELAY_QMF_ANA + DELAY_DEC_QMF + DELAY_HYB_SYN + DELAY_QMF_SYN) - DELAY_PS(fl)) /* 2048 - 463*2 */ + +/* Assumption: that the sample delay resulting of of DELAY_AAC2PS is always smaller than the sample delay implied by DELAY_AAC2SBR */ +#define MAX_SAMPLE_DELAY (DELAY_AAC2SBR(1024) + MAX_DS_FILTER_DELAY) + +/***************************************************************************/ + + + +#define INVALID_TABLE_IDX -1 + +/***************************************************************************/ +/*! + + \brief Selects the SBR tuning settings to use dependent on number of + channels, bitrate, sample rate and core coder + + \return Index to the appropriate table + +****************************************************************************/ +static INT +getSbrTuningTableIndex(UINT bitrate, /*! the total bitrate in bits/sec */ + UINT numChannels,/*! the number of channels for the core coder */ + UINT sampleRate, /*! the sampling rate of the core coder */ + AUDIO_OBJECT_TYPE core + ) +{ + int i, paramSetTop; + + if (core == AOT_ER_AAC_ELD) { + paramSetTop = SBRENC_TUNING_SIZE; + i = 126; + } else { + paramSetTop = 126; + i = 0; + } + + for (; i < paramSetTop ; i++) { + if (numChannels == sbrTuningTable [i].numChannels) { + if ((sampleRate == sbrTuningTable [i].sampleRate) && + (bitrate >= sbrTuningTable [i].bitrateFrom) && + (bitrate < sbrTuningTable [i].bitrateTo)) { + return i ; + } + } + } + + return INVALID_TABLE_IDX; +} + +/***************************************************************************/ +/*! + + \brief Selects the PS tuning settings to use dependent on bitrate + and core coder + + \return Index to the appropriate table + +****************************************************************************/ +static INT +getPsTuningTableIndex(UINT bitrate){ + + INT i, paramSets = sizeof (psTuningTable) / sizeof (psTuningTable [0]); + + for (i = 0 ; i < paramSets ; i++) { + if ((bitrate >= psTuningTable [i].bitrateFrom) && + (bitrate < psTuningTable [i].bitrateTo)) { + return i ; + } + } + + return INVALID_TABLE_IDX; +} + + +/***************************************************************************/ +/*! + + \brief tells us, if for the given coreCoder, bitrate, number of channels + and input sampling rate an SBR setting is available. If yes, it + tells us also the core sampling rate we would need to run with + + \return a flag indicating success: yes (1) or no (0) + +****************************************************************************/ +static UINT +FDKsbrEnc_IsSbrSettingAvail (UINT bitrate, /*! the total bitrate in bits/sec */ + UINT vbrMode, /*! the vbr paramter, 0 means constant bitrate */ + UINT numOutputChannels,/*! the number of channels for the core coder */ + UINT sampleRateInput, /*! the input sample rate [in Hz] */ + AUDIO_OBJECT_TYPE core + ) +{ + INT idx = INVALID_TABLE_IDX; + UINT sampleRateCore; + + if (sampleRateInput < 16000) + return 0; + + if (bitrate==0) { + /* map vbr quality to bitrate */ + if (vbrMode < 30) + bitrate = 24000; + else if (vbrMode < 40) + bitrate = 28000; + else if (vbrMode < 60) + bitrate = 32000; + else if (vbrMode < 75) + bitrate = 40000; + else + bitrate = 48000; + bitrate *= numOutputChannels; + } + + /* try DOWN_SMPL_FAC of the input sampling rate */ + sampleRateCore = sampleRateInput/DOWN_SMPL_FAC; + idx = getSbrTuningTableIndex(bitrate, numOutputChannels, sampleRateCore, core); + + return (idx == INVALID_TABLE_IDX ? 0 : 1); +} + + +/***************************************************************************/ +/*! + + \brief Adjusts the SBR settings according to the chosen core coder + settings which are accessible via config->codecSettings + + \return A flag indicating success: yes (1) or no (0) + +****************************************************************************/ +static UINT +FDKsbrEnc_AdjustSbrSettings (const sbrConfigurationPtr config, /*! output, modified */ + UINT bitRate, /*! the total bitrate in bits/sec */ + UINT numChannels, /*! the core coder number of channels */ + UINT fsCore, /*! the core coder sampling rate in Hz */ + UINT transFac, /*! the short block to long block ratio */ + UINT standardBitrate, /*! the standard bitrate per channel in bits/sec */ + UINT vbrMode, /*! the vbr paramter, 0 poor quality .. 100 high quality*/ + UINT useSpeechConfig, /*!< adapt tuning parameters for speech ? */ + UINT lcsMode, /*! the low complexity stereo mode */ + UINT bParametricStereo, /*!< use parametric stereo */ + AUDIO_OBJECT_TYPE core) /* Core audio codec object type */ +{ + INT idx = INVALID_TABLE_IDX; + UINT sampleRate; + + /* set the codec settings */ + config->codecSettings.bitRate = bitRate; + config->codecSettings.nChannels = numChannels; + config->codecSettings.sampleFreq = fsCore; + config->codecSettings.transFac = transFac; + config->codecSettings.standardBitrate = standardBitrate; + sampleRate = fsCore * DOWN_SMPL_FAC; + + if (bitRate==0) { + /* map vbr quality to bitrate */ + if (vbrMode < 30) + bitRate = 24000; + else if (vbrMode < 40) + bitRate = 28000; + else if (vbrMode < 60) + bitRate = 32000; + else if (vbrMode < 75) + bitRate = 40000; + else + bitRate = 48000; + bitRate *= numChannels; + /* fix to enable mono vbrMode<40 @ 44.1 of 48kHz */ + if (numChannels==1) { + if (sampleRate==44100 || sampleRate==48000) { + if (vbrMode<40) bitRate = 32000; + } + } + } + + idx = getSbrTuningTableIndex(bitRate,numChannels,fsCore, core); + + if (idx != INVALID_TABLE_IDX) { + config->startFreq = sbrTuningTable[idx].startFreq ; + config->stopFreq = sbrTuningTable[idx].stopFreq ; + if (useSpeechConfig) { + config->startFreq = sbrTuningTable[idx].startFreqSpeech; + config->stopFreq = sbrTuningTable[idx].stopFreqSpeech; + } + + config->sbr_noise_bands = sbrTuningTable[idx].numNoiseBands ; + if (core == AOT_ER_AAC_ELD) + config->init_amp_res_FF = SBR_AMP_RES_1_5; + config->noiseFloorOffset= sbrTuningTable[idx].noiseFloorOffset; + + config->ana_max_level = sbrTuningTable[idx].noiseMaxLevel ; + config->stereoMode = sbrTuningTable[idx].stereoMode ; + config->freqScale = sbrTuningTable[idx].freqScale ; + + /* adjust usage of parametric coding dependent on bitrate and speech config flag */ + if (useSpeechConfig) + config->parametricCoding = 0; + + if (core == AOT_ER_AAC_ELD) { + if (bitRate < 28000) + config->init_amp_res_FF = SBR_AMP_RES_3_0; + config->SendHeaderDataTime = -1; + } + + if (numChannels == 1) { + if (bitRate < 16000) { + config->parametricCoding = 0; + } + } + else { + if (bitRate < 20000) { + config->parametricCoding = 0; + } + } + + config->useSpeechConfig = useSpeechConfig; + + /* PS settings */ + config->bParametricStereo = bParametricStereo; + + return 1 ; + } + else { + return 0 ; + } +} + +/***************************************************************************** + + functionname: FDKsbrEnc_InitializeSbrDefaults + description: initializes the SBR confifuration + returns: error status + input: - core codec type, + - fac of SBR to core frame length, + - core frame length + output: initialized SBR configuration + +*****************************************************************************/ +static UINT +FDKsbrEnc_InitializeSbrDefaults (sbrConfigurationPtr config, + INT coreSbrFrameLenFac, + UINT codecGranuleLen) +{ + if ( (coreSbrFrameLenFac != 2) || + (codecGranuleLen*coreSbrFrameLenFac > QMF_CHANNELS*QMF_MAX_TIME_SLOTS) ) + return(1); + + config->SendHeaderDataTime = 1000; + config->useWaveCoding = 0; + config->crcSbr = 0; + config->dynBwSupported = 1; + config->tran_thr = 13000; + config->parametricCoding = 1; + + config->sbrFrameSize = codecGranuleLen * coreSbrFrameLenFac; + + + /* sbr default parameters */ + config->sbr_data_extra = 0; + config->amp_res = SBR_AMP_RES_3_0 ; + config->tran_fc = 0 ; + config->tran_det_mode = 1 ; + config->spread = 1 ; + config->stat = 0 ; + config->e = 1 ; + config->deltaTAcrossFrames = 1 ; + config->dF_edge_1stEnv = FL2FXCONST_DBL(0.3f) ; + config->dF_edge_incr = FL2FXCONST_DBL(0.3f) ; + + config->sbr_invf_mode = INVF_SWITCHED; + config->sbr_xpos_mode = XPOS_LC; + config->sbr_xpos_ctrl = SBR_XPOS_CTRL_DEFAULT; + config->sbr_xpos_level = 0; + config->useSaPan = 0; + config->dynBwEnabled = 0; + config->bDownSampledSbr = 0; + + + /* the following parameters are overwritten by the FDKsbrEnc_AdjustSbrSettings() function since + they are included in the tuning table */ + config->stereoMode = SBR_SWITCH_LRC; + config->ana_max_level = 6; + config->noiseFloorOffset = 0; + config->startFreq = 5; /* 5.9 respectively 6.0 kHz at fs = 44.1/48 kHz */ + config->stopFreq = 9; /* 16.2 respectively 16.8 kHz at fs = 44.1/48 kHz */ + + + /* header_extra_1 */ + config->freqScale = SBR_FREQ_SCALE_DEFAULT; + config->alterScale = SBR_ALTER_SCALE_DEFAULT; + config->sbr_noise_bands = SBR_NOISE_BANDS_DEFAULT; + + /* header_extra_2 */ + config->sbr_limiter_bands = SBR_LIMITER_BANDS_DEFAULT; + config->sbr_limiter_gains = SBR_LIMITER_GAINS_DEFAULT; + config->sbr_interpol_freq = SBR_INTERPOL_FREQ_DEFAULT; + config->sbr_smoothing_length = SBR_SMOOTHING_LENGTH_DEFAULT; + + return 1; +} + + +/***************************************************************************** + + functionname: DeleteEnvChannel + description: frees memory of one SBR channel + returns: - + input: handle of channel + output: released handle + +*****************************************************************************/ +static void +deleteEnvChannel (HANDLE_ENV_CHANNEL hEnvCut) +{ + if (hEnvCut) { + + /* deleteFrameInfoGenerator (&hEnvCut->SbrEnvFrame); */ + + + + /* deleteSbrCodeEnvelope (&hEnvCut->sbrCodeEnvelope); */ + + /* deleteSbrCodeEnvelope (&hEnvCut->sbrCodeNoiseFloor); */ + + FDKsbrEnc_DeleteTonCorrParamExtr(&hEnvCut->TonCorr); + + FDKsbrEnc_deleteExtractSbrEnvelope (&hEnvCut->sbrExtractEnvelope); + + //FreeRam_EnvChannel(phEnvCut); + } + +} + + +/***************************************************************************** + + functionname: sbrEncoder_ChannelClose + description: close the channel coding handle + returns: + input: phSbrChannel + output: + +*****************************************************************************/ +static void +sbrEncoder_ChannelClose(HANDLE_SBR_CHANNEL hSbrChannel) +{ + if (hSbrChannel != NULL) + { + deleteEnvChannel (&hSbrChannel->hEnvChannel); + } +} + +/***************************************************************************** + + functionname: sbrEncoder_ElementClose + description: close the channel coding handle + returns: + input: phSbrChannel + output: + +*****************************************************************************/ +static void +sbrEncoder_ElementClose(HANDLE_SBR_ELEMENT *phSbrElement) +{ + HANDLE_SBR_ELEMENT hSbrElement = *phSbrElement; + + if (hSbrElement!=NULL) { + if (hSbrElement->sbrConfigData.v_k_master) + FreeRam_Sbr_v_k_master(&hSbrElement->sbrConfigData.v_k_master); + if (hSbrElement->sbrConfigData.freqBandTable[LO]) + FreeRam_Sbr_freqBandTableLO(&hSbrElement->sbrConfigData.freqBandTable[LO]); + if (hSbrElement->sbrConfigData.freqBandTable[HI]) + FreeRam_Sbr_freqBandTableHI(&hSbrElement->sbrConfigData.freqBandTable[HI]); + + FreeRam_SbrElement(phSbrElement); + } + return ; + +} + + +void sbrEncoder_Close (HANDLE_SBR_ENCODER *phSbrEncoder) +{ + HANDLE_SBR_ENCODER hSbrEncoder = *phSbrEncoder; + + if (hSbrEncoder != NULL) + { + int el, ch; + + for (el=0; el<(6); el++) + { + if (hSbrEncoder->sbrElement[el]!=NULL) { + sbrEncoder_ElementClose(&hSbrEncoder->sbrElement[el]); + } + } + + /* Close sbr Channels */ + for (ch=0; ch<(6); ch++) + { + if (hSbrEncoder->pSbrChannel[ch]) { + sbrEncoder_ChannelClose(hSbrEncoder->pSbrChannel[ch]); + FreeRam_SbrChannel(&hSbrEncoder->pSbrChannel[ch]); + } + + if (hSbrEncoder->QmfAnalysis[ch].FilterStates) + FreeRam_Sbr_QmfStatesAnalysis((FIXP_QAS**)&hSbrEncoder->QmfAnalysis[ch].FilterStates); + + + } + + if (hSbrEncoder->hPsEncConfig) + FreeRam_PsEncConf(&hSbrEncoder->hPsEncConfig); + if (hSbrEncoder->hParametricStereo) + PSEnc_Destroy(&hSbrEncoder->hParametricStereo); + if (hSbrEncoder->qmfSynthesisPS.FilterStates) + FreeRam_PsQmfStatesSynthesis((FIXP_DBL**)&hSbrEncoder->qmfSynthesisPS.FilterStates); + + /* Release Overlay */ + FreeRam_SbrDynamic_RAM((FIXP_DBL**)&hSbrEncoder->pSBRdynamic_RAM); + + + FreeRam_SbrEncoder(phSbrEncoder); + } + +} + +/***************************************************************************** + + functionname: updateFreqBandTable + description: updates vk_master + returns: - + input: config handle + output: error info + +*****************************************************************************/ +static INT updateFreqBandTable(HANDLE_SBR_CONFIG_DATA sbrConfigData, + HANDLE_SBR_HEADER_DATA sbrHeaderData, + INT noQmfChannels) +{ + INT k0, k2; + + if(FDKsbrEnc_FindStartAndStopBand(sbrConfigData->sampleFreq, + noQmfChannels, + sbrHeaderData->sbr_start_frequency, + sbrHeaderData->sbr_stop_frequency, + sbrHeaderData->sampleRateMode, + &k0, &k2)) + return(1); + + + if(FDKsbrEnc_UpdateFreqScale(sbrConfigData->v_k_master, &sbrConfigData->num_Master, + k0, k2, sbrHeaderData->freqScale, + sbrHeaderData->alterScale)) + return(1); + + + sbrHeaderData->sbr_xover_band=0; + + + if(FDKsbrEnc_UpdateHiRes(sbrConfigData->freqBandTable[HI], + &sbrConfigData->nSfb[HI], + sbrConfigData->v_k_master, + sbrConfigData->num_Master , + &sbrHeaderData->sbr_xover_band, + sbrHeaderData->sampleRateMode, + noQmfChannels)) + return(1); + + + FDKsbrEnc_UpdateLoRes(sbrConfigData->freqBandTable[LO], + &sbrConfigData->nSfb[LO], + sbrConfigData->freqBandTable[HI], + sbrConfigData->nSfb[HI]); + + sbrConfigData->xOverFreq = (sbrConfigData->freqBandTable[LOW_RES][0] * sbrConfigData->sampleFreq / noQmfChannels+1)>>1; + + return (0); +} + + +/***************************************************************************** + + functionname: resetEnvChannel + description: resets parameters and allocates memory + returns: error status + input: + output: hEnv + +*****************************************************************************/ +static INT resetEnvChannel (HANDLE_SBR_CONFIG_DATA sbrConfigData, + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_ENV_CHANNEL hEnv) +{ + /* note !!! hEnv->encEnvData.noOfnoisebands will be updated later in function FDKsbrEnc_extractSbrEnvelope !!!*/ + hEnv->TonCorr.sbrNoiseFloorEstimate.noiseBands = sbrHeaderData->sbr_noise_bands; + + + if(FDKsbrEnc_ResetTonCorrParamExtr(&hEnv->TonCorr, + sbrConfigData->xposCtrlSwitch, + sbrConfigData->freqBandTable[HI][0], + sbrConfigData->v_k_master, + sbrConfigData->num_Master, + sbrConfigData->sampleFreq, + sbrConfigData->freqBandTable, + sbrConfigData->nSfb, + sbrConfigData->noQmfBands)) + return(1); + + hEnv->sbrCodeNoiseFloor.nSfb[LO] = hEnv->TonCorr.sbrNoiseFloorEstimate.noNoiseBands; + hEnv->sbrCodeNoiseFloor.nSfb[HI] = hEnv->TonCorr.sbrNoiseFloorEstimate.noNoiseBands; + + hEnv->sbrCodeEnvelope.nSfb[LO] = sbrConfigData->nSfb[LO]; + hEnv->sbrCodeEnvelope.nSfb[HI] = sbrConfigData->nSfb[HI]; + + hEnv->encEnvData.noHarmonics = sbrConfigData->nSfb[HI]; + + hEnv->sbrCodeEnvelope.upDate = 0; + hEnv->sbrCodeNoiseFloor.upDate = 0; + + return (0); +} + +/* ****************************** FDKsbrEnc_SbrGetXOverFreq ******************************/ +/** + * @fn + * @brief calculates the closest possible crossover frequency + * @return the crossover frequency SBR accepts + * + */ +static INT +FDKsbrEnc_SbrGetXOverFreq(HANDLE_SBR_ELEMENT hEnv, /*!< handle to SBR encoder instance */ + INT xoverFreq) /*!< from core coder suggested crossover frequency */ +{ + INT band; + INT lastDiff, newDiff; + INT cutoffSb; + + UCHAR *RESTRICT pVKMaster = hEnv->sbrConfigData.v_k_master; + + /* Check if there is a matching cutoff frequency in the master table */ + cutoffSb = (4*xoverFreq * hEnv->sbrConfigData.noQmfBands / hEnv->sbrConfigData.sampleFreq + 1)>>1; + lastDiff = cutoffSb; + for (band = 0; band < hEnv->sbrConfigData.num_Master; band++) { + + newDiff = fixp_abs((INT)pVKMaster[band] - cutoffSb); + + if(newDiff >= lastDiff) { + band--; + break; + } + + lastDiff = newDiff; + } + + return ((pVKMaster[band] * hEnv->sbrConfigData.sampleFreq/hEnv->sbrConfigData.noQmfBands+1)>>1); +} + +/***************************************************************************** + + functionname: FDKsbrEnc_EnvEncodeFrame + description: performs the sbr envelope calculation for one element + returns: + input: + output: + +*****************************************************************************/ +INT +FDKsbrEnc_EnvEncodeFrame(HANDLE_SBR_ENCODER hEnvEncoder, + int iElement, + INT_PCM *samples, /*!< time samples, always interleaved */ + UINT timeInStride, /*!< time buffer channel interleaving stride */ + UINT *sbrDataBits, /*!< Size of SBR payload */ + UCHAR *sbrData, /*!< SBR payload */ + int clearOutput /*!< Do not consider any input signal */ + ) +{ + HANDLE_SBR_ELEMENT hSbrElement = hEnvEncoder->sbrElement[iElement]; + FDK_CRCINFO crcInfo; + INT crcReg; + INT ch; + INT band; + INT cutoffSb; + INT newXOver; + + if (hEnvEncoder == NULL) + return -1; + + hSbrElement = hEnvEncoder->sbrElement[iElement]; + + if (hSbrElement == NULL) + return -1; + + + /* header bitstream handling */ + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData = &hSbrElement->sbrBitstreamData; + + INT psHeaderActive = 0; + sbrBitstreamData->HeaderActive = 0; + + /* Anticipate PS header because of internal PS bitstream delay in order to be in sync with SBR header. */ + if ( sbrBitstreamData->CountSendHeaderData==(sbrBitstreamData->NrSendHeaderData-1) ) + { + psHeaderActive = 1; + } + + /* Signal SBR header to be written into bitstream */ + if ( sbrBitstreamData->CountSendHeaderData==0 ) + { + sbrBitstreamData->HeaderActive = 1; + } + + /* Increment header interval counter */ + if (sbrBitstreamData->NrSendHeaderData == 0) { + sbrBitstreamData->CountSendHeaderData = 1; + } + else { + if (sbrBitstreamData->CountSendHeaderData >= 0) { + sbrBitstreamData->CountSendHeaderData++; + sbrBitstreamData->CountSendHeaderData %= sbrBitstreamData->NrSendHeaderData; + } + } + + if (hSbrElement->CmonData.dynBwEnabled ) { + INT i; + for ( i = 4; i > 0; i-- ) + hSbrElement->dynXOverFreqDelay[i] = hSbrElement->dynXOverFreqDelay[i-1]; + + hSbrElement->dynXOverFreqDelay[0] = hSbrElement->CmonData.dynXOverFreqEnc; + if (hSbrElement->dynXOverFreqDelay[1] > hSbrElement->dynXOverFreqDelay[2]) + newXOver = hSbrElement->dynXOverFreqDelay[2]; + else + newXOver = hSbrElement->dynXOverFreqDelay[1]; + + /* has the crossover frequency changed? */ + if ( hSbrElement->sbrConfigData.dynXOverFreq != newXOver ) { + + /* get corresponding master band */ + cutoffSb = ((4* newXOver * hSbrElement->sbrConfigData.noQmfBands + / hSbrElement->sbrConfigData.sampleFreq)+1)>>1; + + for ( band = 0; band < hSbrElement->sbrConfigData.num_Master; band++ ) { + if ( cutoffSb == hSbrElement->sbrConfigData.v_k_master[band] ) + break; + } + FDK_ASSERT( band < hSbrElement->sbrConfigData.num_Master ); + + hSbrElement->sbrConfigData.dynXOverFreq = newXOver; + hSbrElement->sbrHeaderData.sbr_xover_band = band; + hSbrElement->sbrBitstreamData.HeaderActive=1; + psHeaderActive = 1; /* ps header is one frame delayed */ + + /* + update vk_master table + */ + if(updateFreqBandTable(&hSbrElement->sbrConfigData, + &hSbrElement->sbrHeaderData, + hSbrElement->sbrConfigData.noQmfBands)) + return(1); + + + /* reset SBR channels */ + INT nEnvCh = hSbrElement->sbrConfigData.nChannels; + for ( ch = 0; ch < nEnvCh; ch++ ) { + if(resetEnvChannel (&hSbrElement->sbrConfigData, + &hSbrElement->sbrHeaderData, + &hSbrElement->sbrChannel[ch]->hEnvChannel)) + return(1); + + } + } + } + + /* + allocate space for dummy header and crc + */ + crcReg = FDKsbrEnc_InitSbrBitstream(&hSbrElement->CmonData, + hSbrElement->payloadDelayLine[hEnvEncoder->nBitstrDelay], + MAX_PAYLOAD_SIZE*sizeof(UCHAR), + &crcInfo, + hSbrElement->sbrConfigData.sbrSyntaxFlags); + + INT error = noError; + + /* Temporal Envelope Data */ + SBR_FRAME_TEMP_DATA _fData; + SBR_FRAME_TEMP_DATA *fData = &_fData; + SBR_ENV_TEMP_DATA eData[MAX_NUM_CHANNELS]; + + /* Init Temporal Envelope Data */ + { + int i; + + FDKmemclear(&eData[0], sizeof(SBR_ENV_TEMP_DATA)); + FDKmemclear(&eData[1], sizeof(SBR_ENV_TEMP_DATA)); + FDKmemclear(fData, sizeof(SBR_FRAME_TEMP_DATA)); + + for(i=0; ires[i] = FREQ_RES_HIGH; + } + + + if (!clearOutput) + { + /* + * Transform audio data into QMF domain + */ + for(ch = 0; ch < hSbrElement->sbrConfigData.nChannels; ch++) + { + HANDLE_ENV_CHANNEL h_envChan = &hSbrElement->sbrChannel[ch]->hEnvChannel; + HANDLE_SBR_EXTRACT_ENVELOPE sbrExtrEnv = &h_envChan->sbrExtractEnvelope; + + if(hSbrElement->elInfo.fParametricStereo == 0) + { + C_ALLOC_SCRATCH_START(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2); + QMF_SCALE_FACTOR tmpScale; + FIXP_DBL **pQmfReal, **pQmfImag; + + + /* Obtain pointers to QMF buffers. */ + pQmfReal = sbrExtrEnv->rBuffer+sbrExtrEnv->rBufferWriteOffset; + pQmfImag = sbrExtrEnv->iBuffer+sbrExtrEnv->rBufferWriteOffset; + + qmfAnalysisFiltering( hSbrElement->hQmfAnalysis[ch], + pQmfReal, + pQmfImag, + &tmpScale, + samples + hSbrElement->elInfo.ChannelIndex[ch], + timeInStride, + qmfWorkBuffer ); + + C_ALLOC_SCRATCH_END(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2); + + h_envChan->qmfScale = tmpScale.lb_scale + 7; + + } /* fParametricStereo == 0 */ + + + /* + Parametric Stereo processing + */ + if(hSbrElement->elInfo.fParametricStereo) + { + int psCh; + + /* Parametric Stereo QMF buffer preprocessing: copy previous qmf data down */ + UpdatePSQmfData_second(hEnvEncoder->hParametricStereo); + + for (psCh = 0; psCh<2; psCh ++) + { + C_ALLOC_SCRATCH_START(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2); + HANDLE_PS_QMF_DATA hPsQmfData = hEnvEncoder->hParametricStereo->hPsChannelData[psCh]->hPsQmfData; + QMF_SCALE_FACTOR tmpScale; + + + qmfAnalysisFiltering( hSbrElement->hQmfAnalysis[psCh], + hPsQmfData->rQmfData + hPsQmfData->bufferWriteOffset, + hPsQmfData->iQmfData + hPsQmfData->bufferWriteOffset, + &tmpScale, + samples + hSbrElement->elInfo.ChannelIndex[psCh], + timeInStride, + qmfWorkBuffer ); + + C_ALLOC_SCRATCH_END(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2); + + hEnvEncoder->hParametricStereo->hPsChannelData[psCh]->psQmfScale = -tmpScale.lb_scale; + } + + + /* Limit Parametric Stereo to one instance */ + FDK_ASSERT(ch == 0); + + + if(error == noError){ + /* parametric stereo processing: + - input: + o left and right time domain samples + - processing: + o stereo qmf analysis + o stereo hybrid analysis + o ps parameter extraction + o downmix + hybrid synthesis + - output: + o downmixed qmf data is written to sbrExtrEnv->rBuffer and sbrExtrEnv->iBuffer + */ + SCHAR qmfScale; + error = FDKsbrEnc_PSEnc_ParametricStereoProcessing( hEnvEncoder->hParametricStereo, + sbrExtrEnv->rBuffer, + sbrExtrEnv->iBuffer, + sbrExtrEnv->rBufferWriteOffset, + samples + hSbrElement->elInfo.ChannelIndex[ch], + &hEnvEncoder->qmfSynthesisPS, + &qmfScale, + psHeaderActive ); + if (noError != error) + { + error = handBack(error); + } + h_envChan->qmfScale = (int)qmfScale; + } + + + } /* if (hEnvEncoder->hParametricStereo) */ + + /* + + Extract Envelope relevant things from QMF data + + */ + FDKsbrEnc_extractSbrEnvelope1( + &hSbrElement->sbrConfigData, + &hSbrElement->sbrHeaderData, + &hSbrElement->sbrBitstreamData, + h_envChan, + &hSbrElement->CmonData, + &eData[ch], + fData + ); + + } /* hEnvEncoder->sbrConfigData.nChannels */ + } + + /* + Process Envelope relevant things and calculate envelope data and write payload + */ + FDKsbrEnc_extractSbrEnvelope2( + &hSbrElement->sbrConfigData, + &hSbrElement->sbrHeaderData, + (hSbrElement->elInfo.fParametricStereo) ? hEnvEncoder->hParametricStereo : NULL, + &hSbrElement->sbrBitstreamData, + &hSbrElement->sbrChannel[0]->hEnvChannel, + &hSbrElement->sbrChannel[1]->hEnvChannel, + &hSbrElement->CmonData, + eData, + fData, + clearOutput + ); + + /* + format payload, calculate crc + */ + FDKsbrEnc_AssembleSbrBitstream(&hSbrElement->CmonData, &crcInfo, crcReg, hSbrElement->sbrConfigData.sbrSyntaxFlags); + + /* + save new payload, set to zero length if greater than MAX_PAYLOAD_SIZE + */ + hSbrElement->payloadDelayLineSize[hEnvEncoder->nBitstrDelay] = FDKgetValidBits(&hSbrElement->CmonData.sbrBitbuf); + + if(hSbrElement->payloadDelayLineSize[hEnvEncoder->nBitstrDelay] > (MAX_PAYLOAD_SIZE<<3)) + hSbrElement->payloadDelayLineSize[hEnvEncoder->nBitstrDelay]=0; + + /* While filling the Delay lines, sbrData is NULL */ + if (sbrData) { + *sbrDataBits = hSbrElement->payloadDelayLineSize[0]; + FDKmemcpy(sbrData, hSbrElement->payloadDelayLine[0], (hSbrElement->payloadDelayLineSize[0]+7)>>3); + + + } + + +/*******************************/ + + if (hEnvEncoder->fTimeDomainDownsampling) + { + int ch; + int nChannels = hSbrElement->sbrConfigData.nChannels; + + for (ch=0; ch < nChannels; ch++) + { + INT nOutSamples; + + FDKaacEnc_Downsample(&hSbrElement->sbrChannel[ch]->downSampler, + samples + hSbrElement->elInfo.ChannelIndex[ch] + hEnvEncoder->bufferOffset, + hSbrElement->sbrConfigData.frameSize, + timeInStride, + samples + hSbrElement->elInfo.ChannelIndex[ch], + &nOutSamples, + hEnvEncoder->nChannels); + } + } /* downsample */ + + + return (0); +} + +/***************************************************************************** + + functionname: createEnvChannel + description: initializes parameters and allocates memory + returns: error status + input: + output: hEnv + +*****************************************************************************/ + +static INT +createEnvChannel (HANDLE_ENV_CHANNEL hEnv, + INT channel + ,UCHAR* dynamic_RAM + ) +{ + FDKmemclear(hEnv,sizeof (struct ENV_CHANNEL)); + + if ( FDKsbrEnc_CreateTonCorrParamExtr(&hEnv->TonCorr, + channel) ) + { + return(1); + } + + if ( FDKsbrEnc_CreateExtractSbrEnvelope (&hEnv->sbrExtractEnvelope, + channel + ,/*chan*/0 + ,dynamic_RAM + ) ) + { + return(1); + } + + return 0; +} + +/***************************************************************************** + + functionname: initEnvChannel + description: initializes parameters + returns: error status + input: + output: + +*****************************************************************************/ +static INT +initEnvChannel ( HANDLE_SBR_CONFIG_DATA sbrConfigData, + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_ENV_CHANNEL hEnv, + sbrConfigurationPtr params, + ULONG statesInitFlag + ,INT chanInEl + ,UCHAR* dynamic_RAM + ) +{ + int frameShift, tran_off=0; + INT e; + INT tran_fc; + INT timeSlots, timeStep, startIndex; + INT noiseBands[2] = { 3, 3 }; + + e = 1 << params->e; + + FDK_ASSERT(params->e >= 0); + + hEnv->encEnvData.freq_res_fixfix = 1; + hEnv->fLevelProtect = 0; + + hEnv->encEnvData.ldGrid = (sbrConfigData->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) ? 1 : 0; + + hEnv->encEnvData.sbr_xpos_mode = (XPOS_MODE)params->sbr_xpos_mode; + + if (hEnv->encEnvData.sbr_xpos_mode == XPOS_SWITCHED) { + /* + no other type than XPOS_MDCT or XPOS_SPEECH allowed, + but enable switching + */ + sbrConfigData->switchTransposers = TRUE; + hEnv->encEnvData.sbr_xpos_mode = XPOS_MDCT; + } + else { + sbrConfigData->switchTransposers = FALSE; + } + + hEnv->encEnvData.sbr_xpos_ctrl = params->sbr_xpos_ctrl; + + + /* extended data */ + if(params->parametricCoding) { + hEnv->encEnvData.extended_data = 1; + } + else { + hEnv->encEnvData.extended_data = 0; + } + + hEnv->encEnvData.extension_size = 0; + + startIndex = QMF_FILTER_PROTOTYPE_SIZE - sbrConfigData->noQmfBands; + + switch (params->sbrFrameSize) { + case 2304: + timeSlots = 18; + break; + case 2048: + case 1024: + timeSlots = 16; + break; + case 1920: + case 960: + timeSlots = 15; + break; + case 1152: + timeSlots = 9; + break; + default: + return (1); /* Illegal frame size */ + } + + timeStep = sbrConfigData->noQmfSlots / timeSlots; + + if ( FDKsbrEnc_InitTonCorrParamExtr(params->sbrFrameSize, + &hEnv->TonCorr, + sbrConfigData, + timeSlots, + params->sbr_xpos_ctrl, + params->ana_max_level, + sbrHeaderData->sbr_noise_bands, + params->noiseFloorOffset, + params->useSpeechConfig) ) + return(1); + + hEnv->encEnvData.noOfnoisebands = hEnv->TonCorr.sbrNoiseFloorEstimate.noNoiseBands; + + noiseBands[0] = hEnv->encEnvData.noOfnoisebands; + noiseBands[1] = hEnv->encEnvData.noOfnoisebands; + + hEnv->encEnvData.sbr_invf_mode = (INVF_MODE)params->sbr_invf_mode; + + if (hEnv->encEnvData.sbr_invf_mode == INVF_SWITCHED) { + hEnv->encEnvData.sbr_invf_mode = INVF_MID_LEVEL; + hEnv->TonCorr.switchInverseFilt = TRUE; + } + else { + hEnv->TonCorr.switchInverseFilt = FALSE; + } + + + tran_fc = params->tran_fc; + + if (tran_fc == 0) + tran_fc = fixMin (5000, FDKsbrEnc_getSbrStartFreqRAW (sbrHeaderData->sbr_start_frequency,64,sbrConfigData->sampleFreq)); + + + tran_fc = (tran_fc*4*sbrConfigData->noQmfBands/sbrConfigData->sampleFreq + 1)>>1; + + if (sbrConfigData->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + frameShift = LD_PRETRAN_OFF; + tran_off = LD_PRETRAN_OFF + FRAME_MIDDLE_SLOT_512LD*timeStep; + } else + { + frameShift = 0; + switch (params->sbrFrameSize) { + /* The factor of 2 is by definition. */ + case 2048: tran_off = 8 + FRAME_MIDDLE_SLOT_2048 * timeStep; break; + case 1920: tran_off = 7 + FRAME_MIDDLE_SLOT_1920 * timeStep; break; + default: return 1; break; + } + } + if ( FDKsbrEnc_InitExtractSbrEnvelope (&hEnv->sbrExtractEnvelope, + sbrConfigData->noQmfSlots, + sbrConfigData->noQmfBands, startIndex, + timeSlots, timeStep, tran_off, + statesInitFlag + ,chanInEl + ,dynamic_RAM + ,sbrConfigData->sbrSyntaxFlags + ) ) + return(1); + + if(FDKsbrEnc_InitSbrCodeEnvelope (&hEnv->sbrCodeEnvelope, + sbrConfigData->nSfb, + params->deltaTAcrossFrames, + params->dF_edge_1stEnv, + params->dF_edge_incr)) + return(1); + + if(FDKsbrEnc_InitSbrCodeEnvelope (&hEnv->sbrCodeNoiseFloor, + noiseBands, + params->deltaTAcrossFrames, + 0,0)) + return(1); + + sbrConfigData->initAmpResFF = params->init_amp_res_FF; + + if(FDKsbrEnc_InitSbrHuffmanTables (&hEnv->encEnvData, + &hEnv->sbrCodeEnvelope, + &hEnv->sbrCodeNoiseFloor, + sbrHeaderData->sbr_amp_res)) + return(1); + + FDKsbrEnc_initFrameInfoGenerator (&hEnv->SbrEnvFrame, + params->spread, + e, + params->stat, + timeSlots, + hEnv->encEnvData.freq_res_fixfix + ,hEnv->encEnvData.ldGrid + ); + + if(FDKsbrEnc_InitSbrTransientDetector (&hEnv->sbrTransientDetector, + sbrConfigData->frameSize, + sbrConfigData->sampleFreq, + params, + tran_fc, + sbrConfigData->noQmfSlots, + sbrConfigData->noQmfBands, + hEnv->sbrExtractEnvelope.YBufferWriteOffset, + hEnv->sbrExtractEnvelope.YBufferSzShift, + frameShift, + tran_off + )) + return(1); + + + sbrConfigData->xposCtrlSwitch = params->sbr_xpos_ctrl; + + hEnv->encEnvData.noHarmonics = sbrConfigData->nSfb[HI]; + hEnv->encEnvData.addHarmonicFlag = 0; + + return (0); +} + +INT sbrEncoder_Open( + HANDLE_SBR_ENCODER *phSbrEncoder, + INT nElements, + INT nChannels, + INT supportPS + ) +{ + INT i; + INT errorStatus = 1; + HANDLE_SBR_ENCODER hSbrEncoder = NULL; + + if (phSbrEncoder==NULL + ) + { + goto bail; + } + + hSbrEncoder = GetRam_SbrEncoder(); + if (hSbrEncoder==NULL) { + goto bail; + } + FDKmemclear(hSbrEncoder, sizeof(SBR_ENCODER)); + + hSbrEncoder->pSBRdynamic_RAM = (UCHAR*)GetRam_SbrDynamic_RAM(); + hSbrEncoder->dynamicRam = hSbrEncoder->pSBRdynamic_RAM; + + + for (i=0; isbrElement[i] = GetRam_SbrElement(i); + if (hSbrEncoder->sbrElement[i]==NULL) { + goto bail; + } + FDKmemclear(hSbrEncoder->sbrElement[i], sizeof(SBR_ELEMENT)); + hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[LO] = GetRam_Sbr_freqBandTableLO(i); + hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[HI] = GetRam_Sbr_freqBandTableHI(i); + hSbrEncoder->sbrElement[i]->sbrConfigData.v_k_master = GetRam_Sbr_v_k_master(i); + if ( (hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[LO]==NULL) || + (hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[HI]==NULL) || + (hSbrEncoder->sbrElement[i]->sbrConfigData.v_k_master==NULL) ) + { + goto bail; + } + } + + for (i=0; ipSbrChannel[i] = GetRam_SbrChannel(i); + if (hSbrEncoder->pSbrChannel[i]==NULL) { + goto bail; + } + + if ( createEnvChannel(&hSbrEncoder->pSbrChannel[i]->hEnvChannel, + i + ,hSbrEncoder->dynamicRam + ) ) + { + goto bail; + } + + } + + for (i=0; iQmfAnalysis[i].FilterStates = GetRam_Sbr_QmfStatesAnalysis(i); + if (hSbrEncoder->QmfAnalysis[i].FilterStates==NULL) { + goto bail; + } + } + + if (supportPS) { + hSbrEncoder->hPsEncConfig = GetRam_PsEncConf(); + if (hSbrEncoder->hPsEncConfig==NULL) { + goto bail; + } + + if (PSEnc_Create(&hSbrEncoder->hParametricStereo)) + { + goto bail; + } + + hSbrEncoder->qmfSynthesisPS.FilterStates = GetRam_PsQmfStatesSynthesis(); + if (hSbrEncoder->qmfSynthesisPS.FilterStates==NULL) { + goto bail; + } + } /* supportPS */ + + *phSbrEncoder = hSbrEncoder; + + errorStatus = 0; + return errorStatus; + +bail: + /* Close SBR encoder instance */ + sbrEncoder_Close(&hSbrEncoder); + return errorStatus; +} + +static +INT FDKsbrEnc_Reallocate( + HANDLE_SBR_ENCODER hSbrEncoder, + SBR_ELEMENT_INFO elInfo[(6)], + const INT noElements) +{ + INT totalCh = 0; + INT totalQmf = 0; + INT coreEl; + INT el=-1; + + hSbrEncoder->lfeChIdx = -1; /* default value, until lfe found */ + + for (coreEl=0; coreEllfeChIdx = elInfo[coreEl].ChannelIndex[0]; + } + continue; + } + + SBR_ELEMENT_INFO *pelInfo = &elInfo[coreEl]; + HANDLE_SBR_ELEMENT hSbrElement = hSbrEncoder->sbrElement[el]; + + int ch; + for ( ch = 0; ch < pelInfo->nChannelsInEl; ch++ ) { + hSbrElement->sbrChannel[ch] = hSbrEncoder->pSbrChannel[totalCh]; + totalCh++; + } + /* analysis QMF */ + for ( ch = 0; ch < ((pelInfo->fParametricStereo)?2:pelInfo->nChannelsInEl); ch++ ) { + hSbrElement->elInfo.ChannelIndex[ch] = pelInfo->ChannelIndex[ch]; + hSbrElement->hQmfAnalysis[ch] = &hSbrEncoder->QmfAnalysis[totalQmf++]; + } + + /* Copy Element info */ + hSbrElement->elInfo.elType = pelInfo->elType; + hSbrElement->elInfo.instanceTag = pelInfo->instanceTag; + hSbrElement->elInfo.nChannelsInEl = pelInfo->nChannelsInEl; + hSbrElement->elInfo.fParametricStereo = pelInfo->fParametricStereo; + } /* coreEl */ + + return 0; +} + + + +/***************************************************************************** + + functionname: FDKsbrEnc_EnvInit + description: initializes parameters + returns: error status + input: + output: hEnv + +*****************************************************************************/ +static +INT FDKsbrEnc_EnvInit ( + HANDLE_SBR_ELEMENT hSbrElement, + sbrConfigurationPtr params, + INT *coreBandWith, + AUDIO_OBJECT_TYPE aot, + int nBitstrDelay, + int nElement, + ULONG statesInitFlag + ,UCHAR *dynamic_RAM + ) +{ + UCHAR *bitstreamBuffer; + int ch, i; + + if ((params->codecSettings.nChannels < 1) || (params->codecSettings.nChannels > MAX_NUM_CHANNELS)){ + return(1); + } + + /* initialize the encoder handle and structs*/ + bitstreamBuffer = hSbrElement->payloadDelayLine[nBitstrDelay]; + + /* init and set syntax flags */ + hSbrElement->sbrConfigData.sbrSyntaxFlags = 0; + + switch (aot) { + case AOT_DRM_MPEG_PS: + case AOT_DRM_SBR: + hSbrElement->sbrConfigData.sbrSyntaxFlags |= SBR_SYNTAX_SCALABLE; + hSbrElement->sbrConfigData.sbrSyntaxFlags |= SBR_SYNTAX_DRM_CRC; + hSbrElement->sbrConfigData.sbrSyntaxFlags |= SBR_SYNTAX_CRC; + break; + case AOT_ER_AAC_ELD: + hSbrElement->sbrConfigData.sbrSyntaxFlags |= SBR_SYNTAX_LOW_DELAY; + break; + default: + break; + } + if (params->crcSbr) { + hSbrElement->sbrConfigData.sbrSyntaxFlags |= SBR_SYNTAX_CRC; + } + + hSbrElement->sbrConfigData.noQmfBands = QMF_CHANNELS; + hSbrElement->sbrConfigData.noQmfSlots = params->sbrFrameSize/hSbrElement->sbrConfigData.noQmfBands; + + FDKinitBitStream(&hSbrElement->CmonData.sbrBitbuf, bitstreamBuffer, MAX_PAYLOAD_SIZE*sizeof(UCHAR), 0, BS_WRITER); + + /* + now initialize sbrConfigData, sbrHeaderData and sbrBitstreamData, + */ + hSbrElement->sbrConfigData.nChannels = params->codecSettings.nChannels; + + if(params->codecSettings.nChannels == 2) + hSbrElement->sbrConfigData.stereoMode = params->stereoMode; + else + hSbrElement->sbrConfigData.stereoMode = SBR_MONO; + + hSbrElement->sbrConfigData.frameSize = params->sbrFrameSize; + + /* implicit rule for sampleRateMode */ + /* run in "multirate" mode where sbr fs is 2 * codec fs */ + hSbrElement->sbrHeaderData.sampleRateMode = DUAL_RATE; + hSbrElement->sbrConfigData.sampleFreq = 2 * params->codecSettings.sampleFreq; + + hSbrElement->sbrBitstreamData.CountSendHeaderData = 0; + if (params->SendHeaderDataTime > 0 ) { + + hSbrElement->sbrBitstreamData.NrSendHeaderData = (INT)(params->SendHeaderDataTime * hSbrElement->sbrConfigData.sampleFreq + / (1000 * hSbrElement->sbrConfigData.frameSize)); + hSbrElement->sbrBitstreamData.NrSendHeaderData = fixMax(hSbrElement->sbrBitstreamData.NrSendHeaderData,1); + } + else { + hSbrElement->sbrBitstreamData.NrSendHeaderData = 0; + } + + hSbrElement->sbrHeaderData.sbr_data_extra = params->sbr_data_extra; + hSbrElement->sbrBitstreamData.HeaderActive = 0; + hSbrElement->sbrHeaderData.sbr_start_frequency = params->startFreq; + hSbrElement->sbrHeaderData.sbr_stop_frequency = params->stopFreq; + hSbrElement->sbrHeaderData.sbr_xover_band = 0; + hSbrElement->sbrHeaderData.sbr_lc_stereo_mode = 0; + + /* data_extra */ + if (params->sbr_xpos_ctrl!= SBR_XPOS_CTRL_DEFAULT) + hSbrElement->sbrHeaderData.sbr_data_extra = 1; + + hSbrElement->sbrHeaderData.sbr_amp_res = (AMP_RES)params->amp_res; + + /* header_extra_1 */ + hSbrElement->sbrHeaderData.freqScale = params->freqScale; + hSbrElement->sbrHeaderData.alterScale = params->alterScale; + hSbrElement->sbrHeaderData.sbr_noise_bands = params->sbr_noise_bands; + hSbrElement->sbrHeaderData.header_extra_1 = 0; + + if ((params->freqScale != SBR_FREQ_SCALE_DEFAULT) || + (params->alterScale != SBR_ALTER_SCALE_DEFAULT) || + (params->sbr_noise_bands != SBR_NOISE_BANDS_DEFAULT)) + { + hSbrElement->sbrHeaderData.header_extra_1 = 1; + } + + /* header_extra_2 */ + hSbrElement->sbrHeaderData.sbr_limiter_bands = params->sbr_limiter_bands; + hSbrElement->sbrHeaderData.sbr_limiter_gains = params->sbr_limiter_gains; + + if ((hSbrElement->sbrConfigData.sampleFreq > 48000) && + (hSbrElement->sbrHeaderData.sbr_start_frequency >= 9)) + { + hSbrElement->sbrHeaderData.sbr_limiter_gains = SBR_LIMITER_GAINS_INFINITE; + } + + hSbrElement->sbrHeaderData.sbr_interpol_freq = params->sbr_interpol_freq; + hSbrElement->sbrHeaderData.sbr_smoothing_length = params->sbr_smoothing_length; + hSbrElement->sbrHeaderData.header_extra_2 = 0; + + if ((params->sbr_limiter_bands != SBR_LIMITER_BANDS_DEFAULT) || + (params->sbr_limiter_gains != SBR_LIMITER_GAINS_DEFAULT) || + (params->sbr_interpol_freq != SBR_INTERPOL_FREQ_DEFAULT) || + (params->sbr_smoothing_length != SBR_SMOOTHING_LENGTH_DEFAULT)) + { + hSbrElement->sbrHeaderData.header_extra_2 = 1; + } + + /* other switches */ + hSbrElement->sbrConfigData.useWaveCoding = params->useWaveCoding; + hSbrElement->sbrConfigData.useParametricCoding = params->parametricCoding; + + /* init freq band table */ + if(updateFreqBandTable(&hSbrElement->sbrConfigData, + &hSbrElement->sbrHeaderData, + hSbrElement->sbrConfigData.noQmfBands)) + { + return(1); + } + + /* now create envelope ext and QMF for each available channel */ + for ( ch = 0; ch < hSbrElement->sbrConfigData.nChannels; ch++ ) { + + if ( initEnvChannel(&hSbrElement->sbrConfigData, + &hSbrElement->sbrHeaderData, + &hSbrElement->sbrChannel[ch]->hEnvChannel, + params, + statesInitFlag + ,ch + ,dynamic_RAM + ) ) + { + return(1); + } + + + } /* nChannels */ + + /* reset and intialize analysis qmf */ + for ( ch = 0; ch < ((hSbrElement->elInfo.fParametricStereo)?2:hSbrElement->sbrConfigData.nChannels); ch++ ) + { + int err; + UINT qmfFlags = (hSbrElement->sbrConfigData.sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) ? QMF_FLAG_CLDFB : 0; + if (statesInitFlag) + qmfFlags &= ~QMF_FLAG_KEEP_STATES; + else + qmfFlags |= QMF_FLAG_KEEP_STATES; + + err = qmfInitAnalysisFilterBank( hSbrElement->hQmfAnalysis[ch], + (FIXP_QAS*)hSbrElement->hQmfAnalysis[ch]->FilterStates, + hSbrElement->sbrConfigData.noQmfSlots, + hSbrElement->sbrConfigData.noQmfBands, + hSbrElement->sbrConfigData.noQmfBands, + hSbrElement->sbrConfigData.noQmfBands, + qmfFlags ); + } + + /* */ + hSbrElement->CmonData.xOverFreq = hSbrElement->sbrConfigData.xOverFreq; + hSbrElement->CmonData.dynBwEnabled = (params->dynBwSupported && params->dynBwEnabled); + hSbrElement->CmonData.dynXOverFreqEnc = FDKsbrEnc_SbrGetXOverFreq( hSbrElement, hSbrElement->CmonData.xOverFreq); + for ( i = 0; i < 5; i++ ) + hSbrElement->dynXOverFreqDelay[i] = hSbrElement->CmonData.dynXOverFreqEnc; + hSbrElement->CmonData.sbrNumChannels = hSbrElement->sbrConfigData.nChannels; + hSbrElement->sbrConfigData.dynXOverFreq = hSbrElement->CmonData.xOverFreq; + + /* Update Bandwith to be passed to the core encoder */ + *coreBandWith = hSbrElement->CmonData.xOverFreq; + + return(0); + } + +INT sbrEncoder_GetInBufferSize(int noChannels) +{ + INT temp; + + temp = (1024*DOWN_SMPL_FAC); + temp += 1024 + MAX_SAMPLE_DELAY; + temp *= noChannels; + temp *= sizeof(INT_PCM); + return temp; +} + +/* + * Encode Dummy SBR payload frames to fill the delay lines. + */ +static +INT FDKsbrEnc_DelayCompensation ( + HANDLE_SBR_ENCODER hEnvEnc, + INT_PCM *timeBuffer + ) +{ + int n, el; + + for (n=hEnvEnc->nBitstrDelay; n>0; n--) + { + for (el=0; elnoElements; el++) + { + if (FDKsbrEnc_EnvEncodeFrame( + hEnvEnc, + el, + timeBuffer + hEnvEnc->downsampledOffset, + hEnvEnc->sbrElement[el]->sbrConfigData.nChannels, + NULL, + NULL, + 1 + )) + return -1; + sbrEncoder_UpdateBuffers(hEnvEnc, timeBuffer); + } + } + return 0; +} + + +INT sbrEncoder_Init( + HANDLE_SBR_ENCODER hSbrEncoder, + SBR_ELEMENT_INFO elInfo[(6)], + int noElements, + INT_PCM *inputBuffer, + INT *coreBandwidth, + INT *inputBufferOffset, + INT *numChannels, + INT *sampleRate, + INT *frameLength, + AUDIO_OBJECT_TYPE *aot, + int *delay, + int transformFactor, + ULONG statesInitFlag + ) +{ + HANDLE_ERROR_INFO errorInfo = noError; + sbrConfiguration sbrConfig[(6)]; + INT error = 0; + INT lowestBandwidth; + /* Save input parameters */ + INT inputSampleRate = *sampleRate; + int coreFrameLength = *frameLength; + int inputBandWidth = *coreBandwidth; + int inputChannels = *numChannels; + + int downsampledOffset = 0; + int sbrOffset = 0; + int downsamplerDelay = 0; + int downsample = 0; + int nBitstrDelay = 0; + int lowestSbrStartFreq, lowestSbrStopFreq; + int lowDelay = 0; + int usePs = 0; + + /* check whether SBR setting is available for the current encoder configuration (bitrate, samplerate) */ + if ( (*aot==AOT_PS) || (*aot==AOT_MP2_PS) || (*aot==AOT_DABPLUS_PS) || (*aot==AOT_DRM_MPEG_PS) ) { + usePs = 1; + } + if ( (*aot==AOT_ER_AAC_ELD) ) { + lowDelay = 1; + } + else if ( (*aot==AOT_ER_AAC_LD) ) { + error = 1; + goto bail; + } + + /* Parametric Stereo */ + if ( usePs ) { + if ( *numChannels == 2 && noElements == 1) { + /* Override Element type in case of Parametric stereo */ + elInfo[0].elType = ID_SCE; + elInfo[0].fParametricStereo = 1; + elInfo[0].nChannelsInEl = 1; + /* core encoder gets downmixed mono signal */ + *numChannels = 1; + } else { + switch (*aot) { + case AOT_MP2_PS: + *aot = AOT_MP2_SBR; + break; + case AOT_DABPLUS_PS: + *aot = AOT_DABPLUS_SBR; + break; + case AOT_DRM_MPEG_PS: + *aot = AOT_DRM_SBR; + break; + case AOT_PS: + default: + *aot = AOT_SBR; + } + usePs = 0; + } + } /* usePs */ + + /* check whether SBR setting is available for the current encoder configuration (bitrate, samplerate) */ + { + int delayDiff = 0; + int el, coreEl; + + /* Check if every element config is feasible */ + for (coreEl=0; coreEl 0) { + /* + * We must tweak the balancing into a situation where the downsampled path + * is the one to be delayed, because delaying the QMF domain input, also delays + * the downsampled audio, counteracting to the purpose of delay balancing. + */ + while ( delayDiff > 0 ) + { + /* Encoder delay increases */ + *delay += coreFrameLength*DOWN_SMPL_FAC; + /* Add one frame delay to SBR path */ + delayDiff -= coreFrameLength*DOWN_SMPL_FAC; + nBitstrDelay += 1; + } + } else { + *delay += fixp_abs(delayDiff); + } + + if (delayDiff < 0) { + /* Delay AAC data */ + delayDiff = -delayDiff; + /* Multiply downsampled offset by AAC core channels. Divide by 2 because of half samplerate of downsampled data. */ + downsampledOffset = (delayDiff*(*numChannels))/DOWN_SMPL_FAC; + sbrOffset = 0; + } else { + /* Delay SBR input */ + if ( delayDiff > (int)coreFrameLength*DOWN_SMPL_FAC ) + { + /* Do bitstream frame-wise delay balancing if we have more than SBR framelength samples delay difference */ + delayDiff -= coreFrameLength*DOWN_SMPL_FAC; + nBitstrDelay = 1; + } + /* Multiply input offset by input channels */ + sbrOffset = delayDiff*(*numChannels); + downsampledOffset = 0; + } + + hSbrEncoder->nBitstrDelay = nBitstrDelay; + hSbrEncoder->nChannels = *numChannels; + hSbrEncoder->frameSize = *frameLength*DOWN_SMPL_FAC; + hSbrEncoder->fTimeDomainDownsampling = downsample; + hSbrEncoder->estimateBitrate = 0; + hSbrEncoder->inputDataDelay = 0; + + + /* Open SBR elements */ + el = -1; + lowestSbrStartFreq = lowestSbrStopFreq = 9999; + lowestBandwidth = 99999; + + /* Loop through each core encoder element and get a matching SBR element config */ + for (coreEl=0; coreElnoElements = el+1; + + FDKsbrEnc_Reallocate(hSbrEncoder, + elInfo, + noElements); + + for (el=0; elnoElements; el++) { + + int bandwidth = *coreBandwidth; + + /* Use lowest common bandwidth */ + sbrConfig[el].startFreq = lowestSbrStartFreq; + sbrConfig[el].stopFreq = lowestSbrStopFreq; + + /* initialize SBR element, and get core bandwidth */ + error = FDKsbrEnc_EnvInit(hSbrEncoder->sbrElement[el], + &sbrConfig[el], + &bandwidth, + *aot, + nBitstrDelay, + el, + statesInitFlag + ,hSbrEncoder->dynamicRam + ); + + if (error != 0) { + goto bail; + } + + /* Get lowest core encoder bandwidth to be returned later. */ + lowestBandwidth = fixMin(lowestBandwidth, bandwidth); + + } /* second element loop */ + + /* Initialize a downsampler for each channel in each SBR element */ + if (hSbrEncoder->fTimeDomainDownsampling) + { + for (el=0; elnoElements; el++) + { + HANDLE_SBR_ELEMENT hSbrEl = hSbrEncoder->sbrElement[el]; + INT Wc, ch; + + /* Calculated required normalized cutoff frequency (Wc = 1.0 -> lowestBandwidth = inputSampleRate/2) */ + Wc = (2*lowestBandwidth)*1000 / inputSampleRate; + + for (ch=0; chelInfo.nChannelsInEl; ch++) + { + FDKaacEnc_InitDownsampler (&hSbrEl->sbrChannel[ch]->downSampler, Wc, DOWN_SMPL_FAC); + } + + FDK_ASSERT (hSbrEl->sbrChannel[0]->downSampler.delay <=MAX_DS_FILTER_DELAY && hSbrEl->sbrChannel[0]->downSampler.delay <=MAX_DS_FILTER_DELAY); + downsamplerDelay = hSbrEl->sbrChannel[0]->downSampler.delay; + } /* third element loop */ + + /* lfe */ + FDKaacEnc_InitDownsampler (&hSbrEncoder->lfeDownSampler, 0, DOWN_SMPL_FAC); + + /* Add the resampler additional delay to get the final delay and buffer offset values. */ + if (sbrOffset > 0 || downsampledOffset <= ((downsamplerDelay * (*numChannels))/DOWN_SMPL_FAC)) { + sbrOffset += (downsamplerDelay - downsampledOffset) * (*numChannels) ; + *delay += downsamplerDelay - downsampledOffset; + downsampledOffset = 0; + } else { + downsampledOffset -= (downsamplerDelay * (*numChannels))/DOWN_SMPL_FAC; + sbrOffset = 0; + } + + hSbrEncoder->inputDataDelay = downsamplerDelay; + } + + + /* Assign core encoder Bandwidth */ + *coreBandwidth = lowestBandwidth; + + /* Estimate sbr bitrate, 2.5 kBit/s per sbr channel */ + hSbrEncoder->estimateBitrate += 2500 * (*numChannels); + + /* initialize parametric stereo */ + if (usePs) + { + FDK_ASSERT(hSbrEncoder->noElements == 1); + INT psTuningTableIdx = getPsTuningTableIndex(elInfo[0].bitRate); //sbrConfig.codecSettings.bitRate); + + hSbrEncoder->hPsEncConfig->frameSize = *frameLength; //sbrConfig.sbrFrameSize; + hSbrEncoder->hPsEncConfig->qmfFilterMode = 0; + hSbrEncoder->hPsEncConfig->sbrPsDelay = 0; + + /* tuning parameters */ + if (psTuningTableIdx != INVALID_TABLE_IDX) { + hSbrEncoder->hPsEncConfig->nStereoBands = psTuningTable[psTuningTableIdx].nStereoBands; + hSbrEncoder->hPsEncConfig->maxEnvelopes = psTuningTable[psTuningTableIdx].nEnvelopes; + hSbrEncoder->hPsEncConfig->iidQuantErrorThreshold = (FIXP_DBL)psTuningTable[psTuningTableIdx].iidQuantErrorThreshold; + + /* calculation is not quite linear, increased number of envelopes causes more bits */ + /* assume avg. 50 bits per frame for 10 stereo bands / 1 envelope configuration */ + hSbrEncoder->estimateBitrate += ( (((*sampleRate) * 5 * hSbrEncoder->hPsEncConfig->nStereoBands * hSbrEncoder->hPsEncConfig->maxEnvelopes) / hSbrEncoder->frameSize)); + + } else { + error = ERROR(CDI, "Invalid ps tuning table index."); + goto bail; + } + + qmfInitSynthesisFilterBank(&hSbrEncoder->qmfSynthesisPS, + (FIXP_DBL*)hSbrEncoder->qmfSynthesisPS.FilterStates, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfSlots, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands>>1, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands>>1, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands>>1, + (statesInitFlag) ? 0 : QMF_FLAG_KEEP_STATES); + + if(errorInfo == noError){ + /* update delay */ + hSbrEncoder->hPsEncConfig->sbrPsDelay = FDKsbrEnc_GetEnvEstDelay(&hSbrEncoder->sbrElement[0]->sbrChannel[0]->hEnvChannel.sbrExtractEnvelope); + + if(noError != (errorInfo = PSEnc_Init( hSbrEncoder->hParametricStereo, + hSbrEncoder->hPsEncConfig, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfSlots, + hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands + ,hSbrEncoder->dynamicRam + ))) + { + errorInfo = handBack(errorInfo); + } + } + } + + hSbrEncoder->downsampledOffset = downsampledOffset; + hSbrEncoder->downmixSize = coreFrameLength*(*numChannels); + hSbrEncoder->bufferOffset = sbrOffset; + /* Delay Compensation: fill bitstream delay buffer with zero input signal */ + if ( hSbrEncoder->nBitstrDelay > 0 ) + { + error = FDKsbrEnc_DelayCompensation (hSbrEncoder, inputBuffer); + if (error != 0) + goto bail; + } + + /* Set Output frame length */ + *frameLength = coreFrameLength*DOWN_SMPL_FAC; + /* Input buffer offset */ + *inputBufferOffset = fixMax(sbrOffset, downsampledOffset); + + + } + + return error; + +bail: + /* Restore input settings */ + *sampleRate = inputSampleRate; + *frameLength = coreFrameLength; + *numChannels = inputChannels; + *coreBandwidth = inputBandWidth; + + return error; + } + + +INT +sbrEncoder_EncodeFrame( HANDLE_SBR_ENCODER hSbrEncoder, + INT_PCM *samples, + UINT timeInStride, + UINT sbrDataBits[(6)], + UCHAR sbrData[(6)][MAX_PAYLOAD_SIZE] + ) +{ + INT error; + int el; + + for (el=0; elnoElements; el++) + { + if (hSbrEncoder->sbrElement[el] != NULL) + { + error = FDKsbrEnc_EnvEncodeFrame( + hSbrEncoder, + el, + samples + hSbrEncoder->downsampledOffset, + timeInStride, + &sbrDataBits[el], + sbrData[el], + 0 + ); + if (error) + return error; + } + } + + if ( (hSbrEncoder->lfeChIdx!=-1) && (hSbrEncoder->fTimeDomainDownsampling) ) + { + INT nOutSamples; + + FDKaacEnc_Downsample(&hSbrEncoder->lfeDownSampler, + samples + hSbrEncoder->downsampledOffset + hSbrEncoder->bufferOffset + hSbrEncoder->lfeChIdx, + hSbrEncoder->frameSize, + timeInStride, + samples + hSbrEncoder->downsampledOffset + hSbrEncoder->lfeChIdx, + &nOutSamples, + hSbrEncoder->nChannels); + } /* lfe downsampler */ + + return 0; +} + + +INT sbrEncoder_UpdateBuffers( + HANDLE_SBR_ENCODER hSbrEncoder, + INT_PCM *timeBuffer + ) + { + if ( hSbrEncoder->downsampledOffset > 0 ) { + /* Move delayed downsampled data */ + FDKmemcpy ( timeBuffer, + timeBuffer + hSbrEncoder->downmixSize, + sizeof(INT_PCM) * (hSbrEncoder->downsampledOffset) ); + } else { + /* Move delayed input data */ + FDKmemcpy ( timeBuffer, + timeBuffer + hSbrEncoder->nChannels * hSbrEncoder->frameSize, + sizeof(INT_PCM) * hSbrEncoder->bufferOffset ); + } + if ( hSbrEncoder->nBitstrDelay > 0 ) + { + int el; + + for (el=0; elnoElements; el++) + { + FDKmemmove ( hSbrEncoder->sbrElement[el]->payloadDelayLine[0], + hSbrEncoder->sbrElement[el]->payloadDelayLine[1], + sizeof(UCHAR) * (hSbrEncoder->nBitstrDelay*MAX_PAYLOAD_SIZE) ); + + FDKmemmove( &hSbrEncoder->sbrElement[el]->payloadDelayLineSize[0], + &hSbrEncoder->sbrElement[el]->payloadDelayLineSize[1], + sizeof(UINT) * (hSbrEncoder->nBitstrDelay) ); + } + } + return 0; + } + + +INT sbrEncoder_GetEstimateBitrate(HANDLE_SBR_ENCODER hSbrEncoder) +{ + INT estimateBitrate = 0; + + if(hSbrEncoder) { + estimateBitrate += hSbrEncoder->estimateBitrate; + } + + return estimateBitrate; +} + +INT sbrEncoder_GetInputDataDelay(HANDLE_SBR_ENCODER hSbrEncoder) +{ + INT delay = -1; + + if(hSbrEncoder) { + delay = hSbrEncoder->inputDataDelay; + } + return delay; +} + + +INT sbrEncoder_GetLibInfo( LIB_INFO *info ) +{ + int i; + + if (info == NULL) { + return -1; + } + /* search for next free tab */ + for (i = 0; i < FDK_MODULE_LAST; i++) { + if (info[i].module_id == FDK_NONE) break; + } + if (i == FDK_MODULE_LAST) { + return -1; + } + info += i; + + info->module_id = FDK_SBRENC; + info->version = LIB_VERSION(SBRENCODER_LIB_VL0, SBRENCODER_LIB_VL1, SBRENCODER_LIB_VL2); + LIB_VERSION_STRING(info); + info->build_date = __DATE__; + info->build_time = __TIME__; + info->title = "SBR Encoder"; + + /* Set flags */ + info->flags = 0 + | CAPF_SBR_HQ + | CAPF_SBR_PS_MPEG + ; + /* End of flags */ + + return 0; +} diff --git a/libSBRenc/src/sbr_misc.cpp b/libSBRenc/src/sbr_misc.cpp new file mode 100644 index 0000000..b602e99 --- /dev/null +++ b/libSBRenc/src/sbr_misc.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Sbr miscellaneous helper functions $Revision: 36847 $ +*/ +#include "sbr_misc.h" + + +void FDKsbrEnc_Shellsort_fract (FIXP_DBL *in, INT n) +{ + FIXP_DBL v; + INT i, j; + INT inc = 1; + + do + inc = 3 * inc + 1; + while (inc <= n); + + do { + inc = inc / 3; + for (i = inc + 1; i <= n; i++) { + v = in[i-1]; + j = i; + while (in[j-inc-1] > v) { + in[j-1] = in[j-inc-1]; + j -= inc; + if (j <= inc) + break; + } + in[j-1] = v; + } + } while (inc > 1); + +} + +/* Sorting routine */ +void FDKsbrEnc_Shellsort_int (INT *in, INT n) +{ + + INT i, j, v; + INT inc = 1; + + do + inc = 3 * inc + 1; + while (inc <= n); + + do { + inc = inc / 3; + for (i = inc + 1; i <= n; i++) { + v = in[i-1]; + j = i; + while (in[j-inc-1] > v) { + in[j-1] = in[j-inc-1]; + j -= inc; + if (j <= inc) + break; + } + in[j-1] = v; + } + } while (inc > 1); + +} + + + +/******************************************************************************* + Functionname: FDKsbrEnc_AddVecLeft + ******************************************************************************* + + Description: + + Arguments: INT* dst, INT* length_dst, INT* src, INT length_src + + Return: none + +*******************************************************************************/ +void +FDKsbrEnc_AddVecLeft (INT *dst, INT *length_dst, INT *src, INT length_src) +{ + INT i; + + for (i = length_src - 1; i >= 0; i--) + FDKsbrEnc_AddLeft (dst, length_dst, src[i]); +} + + +/******************************************************************************* + Functionname: FDKsbrEnc_AddLeft + ******************************************************************************* + + Description: + + Arguments: INT* vector, INT* length_vector, INT value + + Return: none + +*******************************************************************************/ +void +FDKsbrEnc_AddLeft (INT *vector, INT *length_vector, INT value) +{ + INT i; + + for (i = *length_vector; i > 0; i--) + vector[i] = vector[i - 1]; + vector[0] = value; + (*length_vector)++; +} + + +/******************************************************************************* + Functionname: FDKsbrEnc_AddRight + ******************************************************************************* + + Description: + + Arguments: INT* vector, INT* length_vector, INT value + + Return: none + +*******************************************************************************/ +void +FDKsbrEnc_AddRight (INT *vector, INT *length_vector, INT value) +{ + vector[*length_vector] = value; + (*length_vector)++; +} + + + +/******************************************************************************* + Functionname: FDKsbrEnc_AddVecRight + ******************************************************************************* + + Description: + + Arguments: INT* dst, INT* length_dst, INT* src, INT length_src) + + Return: none + +*******************************************************************************/ +void +FDKsbrEnc_AddVecRight (INT *dst, INT *length_dst, INT *src, INT length_src) +{ + INT i; + for (i = 0; i < length_src; i++) + FDKsbrEnc_AddRight (dst, length_dst, src[i]); +} + + +/***************************************************************************** + + functionname: FDKsbrEnc_LSI_divide_scale_fract + + description: Calculates division with best precision and scales the result. + + return: num*scale/denom + +*****************************************************************************/ +FIXP_DBL FDKsbrEnc_LSI_divide_scale_fract(FIXP_DBL num, FIXP_DBL denom, FIXP_DBL scale) +{ + FIXP_DBL tmp = FL2FXCONST_DBL(0.0f); + if (num != FL2FXCONST_DBL(0.0f)) { + + INT shiftCommon; + INT shiftNum = CountLeadingBits(num); + INT shiftDenom = CountLeadingBits(denom); + INT shiftScale = CountLeadingBits(scale); + + num = num << shiftNum; + scale = scale << shiftScale; + + tmp = fMultDiv2(num,scale); + + if ( denom > (tmp >> fixMin(shiftNum+shiftScale-1,(DFRACT_BITS-1))) ) { + denom = denom << shiftDenom; + tmp = schur_div(tmp,denom,15); + shiftCommon = fixMin((shiftNum-shiftDenom+shiftScale-1),(DFRACT_BITS-1)); + if (shiftCommon < 0) + tmp <<= -shiftCommon; + else + tmp >>= shiftCommon; + } + else { + tmp = /*FL2FXCONST_DBL(1.0)*/ (FIXP_DBL)MAXVAL_DBL; + } + } + + return (tmp); +} + diff --git a/libSBRenc/src/sbr_misc.h b/libSBRenc/src/sbr_misc.h new file mode 100644 index 0000000..37ec8e3 --- /dev/null +++ b/libSBRenc/src/sbr_misc.h @@ -0,0 +1,48 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Sbr miscellaneous helper functions prototypes $Revision: 36847 $ + \author +*/ + +#ifndef _SBR_MISC_H +#define _SBR_MISC_H + +#include "sbr_encoder.h" + +/* Sorting routines */ +void FDKsbrEnc_Shellsort_fract (FIXP_DBL *in, INT n); +void FDKsbrEnc_Shellsort_int (INT *in, INT n); + +void FDKsbrEnc_AddLeft (INT *vector, INT *length_vector, INT value); +void FDKsbrEnc_AddRight (INT *vector, INT *length_vector, INT value); +void FDKsbrEnc_AddVecLeft (INT *dst, INT *length_dst, INT *src, INT length_src); +void FDKsbrEnc_AddVecRight (INT *dst, INT *length_vector_dst, INT *src, INT length_src); + +FIXP_DBL FDKsbrEnc_LSI_divide_scale_fract(FIXP_DBL num, FIXP_DBL denom, FIXP_DBL scale); + +#endif diff --git a/libSBRenc/src/sbr_ram.cpp b/libSBRenc/src/sbr_ram.cpp new file mode 100644 index 0000000..289270c --- /dev/null +++ b/libSBRenc/src/sbr_ram.cpp @@ -0,0 +1,220 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Memory layout + $Revision: 36847 $ + + This module declares all static and dynamic memory spaces +*/ +#include "sbr_ram.h" + +#include "sbr.h" +#include "genericStds.h" + +C_ALLOC_MEM (Ram_SbrDynamic_RAM, FIXP_DBL, ((SBR_ENC_DYN_RAM_SIZE)/sizeof(FIXP_DBL))) + +/*! + \name StaticSbrData + + Static memory areas, must not be overwritten in other sections of the encoder +*/ +/* @{ */ + +/*! static sbr encoder instance for one encoder (2 channels) + all major static and dynamic memory areas are located + in module sbr_ram and sbr rom +*/ +C_ALLOC_MEM (Ram_SbrEncoder, SBR_ENCODER, 1) +C_ALLOC_MEM2(Ram_SbrChannel, SBR_CHANNEL, 1, (6)) +C_ALLOC_MEM2(Ram_SbrElement, SBR_ELEMENT, 1, (6)) + +/*! Filter states for QMF-analysis.
+ Dimension: #MAXNRSBRCHANNELS * #SBR_QMF_FILTER_LENGTH +*/ +C_AALLOC_MEM2_L (Ram_Sbr_QmfStatesAnalysis, FIXP_QAS, QMF_FILTER_LENGTH, (6), SECT_DATA_L1) + + +/*! Matrix holding the quota values for all estimates, all channels + Dimension #MAXNRSBRCHANNELS * +#SBR_QMF_CHANNELS* #MAX_NO_OF_ESTIMATES +*/ +C_ALLOC_MEM2_L (Ram_Sbr_quotaMatrix, FIXP_DBL, (MAX_NO_OF_ESTIMATES*QMF_CHANNELS), (6), SECT_DATA_L1) + +/*! Matrix holding the sign values for all estimates, all channels + Dimension #MAXNRSBRCHANNELS * +#SBR_QMF_CHANNELS* #MAX_NO_OF_ESTIMATES +*/ +C_ALLOC_MEM2 (Ram_Sbr_signMatrix, INT, (MAX_NO_OF_ESTIMATES*QMF_CHANNELS), (6)) + +/*! Frequency band table (low res)
+ Dimension #MAX_FREQ_COEFFS/2+1 +*/ +C_ALLOC_MEM2 (Ram_Sbr_freqBandTableLO, UCHAR, (MAX_FREQ_COEFFS/2+1), (6)) + +/*! Frequency band table (high res)
+ Dimension #MAX_FREQ_COEFFS +1 +*/ +C_ALLOC_MEM2 (Ram_Sbr_freqBandTableHI, UCHAR, (MAX_FREQ_COEFFS+1), (6)) + +/*! vk matser table
+ Dimension #MAX_FREQ_COEFFS +1 +*/ +C_ALLOC_MEM2 (Ram_Sbr_v_k_master, UCHAR, (MAX_FREQ_COEFFS+1), (6)) + + +/* + Missing harmonics detection +*/ + +/*! sbr_detectionVectors
+ Dimension #MAX_NUM_CHANNELS*#MAX_NO_OF_ESTIMATES*#MAX_FREQ_COEFFS] +*/ +C_ALLOC_MEM2 (Ram_Sbr_detectionVectors, UCHAR, (MAX_NO_OF_ESTIMATES*MAX_FREQ_COEFFS), (6)) + +/*! sbr_prevCompVec[
+ Dimension #MAX_NUM_CHANNELS*#MAX_FREQ_COEFFS] +*/ +C_ALLOC_MEM2 (Ram_Sbr_prevEnvelopeCompensation, UCHAR, MAX_FREQ_COEFFS, (6)) +/*! sbr_guideScfb[
+ Dimension #MAX_NUM_CHANNELS*#MAX_FREQ_COEFFS] +*/ +C_ALLOC_MEM2 (Ram_Sbr_guideScfb, UCHAR, MAX_FREQ_COEFFS, (6)) + +/*! sbr_guideVectorDetected
+ Dimension #MAX_NUM_CHANNELS*#MAX_NO_OF_ESTIMATES*#MAX_FREQ_COEFFS] +*/ +C_ALLOC_MEM2 (Ram_Sbr_guideVectorDetected, UCHAR, (MAX_NO_OF_ESTIMATES*MAX_FREQ_COEFFS), (6)) +C_ALLOC_MEM2 (Ram_Sbr_guideVectorDiff, FIXP_DBL, (MAX_NO_OF_ESTIMATES*MAX_FREQ_COEFFS), (6)) +C_ALLOC_MEM2 (Ram_Sbr_guideVectorOrig, FIXP_DBL, (MAX_NO_OF_ESTIMATES*MAX_FREQ_COEFFS), (6)) + +/* + Static Parametric Stereo memory +*/ +C_AALLOC_MEM_L(Ram_PsQmfStatesSynthesis, FIXP_DBL, QMF_FILTER_LENGTH/2, SECT_DATA_L1) + +C_ALLOC_MEM (Ram_PsEnvRBuffer, FIXP_DBL, QMF_MAX_TIME_SLOTS*QMF_CHANNELS/2) +C_ALLOC_MEM (Ram_PsEnvIBuffer, FIXP_DBL, QMF_MAX_TIME_SLOTS*QMF_CHANNELS/2) +C_ALLOC_MEM2 (Ram_PsChData, PS_CHANNEL_DATA, 1, MAX_PS_CHANNELS) +C_ALLOC_MEM (Ram_PsEncConf, PSENC_CONFIG, 1) +C_ALLOC_MEM_L (Ram_PsEncode, PS_ENCODE, 1, SECT_DATA_L1) +C_ALLOC_MEM (Ram_PsData, PS_DATA, 1) +C_ALLOC_MEM (Ram_ParamStereo, PARAMETRIC_STEREO, 1) +C_ALLOC_MEM2 (Ram_PsOut, PS_OUT, 1, 2) + + +/* QMF data + */ +C_ALLOC_MEM (Ram_PsQmfNewSamples, FIXP_DBL, QMF_CHANNELS) + +C_ALLOC_MEM2 (Ram_PsQmfData, PS_QMF_DATA, 1, MAX_PS_CHANNELS) + +/* HYBRID data + */ +C_AALLOC_MEM (Ram_PsHybFFT, FIXP_DBL, 16) + +C_ALLOC_MEM2(Ram_HybData, PS_HYBRID_DATA, 1, MAX_PS_CHANNELS) +C_ALLOC_MEM2(Ram_PsHybrid, PS_HYBRID, 1, MAX_PS_CHANNELS) +C_ALLOC_MEM (Ram_PsHybConfig, PS_HYBRID_CONFIG, 1) + +C_ALLOC_MEM2(Ram_PsRhyb, FIXP_QMF, ((HYBRID_FRAMESIZE+HYBRID_WRITEOFFSET)*HYBRID_NUM_BANDS), MAX_PS_CHANNELS) +C_ALLOC_MEM2(Ram_PsIhyb, FIXP_QMF, ((HYBRID_FRAMESIZE+HYBRID_WRITEOFFSET)*HYBRID_NUM_BANDS), MAX_PS_CHANNELS) + +C_ALLOC_MEM (Ram_PsHybWkReal, FIXP_QMF, (HYBRID_FRAMESIZE + QMF_BUFFER_MOVE)) +C_ALLOC_MEM (Ram_PsHybWkImag, FIXP_QMF, (HYBRID_FRAMESIZE + QMF_BUFFER_MOVE)) + +C_ALLOC_MEM2(Ram_PsMtmpReal, FIXP_QMF, (MAX_HYBRID_RES), HYBRID_FRAMESIZE) +C_ALLOC_MEM2(Ram_PsMtmpImag, FIXP_QMF, (MAX_HYBRID_RES), HYBRID_FRAMESIZE) + + +/* @} */ + + +/*! + \name DynamicSbrData + + Dynamic memory areas, might be reused in other algorithm sections, + e.g. the core encoder. +*/ +/* @{ */ + + /*! Energy buffer for envelope extraction
+ Dimension #MAXNRSBRCHANNELS * +#SBR_QMF_SLOTS * #SBR_QMF_CHANNELS + */ + C_ALLOC_MEM2 (Ram_Sbr_envYBuffer, FIXP_DBL, (QMF_MAX_TIME_SLOTS/2 * QMF_CHANNELS), (6)) + + FIXP_DBL* GetRam_Sbr_envYBuffer (int n, UCHAR* dynamic_RAM) { + FDK_ASSERT(dynamic_RAM!=0); + return ((FIXP_DBL*) (dynamic_RAM + OFFSET_NRG + (n*Y_2_BUF_BYTE) )); + } + + /* + * QMF data + */ + /* The SBR encoder uses a single channel overlapping buffer set (always n=0), but PS does not. */ + FIXP_DBL* GetRam_Sbr_envRBuffer (int n, UCHAR* dynamic_RAM) { + FDK_ASSERT(dynamic_RAM!=0); + return ((FIXP_DBL*) (dynamic_RAM + OFFSET_QMF + (n*ENV_R_BUFF_BYTE*2) )); + } + FIXP_DBL* GetRam_Sbr_envIBuffer (int n, UCHAR* dynamic_RAM) { + FDK_ASSERT(dynamic_RAM!=0); + //return ((FIXP_DBL*) (dynamic_RAM + OFFSET_QMF + (MAX_NUM_CHANNELS*ENV_R_BUFF_BYTE) + n*ENV_I_BUFF_BYTE)); + return ((FIXP_DBL*) (dynamic_RAM + OFFSET_QMF + (ENV_R_BUFF_BYTE) + (n*ENV_I_BUFF_BYTE*2))); + } + + /* reuse QMF buffer in PS module. We Require space to hold 2 channels. */ + C_ALLOC_MEM2(Ram_PsRqmf, FIXP_QMF, ((PSENC_QMF_BUFFER_LENGTH-QMF_MAX_TIME_SLOTS)*(QMF_CHANNELS)), MAX_PS_CHANNELS) + C_ALLOC_MEM2(Ram_PsIqmf, FIXP_QMF, ((PSENC_QMF_BUFFER_LENGTH-QMF_MAX_TIME_SLOTS)*(QMF_CHANNELS)), MAX_PS_CHANNELS) + + FIXP_QMF* FDKsbrEnc_SliceRam_PsRqmf(FIXP_DBL* rQmfData, UCHAR* dynamic_RAM, int ch, int i, int qmfSlots) + { + FDK_ASSERT(dynamic_RAM!=0); + if (i>1 ) + + +/* Workbuffer RAM - Allocation */ +/* + ++++++++++++++++++++++++++++++++++++++++++++++++++++ + | OFFSET_NRG | OFFSET_QMF | + ++++++++++++++++++++++++++++++++++++++++++++++++++++ + -------------------------------------------------- + | 0.5 * | | + | sbr_envYBuffer_size | sbr_envRBuffer | + | | sbr_envIBuffer | + -------------------------------------------------- + +*/ + #define BUF_NRG_SIZE ( (MAX_NUM_CHANNELS * Y_2_BUF_BYTE) ) + + #define OFFSET_NRG ( 0 ) + #define OFFSET_QMF ( OFFSET_NRG + BUF_NRG_SIZE ) + + /* if common dynamic memory used in AAC-core and SBR, find out maximal size of + SCR buffer (see XX in figure above) */ + /* Only PS required holding 2 channel QMF data. AAC_WK_BUF_SIZE_0 must fit into this buffer. */ + #define BUF_QMF_SIZE ( 2*(ENV_R_BUFF_BYTE + ENV_I_BUFF_BYTE) ) + + /* Size of the shareable memory region than can be reused */ + #define SBR_ENC_DYN_RAM_SIZE ( BUF_NRG_SIZE + BUF_QMF_SIZE ) + +/* + ***************************************************************************************************** + */ + + H_ALLOC_MEM(Ram_SbrDynamic_RAM, FIXP_DBL) + + H_ALLOC_MEM(Ram_SbrEncoder, SBR_ENCODER) + H_ALLOC_MEM(Ram_SbrChannel, SBR_CHANNEL) + H_ALLOC_MEM(Ram_SbrElement, SBR_ELEMENT) + + H_ALLOC_MEM(Ram_Sbr_quotaMatrix, FIXP_DBL) + H_ALLOC_MEM(Ram_Sbr_signMatrix, INT) + + H_ALLOC_MEM(Ram_Sbr_QmfStatesAnalysis, FIXP_QAS) + + H_ALLOC_MEM(Ram_Sbr_freqBandTableLO, UCHAR) + H_ALLOC_MEM(Ram_Sbr_freqBandTableHI, UCHAR) + H_ALLOC_MEM(Ram_Sbr_v_k_master, UCHAR) + + H_ALLOC_MEM(Ram_Sbr_detectionVectors, UCHAR) + H_ALLOC_MEM(Ram_Sbr_prevEnvelopeCompensation, UCHAR) + H_ALLOC_MEM(Ram_Sbr_guideScfb, UCHAR) + H_ALLOC_MEM(Ram_Sbr_guideVectorDetected, UCHAR) + + /* Dynamic Memory Allocation */ + + H_ALLOC_MEM(Ram_Sbr_envYBuffer, FIXP_DBL) + FIXP_DBL* GetRam_Sbr_envYBuffer (int n, UCHAR* dynamic_RAM); + FIXP_DBL* GetRam_Sbr_envRBuffer (int n, UCHAR* dynamic_RAM); + FIXP_DBL* GetRam_Sbr_envIBuffer (int n, UCHAR* dynamic_RAM); + + H_ALLOC_MEM(Ram_Sbr_guideVectorDiff, FIXP_DBL) + H_ALLOC_MEM(Ram_Sbr_guideVectorOrig, FIXP_DBL) + + + H_ALLOC_MEM(Ram_PsEnvRBuffer, FIXP_QMF) + H_ALLOC_MEM(Ram_PsEnvIBuffer, FIXP_QMF) + + H_ALLOC_MEM(Ram_PsQmfStatesSynthesis, FIXP_DBL) + H_ALLOC_MEM(Ram_PsQmfNewSamples, FIXP_DBL) + + H_ALLOC_MEM(Ram_PsEncConf, PSENC_CONFIG) + H_ALLOC_MEM(Ram_PsEncode, PS_ENCODE) + H_ALLOC_MEM(Ram_PsData, PS_DATA) + +#define HYBRID_READ_OFFSET ( 10 ) +#define HYBRID_WRITE_OFFSET ( ((32)>>1)-6 ) + +#define HYBRID_DATA_READ_OFFSET ( 0 ) +#define QMF_READ_OFFSET ( 0 ) + + H_ALLOC_MEM(Ram_PsRqmf, FIXP_DBL) + H_ALLOC_MEM(Ram_PsIqmf, FIXP_DBL) + FIXP_DBL* FDKsbrEnc_SliceRam_PsRqmf (FIXP_DBL* rQmfData, UCHAR* dynamic_RAM, int n, int i, int qmfSlots); + FIXP_DBL* FDKsbrEnc_SliceRam_PsIqmf (FIXP_DBL* iQmfData, UCHAR* dynamic_RAM, int n, int i, int qmfSlots); + + H_ALLOC_MEM(Ram_PsQmfData, PS_QMF_DATA) + H_ALLOC_MEM(Ram_PsChData, PS_CHANNEL_DATA) + + H_ALLOC_MEM(Ram_ParamStereo, PARAMETRIC_STEREO) + H_ALLOC_MEM(Ram_PsOut, PS_OUT) + + /* HYBRID */ + H_ALLOC_MEM(Ram_PsHybFFT, FIXP_DBL) + + H_ALLOC_MEM(Ram_HybData, PS_HYBRID_DATA) + H_ALLOC_MEM(Ram_PsRhyb, FIXP_DBL) + H_ALLOC_MEM(Ram_PsIhyb, FIXP_DBL) + + H_ALLOC_MEM(Ram_PsHybConfig, PS_HYBRID_CONFIG) + H_ALLOC_MEM(Ram_PsHybrid, PS_HYBRID) + + FIXP_DBL* psMqmfBufferRealInit (INT ch, INT i); + FIXP_DBL* psMqmfBufferImagInit (INT ch, INT i); + + + /* working buffer */ + H_ALLOC_MEM(Ram_PsHybWkReal, FIXP_DBL) + H_ALLOC_MEM(Ram_PsHybWkImag, FIXP_DBL) + + H_ALLOC_MEM(Ram_PsMtmpReal, FIXP_DBL) + H_ALLOC_MEM(Ram_PsMtmpImag, FIXP_DBL) + + + +#endif + diff --git a/libSBRenc/src/sbr_rom.cpp b/libSBRenc/src/sbr_rom.cpp new file mode 100644 index 0000000..e83a519 --- /dev/null +++ b/libSBRenc/src/sbr_rom.cpp @@ -0,0 +1,681 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ +******************************************************************************/ +/*! + \file + \brief Definition of constant tables + $Revision: 36914 $ + + This module contains most of the constant data that can be stored in ROM. +*/ + +#include "sbr_rom.h" +#include "genericStds.h" + +//@{ +/******************************************************************************* + + Table Overview: + + o envelope level, 1.5 dB: + 1a) v_Huff_envelopeLevelC10T[121] + 1b) v_Huff_envelopeLevelL10T[121] + 2a) v_Huff_envelopeLevelC10F[121] + 2b) v_Huff_envelopeLevelL10F[121] + + o envelope balance, 1.5 dB: + 3a) bookSbrEnvBalanceC10T[49] + 3b) bookSbrEnvBalanceL10T[49] + 4a) bookSbrEnvBalanceC10F[49] + 4b) bookSbrEnvBalanceL10F[49] + + o envelope level, 3.0 dB: + 5a) v_Huff_envelopeLevelC11T[63] + 5b) v_Huff_envelopeLevelL11T[63] + 6a) v_Huff_envelopeLevelC11F[63] + 6b) v_Huff_envelopeLevelC11F[63] + + o envelope balance, 3.0 dB: + 7a) bookSbrEnvBalanceC11T[25] + 7b) bookSbrEnvBalanceL11T[25] + 8a) bookSbrEnvBalanceC11F[25] + 8b) bookSbrEnvBalanceL11F[25] + + o noise level, 3.0 dB: + 9a) v_Huff_NoiseLevelC11T[63] + 9b) v_Huff_NoiseLevelL11T[63] + - ) (v_Huff_envelopeLevelC11F[63] is used for freq dir) + - ) (v_Huff_envelopeLevelL11F[63] is used for freq dir) + + o noise balance, 3.0 dB: + 10a) bookSbrNoiseBalanceC11T[25] + 10b) bookSbrNoiseBalanceL11T[25] + - ) (bookSbrEnvBalanceC11F[25] is used for freq dir) + - ) (bookSbrEnvBalanceL11F[25] is used for freq dir) + + + (1.5 dB is never used for noise) + +********************************************************************************/ + + +/*******************************************************************************/ +/* table : envelope level, 1.5 dB */ +/* theor range : [-58,58], CODE_BOOK_SCF_LAV = 58 */ +/* implem range: [-60,60], CODE_BOOK_SCF_LAV10 = 60 */ +/* raw stats : envelopeLevel_00 (yes, wrong suffix in name) KK 01-03-09 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode3C2FIX.m/envelopeLevel_00T_cF.mat/v_nChex_cF + built by : FH 01-07-05 */ + +const INT v_Huff_envelopeLevelC10T[121] = +{ + 0x0003FFD6, 0x0003FFD7, 0x0003FFD8, 0x0003FFD9, 0x0003FFDA, 0x0003FFDB, 0x0007FFB8, 0x0007FFB9, + 0x0007FFBA, 0x0007FFBB, 0x0007FFBC, 0x0007FFBD, 0x0007FFBE, 0x0007FFBF, 0x0007FFC0, 0x0007FFC1, + 0x0007FFC2, 0x0007FFC3, 0x0007FFC4, 0x0007FFC5, 0x0007FFC6, 0x0007FFC7, 0x0007FFC8, 0x0007FFC9, + 0x0007FFCA, 0x0007FFCB, 0x0007FFCC, 0x0007FFCD, 0x0007FFCE, 0x0007FFCF, 0x0007FFD0, 0x0007FFD1, + 0x0007FFD2, 0x0007FFD3, 0x0001FFE6, 0x0003FFD4, 0x0000FFF0, 0x0001FFE9, 0x0003FFD5, 0x0001FFE7, + 0x0000FFF1, 0x0000FFEC, 0x0000FFED, 0x0000FFEE, 0x00007FF4, 0x00003FF9, 0x00003FF7, 0x00001FFA, + 0x00001FF9, 0x00000FFB, 0x000007FC, 0x000003FC, 0x000001FD, 0x000000FD, 0x0000007D, 0x0000003D, + 0x0000001D, 0x0000000D, 0x00000005, 0x00000001, 0x00000000, 0x00000004, 0x0000000C, 0x0000001C, + 0x0000003C, 0x0000007C, 0x000000FC, 0x000001FC, 0x000003FD, 0x00000FFA, 0x00001FF8, 0x00003FF6, + 0x00003FF8, 0x00007FF5, 0x0000FFEF, 0x0001FFE8, 0x0000FFF2, 0x0007FFD4, 0x0007FFD5, 0x0007FFD6, + 0x0007FFD7, 0x0007FFD8, 0x0007FFD9, 0x0007FFDA, 0x0007FFDB, 0x0007FFDC, 0x0007FFDD, 0x0007FFDE, + 0x0007FFDF, 0x0007FFE0, 0x0007FFE1, 0x0007FFE2, 0x0007FFE3, 0x0007FFE4, 0x0007FFE5, 0x0007FFE6, + 0x0007FFE7, 0x0007FFE8, 0x0007FFE9, 0x0007FFEA, 0x0007FFEB, 0x0007FFEC, 0x0007FFED, 0x0007FFEE, + 0x0007FFEF, 0x0007FFF0, 0x0007FFF1, 0x0007FFF2, 0x0007FFF3, 0x0007FFF4, 0x0007FFF5, 0x0007FFF6, + 0x0007FFF7, 0x0007FFF8, 0x0007FFF9, 0x0007FFFA, 0x0007FFFB, 0x0007FFFC, 0x0007FFFD, 0x0007FFFE, + 0x0007FFFF +}; + + +/* direction: time + contents : codeword lengths + raw table: HuffCode3C2FIX.m/envelopeLevel_00T_cF.mat/v_nLhex_cF + built by : FH 01-07-05 */ + +const UCHAR v_Huff_envelopeLevelL10T[121] = +{ + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x11, 0x12, 0x10, 0x11, 0x12, 0x11, 0x10, 0x10, 0x10, 0x10, 0x0F, 0x0E, 0x0E, 0x0D, + 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0C, 0x0D, 0x0E, 0x0E, 0x0F, 0x10, 0x11, 0x10, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13 +}; + + +/* direction: freq + contents : codewords + raw table: HuffCode3C2FIX.m/envelopeLevel_00F_cF.mat/v_nChex_cF + built by : FH 01-07-05 */ + +const INT v_Huff_envelopeLevelC10F[121] = +{ + 0x0007FFE7, 0x0007FFE8, 0x000FFFD2, 0x000FFFD3, 0x000FFFD4, 0x000FFFD5, 0x000FFFD6, 0x000FFFD7, + 0x000FFFD8, 0x0007FFDA, 0x000FFFD9, 0x000FFFDA, 0x000FFFDB, 0x000FFFDC, 0x0007FFDB, 0x000FFFDD, + 0x0007FFDC, 0x0007FFDD, 0x000FFFDE, 0x0003FFE4, 0x000FFFDF, 0x000FFFE0, 0x000FFFE1, 0x0007FFDE, + 0x000FFFE2, 0x000FFFE3, 0x000FFFE4, 0x0007FFDF, 0x000FFFE5, 0x0007FFE0, 0x0003FFE8, 0x0007FFE1, + 0x0003FFE0, 0x0003FFE9, 0x0001FFEF, 0x0003FFE5, 0x0001FFEC, 0x0001FFED, 0x0001FFEE, 0x0000FFF4, + 0x0000FFF3, 0x0000FFF0, 0x00007FF7, 0x00007FF6, 0x00003FFA, 0x00001FFA, 0x00001FF9, 0x00000FFA, + 0x00000FF8, 0x000007F9, 0x000003FB, 0x000001FC, 0x000001FA, 0x000000FB, 0x0000007C, 0x0000003C, + 0x0000001C, 0x0000000C, 0x00000005, 0x00000001, 0x00000000, 0x00000004, 0x0000000D, 0x0000001D, + 0x0000003D, 0x000000FA, 0x000000FC, 0x000001FB, 0x000003FA, 0x000007F8, 0x000007FA, 0x000007FB, + 0x00000FF9, 0x00000FFB, 0x00001FF8, 0x00001FFB, 0x00003FF8, 0x00003FF9, 0x0000FFF1, 0x0000FFF2, + 0x0001FFEA, 0x0001FFEB, 0x0003FFE1, 0x0003FFE2, 0x0003FFEA, 0x0003FFE3, 0x0003FFE6, 0x0003FFE7, + 0x0003FFEB, 0x000FFFE6, 0x0007FFE2, 0x000FFFE7, 0x000FFFE8, 0x000FFFE9, 0x000FFFEA, 0x000FFFEB, + 0x000FFFEC, 0x0007FFE3, 0x000FFFED, 0x000FFFEE, 0x000FFFEF, 0x000FFFF0, 0x0007FFE4, 0x000FFFF1, + 0x0003FFEC, 0x000FFFF2, 0x000FFFF3, 0x0007FFE5, 0x0007FFE6, 0x000FFFF4, 0x000FFFF5, 0x000FFFF6, + 0x000FFFF7, 0x000FFFF8, 0x000FFFF9, 0x000FFFFA, 0x000FFFFB, 0x000FFFFC, 0x000FFFFD, 0x000FFFFE, + 0x000FFFFF +}; + + +/* direction: freq + contents : codeword lengths + raw table: HuffCode3C2FIX.m/envelopeLevel_00F_cF.mat/v_nLhex_cF + built by : FH 01-07-05 */ + +const UCHAR v_Huff_envelopeLevelL10F[121] = +{ + 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x13, 0x14, 0x14, 0x14, 0x14, 0x13, 0x14, + 0x13, 0x13, 0x14, 0x12, 0x14, 0x14, 0x14, 0x13, 0x14, 0x14, 0x14, 0x13, 0x14, 0x13, 0x12, 0x13, + 0x12, 0x12, 0x11, 0x12, 0x11, 0x11, 0x11, 0x10, 0x10, 0x10, 0x0F, 0x0F, 0x0E, 0x0D, 0x0D, 0x0C, + 0x0C, 0x0B, 0x0A, 0x09, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x08, 0x08, 0x09, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0D, 0x0D, 0x0E, 0x0E, 0x10, 0x10, + 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x14, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x13, 0x14, 0x14, 0x14, 0x14, 0x13, 0x14, 0x12, 0x14, 0x14, 0x13, 0x13, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14 +}; + + +/*******************************************************************************/ +/* table : envelope balance, 1.5 dB */ +/* theor range : [-48,48], CODE_BOOK_SCF_LAV = 48 */ +/* implem range: same but mapped to [-24,24], CODE_BOOK_SCF_LAV_BALANCE10 = 24 */ +/* raw stats : envelopePan_00 (yes, wrong suffix in name) KK 01-03-09 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode3C.m/envelopePan_00T.mat/v_nBhex + built by : FH 01-05-15 */ + +const INT bookSbrEnvBalanceC10T[49] = +{ + 0x0000FFE4, 0x0000FFE5, 0x0000FFE6, 0x0000FFE7, 0x0000FFE8, 0x0000FFE9, 0x0000FFEA, 0x0000FFEB, + 0x0000FFEC, 0x0000FFED, 0x0000FFEE, 0x0000FFEF, 0x0000FFF0, 0x0000FFF1, 0x0000FFF2, 0x0000FFF3, + 0x0000FFF4, 0x0000FFE2, 0x00000FFC, 0x000007FC, 0x000001FE, 0x0000007E, 0x0000001E, 0x00000006, + 0x00000000, 0x00000002, 0x0000000E, 0x0000003E, 0x000000FE, 0x000007FD, 0x00000FFD, 0x00007FF0, + 0x0000FFE3, 0x0000FFF5, 0x0000FFF6, 0x0000FFF7, 0x0000FFF8, 0x0000FFF9, 0x0000FFFA, 0x0001FFF6, + 0x0001FFF7, 0x0001FFF8, 0x0001FFF9, 0x0001FFFA, 0x0001FFFB, 0x0001FFFC, 0x0001FFFD, 0x0001FFFE, + 0x0001FFFF +}; + + +/* direction: time + contents : codeword lengths + raw table: HuffCode3C.m/envelopePan_00T.mat/v_nLhex + built by : FH 01-05-15 */ + +const UCHAR bookSbrEnvBalanceL10T[49] = +{ + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x0C, 0x0B, 0x09, 0x07, 0x05, 0x03, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0B, 0x0C, 0x0F, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11 +}; + + +/* direction: freq + contents : codewords + raw table: HuffCode3C.m/envelopePan_00F.mat/v_nBhex + built by : FH 01-05-15 */ + +const INT bookSbrEnvBalanceC10F[49] = +{ + 0x0003FFE2, 0x0003FFE3, 0x0003FFE4, 0x0003FFE5, 0x0003FFE6, 0x0003FFE7, 0x0003FFE8, 0x0003FFE9, + 0x0003FFEA, 0x0003FFEB, 0x0003FFEC, 0x0003FFED, 0x0003FFEE, 0x0003FFEF, 0x0003FFF0, 0x0000FFF7, + 0x0001FFF0, 0x00003FFC, 0x000007FE, 0x000007FC, 0x000000FE, 0x0000007E, 0x0000000E, 0x00000002, + 0x00000000, 0x00000006, 0x0000001E, 0x0000003E, 0x000001FE, 0x000007FD, 0x00000FFE, 0x00007FFA, + 0x0000FFF6, 0x0003FFF1, 0x0003FFF2, 0x0003FFF3, 0x0003FFF4, 0x0003FFF5, 0x0003FFF6, 0x0003FFF7, + 0x0003FFF8, 0x0003FFF9, 0x0003FFFA, 0x0003FFFB, 0x0003FFFC, 0x0003FFFD, 0x0003FFFE, 0x0007FFFE, + 0x0007FFFF +}; + + +/* direction: freq + contents : codeword lengths + raw table: HuffCode3C.m/envelopePan_00F.mat/v_nLhex + built by : FH 01-05-15 */ + +const UCHAR bookSbrEnvBalanceL10F[49] = +{ + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x10, + 0x11, 0x0E, 0x0B, 0x0B, 0x08, 0x07, 0x04, 0x02, 0x01, 0x03, 0x05, 0x06, 0x09, 0x0B, 0x0C, 0x0F, + 0x10, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, + 0x13 +}; + + +/*******************************************************************************/ +/* table : envelope level, 3.0 dB */ +/* theor range : [-29,29], CODE_BOOK_SCF_LAV = 29 */ +/* implem range: [-31,31], CODE_BOOK_SCF_LAV11 = 31 */ +/* raw stats : envelopeLevel_11 KK 00-02-03 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const INT v_Huff_envelopeLevelC11T[63] = { + 0x0003FFED, 0x0003FFEE, 0x0007FFDE, 0x0007FFDF, 0x0007FFE0, 0x0007FFE1, 0x0007FFE2, 0x0007FFE3, + 0x0007FFE4, 0x0007FFE5, 0x0007FFE6, 0x0007FFE7, 0x0007FFE8, 0x0007FFE9, 0x0007FFEA, 0x0007FFEB, + 0x0007FFEC, 0x0001FFF4, 0x0000FFF7, 0x0000FFF9, 0x0000FFF8, 0x00003FFB, 0x00003FFA, 0x00003FF8, + 0x00001FFA, 0x00000FFC, 0x000007FC, 0x000000FE, 0x0000003E, 0x0000000E, 0x00000002, 0x00000000, + 0x00000006, 0x0000001E, 0x0000007E, 0x000001FE, 0x000007FD, 0x00001FFB, 0x00003FF9, 0x00003FFC, + 0x00007FFA, 0x0000FFF6, 0x0001FFF5, 0x0003FFEC, 0x0007FFED, 0x0007FFEE, 0x0007FFEF, 0x0007FFF0, + 0x0007FFF1, 0x0007FFF2, 0x0007FFF3, 0x0007FFF4, 0x0007FFF5, 0x0007FFF6, 0x0007FFF7, 0x0007FFF8, + 0x0007FFF9, 0x0007FFFA, 0x0007FFFB, 0x0007FFFC, 0x0007FFFD, 0x0007FFFE, 0x0007FFFF +}; + + +/* direction: time + contents : codeword lengths + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const UCHAR v_Huff_envelopeLevelL11T[63] = { + 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x11, 0x10, 0x10, 0x10, 0x0E, 0x0E, 0x0E, 0x0D, 0x0C, 0x0B, 0x08, 0x06, 0x04, 0x02, 0x01, + 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0E, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13 +}; + + +/* direction: freq + contents : codewords + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const INT v_Huff_envelopeLevelC11F[63] = { + 0x000FFFF0, 0x000FFFF1, 0x000FFFF2, 0x000FFFF3, 0x000FFFF4, 0x000FFFF5, 0x000FFFF6, 0x0003FFF3, + 0x0007FFF5, 0x0007FFEE, 0x0007FFEF, 0x0007FFF6, 0x0003FFF4, 0x0003FFF2, 0x000FFFF7, 0x0007FFF0, + 0x0001FFF5, 0x0003FFF0, 0x0001FFF4, 0x0000FFF7, 0x0000FFF6, 0x00007FF8, 0x00003FFB, 0x00000FFD, + 0x000007FD, 0x000003FD, 0x000001FD, 0x000000FD, 0x0000003E, 0x0000000E, 0x00000002, 0x00000000, + 0x00000006, 0x0000001E, 0x000000FC, 0x000001FC, 0x000003FC, 0x000007FC, 0x00000FFC, 0x00001FFC, + 0x00003FFA, 0x00007FF9, 0x00007FFA, 0x0000FFF8, 0x0000FFF9, 0x0001FFF6, 0x0001FFF7, 0x0003FFF5, + 0x0003FFF6, 0x0003FFF1, 0x000FFFF8, 0x0007FFF1, 0x0007FFF2, 0x0007FFF3, 0x000FFFF9, 0x0007FFF7, + 0x0007FFF4, 0x000FFFFA, 0x000FFFFB, 0x000FFFFC, 0x000FFFFD, 0x000FFFFE, 0x000FFFFF +}; + + +/* direction: freq + contents : codeword lengths + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const UCHAR v_Huff_envelopeLevelL11F[63] = { + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x12, 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x14, 0x13, + 0x11, 0x12, 0x11, 0x10, 0x10, 0x0F, 0x0E, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01, + 0x03, 0x05, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x0F, 0x10, 0x10, 0x11, 0x11, 0x12, + 0x12, 0x12, 0x14, 0x13, 0x13, 0x13, 0x14, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14 +}; + + + +/*******************************************************************************/ +/* table : envelope balance, 3.0 dB */ +/* theor range : [-24,24], CODE_BOOK_SCF_LAV = 24 */ +/* implem range: same but mapped to [-12,12], CODE_BOOK_SCF_LAV_BALANCE11 = 12 */ +/* raw stats : envelopeBalance_11 KK 00-02-03 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode3C.m/envelopeBalance_11T.mat/v_nBhex + built by : FH 01-05-15 */ + +const INT bookSbrEnvBalanceC11T[25] = +{ + 0x00001FF2, 0x00001FF3, 0x00001FF4, 0x00001FF5, 0x00001FF6, 0x00001FF7, 0x00001FF8, 0x00000FF8, + 0x000000FE, 0x0000007E, 0x0000000E, 0x00000006, 0x00000000, 0x00000002, 0x0000001E, 0x0000003E, + 0x000001FE, 0x00001FF9, 0x00001FFA, 0x00001FFB, 0x00001FFC, 0x00001FFD, 0x00001FFE, 0x00003FFE, + 0x00003FFF +}; + + +/* direction: time + contents : codeword lengths + raw table: HuffCode3C.m/envelopeBalance_11T.mat/v_nLhex + built by : FH 01-05-15 */ + +const UCHAR bookSbrEnvBalanceL11T[25] = +{ + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x08, 0x07, 0x04, 0x03, 0x01, 0x02, 0x05, 0x06, + 0x09, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E +}; + + +/* direction: freq + contents : codewords + raw table: HuffCode3C.m/envelopeBalance_11F.mat/v_nBhex + built by : FH 01-05-15 */ + +const INT bookSbrEnvBalanceC11F[25] = +{ + 0x00001FF7, 0x00001FF8, 0x00001FF9, 0x00001FFA, 0x00001FFB, 0x00003FF8, 0x00003FF9, 0x000007FC, + 0x000000FE, 0x0000007E, 0x0000000E, 0x00000002, 0x00000000, 0x00000006, 0x0000001E, 0x0000003E, + 0x000001FE, 0x00000FFA, 0x00001FF6, 0x00003FFA, 0x00003FFB, 0x00003FFC, 0x00003FFD, 0x00003FFE, + 0x00003FFF +}; + + +/* direction: freq + contents : codeword lengths + raw table: HuffCode3C.m/envelopeBalance_11F.mat/v_nLhex + built by : FH 01-05-15 */ + +const UCHAR bookSbrEnvBalanceL11F[25] = +{ + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0B, 0x08, 0x07, 0x04, 0x02, 0x01, 0x03, 0x05, 0x06, + 0x09, 0x0C, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E +}; + + +/*******************************************************************************/ +/* table : noise level, 3.0 dB */ +/* theor range : [-29,29], CODE_BOOK_SCF_LAV = 29 */ +/* implem range: [-31,31], CODE_BOOK_SCF_LAV11 = 31 */ +/* raw stats : noiseLevel_11 KK 00-02-03 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const INT v_Huff_NoiseLevelC11T[63] = { + 0x00001FCE, 0x00001FCF, 0x00001FD0, 0x00001FD1, 0x00001FD2, 0x00001FD3, 0x00001FD4, 0x00001FD5, + 0x00001FD6, 0x00001FD7, 0x00001FD8, 0x00001FD9, 0x00001FDA, 0x00001FDB, 0x00001FDC, 0x00001FDD, + 0x00001FDE, 0x00001FDF, 0x00001FE0, 0x00001FE1, 0x00001FE2, 0x00001FE3, 0x00001FE4, 0x00001FE5, + 0x00001FE6, 0x00001FE7, 0x000007F2, 0x000000FD, 0x0000003E, 0x0000000E, 0x00000006, 0x00000000, + 0x00000002, 0x0000001E, 0x000000FC, 0x000003F8, 0x00001FCC, 0x00001FE8, 0x00001FE9, 0x00001FEA, + 0x00001FEB, 0x00001FEC, 0x00001FCD, 0x00001FED, 0x00001FEE, 0x00001FEF, 0x00001FF0, 0x00001FF1, + 0x00001FF2, 0x00001FF3, 0x00001FF4, 0x00001FF5, 0x00001FF6, 0x00001FF7, 0x00001FF8, 0x00001FF9, + 0x00001FFA, 0x00001FFB, 0x00001FFC, 0x00001FFD, 0x00001FFE, 0x00003FFE, 0x00003FFF +}; + + +/* direction: time + contents : codeword lengths + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const UCHAR v_Huff_NoiseLevelL11T[63] = { + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000B, 0x00000008, 0x00000006, 0x00000004, 0x00000003, 0x00000001, + 0x00000002, 0x00000005, 0x00000008, 0x0000000A, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000E, 0x0000000E +}; + + +/*******************************************************************************/ +/* table : noise balance, 3.0 dB */ +/* theor range : [-24,24], CODE_BOOK_SCF_LAV = 24 */ +/* implem range: same but mapped to [-12,12], CODE_BOOK_SCF_LAV_BALANCE11 = 12 */ +/* raw stats : noiseBalance_11 KK 00-02-03 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode3C.m/noiseBalance_11.mat/v_nBhex + built by : FH 01-05-15 */ + +const INT bookSbrNoiseBalanceC11T[25] = +{ + 0x000000EC, 0x000000ED, 0x000000EE, 0x000000EF, 0x000000F0, 0x000000F1, 0x000000F2, 0x000000F3, + 0x000000F4, 0x000000F5, 0x0000001C, 0x00000002, 0x00000000, 0x00000006, 0x0000003A, 0x000000F6, + 0x000000F7, 0x000000F8, 0x000000F9, 0x000000FA, 0x000000FB, 0x000000FC, 0x000000FD, 0x000000FE, + 0x000000FF +}; + + +/* direction: time + contents : codeword lengths + raw table: HuffCode3C.m/noiseBalance_11.mat/v_nLhex + built by : FH 01-05-15 */ + +const UCHAR bookSbrNoiseBalanceL11T[25] = +{ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x05, 0x02, 0x01, 0x03, 0x06, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 +}; + +/* + tuningTable +*/ +const sbrTuningTable_t sbrTuningTable[SBRENC_TUNING_SIZE] = +{ + + /*** AAC ***/ + /* sf,sfsp,sf,sfsp,nnb,nfo,saml,SM,FS*/ + + /*** mono ***/ + + /* 8/16 kHz dual rate */ + { 8000, 10000, 8000, 1, 7, 6, 11,10, 1, 0, 6, SBR_MONO, 3 }, + { 10000, 12000, 8000, 1, 11, 7, 13,12, 1, 0, 6, SBR_MONO, 3 }, + { 12000, 16001, 8000, 1, 14,10, 13,13, 1, 0, 6, SBR_MONO, 3 }, + { 16000, 24000, 8000, 1, 14,10, 14,14, 2, 0, 3, SBR_MONO, 2 }, /* placebo */ + { 24000, 32000, 8000, 1, 14,10, 14,14, 2, 0, 3, SBR_MONO, 2 }, /* placebo */ + { 32000, 48001, 8000, 1, 14,11, 15,15, 2, 0, 3, SBR_MONO, 2 }, /* placebo */ /* bitrates higher than 48000 not supported by AAC core */ + + /* 11/22 kHz dual rate */ + { 8000, 10000, 11025, 1, 5, 4, 6, 6, 1, 0, 6, SBR_MONO, 3 }, + { 10000, 12000, 11025, 1, 8, 5, 12, 9, 1, 0, 6, SBR_MONO, 3 }, + { 12000, 16000, 11025, 1, 12, 8, 13, 8, 1, 0, 6, SBR_MONO, 3 }, + { 16000, 20000, 11025, 1, 12, 8, 13, 8, 1, 0, 6, SBR_MONO, 3 }, /* at such "high" bitrates it's better to upsample the input */ + { 20000, 24001, 11025, 1, 13, 9, 13, 8, 1, 0, 6, SBR_MONO, 3 }, /* signal by a factor of 2 before sending it into the encoder */ + { 24000, 32000, 11025, 1, 14,10, 14, 9, 2, 0, 3, SBR_MONO, 2 }, /* placebo */ + { 32000, 48000, 11025, 1, 15,11, 15,10, 2, 0, 3, SBR_MONO, 2 }, /* placebo */ + { 48000, 64001, 11025, 1, 15,11, 15,10, 2, 0, 3, SBR_MONO, 1 }, /* placebo */ + + /* 12/24 kHz dual rate */ + { 8000, 10000, 12000, 1, 4, 3, 6, 6, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 8 kbit/s */ + { 10000, 12000, 12000, 1, 7, 4, 11, 8, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 10 kbit/s */ + { 12000, 16000, 12000, 1, 11, 7, 12, 8, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 12 kbit/s */ + { 16000, 20000, 12000, 1, 11, 7, 12, 8, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ /* at such "high" bitrates it's better to upsample the input */ + { 20000, 24001, 12000, 1, 12, 8, 12, 8, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 20 kbit/s */ /* signal by a factor of 2 before sending it into the encoder */ + { 24000, 32000, 12000, 1, 13, 9, 13, 9, 2, 0, 3, SBR_MONO, 2 }, /* placebo */ + { 32000, 48000, 12000, 1, 14,10, 14,10, 2, 0, 3, SBR_MONO, 2 }, /* placebo */ + { 48000, 64001, 12000, 1, 15,11, 15,11, 2, 0, 3, SBR_MONO, 1 }, /* placebo */ + + /* 16/32 kHz dual rate */ + { 8000, 10000, 16000, 1, 1, 1, 0, 0, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 8 kbit/s */ + { 10000, 12000, 16000, 1, 2, 1, 6, 0, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 10 kbit/s */ + { 12000, 16000, 16000, 1, 4, 2, 6, 0, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 12 kbit/s */ + { 16000, 18000, 16000, 1, 4, 2, 8, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ + { 18000, 22000, 16000, 1, 6, 5,11, 7, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 20 kbit/s */ + { 22000, 28000, 16000, 1, 10, 9,12, 8, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 16000, 1, 12,12,13,13, 2, 0, 3, SBR_MONO, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 16000, 1, 14,14,13,13, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 40 kbit/s */ + { 44000, 64001, 16000, 1, 15,15,13,13, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 48 kbit/s */ + + /* 22.05/44.1 kHz dual rate */ + /* { 8000, 11369, 22050, 1, 1, 1, 1, 1, 1, 0, 6, SBR_MONO, 3 }, */ /* nominal: 8 kbit/s */ /* encoder can not work stable at this extremely low bitrate */ + { 11369, 16000, 22050, 1, 3, 1, 4, 4, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 12 kbit/s */ + { 16000, 18000, 22050, 1, 3, 1, 5, 4, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ + { 18000, 22000, 22050, 1, 4, 4, 8, 5, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 20 kbit/s */ + { 22000, 28000, 22050, 1, 7, 6, 8, 6, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 22050, 1, 10,10, 9, 9, 2, 0, 3, SBR_MONO, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 22050, 1, 11,11,10,10, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 40 kbit/s */ + { 44000, 64001, 22050, 1, 13,13,12,12, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 48 kbit/s */ + + /* 24/48 kHz dual rate */ + /* { 8000, 12000, 24000, 1, 1, 1, 1, 1, 1, 0, 6, SBR_MONO, 3 }, */ /* nominal: 8 kbit/s */ /* encoder can not work stable at this extremely low bitrate */ + { 12000, 16000, 24000, 1, 3, 1, 4, 4, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 12 kbit/s */ + { 16000, 18000, 24000, 1, 3, 1, 5, 4, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ + { 18000, 22000, 24000, 1, 4, 3, 8, 5, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 20 kbit/s */ + { 22000, 28000, 24000, 1, 7, 6, 8, 6, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 24000, 1, 10,10, 9, 9, 2, 0, 3, SBR_MONO, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 24000, 1, 11,11,10,10, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 40 kbit/s */ + { 44000, 64001, 24000, 1, 13,13,11,11, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 48 kbit/s */ + + /* 32/64 kHz dual rate */ /* placebo settings */ + { 24000, 36000, 32000, 1, 4, 4, 4, 4, 2, 0, 3, SBR_MONO, 3 }, /* lowest range */ + { 36000, 60000, 32000, 1, 7, 7, 6, 6, 2, 0, 3, SBR_MONO, 2 }, /* lowest range */ + { 60000, 72000, 32000, 1, 9, 9, 8, 8, 2, 0, 3, SBR_MONO, 1 }, /* low range */ + { 72000,100000, 32000, 1, 11,11,10,10, 2, 0, 3, SBR_MONO, 1 }, /* SBR sweet spot */ + { 100000,160001, 32000, 1, 13,13,11,11, 2, 0, 3, SBR_MONO, 1 }, /* backwards compatible */ + + /* 44.1/88.2 kHz dual rate */ /* placebo settings */ + { 24000, 36000, 44100, 1, 4, 4, 4, 4, 2, 0, 3, SBR_MONO, 3 }, /* lowest range (multichannel rear) */ + { 36000, 60000, 44100, 1, 7, 7, 6, 6, 2, 0, 3, SBR_MONO, 2 }, /* lowest range (multichannel rear) */ + { 60000, 72000, 44100, 1, 9, 9, 8, 8, 2, 0, 3, SBR_MONO, 1 }, /* low range */ + { 72000,100000, 44100, 1, 11,11,10,10, 2, 0, 3, SBR_MONO, 1 }, /* SBR sweet spot */ + { 100000,160001, 44100, 1, 13,13,11,11, 2, 0, 3, SBR_MONO, 1 }, /* backwards compatible */ + + /* 48/96 kHz dual rate */ /* not yet finally tuned */ + { 24000, 36000, 48000, 1, 4, 4, 9, 9, 2, 0, 3, SBR_MONO, 3 }, /* lowest range (multichannel rear) */ + { 36000, 60000, 48000, 1, 7, 7,10,10, 2, 0, 3, SBR_MONO, 2 }, /* nominal: 40 */ + { 60000, 72000, 48000, 1, 9, 9,10,10, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 64 */ + { 72000,100000, 48000, 1, 11,11,11,11, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 80 */ + { 100000,160001, 48000, 1, 13,13,11,11, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 128 */ + + /*** stereo ***/ + /* 08/16 kHz dual rate */ + { 16000, 24000, 8000, 2, 6, 6, 9, 7, 1, 0,-3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ /* placebo */ + { 24000, 28000, 8000, 2, 9, 9, 11, 9, 1, 0,-3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 8000, 2, 11, 9, 11, 9, 2, 0,-3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 8000, 2, 13,11, 13,11, 2, 0,-3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 8000, 2, 14,12, 13,12, 2, 0,-3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 8000, 2, 15,15, 13,13, 3, 0,-3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 8000, 2, 15,15, 13,13, 3, 0,-3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000,128001, 8000, 2, 15,15, 13,13, 3, 0,-3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + + /* 11/22 kHz dual rate */ + { 16000, 24000, 11025, 2, 7, 5, 9, 7, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ /* placebo */ + { 24000, 28000, 11025, 2, 10, 8,10, 8, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 11025, 2, 12, 8,12, 8, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 11025, 2, 13, 9,13, 9, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 11025, 2, 14,11,13,11, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 11025, 2, 15,15,13,13, 3, 0, -3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 11025, 2, 15,15,13,13, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000,128001, 11025, 2, 15,15,13,13, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + + /* 12/24 kHz dual rate */ + { 16000, 24000, 12000, 2, 6, 4, 9, 7, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ /* placebo */ + { 24000, 28000, 12000, 2, 9, 7,10, 8, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 12000, 2, 11, 7,12, 8, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 12000, 2, 12, 9,12, 9, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 12000, 2, 13,12,13,12, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 12000, 2, 14,14,13,13, 3, 0, -3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 12000, 2, 15,15,13,13, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000,128001, 12000, 2, 15,15,13,13, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + + /* 16/32 kHz dual rate */ + { 16000, 24000, 16000, 2, 4, 2, 1, 0, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ + { 24000, 28000, 16000, 2, 8, 7,10, 8, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 16000, 2, 10, 9,12,11, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 16000, 2, 13,13,13,13, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 16000, 2, 15,15,13,13, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 16000, 2, 15,15,13,13, 3, 0, -3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 16000, 2, 15,15,13,13, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000,128001, 16000, 2, 15,15,13,13, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + + /* 22.05/44.1 kHz dual rate */ + { 16000, 24000, 22050, 2, 2, 1, 1, 0, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ + { 24000, 28000, 22050, 2, 5, 4, 6, 5, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 32000, 22050, 2, 5, 4, 8, 7, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 28 kbit/s */ + { 32000, 36000, 22050, 2, 7, 6, 8, 7, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 22050, 2, 10,10, 9, 9, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 22050, 2, 12,12, 9, 9, 3, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 22050, 2, 13,13,10,10, 3, 0, -3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 22050, 2, 14,14,12,12, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000,128001, 22050, 2, 14,14,12,12, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + + /* 24/48 kHz dual rate */ + { 16000, 24000, 24000, 2, 2, 1, 1, 0, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ + { 24000, 28000, 24000, 2, 5, 5, 6, 6, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 24000, 2, 7, 6, 8, 7, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 24000, 2, 10,10, 9, 9, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 24000, 2, 12,12, 9, 9, 3, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 24000, 2, 13,13,10,10, 3, 0, -3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 24000, 2, 14,14,12,12, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000,128001, 24000, 2, 15,15,12,12, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + + /* 32/64 kHz dual rate */ /* placebo settings */ + { 32000, 60000, 32000, 2, 4, 4, 4, 4, 2, 0, -3, SBR_SWITCH_LRC, 3 }, /* lowest range (multichannel rear) */ + { 60000, 80000, 32000, 2, 7, 7, 6, 6, 3, 0, -3, SBR_SWITCH_LRC, 2 }, /* lowest range (multichannel rear) */ + { 80000,112000, 32000, 2, 9, 9, 8, 8, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* low range */ + { 112000,144000, 32000, 2, 11,11,10,10, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* SBR sweet spot */ + { 144000,256001, 32000, 2, 13,13,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* backwards compatible */ + + /* 44.1/88.2 kHz dual rate */ /* placebo settings */ + { 32000, 60000, 44100, 2, 4, 4, 4, 4, 2, 0, -3, SBR_SWITCH_LRC, 3 }, /* lowest range (multichannel rear) */ + { 60000, 80000, 44100, 2, 7, 7, 6, 6, 3, 0, -3, SBR_SWITCH_LRC, 2 }, /* lowest range (multichannel rear) */ + { 80000,112000, 44100, 2, 9, 9, 8, 8, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* low range */ + { 112000,144000, 44100, 2, 11,11,10,10, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* SBR sweet spot */ + { 144000,256001, 44100, 2, 13,13,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* backwards compatible */ + + /* 48/96 kHz dual rate */ /* not yet finally tuned */ + { 32000, 60000, 48000, 2, 4, 4, 9, 9, 2, 0, -3, SBR_SWITCH_LRC, 3 }, /* lowest range (multichannel rear) */ + { 60000, 80000, 48000, 2, 7, 7, 9, 9, 3, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 64 */ + { 80000,112000, 48000, 2, 9, 9,10,10, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 96 */ + { 112000,144000, 48000, 2, 11,11,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 128 */ + { 144000,256001, 48000, 2, 13,13,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 192 */ + + /** AAC LOW DELAY SECTION **/ + + /* 22.05/44.1 kHz dual rate */ + { 8000, 11369, 22050, 1, 1, 1, 1, 1, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 8 kbit/s */ /**changed (not changed !!)*/ + { 11369, 16000, 22050, 1, 1, 0, 3, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 12 kbit/s */ + { 16000, 18000, 22050, 1, 1, 0, 4, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ + { 18000, 22000, 22050, 1, 1, 2, 5, 4, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 20 kbit/s */ + { 22000, 28000, 22050, 1, 4, 4, 6, 5, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 22050, 1, 7, 8, 8, 8, 2, 0, 3, SBR_MONO, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 22050, 1, 9, 9, 9, 9, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 22050, 1, 11,11,11,11, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 48 kbit/s */ + { 52000, 64001, 22050, 1, 12,11,11,11, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 56 kbit/s */ + + /* 24/48 kHz dual rate */ + { 8000, 12000, 24000, 1, 1, 1, 1, 1, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 8 kbit/s */ /**changed (not changed !!)*/ + { 12000, 16000, 24000, 1, 1, 0, 3, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 12 kbit/s */ + { 16000, 18000, 24000, 1, 1, 0, 4, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ + { 18000, 22000, 24000, 1, 1, 1, 4, 4, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 20 kbit/s */ + { 22000, 28000, 24000, 1, 4, 4, 6, 5, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 24000, 1, 6, 8, 8, 8, 2, 0, 3, SBR_MONO, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 24000, 1, 8, 9, 9, 9, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 24000, 1, 12,11,11,10, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 48 kbit/s */ + { 52000, 64001, 24000, 1, 13,11,11,10, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 48 kbit/s */ + + /* 22.05/44.1 kHz dual rate */ + { 16000, 24000, 22050, 2, 0, 0, 0, 0, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ + { 24000, 28000, 22050, 2, 3, 2, 5, 4, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 32000, 22050, 2, 3, 2, 7, 6, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 28 kbit/s */ + { 32000, 36000, 22050, 2, 5, 4, 7, 6, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 22050, 2, 5, 8, 8, 8, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 22050, 2, 7,10, 8, 8, 3, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 22050, 2, 9,11, 9, 9, 3, 0, -3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 22050, 2, 10,12,10,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000, 82000, 22050, 2, 12,12,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + { 82000,128001, 22050, 2, 13,12,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + + /* 24/48 kHz dual rate */ + { 16000, 24000, 24000, 2, 0, 0, 0, 0, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ + { 24000, 28000, 24000, 2, 3, 3, 5, 5, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 24000, 2, 5, 4, 7, 6, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 24000, 2, 4, 8, 8, 8, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 24000, 2, 6,10, 8, 8, 3, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 24000, 2, 9,11, 9, 9, 3, 0, -3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 24000, 2, 11,12,10,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000, 88000, 24000, 2, 12,13,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + { 88000,128001, 24000, 2, 13,13,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 92 kbit/s */ +}; + +const psTuningTable_t psTuningTable[4] = +{ + { 8000, 22000, PSENC_STEREO_BANDS_10, PSENC_NENV_1, FL2FXCONST_DBL(3.0f/4.0f) }, + { 22000, 28000, PSENC_STEREO_BANDS_20, PSENC_NENV_1, FL2FXCONST_DBL(2.0f/4.0f) }, + { 28000, 36000, PSENC_STEREO_BANDS_20, PSENC_NENV_2, FL2FXCONST_DBL(1.5f/4.0f) }, + { 36000, 160001, PSENC_STEREO_BANDS_20, PSENC_NENV_4, FL2FXCONST_DBL(1.1f/4.0f) }, +}; + + +//@} + + + diff --git a/libSBRenc/src/sbr_rom.h b/libSBRenc/src/sbr_rom.h new file mode 100644 index 0000000..696a54c --- /dev/null +++ b/libSBRenc/src/sbr_rom.h @@ -0,0 +1,70 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! +\file +\brief Declaration of constant tables +$Revision: 36847 $ +*/ +#ifndef __SBR_ROM_H +#define __SBR_ROM_H + +#include "sbr_def.h" +#include "sbr_encoder.h" + +#include "ps_main.h" + +/* + huffman tables +*/ +extern const INT v_Huff_envelopeLevelC10T[121]; +extern const UCHAR v_Huff_envelopeLevelL10T[121]; +extern const INT v_Huff_envelopeLevelC10F[121]; +extern const UCHAR v_Huff_envelopeLevelL10F[121]; +extern const INT bookSbrEnvBalanceC10T[49]; +extern const UCHAR bookSbrEnvBalanceL10T[49]; +extern const INT bookSbrEnvBalanceC10F[49]; +extern const UCHAR bookSbrEnvBalanceL10F[49]; +extern const INT v_Huff_envelopeLevelC11T[63]; +extern const UCHAR v_Huff_envelopeLevelL11T[63]; +extern const INT v_Huff_envelopeLevelC11F[63]; +extern const UCHAR v_Huff_envelopeLevelL11F[63]; +extern const INT bookSbrEnvBalanceC11T[25]; +extern const UCHAR bookSbrEnvBalanceL11T[25]; +extern const INT bookSbrEnvBalanceC11F[25]; +extern const UCHAR bookSbrEnvBalanceL11F[25]; +extern const INT v_Huff_NoiseLevelC11T[63]; +extern const UCHAR v_Huff_NoiseLevelL11T[63]; +extern const INT bookSbrNoiseBalanceC11T[25]; +extern const UCHAR bookSbrNoiseBalanceL11T[25]; + +#define SBRENC_TUNING_SIZE (126 + 37) + +extern const sbrTuningTable_t sbrTuningTable[SBRENC_TUNING_SIZE]; + +extern const psTuningTable_t psTuningTable[4]; + + +#endif diff --git a/libSBRenc/src/sbrenc_freq_sca.cpp b/libSBRenc/src/sbrenc_freq_sca.cpp new file mode 100644 index 0000000..ce492c9 --- /dev/null +++ b/libSBRenc/src/sbrenc_freq_sca.cpp @@ -0,0 +1,613 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief frequency scale $Revision: 36847 $ +*/ + +#include "sbrenc_freq_sca.h" +#include "sbr_misc.h" + +#include "genericStds.h" + +/* StartFreq */ +static INT getStartFreq(INT fs, const INT start_freq); + +/* StopFreq */ +static INT getStopFreq(INT fs, const INT stop_freq, const INT noChannels); + +static INT numberOfBands(INT b_p_o, INT start, INT stop, FIXP_DBL warp_factor); +static void CalcBands(INT * diff, INT start , INT stop , INT num_bands); +static INT modifyBands(INT max_band, INT * diff, INT length); +static void cumSum(INT start_value, INT* diff, INT length, UCHAR *start_adress); + + + +/******************************************************************************* + Functionname: FDKsbrEnc_getSbrStartFreqRAW + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ + +INT +FDKsbrEnc_getSbrStartFreqRAW (INT startFreq, INT QMFbands, INT fs) +{ + INT result; + + if ( startFreq < 0 || startFreq > 15) { + return -1; + } + /* Update startFreq struct */ + result = getStartFreq(fs, startFreq); + + result = (result*fs/QMFbands+1)>>1; + + return (result); + +} /* End FDKsbrEnc_getSbrStartFreqRAW */ + + +/******************************************************************************* + Functionname: getSbrStopFreq + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +INT FDKsbrEnc_getSbrStopFreqRAW (INT stopFreq, INT QMFbands, INT fs) +{ + INT result; + + if ( stopFreq < 0 || stopFreq > 13) + return -1; + + + /* Uppdate stopFreq struct */ + result = getStopFreq( fs, stopFreq, QMFbands); + result = (result*fs/QMFbands+1)>>1; + + return (result); +} /* End getSbrStopFreq */ + + +/******************************************************************************* + Functionname: getStartFreq + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +static INT +getStartFreq(INT fs, const INT start_freq) +{ + INT k0_min; + + switch(fs){ + case 16000: k0_min = 24; + break; + case 22050: k0_min = 17; + break; + case 24000: k0_min = 16; + break; + case 32000: k0_min = 16; + break; + case 44100: k0_min = 12; + break; + case 48000: k0_min = 11; + break; + case 64000: k0_min = 10; + break; + case 88200: k0_min = 7; + break; + case 96000: k0_min = 7; + break; + default: + k0_min=11; /* illegal fs */ + } + + + switch (fs) { + + case 16000: + { + INT v_offset[]= {-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7}; + return (k0_min + v_offset[start_freq]); + } + case 22050: + { + INT v_offset[]= {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13}; + return (k0_min + v_offset[start_freq]); + } + case 24000: + { + INT v_offset[]= {-5, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16}; + return (k0_min + v_offset[start_freq]); + } + case 32000: + { + INT v_offset[]= {-6, -4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16}; + return (k0_min + v_offset[start_freq]); + } + case 44100: + case 48000: + case 64000: + { + INT v_offset[]= {-4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20}; + return (k0_min + v_offset[start_freq]); + } + case 88200: + case 96000: + { + INT v_offset[]= {-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24}; + return (k0_min + v_offset[start_freq]); + } + default: + { + INT v_offset[]= {0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24, 28, 33}; + return (k0_min + v_offset[start_freq]); + } + } +} /* End getStartFreq */ + + +/******************************************************************************* + Functionname: getStopFreq + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ + static INT +getStopFreq(INT fs, const INT stop_freq, const INT noChannels) +{ + INT result,i; + INT k1_min; + INT v_dstop[13]; + + + INT *v_stop_freq = NULL; + INT v_stop_freq_16[14] = {48,49,50,51,52,54,55,56,57,59,60,61,63,64}; + INT v_stop_freq_22[14] = {35,37,38,40,42,44,46,48,51,53,56,58,61,64}; + INT v_stop_freq_24[14] = {32,34,36,38,40,42,44,46,49,52,55,58,61,64}; + INT v_stop_freq_32[14] = {32,34,36,38,40,42,44,46,49,52,55,58,61,64}; + INT v_stop_freq_44[14] = {23,25,27,29,32,34,37,40,43,47,51,55,59,64}; + INT v_stop_freq_48[14] = {21,23,25,27,30,32,35,38,42,45,49,54,59,64}; + INT v_stop_freq_64[14] = {20,22,24,26,29,31,34,37,41,45,49,54,59,64}; + INT v_stop_freq_88[14] = {15,17,19,21,23,26,29,33,37,41,46,51,57,64}; + INT v_stop_freq_96[14] = {13,15,17,19,21,24,27,31,35,39,44,50,57,64}; + + switch(fs){ + case 16000: k1_min = 48; + v_stop_freq =v_stop_freq_16; + break; + case 22050: k1_min = 35; + v_stop_freq =v_stop_freq_22; + break; + case 24000: k1_min = 32; + v_stop_freq =v_stop_freq_24; + break; + case 32000: k1_min = 32; + v_stop_freq =v_stop_freq_32; + break; + case 44100: k1_min = 23; + v_stop_freq =v_stop_freq_44; + break; + case 48000: k1_min = 21; + v_stop_freq =v_stop_freq_48; + break; + case 64000: k1_min = 20; + v_stop_freq =v_stop_freq_64; + break; + case 88200: k1_min = 15; + v_stop_freq =v_stop_freq_88; + break; + case 96000: k1_min = 13; + v_stop_freq =v_stop_freq_96; + break; + default: + k1_min = 21; /* illegal fs */ + } + + + /* Ensure increasing bandwidth */ + for(i = 0; i <= 12; i++) { + v_dstop[i] = v_stop_freq[i+1] - v_stop_freq[i]; + } + + FDKsbrEnc_Shellsort_int(v_dstop, 13); /* Sort bandwidth changes */ + + result = k1_min; + for(i = 0; i < stop_freq; i++) { + result = result + v_dstop[i]; + } + + return(result); + +}/* End getStopFreq */ + + +/******************************************************************************* + Functionname: FDKsbrEnc_FindStartAndStopBand + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +INT +FDKsbrEnc_FindStartAndStopBand(const INT samplingFreq, + const INT noChannels, + const INT startFreq, + const INT stopFreq, + const SR_MODE sampleRateMode, + INT *k0, + INT *k2) +{ + + /* Update startFreq struct */ + *k0 = getStartFreq(samplingFreq, startFreq); + + /* Test if start freq is outside corecoder range */ + if( ( sampleRateMode == 1 ) && + ( samplingFreq*noChannels < + 2**k0 * samplingFreq) ) { + return (1); /* raise the cross-over frequency and/or lower the number + of target bands per octave (or lower the sampling frequency) */ + } + + /*Update stopFreq struct */ + if ( stopFreq < 14 ) { + *k2 = getStopFreq(samplingFreq, stopFreq, noChannels); + } else if( stopFreq == 14 ) { + *k2 = 2 * *k0; + } else { + *k2 = 3 * *k0; + } + + /* limit to Nyqvist */ + if (*k2 > noChannels) { + *k2 = noChannels; + } + + + + /* Test for invalid k0 k2 combinations */ + if ( (samplingFreq == 44100) && ( (*k2 - *k0) > MAX_FREQ_COEFFS_FS44100 ) ) + return (1); /* Number of bands exceeds valid range of MAX_FREQ_COEFFS for fs=44.1kHz */ + + if ( (samplingFreq >= 48000) && ( (*k2 - *k0) > MAX_FREQ_COEFFS_FS48000 ) ) + return (1); /* Number of bands exceeds valid range of MAX_FREQ_COEFFS for fs>=48kHz */ + + if ((*k2 - *k0) > MAX_FREQ_COEFFS) + return (1);/*Number of bands exceeds valid range of MAX_FREQ_COEFFS */ + + if ((*k2 - *k0) < 0) + return (1);/* Number of bands is negative */ + + + return(0); +} + +/******************************************************************************* + Functionname: FDKsbrEnc_UpdateFreqScale + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +INT +FDKsbrEnc_UpdateFreqScale(UCHAR *v_k_master, INT *h_num_bands, + const INT k0, const INT k2, + const INT freqScale, + const INT alterScale) + +{ + + INT b_p_o = 0; /* bands_per_octave */ + FIXP_DBL warp = FL2FXCONST_DBL(0.0f); + INT dk = 0; + + /* Internal variables */ + INT k1 = 0, i; + INT num_bands0; + INT num_bands1; + INT diff_tot[MAX_OCTAVE + MAX_SECOND_REGION]; + INT *diff0 = diff_tot; + INT *diff1 = diff_tot+MAX_OCTAVE; + INT k2_achived; + INT k2_diff; + INT incr = 0; + + /* Init */ + if (freqScale==1) b_p_o = 12; + if (freqScale==2) b_p_o = 10; + if (freqScale==3) b_p_o = 8; + + + if(freqScale > 0) /*Bark*/ + { + if(alterScale==0) + warp = FL2FXCONST_DBL(0.5f); /* 1.0/(1.0*2.0) */ + else + warp = FL2FXCONST_DBL(1.0f/2.6f); /* 1.0/(1.3*2.0); */ + + + if(4*k2 >= 9*k0) /*two or more regions*/ + { + k1=2*k0; + + num_bands0=numberOfBands(b_p_o, k0, k1, FL2FXCONST_DBL(0.5f)); + num_bands1=numberOfBands(b_p_o, k1, k2, warp); + + CalcBands(diff0, k0, k1, num_bands0);/*CalcBands1 => diff0 */ + FDKsbrEnc_Shellsort_int( diff0, num_bands0);/*SortBands sort diff0 */ + + if (diff0[0] == 0) /* too wide FB bands for target tuning */ + { + return (1);/* raise the cross-over frequency and/or lower the number + of target bands per octave (or lower the sampling frequency */ + } + + cumSum(k0, diff0, num_bands0, v_k_master); /* cumsum */ + + CalcBands(diff1, k1, k2, num_bands1); /* CalcBands2 => diff1 */ + FDKsbrEnc_Shellsort_int( diff1, num_bands1); /* SortBands sort diff1 */ + if(diff0[num_bands0-1] > diff1[0]) /* max(1) > min(2) */ + { + if(modifyBands(diff0[num_bands0-1],diff1, num_bands1)) + return(1); + } + + /* Add 2'nd region */ + cumSum(k1, diff1, num_bands1, &v_k_master[num_bands0]); + *h_num_bands=num_bands0+num_bands1; /* Output nr of bands */ + + } + else /* one region */ + { + k1=k2; + + num_bands0=numberOfBands(b_p_o, k0, k1, FL2FXCONST_DBL(0.5f)); + CalcBands(diff0, k0, k1, num_bands0);/* CalcBands1 => diff0 */ + FDKsbrEnc_Shellsort_int( diff0, num_bands0); /* SortBands sort diff0 */ + + if (diff0[0] == 0) /* too wide FB bands for target tuning */ + { + return (1); /* raise the cross-over frequency and/or lower the number + of target bands per octave (or lower the sampling frequency */ + } + + cumSum(k0, diff0, num_bands0, v_k_master);/* cumsum */ + *h_num_bands=num_bands0; /* Output nr of bands */ + + } + } + else /* Linear mode */ + { + if (alterScale==0) { + dk = 1; + num_bands0 = 2 * ((k2 - k0)/2); /* FLOOR to get to few number of bands*/ + } else { + dk = 2; + num_bands0 = 2 * (((k2 - k0)/dk +1)/2); /* ROUND to get closest fit */ + } + + k2_achived = k0 + num_bands0*dk; + k2_diff = k2 - k2_achived; + + for(i=0;i 0) { + incr = -1; + i = num_bands0-1; + } + + /* Adjust diff vector to get sepc. SBR range */ + while (k2_diff != 0) { + diff_tot[i] = diff_tot[i] - incr; + i = i + incr; + k2_diff = k2_diff + incr; + } + + cumSum(k0, diff_tot, num_bands0, v_k_master);/* cumsum */ + *h_num_bands=num_bands0; /* Output nr of bands */ + + } + + if (*h_num_bands < 1) + return(1); /*To small sbr area */ + + return (0); +}/* End FDKsbrEnc_UpdateFreqScale */ + +static INT +numberOfBands(INT b_p_o, INT start, INT stop, FIXP_DBL warp_factor) +{ + INT result=0; + /* result = 2* (INT) ( (double)b_p_o * (double)(FDKlog((double)stop/(double)start)/FDKlog((double)2)) * (double)FX_DBL2FL(warp_factor) + 0.5); */ + result = ( ( b_p_o * fMult( (CalcLdInt(stop) - CalcLdInt(start)), warp_factor) + (FL2FX_DBL(0.5f)>>LD_DATA_SHIFT) + ) >> ((DFRACT_BITS-1)-LD_DATA_SHIFT) ) << 1; /* do not optimize anymore (rounding!!) */ + + return(result); +} + + +static void +CalcBands(INT * diff, INT start , INT stop , INT num_bands) +{ + INT i, qb, qe, qtmp; + INT previous; + INT current; + FIXP_DBL base, exp, tmp; + + previous=start; + for(i=1; i<= num_bands; i++) + { + base = fDivNorm((FIXP_DBL)stop, (FIXP_DBL)start, &qb); + exp = fDivNorm((FIXP_DBL)i, (FIXP_DBL)num_bands, &qe); + tmp = fPow(base, qb, exp, qe, &qtmp); + tmp = fMult(tmp, (FIXP_DBL)(start<<24)); + current = (INT)scaleValue(tmp, qtmp-23); + current = (current+1) >> 1; /* rounding*/ + diff[i-1] = current-previous; + previous = current; + } + +}/* End CalcBands */ + + +static void +cumSum(INT start_value, INT* diff, INT length, UCHAR *start_adress) +{ + INT i; + start_adress[0]=start_value; + for(i=1;i<=length;i++) + start_adress[i]=start_adress[i-1]+diff[i-1]; +} /* End cumSum */ + + +static INT +modifyBands(INT max_band_previous, INT * diff, INT length) +{ + INT change=max_band_previous-diff[0]; + + /* Limit the change so that the last band cannot get narrower than the first one */ + if ( change > (diff[length-1] - diff[0]) / 2 ) + change = (diff[length-1] - diff[0]) / 2; + + diff[0] += change; + diff[length-1] -= change; + FDKsbrEnc_Shellsort_int(diff, length); + + return(0); +}/* End modifyBands */ + + +/******************************************************************************* + Functionname: FDKsbrEnc_UpdateHiRes + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +INT +FDKsbrEnc_UpdateHiRes(UCHAR *h_hires, INT *num_hires,UCHAR * v_k_master, + INT num_master , INT *xover_band, SR_MODE drOrSr, + INT noQMFChannels) +{ + INT i; + INT divider; + INT max1,max2; + + /* Check if we use a Dual rate => diver=2 else 1 */ + divider = (drOrSr == DUAL_RATE) ? 2 : 1; + + if( (v_k_master[*xover_band] > (noQMFChannels/divider) ) || + ( *xover_band > num_master ) ) { + /* xover_band error, too big for this startFreq. Will be clipped */ + + /* Calculate maximum value for xover_band */ + max1=0; + max2=num_master; + while( (v_k_master[max1+1] < (noQMFChannels/divider)) && + ( (max1+1) < max2) ) + { + max1++; + } + + *xover_band=max1; + } + + *num_hires = num_master - *xover_band; + for(i = *xover_band; i <= num_master; i++) + { + h_hires[i - *xover_band] = v_k_master[i]; + } + + return (0); +}/* End FDKsbrEnc_UpdateHiRes */ + + +/******************************************************************************* + Functionname: FDKsbrEnc_UpdateLoRes + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +void +FDKsbrEnc_UpdateLoRes(UCHAR * h_lores, INT *num_lores, UCHAR * h_hires, INT num_hires) +{ + INT i; + + if(num_hires%2 == 0) /* if even number of hires bands */ + { + *num_lores=num_hires/2; + /* Use every second lores=hires[0,2,4...] */ + for(i=0;i<=*num_lores;i++) + h_lores[i]=h_hires[i*2]; + + } + else /* odd number of hires which means xover is odd */ + { + *num_lores=(num_hires+1)/2; + + /* Use lores=hires[0,1,3,5 ...] */ + h_lores[0]=h_hires[0]; + for(i=1;i<=*num_lores;i++) + { + h_lores[i]=h_hires[i*2-1]; + } + } + +}/* End FDKsbrEnc_UpdateLoRes */ diff --git a/libSBRenc/src/sbrenc_freq_sca.h b/libSBRenc/src/sbrenc_freq_sca.h new file mode 100644 index 0000000..a4048e9 --- /dev/null +++ b/libSBRenc/src/sbrenc_freq_sca.h @@ -0,0 +1,71 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief frequency scale prototypes $Revision: 36867 $ +*/ +#ifndef __FREQ_SCA2_H +#define __FREQ_SCA2_H + +#include "sbr_encoder.h" +#include "sbr_def.h" + +#define MAX_OCTAVE 29 +#define MAX_SECOND_REGION 50 + + +INT +FDKsbrEnc_UpdateFreqScale(UCHAR *v_k_master, INT *h_num_bands, + const INT k0, const INT k2, + const INT freq_scale, + const INT alter_scale); + +INT +FDKsbrEnc_UpdateHiRes(UCHAR *h_hires, + INT *num_hires, + UCHAR *v_k_master, + INT num_master , + INT *xover_band, + SR_MODE drOrSr, + INT noQMFChannels); + +void FDKsbrEnc_UpdateLoRes(UCHAR * v_lores, + INT *num_lores, + UCHAR * v_hires, + INT num_hires); + +INT +FDKsbrEnc_FindStartAndStopBand(const INT samplingFreq, + const INT noChannels, + const INT startFreq, + const INT stop_freq, + const SR_MODE sampleRateMode, + INT *k0, + INT *k2); + +INT FDKsbrEnc_getSbrStartFreqRAW (INT startFreq, INT QMFbands, INT fs ); +INT FDKsbrEnc_getSbrStopFreqRAW (INT stopFreq, INT QMFbands, INT fs); +#endif diff --git a/libSBRenc/src/ton_corr.cpp b/libSBRenc/src/ton_corr.cpp new file mode 100644 index 0000000..cc4913c --- /dev/null +++ b/libSBRenc/src/ton_corr.cpp @@ -0,0 +1,829 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Header$ + +*******************************************************************************/ + +#include "ton_corr.h" + +#include "sbr_ram.h" +#include "sbr_misc.h" +#include "genericStds.h" +#include "autocorr2nd.h" + + + +/*************************************************************************** + + Send autoCorrSecondOrder to mlfile + +****************************************************************************/ + +/**************************************************************************/ +/*! + \brief Calculates the tonal to noise ration for different frequency bands + and time segments. + + The ratio between the predicted energy (tonal energy A) and the total + energy (A + B) is calculated. This is converted to the ratio between + the predicted energy (tonal energy A) and the non-predictable energy + (noise energy B). Hence the quota-matrix contains A/B = q/(1-q). + + The samples in nrgVector are scaled by 1.0/16.0 + The samples in pNrgVectorFreq are scaled by 1.0/2.0 + The samples in quotaMatrix are scaled by RELAXATION + + \return none. + +*/ +/**************************************************************************/ + +void +FDKsbrEnc_CalculateTonalityQuotas( HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + FIXP_DBL **RESTRICT sourceBufferReal, /*!< The real part of the QMF-matrix. */ + FIXP_DBL **RESTRICT sourceBufferImag, /*!< The imaginary part of the QMF-matrix. */ + INT usb, /*!< upper side band, highest + 1 QMF band in the SBR range. */ + INT qmfScale /*!< sclefactor of QMF subsamples */ + ) +{ + INT i, k, r, r2, timeIndex, autoCorrScaling; + + INT startIndexMatrix = hTonCorr->startIndexMatrix; + INT totNoEst = hTonCorr->numberOfEstimates; + INT noEstPerFrame = hTonCorr->numberOfEstimatesPerFrame; + INT move = hTonCorr->move; + INT noQmfChannels = hTonCorr->noQmfChannels; /* Numer of Bands */ + INT buffLen = hTonCorr->bufferLength; /* Numer of Slots */ + INT stepSize = hTonCorr->stepSize; + INT *pBlockLength = hTonCorr->lpcLength; + INT** RESTRICT signMatrix = hTonCorr->signMatrix; + FIXP_DBL* RESTRICT nrgVector = hTonCorr->nrgVector; + FIXP_DBL** RESTRICT quotaMatrix = hTonCorr->quotaMatrix; + FIXP_DBL* RESTRICT pNrgVectorFreq = hTonCorr->nrgVectorFreq; + +#define BAND_V_SIZE QMF_MAX_TIME_SLOTS +#define NUM_V_COMBINE 8 /* Must be a divisor of 64 and fulfill the ASSERTs below */ + + FIXP_DBL *realBuf; + FIXP_DBL *imagBuf; + + FIXP_DBL alphar[2],alphai[2],fac; + + C_ALLOC_SCRATCH_START(ac, ACORR_COEFS, 1); + C_ALLOC_SCRATCH_START(realBufRef, FIXP_DBL, 2*BAND_V_SIZE*NUM_V_COMBINE); + + realBuf = realBufRef; + imagBuf = realBuf + BAND_V_SIZE*NUM_V_COMBINE; + + + FDK_ASSERT(buffLen <= BAND_V_SIZE); + FDK_ASSERT(sizeof(FIXP_DBL)*NUM_V_COMBINE*BAND_V_SIZE*2 < (1024*sizeof(FIXP_DBL)-sizeof(ACORR_COEFS)) ); + + /* + * Buffering of the quotaMatrix and the quotaMatrixTransp. + *********************************************************/ + for(i = 0 ; i < move; i++){ + FDKmemcpy(quotaMatrix[i],quotaMatrix[i + noEstPerFrame],noQmfChannels * sizeof(FIXP_DBL)); + FDKmemcpy(signMatrix[i],signMatrix[i + noEstPerFrame],noQmfChannels * sizeof(INT)); + } + + FDKmemmove(nrgVector,nrgVector+noEstPerFrame,move*sizeof(FIXP_DBL)); + FDKmemclear(nrgVector+startIndexMatrix,(totNoEst-startIndexMatrix)*sizeof(FIXP_DBL)); + FDKmemclear(pNrgVectorFreq,noQmfChannels * sizeof(FIXP_DBL)); + + /* + * Calculate the quotas for the current time steps. + **************************************************/ + + for (r = 0; r < usb; r++) + { + int blockLength; + + k = hTonCorr->nextSample; /* startSample */ + timeIndex = startIndexMatrix; + /* Copy as many as possible Band accross all Slots at once */ + if (realBuf != realBufRef) { + realBuf -= BAND_V_SIZE; + imagBuf -= BAND_V_SIZE; + } else { + realBuf += BAND_V_SIZE*(NUM_V_COMBINE-1); + imagBuf += BAND_V_SIZE*(NUM_V_COMBINE-1); + for (i = 0; i < buffLen; i++) { + int v; + FIXP_DBL *ptr; + ptr = realBuf+i; + for (v=0; vdet == FL2FXCONST_DBL(0.0f)){ + alphar[1] = alphai[1] = FL2FXCONST_DBL(0.0f); + + alphar[0] = (ac->r01r)>>2; + alphai[0] = (ac->r01i)>>2; + + fac = fMultDiv2(ac->r00r, ac->r11r)>>1; + } + else{ + alphar[1] = (fMultDiv2(ac->r01r, ac->r12r)>>1) - (fMultDiv2(ac->r01i, ac->r12i)>>1) - (fMultDiv2(ac->r02r, ac->r11r)>>1); + alphai[1] = (fMultDiv2(ac->r01i, ac->r12r)>>1) + (fMultDiv2(ac->r01r, ac->r12i)>>1) - (fMultDiv2(ac->r02i, ac->r11r)>>1); + + alphar[0] = (fMultDiv2(ac->r01r, ac->det)>>(ac->det_scale+1)) + fMult(alphar[1], ac->r12r) + fMult(alphai[1], ac->r12i); + alphai[0] = (fMultDiv2(ac->r01i, ac->det)>>(ac->det_scale+1)) + fMult(alphai[1], ac->r12r) - fMult(alphar[1], ac->r12i); + + fac = fMultDiv2(ac->r00r, fMult(ac->det, ac->r11r))>>(ac->det_scale+1); + } + + if(fac == FL2FXCONST_DBL(0.0f)){ + quotaMatrix[timeIndex][r] = FL2FXCONST_DBL(0.0f); + signMatrix[timeIndex][r] = 0; + } + else { + /* quotaMatrix is scaled with the factor RELAXATION + parse RELAXATION in fractional part and shift factor: 1/(1/0.524288 * 2^RELAXATION_SHIFT) */ + FIXP_DBL tmp,num,denom; + INT numShift,denomShift,commonShift; + INT sign; + + num = fMultDiv2(alphar[0], ac->r01r) + fMultDiv2(alphai[0], ac->r01i) - fMultDiv2(alphar[1], fMult(ac->r02r, ac->r11r)) - fMultDiv2(alphai[1], fMult(ac->r02i, ac->r11r)); + num = fixp_abs(num); + + denom = (fac>>1) + (fMultDiv2(fac,RELAXATION_FRACT)>>RELAXATION_SHIFT) - num; + denom = fixp_abs(denom); + + num = fMult(num,RELAXATION_FRACT); + + numShift = CountLeadingBits(num) - 2; + num = scaleValue(num, numShift); + + denomShift = CountLeadingBits(denom); + denom = (FIXP_DBL)denom << denomShift; + + if ((num > FL2FXCONST_DBL(0.0f)) && (denom != FL2FXCONST_DBL(0.0f))) { + commonShift = fixMin(numShift - denomShift + RELAXATION_SHIFT, DFRACT_BITS-1); + if (commonShift < 0) { + commonShift = -commonShift; + tmp = schur_div(num,denom,16); + commonShift = fixMin(commonShift,CountLeadingBits(tmp)); + quotaMatrix[timeIndex][r] = tmp << commonShift; + } + else { + quotaMatrix[timeIndex][r] = schur_div(num,denom,16) >> commonShift; + } + } + else { + quotaMatrix[timeIndex][r] = FL2FXCONST_DBL(0.0f); + } + + if (ac->r11r != FL2FXCONST_DBL(0.0f)) { + if ( ( (ac->r01r >= FL2FXCONST_DBL(0.0f) ) && ( ac->r11r >= FL2FXCONST_DBL(0.0f) ) ) + ||( (ac->r01r < FL2FXCONST_DBL(0.0f) ) && ( ac->r11r < FL2FXCONST_DBL(0.0f) ) ) ) { + sign = 1; + } + else { + sign = -1; + } + } + else { + sign = 1; + } + + if(sign < 0) { + r2 = r; /* (INT) pow(-1, band); */ + } + else { + r2 = r + 1; /* (INT) pow(-1, band+1); */ + } + signMatrix[timeIndex][r] = 1 - 2*(r2 & 0x1); + } + + nrgVector[timeIndex] += ((ac->r00r) >> fixMin(DFRACT_BITS-1,(2*qmfScale+autoCorrScaling + SCALE_NRGVEC))); + /* pNrgVectorFreq[r] finally has to be divided by noEstPerFrame, replaced division by shifting with one */ + pNrgVectorFreq[r] = pNrgVectorFreq[r] + ((ac->r00r) >> fixMin(DFRACT_BITS-1,(2*qmfScale+autoCorrScaling + SCALE_NRGVEC))); + + blockLength = pBlockLength[1]; + k += stepSize; + timeIndex++; + } + } + + FDK_ASSERT(noEstPerFrame == 2); + + + C_ALLOC_SCRATCH_END(realBuf, FIXP_DBL, 2*BAND_V_SIZE*NUM_V_COMBINE); + C_ALLOC_SCRATCH_END(ac, ACORR_COEFS, 1); +} + +/**************************************************************************/ +/*! + \brief Extracts the parameters required in the decoder to obtain the + correct tonal to noise ratio after SBR. + + Estimates the tonal to noise ratio of the original signal (using LPC). + Predicts the tonal to noise ration of the SBR signal (in the decoder) by + patching the tonal to noise ratio values similar to the patching of the + lowband in the decoder. Given the tonal to noise ratio of the original + and the SBR signal, it estimates the required amount of inverse filtering, + additional noise as well as any additional sines. + + \return none. + +*/ +/**************************************************************************/ +void +FDKsbrEnc_TonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr,/*!< Handle to SBR_TON_CORR struct. */ + INVF_MODE* infVec, /*!< Vector where the inverse filtering levels will be stored. */ + FIXP_DBL * noiseLevels, /*!< Vector where the noise levels will be stored. */ + INT* missingHarmonicFlag, /*!< Flag set to one or zero, dependent on if any strong sines are missing.*/ + UCHAR * missingHarmonicsIndex, /*!< Vector indicating where sines are missing. */ + UCHAR * envelopeCompensation, /*!< Vector to store compensation values for the energies in. */ + const SBR_FRAME_INFO *frameInfo, /*!< Frame info struct, contains the time and frequency grid of the current frame.*/ + UCHAR* transientInfo, /*!< Transient info.*/ + UCHAR* freqBandTable, /*!< Frequency band tables for high-res.*/ + INT nSfb, /*!< Number of scalefactor bands for high-res. */ + XPOS_MODE xposType, /*!< Type of transposer used in the decoder.*/ + UINT sbrSyntaxFlags + ) +{ + INT band; + INT transientFlag = transientInfo[1] ; /*!< Flag indicating if a transient is present in the current frame. */ + INT transientPos = transientInfo[0]; /*!< Position of the transient.*/ + INT transientFrame, transientFrameInvfEst; + INVF_MODE* infVecPtr; + + + /* Determine if this is a frame where a transient starts... + + The detection of noise-floor, missing harmonics and invf_est, is not in sync for the + non-buf-opt decoder such as AAC. Hence we need to keep track on the transient in the + present frame as well as in the next. + */ + transientFrame = 0; + if(hTonCorr->transientNextFrame){ /* The transient was detected in the previous frame, but is actually */ + transientFrame = 1; + hTonCorr->transientNextFrame = 0; + + if(transientFlag){ + if(transientPos + hTonCorr->transientPosOffset >= frameInfo->borders[frameInfo->nEnvelopes]){ + hTonCorr->transientNextFrame = 1; + } + } + } + else{ + if(transientFlag){ + if(transientPos + hTonCorr->transientPosOffset < frameInfo->borders[frameInfo->nEnvelopes]){ + transientFrame = 1; + hTonCorr->transientNextFrame = 0; + } + else{ + hTonCorr->transientNextFrame = 1; + } + } + } + transientFrameInvfEst = transientFrame; + + + /* + Estimate the required invese filtereing level. + */ + if (hTonCorr->switchInverseFilt) + FDKsbrEnc_qmfInverseFilteringDetector(&hTonCorr->sbrInvFilt, + hTonCorr->quotaMatrix, + hTonCorr->nrgVector, + hTonCorr->indexVector, + hTonCorr->frameStartIndexInvfEst, + hTonCorr->numberOfEstimatesPerFrame + hTonCorr->frameStartIndexInvfEst, + transientFrameInvfEst, + infVec); + + /* + Detect what tones will be missing. + */ + if (xposType == XPOS_LC ){ + FDKsbrEnc_SbrMissingHarmonicsDetectorQmf(&hTonCorr->sbrMissingHarmonicsDetector, + hTonCorr->quotaMatrix, + hTonCorr->signMatrix, + hTonCorr->indexVector, + frameInfo, + transientInfo, + missingHarmonicFlag, + missingHarmonicsIndex, + freqBandTable, + nSfb, + envelopeCompensation, + hTonCorr->nrgVectorFreq); + } + else{ + *missingHarmonicFlag = 0; + FDKmemclear(missingHarmonicsIndex,nSfb*sizeof(UCHAR)); + } + + + + /* + Noise floor estimation + */ + + infVecPtr = hTonCorr->sbrInvFilt.prevInvfMode; + + FDKsbrEnc_sbrNoiseFloorEstimateQmf(&hTonCorr->sbrNoiseFloorEstimate, + frameInfo, + noiseLevels, + hTonCorr->quotaMatrix, + hTonCorr->indexVector, + *missingHarmonicFlag, + hTonCorr->frameStartIndex, + hTonCorr->numberOfEstimatesPerFrame, + transientFrame, + infVecPtr, + sbrSyntaxFlags); + + + /* Store the invfVec data for the next frame...*/ + for(band = 0 ; band < hTonCorr->sbrInvFilt.noDetectorBands; band++){ + hTonCorr->sbrInvFilt.prevInvfMode[band] = infVec[band]; + } +} + +/**************************************************************************/ +/*! + \brief Searches for the closest match in the frequency master table. + + + + \return closest entry. + +*/ +/**************************************************************************/ +static INT +findClosestEntry(INT goalSb, + UCHAR *v_k_master, + INT numMaster, + INT direction) +{ + INT index; + + if( goalSb <= v_k_master[0] ) + return v_k_master[0]; + + if( goalSb >= v_k_master[numMaster] ) + return v_k_master[numMaster]; + + if(direction) { + index = 0; + while( v_k_master[index] < goalSb ) { + index++; + } + } else { + index = numMaster; + while( v_k_master[index] > goalSb ) { + index--; + } + } + + return v_k_master[index]; +} + + +/**************************************************************************/ +/*! + \brief resets the patch + + + + \return errorCode, noError if successful. + +*/ +/**************************************************************************/ +static INT +resetPatch(HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + INT xposctrl, /*!< Different patch modes. */ + INT highBandStartSb, /*!< Start band of the SBR range. */ + UCHAR *v_k_master, /*!< Master frequency table from which all other table are derived.*/ + INT numMaster, /*!< Number of elements in the master table. */ + INT fs, /*!< Sampling frequency. */ + INT noChannels) /*!< Number of QMF-channels. */ +{ + INT patch,k,i; + INT targetStopBand; + + PATCH_PARAM *patchParam = hTonCorr->patchParam; + + INT sbGuard = hTonCorr->guard; + INT sourceStartBand; + INT patchDistance; + INT numBandsInPatch; + + INT lsb = v_k_master[0]; /* Lowest subband related to the synthesis filterbank */ + INT usb = v_k_master[numMaster]; /* Stop subband related to the synthesis filterbank */ + INT xoverOffset = highBandStartSb - v_k_master[0]; /* Calculate distance in subbands between k0 and kx */ + + INT goalSb; + + + /* + * Initialize the patching parameter + */ + + if (xposctrl == 1) { + lsb += xoverOffset; + xoverOffset = 0; + } + + goalSb = (INT)( (2 * noChannels * 16000 + (fs>>1)) / fs ); /* 16 kHz band */ + goalSb = findClosestEntry(goalSb, v_k_master, numMaster, 1); /* Adapt region to master-table */ + + /* First patch */ + sourceStartBand = hTonCorr->shiftStartSb + xoverOffset; + targetStopBand = lsb + xoverOffset; + + /* even (odd) numbered channel must be patched to even (odd) numbered channel */ + patch = 0; + while(targetStopBand < usb) { + + /* To many patches */ + if (patch >= MAX_NUM_PATCHES) + return(1); /*Number of patches to high */ + + patchParam[patch].guardStartBand = targetStopBand; + targetStopBand += sbGuard; + patchParam[patch].targetStartBand = targetStopBand; + + numBandsInPatch = goalSb - targetStopBand; /* get the desired range of the patch */ + + if ( numBandsInPatch >= lsb - sourceStartBand ) { + /* desired number bands are not available -> patch whole source range */ + patchDistance = targetStopBand - sourceStartBand; /* get the targetOffset */ + patchDistance = patchDistance & ~1; /* rounding off odd numbers and make all even */ + numBandsInPatch = lsb - (targetStopBand - patchDistance); + numBandsInPatch = findClosestEntry(targetStopBand + numBandsInPatch, v_k_master, numMaster, 0) - + targetStopBand; /* Adapt region to master-table */ + } + + /* desired number bands are available -> get the minimal even patching distance */ + patchDistance = numBandsInPatch + targetStopBand - lsb; /* get minimal distance */ + patchDistance = (patchDistance + 1) & ~1; /* rounding up odd numbers and make all even */ + + if (numBandsInPatch <= 0) { + patch--; + } else { + patchParam[patch].sourceStartBand = targetStopBand - patchDistance; + patchParam[patch].targetBandOffs = patchDistance; + patchParam[patch].numBandsInPatch = numBandsInPatch; + patchParam[patch].sourceStopBand = patchParam[patch].sourceStartBand + numBandsInPatch; + + targetStopBand += patchParam[patch].numBandsInPatch; + } + + /* All patches but first */ + sourceStartBand = hTonCorr->shiftStartSb; + + /* Check if we are close to goalSb */ + if( fixp_abs(targetStopBand - goalSb) < 3) { + goalSb = usb; + } + + patch++; + + } + + patch--; + + /* if highest patch contains less than three subband: skip it */ + if ( patchParam[patch].numBandsInPatch < 3 && patch > 0 ) { + patch--; + targetStopBand = patchParam[patch].targetStartBand + patchParam[patch].numBandsInPatch; + } + + hTonCorr->noOfPatches = patch + 1; + + + /* Assign the index-vector, so we know where to look for the high-band. + -1 represents a guard-band. */ + for(k = 0; k < hTonCorr->patchParam[0].guardStartBand; k++) + hTonCorr->indexVector[k] = k; + + for(i = 0; i < hTonCorr->noOfPatches; i++) + { + INT sourceStart = hTonCorr->patchParam[i].sourceStartBand; + INT targetStart = hTonCorr->patchParam[i].targetStartBand; + INT numberOfBands = hTonCorr->patchParam[i].numBandsInPatch; + INT startGuardBand = hTonCorr->patchParam[i].guardStartBand; + + for(k = 0; k < (targetStart- startGuardBand); k++) + hTonCorr->indexVector[startGuardBand+k] = -1; + + for(k = 0; k < numberOfBands; k++) + hTonCorr->indexVector[targetStart+k] = sourceStart+k; + } + + return (0); +} + +/**************************************************************************/ +/*! + \brief Creates an instance of the tonality correction parameter module. + + The module includes modules for inverse filtering level estimation, + missing harmonics detection and noise floor level estimation. + + \return errorCode, noError if successful. +*/ +/**************************************************************************/ +INT +FDKsbrEnc_CreateTonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Pointer to handle to SBR_TON_CORR struct. */ + INT chan) /*!< Channel index, needed for mem allocation */ +{ + INT i; + FIXP_DBL* quotaMatrix = GetRam_Sbr_quotaMatrix(chan); + INT* signMatrix = GetRam_Sbr_signMatrix(chan); + + FDKmemclear(hTonCorr, sizeof(SBR_TON_CORR_EST)); + + for (i=0; iquotaMatrix[i] = quotaMatrix + (i*QMF_CHANNELS); + hTonCorr->signMatrix[i] = signMatrix + (i*QMF_CHANNELS); + } + + FDKsbrEnc_CreateSbrMissingHarmonicsDetector (&hTonCorr->sbrMissingHarmonicsDetector, chan); + + return 0; +} + + + +/**************************************************************************/ +/*! + \brief Initialize an instance of the tonality correction parameter module. + + The module includes modules for inverse filtering level estimation, + missing harmonics detection and noise floor level estimation. + + \return errorCode, noError if successful. +*/ +/**************************************************************************/ +INT +FDKsbrEnc_InitTonCorrParamExtr (INT frameSize, /*!< Current SBR frame size. */ + HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Pointer to handle to SBR_TON_CORR struct. */ + HANDLE_SBR_CONFIG_DATA sbrCfg, /*!< Pointer to SBR configuration parameters. */ + INT timeSlots, /*!< Number of time-slots per frame */ + INT xposCtrl, /*!< Different patch modes. */ + INT ana_max_level, /*!< Maximum level of the adaptive noise. */ + INT noiseBands, /*!< Number of noise bands per octave. */ + INT noiseFloorOffset, /*!< Noise floor offset. */ + UINT useSpeechConfig) /*!< Speech or music tuning. */ +{ + INT nCols = sbrCfg->noQmfSlots; + INT fs = sbrCfg->sampleFreq; + INT noQmfChannels = sbrCfg->noQmfBands; + + INT highBandStartSb = sbrCfg->freqBandTable[LOW_RES][0]; + UCHAR *v_k_master = sbrCfg->v_k_master; + INT numMaster = sbrCfg->num_Master; + + UCHAR **freqBandTable = sbrCfg->freqBandTable; + INT *nSfb = sbrCfg->nSfb; + + INT i; + + /* + Reset the patching and allocate memory for the quota matrix. + Assing parameters for the LPC analysis. + */ + if (sbrCfg->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + switch (timeSlots) { + case NUMBER_TIME_SLOTS_1920: + hTonCorr->lpcLength[0] = 8 - LPC_ORDER; + hTonCorr->lpcLength[1] = 7 - LPC_ORDER; + hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LD; + hTonCorr->numberOfEstimatesPerFrame = sbrCfg->noQmfSlots / 7; + hTonCorr->frameStartIndexInvfEst = 0; + hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_512LD; + break; + case NUMBER_TIME_SLOTS_2048: + hTonCorr->lpcLength[0] = 8 - LPC_ORDER; + hTonCorr->lpcLength[1] = 8 - LPC_ORDER; + hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LD; + hTonCorr->numberOfEstimatesPerFrame = sbrCfg->noQmfSlots / 8; + hTonCorr->frameStartIndexInvfEst = 0; + hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_512LD; + break; + } + } else + switch (timeSlots) { + case NUMBER_TIME_SLOTS_2048: + hTonCorr->lpcLength[0] = 16 - LPC_ORDER; /* blockLength[0] */ + hTonCorr->lpcLength[1] = 16 - LPC_ORDER; /* blockLength[0] */ + hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LC; + hTonCorr->numberOfEstimatesPerFrame = sbrCfg->noQmfSlots / 16; + hTonCorr->frameStartIndexInvfEst = 0; + hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_2048; + break; + case NUMBER_TIME_SLOTS_1920: + hTonCorr->lpcLength[0] = 15 - LPC_ORDER; /* blockLength[0] */ + hTonCorr->lpcLength[1] = 15 - LPC_ORDER; /* blockLength[0] */ + hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LC; + hTonCorr->numberOfEstimatesPerFrame = sbrCfg->noQmfSlots / 15; + hTonCorr->frameStartIndexInvfEst = 0; + hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_1920; + break; + default: + return -1; + } + + hTonCorr->bufferLength = nCols; + hTonCorr->stepSize = hTonCorr->lpcLength[0] + LPC_ORDER; /* stepSize[0] implicitly 0. */ + + hTonCorr->nextSample = LPC_ORDER; /* firstSample */ + hTonCorr->move = hTonCorr->numberOfEstimates - hTonCorr->numberOfEstimatesPerFrame; /* Number of estimates to move when buffering.*/ + hTonCorr->startIndexMatrix = hTonCorr->numberOfEstimates - hTonCorr->numberOfEstimatesPerFrame; /* Where to store the latest estimations in the tonality Matrix.*/ + hTonCorr->frameStartIndex = 0; /* Where in the tonality matrix the current frame (to be sent to the decoder) starts. */ + hTonCorr->prevTransientFlag = 0; + hTonCorr->transientNextFrame = 0; + + hTonCorr->noQmfChannels = noQmfChannels; + + for (i=0; inumberOfEstimates; i++) { + FDKmemclear (hTonCorr->quotaMatrix[i] , sizeof(FIXP_DBL)*noQmfChannels); + FDKmemclear (hTonCorr->signMatrix[i] , sizeof(INT)*noQmfChannels); + } + + /* Reset the patch.*/ + hTonCorr->guard = 0; + hTonCorr->shiftStartSb = 1; + + if(resetPatch(hTonCorr, + xposCtrl, + highBandStartSb, + v_k_master, + numMaster, + fs, + noQmfChannels)) + return(1); + + if(FDKsbrEnc_InitSbrNoiseFloorEstimate (&hTonCorr->sbrNoiseFloorEstimate, + ana_max_level, + freqBandTable[LO], + nSfb[LO], + noiseBands, + noiseFloorOffset, + timeSlots, + useSpeechConfig)) + return(1); + + + if(FDKsbrEnc_initInvFiltDetector(&hTonCorr->sbrInvFilt, + hTonCorr->sbrNoiseFloorEstimate.freqBandTableQmf, + hTonCorr->sbrNoiseFloorEstimate.noNoiseBands, + useSpeechConfig)) + return(1); + + + + if(FDKsbrEnc_InitSbrMissingHarmonicsDetector( + &hTonCorr->sbrMissingHarmonicsDetector, + fs, + frameSize, + nSfb[HI], + noQmfChannels, + hTonCorr->numberOfEstimates, + hTonCorr->move, + hTonCorr->numberOfEstimatesPerFrame, + sbrCfg->sbrSyntaxFlags)) + return(1); + + + + return (0); +} + + + +/**************************************************************************/ +/*! + \brief resets tonality correction parameter module. + + + + \return errorCode, noError if successful. + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_ResetTonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + INT xposctrl, /*!< Different patch modes. */ + INT highBandStartSb, /*!< Start band of the SBR range. */ + UCHAR *v_k_master, /*!< Master frequency table from which all other table are derived.*/ + INT numMaster, /*!< Number of elements in the master table. */ + INT fs, /*!< Sampling frequency (of the SBR part). */ + UCHAR ** freqBandTable, /*!< Frequency band table for low-res and high-res. */ + INT* nSfb, /*!< Number of frequency bands (hig-res and low-res). */ + INT noQmfChannels /*!< Number of QMF channels. */ + ) +{ + + /* Reset the patch.*/ + hTonCorr->guard = 0; + hTonCorr->shiftStartSb = 1; + + if(resetPatch(hTonCorr, + xposctrl, + highBandStartSb, + v_k_master, + numMaster, + fs, + noQmfChannels)) + return(1); + + + + /* Reset the noise floor estimate.*/ + if(FDKsbrEnc_resetSbrNoiseFloorEstimate (&hTonCorr->sbrNoiseFloorEstimate, + freqBandTable[LO], + nSfb[LO])) + return(1); + + /* + Reset the inveerse filtereing detector. + */ + if(FDKsbrEnc_resetInvFiltDetector(&hTonCorr->sbrInvFilt, + hTonCorr->sbrNoiseFloorEstimate.freqBandTableQmf, + hTonCorr->sbrNoiseFloorEstimate.noNoiseBands)) + return(1); +/* Reset the missing harmonics detector. */ + if(FDKsbrEnc_ResetSbrMissingHarmonicsDetector (&hTonCorr->sbrMissingHarmonicsDetector, + nSfb[HI])) + return(1); + + return (0); +} + + + + + +/**************************************************************************/ +/*! + \brief Deletes the tonality correction paramtere module. + + + + \return none + +*/ +/**************************************************************************/ +void +FDKsbrEnc_DeleteTonCorrParamExtr (HANDLE_SBR_TON_CORR_EST hTonCorr) /*!< Handle to SBR_TON_CORR struct. */ +{ + + if (hTonCorr) { + + FreeRam_Sbr_quotaMatrix(hTonCorr->quotaMatrix); + + FreeRam_Sbr_signMatrix(hTonCorr->signMatrix); + + FDKsbrEnc_DeleteSbrMissingHarmonicsDetector (&hTonCorr->sbrMissingHarmonicsDetector); + + /* deleteInvFiltDetector (&hTonCorr->sbrInvFilt); */ + + } +} diff --git a/libSBRenc/src/ton_corr.h b/libSBRenc/src/ton_corr.h new file mode 100644 index 0000000..c4e9be0 --- /dev/null +++ b/libSBRenc/src/ton_corr.h @@ -0,0 +1,154 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Header$ + +*******************************************************************************/ +/*! + \file + \brief General tonality correction detector module. +*/ +#ifndef _TON_CORR_EST_H +#define _TON_CORR_EST_H + +#include "sbr_encoder.h" +#include "mh_det.h" +#include "nf_est.h" +#include "invf_est.h" + + +#define MAX_NUM_PATCHES 6 +#define SCALE_NRGVEC 4 + +/** parameter set for one single patch */ +typedef struct { + INT sourceStartBand; /*!< first band in lowbands where to take the samples from */ + INT sourceStopBand; /*!< first band in lowbands which is not included in the patch anymore */ + INT guardStartBand; /*!< first band in highbands to be filled with zeros in order to + reduce interferences between patches */ + INT targetStartBand; /*!< first band in highbands to be filled with whitened lowband signal */ + INT targetBandOffs; /*!< difference between 'startTargetBand' and 'startSourceBand' */ + INT numBandsInPatch; /*!< number of consecutive bands in this one patch */ +} PATCH_PARAM; + + + + +typedef struct +{ + INT switchInverseFilt; /*!< Flag to enable dynamic adaption of invf. detection */ + INT noQmfChannels; + INT bufferLength; /*!< Length of the r and i buffers. */ + INT stepSize; /*!< Stride for the lpc estimate. */ + INT numberOfEstimates; /*!< The total number of estiamtes, available in the quotaMatrix.*/ + INT numberOfEstimatesPerFrame; /*!< The number of estimates per frame available in the quotaMatrix.*/ + INT lpcLength[2]; /*!< Segment length used for second order LPC analysis.*/ + INT nextSample; /*!< Where to start the LPC analysis of the current frame.*/ + INT move; /*!< How many estimates to move in the quotaMatrix, when buffering. */ + INT frameStartIndex; /*!< The start index for the current frame in the r and i buffers. */ + INT startIndexMatrix; /*!< The start index for the current frame in the quotaMatrix. */ + INT frameStartIndexInvfEst; /*!< The start index of the inverse filtering, not the same as the others, + dependent on what decoder is used (buffer opt, or no buffer opt). */ + INT prevTransientFlag; /*!< The transisent flag (from the transient detector) for the previous frame. */ + INT transientNextFrame; /*!< Flag to indicate that the transient will show up in the next frame. */ + INT transientPosOffset; /*!< An offset value to match the transient pos as calculated by the transient detector + with the actual position in the frame.*/ + + INT *signMatrix[MAX_NO_OF_ESTIMATES]; /*!< Matrix holding the sign of each channe, i.e. indicating in what + part of a QMF channel a possible sine is. */ + + FIXP_DBL *quotaMatrix[MAX_NO_OF_ESTIMATES];/*!< Matrix holding the quota values for all estimates, all channels. */ + + FIXP_DBL nrgVector[MAX_NO_OF_ESTIMATES]; /*!< Vector holding the averaged energies for every QMF band. */ + FIXP_DBL nrgVectorFreq[QMF_CHANNELS]; /*!< Vector holding the averaged energies for every QMF channel */ + + SCHAR indexVector[QMF_CHANNELS]; /*!< Index vector poINTing to the correct lowband channel, + when indexing a highband channel, -1 represents a guard band */ + PATCH_PARAM patchParam[MAX_NUM_PATCHES]; /*!< new parameter set for patching */ + INT guard; /*!< number of guardbands between every patch */ + INT shiftStartSb; /*!< lowest subband of source range to be included in the patches */ + INT noOfPatches; /*!< number of patches */ + + SBR_MISSING_HARMONICS_DETECTOR sbrMissingHarmonicsDetector; /*!< SBR_MISSING_HARMONICS_DETECTOR struct. */ + SBR_NOISE_FLOOR_ESTIMATE sbrNoiseFloorEstimate; /*!< SBR_NOISE_FLOOR_ESTIMATE struct. */ + SBR_INV_FILT_EST sbrInvFilt; /*!< SBR_INV_FILT_EST struct. */ +} +SBR_TON_CORR_EST; + +typedef SBR_TON_CORR_EST *HANDLE_SBR_TON_CORR_EST; + +void +FDKsbrEnc_TonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + INVF_MODE* infVec, /*!< Vector where the inverse filtering levels will be stored. */ + FIXP_DBL * noiseLevels, /*!< Vector where the noise levels will be stored. */ + INT* missingHarmonicFlag, /*!< Flag set to one or zero, dependent on if any strong sines are missing.*/ + UCHAR* missingHarmonicsIndex, /*!< Vector indicating where sines are missing. */ + UCHAR* envelopeCompensation, /*!< Vector to store compensation values for the energies in. */ + const SBR_FRAME_INFO *frameInfo, /*!< Frame info struct, contains the time and frequency grid of the current frame.*/ + UCHAR* transientInfo, /*!< Transient info.*/ + UCHAR * freqBandTable, /*!< Frequency band tables for high-res.*/ + INT nSfb, /*!< Number of scalefactor bands for high-res. */ + XPOS_MODE xposType, /*!< Type of transposer used in the decoder.*/ + UINT sbrSyntaxFlags + ); + +INT +FDKsbrEnc_CreateTonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Pointer to handle to SBR_TON_CORR struct. */ + INT chan); /*!< Channel index, needed for mem allocation */ + +INT +FDKsbrEnc_InitTonCorrParamExtr(INT frameSize, /*!< Current SBR frame size. */ + HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Pointer to handle to SBR_TON_CORR struct. */ + HANDLE_SBR_CONFIG_DATA sbrCfg, /*!< Pointer to SBR configuration parameters. */ + INT timeSlots, /*!< Number of time-slots per frame */ + INT xposCtrl, /*!< Different patch modes. */ + INT ana_max_level, /*!< Maximum level of the adaptive noise. */ + INT noiseBands, /*!< Number of noise bands per octave. */ + INT noiseFloorOffset, /*!< Noise floor offset. */ + UINT useSpeechConfig /*!< Speech or music tuning. */ + ); + +void +FDKsbrEnc_DeleteTonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr); /*!< Handle to SBR_TON_CORR struct. */ + + +void +FDKsbrEnc_CalculateTonalityQuotas(HANDLE_SBR_TON_CORR_EST hTonCorr, + FIXP_DBL **sourceBufferReal, + FIXP_DBL **sourceBufferImag, + INT usb, + INT qmfScale /*!< sclefactor of QMF subsamples */ + ); + +INT +FDKsbrEnc_ResetTonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + INT xposctrl, /*!< Different patch modes. */ + INT highBandStartSb, /*!< Start band of the SBR range. */ + UCHAR *v_k_master, /*!< Master frequency table from which all other table are derived.*/ + INT numMaster, /*!< Number of elements in the master table. */ + INT fs, /*!< Sampling frequency (of the SBR part). */ + UCHAR** freqBandTable, /*!< Frequency band table for low-res and high-res. */ + INT* nSfb, /*!< Number of frequency bands (hig-res and low-res). */ + INT noQmfChannels /*!< Number of QMF channels. */ + ); +#endif + diff --git a/libSBRenc/src/tran_det.cpp b/libSBRenc/src/tran_det.cpp new file mode 100644 index 0000000..4011bf3 --- /dev/null +++ b/libSBRenc/src/tran_det.cpp @@ -0,0 +1,645 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +#include "tran_det.h" + +#include "fram_gen.h" +#include "sbr_ram.h" +#include "sbr_misc.h" + +#include "genericStds.h" + +#define NORM_QMF_ENERGY 5.684341886080801486968994140625e-14 /* 2^-44 */ + +/* static FIXP_DBL ABS_THRES = fixMax( FL2FXCONST_DBL(1.28e5 * NORM_QMF_ENERGY), (FIXP_DBL)1) Minimum threshold for detecting changes */ +#define ABS_THRES ((FIXP_DBL)16) + +/******************************************************************************* + Functionname: spectralChange + ******************************************************************************* + \brief Calculates a measure for the spectral change within the frame + + The function says how good it would be to split the frame at the given border + position into 2 envelopes. + + The return value delta_sum is scaled with the factor 1/64 + + \return calculated value +*******************************************************************************/ +static FIXP_DBL spectralChange(FIXP_DBL Energies[NUMBER_TIME_SLOTS_2304][MAX_FREQ_COEFFS], + INT *scaleEnergies, + FIXP_DBL EnergyTotal, + INT nSfb, + INT start, + INT border, + INT stop) +{ + INT i,j; + INT len1,len2; + FIXP_DBL delta,tmp0,tmp1,tmp2; + FIXP_DBL accu1,accu2,delta_sum,result; + + FDK_ASSERT(scaleEnergies[0] >= 0); + + /* equal for aac (would be not equal for mp3) */ + len1 = border-start; + len2 = stop-border; + + /* prefer borders near the middle of the frame */ + FIXP_DBL pos_weight; + pos_weight = FL2FXCONST_DBL(0.5f) - (len1*GetInvInt(len1+len2)); + pos_weight = /*FL2FXCONST_DBL(1.0)*/ (FIXP_DBL)MAXVAL_DBL - (fMult(pos_weight, pos_weight)<<2); + + delta_sum = FL2FXCONST_DBL(0.0f); + + /* Sum up energies of all QMF-timeslots for both halfs */ + for (j=0; j>NRG_SCALE; /* complex init for compare with original version */ + accu2 = ((FL2FXCONST_DBL((1.0e6*NORM_QMF_ENERGY*8.0/32))) << fixMin(scaleEnergies[0],25))>>NRG_SCALE; /* can be simplified in dsp implementation */ + + /* Sum up energies in first half */ + for (i=start; i>NRG_SCALE); + } + + /* Sum up energies in second half */ + for (i=border; i>NRG_SCALE); + } + + /* Energy change in current band */ + tmp0 = CalcLdData(accu2); + tmp1 = CalcLdData(accu1); + tmp2 = (tmp0 - tmp1 + CalcLdData(len1)-CalcLdData(len2)); + delta = fixp_abs(fMult(tmp2, FL2FXCONST_DBL(0.6931471806f))); + + /* Weighting with amplitude ratio of this band */ + result = (EnergyTotal == FL2FXCONST_DBL(0.0f)) + ? FL2FXCONST_DBL(0.f) + : FDKsbrEnc_LSI_divide_scale_fract( (accu1+accu2), + (EnergyTotal>>NRG_SCALE)+(FIXP_DBL)1, + (FIXP_DBL)MAXVAL_DBL >> fixMin(scaleEnergies[0],(DFRACT_BITS-1)) ); + + delta_sum += (FIXP_DBL)(fMult(sqrtFixp(result), delta)); + } + + return fMult(delta_sum, pos_weight); +} + + +/******************************************************************************* + Functionname: addLowbandEnergies + ******************************************************************************* + \brief Calculates total lowband energy + + The return value nrgTotal is scaled by the factor (1/32.0) + + \return total energy in the lowband +*******************************************************************************/ +static FIXP_DBL addLowbandEnergies(FIXP_DBL **Energies, + int *scaleEnergies, + int YBufferWriteOffset, + int nrgSzShift, + int tran_off, + UCHAR *freqBandTable, + int slots) +{ + FIXP_DBL nrgTotal; + FIXP_DBL accu1 = FL2FXCONST_DBL(0.0f); + FIXP_DBL accu2 = FL2FXCONST_DBL(0.0f); + int tran_offdiv2 = tran_off>>nrgSzShift; + int ts,k; + + /* Sum up lowband energy from one frame at offset tran_off */ + for (ts=tran_offdiv2; ts> 6; + } + } + for (; ts>nrgSzShift); ts++) { + for (k = 0; k < freqBandTable[0]; k++) { + accu2 += Energies[ts][k] >> 6; + } + } + + nrgTotal = ( (accu1 >> fixMin(scaleEnergies[0],(DFRACT_BITS-1))) + + (accu2 >> fixMin(scaleEnergies[1],(DFRACT_BITS-1))) ) << (2); + + return(nrgTotal); +} + + +/******************************************************************************* + Functionname: addHighbandEnergies + ******************************************************************************* + \brief Add highband energies + + Highband energies are mapped to an array with smaller dimension: + Its time resolution is only 1 SBR-timeslot and its frequency resolution + is 1 SBR-band. Therefore the data to be fed into the spectralChange + function is reduced. + + The values EnergiesM are scaled by the factor (1/32.0) and scaleEnergies[0] + The return value nrgTotal is scaled by the factor (1/32.0) + + \return total energy in the highband +*******************************************************************************/ + +static FIXP_DBL addHighbandEnergies(FIXP_DBL **RESTRICT Energies, /*!< input */ + INT *scaleEnergies, + FIXP_DBL EnergiesM[NUMBER_TIME_SLOTS_2304][MAX_FREQ_COEFFS], /*!< Combined output */ + UCHAR *RESTRICT freqBandTable, + INT nSfb, + INT sbrSlots, + INT timeStep) +{ + INT i,j,k,slotIn,slotOut,scale; + INT li,ui; + FIXP_DBL nrgTotal; + FIXP_DBL accu = FL2FXCONST_DBL(0.0f); + + /* Combine QMF-timeslots to SBR-timeslots, + combine QMF-bands to SBR-bands, + combine Left and Right channel */ + for (slotOut=0; slotOut>1][k] >> 5); + } + } + EnergiesM[slotOut][j] = accu; + } + } + + scale = fixMin(8,scaleEnergies[0]); /* scale energies down before add up */ + + if ((scaleEnergies[0]-1) > (DFRACT_BITS-1) ) + nrgTotal = FL2FXCONST_DBL(0.0f); + else { + /* Now add all energies */ + accu = FL2FXCONST_DBL(0.0f); + for (slotOut=0; slotOut> scale); + } + } + nrgTotal = accu >> (scaleEnergies[0]-scale); + } + + return(nrgTotal); +} + + +/******************************************************************************* + Functionname: FDKsbrEnc_frameSplitter + ******************************************************************************* + \brief Decides if a FIXFIX-frame shall be splitted into 2 envelopes + + If no transient has been detected before, the frame can still be splitted + into 2 envelopes. +*******************************************************************************/ +void +FDKsbrEnc_frameSplitter(FIXP_DBL **Energies, + INT *scaleEnergies, + HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, + UCHAR *freqBandTable, + UCHAR *tran_vector, + int YBufferWriteOffset, + int YBufferSzShift, + int nSfb, + int timeStep, + int no_cols) +{ + if (tran_vector[1]==0) /* no transient was detected */ + { + FIXP_DBL delta; + FIXP_DBL EnergiesM[NUMBER_TIME_SLOTS_2304][MAX_FREQ_COEFFS]; + FIXP_DBL EnergyTotal,newLowbandEnergy,newHighbandEnergy; + INT border; + INT sbrSlots = fMultI(GetInvInt(timeStep),no_cols); + + FDK_ASSERT( sbrSlots * timeStep == no_cols ); + + /* + Get Lowband-energy over a range of 2 frames (Look half a frame back and ahead). + */ + newLowbandEnergy = addLowbandEnergies(Energies, + scaleEnergies, + YBufferWriteOffset, + YBufferSzShift, + h_sbrTransientDetector->tran_off, + freqBandTable, + no_cols); + + newHighbandEnergy = addHighbandEnergies(Energies, + scaleEnergies, + EnergiesM, + freqBandTable, + nSfb, + sbrSlots, + timeStep); + + if ( h_sbrTransientDetector->frameShift != 0 ) { + if (tran_vector[1]==0) + tran_vector[0] = 0; + } else + { + /* prevLowBandEnergy: Corresponds to 1 frame, starting with half a frame look-behind + newLowbandEnergy: Corresponds to 1 frame, starting in the middle of the current frame */ + EnergyTotal = (newLowbandEnergy + h_sbrTransientDetector->prevLowBandEnergy) >> 1; + EnergyTotal += newHighbandEnergy; + /* The below border should specify the same position as the middle border + of a FIXFIX-frame with 2 envelopes. */ + border = (sbrSlots+1) >> 1; + + delta = spectralChange(EnergiesM, + scaleEnergies, + EnergyTotal, + nSfb, + 0, + border, + sbrSlots); + + if (delta > (h_sbrTransientDetector->split_thr >> LD_DATA_SHIFT)) /* delta scaled by 1/64 */ + tran_vector[0] = 1; /* Set flag for splitting */ + else + tran_vector[0] = 0; + } + + /* Update prevLowBandEnergy */ + h_sbrTransientDetector->prevLowBandEnergy = newLowbandEnergy; + h_sbrTransientDetector->prevHighBandEnergy = newHighbandEnergy; + } +} + +/* + * Calculate transient energy threshold for each QMF band + */ +static void +calculateThresholds(FIXP_DBL **RESTRICT Energies, + INT *RESTRICT scaleEnergies, + FIXP_DBL *RESTRICT thresholds, + int YBufferWriteOffset, + int YBufferSzShift, + int noCols, + int noRows, + int tran_off) +{ + FIXP_DBL mean_val,std_val,temp; + FIXP_DBL i_noCols; + FIXP_DBL i_noCols1; + FIXP_DBL accu,accu0,accu1; + int scaleFactor0,scaleFactor1,commonScale; + int i,j; + + i_noCols = GetInvInt(noCols + tran_off ) << YBufferSzShift; + i_noCols1 = GetInvInt(noCols + tran_off - 1) << YBufferSzShift; + + /* calc minimum scale of energies of previous and current frame */ + commonScale = fixMin(scaleEnergies[0],scaleEnergies[1]); + + /* calc scalefactors to adapt energies to common scale */ + scaleFactor0 = fixMin((scaleEnergies[0]-commonScale), (DFRACT_BITS-1)); + scaleFactor1 = fixMin((scaleEnergies[1]-commonScale), (DFRACT_BITS-1)); + + FDK_ASSERT((scaleFactor0 >= 0) && (scaleFactor1 >= 0)); + + /* calculate standard deviation in every subband */ + for (i=0; i>YBufferSzShift); + int endEnergy = ((noCols>>YBufferSzShift)+tran_off); + int shift; + + /* calculate mean value over decimated energy values (downsampled by 2). */ + accu0 = accu1 = FL2FXCONST_DBL(0.0f); + + for (j=startEnergy; j> scaleFactor0) + (accu1 >> scaleFactor1); /* average */ + shift = fixMax(0,CountLeadingBits(mean_val)-6); /* -6 to keep room for accumulating upto N = 24 values */ + + /* calculate standard deviation */ + accu = FL2FXCONST_DBL(0.0f); + + /* summe { ((mean_val-nrg)^2) * i_noCols1 } */ + for (j=startEnergy; j> scaleFactor0))<> scaleFactor1))<>shift; /* standard deviation */ + + /* + Take new threshold as average of calculated standard deviation ratio + and old threshold if greater than absolute threshold + */ + temp = ( commonScale<=(DFRACT_BITS-1) ) + ? fMult(FL2FXCONST_DBL(0.66f), thresholds[i]) + (fMult(FL2FXCONST_DBL(0.34f), std_val) >> commonScale) + : (FIXP_DBL) 0; + + thresholds[i] = fixMax(ABS_THRES,temp); + + FDK_ASSERT(commonScale >= 0); + } +} + +/* + * Calculate transient levels for each QMF time slot. + */ +static void +extractTransientCandidates(FIXP_DBL **RESTRICT Energies, + INT *RESTRICT scaleEnergies, + FIXP_DBL *RESTRICT thresholds, + FIXP_DBL *RESTRICT transients, + int YBufferWriteOffset, + int YBufferSzShift, + int noCols, + int start_band, + int stop_band, + int tran_off, + int addPrevSamples) +{ + FIXP_DBL i_thres; + C_ALLOC_SCRATCH_START(EnergiesTemp, FIXP_DBL, 2*QMF_MAX_TIME_SLOTS); + FIXP_DBL *RESTRICT pEnergiesTemp = EnergiesTemp; + int tmpScaleEnergies0, tmpScaleEnergies1; + int endCond; + int startEnerg,endEnerg; + int i,j,jIndex,jpBM; + + tmpScaleEnergies0 = scaleEnergies[0]; + tmpScaleEnergies1 = scaleEnergies[1]; + + /* Scale value for first energies, upto YBufferWriteOffset */ + tmpScaleEnergies0 = fixMin(tmpScaleEnergies0, MAX_SHIFT_DBL); + /* Scale value for first energies, from YBufferWriteOffset upwards */ + tmpScaleEnergies1 = fixMin(tmpScaleEnergies1, MAX_SHIFT_DBL); + + FDK_ASSERT((tmpScaleEnergies0 >= 0) && (tmpScaleEnergies1 >= 0)); + + /* Keep addPrevSamples extra previous transient candidates. */ + FDKmemmove(transients, transients + noCols - addPrevSamples, (tran_off+addPrevSamples) * sizeof (FIXP_DBL)); + FDKmemclear(transients + tran_off + addPrevSamples, noCols * sizeof (FIXP_DBL)); + + endCond = noCols; /* Amount of new transient values to be calculated. */ + startEnerg = (tran_off-3)>>YBufferSzShift; /* >>YBufferSzShift because of amount of energy values. -3 because of neighbors being watched. */ + endEnerg = ((noCols+ (YBufferWriteOffset<>YBufferSzShift; /* YBufferSzShift shifts because of half energy values. */ + + /* Compute differential values with two different weightings in every subband */ + for (i=start_band; i=256) + i_thres = (LONG)( (LONG)MAXVAL_DBL / ((((LONG)thresholds[i]))+1) )<<(32-24); + else + i_thres = (LONG)MAXVAL_DBL; + + /* Copy one timeslot and de-scale and de-squish */ + if (YBufferSzShift == 1) { + for(j=startEnerg; j>tmpScaleEnergies0; + } + for(; j<=endEnerg; j++) { + FIXP_DBL tmp = Energies[j][i]; + EnergiesTemp[(j<<1)+1] = EnergiesTemp[j<<1] = tmp>>tmpScaleEnergies1; + } + } else { + for(j=startEnerg; j>tmpScaleEnergies0; + } + for(; j<=endEnerg; j++) { + FIXP_DBL tmp = Energies[j][i]; + EnergiesTemp[j] = tmp>>tmpScaleEnergies1; + } + } + + /* Detect peaks in energy values. */ + + jIndex = tran_off; + jpBM = jIndex+addPrevSamples; + + for (j=endCond; j--; jIndex++, jpBM++) + { + + FIXP_DBL delta, tran; + int d; + + delta = (FIXP_DBL)0; + tran = (FIXP_DBL)0; + + for (d=1; d<4; d++) { + delta += pEnergiesTemp[jIndex+d]; /* R */ + delta -= pEnergiesTemp[jIndex-d]; /* L */ + delta -= thres; + + if ( delta > (FIXP_DBL)0 ) { + tran += fMult(i_thres, delta); + } + } + transients[jpBM] += tran; + } + } + C_ALLOC_SCRATCH_END(EnergiesTemp, FIXP_DBL, 2*QMF_MAX_TIME_SLOTS); +} + +void +FDKsbrEnc_transientDetect(HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTran, + FIXP_DBL **Energies, + INT *scaleEnergies, + UCHAR *transient_info, + int YBufferWriteOffset, + int YBufferSzShift, + int timeStep, + int frameMiddleBorder) +{ + int no_cols = h_sbrTran->no_cols; + int qmfStartSample; + int addPrevSamples; + int timeStepShift=0; + int i, cond; + + /* Where to start looking for transients in the transient candidate buffer */ + qmfStartSample = timeStep * frameMiddleBorder; + /* We need to look one value backwards in the transients, so we might need one more previous value. */ + addPrevSamples = (qmfStartSample > 0) ? 0: 1; + + switch (timeStep) { + case 1: timeStepShift = 0; break; + case 2: timeStepShift = 1; break; + case 4: timeStepShift = 2; break; + } + + calculateThresholds(Energies, + scaleEnergies, + h_sbrTran->thresholds, + YBufferWriteOffset, + YBufferSzShift, + h_sbrTran->no_cols, + h_sbrTran->no_rows, + h_sbrTran->tran_off); + + extractTransientCandidates(Energies, + scaleEnergies, + h_sbrTran->thresholds, + h_sbrTran->transients, + YBufferWriteOffset, + YBufferSzShift, + h_sbrTran->no_cols, + 0, + h_sbrTran->no_rows, + h_sbrTran->tran_off, + addPrevSamples ); + + transient_info[0] = 0; + transient_info[1] = 0; + transient_info[2] = 0; + + /* Offset by the amount of additional previous transient candidates being kept. */ + qmfStartSample += addPrevSamples; + + /* Check for transients in second granule (pick the last value of subsequent values) */ + for (i=qmfStartSample; itransients[i] < fMult(FL2FXCONST_DBL(0.9f), h_sbrTran->transients[i - 1]) ) + && (h_sbrTran->transients[i - 1] > h_sbrTran->tran_thr); + + if (cond) { + transient_info[0] = (i - qmfStartSample)>>timeStepShift; + /* FDKprintf("\nSBR Transient at timeSlot %d\n", transient_info[0]); */ + transient_info[1] = 1; + break; + } + } + + if ( h_sbrTran->frameShift != 0) { + /* transient prediction for LDSBR */ + /* Check for transients in first qmf-slots of second frame */ + for (i=qmfStartSample+no_cols; iframeShift; i++) { + + cond = (h_sbrTran->transients[i] < fMult(FL2FXCONST_DBL(0.9f), h_sbrTran->transients[i - 1]) ) + && (h_sbrTran->transients[i - 1] > h_sbrTran->tran_thr); + + if (cond) { + int pos = (int) ( (i - qmfStartSample-no_cols) >> timeStepShift ); + if ((pos < 3) && (transient_info[1]==0)) { + transient_info[2] = 1; + } + break; + } + } + } +} + +int +FDKsbrEnc_InitSbrTransientDetector(HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, + INT frameSize, + INT sampleFreq, + sbrConfigurationPtr params, + int tran_fc, + int no_cols, + int no_rows, + int YBufferWriteOffset, + int YBufferSzShift, + int frameShift, + int tran_off) +{ + INT totalBitrate = params->codecSettings.standardBitrate * params->codecSettings.nChannels; + INT codecBitrate = params->codecSettings.bitRate; + FIXP_DBL bitrateFactor_fix, framedur_fix; + INT scale_0, scale_1; + + FDKmemclear(h_sbrTransientDetector,sizeof(SBR_TRANSIENT_DETECTOR)); + + h_sbrTransientDetector->frameShift = frameShift; + h_sbrTransientDetector->tran_off = tran_off; + + if(codecBitrate) { + bitrateFactor_fix = fDivNorm((FIXP_DBL)totalBitrate, (FIXP_DBL)(codecBitrate<<2),&scale_0); + } + else { + bitrateFactor_fix = FL2FXCONST_DBL(1.0/4.0); + scale_0 = 0; + } + + framedur_fix = fDivNorm(frameSize, sampleFreq); + + /* The longer the frames, the more often should the FIXFIX- + case transmit 2 envelopes instead of 1. + Frame durations below 10 ms produce the highest threshold + so that practically always only 1 env is transmitted. */ + FIXP_DBL tmp = framedur_fix - FL2FXCONST_DBL(0.010); + + tmp = fixMax(tmp, FL2FXCONST_DBL(0.0001)); + tmp = fDivNorm(FL2FXCONST_DBL(0.000075), fPow2(tmp), &scale_1); + + scale_1 = -(scale_1 + scale_0 + 2); + + FDK_ASSERT(no_cols <= QMF_MAX_TIME_SLOTS); + FDK_ASSERT(no_rows <= QMF_CHANNELS); + + h_sbrTransientDetector->no_cols = no_cols; + h_sbrTransientDetector->tran_thr = (FIXP_DBL)((params->tran_thr << (32-24-1)) / no_rows); + h_sbrTransientDetector->tran_fc = tran_fc; + + if (scale_1>=0) { + h_sbrTransientDetector->split_thr = fMult(tmp, bitrateFactor_fix) >> scale_1; + } + else { + h_sbrTransientDetector->split_thr = fMult(tmp, bitrateFactor_fix) << (-scale_1); + } + + h_sbrTransientDetector->no_rows = no_rows; + h_sbrTransientDetector->mode = params->tran_det_mode; + h_sbrTransientDetector->prevLowBandEnergy = FL2FXCONST_DBL(0.0f); + + return (0); +} + diff --git a/libSBRenc/src/tran_det.h b/libSBRenc/src/tran_det.h new file mode 100644 index 0000000..3430b44 --- /dev/null +++ b/libSBRenc/src/tran_det.h @@ -0,0 +1,92 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Transient detector prototypes $Revision: 36847 $ +*/ +#ifndef __TRAN_DET_H +#define __TRAN_DET_H + +#include "sbr_encoder.h" +#include "sbr_def.h" + +typedef struct +{ + FIXP_DBL transients[QMF_MAX_TIME_SLOTS+(QMF_MAX_TIME_SLOTS/2)]; + FIXP_DBL thresholds[QMF_CHANNELS]; + FIXP_DBL tran_thr; /* Master threshold for transient signals */ + FIXP_DBL split_thr; /* Threshold for splitting FIXFIX-frames into 2 env */ + FIXP_DBL prevLowBandEnergy; /* Energy of low band */ + FIXP_DBL prevHighBandEnergy; /* Energy of high band */ + INT tran_fc; /* Number of lowband subbands to discard */ + INT no_cols; + INT no_rows; + INT mode; + + int frameShift; + int tran_off; /* Offset for reading energy values. */ +} +SBR_TRANSIENT_DETECTOR; + + +typedef SBR_TRANSIENT_DETECTOR *HANDLE_SBR_TRANSIENT_DETECTOR; + +void +FDKsbrEnc_transientDetect(HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, + FIXP_DBL **Energies, + INT *scaleEnergies, + UCHAR *tran_vector, + int YBufferWriteOffset, + int YBufferSzShift, + int timeStep, + int frameMiddleBorder); + +int +FDKsbrEnc_InitSbrTransientDetector (HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, + INT frameSize, + INT sampleFreq, + sbrConfigurationPtr params, + int tran_fc, + int no_cols, + int no_rows, + int YBufferWriteOffset, + int YBufferSzShift, + int frameShift, + int tran_off); + +void +FDKsbrEnc_frameSplitter(FIXP_DBL **Energies, + INT *scaleEnergies, + HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, + UCHAR *freqBandTable, + UCHAR *tran_vector, + int YBufferWriteOffset, + int YBufferSzShift, + int nSfb, + int timeStep, + int no_cols); + +#endif diff --git a/libSYS/Android.mk b/libSYS/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/libSYS/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/libSYS/include/FDK_audio.h b/libSYS/include/FDK_audio.h new file mode 100644 index 0000000..1d28187 --- /dev/null +++ b/libSYS/include/FDK_audio.h @@ -0,0 +1,544 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +/** \file FDK_audio.h + * \brief Global audio struct and constant definitions. + */ + +#ifndef FDK_AUDIO_H +#define FDK_AUDIO_H + +#include "machine_type.h" +#include "genericStds.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * File format identifiers. + */ +typedef enum +{ + FF_UNKNOWN = -1, /**< Unknown format. */ + FF_RAW = 0, /**< No container, bit stream data conveyed "as is". */ + + FF_MP4_3GPP = 3, /**< 3GPP file format. */ + FF_MP4_MP4F = 4, /**< MPEG-4 File format. */ + + FF_RAWPACKETS = 5, /**< Proprietary raw packet file. */ + + FF_DRMCT = 12 /**< Digital Radio Mondial (DRM30/DRM+) CT proprietary file format. */ + +} FILE_FORMAT; + +/** + * Transport type identifiers. + */ +typedef enum +{ + TT_UNKNOWN = -1, /**< Unknown format. */ + TT_MP4_RAW = 0, /**< "as is" access units (packet based since there is obviously no sync layer) */ + TT_MP4_ADIF = 1, /**< ADIF bitstream format. */ + TT_MP4_ADTS = 2, /**< ADTS bitstream format. */ + + TT_MP4_LATM_MCP1 = 6, /**< Audio Mux Elements with muxConfigPresent = 1 */ + TT_MP4_LATM_MCP0 = 7, /**< Audio Mux Elements with muxConfigPresent = 0, out of band StreamMuxConfig */ + + TT_MP4_LOAS = 10, /**< Audio Sync Stream. */ + + TT_DRM = 12, /**< Digital Radio Mondial (DRM30/DRM+) bitstream format. */ + + TT_MP1_L1 = 16, /**< MPEG 1 Audio Layer 1 audio bitstream. */ + TT_MP1_L2 = 17, /**< MPEG 1 Audio Layer 2 audio bitstream. */ + TT_MP1_L3 = 18, /**< MPEG 1 Audio Layer 3 audio bitstream. */ + + TT_RSVD50 = 50 /**< */ + +} TRANSPORT_TYPE; + +/** + * Audio Object Type definitions. + */ +typedef enum +{ + AOT_NONE = -1, + AOT_NULL_OBJECT = 0, + AOT_AAC_MAIN = 1, /**< Main profile */ + AOT_AAC_LC = 2, /**< Low Complexity object */ + AOT_AAC_SSR = 3, + AOT_AAC_LTP = 4, + AOT_SBR = 5, + AOT_AAC_SCAL = 6, + AOT_TWIN_VQ = 7, + AOT_CELP = 8, + AOT_HVXC = 9, + AOT_RSVD_10 = 10, /**< (reserved) */ + AOT_RSVD_11 = 11, /**< (reserved) */ + AOT_TTSI = 12, /**< TTSI Object */ + AOT_MAIN_SYNTH = 13, /**< Main Synthetic object */ + AOT_WAV_TAB_SYNTH = 14, /**< Wavetable Synthesis object */ + AOT_GEN_MIDI = 15, /**< General MIDI object */ + AOT_ALG_SYNTH_AUD_FX = 16, /**< Algorithmic Synthesis and Audio FX object */ + AOT_ER_AAC_LC = 17, /**< Error Resilient(ER) AAC Low Complexity */ + AOT_RSVD_18 = 18, /**< (reserved) */ + AOT_ER_AAC_LTP = 19, /**< Error Resilient(ER) AAC LTP object */ + AOT_ER_AAC_SCAL = 20, /**< Error Resilient(ER) AAC Scalable object */ + AOT_ER_TWIN_VQ = 21, /**< Error Resilient(ER) TwinVQ object */ + AOT_ER_BSAC = 22, /**< Error Resilient(ER) BSAC object */ + AOT_ER_AAC_LD = 23, /**< Error Resilient(ER) AAC LowDelay object */ + AOT_ER_CELP = 24, /**< Error Resilient(ER) CELP object */ + AOT_ER_HVXC = 25, /**< Error Resilient(ER) HVXC object */ + AOT_ER_HILN = 26, /**< Error Resilient(ER) HILN object */ + AOT_ER_PARA = 27, /**< Error Resilient(ER) Parametric object */ + AOT_RSVD_28 = 28, /**< might become SSC */ + AOT_PS = 29, /**< PS, Parametric Stereo (includes SBR) */ + AOT_MPEGS = 30, /**< MPEG Surround */ + + AOT_ESCAPE = 31, /**< Signal AOT uses more than 5 bits */ + + AOT_MP3ONMP4_L1 = 32, /**< MPEG-Layer1 in mp4 */ + AOT_MP3ONMP4_L2 = 33, /**< MPEG-Layer2 in mp4 */ + AOT_MP3ONMP4_L3 = 34, /**< MPEG-Layer3 in mp4 */ + AOT_RSVD_35 = 35, /**< might become DST */ + AOT_RSVD_36 = 36, /**< might become ALS */ + AOT_AAC_SLS = 37, /**< AAC + SLS */ + AOT_SLS = 38, /**< SLS */ + AOT_ER_AAC_ELD = 39, /**< AAC Enhanced Low Delay */ + + AOT_USAC = 42, /**< USAC */ + AOT_SAOC = 43, /**< SAOC */ + AOT_LD_MPEGS = 44, /**< Low Delay MPEG Surround */ + + AOT_RSVD50 = 50, /**< Interim AOT for Rsvd50 */ + + /* Pseudo AOTs */ + AOT_MP2_AAC_MAIN = 128, /**< Virtual AOT MP2 Main profile */ + AOT_MP2_AAC_LC = 129, /**< Virtual AOT MP2 Low Complexity profile */ + AOT_MP2_AAC_SSR = 130, /**< Virtual AOT MP2 Scalable Sampling Rate profile */ + + AOT_MP2_SBR = 132, /**< Virtual AOT MP2 Low Complexity Profile with SBR */ + + AOT_DAB = 134, /**< Virtual AOT for DAB (Layer2 with scalefactor CRC) */ + AOT_DABPLUS_AAC_LC = 135, /**< Virtual AOT for DAB plus AAC-LC */ + AOT_DABPLUS_SBR = 136, /**< Virtual AOT for DAB plus HE-AAC */ + AOT_DABPLUS_PS = 137, /**< Virtual AOT for DAB plus HE-AAC v2 */ + + AOT_PLAIN_MP1 = 140, /**< Virtual AOT for plain mp1 */ + AOT_PLAIN_MP2 = 141, /**< Virtual AOT for plain mp2 */ + AOT_PLAIN_MP3 = 142, /**< Virtual AOT for plain mp3 */ + + AOT_DRM_AAC = 143, /**< Virtual AOT for DRM (ER-AAC-SCAL without SBR) */ + AOT_DRM_SBR = 144, /**< Virtual AOT for DRM (ER-AAC-SCAL with SBR) */ + AOT_DRM_MPEG_PS = 145, /**< Virtual AOT for DRM (ER-AAC-SCAL with SBR and MPEG-PS) */ + AOT_DRM_SURROUND = 146, /**< Virtual AOT for DRM Surround (ER-AAC-SCAL (+SBR) +MPS) */ + + AOT_MP2_PS = 156, /**< Virtual AOT MP2 Low Complexity Profile with SBR and PS */ + + AOT_MPEGS_RESIDUALS = 256 /**< Virtual AOT for MPEG Surround residuals */ + +} AUDIO_OBJECT_TYPE; + +/** Channel Mode ( 1-7 equals MPEG channel configurations, others are arbitrary). */ +typedef enum { + MODE_INVALID = -1, + MODE_UNKNOWN = 0, + MODE_1 = 1, /**< SCE */ + MODE_2 = 2, /**< CPE */ + MODE_1_2 = 3, /**< SCE,CPE */ + MODE_1_2_1 = 4, /**< SCE,CPE,SCE */ + MODE_1_2_2 = 5, /**< SCE,CPE,CPE */ + MODE_1_2_2_1 = 6, /**< SCE,CPE,CPE,LFE */ + MODE_1_2_2_2_1 = 7, /**< SCE,CPE,CPE,CPE,LFE */ + + MODE_1_1 = 16, /**< 2 SCEs (dual mono) */ + MODE_1_1_1_1 = 17, /**< 4 SCEs */ + MODE_1_1_1_1_1_1 = 18, /**< 6 SCEs */ + MODE_1_1_1_1_1_1_1_1 = 19, /**< 8 SCEs */ + MODE_1_1_1_1_1_1_1_1_1_1_1_1 = 20, /**< 12 SCEs */ + + MODE_2_2 = 21, /**< 2 CPEs */ + MODE_2_2_2 = 22, /**< 3 CPEs */ + MODE_2_2_2_2 = 23, /**< 4 CPEs */ + MODE_2_2_2_2_2_2 = 24, /**< 6 CPEs */ + + MODE_2_1 = 30 /**< CPE,SCE (ARIB standard) */ + +} CHANNEL_MODE; + +/** Speaker description tags */ +typedef enum { + ACT_NONE, + ACT_FRONT, + ACT_SIDE, + ACT_BACK, + ACT_LFE, + ACT_FRONT_TOP, + ACT_SIDE_TOP, + ACT_BACK_TOP, + ACT_TOP /* Ts */ +} AUDIO_CHANNEL_TYPE; + +/** + * Audio Codec flags. + */ +#define AC_ER_VCB11 0x000001 /*!< aacSectionDataResilienceFlag flag (from ASC): 1 means use virtual codebooks */ +#define AC_ER_RVLC 0x000002 /*!< aacSpectralDataResilienceFlag flag (from ASC): 1 means use huffman codeword reordering */ +#define AC_ER_HCR 0x000004 /*!< aacSectionDataResilienceFlag flag (from ASC): 1 means use virtual codebooks */ +#define AC_SCALABLE 0x000008 /*!< AAC Scalable*/ +#define AC_ELD 0x000010 /*!< AAC-ELD */ +#define AC_LD 0x000020 /*!< AAC-LD */ +#define AC_ER 0x000040 /*!< ER syntax */ +#define AC_BSAC 0x000080 /*!< BSAC */ +#define AC_USAC 0x000100 /*!< USAC */ +#define AC_USAC_TW 0x000200 /*!< USAC time warped filter bank is active */ +#define AC_USAC_NOISE 0x000400 /*!< USAC noise filling is active */ +#define AC_USAC_HBE 0x000800 /*!< USAC harmonic bandwidth extension is active */ +#define AC_RSVD50 0x001000 /*!< Rsvd50 */ +#define AC_SBR_PRESENT 0x002000 /*!< SBR present flag (from ASC) */ +#define AC_SBRCRC 0x004000 /*!< SBR CRC present flag. Only relevant for AAC-ELD for now. */ +#define AC_PS_PRESENT 0x008000 /*!< PS present flag (from ASC or implicit) */ +#define AC_MPS_PRESENT 0x010000 /*!< MPS present flag (from ASC or implicit) */ +#define AC_DRM 0x020000 /*!< DRM bit stream syntax */ +#define AC_INDEP 0x040000 /*!< Independency flag */ +#define AC_MPS_RES 0x080000 /*!< MPS residual individual channel data. */ +#define AC_DAB 0x800000 /*!< DAB bit stream syntax */ +#define AC_LD_MPS 0x01000000 /*!< Low Delay MPS. */ + + +/* CODER_CONFIG::flags */ +#define CC_MPEG_ID 0x00100000 +#define CC_IS_BASELAYER 0x00200000 +#define CC_PROTECTION 0x00400000 +#define CC_SBR 0x00800000 +#define CC_RVLC 0x01000000 +#define CC_VCB11 0x02000000 +#define CC_HCR 0x04000000 +#define CC_PSEUDO_SURROUND 0x08000000 +#define CC_USAC_NOISE 0x10000000 +#define CC_USAC_TW 0x20000000 +#define CC_USAC_HBE 0x40000000 + +/** Generic audio coder configuration structure. */ +typedef struct { + AUDIO_OBJECT_TYPE aot; /**< Audio Object Type (AOT). */ + AUDIO_OBJECT_TYPE extAOT; /**< Extension Audio Object Type (SBR). */ + CHANNEL_MODE channelMode; /**< Channel mode. */ + INT samplingRate; /**< Sampling rate. */ + INT extSamplingRate; /**< Extended samplerate (SBR). */ + INT bitRate; /**< Average bitrate. */ + int samplesPerFrame; /**< Number of PCM samples per codec frame and audio channel. */ + int noChannels; /**< Number of audio channels. */ + int bitsFrame; + int nSubFrames; /**< Amount of encoder subframes. 1 means no subframing. */ + int BSACnumOfSubFrame; /**< The number of the sub-frames which are grouped and transmitted in a super-frame (BSAC). */ + int BSAClayerLength; /**< The average length of the large-step layers in bytes (BSAC). */ + UINT flags; /**< flags */ + UCHAR matrixMixdownA; /**< Matrix mixdown index to put into PCE. Default value 0 means no mixdown coefficient, + valid values are 1-4 which correspond to matrix_mixdown_idx 0-3. */ + UCHAR headerPeriod; /**< Frame period for sending in band configuration buffers in the transport layer. */ + + UCHAR stereoConfigIndex; /**< USAC MPS stereo mode */ + UCHAR sbrMode; /**< USAC SBR mode */ +} CODER_CONFIG; + +/** MP4 Element IDs. */ +typedef enum +{ + ID_NONE = -1, /**< Invalid Element helper ID. */ + ID_SCE = 0, /**< Single Channel Element. */ + ID_CPE = 1, /**< Channel Pair Element. */ + ID_CCE = 2, /**< Coupling Channel Element. */ + ID_LFE = 3, /**< LFE Channel Element. */ + ID_DSE = 4, /**< Currently one Data Stream Element for ancillary data is supported. */ + ID_PCE = 5, /**< Program Config Element. */ + ID_FIL = 6, /**< Fill Element. */ + ID_END = 7, /**< Arnie (End Element = Terminator). */ + ID_EXT = 8, /**< Extension Payload (ER only). */ + ID_SCAL = 9, /**< AAC scalable element (ER only). */ + ID_LAST +} MP4_ELEMENT_ID; + +#define EXT_ID_BITS 4 /**< Size in bits of extension payload type tags. */ + +/** Extension payload types. */ +typedef enum { + EXT_FIL = 0x00, + EXT_FILL_DATA = 0x01, + EXT_DATA_ELEMENT = 0x02, + EXT_DATA_LENGTH = 0x03, + EXT_LDSAC_DATA = 0x09, + EXT_SAOC_DATA = 0x0a, + EXT_DYNAMIC_RANGE = 0x0b, + EXT_SAC_DATA = 0x0c, + EXT_SBR_DATA = 0x0d, + EXT_SBR_DATA_CRC = 0x0e +} EXT_PAYLOAD_TYPE; + + +/** + * Proprietary raw packet file configuration data type identifier. + */ +typedef enum +{ + TC_NOTHING = 0, /* No configuration available -> in-band configuration. */ + TC_RAW_ASC, /* Configuration data field is a raw AudioSpecificConfig. */ + TC_RAW_SMC, /* Configuration data field is a raw StreamMuxConfig. */ + TC_RAW_SDC /* Configuration data field is a raw Drm SDC. */ + +} TP_CONFIG_TYPE; + +/* + * ############################################################################################## + * Library identification and error handling + * ############################################################################################## + */ +/* \cond */ +#define MODULE_ID_MASK (0x000000ff) +#define MODULE_ID_SHIFT (24) + +typedef enum { + FDK_NONE = 0, + FDK_TOOLS = 1, + FDK_SYSLIB = 2, + FDK_AACDEC = 3, + FDK_AACENC = 4, + FDK_SBRDEC = 5, + FDK_SBRENC = 6, + FDK_TPDEC = 7, + FDK_TPENC = 8, + FDK_MPSDEC = 9, + FDK_MPEGFILEREAD = 10, + FDK_MPEGFILEWRITE = 11, + FDK_MP2DEC = 12, + FDK_DABDEC = 13, + FDK_DABPARSE = 14, + FDK_DRMDEC = 15, + FDK_DRMPARSE = 16, + FDK_AACLDENC = 17, + FDK_MP2ENC = 18, + FDK_MP3ENC = 19, + FDK_MP3DEC = 20, + FDK_MP3HEADPHONE = 21, + FDK_MP3SDEC = 22, + FDK_MP3SENC = 23, + FDK_EAEC = 24, + FDK_DABENC = 25, + FDK_DMBDEC = 26, + FDK_FDREVERB = 27, + FDK_DRMENC = 28, + FDK_METADATATRANSCODER = 29, + FDK_AC3DEC = 30, + FDK_PCMDMX = 31, + + FDK_MODULE_LAST + +} FDK_MODULE_ID; + +/* AAC capability flags */ +#define CAPF_AAC_LC 0x00000001 /**< Support flag for AAC Low Complexity. */ +#define CAPF_ER_AAC_LD 0x00000002 /**< Support flag for AAC Low Delay with Error Resilience tools. */ +#define CAPF_ER_AAC_SCAL 0x00000004 /**< Support flag for AAC Scalable. */ +#define CAPF_ER_AAC_LC 0x00000008 /**< Support flag for AAC Low Complexity with Error Resilience tools. */ +#define CAPF_AAC_480 0x00000010 /**< Support flag for AAC with 480 framelength. */ +#define CAPF_AAC_512 0x00000020 /**< Support flag for AAC with 512 framelength. */ +#define CAPF_AAC_960 0x00000040 /**< Support flag for AAC with 960 framelength. */ +#define CAPF_AAC_1024 0x00000080 /**< Support flag for AAC with 1024 framelength. */ +#define CAPF_AAC_HCR 0x00000100 /**< Support flag for AAC with Huffman Codeword Reordering. */ +#define CAPF_AAC_VCB11 0x00000200 /**< Support flag for AAC Virtual Codebook 11. */ +#define CAPF_AAC_RVLC 0x00000400 /**< Support flag for AAC Reversible Variable Length Coding. */ +#define CAPF_AAC_MPEG4 0x00000800 /**< Support flag for MPEG file format. */ +#define CAPF_AAC_DRC 0x00001000 /**< Support flag for AAC Dynamic Range Control. */ +#define CAPF_AAC_CONCEALMENT 0x00002000 /**< Support flag for AAC concealment. */ +#define CAPF_AAC_DRM_BSFORMAT 0x00004000 /**< Support flag for AAC DRM bistream format. */ +#define CAPF_ER_AAC_ELD 0x00008000 /**< Support flag for AAC Enhanced Low Delay with Error Resilience tools. */ +#define CAPF_ER_AAC_BSAC 0x00010000 /**< Support flag for AAC BSAC. */ +#define CAPF_AAC_SUPERFRAMING 0x00020000 /**< Support flag for AAC Superframing. */ + +/* Transport capability flags */ +#define CAPF_ADTS 0x00000001 /**< Support flag for ADTS transport format. */ +#define CAPF_ADIF 0x00000002 /**< Support flag for ADIF transport format. */ +#define CAPF_LATM 0x00000004 /**< Support flag for LATM transport format. */ +#define CAPF_LOAS 0x00000008 /**< Support flag for LOAS transport format. */ +#define CAPF_RAWPACKETS 0x00000010 /**< Support flag for RAW PACKETS transport format. */ +#define CAPF_DRM 0x00000020 /**< Support flag for DRM/DRM+ transport format. */ +#define CAPF_RSVD50 0x00000040 /**< Support flag for RSVD50 transport format */ + +/* SBR capability flags */ +#define CAPF_SBR_LP 0x00000001 /**< Support flag for SBR Low Power mode. */ +#define CAPF_SBR_HQ 0x00000002 /**< Support flag for SBR High Quality mode. */ +#define CAPF_SBR_DRM_BS 0x00000004 /**< Support flag for */ +#define CAPF_SBR_CONCEALMENT 0x00000008 /**< Support flag for SBR concealment. */ +#define CAPF_SBR_DRC 0x00000010 /**< Support flag for SBR Dynamic Range Control. */ +#define CAPF_SBR_PS_MPEG 0x00000020 /**< Support flag for MPEG Parametric Stereo. */ +#define CAPF_SBR_PS_DRM 0x00000040 /**< Support flag for DRM Parametric Stereo. */ + +/* MP2 encoder capability flags */ +#define CAPF_MP2ENC_SS 0x00000001 /**< Support flag for Seamless Switching. */ +#define CAPF_MP2ENC_DAB 0x00000002 /**< Support flag for Layer2 DAB. */ + +/* DAB capability flags */ +#define CAPF_DAB_MP2 0x00000001 /**< Support flag for Layer2 DAB. */ +#define CAPF_DAB_AAC 0x00000002 /**< Support flag for DAB+ (HE-AAC v2). */ +#define CAPF_DAB_PAD 0x00000004 /**< Support flag for PAD extraction. */ +#define CAPF_DAB_DRC 0x00000008 /**< Support flag for Dynamic Range Control. */ +#define CAPF_DAB_SURROUND 0x00000010 /**< Support flag for DAB Surround (MPS). */ + +/* DMB capability flags */ +#define CAPF_DMB_BSAC 0x00000001 /**< Support flag for ER AAC BSAC. */ +#define CAPF_DMB_DRC 0x00000008 /**< Support flag for Dynamic Range Control. */ +#define CAPF_DMB_SURROUND 0x00000010 /**< Support flag for DMB Surround (MPS). */ + +/* PCM up/downmmix capability flags */ +#define CAPF_DMX_BLIND 0x00000001 /**< Support flag for blind downmixing. */ +#define CAPF_DMX_PCE 0x00000002 /**< Support flag for guided downmix with data from MPEG-2/4 Program Config Elements (PCE). */ +#define CAPF_DMX_ARIB 0x00000004 /**< Support flag for PCE guided downmix with slightly different equations and levels to fulfill ARIB standard. */ +#define CAPF_DMX_DVB 0x00000008 /**< Support flag for guided downmix with data from DVB ancillary data fields. */ +#define CAPF_DMX_CH_EXP 0x00000010 /**< Support flag for simple upmixing by dublicating channels or adding zero channels. */ +/* \endcond */ + + +/* + * ############################################################################################## + * Library versioning + * ############################################################################################## + */ + +/** + * Convert each member of version numbers to one single numeric version representation. + * \param lev0 1st level of version number. + * \param lev1 2nd level of version number. + * \param lev2 3rd level of version number. + */ +#define LIB_VERSION(lev0, lev1, lev2) ((lev0<<24 & 0xff000000) | \ + (lev1<<16 & 0x00ff0000) | \ + (lev2<<8 & 0x0000ff00)) + +/** + * Build text string of version. + */ +#define LIB_VERSION_STRING(info) FDKsprintf((info)->versionStr, "%d.%d.%d", (((info)->version >> 24) & 0xff), (((info)->version >> 16) & 0xff), (((info)->version >> 8 ) & 0xff)) + +/** + * Library information. + */ +typedef struct LIB_INFO +{ + const char* title; + const char* build_date; + const char* build_time; + FDK_MODULE_ID module_id; + INT version; + UINT flags; + char versionStr[32]; +} LIB_INFO; + +/** Initialize library info. */ +static inline void FDKinitLibInfo( LIB_INFO* info ) +{ + int i; + + for (i = 0; i < FDK_MODULE_LAST; i++) { + info[i].module_id = FDK_NONE; + } +} + +/** Aquire supported features of library. */ +static inline UINT FDKlibInfo_getCapabilities( const LIB_INFO* info, FDK_MODULE_ID module_id ) +{ + int i; + + for (i=0; i + #ifndef _tstof /* For Visual Studio 6 */ + #ifdef _UNICODE + #include + #define _tstof(x) (float) wcstod(x, NULL) /* For Visual Studio 6 */ + #else + #define _tstof atof + #endif + #endif + + #ifndef _tstol /* For Visual Studio 6 */ + #ifdef _UNICODE + #define _tstol _wtol + #else + #define _tstol atol + #endif + #endif + + #ifndef _tstoi /* For Visual Studio 6 */ + #ifdef _UNICODE + #define _tstoi _wtoi + #else + #define _tstoi atoi + #endif + #endif + + #ifndef TEXTCHAR + #define TEXTCHAR char + #endif + + #ifndef _TEXT + #define _TEXT + #endif + +#else /* WIN32 */ + + #define TEXTCHAR char + #define _tcslen(a) FDKstrlen(a) + #define _tcscpy strcpy + #define _tcscmp FDKstrcmp + #define _tcsncmp FDKstrncmp + #define _tscanf scanf + #define _TEXT(x) x + #define _tfopen fopen + #define _ftprintf fprintf + #define _tcsncpy FDKstrncpy + #define _tstof FDKatof + #define _tstol FDKatol + #define _tstoi FDKatoi + #define _tcstol strtol + #define _istdigit isdigit +#endif /* WIN32 */ + +/* \endcond */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * Scans argc, argv and a scanf style format string for parameters and stores the + * values in the variable number of pointers passed to the function. + + For example: + \code + #define ARG_PARAM "(-a %d) (-v %1)" + #define ARG_VALUE &config->aot, &verbose + int nFoundArgs = IIS_ScanCmdl(argc, argv, ARG_PARAM, ARG_VALUE); + \endcode + wheras the wild-cards (\%d, \%1, ..) define the data type of the argument: + - \%1 boolean (e. g. -x) + - \%d integer (e. g. -x 23) + - \%f float (e. g. -x 3.4) + - \%y double (e. g. -x 31415926535897932384626433832795028841971693993751) + - \%s string (e. g. -x "file.dat") + - \%u unsigned character (e. g. -x 3) + - \%c signed character (e. g. -x -3) + More examples on how to use it are located in every (encoder/decoder) example framework. + + * \param argc Number of arguments. + * \param argv Complete character string of the command line arguments. + * \param pReqArgs A list of parameters and a corresponding list of memory addresses to + * assign each parameter to. + * + * \return Number of found arguments. + */ +INT IIS_ScanCmdl(INT argc, TEXTCHAR* argv[], const TEXTCHAR* pReqArgs, ...); + +#ifdef __cplusplus +} +#endif + +/** + * Reads a text file, assembles argc and argv parameters for each text line + * and calls the given function for each set of argc, argv parameters. + * + * \param param_filename Name of text file that should be parsed. + * \param pFunction Pointer to function that should be called for every text line found. + * + * \return 0 on success, 1 on failure. + */ +INT IIS_ProcessCmdlList(const TEXTCHAR* param_filename, int (*pFunction)(int, TEXTCHAR**)); + + +#endif /* __PARSER_H */ diff --git a/libSYS/include/conv_string.h b/libSYS/include/conv_string.h new file mode 100644 index 0000000..923ae4d --- /dev/null +++ b/libSYS/include/conv_string.h @@ -0,0 +1,74 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (2009) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +/** \file conv_string.h + * \brief String conversion functions. + */ + +#ifndef _CONV_STRING_H +#define _CONV_STRING_H + + + +#include "genericStds.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * \brief Convert a bitbuffer to a hex string. + * \param string Hex string. + * \param charBuf Input buffer that has to be converted. + * \param charBufLength Size of the input buffer. + * \return Error code. + */ +INT charBuf2HexString(char *string, UCHAR *charBuf, INT charBufLength); + +/** + * \brief Convert a hex string to bits. + * \param string Hex string that has to be converted. + * \param charBuf Output buffer holding the bits, will be filled up with zeros. + * \param charBufLength Size of the output buffer. + * \return Error code. + */ +INT hexString2CharBuf(const char *string, UCHAR *charBuf, UINT charBufLength); + +/** + * \brief Convert a character representing a hex sign to the appropriate value. + * \param c Character that has to be converted. + * \return Converted value (value between 0 and 15), if 16, an error has occured. + */ +UCHAR hexChar2Dec(const char c); + +#ifdef __cplusplus +} +#endif + + +#endif /* _CONV_STRING_H */ diff --git a/libSYS/include/genericStds.h b/libSYS/include/genericStds.h new file mode 100644 index 0000000..8009050 --- /dev/null +++ b/libSYS/include/genericStds.h @@ -0,0 +1,421 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (2002) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +/** \file genericStds.h + \brief Generic Run-Time Support function wrappers and heap allocation monitoring. + */ + +#if !defined(__GENERICSTDS_H__) +#define __GENERICSTDS_H__ + +#include "machine_type.h" + +/* Work around for broken android toolchain: sys/types.h:137: error: 'uint64_t' does not name a type */ +#define _SYS_TYPES_H_ + + +/* Always increase verbosity of memory allocation in case of a debug built. DEBUG is defined globally in that case. */ +#if defined(DEBUG) || defined(FDK_DEBUG) +#define MEMORY_MEASUREMENT +#endif + +#ifndef M_PI + #define M_PI 3.14159265358979323846 /*! Pi. Only used in example projects. */ +#endif + + +/* #define _CRT_SECURE_NO_DEPRECATE */ + + +/** + * Identifiers for various memory locations. They are used along with memory allocation + * functions like FDKcalloc_L() to specify the requested memory's location. + */ +typedef enum { + /* Internal */ + SECT_DATA_L1 = 0x2000, + SECT_DATA_L2, + SECT_DATA_L1_A, + SECT_DATA_L1_B, + SECT_CONSTDATA_L1, + + /* External */ + SECT_DATA_EXTERN = 0x4000, + SECT_CONSTDATA_EXTERN + +} MEMORY_SECTION; + + +/** + * The H_ prefix indicates header file version, the C_* prefix indicates the corresponding + * object version. + * + * Declaring memory areas requires to specify a unique name and a data type. Use the H_ macro + * for this purpose inside a header file. + * + * For defining a memory area your require additionally one or two sizes, depending if the + * memory should be organized into one or two dimensions. + * + * The macros containing the keyword AALLOC instead of ALLOC also do take care of returning + * aligned memory addresses (beyond the natural alignment of its type). The preprocesor macro + * ::ALIGNMENT_DEFAULT indicates the aligment to be used (this is hardware specific). + * + * The _L suffix indicates that the memory will be located in a specific section. This is + * useful to allocate critical memory section into fast internal SRAM for example. + * + */ + +#define H_ALLOC_MEM(name,type) type * Get ## name(int n=0); void Free ## name(type** p); \ + UINT GetRequiredMem ## name(void); + +/** See #H_ALLOC_MEM for description. */ +#define H_ALLOC_MEM_OVERLAY(name,type) type * Get ## name(int n=0); void Free ## name(type** p); \ + UINT GetRequiredMem ## name(void); + + + /** See #H_ALLOC_MEM for description. */ + #define C_ALLOC_MEM(name,type,num) \ + type * Get ## name(int n) { FDK_ASSERT((n) == 0); return ((type*)FDKcalloc(num, sizeof(type))); } \ + void Free ## name(type** p) { if (p != NULL) { FDKfree(*p); *p=NULL; } } \ + UINT GetRequiredMem ## name(void) { return ALGN_SIZE_EXTRES((num) * sizeof(type)); } + + /** See #H_ALLOC_MEM for description. */ + #define C_ALLOC_MEM_STATIC(name,type,num) \ + static type * Get ## name(int n) { FDK_ASSERT((n) == 0); return ((type*)FDKcalloc(num, sizeof(type))); } \ + static void Free ## name(type** p) { if (p != NULL) { FDKfree(*p); *p=NULL; } } \ + static UINT GetRequiredMem ## name(void) { return ALGN_SIZE_EXTRES((num) * sizeof(type)); } + + /** See #H_ALLOC_MEM for description. */ + #define C_ALLOC_MEM2(name,type,n1,n2) \ + type * Get ## name (int n) { FDK_ASSERT((n) < (n2)); return ((type*)FDKcalloc(n1, sizeof(type))); } \ + void Free ## name(type** p) { if (p != NULL) { FDKfree(*p); *p=NULL; } } \ + UINT GetRequiredMem ## name(void) { return ALGN_SIZE_EXTRES((n1) * sizeof(type)) * (n2); } + + /** See #H_ALLOC_MEM for description. */ + #define C_AALLOC_MEM(name,type,num) \ + type * Get ## name(int n) { FDK_ASSERT((n) == 0); return ((type*)FDKaalloc((num)*sizeof(type), ALIGNMENT_DEFAULT)); } \ + void Free ## name(type** p) { if (p != NULL) { FDKafree(*p); *p=NULL; } } \ + UINT GetRequiredMem ## name(void) { return ALGN_SIZE_EXTRES((num) * sizeof(type) + ALIGNMENT_DEFAULT + sizeof(void *)); } + + /** See #H_ALLOC_MEM for description. */ + #define C_AALLOC_MEM2(name,type,n1,n2) \ + type * Get ## name (int n) { FDK_ASSERT((n) < (n2)); return ((type*)FDKaalloc((n1)*sizeof(type), ALIGNMENT_DEFAULT)); } \ + void Free ## name(type** p) { if (p != NULL) { FDKafree(*p); *p=NULL; } } \ + UINT GetRequiredMem ## name(void) { return ALGN_SIZE_EXTRES((n1) * sizeof(type) + ALIGNMENT_DEFAULT + sizeof(void *)) * (n2); } + + /** See #H_ALLOC_MEM for description. */ + #define C_ALLOC_MEM_L(name,type,num,s) \ + type * Get ## name(int n) { FDK_ASSERT((n) == 0); return ((type*)FDKcalloc_L(num, sizeof(type), s)); } \ + void Free ## name(type** p) { if (p != NULL) { FDKfree_L(*p); *p=NULL; } } \ + UINT GetRequiredMem ## name(void) { return ALGN_SIZE_EXTRES((num) * sizeof(type)); } + + /** See #H_ALLOC_MEM for description. */ + #define C_ALLOC_MEM2_L(name,type,n1,n2,s) \ + type * Get ## name (int n) { FDK_ASSERT((n) < (n2)); return (type*)FDKcalloc_L(n1, sizeof(type), s); } \ + void Free ## name(type** p) { if (p != NULL) { FDKfree_L(*p); *p=NULL; } } \ + UINT GetRequiredMem ## name(void) { return ALGN_SIZE_EXTRES((n1) * sizeof(type)) * (n2); } + + /** See #H_ALLOC_MEM for description. */ + #define C_AALLOC_MEM_L(name,type,num,s) \ + type * Get ## name(int n) { FDK_ASSERT((n) == 0); return ((type*)FDKaalloc_L((num)*sizeof(type), ALIGNMENT_DEFAULT, s)); } \ + void Free ## name(type** p) { if (p != NULL) { FDKafree_L(*p); *p=NULL; } } \ + UINT GetRequiredMem ## name(void) { return ALGN_SIZE_EXTRES((num) * sizeof(type) + ALIGNMENT_DEFAULT + sizeof(void *)); } + + /** See #H_ALLOC_MEM for description. */ + #define C_AALLOC_MEM2_L(name,type,n1,n2,s) \ + type * Get ## name (int n) { FDK_ASSERT((n) < (n2)); return ((type*)FDKaalloc_L((n1)*sizeof(type), ALIGNMENT_DEFAULT, s)); } \ + void Free ## name(type** p) { if (p != NULL) { FDKafree_L(*p); *p=NULL; } } \ + UINT GetRequiredMem ## name(void) { return ALGN_SIZE_EXTRES((n1) * sizeof(type) + ALIGNMENT_DEFAULT + sizeof(void *)) * (n2); } + +/** See #H_ALLOC_MEM_OVERLAY for description. */ + + + #define C_ALLOC_MEM_OVERLAY(name,type,num,sect,tag) C_AALLOC_MEM_L(name,type,num,sect) + + + #define C_AALLOC_SCRATCH_START(name,type,n) \ + type _ ## name[(n)+(ALIGNMENT_DEFAULT+sizeof(type)-1)]; \ + type * name = (type*)ALIGN_PTR(_ ## name); \ + + #define C_ALLOC_SCRATCH_START(name,type,n) \ + type name[n]; + + #define C_AALLOC_SCRATCH_END(name,type,n) + #define C_ALLOC_SCRATCH_END(name,type,n) + + +/*-------------------------------------------- + * Runtime support declarations + *---------------------------------------------*/ +#ifdef __cplusplus +extern "C" { +#endif + +/** printf() using stdout. If ::ARCH_WA_FLUSH_CONSOLE defined, a flush is done additionally after printf(). */ +void FDKprintf ( const char* szFmt, ...); + +/** printf() using stderr. If ::ARCH_WA_FLUSH_CONSOLE defined, a flush is done additionally after printf(). */ +void FDKprintfErr ( const char* szFmt, ...); + +/** Wrapper for 's getchar(). */ +int FDKgetchar(void); + +INT FDKfprintf(void *stream, const char *format, ...); +INT FDKsprintf(char *str, const char *format, ...); + + + +const char *FDKstrchr(const char *s, INT c); +const char *FDKstrstr(const char *haystack, const char *needle); +char *FDKstrcpy(char *dest, const char *src); +char *FDKstrncpy(char *dest, const char *src, const UINT n); + +#define FDK_MAX_OVERLAYS 8 /**< Maximum number of memory overlays. */ + + +void *FDKcalloc (const UINT n, const UINT size); +void *FDKmalloc (const UINT size); +void FDKfree (void *ptr); + +/** + * Allocate and clear an aligned memory area. Use FDKafree() instead of FDKfree() for these memory areas. + * + * \param size Size of requested memory in bytes. + * \param alignment Alignment of requested memory in bytes. + * \return Pointer to allocated memory. + */ +void *FDKaalloc (const UINT size, const UINT alignment); + +/** + * Free an aligned memory area. + * + * \param ptr Pointer to be freed. + * \return void + */ +void FDKafree (void *ptr); + + +/** + * Allocate memory in a specific memory section. + * Requests can be made for internal or external memory. If internal memory is + * requested, FDKcalloc_L() first tries to use L1 memory, which sizes are defined + * by ::DATA_L1_A_SIZE and ::DATA_L1_B_SIZE. If no L1 memory is available, then + * FDKcalloc_L() tries to use L2 memory. If that fails as well, the requested + * memory is allocated at an extern location using the fallback FDKcalloc(). + * + * \param n See MSDN documentation on calloc(). + * \param size See MSDN documentation on calloc(). + * \param s Memory section. + * \return See MSDN documentation on calloc(). + */ +void *FDKcalloc_L(const UINT n, const UINT size, MEMORY_SECTION s); + +/** + * Allocate aligned memory in a specific memory section. + * See FDKcalloc_L() description for details - same applies here. + */ +void *FDKaalloc_L(const UINT size, const UINT alignment, MEMORY_SECTION s); + +/** + * Free memory that was allocated in a specific memory section. + */ +void FDKfree_L(void *ptr); + +/** + * Free aligned memory that was allocated in a specific memory section. + */ +void FDKafree_L(void *ptr); + + +/** + * Copy memory. Source and destination memory must not overlap. + * Either use implementation from a Standard Library, or, if no Standard Library + * is available, a generic implementation. + * The define ::USE_BUILTIN_MEM_FUNCTIONS in genericStds.cpp controls what to use. + * The function arguments correspond to the standard memcpy(). Please see MSDN + * documentation for details on how to use it. + */ +void FDKmemcpy(void *dst, const void *src, const UINT size); + +/** + * Copy memory. Source and destination memory are allowed to overlap. + * Either use implementation from a Standard Library, or, if no Standard Library + * is available, a generic implementation. + * The define ::USE_BUILTIN_MEM_FUNCTIONS in genericStds.cpp controls what to use. + * The function arguments correspond to the standard memmove(). Please see MSDN + * documentation for details on how to use it. +*/ +void FDKmemmove(void *dst, const void *src, const UINT size); + +/** + * Clear memory. + * Either use implementation from a Standard Library, or, if no Standard Library + * is available, a generic implementation. + * The define ::USE_BUILTIN_MEM_FUNCTIONS in genericStds.cpp controls what to use. + * The function arguments correspond to the standard memclear(). Please see MSDN + * documentation for details on how to use it. +*/ +void FDKmemclear(void *memPtr, const UINT size); + +/** + * Fill memory with values. + * The function arguments correspond to the standard memset(). Please see MSDN + * documentation for details on how to use it. + */ +void FDKmemset(void *memPtr, const INT value, const UINT size); + +/* Compare function wrappers */ +INT FDKmemcmp(const void *s1, const void *s2, const UINT size); +INT FDKstrcmp(const char *s1, const char *s2); +INT FDKstrncmp(const char *s1, const char *s2, const UINT size); + +UINT FDKstrlen(const char *s); + +#define FDKmax(a,b) ( (a) > (b) ? (a):(b)) +#define FDKmin(a,b) ( (a) < (b) ? (a):(b)) + +#define FDK_INT_MAX ((INT)0x7FFFFFFF) +#define FDK_INT_MIN ((INT)0x80000000) + +/* Math function wrappers. Only intended for compatibility, not to be highly optimized. */ +/* Used for debugging, dev code .. */ + +INT FDKabs(INT j); +double FDKfabs(double x); +double FDKpow(double x, double y); +double FDKsqrt(double x); +double FDKatan(double x); +double FDKlog(double x); +double FDKsin(double x); +double FDKcos(double x); +double FDKexp(double x); +#define FDKlog2(a) (FDKlog(a)*1.442695041) /* log(2.0) = 1.442695041 */ +#define FDKlog10(a) (FDKlog(a)*0.434294482) /* 1.0/log(10.0) = 0.434294482 */ +double FDKatan2(double y, double x); +double FDKacos(double x); +double FDKtan(double x); +double FDKfloor(double x); +double FDKceil(double x); +INT FDKatoi(const char *nptr); +long FDKatol(const char *nptr); +float FDKatof(const char *nptr); +/* LONG LONG FDKatoll(const char *nptr); */ +/* LONG LONG FDKatoq(const char *nptr); */ + + + +/* FILE I/O */ + +/*! + * Check platform for endianess. + * + * \return 1 if platform is little endian, non-1 if platform is big endian. + */ +#ifdef __cplusplus +inline +#else +static +#endif +int IS_LITTLE_ENDIAN(void) { + int __dummy = 1; + return ( *( (UCHAR*)(&(__dummy) ) ) ); +} + +/*! + * Convert input value to little endian format. + * + * \param val Value to be converted. It may be in both big or little endian. + * \return Value in little endian format. + */ +#define TO_LITTLE_ENDIAN(val) \ + ( (IS_LITTLE_ENDIAN()) ? \ + (val) \ + : ( (((val) & 0xff) << 24) || (((val) & 0xff00)<< 8) || (((val) & 0xff0000)>>8) || (((val) & 0xff000000) >> 24) ) ) + + +/*! + * \fn FDKFILE *FDKfopen(const char *filename, const char *mode); + * Standard fopen() wrapper. + * \fn INT FDKfclose(FDKFILE *FP); + * Standard fclose() wrapper. + * \fn INT FDKfseek(FDKFILE *FP, LONG OFFSET, int WHENCE); + * Standard fseek() wrapper. + * \fn INT FDKftell(FDKFILE *FP); + * Standard ftell() wrapper. + * \fn INT FDKfflush(FDKFILE *fp); + * Standard fflush() wrapper. + * \fn UINT FDKfwrite(void *ptrf, INT size, UINT nmemb, FDKFILE *fp); + * Standard fwrite() wrapper. + * \fn UINT FDKfread(void *dst, INT size, UINT nmemb, FDKFILE *fp); + * Standard fread() wrapper. + */ +typedef void FDKFILE; +extern const INT FDKSEEK_SET, FDKSEEK_CUR, FDKSEEK_END; + +FDKFILE *FDKfopen(const char *filename, const char *mode); +INT FDKfclose(FDKFILE *FP); +INT FDKfseek(FDKFILE *FP, LONG OFFSET, int WHENCE); +INT FDKftell(FDKFILE *FP); +INT FDKfflush(FDKFILE *fp); +UINT FDKfwrite(void *ptrf, INT size, UINT nmemb, FDKFILE *fp); +UINT FDKfread(void *dst, INT size, UINT nmemb, FDKFILE *fp); +char* FDKfgets(void *dst, INT size, FDKFILE *fp); +void FDKrewind(FDKFILE *fp); +INT FDKfeof(FDKFILE *fp); + +/** + * \brief Write each member in little endian order. Convert automatically to host endianess. + * \param ptrf Pointer to memory where to read data from. + * \param size Size of each item to be written. + * \param nmemb Number of items to be written. + * \param fp File pointer of type FDKFILE. + * \return Number of items read on success and fread() error on failure. + */ +UINT FDKfwrite_EL(void *ptrf, INT size, UINT nmemb, FDKFILE *fp); + +/** + * \brief Read variable of size "size" as little endian. Convert automatically to host endianess. + * 4-byte alignment is enforced for 24 bit data, at 32 bit full scale. + * \param dst Pointer to memory where to store data into. + * \param size Size of each item to be read. + * \param nmemb Number of items to be read. + * \param fp File pointer of type FDKFILE. + * \return Number of items read on success and fread() error on failure. + */ +UINT FDKfread_EL(void *dst, INT size, UINT nmemb, FDKFILE *fp); + + +/** + * \brief Print FDK software disclaimer. + */ +void FDKprintDisclaimer(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __GENERICSTDS_H__ */ diff --git a/libSYS/include/machine_type.h b/libSYS/include/machine_type.h new file mode 100644 index 0000000..6b9b7e6 --- /dev/null +++ b/libSYS/include/machine_type.h @@ -0,0 +1,295 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (2003) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +/** \file machine_type.h + * \brief Type defines for various processors and compiler tools. + */ + +#if !defined(__MACHINE_TYPE_H__) +#define __MACHINE_TYPE_H__ + + +/* Library calling convention spec. __cdecl and friends might be added here as required. */ + #define LINKSPEC_H + #define LINKSPEC_CPP + + +/** + * collate all corresponding compiler specific macros to detect a debug build, and set the DEBUG macro if that is the case. + */ +#if defined(_DEBUG) +#define DEBUG +#endif + + +/* for doxygen the following docu parts must be separated */ +/** \var SCHAR + * Data type representing at least 1 byte signed integer on all supported platforms. + */ +/** \var UCHAR + * Data type representing at least 1 byte unsigned integer on all supported platforms. + */ +/** \var INT + * Data type representing at least 4 byte signed integer on all supported platforms. + */ +/** \var UINT + * Data type representing at least 4 byte unsigned integer on all supported platforms. + */ +/** \var LONG + * Data type representing 4 byte signed integer on all supported platforms. + */ +/** \var ULONG + * Data type representing 4 byte unsigned integer on all supported platforms. + */ +/** \var SHORT + * Data type representing 2 byte signed integer on all supported platforms. + */ +/** \var USHORT + * Data type representing 2 byte unsigned integer on all supported platforms. + */ +/** \var INT64 + * Data type representing 8 byte signed integer on all supported platforms. + */ +/** \var UINT64 + * Data type representing 8 byte unsigned integer on all supported platforms. + */ +/** \def SHORT_BITS + * Number of bits the data type short represents. sizeof() is not suited to get this info, + * because a byte is not always defined as 8 bits. + */ +/** \def CHAR_BITS + * Number of bits the data type char represents. sizeof() is not suited to get this info, + * because a byte is not always defined as 8 bits. + */ +/** \var INT_PCM + * Data type representing the width of input and output PCM samples. + */ + + + typedef signed int INT; + typedef unsigned int UINT; +#ifdef __x86_64__ + /* force FDK long-datatypes to 4 byte */ + /* jdr: Use defines to avoid type alias problems on 64 bit machines. */ + #define LONG INT + #define ULONG UINT +#else /* __x86_64__ */ + typedef signed long LONG; + typedef unsigned long ULONG; +#endif /* __x86_64__ */ + typedef signed short SHORT; + typedef unsigned short USHORT; + typedef signed char SCHAR; + typedef unsigned char UCHAR; + + #define SHORT_BITS 16 + #define CHAR_BITS 8 + + +/* Define 64 bit base integer type. */ +#ifdef _WIN32 + typedef __int64 INT64; + typedef unsigned __int64 UINT64; +#else + typedef long long INT64; + typedef unsigned long long UINT64; +#endif + +#ifndef NULL + #ifdef __cplusplus + #define NULL 0 + #else + #define NULL ((void *)0) + #endif +#endif + +/* Assert is functional on x86 PC's and also when debugging is turned on. */ +#if defined(DEBUG) || defined(__i686__) || defined(__i586__) || defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(FDK_DEBUG) || defined(FDK_ASSERT_ENABLE) + #include + #define FDK_ASSERT(x) assert(x) +#else + #define FDK_ASSERT(ignore) +#endif + + typedef SHORT INT_PCM; + #define WAV_BITS 16 + #define SAMPLE_BITS 16 + #define SAMPLE_MAX (((LONG)1<<(SAMPLE_BITS-1))-1) + #define SAMPLE_MIN (~SAMPLE_MAX) + +/*! +* \def RAM_ALIGN +* Used to align memory as prefix before memory declaration. For example: + \code + RAM_ALIGN + int myArray[16]; + \endcode + + Note, that not all platforms support this mechanism. For example with TI compilers + a preprocessor pragma is used, but to do something like + + \code + #define RAM_ALIGN #pragma DATA_ALIGN(x) + \encode + + would require the preprocessor to process this line twice to fully resolve it. Hence, + a fully platform-independant way to use alignment is not supported. + +* \def ALIGNMENT_DEFAULT +* Default alignment in bytes. +*/ +#if defined(__GNUC__) /* cppp replaced: elif */ + #define ALIGNMENT_DEFAULT 8 + #define RAM_ALIGN __attribute__((aligned(ALIGNMENT_DEFAULT))) +#else + #define ALIGNMENT_DEFAULT 8 + #define RAM_ALIGN +#endif + + +/*! +* \def RESTRICT +* The restrict keyword is supported by some platforms and RESTRICT maps to +* either the corresponding keyword on each platform or to void if the +* compiler does not provide such feature. +* +* \def WORD_ALIGNED(x) +* Tells the compiler that pointer x is WORD aligned. +* At the moment only supported by TI compilers. +* +* \def DWORD_ALIGNED(x) +* Tells the compiler that pointer x is DWORD aligned. +* At the moment only supported by TI compilers. +*/ + #define RESTRICT + #define WORD_ALIGNED(x) + #define DWORD_ALIGNED(x) + + +/*----------------------------------------------------------------------------------- + * ALIGN_SIZE + *-----------------------------------------------------------------------------------*/ +/*! + * \brief This macro aligns a given value depending on ::ALIGNMENT_DEFAULT. + * + * For example if #ALIGNMENT_DEFAULT equals 8, then: + * - ALIGN_SIZE(3) returns 8 + * - ALIGN_SIZE(8) returns 8 + * - ALIGN_SIZE(9) returns 16 + */ +#define ALIGN_SIZE(a) ((a)+ (((INT)ALIGNMENT_DEFAULT - ((INT)(a) & (ALIGNMENT_DEFAULT-1)) ) & (ALIGNMENT_DEFAULT-1))) + +/*----------------------------------------------------------------------------------- + * ALIGN_PTR + * cast (a) to width of pointer + *-----------------------------------------------------------------------------------*/ +/*! + * \brief This macro aligns a given address depending on ::ALIGNMENT_DEFAULT. + */ +#define ALIGN_PTR(a) ( (unsigned char*)(a) + (((INT)ALIGNMENT_DEFAULT - ((INT)(UINT64)(a) & (ALIGNMENT_DEFAULT-1)) ) & (ALIGNMENT_DEFAULT-1)) ) + + /* Alignment macro for libSYS heap implementation */ +#define ALIGNMENT_EXTRES ( ALIGNMENT_DEFAULT ) +#define ALGN_SIZE_EXTRES(a) ((a)+ (((INT)ALIGNMENT_EXTRES - ((INT)(a) & (ALIGNMENT_EXTRES-1)) ) & (ALIGNMENT_EXTRES-1))) + + +/*! + * \def FORCEINLINE + * Sometimes compiler do not do what they are told to do, and in case of inlining some + * additional command might be necessary depending on the platform. + * + * \def FDK_INLINE + * Defines how the compiler is told to inline stuff. + */ +#ifdef DEBUG +#undef FORCEINLINE +#define FORCEINLINE +#else +#ifndef FORCEINLINE + #if defined(__GNUC__) /* cppp replaced: elif */ + #define FORCEINLINE __attribute((always_inline)) + #else + #define FORCEINLINE + #endif +#endif +#endif + + /* for all other platforms */ + #define FDK_INLINE inline + + +/*! + * \def LNK_SECTION_DATA_L1 + * The LNK_SECTION_* defines allow memory to be drawn from specific memory + * sections. Used as prefix before variable declaration. + * + * \def LNK_SECTION_DATA_L2 + * See ::LNK_SECTION_DATA_L1 + * \def LNK_SECTION_L1_DATA_A + * See ::LNK_SECTION_DATA_L1 + * \def LNK_SECTION_L1_DATA_B + * See ::LNK_SECTION_DATA_L1 + * \def LNK_SECTION_CONSTDATA_L1 + * See ::LNK_SECTION_DATA_L1 + * \def LNK_SECTION_CONSTDATA + * See ::LNK_SECTION_DATA_L1 + * \def LNK_SECTION_CODE_L1 + * See ::LNK_SECTION_DATA_L1 + * \def LNK_SECTION_CODE_L2 + * See ::LNK_SECTION_DATA_L1 + * \def LNK_SECTION_INITCODE + * See ::LNK_SECTION_DATA_L1 + */ +/************************************************** + * Code Section macros + **************************************************/ + #define LNK_SECTION_CODE_L1 + #define LNK_SECTION_CODE_L2 + #define LNK_SECTION_INITCODE + +/* Memory section macros. */ + + /* default fall back */ + #define LNK_SECTION_DATA_L1 + #define LNK_SECTION_DATA_L2 + #define LNK_SECTION_CONSTDATA + #define LNK_SECTION_CONSTDATA_L1 + + #define LNK_SECTION_L1_DATA_A + #define LNK_SECTION_L1_DATA_B + + +#ifdef _MSC_VER + /* + * Sometimes certain features are excluded from compilation and therefore the warning 4065 may occur: + * "switch statement contains 'default' but no 'case' labels" + * We consider this warning irrelevant and disable it. + */ + #pragma warning( disable : 4065 ) +#endif + +#endif /* __MACHINE_TYPE_H__ */ diff --git a/libSYS/include/wav_file.h b/libSYS/include/wav_file.h new file mode 100644 index 0000000..bebf112 --- /dev/null +++ b/libSYS/include/wav_file.h @@ -0,0 +1,150 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (2000) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Eric Allamanche + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +/** \file wav_file.h + * \brief Rudimentary WAVE file read/write support. + * + * The WAVE file reader/writer is intented to be used in the codec's example + * framework for easily getting started with encoding/decoding. Therefore + * it serves mainly for helping quickly understand how a codec's API actually + * works. + * Being a WAVE file reader/writer with very basic functionality, it may not be + * able to read WAVE files that come with unusual configurations. + * Details on how to use the interface functions can be found in every + * (encoder/decoder) example framework. + */ + +#ifndef __WAV_FILE_H__ +#define __WAV_FILE_H__ + + + +#include "genericStds.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * RIFF WAVE file struct. + * For details see WAVE file format documentation (for example at http://www.wotsit.org). + */ +typedef struct WAV_HEADER +{ + char riffType[4]; + UINT riffSize; + char waveType[4]; + char formatType[4]; + UINT formatSize; + USHORT compressionCode; + USHORT numChannels; + UINT sampleRate; + UINT bytesPerSecond; + USHORT blockAlign; + USHORT bitsPerSample; + char dataType[4]; + UINT dataSize; +} WAV_HEADER; + +struct WAV +{ + WAV_HEADER header; + FDKFILE *fp; +}; + +typedef struct WAV *HANDLE_WAV; + +/** + * \brief Open a WAV file handle for reading. + * + * \param pWav Pointer to a memory location, where a WAV handle is returned. + * \param filename File name to be opened. + * + * \return 0 on success and non-zero on failure. + */ +INT WAV_InputOpen (HANDLE_WAV *pWav, const char *filename); + +/** + * \brief Read samples from a WAVE file. The samples are automatically re-ordered to the + * native host endianess and scaled to full scale of the INT_PCM type, from + * whatever BPS the WAVE file had specified in its header data. + * + * \param wav Handle of WAV file. + * \param sampleBuffer Pointer to store audio data. + * \param numSamples Desired number of samples to read. + * \param nBufBits Size in bit of each audio sample of sampleBuffer. + * + * \return Number of samples actually read. + */ +INT WAV_InputRead (HANDLE_WAV wav, void *sampleBuffer, UINT numSamples, int nBufBits); + +/** + * \brief Close a WAV file reading handle. + * \param pWav Pointer to a WAV file reading handle. + * \return void + */ +void WAV_InputClose(HANDLE_WAV *pWav); + +/** + * \brief Open WAV output/writer handle. + * + * \param pWav Pointer to WAV handle to be returned. + * \param outputFilename File name of the file to be written to. + * \param sampleRate Desired samplerate of the resulting WAV file. + * \param numChannels Desired number of audio channels of the resulting WAV file. + * \param bitsPerSample Desired number of bits per audio sample of the resulting WAV file. + * + * \return 0: ok; -1: error + */ +INT WAV_OutputOpen(HANDLE_WAV *pWav, const char *outputFilename, INT sampleRate, INT numChannels, INT bitsPerSample); + +/** + * \brief Write data to WAV file asociated to WAV handle. + * + * \param wav Handle of WAV file + * \param sampleBuffer Pointer to audio samples, right justified integer values. + * \param numberOfSamples The number of individual audio sample valuesto be written. + * \param nBufBits Size in bits of each audio sample in sampleBuffer. + * \param nSigBits Amount of significant bits of each nBufBits in sampleBuffer. + * + * \return 0: ok; -1: error + */ +INT WAV_OutputWrite(HANDLE_WAV wav, void *sampleBuffer, UINT numberOfSamples, int nBufBits, int nSigBits); + +/** + * \brief Close WAV output handle. + * \param pWav Pointer to WAV handle. *pWav is set to NULL. + * \return void + */ +void WAV_OutputClose(HANDLE_WAV *pWav); + +#ifdef __cplusplus +} +#endif + + +#endif /* __WAV_FILE_H__ */ diff --git a/libSYS/src/Android.mk b/libSYS/src/Android.mk new file mode 100644 index 0000000..5078535 --- /dev/null +++ b/libSYS/src/Android.mk @@ -0,0 +1,19 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + cmdl_parser.cpp \ + conv_string.cpp \ + genericStds.cpp \ + wav_file.cpp + +LOCAL_CFLAGS := -DANDROID + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../../libFDK/include + +LOCAL_MODULE:= libSYS + +include $(BUILD_STATIC_LIBRARY) diff --git a/libSYS/src/cmdl_parser.cpp b/libSYS/src/cmdl_parser.cpp new file mode 100644 index 0000000..a2578c3 --- /dev/null +++ b/libSYS/src/cmdl_parser.cpp @@ -0,0 +1,522 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (1999) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: command line parser + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + + + +#define _CRT_SECURE_NO_WARNINGS + +/* Work around for broken android toolchain: sys/types.h:137: error: 'uint64_t' does not name a type */ +#define _SYS_TYPES_H_ + +#include +#include +#include +#include +#include + +#include "cmdl_parser.h" +#include "genericStds.h" + + + +/************************ interface ************************/ + +static INT GetArgFromString(INT argc, TEXTCHAR* argv[], TEXTCHAR* search_string, TEXTCHAR type, TEXTCHAR* found_string , INT* switches_used); +static void RemoveWhiteSpace(const TEXTCHAR* pReqArgs, TEXTCHAR* Removed); +static INT CheckArg(TEXTCHAR* arg, TEXTCHAR* str, UINT numArgs, TEXTCHAR type, TEXTCHAR* current_str); +static INT CheckForUnusedSwitches(INT argc, /*TEXTCHAR* argv[],*/ INT* switches_used); +static INT ParseString(TEXTCHAR* str, INT*, TEXTCHAR*, TEXTCHAR*); +static void GetNumberOfArgs(TEXTCHAR* str, INT* nArgs); + +static +void removeQuotes(char *str) +{ + if (str[0] == '"') { + FDKstrcpy(str, str+1); + str[FDKstrlen(str)-1] = 0; + } +} + + +/********************** implementation *********************/ + +INT IIS_ScanCmdl(INT argc, TEXTCHAR* argv[], const TEXTCHAR* str, ...) +{ + INT i = 0; + INT found_and_set = 0; + INT nArgs = 0; + INT* switches_used = 0; + INT* b_str_opt = 0; + TEXTCHAR* s_str = 0; + TEXTCHAR* c_str_type = 0; + TEXTCHAR* str_clean = 0; + + va_list ap; + + if (argc == 0 || argc == 1) + { + FDKprintf("No command line arguments\n"); + goto bail; + } + + str_clean = (TEXTCHAR*) FDKcalloc((unsigned int)_tcslen(str), sizeof(TEXTCHAR)); + if (str_clean == NULL) { + FDKprintf("Error allocating memory line %d, file %s\n", __LINE__, __FILE__); + return 0; + } + + RemoveWhiteSpace(str, str_clean ); + GetNumberOfArgs(str_clean, &nArgs); + + b_str_opt = (INT*) FDKcalloc(nArgs, sizeof(INT)); + s_str = (TEXTCHAR*) FDKcalloc(nArgs*CMDL_MAX_ARGC, sizeof(TEXTCHAR) ); + c_str_type = (TEXTCHAR*) FDKcalloc(nArgs, sizeof(TEXTCHAR)); + switches_used = (INT*) FDKcalloc(argc, sizeof(INT)); + + if (b_str_opt == NULL || s_str == NULL || c_str_type == NULL || switches_used == NULL) { + FDKprintf("Error allocating memory line %d, file %s\n", __LINE__, __FILE__); + goto bail; + } + + if ( ParseString( str_clean, b_str_opt, s_str, c_str_type )) { + goto bail; + } + + va_start(ap, str); + + for ( i = 0; i < nArgs; i++ ) + { + TEXTCHAR arg[CMDL_MAX_STRLEN] = {L'\0'}; + TEXTCHAR* p_arg = arg; + TEXTCHAR* current_str = &(s_str[i*CMDL_MAX_ARGC]); + + if (GetArgFromString(argc, argv, current_str, c_str_type[i], arg, switches_used ) + && !b_str_opt[i] ) + { +#ifdef _UNICODE + _ftprintf(stderr, _TEXT("\n\nError: Parsing argument for required switch '%ls'.\n" ), current_str); +#else + _ftprintf(stderr, _TEXT("\n\nError: Parsing argument for required switch '%s'.\n" ), current_str); +#endif + found_and_set = 0; + goto bail; + } + if (CheckArg(p_arg, s_str, nArgs, c_str_type[i], current_str)) + { + goto bail; + } + + switch (c_str_type[i] ) + { + case 's': + { + TEXTCHAR* tmp; + tmp = va_arg(ap, TEXTCHAR*); + + if ( arg[0] == '\0' ) + break; + + _tcsncpy( tmp, arg, CMDL_MAX_STRLEN ); + /* Remove quotes. Windows Mobile Workaround. */ + removeQuotes(tmp); + found_and_set++; + break; + } + case 'd': + { + INT* tmp = va_arg(ap, INT*); + + if ( arg[0] == '\0' ) + break; + + *tmp = _tcstol(arg, NULL, 0); + found_and_set++; + break; + } + case 'c': + { + char* tmp = va_arg(ap, char*); + + if ( arg[0] == '\0' ) + break; + + *tmp = *arg; + found_and_set++; + break; + } + case 'u': + { + UCHAR* tmp = va_arg(ap, UCHAR*); + + if ( arg[0] == '\0' ) + break; + + *tmp = _tstoi(arg); + found_and_set++; + break; + } + case 'f': + { + float* tmp = (float*) va_arg( ap,double*); + + if ( arg[0] == '\0' ) + break; + + *tmp = (float) _tstof(arg); + found_and_set++; + break; + } + case 'y': // support 'data type double' + { + double* tmp = (double*) va_arg( ap,double*); + // use sscanf instead _tstof because of gcc + //_tstof(arg,"%lf",tmp); // '%lf' reads as double + *tmp = _tstof(arg); // '%lf' reads as double + found_and_set++; + break; + } + case '1': + { + + INT* tmp = va_arg( ap, INT*); + + if ( arg[0] == '\0' ) + break; + + *tmp = 1; + found_and_set++; + break; + } + + default: + FDKprintfErr("Bug: unsupported data identifier \"%c\"\n", c_str_type[i]); + break; + + } + + } + + va_end(ap); + + CheckForUnusedSwitches(argc, /*argv,*/ switches_used); + +bail: + if (b_str_opt) FDKfree(b_str_opt); + if (s_str) FDKfree(s_str); + if (c_str_type) FDKfree(c_str_type); + if (str_clean) FDKfree(str_clean); + if (switches_used) FDKfree(switches_used); + + return found_and_set; +} + + +void GetNumberOfArgs(TEXTCHAR* str, INT* nArgs) +{ + UINT i = 0; + for ( i = 0; i < _tcslen(str); ++i ) + { + if ( str[i] == '%') + *nArgs+= 1; + } + +} + +INT ParseString(TEXTCHAR* str, INT* b_str_opt, TEXTCHAR* s_str, TEXTCHAR* c_str_type ) +{ + UINT i = 0; + INT argCounter = 0; + + TEXTCHAR* str_start = 0; + TEXTCHAR* str_stop = 0; + + + str_start = str; + str_stop = str_start; + + for ( i = 0; i < _tcslen(str) - 1; ++i ) + { + if ( str[i] == '%' ) /* We have an Argument */ + { + if ( argCounter ) + { + if ( b_str_opt[argCounter-1] ) + str_start = str_stop + 3; + + else + str_start = str_stop + 2; + } + + /* Save Argument type */ + c_str_type[argCounter] = str[i+1]; + + if ( *str_start == '(' ) /* Optional Argument */ + { + b_str_opt[argCounter] = 1; + str_start++; + } + + /* Save Argument */ + str[i] = '\0'; + + _tcsncpy(&(s_str[argCounter*CMDL_MAX_ARGC]), str_start, CMDL_MAX_ARGC ); + + str[i] = '%'; + + str_stop = &(str[i]); + + if ( b_str_opt[argCounter] ) + { + if ( i+2 > ( _tcslen(str) -1 )) + { + _ftprintf(stderr,_TEXT("\n\nInternal Parser Error: Strlen Problem\n") ); + return 1; + } + if ( str[i+2] != ')' ) + { + _ftprintf(stderr,_TEXT("\n\nInternal Parser Error: Missing bracket ')'\n") ); + return 1; + } + + } + + + argCounter++; + } + + + } + + return 0; + } + + + + +void RemoveWhiteSpace(const TEXTCHAR* pReqArgs, TEXTCHAR* pRemoved) +{ + UINT i = 0; + INT k = 0; + UINT len = (UINT)_tcslen(pReqArgs); + + + for ( i = 0; i < len; ++i ) + { + + if ( pReqArgs[i] != ' ' ) + { + pRemoved[k] = pReqArgs[i]; + k++; + } + } +} + + +INT GetArgFromString(INT argc, TEXTCHAR* argv[], TEXTCHAR* search_string, TEXTCHAR type, TEXTCHAR* found_string, INT* sw_used ) +{ + INT i = 0; + + for (i = 1; i < argc; ++i ) { + if ( !_tcscmp(search_string, argv[i]) ) /* Strings are equal */ + { + if ( type == '1' ) /* Switch without argument */ + { + _tcsncpy( found_string, _TEXT("1"), 1); + sw_used[i] = 1; + return 0; + + } + + if ( i == (argc - 1)) /* We have %s or %d but are finished*/ + return 1; + + if ( _tcslen(argv[i+1]) > CMDL_MAX_STRLEN ) + { +#ifdef _UNICODE + _ftprintf (stderr,_TEXT("Warning: Ignoring argument for switch '%ls'. "), search_string ); +#else + _ftprintf (stderr,_TEXT("Warning: Ignoring argument for switch '%s'. "), search_string ); +#endif + _ftprintf (stderr,_TEXT("Argument is too LONG.\n") ); + return 1; + } + else + { + _tcsncpy( found_string, argv[i+1], CMDL_MAX_STRLEN); + sw_used[i] = 1; + sw_used[i+1] = 1; + return 0; + } + } + } + return 1; +} + + + +INT CheckArg(TEXTCHAR* arg, TEXTCHAR* str, UINT numArgs, TEXTCHAR type, TEXTCHAR* cur_str) +{ + UINT i = 0; + + /* No argument given-> return */ + if (arg[0] == '\0') + return 0; + + + /* Check if arg is switch */ + for ( i = 0; i < numArgs; ++i ) + { + if (!_tcscmp(arg, &(str[i*CMDL_MAX_ARGC]))) + { +#ifdef _UNICODE + _ftprintf(stderr, _TEXT("\n\nError: Argument '%ls' for switch '%ls' is not valid \n" ), arg, cur_str ); +#else + _ftprintf(stderr, _TEXT("\n\nError: Argument '%s' for switch '%s' is not valid \n" ), arg, cur_str ); +#endif + return 1; + } + + } + /* Check if type is %d but a string is given */ + + for ( i = 0; i < _tcslen(arg); ++i ) + { + if ( (type == 'd') && !_istdigit(arg[i]) && arg[i] != 'x' ) + { +#ifdef _UNICODE + _ftprintf(stderr, _TEXT("\n\nError: Argument '%ls' for switch '%ls' is not a valid number.\n" ), arg, cur_str); +#else + _ftprintf(stderr, _TEXT("\n\nError: Argument '%s' for switch '%s' is not a valid number.\n" ), arg, cur_str); +#endif + return 1; + } + } + + + return 0; +} + + +INT CheckForUnusedSwitches(INT argc, /*TEXTCHAR* argv[],*/ INT* switches_used) +{ + INT i = 0; + + for( i = 1; i < argc; ++i ) + { + if ( !switches_used[i] ) + { + ++i; + } + } + + return 0; +} + + + +static char line[CMDL_MAX_STRLEN*CMDL_MAX_ARGC]; +static char *argv_ptr[CMDL_MAX_ARGC]; +#ifdef CMDFILE_PREFIX +static char tmp[256]; /* this array is used to store the prefix and the filepath/name */ +#endif + +int IIS_ProcessCmdlList(const char* param_filename, int (*pFunction)(int, TEXTCHAR**)) +{ + /* static to reduce required stack size */ + + FDKFILE *config_fp; + int argc; + char *line_ptr; + +#ifdef CMDFILE_PREFIX + FDKstrcpy(tmp, CMDFILE_PREFIX); + FDKstrcpy(tmp+FDKstrlen(CMDFILE_PREFIX), param_filename); + /* Open the file with command lines */ + config_fp = FDKfopen(tmp, "r"); +#else + /* Open the file with command lines */ + config_fp = FDKfopen(param_filename, "r"); +#endif + + if(config_fp == NULL) + { +#ifdef CMDFILE_PREFIX + FDKprintf("\ncould not open config file %s", tmp); +#else + FDKprintf("\ncould not open config file %s", param_filename); +#endif + return 1; + } + + /* Obtain a command line from config file */ + while (FDKfgets(line, CMDL_MAX_STRLEN*CMDL_MAX_ARGC, config_fp) != NULL) + { + argc = 1; + + /* Eat \n */ + line_ptr = (char*)FDKstrchr(line, '\n'); + if (line_ptr != NULL) + *line_ptr = ' '; + + line_ptr = line; + + /* Scan the line and put the command line params into argv */ + do { + /* Skip consecutive blanks. */ + while (*line_ptr == ' ' && line_ptr < line+CMDL_MAX_STRLEN) + line_ptr++; + /* Assign argument. TODO: maybe handle quotes */ + argv_ptr[argc] = line_ptr; + /* Get pointer to next blank. */ + line_ptr = (char*)FDKstrchr(line_ptr, ' '); + /* */ + if (line_ptr != NULL) { + /* Null terminate */ + *line_ptr = 0; + /* Skip former blank (now null character) */ + line_ptr++; + /* Advance argument counter */ + } + argc++; + } while ( line_ptr != NULL && argc < CMDL_MAX_ARGC); + + /* call "would be main()" */ + if (argc > 2 && *argv_ptr[1] != '#' && FDKstrlen(argv_ptr[1])>1) + { + int retval; + + retval = (*pFunction)(argc, argv_ptr); + + FDKprintf("main returned %d\n", retval); + } + } + + FDKfclose(config_fp); + return 0; +} + diff --git a/libSYS/src/conv_string.cpp b/libSYS/src/conv_string.cpp new file mode 100644 index 0000000..37af9c1 --- /dev/null +++ b/libSYS/src/conv_string.cpp @@ -0,0 +1,117 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (2009) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: string conversion functions + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + + + +#include "genericStds.h" +#include "conv_string.h" + +INT charBuf2HexString(char *string, UCHAR *charBuf, INT charBufLength) +{ + INT i; + UCHAR c1, c2; + + /* sanity checks */ + /* check array length */ + if (charBufLength == 0) { + return -1; + } + + /* define hex string Table */ + UCHAR hexSymb[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + + /* calculate corresponding hex string from charBuffer */ + for (i=0;i>4)&0x0f; /* upper nibble */ + c2 = (charBuf[i])&0x0f; /* lower nibble */ + + string[i*2] = hexSymb[c1]; /* convert to string */ + string[i*2+1] = hexSymb[c2]; /* convert to string */ + } + + /* terminate string */ + string[charBufLength<<1]='\0'; + + return 0; + +} + +INT hexString2CharBuf(const char *string, UCHAR *charBuf, UINT charBufLength) +{ + UINT i, k = 0; + UCHAR hNibble, lNibble; + + /* sanity checks */ + if (string[0] == '\0') { + return -1; /* invalid string size */ + } + + if (charBufLength<=0){ + return -2; /* invalid buffer size */ + } + + /* convert to hex characters to corresponding 8bit value */ + for (i=0;(string[i]!='\0')&&((i>>1)>1; + hNibble = hexChar2Dec(string[i]); + lNibble = hexChar2Dec(string[i+1]); + if ((hNibble == 16) || (lNibble == 16)) { + return -3; /* invalid character */ + } + charBuf[k] = ((hNibble<<4)&0xf0) + lNibble; + } + + /* check if last character was string terminator */ + if ((string[i-2]!=0) && (string[i]!=0)) { + return -1; /* invalid string size */ + } + + /* fill charBuffer with zeros */ + for (i=k+1;i= '0') && (c <= '9')) + r = c-'0'; + else if ((c >= 'a') && (c <= 'f')) + r = c-'a'+10; + else if ((c >= 'A') && (c <= 'F')) + r = c-'A'+10; + else + r = 16; /* invalid hex character */ + + return (UCHAR)r; +} + diff --git a/libSYS/src/genericStds.cpp b/libSYS/src/genericStds.cpp new file mode 100644 index 0000000..b83aa50 --- /dev/null +++ b/libSYS/src/genericStds.cpp @@ -0,0 +1,429 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (2002) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: - Generic memory, stdio, string, etc. function wrappers or + builtins. + - OS dependant function wrappers. + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#define _CRT_SECURE_NO_WARNINGS + +#include "genericStds.h" + +#include + +/* library info */ +#define SYS_LIB_VL0 1 +#define SYS_LIB_VL1 1 +#define SYS_LIB_VL2 25 +#define SYS_LIB_TITLE "System Integration Library" +#define SYS_LIB_BUILD_DATE __DATE__ +#define SYS_LIB_BUILD_TIME __TIME__ + + #include + #include + #include + #include + + +/*************************************************************** + * memory allocation monitoring variables + ***************************************************************/ + + +/* Include OS/System specific implementations. */ +#if defined(__linux__) /* cppp replaced: elif */ + #include "linux/genericStds_linux.cpp" +#endif + + +#if !(defined(USE_BUILTIN_STRING_FUNCTIONS) || defined(__SYMBIAN32__)) +#include +#include +#include + +#ifndef FUNCTION_FDKprintf +void FDKprintf( const char* szFmt, ...) { + va_list ap; + va_start(ap, szFmt); + vprintf(szFmt, ap); + va_end(ap); +#ifdef ARCH_WA_FLUSH_CONSOLE + fflush(stdout); +#endif +} +#endif + +#ifndef FUNCTION_FDKprintfErr +void FDKprintfErr( const char* szFmt, ...) { + va_list ap; + va_start(ap, szFmt); +#if defined(ARCH_WA_SLOWCON) + vprintf(szFmt, ap); +#else + vfprintf(stderr, szFmt, ap); +#endif + va_end(ap); +#ifdef ARCH_WA_FLUSH_CONSOLE + fflush(stderr); +#endif +} +#endif + +int FDKgetchar(void) { return getchar(); } + +INT FDKfprintf(FDKFILE *stream, const char *format, ...) { + INT chars = 0; + va_list ap; + va_start(ap, format); + chars += vfprintf((FILE*)stream, format, ap); + va_end(ap); + return chars; +} + +#ifndef FUNCTION_FDKsprintf +INT FDKsprintf(char *str, const char *format, ...) { + INT chars = 0; + va_list ap; + va_start(ap, format); + chars += vsprintf(str, format, ap); + va_end(ap); + return chars; +} +#endif + +#else + +void FDKprintf( const char* szFmt, ...) { /* stub! */; } +void FDKprintfErr( const char* szFmt, ...) { /* stub! */; } +INT FDKfprintf(FILE *stream, const char *format, ...) { /*stub ! */; } +INT FDKsprintf(char *str, const char *format, ...) { /* stub! */; } + +#endif + +/************************************************************************************************/ + + +const char *FDKstrchr(const char *s, INT c) { return strchr(s, c); } +const char *FDKstrstr(const char *haystack, const char *needle) { return strstr(haystack, needle); } +#ifndef FUNCTION_FDKstrcpy +char *FDKstrcpy(char *dest, const char *src) { return strcpy(dest, src); } +#endif +char *FDKstrncpy(char *dest, const char *src, UINT n) { return strncpy(dest, src, n); } + +/************************************************************************* + * DYNAMIC MEMORY management (heap) + *************************************************************************/ + +#ifndef FUNCTION_FDKcalloc +void *FDKcalloc (const UINT n, const UINT size) +{ + void* ptr; + + ptr = calloc(n, size); + + return ptr; +} +#endif + +#ifndef FUNCTION_FDKmalloc +void *FDKmalloc (const UINT size) +{ + void* ptr; + + ptr = malloc(size); + + return ptr; +} +#endif + +#ifndef FUNCTION_FDKfree +void FDKfree (void *ptr) +{ + /* FDKprintf("f, heapSize: %d\n", heapSizeCurr); */ + free((INT*)ptr); +} +#endif + +#ifndef FUNCTION_FDKaalloc +void *FDKaalloc(const UINT size, const UINT alignment) +{ + void *addr, *result=NULL; + addr = FDKcalloc(1, size + alignment + sizeof(void*)); /* Malloc and clear memory. */ + + if (addr!=NULL) + { + result = ALIGN_PTR((unsigned char*)addr + sizeof(void*)); /* Get aligned memory base address. */ + *(((void**)result) - 1) = addr; /* Save malloc'ed memory pointer. */ + } + + return result; /* Return aligned address. */ +} +#endif + +#ifndef FUNCTION_FDKafree +void FDKafree (void *ptr) +{ + void *addr; + addr = *(((void**)ptr)-1); /* Get pointer to malloc'ed memory. */ + FDKfree(addr); /* Free malloc'ed memory area. */ +} +#endif + + +#ifndef FUNCTION_FDKcalloc_L + +/*--------------------------------------------------------------------------* + * DATA MEMORY L1/L2 (fallback) + *--------------------------------------------------------------------------*/ + + + +/*--------------------------------------------------------------------------* + * FDKcalloc_L + *--------------------------------------------------------------------------*/ +void *FDKcalloc_L(const UINT dim, const UINT size, MEMORY_SECTION s) +{ + int a_size; + + if (s == SECT_DATA_EXTERN) + goto fallback; + + a_size = ((dim*size+3)&0xfffffffc); /* force 4 byte alignment (1111 .... 1111 1100) */ + + + + + + //printf("Warning, out of internal memory\n"); + +fallback: + return FDKcalloc(dim, size); +} +#endif /* FUNCTION_FDKcalloc_L */ + +#ifndef FUNCTION_FDKfree_L +void FDKfree_L (void *p) +{ + + FDKfree(p); +} +#endif /* FUNCTION_FDKfree_L */ + +#ifndef FUNCTION_FDKaalloc_L +void *FDKaalloc_L(const UINT size, const UINT alignment, MEMORY_SECTION s) +{ + void *addr, *result=NULL; + addr = FDKcalloc_L(1, size + alignment + sizeof(void*), s); /* Malloc and clear memory. */ + + if (addr!=NULL) + { + result = ALIGN_PTR((unsigned char *)addr + sizeof(void*)); /* Get aligned memory base address. */ + *(((void**)result) - 1) = addr; /* Save malloc'ed memory pointer. */ + } + + return result; /* Return aligned address. */ +} +#endif + +#ifndef FUNCTION_FDKafree_L +void FDKafree_L (void *ptr) +{ + void *addr; + + addr = *(((void**)ptr)-1); /* Get pointer to malloc'ed memory. */ + FDKfree_L(addr); /* Free malloc'ed memory area. */ +} +#endif + + + +/*--------------------------------------------------------------------------------------- + * FUNCTION: FDKmemcpy + * DESCRIPTION: - copies memory from "src" to "dst" with length "size" bytes + * - compiled with FDK_DEBUG will give you warnings + *---------------------------------------------------------------------------------------*/ +void FDKmemcpy(void *dst, const void *src, const UINT size) +{ + + /* do the copy */ + memcpy(dst, src, size); +} + +void FDKmemmove(void *dst, const void *src, const UINT size) { memmove(dst, src, size); } +void FDKmemset(void *memPtr, const INT value, const UINT size) { memset(memPtr, value, size); } +void FDKmemclear(void *memPtr, const UINT size) { FDKmemset(memPtr,0,size); } +UINT FDKstrlen(const char *s) { return (UINT)strlen(s); } + +/* Compare function wrappers */ +INT FDKmemcmp(const void *s1, const void *s2, const UINT size) { return memcmp(s1, s2, size); } +INT FDKstrcmp(const char *s1, const char *s2) { return strcmp(s1, s2); } +INT FDKstrncmp(const char *s1, const char *s2, const UINT size) { return strncmp(s1, s2, size); } + + +/* Math function wrappers. Only intended for compatibility, not to be highly optimized. */ + +INT FDKabs(INT j) { return abs(j); } +double FDKfabs(double x) { return fabs(x); } +double FDKpow(double x, double y) { return pow(x,y); } +double FDKsqrt(double x) { return sqrt(x); } +double FDKatan(double x) { return atan(x); } +double FDKlog(double x) { return log(x); } +double FDKsin(double x) { return sin(x); } +double FDKcos(double x) { return cos(x); } +double FDKexp(double x) { return exp(x); } +double FDKatan2(double y, double x) { return atan2(y, x); } +double FDKacos(double x) { return acos(x); } +double FDKtan(double x) { return tan(x); } +double FDKfloor(double x) { return floor(x); } +double FDKceil(double x) { return ceil(x); } + +INT FDKatoi(const char *nptr) { return atoi(nptr); } +long FDKatol(const char *nptr) { return atol(nptr); } +float FDKatof(const char *nptr) { return (float)atof(nptr); } + + +/* ==================== FILE I/O ====================== */ + +#if !defined(FUNCTION_FDKfopen) +FDKFILE *FDKfopen(const char *filename, const char *mode) { return fopen(filename, mode); } +#endif +#if !defined(FUNCTION_FDKfclose) +INT FDKfclose(FDKFILE *fp) { return fclose((FILE*)fp);} +#endif +#if !defined(FUNCTION_FDKfseek) +INT FDKfseek(FDKFILE *fp, LONG OFFSET, int WHENCE) { return fseek((FILE*)fp, OFFSET, WHENCE);} +#endif +#if !defined(FUNCTION_FDKftell) +INT FDKftell(FDKFILE *fp) { return ftell((FILE*)fp); } +#endif +#if !defined(FUNCTION_FDKfflush) +INT FDKfflush(FDKFILE *fp) { return fflush((FILE*)fp); } +#endif +const INT FDKSEEK_SET = SEEK_SET; +const INT FDKSEEK_CUR = SEEK_CUR; +const INT FDKSEEK_END = SEEK_END; + +#if !defined(FUNCTION_FDKfwrite) +UINT FDKfwrite(void *ptrf, INT size, UINT nmemb, FDKFILE *fp) { return fwrite(ptrf, size, nmemb, (FILE*)fp); } +#endif +#if !defined(FUNCTION_FDKfread) +UINT FDKfread(void *dst, INT size, UINT nmemb, FDKFILE *fp) { return fread(dst, size, nmemb, (FILE*)fp); } +#endif +#if !defined(FUNCTION_FDKfgets) +char* FDKfgets(void *dst, INT size, FDKFILE *fp) { return fgets((char *)dst, size, (FILE*)fp); } +#endif +#if !defined(FUNCTION_FDKrewind) +void FDKrewind(FDKFILE *fp) { FDKfseek((FILE*)fp,0,FDKSEEK_SET); } +#endif + + +UINT FDKfwrite_EL(void *ptrf, INT size, UINT nmemb, FDKFILE *fp) { + + if (IS_LITTLE_ENDIAN()) { + FDKfwrite(ptrf, size, nmemb, fp); + } else { + UINT n; + INT s; + + UCHAR *ptr = (UCHAR*) ptrf; + + for (n=0; n=0; s--) { + //FDKprintf("char = %c\n", (char)*(ptr+s)); + FDKfwrite(ptr + s, 1, 1, fp); + } + ptr = ptr + size; + } + } + return nmemb; +} + + +UINT FDKfread_EL(void *dst, INT size, UINT nmemb, FDKFILE *fp) { + UINT n, s0, s1, err; + UCHAR tmp, *ptr; + UCHAR tmp24[3]; + + /* Enforce alignment of 24 bit data. */ + if (size == 3) { + ptr = (UCHAR*)dst; + err = 0; + for (n=0; n 1) { + ptr = (UCHAR*)dst; + for (n=0; n +#endif + + + + +void FDKprintDisclaimer(void) +{ + FDKprintf( + "This program is protected by copyright law and international treaties.\n" \ + "Any reproduction or distribution of this program, or any portion\n" \ + "of it, may result in severe civil and criminal penalties, and will be\n" \ + "prosecuted to the maximum extent possible under law.\n\n"); +} + diff --git a/libSYS/src/linux/FDK_stackload_linux.cpp b/libSYS/src/linux/FDK_stackload_linux.cpp new file mode 100644 index 0000000..d90f295 --- /dev/null +++ b/libSYS/src/linux/FDK_stackload_linux.cpp @@ -0,0 +1,28 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: Stack consumption information gathering. + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + diff --git a/libSYS/src/linux/audio_linux.cpp b/libSYS/src/linux/audio_linux.cpp new file mode 100644 index 0000000..ffc78ff --- /dev/null +++ b/libSYS/src/linux/audio_linux.cpp @@ -0,0 +1,28 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (2003) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author: Manuel Jander + Description: Audio support + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + diff --git a/libSYS/src/linux/coresup_linux.cpp b/libSYS/src/linux/coresup_linux.cpp new file mode 100644 index 0000000..9b80869 --- /dev/null +++ b/libSYS/src/linux/coresup_linux.cpp @@ -0,0 +1,28 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (2003) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: System support routines + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + diff --git a/libSYS/src/linux/genericStds_linux.cpp b/libSYS/src/linux/genericStds_linux.cpp new file mode 100644 index 0000000..ce10f9c --- /dev/null +++ b/libSYS/src/linux/genericStds_linux.cpp @@ -0,0 +1,232 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: Linux genericStds (mostly kernel SRAM driver bindings) + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + + +/* + * NOTE: it makes only sense to enable this if you also have the corresponding + * GNU/Linux kernel driver to access fast SRAM. + */ +#if defined(__arm__) /* || defined(__mips__) */ + +/** + * EABI static linking problem workaround + * + * These function are normally present in libc.a but + * apparently can be linked only statically. + * While using C++ (iisisoff) that is a problem, + * because it wont work (static global constructors + * cause problems with static linked programs). + * So the workaround is to include those functions here, + * because libSYS.a is linked statically, and libc can be + * linked dynamically as usual. + * + * Add more EABI functions here if you get unresolved + * symbols of EABI functions. + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif +void __aeabi_memcpy(void *dest, void *src, int size) +{ + memcpy(dest, src, size); +} +void __aeabi_memcpy4(void *dest, void *src, int size) +{ + memcpy(dest, src, size); +} +void __aeabi_memmove4(void *dest, void *src, int size) +{ + memmove(dest, src, size); +} +void __aeabi_memclr(void *ptr, int size) +{ + memset(ptr, 0, size); +} +void __aeabi_memclr4(void *ptr, int size) +{ + memset(ptr, 0, size); +} +#ifdef __cplusplus +} +#endif + +/* Include Linux kernel config, or set ARCH and processor macros directly */ +/* +#define CONFIG_ARCH_MXC +#define CONFIG_ARCH_MX25 +*/ + +#if defined(CONFIG_ARCH_OMAP3) +#define KERNEL_SRAM_SIZE 65536 +#elif defined(CONFIG_ARCH_MX31) +#define KERNEL_SRAM_SIZE 16384 +#elif defined(CONFIG_ARCH_MX25) +#define KERNEL_SRAM_SIZE 131072 +#elif defined(CONFIG_ARCH_MX35) +#define KERNEL_SRAM_SIZE 131072 +#else +#define KERNEL_SRAM_SIZE 0 +#endif + +#if (KERNEL_SRAM_SIZE > 0) +#define KERNEL_SCRATCH_SIZE (4096) +#define FDK_SCRATCHBUF_SIZE (KERNEL_SCRATCH_SIZE/sizeof(INT)) +#define DATA_L1_A_SIZE (KERNEL_SRAM_SIZE-KERNEL_SCRATCH_SIZE) + +#define RESOURCE_scratchBuffer +#define FUNCTION_FDKprolog +#define FUNCTION_FDKepilog + +static unsigned char *L1_DATA_A=NULL; +static unsigned char *_a=NULL; + + +#ifdef RESOURCE_scratchBuffer +static INT *__scratchBuffer; +static unsigned char *__pScratchBuffer = NULL; +#endif + + +#ifdef __linux__ + +#include +#include +#include +#include +#include +#include + +static int fd; +static inline void * getSram(void) +{ + unsigned long *ptr = NULL; + + /* Open driver */ + fd = open("/dev/sram", 0); + if (fd < 0) + { + printf("Unable to open /dev/sram. Fallback to malloc\n"); + /* Signal "no sram driver at use". */ + fd = -1; + /* Return malloced pointer (fallback) */ + return FDKaalloc(KERNEL_SRAM_SIZE, 8); + } + + /* Get memory mapped into CPU (virtual) address space */ + ptr = (unsigned long *)mmap(NULL, KERNEL_SRAM_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if(ptr == MAP_FAILED) + { + printf("Unable to mmap(). Fallback to malloc\n"); + /* Give up on the sram driver */ + close(fd); + /* Signal "no sram driver at use". */ + fd = -1; + /* Return malloced pointer (fallback) */ + ptr = (unsigned long *)FDKaalloc(KERNEL_SRAM_SIZE, 8); + } + + + /* Return pointer to sram */ + return (void*)ptr; +} + +static inline void freeSram(void* ptr) +{ + /* Check if sram driver is being used. */ + if (fd == -1) + { + FDKafree(ptr); + return; + } + + /* Unmap memory */ + munmap(ptr, KERNEL_SRAM_SIZE); + /* Close driver */ + close(fd); + + return; +} + +#else + +static inline void * getSram(void) +{ + return FDKaalloc(KERNEL_SRAM_SIZE, 8); +} +static inline void * freeSram(void* ptr) +{ + FDKafree(ptr); +} + +#endif + + +#ifdef FUNCTION_FDKprolog +void FDKprolog(void) +{ + unsigned char *addr = (unsigned char*)getSram(); + + + if (addr == NULL) + { + printf("SRAM allocation failed ! This is fatal.\n"); + exit(-1); + } + +#ifdef RESOURCE_scratchBuffer + __scratchBuffer = (INT*) ( addr + (KERNEL_SRAM_SIZE-KERNEL_SCRATCH_SIZE) ); + __pScratchBuffer = addr + (KERNEL_SRAM_SIZE); +#endif + + printf("SRAM @ 0x%08x\n", (unsigned int) addr); + atexit(FDKepilog); + + FDKprolog_generic(); +} +#endif + +#ifdef FUNCTION_FDKepilog +void FDKepilog(void) +{ + /* Because of atexit(), make sure to call this only once */ + if (L1_DATA_A != NULL) + { + freeSram(L1_DATA_A); + L1_DATA_A = NULL; + + FDKepilog_generic(); + } +} +#endif + +#endif /* KERNEL_SRAM > 0 */ + +#endif /* ifdef __arm__ */ + diff --git a/libSYS/src/linux/uart_linux.cpp b/libSYS/src/linux/uart_linux.cpp new file mode 100644 index 0000000..6497c9f --- /dev/null +++ b/libSYS/src/linux/uart_linux.cpp @@ -0,0 +1,28 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (2003) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author: Manuel Jander + Description: UART support + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + diff --git a/libSYS/src/mips/genericStds_mips.cpp b/libSYS/src/mips/genericStds_mips.cpp new file mode 100644 index 0000000..7e77eee --- /dev/null +++ b/libSYS/src/mips/genericStds_mips.cpp @@ -0,0 +1,230 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (2006) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Manuel Jander + Description: + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#define RESOURCE_scratchBuffer +#define FUNCTION_FDKprolog +#define FUNCTION_FDKepilog + +#define MIPS_VIRTUAL_START (0x80000000) +/* value below is defined in simulator config (MipsMemIntf-{24KE,4KE}.cfg) */ +#define MIPS_SDE_SCRATCHPAD (0x00058000) + +//#define MIPS_SRAM_SIZE (32768) +#define MIPS_SRAM_SIZE (4096) + +#define MIPS_SCRATCH_SIZE (4096) +#define DATA_L1_A_SIZE (MIPS_SRAM_SIZE-MIPS_SCRATCH_SIZE) + + + + +#ifdef RESOURCE_scratchBuffer +#define FDK_SCRATCHBUF_SIZE 1024 +static LONG *___scratchBuffer = NULL; +static LONG *__scratchBuffer = NULL; +static unsigned char *__pScratchBuffer = NULL; +#endif + + +#ifdef __linux__ + +#include +#include +#include +#include +#include +#include + +static int fd; +static inline void * getSram(void) +{ + unsigned long *ptr = NULL; + + /* Open driver */ + fd = open("/dev/sram", 0); + if (fd < 0) + { + printf("Unable to access sram. Fallback to malloc\n"); + /* Signal "no sram driver at use". */ + fd = -1; + /* Return malloced pointer (fallback) */ + return malloc(MIPS_SRAM_SIZE); + } + + /* Get memory mapped into CPU (virtual) address space */ + ptr = (unsigned long *)mmap(NULL, MIPS_SRAM_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if(ptr == MAP_FAILED) + { + printf("Unable to access sram. Fallback to malloc\n"); + /* Give up on the sram driver */ + close(fd); + /* Signal "no sram driver at use". */ + fd = -1; + /* Return malloced pointer (fallback) */ + ptr = (unsigned long *)malloc(MIPS_SRAM_SIZE); + } + + + /* Return pointer to sram */ + return (void*)ptr; +} + +static inline void freeSram(void* ptr) +{ + /* Check if sram driver is being used. */ + if (fd == -1) + { + free(ptr); + return; + } + + /* Unmap memory */ + munmap(ptr, MIPS_SRAM_SIZE); + /* Close driver */ + close(fd); + + return; +} + +#elif defined(__SDE_MIPS__) + +#include +#include + +static int hasISPRAM, hasDSPRAM; + +static inline void * getSram(void) +{ + void *addr; + unsigned int Config; + + Config = mips_getconfig(); + hasISPRAM = (Config >> 24) & 1; + hasDSPRAM = (Config >> 23) & 1; + + FDKprintf("Config ISP/DSP: %d/%d\n", hasISPRAM, hasDSPRAM); + + if (hasDSPRAM) { + long paddr, laddr; + + FDKprintf("wrong\n"); + paddr = MIPS_SDE_SCRATCHPAD; + /* Fixed mapping of kseg0: 0x80000000-0x9fffffff virtual => 0x00000000-0x1fffffff physical */ + laddr = MIPS_VIRTUAL_START + MIPS_SDE_SCRATCHPAD; + addr = (void*)(laddr); + } else { + FDKprintf("ok\n"); + addr = malloc(MIPS_SRAM_SIZE); + FDKprintf("addr %d\n", (int)addr); + } + return addr; +} +static inline void freeSram(void* ptr) +{ + if (!hasDSPRAM) { + free(ptr); + } +} + +#else + +static inline void * getSram(void) +{ + return malloc(MIPS_SRAM_SIZE); +} +static inline void freeSram(void* ptr) +{ + free(ptr); +} + +#endif + + +#ifdef FUNCTION_FDKprolog +void FDKprolog(void) +{ + unsigned char *addr; + +#ifdef _MIPS_ARCH_MIPS32R2 + unsigned status; + asm volatile("mfc0 %0, $12, 0;\n" : "=r" (status)); + status |= (1 << 24); + asm volatile("mtc0 %0, $12, 0;\n" :: "r" (status)); +#endif + + addr = (unsigned char*)getSram(); + if (addr == NULL) { + FDKprintfErr("SRAM allocation failed ! This is fatal.\n"); + exit(-1); + } else { + FDKprintf("SRAM @ 0x%08x, size = 0x%x\n", (unsigned int) addr, MIPS_SRAM_SIZE); + } + + +#ifdef RESOURCE_scratchBuffer + ___scratchBuffer = (LONG*)(addr + MIPS_SRAM_SIZE - MIPS_SCRATCH_SIZE); +#endif + + atexit(FDKepilog); + + FDKprolog_generic(); +} +#endif + +#ifdef FUNCTION_FDKepilog +void FDKepilog(void) +{ + +#ifdef _MIPS_ARCH_MIPS32R2 + unsigned status; + asm volatile("mfc0 %0, $12, 0;\n" : "=r" (status)); + status &= ~(1 << 24); + asm volatile("mtc0 %0, $12, 0;\n" :: "r" (status)); +#endif + + FDKepilog_generic(); +} +#endif + + +#if !defined(__linux__) + +#define FUNCTION_FDKclock + +#ifndef MIPS_CPU_CLK +#define MIPS_CPU_CLK 100000000 +#endif + +INT FDKclock(void) { + INT clk; + + asm volatile ("mfc0 %0,$9 " : "=r" (clk)); + return clk; +} + +#endif /* !defined(__linux__) */ diff --git a/libSYS/src/wav_file.cpp b/libSYS/src/wav_file.cpp new file mode 100644 index 0000000..da401e4 --- /dev/null +++ b/libSYS/src/wav_file.cpp @@ -0,0 +1,492 @@ +/************************** Fraunhofer IIS FDK SysLib ********************** + + (C) Copyright Fraunhofer IIS (2000) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Eric Allamanche + Description: a rudimentary wav file interface + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + + + +#include "wav_file.h" +#include "genericStds.h" + + +static INT_PCM ulaw2pcm (UCHAR ulawbyte); + +/*! + * + * \brief Read header from a WAVEfile. Host endianess is handled accordingly. + * \wav->fp filepointer of type FILE*. + * \wavinfo SWavInfo struct where the decoded header info is stored into. + * \return 0 on success and non-zero on failure. + * + */ +INT WAV_InputOpen (HANDLE_WAV *pWav, const char *filename) +{ + HANDLE_WAV wav = (HANDLE_WAV)FDKcalloc(1, sizeof(struct WAV)); + INT offset; + + if (wav == NULL) { + FDKprintfErr("WAV_InputOpen(): Unable to allocate WAV struct.\n"); + goto error; + } + + wav->fp = FDKfopen(filename, "rb"); + if (wav->fp == NULL) { + FDKprintfErr("WAV_InputOpen(): Unable to open wav file. %s\n", filename); + goto error; + } + + /* read RIFF-chunk */ + if (FDKfread(&(wav->header.riffType), 1, 4, wav->fp) != 4) { + FDKprintfErr("WAV_InputOpen(): couldn't read RIFF_ID\n"); + goto error; /* bad error "couldn't read RIFF_ID" */ + } + if (FDKstrncmp("RIFF", wav->header.riffType, 4)) { + FDKprintfErr("WAV_InputOpen(): RIFF descriptor not found.\n") ; + goto error; + } + + /* Read RIFF size. Ignored. */ + FDKfread_EL(&(wav->header.riffSize), 4, 1, wav->fp); + + /* read WAVE-chunk */ + if (FDKfread(&wav->header.waveType, 1, 4, wav->fp) !=4) { + FDKprintfErr("WAV_InputOpen(): couldn't read format\n"); + goto error; /* bad error "couldn't read format" */ + } + if (FDKstrncmp("WAVE", wav->header.waveType, 4)) { + FDKprintfErr("WAV_InputOpen(): WAVE chunk ID not found.\n") ; + goto error; + } + + /* read format-chunk */ + if (FDKfread(&(wav->header.formatType), 1, 4, wav->fp) != 4) { + FDKprintfErr("WAV_InputOpen(): couldn't read format_ID\n"); + goto error; /* bad error "couldn't read format_ID" */ + } + if (FDKstrncmp("fmt", wav->header.formatType, 3)) { + FDKprintfErr("WAV_InputOpen(): fmt chunk format not found.\n") ; + goto error; + } + + + FDKfread_EL(&wav->header.formatSize, 4, 1, wav->fp); /* should be 16 for PCM-format (uncompressed) */ + + + /* read info */ + FDKfread_EL(&(wav->header.compressionCode), 2, 1, wav->fp); + FDKfread_EL(&(wav->header.numChannels), 2, 1, wav->fp); + FDKfread_EL(&(wav->header.sampleRate), 4, 1, wav->fp); + FDKfread_EL(&(wav->header.bytesPerSecond), 4, 1, wav->fp); + FDKfread_EL(&(wav->header.blockAlign), 2, 1, wav->fp); + FDKfread_EL(&(wav->header.bitsPerSample), 2, 1, wav->fp); + + offset = wav->header.formatSize - 16; + + /* Wave format extensible */ + if (wav->header.compressionCode == 0xFFFE) { + static const UCHAR guidPCM[16] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 + }; + USHORT extraFormatBytes, validBitsPerSample; + UINT channelMask; + UCHAR guid[16]; + INT i; + + /* read extra bytes */ + FDKfread_EL(&(extraFormatBytes), 2, 1, wav->fp); + offset -= 2; + + if (extraFormatBytes >= 22) { + FDKfread_EL(&(validBitsPerSample), 2, 1, wav->fp); + FDKfread_EL(&(channelMask), 4, 1, wav->fp); + FDKfread_EL(&(guid), 16, 1, wav->fp); + + /* check for PCM GUID */ + for (i = 0; i < 16; i++) if (guid[i] != guidPCM[i]) break; + if (i == 16) wav->header.compressionCode = 0x01; + + offset -= 22; + } + } + + /* Skip rest of fmt header if any. */ + for (;offset > 0; offset--) { + FDKfread(&wav->header.formatSize, 1, 1, wav->fp); + } + + do { + /* Read data chunk ID */ + if (FDKfread(wav->header.dataType, 1, 4, wav->fp) != 4) { + FDKprintfErr("WAV_InputOpen(): Unable to read data chunk ID.\n"); + FDKfree(wav); + goto error; + } + + /* Read chunk length. */ + FDKfread_EL(&offset, 4, 1, wav->fp); + + /* Check for data chunk signature. */ + if (FDKstrncmp("data", wav->header.dataType, 4) == 0) { + wav->header.dataSize = offset; + break; + } + /* Jump over non data chunk. */ + for (;offset > 0; offset--) { + FDKfread(&(wav->header.dataSize), 1, 1, wav->fp); + } + } while (!FDKfeof(wav->fp)); + + /* return success */ + *pWav = wav; + return 0; + + /* Error path */ +error: + if (wav->fp) { + FDKfclose(wav->fp); + wav->fp = NULL; + } + + if (wav) { + FDKfree(wav); + } + + *pWav = NULL; + + return -1; +} + +/*! + * + * \brief Read samples from a WAVEfile. The samples are automatically reorder to the native + * host endianess and scaled to full scale of the INT_PCM type, from whatever bps the WAVEfile + * had specified in its haader data. + * + * \wav HANDLE_WAV of the wav file. + * \buffer Pointer to store read data. + * \numSamples Desired number of samples to read. + * \nBits sample size in bits to be used for the buffer + * + * \return Number of samples actually read. + * + */ + +INT WAV_InputRead (HANDLE_WAV wav, void *buffer, UINT numSamples, int nBits) +{ + UINT result = 0 ; + UINT i; + SCHAR *bptr = (SCHAR*)buffer; + LONG *lptr = (LONG*)buffer; + SHORT *sptr = (SHORT*)buffer; + + switch (wav->header.compressionCode) + { + case 0x01: /* PCM uncompressed */ + if (nBits == wav->header.bitsPerSample) { + result = FDKfread_EL(buffer, wav->header.bitsPerSample >> 3, numSamples, wav->fp) ; + } else { + result = 0; + for (i=0; iheader.bitsPerSample >> 3, 1, wav->fp) ; + + /* Move read bits to lower bits of LONG. */ + if ( !IS_LITTLE_ENDIAN() && wav->header.bitsPerSample != 24 && wav->header.bitsPerSample < 32) { + tmp >>= (32-wav->header.bitsPerSample); + } + + /* Full scale */ + if (wav->header.bitsPerSample > nBits) + tmp >>= (wav->header.bitsPerSample-nBits); + else + tmp <<= (nBits-wav->header.bitsPerSample); + + if (nBits == 8) + *bptr++ = (SCHAR) tmp; + if (nBits == 16) + *sptr++ = (SHORT) tmp; + if (nBits == 32) + *lptr++ = (LONG) tmp; + } + } + break; + + case 0x07: /* u-Law compression */ + for (i=0; ifp) ; + sptr[i] = ulaw2pcm(bptr[i<<1]) ; + } + break ; + + default: + FDKprintf("WAV_InputRead(): unsupported data-compression!!") ; + break ; + } + return result ; +} + +void WAV_InputClose(HANDLE_WAV *pWav) +{ + HANDLE_WAV wav = *pWav; + + if (wav != NULL) { + if (wav->fp != NULL) { + FDKfclose(wav->fp); + wav->fp = NULL; + } + if (wav) { + FDKfree(wav); + } + } + *pWav = NULL; +} + +/* conversion of u-law to linear coding */ +static INT_PCM ulaw2pcm (UCHAR ulawbyte) +{ + static const INT exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 } ; + INT sign, exponent, mantissa, sample ; + + ulawbyte = (UCHAR)~ulawbyte ; + sign = (ulawbyte & 0x80) ; + exponent = (ulawbyte >> 4) & 0x07 ; + mantissa = ulawbyte & 0x0F ; + + sample = exp_lut[exponent] + (mantissa << (exponent + 3)) ; + if (sign != 0) + sample = -sample ; + + return (INT_PCM)sample ; +} + +/************** Writer ***********************/ + +static UINT LittleEndian32(UINT v) +{ + if (IS_LITTLE_ENDIAN()) + return v ; + else + return (v & 0x000000FF) << 24 | (v & 0x0000FF00) << 8 | (v & 0x00FF0000) >> 8 | (v & 0xFF000000) >> 24; +} + +static SHORT LittleEndian16(SHORT v) +{ + if (IS_LITTLE_ENDIAN()) + return v; + else + return (SHORT)(((v << 8) & 0xFF00) | ((v >> 8) & 0x00FF)); +} + +static USHORT Unpack(USHORT v) +{ + if (IS_LITTLE_ENDIAN()) + return v; + else + return (SHORT)(((v << 8) & 0xFF00) | ((v >> 8) & 0x00FF)); +} + +/** + * WAV_OutputOpen + * \brief Open WAV output/writer handle + * \param pWav pointer to WAV handle to be returned + * \param sampleRate desired samplerate of the resulting WAV file + * \param numChannels desired number of audio channels of the resulting WAV file + * \param bitsPerSample desired number of bits per audio sample of the resulting WAV file + * + * \return value: 0: ok + * -1: error + */ +INT WAV_OutputOpen(HANDLE_WAV *pWav, const char *outputFilename, INT sampleRate, INT numChannels, INT bitsPerSample) +{ + HANDLE_WAV wav = (HANDLE_WAV)FDKcalloc(1, sizeof(struct WAV)); + UINT size = 0; + + if (bitsPerSample != 16 && bitsPerSample != 24 && bitsPerSample != 32) + { + FDKprintfErr("WAV_OutputOpen(): Invalid argument (bitsPerSample).\n"); + goto bail; + } + + wav->fp = FDKfopen(outputFilename, "wb"); + if (wav->fp == NULL) + { + FDKprintfErr("WAV_OutputOpen(): unable to create file %s\n", outputFilename); + goto bail; + } + + FDKstrcpy(wav->header.riffType, "RIFF"); + wav->header.riffSize = LittleEndian32(0x7fffffff); /* in case fseek() doesn't work later in WAV_OutputClose() */ + FDKstrcpy(wav->header.waveType, "WAVE"); + + FDKstrcpy(wav->header.formatType, "fmt "); + wav->header.formatSize = LittleEndian32(16); + + wav->header.compressionCode = LittleEndian16(0x01); + wav->header.bitsPerSample = LittleEndian16((SHORT)bitsPerSample); + wav->header.numChannels = LittleEndian16((SHORT)numChannels); + wav->header.blockAlign = LittleEndian16((SHORT)(numChannels * (bitsPerSample >> 3))); + wav->header.sampleRate = LittleEndian32(sampleRate); + wav->header.bytesPerSecond = LittleEndian32(sampleRate * wav->header.blockAlign); + FDKstrcpy(wav->header.dataType, "data"); + wav->header.dataSize = LittleEndian32(0x7fffffff - 36); + + + size = sizeof(WAV_HEADER); + if (FDKfwrite(&wav->header, 1, size, wav->fp) != size) + { + FDKprintfErr("WAV_OutputOpen(): error writing to output file %s\n", outputFilename); + goto bail; + } + + + wav->header.dataSize = wav->header.riffSize = 0; + + *pWav = wav; + + return 0; + +bail: + if (wav->fp) + FDKfclose(wav->fp); + if (wav) + FDKfree(wav); + + pWav = NULL; + + return -1; +} + + +/** + * WAV_OutputWrite + * \brief Write data to WAV file asociated to WAV handle + * + * \param wav handle of wave file + * \param sampleBuffer pointer to audio samples, right justified integer values + * \param nBufBits size in bits of each audio sample in sampleBuffer + * \param nSigBits amount of significant bits of each nBufBits in sampleBuffer + * + * \return value: 0: ok + * -1: error + */ +INT WAV_OutputWrite(HANDLE_WAV wav, void *sampleBuffer, UINT numberOfSamples, int nBufBits, int nSigBits) +{ + SCHAR *bptr = (SCHAR*)sampleBuffer; + SHORT *sptr = (SHORT*)sampleBuffer; + LONG *lptr = (LONG*)sampleBuffer; + LONG tmp; + + int bps = Unpack(wav->header.bitsPerSample); + UINT i; + + /* Pack samples if required */ + if (bps == nBufBits && bps == nSigBits) { + if (FDKfwrite_EL(sampleBuffer, (bps>>3), numberOfSamples, wav->fp) != numberOfSamples) + { + FDKprintfErr("WAV_OutputWrite(): error: unable to write to file %d\n", wav->fp); + return -1; + } + } else { + for (i=0; i>= -shift; + else + tmp <<= shift; + + /* Write sample */ + result=FDKfwrite_EL(&tmp, bps>>3, 1, wav->fp); + if (result <= 0) { + FDKprintfErr("WAV_OutputWrite(): error: unable to write to file %d\n", wav->fp); + return -1; + } + } + } + + wav->header.dataSize += (numberOfSamples * (bps>>3)); + return 0; +} + + +/** + * WAV_OutputClose + * \brief Close WAV Output handle + * \param pWav pointer to WAV handle. *pWav is set to NULL. + */ +void WAV_OutputClose(HANDLE_WAV *pWav) +{ + HANDLE_WAV wav = *pWav; + UINT size = 0; + + if ( wav == NULL ) { + return; + } + + wav->header.dataSize = LittleEndian32(wav->header.dataSize); + wav->header.riffSize = LittleEndian32(wav->header.dataSize + 36); + + if (wav->fp != NULL) + { + if (FDKfseek(wav->fp, 0, FDKSEEK_SET)) { + FDKprintf("WAV_OutputClose(): fseek() failed.\n"); + } + + size = sizeof(WAV_HEADER); + if (FDKfwrite(&wav->header.riffType, 1, size, wav->fp) != size) + { + FDKprintfErr("WAV_OutputClose(): unable to write header\n"); + } + + if (FDKfclose(wav->fp)) + { + FDKprintfErr("WAV_OutputClose(): unable to close wav file\n"); + } + wav->fp = NULL; + } + + FDKfree(wav); + *pWav = NULL; +} + -- cgit v1.2.3