/* * aac_decoder.cpp * libhelix_HAACDECODER * * Created on: 26.10.2018 * Updated on: 10.09.2021 ************************************************************************************/ #include "aac_decoder.h" const uint32_t SQRTHALF = 0x5a82799a; /* sqrt(0.5), format = Q31 */ const uint32_t Q28_2 = 0x20000000; /* Q28: 2.0 */ const uint32_t Q28_15 = 0x30000000; /* Q28: 1.5 */ const uint8_t NUM_ITER_IRN = 5; const uint8_t NUM_TERMS_RPI = 5; const uint32_t LOG2_EXP_INV = 0x58b90bfc; /* 1/log2(e), Q31 */ const uint8_t SF_OFFSET = 100; const uint8_t AAC_PROFILE_LC = 1; const uint8_t NUM_TIME_SLOTS = 16; const uint8_t SAMPLES_PER_SLOT = 2; /* RATE in spec */ const uint8_t SYNCWORDH = 0xff; /* 12-bit syncword */ const uint8_t SYNCWORDL = 0xf0; const uint8_t NUM_SAMPLE_RATES = 12; const uint8_t NUM_DEF_CHAN_MAPS = 8; const uint32_t NSAMPS_LONG = 1024; const uint8_t NSAMPS_SHORT = 128; const uint8_t NUM_SYN_ID_BITS = 3; const uint8_t NUM_INST_TAG_BITS = 4; const uint8_t NWINDOWS_LONG = 1; const uint8_t NWINDOWS_SHORT = 8; const uint8_t AAC_MAX_NCHANS = 2; /* set to default max number of channels */ const uint16_t AAC_MAX_NSAMPS = 1024; const uint8_t MAX_NCHANS_ELEM = 2; /* max number of channels in any single bitstream element */ const uint8_t MAX_NUM_PCE_ADIF = 16; const uint8_t ADIF_COPYID_SIZE = 9; const uint8_t HUFFTAB_SPEC_OFFSET = 1; const uint8_t FBITS_OUT_DQ_OFF = 20 - 15; /* (FBITS_OUT_DQ - SF_DQ_OFFSET) */ const uint8_t GBITS_IN_DCT4 = 4; /* min guard bits in for DCT4 */ const uint8_t FBITS_LOST_DCT4 = 1; /* number of fraction bits lost (>> out) in DCT-IV */ const uint8_t FBITS_OUT_IMDCT = 3; const uint8_t NUM_IMDCT_SIZES = 2; const uint8_t FBITS_LPC_COEFS = 20; const uint8_t NUM_ITER_INVSQRT = 4; const uint32_t X0_COEF_2 = 0xc0000000; /* Q29: -2.0 */ const uint32_t X0_OFF_2 = 0x60000000; /* Q29: 3.0 */ const uint32_t Q26_3 = 0x0c000000; /* Q26: 3.0 */ const uint8_t EXT_SBR_DATA = 0x0d; const uint8_t EXT_SBR_DATA_CRC = 0x0e; const uint8_t NUM_SAMPLE_RATES_SBR = 9; /* downsampled (single-rate) mode unsupported */ const uint8_t MAX_NUM_PATCHES = 5; const uint8_t MAX_QMF_BANDS = 48; /* max QMF subbands covered by SBR (4.6.18.3.6) */ const uint8_t MAX_NUM_ENV = 5; const uint8_t NUM_QMF_DELAY_BUFS = 10; const uint8_t FBITS_IN_QMFA = 14; const uint8_t NOISE_FLOOR_OFFSET = 6; const uint8_t FBITS_OUT_DQ_NOISE = 24; /* range of Q_orig = [2^-24, 2^6] */ const uint8_t FBITS_LOST_QMFA = (1 + 2 + 3 + 2 + 1); const uint8_t FBITS_OUT_QMFA = (FBITS_IN_QMFA - FBITS_LOST_QMFA); const uint8_t FBITS_IN_QMFS = FBITS_OUT_QMFA; const uint8_t FBITS_LOST_DCT4_64 = (2 + 3 + 2); /* 2 in premul, 3 in FFT, 2 in postmul */ const uint8_t FBITS_OUT_QMFS = (FBITS_IN_QMFS - FBITS_LOST_DCT4_64 + 6 - 1); const uint8_t RND_VAL = (1 << (FBITS_OUT_QMFS-1)); const uint8_t HF_ADJ = 2; const uint8_t HF_GEN = 8; const uint8_t FBITS_LPCOEFS = 29; /* Q29 for range of (-4, 4) */ const uint32_t MAG_16 = (16 * (1 << (32 - (2*(32-FBITS_LPCOEFS))))); /* i.e. 16 in Q26 format */ const uint32_t RELAX_COEF = 0x7ffff79c; /* 1.0 / (1.0 + 1e-6), Q31 */ const uint8_t MAX_NUM_SMOOTH_COEFS = 5; const uint8_t FBITS_OUT_DQ_ENV = 29; /* dequantized env scalefactors are Q(29 - envDataDequantScale) */ const uint8_t FBITS_GLIM_BOOST = 24; const uint8_t FBITS_QLIM_BOOST = 14; const uint8_t MIN_GBITS_IN_QMFS = 2; const uint16_t nmdctTab[2] = {128, 1024}; const uint8_t postSkip[2] = {15, 1}; const uint16_t nfftTab[2] = {64, 512}; const uint8_t nfftlog2Tab[2] = {6, 9}; const uint8_t cos4sin4tabOffset[2] = {0, 128}; PSInfoBase_t *m_PSInfoBase; AACDecInfo_t *m_AACDecInfo; AACFrameInfo_t m_AACFrameInfo; ADTSHeader_t m_fhADTS; ADIFHeader_t m_fhADIF; ProgConfigElement_t *m_pce[16]; PulseInfo_t m_pulseInfo[2]; // [MAX_NCHANS_ELEM] aac_BitStreamInfo_t m_aac_BitStreamInfo; PSInfoSBR_t *m_PSInfoSBR; //---------------------------------------------------------------------------------------------------------------------- inline int MULSHIFT32(int x, int y){ int z; z = (int64_t)x * (int64_t)y >> 32; return z; } inline int CLZ(int x){ #ifdef __XTENSA__ return __builtin_clz(x); #else int numZeros; if(!x) return 32; /* count leading zeros with binary search (function should be 17 ARM instructions total) */ numZeros = 1; if (!((unsigned int)x >> 16)) { numZeros += 16; x <<= 16; } if (!((unsigned int)x >> 24)) { numZeros += 8; x <<= 8; } if (!((unsigned int)x >> 28)) { numZeros += 4; x <<= 4; } if (!((unsigned int)x >> 30)) { numZeros += 2; x <<= 2; } numZeros -= ((unsigned int)x >> 31); return numZeros; #endif } inline int FASTABS(int x){ #ifdef __XTENSA__ //fb return __builtin_abs(x); #else int sign; sign = x >> (sizeof(int) * 8 - 1); x ^= sign; x -= sign; return x; #endif } inline int64_t MADD64(int64_t sum64, int x, int y){ sum64 += (int64_t)x * (int64_t)y; return sum64; } inline short CLIPTOSHORT(int x){ #ifdef __XTENSA__ //fb asm ("clamps %0, %1, 15" : "=a" (x) : "a" (x) : ); return x; #else int sign; /* clip to [-32768, 32767] */ sign = x >> 31; if (sign != (x >> 15)) x = sign ^ ((1 << 15) - 1); return (short)x; #endif } inline int CLIP_2N(int y, int n){ #ifdef __XTENSA__ //fb int x = 1 << n; \ if (y < -x) y = -x; \ x--; \ if (y > x) y = x; \ return y; #else int sign = y >> 31; if(sign != (y >> n)) y = sign ^ ((1 << n) - 1); return y; #endif } inline int CLIP_2N_SHIFT30(int y, int n){ int sign = y >> 31; if(sign != (y >> (30 - n))) y = sign ^ (0x3fffffff); else y = (y << n); return y; } //---------------------------------------------------------------------------------------------------------------------- const uint32_t cos4sin4tab[128 + 1024] PROGMEM = { /* 128 - format = Q30 * 2^-7 */ 0xbf9bc731, 0xff9b783c, 0xbed5332c, 0xc002c697, 0xbe112251, 0xfe096c8d, 0xbd4f9c30, 0xc00f1c4a, 0xbc90a83f, 0xfc77ae5e, 0xbbd44dd9, 0xc0254e27, 0xbb1a9443, 0xfae67ba2, 0xba6382a6, 0xc04558c0, 0xb9af200f, 0xf9561237, 0xb8fd7373, 0xc06f3726, 0xb84e83ac, 0xf7c6afdc, 0xb7a25779, 0xc0a2e2e3, 0xb6f8f57c, 0xf6389228, 0xb652643e, 0xc0e05401, 0xb5aeaa2a, 0xf4abf67e, 0xb50dcd90, 0xc1278104, 0xb46fd4a4, 0xf3211a07, 0xb3d4c57c, 0xc1785ef4, 0xb33ca614, 0xf19839a6, 0xb2a77c49, 0xc1d2e158, 0xb2154dda, 0xf01191f3, 0xb186206b, 0xc236fa3b, 0xb0f9f981, 0xee8d5f29, 0xb070de82, 0xc2a49a2e, 0xafead4b9, 0xed0bdd25, 0xaf67e14f, 0xc31bb049, 0xaee80952, 0xeb8d475b, 0xae6b51ae, 0xc39c2a2f, 0xadf1bf34, 0xea11d8c8, 0xad7b5692, 0xc425f410, 0xad081c5a, 0xe899cbf1, 0xac9814fd, 0xc4b8f8ad, 0xac2b44cc, 0xe7255ad1, 0xabc1aff9, 0xc555215a, 0xab5b5a96, 0xe5b4bed8, 0xaaf84896, 0xc5fa5603, 0xaa987dca, 0xe44830dd, 0xaa3bfde3, 0xc6a87d2d, 0xa9e2cc73, 0xe2dfe917, 0xa98cece9, 0xc75f7bfe, 0xa93a6296, 0xe17c1f15, 0xa8eb30a7, 0xc81f363d, 0xa89f5a2b, 0xe01d09b4, 0xa856e20e, 0xc8e78e5b, 0xa811cb1b, 0xdec2df18, 0xa7d017fc, 0xc9b86572, 0xa791cb39, 0xdd6dd4a2, 0xa756e73a, 0xca919b4e, 0xa71f6e43, 0xdc1e1ee9, 0xa6eb6279, 0xcb730e70, 0xa6bac5dc, 0xdad3f1b1, 0xa68d9a4c, 0xcc5c9c14, 0xa663e188, 0xd98f7fe6, 0xa63d9d2b, 0xcd4e2037, 0xa61aceaf, 0xd850fb8e, 0xa5fb776b, 0xce47759a, 0xa5df9894, 0xd71895c9, 0xa5c7333e, 0xcf4875ca, 0xa5b2485a, 0xd5e67ec1, 0xa5a0d8b5, 0xd050f926, 0xa592e4fd, 0xd4bae5ab, 0xa5886dba, 0xd160d6e5, 0xa5817354, 0xd395f8ba, 0xa57df60f, 0xd277e518, /* 1024 - format = Q30 * 2^-10 */ 0xbff3703e, 0xfff36f02, 0xbfda5824, 0xc0000b1a, 0xbfc149ed, 0xffc12b16, 0xbfa845a0, 0xc0003c74, 0xbf8f4b3e, 0xff8ee750, 0xbf765acc, 0xc0009547, 0xbf5d744e, 0xff5ca3d0, 0xbf4497c8, 0xc0011594, 0xbf2bc53d, 0xff2a60b4, 0xbf12fcb2, 0xc001bd5c, 0xbefa3e2a, 0xfef81e1d, 0xbee189a8, 0xc0028c9c, 0xbec8df32, 0xfec5dc28, 0xbeb03eca, 0xc0038356, 0xbe97a875, 0xfe939af5, 0xbe7f1c36, 0xc004a188, 0xbe669a10, 0xfe615aa3, 0xbe4e2209, 0xc005e731, 0xbe35b423, 0xfe2f1b50, 0xbe1d5062, 0xc0075452, 0xbe04f6cb, 0xfdfcdd1d, 0xbdeca760, 0xc008e8e8, 0xbdd46225, 0xfdcaa027, 0xbdbc2720, 0xc00aa4f3, 0xbda3f652, 0xfd98648d, 0xbd8bcfbf, 0xc00c8872, 0xbd73b36d, 0xfd662a70, 0xbd5ba15d, 0xc00e9364, 0xbd439995, 0xfd33f1ed, 0xbd2b9c17, 0xc010c5c7, 0xbd13a8e7, 0xfd01bb24, 0xbcfbc00a, 0xc0131f9b, 0xbce3e182, 0xfccf8634, 0xbccc0d53, 0xc015a0dd, 0xbcb44382, 0xfc9d533b, 0xbc9c8411, 0xc018498c, 0xbc84cf05, 0xfc6b2259, 0xbc6d2461, 0xc01b19a7, 0xbc558428, 0xfc38f3ac, 0xbc3dee5f, 0xc01e112b, 0xbc266309, 0xfc06c754, 0xbc0ee22a, 0xc0213018, 0xbbf76bc4, 0xfbd49d70, 0xbbdfffdd, 0xc024766a, 0xbbc89e77, 0xfba2761e, 0xbbb14796, 0xc027e421, 0xbb99fb3e, 0xfb70517d, 0xbb82b972, 0xc02b7939, 0xbb6b8235, 0xfb3e2fac, 0xbb54558d, 0xc02f35b1, 0xbb3d337b, 0xfb0c10cb, 0xbb261c04, 0xc0331986, 0xbb0f0f2b, 0xfad9f4f8, 0xbaf80cf4, 0xc03724b6, 0xbae11561, 0xfaa7dc52, 0xbaca2878, 0xc03b573f, 0xbab3463b, 0xfa75c6f8, 0xba9c6eae, 0xc03fb11d, 0xba85a1d4, 0xfa43b508, 0xba6edfb1, 0xc044324f, 0xba582849, 0xfa11a6a3, 0xba417b9e, 0xc048dad1, 0xba2ad9b5, 0xf9df9be6, 0xba144291, 0xc04daaa1, 0xb9fdb635, 0xf9ad94f0, 0xb9e734a4, 0xc052a1bb, 0xb9d0bde4, 0xf97b91e1, 0xb9ba51f6, 0xc057c01d, 0xb9a3f0de, 0xf94992d7, 0xb98d9aa0, 0xc05d05c3, 0xb9774f3f, 0xf91797f0, 0xb9610ebe, 0xc06272aa, 0xb94ad922, 0xf8e5a14d, 0xb934ae6d, 0xc06806ce, 0xb91e8ea3, 0xf8b3af0c, 0xb90879c7, 0xc06dc22e, 0xb8f26fdc, 0xf881c14b, 0xb8dc70e7, 0xc073a4c3, 0xb8c67cea, 0xf84fd829, 0xb8b093ea, 0xc079ae8c, 0xb89ab5e8, 0xf81df3c5, 0xb884e2e9, 0xc07fdf85, 0xb86f1af0, 0xf7ec143e, 0xb8595e00, 0xc08637a9, 0xb843ac1d, 0xf7ba39b3, 0xb82e0549, 0xc08cb6f5, 0xb818698a, 0xf7886442, 0xb802d8e0, 0xc0935d64, 0xb7ed5351, 0xf756940a, 0xb7d7d8df, 0xc09a2af3, 0xb7c2698e, 0xf724c92a, 0xb7ad0561, 0xc0a11f9d, 0xb797ac5b, 0xf6f303c0, 0xb7825e80, 0xc0a83b5e, 0xb76d1bd2, 0xf6c143ec, 0xb757e455, 0xc0af7e33, 0xb742b80d, 0xf68f89cb, 0xb72d96fd, 0xc0b6e815, 0xb7188127, 0xf65dd57d, 0xb7037690, 0xc0be7901, 0xb6ee773a, 0xf62c2721, 0xb6d98328, 0xc0c630f2, 0xb6c49a5e, 0xf5fa7ed4, 0xb6afbce0, 0xc0ce0fe3, 0xb69aeab0, 0xf5c8dcb6, 0xb68623d1, 0xc0d615cf, 0xb6716847, 0xf59740e5, 0xb65cb815, 0xc0de42b2, 0xb648133e, 0xf565ab80, 0xb63379c5, 0xc0e69686, 0xb61eebae, 0xf5341ca5, 0xb60a68fb, 0xc0ef1147, 0xb5f5f1b1, 0xf5029473, 0xb5e185d1, 0xc0f7b2ee, 0xb5cd255f, 0xf4d11308, 0xb5b8d05f, 0xc1007b77, 0xb5a486d2, 0xf49f9884, 0xb59048be, 0xc1096add, 0xb57c1624, 0xf46e2504, 0xb567ef08, 0xc1128119, 0xb553d36c, 0xf43cb8a7, 0xb53fc355, 0xc11bbe26, 0xb52bbec4, 0xf40b538b, 0xb517c5be, 0xc12521ff, 0xb503d845, 0xf3d9f5cf, 0xb4eff65c, 0xc12eac9d, 0xb4dc2007, 0xf3a89f92, 0xb4c85548, 0xc1385dfb, 0xb4b49622, 0xf37750f2, 0xb4a0e299, 0xc1423613, 0xb48d3ab0, 0xf3460a0d, 0xb4799e69, 0xc14c34df, 0xb4660dc8, 0xf314cb02, 0xb45288cf, 0xc1565a58, 0xb43f0f82, 0xf2e393ef, 0xb42ba1e4, 0xc160a678, 0xb4183ff7, 0xf2b264f2, 0xb404e9bf, 0xc16b193a, 0xb3f19f3e, 0xf2813e2a, 0xb3de6078, 0xc175b296, 0xb3cb2d70, 0xf2501fb5, 0xb3b80628, 0xc1807285, 0xb3a4eaa4, 0xf21f09b1, 0xb391dae6, 0xc18b5903, 0xb37ed6f1, 0xf1edfc3d, 0xb36bdec9, 0xc1966606, 0xb358f26f, 0xf1bcf777, 0xb34611e8, 0xc1a1998a, 0xb3333d36, 0xf18bfb7d, 0xb320745c, 0xc1acf386, 0xb30db75d, 0xf15b086d, 0xb2fb063b, 0xc1b873f5, 0xb2e860fa, 0xf12a1e66, 0xb2d5c79d, 0xc1c41ace, 0xb2c33a26, 0xf0f93d86, 0xb2b0b898, 0xc1cfe80a, 0xb29e42f6, 0xf0c865ea, 0xb28bd943, 0xc1dbdba3, 0xb2797b82, 0xf09797b2, 0xb26729b5, 0xc1e7f591, 0xb254e3e0, 0xf066d2fa, 0xb242aa05, 0xc1f435cc, 0xb2307c27, 0xf03617e2, 0xb21e5a49, 0xc2009c4e, 0xb20c446d, 0xf0056687, 0xb1fa3a97, 0xc20d290d, 0xb1e83cc9, 0xefd4bf08, 0xb1d64b06, 0xc219dc03, 0xb1c46551, 0xefa42181, 0xb1b28bad, 0xc226b528, 0xb1a0be1b, 0xef738e12, 0xb18efca0, 0xc233b473, 0xb17d473d, 0xef4304d8, 0xb16b9df6, 0xc240d9de, 0xb15a00cd, 0xef1285f2, 0xb1486fc5, 0xc24e255e, 0xb136eae1, 0xeee2117c, 0xb1257223, 0xc25b96ee, 0xb114058e, 0xeeb1a796, 0xb102a524, 0xc2692e83, 0xb0f150e9, 0xee81485c, 0xb0e008e0, 0xc276ec16, 0xb0cecd09, 0xee50f3ed, 0xb0bd9d6a, 0xc284cf9f, 0xb0ac7a03, 0xee20aa67, 0xb09b62d8, 0xc292d914, 0xb08a57eb, 0xedf06be6, 0xb079593f, 0xc2a1086d, 0xb06866d7, 0xedc0388a, 0xb05780b5, 0xc2af5da2, 0xb046a6db, 0xed901070, 0xb035d94e, 0xc2bdd8a9, 0xb025180e, 0xed5ff3b5, 0xb014631e, 0xc2cc7979, 0xb003ba82, 0xed2fe277, 0xaff31e3b, 0xc2db400a, 0xafe28e4d, 0xecffdcd4, 0xafd20ab9, 0xc2ea2c53, 0xafc19383, 0xeccfe2ea, 0xafb128ad, 0xc2f93e4a, 0xafa0ca39, 0xec9ff4d6, 0xaf90782a, 0xc30875e5, 0xaf803283, 0xec7012b5, 0xaf6ff945, 0xc317d31c, 0xaf5fcc74, 0xec403ca5, 0xaf4fac12, 0xc32755e5, 0xaf3f9822, 0xec1072c4, 0xaf2f90a5, 0xc336fe37, 0xaf1f959f, 0xebe0b52f, 0xaf0fa712, 0xc346cc07, 0xaeffc500, 0xebb10404, 0xaeefef6c, 0xc356bf4d, 0xaee02658, 0xeb815f60, 0xaed069c7, 0xc366d7fd, 0xaec0b9bb, 0xeb51c760, 0xaeb11636, 0xc377160f, 0xaea17f3b, 0xeb223c22, 0xae91f4cd, 0xc3877978, 0xae8276ed, 0xeaf2bdc3, 0xae73059f, 0xc398022f, 0xae63a0e3, 0xeac34c60, 0xae5448be, 0xc3a8b028, 0xae44fd31, 0xea93e817, 0xae35be3f, 0xc3b9835a, 0xae268be9, 0xea649105, 0xae176633, 0xc3ca7bba, 0xae084d1f, 0xea354746, 0xadf940ae, 0xc3db993e, 0xadea40e4, 0xea060af9, 0xaddb4dc2, 0xc3ecdbdc, 0xadcc674b, 0xe9d6dc3b, 0xadbd8d82, 0xc3fe4388, 0xadaec067, 0xe9a7bb28, 0xad9fffff, 0xc40fd037, 0xad914c4b, 0xe978a7dd, 0xad82a54c, 0xc42181e0, 0xad740b07, 0xe949a278, 0xad657d7c, 0xc4335877, 0xad56fcaf, 0xe91aab16, 0xad4888a0, 0xc44553f2, 0xad3a2153, 0xe8ebc1d3, 0xad2bc6ca, 0xc4577444, 0xad1d7907, 0xe8bce6cd, 0xad0f380c, 0xc469b963, 0xad0103db, 0xe88e1a20, 0xacf2dc77, 0xc47c2344, 0xace4c1e2, 0xe85f5be9, 0xacd6b41e, 0xc48eb1db, 0xacc8b32c, 0xe830ac45, 0xacbabf10, 0xc4a1651c, 0xacacd7cb, 0xe8020b52, 0xac9efd60, 0xc4b43cfd, 0xac912fd1, 0xe7d3792b, 0xac836f1f, 0xc4c73972, 0xac75bb4d, 0xe7a4f5ed, 0xac68145d, 0xc4da5a6f, 0xac5a7a52, 0xe77681b6, 0xac4ced2c, 0xc4ed9fe7, 0xac3f6cef, 0xe7481ca1, 0xac31f99d, 0xc50109d0, 0xac249336, 0xe719c6cb, 0xac1739bf, 0xc514981d, 0xac09ed38, 0xe6eb8052, 0xabfcada3, 0xc5284ac3, 0xabef7b04, 0xe6bd4951, 0xabe2555b, 0xc53c21b4, 0xabd53caa, 0xe68f21e5, 0xabc830f5, 0xc5501ce5, 0xabbb323c, 0xe6610a2a, 0xabae4082, 0xc5643c4a, 0xaba15bc9, 0xe633023e, 0xab948413, 0xc5787fd6, 0xab87b962, 0xe6050a3b, 0xab7afbb7, 0xc58ce77c, 0xab6e4b15, 0xe5d72240, 0xab61a77d, 0xc5a17330, 0xab5510f3, 0xe5a94a67, 0xab488776, 0xc5b622e6, 0xab3c0b0b, 0xe57b82cd, 0xab2f9bb1, 0xc5caf690, 0xab23396c, 0xe54dcb8f, 0xab16e43d, 0xc5dfee22, 0xab0a9c27, 0xe52024c9, 0xaafe612a, 0xc5f5098f, 0xaaf23349, 0xe4f28e96, 0xaae61286, 0xc60a48c9, 0xaad9fee3, 0xe4c50914, 0xaacdf861, 0xc61fabc4, 0xaac1ff03, 0xe497945d, 0xaab612ca, 0xc6353273, 0xaaaa33b8, 0xe46a308f, 0xaa9e61cf, 0xc64adcc7, 0xaa929d10, 0xe43cddc4, 0xaa86e57e, 0xc660aab5, 0xaa7b3b1b, 0xe40f9c1a, 0xaa6f9de7, 0xc6769c2e, 0xaa640de6, 0xe3e26bac, 0xaa588b18, 0xc68cb124, 0xaa4d157f, 0xe3b54c95, 0xaa41ad1e, 0xc6a2e98b, 0xaa3651f6, 0xe3883ef2, 0xaa2b0409, 0xc6b94554, 0xaa1fc358, 0xe35b42df, 0xaa148fe6, 0xc6cfc472, 0xaa0969b3, 0xe32e5876, 0xa9fe50c2, 0xc6e666d7, 0xa9f34515, 0xe3017fd5, 0xa9e846ad, 0xc6fd2c75, 0xa9dd558b, 0xe2d4b916, 0xa9d271b2, 0xc714153e, 0xa9c79b23, 0xe2a80456, 0xa9bcd1e0, 0xc72b2123, 0xa9b215ea, 0xe27b61af, 0xa9a76744, 0xc7425016, 0xa99cc5ee, 0xe24ed13d, 0xa99231eb, 0xc759a20a, 0xa987ab3c, 0xe222531c, 0xa97d31e3, 0xc77116f0, 0xa972c5e1, 0xe1f5e768, 0xa9686738, 0xc788aeb9, 0xa95e15e9, 0xe1c98e3b, 0xa953d1f7, 0xc7a06957, 0xa9499b62, 0xe19d47b1, 0xa93f722c, 0xc7b846ba, 0xa9355658, 0xe17113e5, 0xa92b47e5, 0xc7d046d6, 0xa92146d7, 0xe144f2f3, 0xa917532e, 0xc7e8699a, 0xa90d6cec, 0xe118e4f6, 0xa9039413, 0xc800aef7, 0xa8f9c8a4, 0xe0ecea09, 0xa8f00aa0, 0xc81916df, 0xa8e65a0a, 0xe0c10247, 0xa8dcb6e2, 0xc831a143, 0xa8d3212a, 0xe0952dcb, 0xa8c998e3, 0xc84a4e14, 0xa8c01e10, 0xe0696cb0, 0xa8b6b0b1, 0xc8631d42, 0xa8ad50c8, 0xe03dbf11, 0xa8a3fe57, 0xc87c0ebd, 0xa89ab95e, 0xe012250a, 0xa89181df, 0xc8952278, 0xa88857dc, 0xdfe69eb4, 0xa87f3b57, 0xc8ae5862, 0xa8762c4f, 0xdfbb2c2c, 0xa86d2ac8, 0xc8c7b06b, 0xa86436c2, 0xdf8fcd8b, 0xa85b503e, 0xc8e12a84, 0xa852773f, 0xdf6482ed, 0xa849abc4, 0xc8fac69e, 0xa840edd1, 0xdf394c6b, 0xa8383d66, 0xc91484a8, 0xa82f9a84, 0xdf0e2a22, 0xa827052d, 0xc92e6492, 0xa81e7d62, 0xdee31c2b, 0xa8160324, 0xc948664d, 0xa80d9675, 0xdeb822a1, 0xa8053756, 0xc96289c9, 0xa7fce5c9, 0xde8d3d9e, 0xa7f4a1ce, 0xc97ccef5, 0xa7ec6b66, 0xde626d3e, 0xa7e44294, 0xc99735c2, 0xa7dc2759, 0xde37b199, 0xa7d419b4, 0xc9b1be1e, 0xa7cc19a9, 0xde0d0acc, 0xa7c42738, 0xc9cc67fa, 0xa7bc4262, 0xdde278ef, 0xa7b46b29, 0xc9e73346, 0xa7aca18e, 0xddb7fc1e, 0xa7a4e591, 0xca021fef, 0xa79d3735, 0xdd8d9472, 0xa795967a, 0xca1d2de7, 0xa78e0361, 0xdd634206, 0xa7867dec, 0xca385d1d, 0xa77f061c, 0xdd3904f4, 0xa7779bf2, 0xca53ad7e, 0xa7703f70, 0xdd0edd55, 0xa768f095, 0xca6f1efc, 0xa761af64, 0xdce4cb44, 0xa75a7bdd, 0xca8ab184, 0xa7535602, 0xdcbacedb, 0xa74c3dd4, 0xcaa66506, 0xa7453353, 0xdc90e834, 0xa73e3681, 0xcac23971, 0xa7374760, 0xdc671768, 0xa73065ef, 0xcade2eb3, 0xa7299231, 0xdc3d5c91, 0xa722cc25, 0xcafa44bc, 0xa71c13ce, 0xdc13b7c9, 0xa715692c, 0xcb167b79, 0xa70ecc41, 0xdbea292b, 0xa7083d0d, 0xcb32d2da, 0xa701bb91, 0xdbc0b0ce, 0xa6fb47ce, 0xcb4f4acd, 0xa6f4e1c6, 0xdb974ece, 0xa6ee8979, 0xcb6be341, 0xa6e83ee8, 0xdb6e0342, 0xa6e20214, 0xcb889c23, 0xa6dbd2ff, 0xdb44ce46, 0xa6d5b1a9, 0xcba57563, 0xa6cf9e13, 0xdb1baff2, 0xa6c9983e, 0xcbc26eee, 0xa6c3a02b, 0xdaf2a860, 0xa6bdb5da, 0xcbdf88b3, 0xa6b7d94e, 0xdac9b7a9, 0xa6b20a86, 0xcbfcc29f, 0xa6ac4984, 0xdaa0dde7, 0xa6a69649, 0xcc1a1ca0, 0xa6a0f0d5, 0xda781b31, 0xa69b5929, 0xcc3796a5, 0xa695cf46, 0xda4f6fa3, 0xa690532d, 0xcc55309b, 0xa68ae4df, 0xda26db54, 0xa685845c, 0xcc72ea70, 0xa68031a6, 0xd9fe5e5e, 0xa67aecbd, 0xcc90c412, 0xa675b5a3, 0xd9d5f8d9, 0xa6708c57, 0xccaebd6e, 0xa66b70db, 0xd9adaadf, 0xa6666330, 0xccccd671, 0xa6616355, 0xd9857489, 0xa65c714d, 0xcceb0f0a, 0xa6578d18, 0xd95d55ef, 0xa652b6b6, 0xcd096725, 0xa64dee28, 0xd9354f2a, 0xa6493370, 0xcd27deb0, 0xa644868d, 0xd90d6053, 0xa63fe781, 0xcd467599, 0xa63b564c, 0xd8e58982, 0xa636d2ee, 0xcd652bcb, 0xa6325d6a, 0xd8bdcad0, 0xa62df5bf, 0xcd840134, 0xa6299bed, 0xd8962456, 0xa6254ff7, 0xcda2f5c2, 0xa62111db, 0xd86e962b, 0xa61ce19c, 0xcdc20960, 0xa618bf39, 0xd8472069, 0xa614aab3, 0xcde13bfd, 0xa610a40c, 0xd81fc328, 0xa60cab43, 0xce008d84, 0xa608c058, 0xd7f87e7f, 0xa604e34e, 0xce1ffde2, 0xa6011424, 0xd7d15288, 0xa5fd52db, 0xce3f8d05, 0xa5f99f73, 0xd7aa3f5a, 0xa5f5f9ed, 0xce5f3ad8, 0xa5f2624a, 0xd783450d, 0xa5eed88a, 0xce7f0748, 0xa5eb5cae, 0xd75c63ba, 0xa5e7eeb6, 0xce9ef241, 0xa5e48ea3, 0xd7359b78, 0xa5e13c75, 0xcebefbb0, 0xa5ddf82d, 0xd70eec60, 0xa5dac1cb, 0xcedf2380, 0xa5d79950, 0xd6e85689, 0xa5d47ebc, 0xceff699f, 0xa5d17210, 0xd6c1da0b, 0xa5ce734d, 0xcf1fcdf8, 0xa5cb8272, 0xd69b76fe, 0xa5c89f80, 0xcf405077, 0xa5c5ca77, 0xd6752d79, 0xa5c30359, 0xcf60f108, 0xa5c04a25, 0xd64efd94, 0xa5bd9edc, 0xcf81af97, 0xa5bb017f, 0xd628e767, 0xa5b8720d, 0xcfa28c10, 0xa5b5f087, 0xd602eb0a, 0xa5b37cee, 0xcfc3865e, 0xa5b11741, 0xd5dd0892, 0xa5aebf82, 0xcfe49e6d, 0xa5ac75b0, 0xd5b74019, 0xa5aa39cd, 0xd005d42a, 0xa5a80bd7, 0xd59191b5, 0xa5a5ebd0, 0xd027277e, 0xa5a3d9b8, 0xd56bfd7d, 0xa5a1d590, 0xd0489856, 0xa59fdf57, 0xd5468389, 0xa59df70e, 0xd06a269d, 0xa59c1cb5, 0xd52123f0, 0xa59a504c, 0xd08bd23f, 0xa59891d4, 0xd4fbdec9, 0xa596e14e, 0xd0ad9b26, 0xa5953eb8, 0xd4d6b42b, 0xa593aa14, 0xd0cf813e, 0xa5922362, 0xd4b1a42c, 0xa590aaa2, 0xd0f18472, 0xa58f3fd4, 0xd48caee4, 0xa58de2f8, 0xd113a4ad, 0xa58c940f, 0xd467d469, 0xa58b5319, 0xd135e1d9, 0xa58a2016, 0xd44314d3, 0xa588fb06, 0xd1583be2, 0xa587e3ea, 0xd41e7037, 0xa586dac1, 0xd17ab2b3, 0xa585df8c, 0xd3f9e6ad, 0xa584f24b, 0xd19d4636, 0xa58412fe, 0xd3d5784a, 0xa58341a5, 0xd1bff656, 0xa5827e40, 0xd3b12526, 0xa581c8d0, 0xd1e2c2fd, 0xa5812154, 0xd38ced57, 0xa58087cd, 0xd205ac17, 0xa57ffc3b, 0xd368d0f3, 0xa57f7e9d, 0xd228b18d, 0xa57f0ef5, 0xd344d011, 0xa57ead41, 0xd24bd34a, 0xa57e5982, 0xd320eac6, 0xa57e13b8, 0xd26f1138, 0xa57ddbe4, 0xd2fd2129, 0xa57db204, 0xd2926b41, 0xa57d961a, 0xd2d97350, 0xa57d8825, 0xd2b5e151, }; const int cos1sin1tab[514] PROGMEM = { /* format = Q30 */ 0x40000000, 0x00000000, 0x40323034, 0x003243f1, 0x406438cf, 0x006487c4, 0x409619b2, 0x0096cb58, 0x40c7d2bd, 0x00c90e90, 0x40f963d3, 0x00fb514b, 0x412accd4, 0x012d936c, 0x415c0da3, 0x015fd4d2, 0x418d2621, 0x0192155f, 0x41be162f, 0x01c454f5, 0x41eeddaf, 0x01f69373, 0x421f7c84, 0x0228d0bb, 0x424ff28f, 0x025b0caf, 0x42803fb2, 0x028d472e, 0x42b063d0, 0x02bf801a, 0x42e05ecb, 0x02f1b755, 0x43103085, 0x0323ecbe, 0x433fd8e1, 0x03562038, 0x436f57c1, 0x038851a2, 0x439ead09, 0x03ba80df, 0x43cdd89a, 0x03ecadcf, 0x43fcda59, 0x041ed854, 0x442bb227, 0x0451004d, 0x445a5fe8, 0x0483259d, 0x4488e37f, 0x04b54825, 0x44b73ccf, 0x04e767c5, 0x44e56bbd, 0x0519845e, 0x4513702a, 0x054b9dd3, 0x454149fc, 0x057db403, 0x456ef916, 0x05afc6d0, 0x459c7d5a, 0x05e1d61b, 0x45c9d6af, 0x0613e1c5, 0x45f704f7, 0x0645e9af, 0x46240816, 0x0677edbb, 0x4650dff1, 0x06a9edc9, 0x467d8c6d, 0x06dbe9bb, 0x46aa0d6d, 0x070de172, 0x46d662d6, 0x073fd4cf, 0x47028c8d, 0x0771c3b3, 0x472e8a76, 0x07a3adff, 0x475a5c77, 0x07d59396, 0x47860275, 0x08077457, 0x47b17c54, 0x08395024, 0x47dcc9f9, 0x086b26de, 0x4807eb4b, 0x089cf867, 0x4832e02d, 0x08cec4a0, 0x485da887, 0x09008b6a, 0x4888443d, 0x09324ca7, 0x48b2b335, 0x09640837, 0x48dcf556, 0x0995bdfd, 0x49070a84, 0x09c76dd8, 0x4930f2a6, 0x09f917ac, 0x495aada2, 0x0a2abb59, 0x49843b5f, 0x0a5c58c0, 0x49ad9bc2, 0x0a8defc3, 0x49d6ceb3, 0x0abf8043, 0x49ffd417, 0x0af10a22, 0x4a28abd6, 0x0b228d42, 0x4a5155d6, 0x0b540982, 0x4a79d1ff, 0x0b857ec7, 0x4aa22036, 0x0bb6ecef, 0x4aca4065, 0x0be853de, 0x4af23270, 0x0c19b374, 0x4b19f641, 0x0c4b0b94, 0x4b418bbe, 0x0c7c5c1e, 0x4b68f2cf, 0x0cada4f5, 0x4b902b5c, 0x0cdee5f9, 0x4bb7354d, 0x0d101f0e, 0x4bde1089, 0x0d415013, 0x4c04bcf8, 0x0d7278eb, 0x4c2b3a84, 0x0da39978, 0x4c518913, 0x0dd4b19a, 0x4c77a88e, 0x0e05c135, 0x4c9d98de, 0x0e36c82a, 0x4cc359ec, 0x0e67c65a, 0x4ce8eb9f, 0x0e98bba7, 0x4d0e4de2, 0x0ec9a7f3, 0x4d33809c, 0x0efa8b20, 0x4d5883b7, 0x0f2b650f, 0x4d7d571c, 0x0f5c35a3, 0x4da1fab5, 0x0f8cfcbe, 0x4dc66e6a, 0x0fbdba40, 0x4deab226, 0x0fee6e0d, 0x4e0ec5d1, 0x101f1807, 0x4e32a956, 0x104fb80e, 0x4e565c9f, 0x10804e06, 0x4e79df95, 0x10b0d9d0, 0x4e9d3222, 0x10e15b4e, 0x4ec05432, 0x1111d263, 0x4ee345ad, 0x11423ef0, 0x4f06067f, 0x1172a0d7, 0x4f289692, 0x11a2f7fc, 0x4f4af5d1, 0x11d3443f, 0x4f6d2427, 0x12038584, 0x4f8f217e, 0x1233bbac, 0x4fb0edc1, 0x1263e699, 0x4fd288dc, 0x1294062f, 0x4ff3f2bb, 0x12c41a4f, 0x50152b47, 0x12f422db, 0x5036326e, 0x13241fb6, 0x50570819, 0x135410c3, 0x5077ac37, 0x1383f5e3, 0x50981eb1, 0x13b3cefa, 0x50b85f74, 0x13e39be9, 0x50d86e6d, 0x14135c94, 0x50f84b87, 0x144310dd, 0x5117f6ae, 0x1472b8a5, 0x51376fd0, 0x14a253d1, 0x5156b6d9, 0x14d1e242, 0x5175cbb5, 0x150163dc, 0x5194ae52, 0x1530d881, 0x51b35e9b, 0x15604013, 0x51d1dc80, 0x158f9a76, 0x51f027eb, 0x15bee78c, 0x520e40cc, 0x15ee2738, 0x522c270f, 0x161d595d, 0x5249daa2, 0x164c7ddd, 0x52675b72, 0x167b949d, 0x5284a96e, 0x16aa9d7e, 0x52a1c482, 0x16d99864, 0x52beac9f, 0x17088531, 0x52db61b0, 0x173763c9, 0x52f7e3a6, 0x1766340f, 0x5314326d, 0x1794f5e6, 0x53304df6, 0x17c3a931, 0x534c362d, 0x17f24dd3, 0x5367eb03, 0x1820e3b0, 0x53836c66, 0x184f6aab, 0x539eba45, 0x187de2a7, 0x53b9d48f, 0x18ac4b87, 0x53d4bb34, 0x18daa52f, 0x53ef6e23, 0x1908ef82, 0x5409ed4b, 0x19372a64, 0x5424389d, 0x196555b8, 0x543e5007, 0x19937161, 0x5458337a, 0x19c17d44, 0x5471e2e6, 0x19ef7944, 0x548b5e3b, 0x1a1d6544, 0x54a4a56a, 0x1a4b4128, 0x54bdb862, 0x1a790cd4, 0x54d69714, 0x1aa6c82b, 0x54ef4171, 0x1ad47312, 0x5507b76a, 0x1b020d6c, 0x551ff8ef, 0x1b2f971e, 0x553805f2, 0x1b5d100a, 0x554fde64, 0x1b8a7815, 0x55678236, 0x1bb7cf23, 0x557ef15a, 0x1be51518, 0x55962bc0, 0x1c1249d8, 0x55ad315b, 0x1c3f6d47, 0x55c4021d, 0x1c6c7f4a, 0x55da9df7, 0x1c997fc4, 0x55f104dc, 0x1cc66e99, 0x560736bd, 0x1cf34baf, 0x561d338d, 0x1d2016e9, 0x5632fb3f, 0x1d4cd02c, 0x56488dc5, 0x1d79775c, 0x565deb11, 0x1da60c5d, 0x56731317, 0x1dd28f15, 0x568805c9, 0x1dfeff67, 0x569cc31b, 0x1e2b5d38, 0x56b14b00, 0x1e57a86d, 0x56c59d6a, 0x1e83e0eb, 0x56d9ba4e, 0x1eb00696, 0x56eda1a0, 0x1edc1953, 0x57015352, 0x1f081907, 0x5714cf59, 0x1f340596, 0x572815a8, 0x1f5fdee6, 0x573b2635, 0x1f8ba4dc, 0x574e00f2, 0x1fb7575c, 0x5760a5d5, 0x1fe2f64c, 0x577314d2, 0x200e8190, 0x57854ddd, 0x2039f90f, 0x579750ec, 0x20655cac, 0x57a91df2, 0x2090ac4d, 0x57bab4e6, 0x20bbe7d8, 0x57cc15bc, 0x20e70f32, 0x57dd406a, 0x21122240, 0x57ee34e5, 0x213d20e8, 0x57fef323, 0x21680b0f, 0x580f7b19, 0x2192e09b, 0x581fccbc, 0x21bda171, 0x582fe804, 0x21e84d76, 0x583fcce6, 0x2212e492, 0x584f7b58, 0x223d66a8, 0x585ef351, 0x2267d3a0, 0x586e34c7, 0x22922b5e, 0x587d3fb0, 0x22bc6dca, 0x588c1404, 0x22e69ac8, 0x589ab1b9, 0x2310b23e, 0x58a918c6, 0x233ab414, 0x58b74923, 0x2364a02e, 0x58c542c5, 0x238e7673, 0x58d305a6, 0x23b836ca, 0x58e091bd, 0x23e1e117, 0x58ede700, 0x240b7543, 0x58fb0568, 0x2434f332, 0x5907eced, 0x245e5acc, 0x59149d87, 0x2487abf7, 0x5921172e, 0x24b0e699, 0x592d59da, 0x24da0a9a, 0x59396584, 0x250317df, 0x59453a24, 0x252c0e4f, 0x5950d7b3, 0x2554edd1, 0x595c3e2a, 0x257db64c, 0x59676d82, 0x25a667a7, 0x597265b4, 0x25cf01c8, 0x597d26b8, 0x25f78497, 0x5987b08a, 0x261feffa, 0x59920321, 0x264843d9, 0x599c1e78, 0x2670801a, 0x59a60288, 0x2698a4a6, 0x59afaf4c, 0x26c0b162, 0x59b924bc, 0x26e8a637, 0x59c262d5, 0x2710830c, 0x59cb698f, 0x273847c8, 0x59d438e5, 0x275ff452, 0x59dcd0d3, 0x27878893, 0x59e53151, 0x27af0472, 0x59ed5a5c, 0x27d667d5, 0x59f54bee, 0x27fdb2a7, 0x59fd0603, 0x2824e4cc, 0x5a048895, 0x284bfe2f, 0x5a0bd3a1, 0x2872feb6, 0x5a12e720, 0x2899e64a, 0x5a19c310, 0x28c0b4d2, 0x5a20676c, 0x28e76a37, 0x5a26d42f, 0x290e0661, 0x5a2d0957, 0x29348937, 0x5a3306de, 0x295af2a3, 0x5a38ccc2, 0x2981428c, 0x5a3e5afe, 0x29a778db, 0x5a43b190, 0x29cd9578, 0x5a48d074, 0x29f3984c, 0x5a4db7a6, 0x2a19813f, 0x5a526725, 0x2a3f503a, 0x5a56deec, 0x2a650525, 0x5a5b1efa, 0x2a8a9fea, 0x5a5f274b, 0x2ab02071, 0x5a62f7dd, 0x2ad586a3, 0x5a6690ae, 0x2afad269, 0x5a69f1bb, 0x2b2003ac, 0x5a6d1b03, 0x2b451a55, 0x5a700c84, 0x2b6a164d, 0x5a72c63b, 0x2b8ef77d, 0x5a754827, 0x2bb3bdce, 0x5a779246, 0x2bd8692b, 0x5a79a498, 0x2bfcf97c, 0x5a7b7f1a, 0x2c216eaa, 0x5a7d21cc, 0x2c45c8a0, 0x5a7e8cac, 0x2c6a0746, 0x5a7fbfbb, 0x2c8e2a87, 0x5a80baf6, 0x2cb2324c, 0x5a817e5d, 0x2cd61e7f, 0x5a8209f1, 0x2cf9ef09, 0x5a825db0, 0x2d1da3d5, 0x5a82799a, 0x2d413ccd, }; const uint8_t sinWindowOffset[NUM_IMDCT_SIZES] PROGMEM = {0, 128}; const int sinWindow[128 + 1024] PROGMEM = { /* 128 - format = Q31 * 2^0 */ 0x00c90f88, 0x7fff6216, 0x025b26d7, 0x7ffa72d1, 0x03ed26e6, 0x7ff09478, 0x057f0035, 0x7fe1c76b, 0x0710a345, 0x7fce0c3e, 0x08a2009a, 0x7fb563b3, 0x0a3308bd, 0x7f97cebd, 0x0bc3ac35, 0x7f754e80, 0x0d53db92, 0x7f4de451, 0x0ee38766, 0x7f2191b4, 0x1072a048, 0x7ef05860, 0x120116d5, 0x7eba3a39, 0x138edbb1, 0x7e7f3957, 0x151bdf86, 0x7e3f57ff, 0x16a81305, 0x7dfa98a8, 0x183366e9, 0x7db0fdf8, 0x19bdcbf3, 0x7d628ac6, 0x1b4732ef, 0x7d0f4218, 0x1ccf8cb3, 0x7cb72724, 0x1e56ca1e, 0x7c5a3d50, 0x1fdcdc1b, 0x7bf88830, 0x2161b3a0, 0x7b920b89, 0x22e541af, 0x7b26cb4f, 0x24677758, 0x7ab6cba4, 0x25e845b6, 0x7a4210d8, 0x27679df4, 0x79c89f6e, 0x28e5714b, 0x794a7c12, 0x2a61b101, 0x78c7aba2, 0x2bdc4e6f, 0x78403329, 0x2d553afc, 0x77b417df, 0x2ecc681e, 0x77235f2d, 0x3041c761, 0x768e0ea6, 0x31b54a5e, 0x75f42c0b, 0x3326e2c3, 0x7555bd4c, 0x34968250, 0x74b2c884, 0x36041ad9, 0x740b53fb, 0x376f9e46, 0x735f6626, 0x38d8fe93, 0x72af05a7, 0x3a402dd2, 0x71fa3949, 0x3ba51e29, 0x71410805, 0x3d07c1d6, 0x708378ff, 0x3e680b2c, 0x6fc19385, 0x3fc5ec98, 0x6efb5f12, 0x4121589b, 0x6e30e34a, 0x427a41d0, 0x6d6227fa, 0x43d09aed, 0x6c8f351c, 0x452456bd, 0x6bb812d1, 0x46756828, 0x6adcc964, 0x47c3c22f, 0x69fd614a, 0x490f57ee, 0x6919e320, 0x4a581c9e, 0x683257ab, 0x4b9e0390, 0x6746c7d8, 0x4ce10034, 0x66573cbb, 0x4e210617, 0x6563bf92, 0x4f5e08e3, 0x646c59bf, 0x5097fc5e, 0x637114cc, 0x51ced46e, 0x6271fa69, 0x53028518, 0x616f146c, 0x5433027d, 0x60686ccf, 0x556040e2, 0x5f5e0db3, 0x568a34a9, 0x5e50015d, 0x57b0d256, 0x5d3e5237, 0x58d40e8c, 0x5c290acc, 0x59f3de12, 0x5b1035cf, /* 1024 - format = Q31 * 2^0 */ 0x001921fb, 0x7ffffd88, 0x004b65ee, 0x7fffe9cb, 0x007da9d4, 0x7fffc251, 0x00afeda8, 0x7fff8719, 0x00e23160, 0x7fff3824, 0x011474f6, 0x7ffed572, 0x0146b860, 0x7ffe5f03, 0x0178fb99, 0x7ffdd4d7, 0x01ab3e97, 0x7ffd36ee, 0x01dd8154, 0x7ffc8549, 0x020fc3c6, 0x7ffbbfe6, 0x024205e8, 0x7ffae6c7, 0x027447b0, 0x7ff9f9ec, 0x02a68917, 0x7ff8f954, 0x02d8ca16, 0x7ff7e500, 0x030b0aa4, 0x7ff6bcf0, 0x033d4abb, 0x7ff58125, 0x036f8a51, 0x7ff4319d, 0x03a1c960, 0x7ff2ce5b, 0x03d407df, 0x7ff1575d, 0x040645c7, 0x7fefcca4, 0x04388310, 0x7fee2e30, 0x046abfb3, 0x7fec7c02, 0x049cfba7, 0x7feab61a, 0x04cf36e5, 0x7fe8dc78, 0x05017165, 0x7fe6ef1c, 0x0533ab20, 0x7fe4ee06, 0x0565e40d, 0x7fe2d938, 0x05981c26, 0x7fe0b0b1, 0x05ca5361, 0x7fde7471, 0x05fc89b8, 0x7fdc247a, 0x062ebf22, 0x7fd9c0ca, 0x0660f398, 0x7fd74964, 0x06932713, 0x7fd4be46, 0x06c5598a, 0x7fd21f72, 0x06f78af6, 0x7fcf6ce8, 0x0729bb4e, 0x7fcca6a7, 0x075bea8c, 0x7fc9ccb2, 0x078e18a7, 0x7fc6df08, 0x07c04598, 0x7fc3dda9, 0x07f27157, 0x7fc0c896, 0x08249bdd, 0x7fbd9fd0, 0x0856c520, 0x7fba6357, 0x0888ed1b, 0x7fb7132b, 0x08bb13c5, 0x7fb3af4e, 0x08ed3916, 0x7fb037bf, 0x091f5d06, 0x7facac7f, 0x09517f8f, 0x7fa90d8e, 0x0983a0a7, 0x7fa55aee, 0x09b5c048, 0x7fa1949e, 0x09e7de6a, 0x7f9dbaa0, 0x0a19fb04, 0x7f99ccf4, 0x0a4c1610, 0x7f95cb9a, 0x0a7e2f85, 0x7f91b694, 0x0ab0475c, 0x7f8d8de1, 0x0ae25d8d, 0x7f895182, 0x0b147211, 0x7f850179, 0x0b4684df, 0x7f809dc5, 0x0b7895f0, 0x7f7c2668, 0x0baaa53b, 0x7f779b62, 0x0bdcb2bb, 0x7f72fcb4, 0x0c0ebe66, 0x7f6e4a5e, 0x0c40c835, 0x7f698461, 0x0c72d020, 0x7f64aabf, 0x0ca4d620, 0x7f5fbd77, 0x0cd6da2d, 0x7f5abc8a, 0x0d08dc3f, 0x7f55a7fa, 0x0d3adc4e, 0x7f507fc7, 0x0d6cda53, 0x7f4b43f2, 0x0d9ed646, 0x7f45f47b, 0x0dd0d01f, 0x7f409164, 0x0e02c7d7, 0x7f3b1aad, 0x0e34bd66, 0x7f359057, 0x0e66b0c3, 0x7f2ff263, 0x0e98a1e9, 0x7f2a40d2, 0x0eca90ce, 0x7f247ba5, 0x0efc7d6b, 0x7f1ea2dc, 0x0f2e67b8, 0x7f18b679, 0x0f604faf, 0x7f12b67c, 0x0f923546, 0x7f0ca2e7, 0x0fc41876, 0x7f067bba, 0x0ff5f938, 0x7f0040f6, 0x1027d784, 0x7ef9f29d, 0x1059b352, 0x7ef390ae, 0x108b8c9b, 0x7eed1b2c, 0x10bd6356, 0x7ee69217, 0x10ef377d, 0x7edff570, 0x11210907, 0x7ed94538, 0x1152d7ed, 0x7ed28171, 0x1184a427, 0x7ecbaa1a, 0x11b66dad, 0x7ec4bf36, 0x11e83478, 0x7ebdc0c6, 0x1219f880, 0x7eb6aeca, 0x124bb9be, 0x7eaf8943, 0x127d7829, 0x7ea85033, 0x12af33ba, 0x7ea1039b, 0x12e0ec6a, 0x7e99a37c, 0x1312a230, 0x7e922fd6, 0x13445505, 0x7e8aa8ac, 0x137604e2, 0x7e830dff, 0x13a7b1bf, 0x7e7b5fce, 0x13d95b93, 0x7e739e1d, 0x140b0258, 0x7e6bc8eb, 0x143ca605, 0x7e63e03b, 0x146e4694, 0x7e5be40c, 0x149fe3fc, 0x7e53d462, 0x14d17e36, 0x7e4bb13c, 0x1503153a, 0x7e437a9c, 0x1534a901, 0x7e3b3083, 0x15663982, 0x7e32d2f4, 0x1597c6b7, 0x7e2a61ed, 0x15c95097, 0x7e21dd73, 0x15fad71b, 0x7e194584, 0x162c5a3b, 0x7e109a24, 0x165dd9f0, 0x7e07db52, 0x168f5632, 0x7dff0911, 0x16c0cef9, 0x7df62362, 0x16f2443e, 0x7ded2a47, 0x1723b5f9, 0x7de41dc0, 0x17552422, 0x7ddafdce, 0x17868eb3, 0x7dd1ca75, 0x17b7f5a3, 0x7dc883b4, 0x17e958ea, 0x7dbf298d, 0x181ab881, 0x7db5bc02, 0x184c1461, 0x7dac3b15, 0x187d6c82, 0x7da2a6c6, 0x18aec0db, 0x7d98ff17, 0x18e01167, 0x7d8f4409, 0x19115e1c, 0x7d85759f, 0x1942a6f3, 0x7d7b93da, 0x1973ebe6, 0x7d719eba, 0x19a52ceb, 0x7d679642, 0x19d669fc, 0x7d5d7a74, 0x1a07a311, 0x7d534b50, 0x1a38d823, 0x7d4908d9, 0x1a6a0929, 0x7d3eb30f, 0x1a9b361d, 0x7d3449f5, 0x1acc5ef6, 0x7d29cd8c, 0x1afd83ad, 0x7d1f3dd6, 0x1b2ea43a, 0x7d149ad5, 0x1b5fc097, 0x7d09e489, 0x1b90d8bb, 0x7cff1af5, 0x1bc1ec9e, 0x7cf43e1a, 0x1bf2fc3a, 0x7ce94dfb, 0x1c240786, 0x7cde4a98, 0x1c550e7c, 0x7cd333f3, 0x1c861113, 0x7cc80a0f, 0x1cb70f43, 0x7cbcccec, 0x1ce80906, 0x7cb17c8d, 0x1d18fe54, 0x7ca618f3, 0x1d49ef26, 0x7c9aa221, 0x1d7adb73, 0x7c8f1817, 0x1dabc334, 0x7c837ad8, 0x1ddca662, 0x7c77ca65, 0x1e0d84f5, 0x7c6c06c0, 0x1e3e5ee5, 0x7c602fec, 0x1e6f342c, 0x7c5445e9, 0x1ea004c1, 0x7c4848ba, 0x1ed0d09d, 0x7c3c3860, 0x1f0197b8, 0x7c3014de, 0x1f325a0b, 0x7c23de35, 0x1f63178f, 0x7c179467, 0x1f93d03c, 0x7c0b3777, 0x1fc4840a, 0x7bfec765, 0x1ff532f2, 0x7bf24434, 0x2025dcec, 0x7be5ade6, 0x205681f1, 0x7bd9047c, 0x208721f9, 0x7bcc47fa, 0x20b7bcfe, 0x7bbf7860, 0x20e852f6, 0x7bb295b0, 0x2118e3dc, 0x7ba59fee, 0x21496fa7, 0x7b989719, 0x2179f64f, 0x7b8b7b36, 0x21aa77cf, 0x7b7e4c45, 0x21daf41d, 0x7b710a49, 0x220b6b32, 0x7b63b543, 0x223bdd08, 0x7b564d36, 0x226c4996, 0x7b48d225, 0x229cb0d5, 0x7b3b4410, 0x22cd12bd, 0x7b2da2fa, 0x22fd6f48, 0x7b1feee5, 0x232dc66d, 0x7b1227d3, 0x235e1826, 0x7b044dc7, 0x238e646a, 0x7af660c2, 0x23beab33, 0x7ae860c7, 0x23eeec78, 0x7ada4dd8, 0x241f2833, 0x7acc27f7, 0x244f5e5c, 0x7abdef25, 0x247f8eec, 0x7aafa367, 0x24afb9da, 0x7aa144bc, 0x24dfdf20, 0x7a92d329, 0x250ffeb7, 0x7a844eae, 0x25401896, 0x7a75b74f, 0x25702cb7, 0x7a670d0d, 0x25a03b11, 0x7a584feb, 0x25d0439f, 0x7a497feb, 0x26004657, 0x7a3a9d0f, 0x26304333, 0x7a2ba75a, 0x26603a2c, 0x7a1c9ece, 0x26902b39, 0x7a0d836d, 0x26c01655, 0x79fe5539, 0x26effb76, 0x79ef1436, 0x271fda96, 0x79dfc064, 0x274fb3ae, 0x79d059c8, 0x277f86b5, 0x79c0e062, 0x27af53a6, 0x79b15435, 0x27df1a77, 0x79a1b545, 0x280edb23, 0x79920392, 0x283e95a1, 0x79823f20, 0x286e49ea, 0x797267f2, 0x289df7f8, 0x79627e08, 0x28cd9fc1, 0x79528167, 0x28fd4140, 0x79427210, 0x292cdc6d, 0x79325006, 0x295c7140, 0x79221b4b, 0x298bffb2, 0x7911d3e2, 0x29bb87bc, 0x790179cd, 0x29eb0957, 0x78f10d0f, 0x2a1a847b, 0x78e08dab, 0x2a49f920, 0x78cffba3, 0x2a796740, 0x78bf56f9, 0x2aa8ced3, 0x78ae9fb0, 0x2ad82fd2, 0x789dd5cb, 0x2b078a36, 0x788cf94c, 0x2b36ddf7, 0x787c0a36, 0x2b662b0e, 0x786b088c, 0x2b957173, 0x7859f44f, 0x2bc4b120, 0x7848cd83, 0x2bf3ea0d, 0x7837942b, 0x2c231c33, 0x78264849, 0x2c52478a, 0x7814e9df, 0x2c816c0c, 0x780378f1, 0x2cb089b1, 0x77f1f581, 0x2cdfa071, 0x77e05f91, 0x2d0eb046, 0x77ceb725, 0x2d3db928, 0x77bcfc3f, 0x2d6cbb10, 0x77ab2ee2, 0x2d9bb5f6, 0x77994f11, 0x2dcaa9d5, 0x77875cce, 0x2df996a3, 0x7775581d, 0x2e287c5a, 0x776340ff, 0x2e575af3, 0x77511778, 0x2e863267, 0x773edb8b, 0x2eb502ae, 0x772c8d3a, 0x2ee3cbc1, 0x771a2c88, 0x2f128d99, 0x7707b979, 0x2f41482e, 0x76f5340e, 0x2f6ffb7a, 0x76e29c4b, 0x2f9ea775, 0x76cff232, 0x2fcd4c19, 0x76bd35c7, 0x2ffbe95d, 0x76aa670d, 0x302a7f3a, 0x76978605, 0x30590dab, 0x768492b4, 0x308794a6, 0x76718d1c, 0x30b61426, 0x765e7540, 0x30e48c22, 0x764b4b23, 0x3112fc95, 0x76380ec8, 0x31416576, 0x7624c031, 0x316fc6be, 0x76115f63, 0x319e2067, 0x75fdec60, 0x31cc7269, 0x75ea672a, 0x31fabcbd, 0x75d6cfc5, 0x3228ff5c, 0x75c32634, 0x32573a3f, 0x75af6a7b, 0x32856d5e, 0x759b9c9b, 0x32b398b3, 0x7587bc98, 0x32e1bc36, 0x7573ca75, 0x330fd7e1, 0x755fc635, 0x333debab, 0x754bafdc, 0x336bf78f, 0x7537876c, 0x3399fb85, 0x75234ce8, 0x33c7f785, 0x750f0054, 0x33f5eb89, 0x74faa1b3, 0x3423d78a, 0x74e63108, 0x3451bb81, 0x74d1ae55, 0x347f9766, 0x74bd199f, 0x34ad6b32, 0x74a872e8, 0x34db36df, 0x7493ba34, 0x3508fa66, 0x747eef85, 0x3536b5be, 0x746a12df, 0x356468e2, 0x74552446, 0x359213c9, 0x744023bc, 0x35bfb66e, 0x742b1144, 0x35ed50c9, 0x7415ece2, 0x361ae2d3, 0x7400b69a, 0x36486c86, 0x73eb6e6e, 0x3675edd9, 0x73d61461, 0x36a366c6, 0x73c0a878, 0x36d0d746, 0x73ab2ab4, 0x36fe3f52, 0x73959b1b, 0x372b9ee3, 0x737ff9ae, 0x3758f5f2, 0x736a4671, 0x37864477, 0x73548168, 0x37b38a6d, 0x733eaa96, 0x37e0c7cc, 0x7328c1ff, 0x380dfc8d, 0x7312c7a5, 0x383b28a9, 0x72fcbb8c, 0x38684c19, 0x72e69db7, 0x389566d6, 0x72d06e2b, 0x38c278d9, 0x72ba2cea, 0x38ef821c, 0x72a3d9f7, 0x391c8297, 0x728d7557, 0x39497a43, 0x7276ff0d, 0x39766919, 0x7260771b, 0x39a34f13, 0x7249dd86, 0x39d02c2a, 0x72333251, 0x39fd0056, 0x721c7580, 0x3a29cb91, 0x7205a716, 0x3a568dd4, 0x71eec716, 0x3a834717, 0x71d7d585, 0x3aaff755, 0x71c0d265, 0x3adc9e86, 0x71a9bdba, 0x3b093ca3, 0x71929789, 0x3b35d1a5, 0x717b5fd3, 0x3b625d86, 0x7164169d, 0x3b8ee03e, 0x714cbbeb, 0x3bbb59c7, 0x71354fc0, 0x3be7ca1a, 0x711dd220, 0x3c143130, 0x7106430e, 0x3c408f03, 0x70eea28e, 0x3c6ce38a, 0x70d6f0a4, 0x3c992ec0, 0x70bf2d53, 0x3cc5709e, 0x70a7589f, 0x3cf1a91c, 0x708f728b, 0x3d1dd835, 0x70777b1c, 0x3d49fde1, 0x705f7255, 0x3d761a19, 0x70475839, 0x3da22cd7, 0x702f2ccd, 0x3dce3614, 0x7016f014, 0x3dfa35c8, 0x6ffea212, 0x3e262bee, 0x6fe642ca, 0x3e52187f, 0x6fcdd241, 0x3e7dfb73, 0x6fb5507a, 0x3ea9d4c3, 0x6f9cbd79, 0x3ed5a46b, 0x6f841942, 0x3f016a61, 0x6f6b63d8, 0x3f2d26a0, 0x6f529d40, 0x3f58d921, 0x6f39c57d, 0x3f8481dd, 0x6f20dc92, 0x3fb020ce, 0x6f07e285, 0x3fdbb5ec, 0x6eeed758, 0x40074132, 0x6ed5bb10, 0x4032c297, 0x6ebc8db0, 0x405e3a16, 0x6ea34f3d, 0x4089a7a8, 0x6e89ffb9, 0x40b50b46, 0x6e709f2a, 0x40e064ea, 0x6e572d93, 0x410bb48c, 0x6e3daaf8, 0x4136fa27, 0x6e24175c, 0x416235b2, 0x6e0a72c5, 0x418d6729, 0x6df0bd35, 0x41b88e84, 0x6dd6f6b1, 0x41e3abbc, 0x6dbd1f3c, 0x420ebecb, 0x6da336dc, 0x4239c7aa, 0x6d893d93, 0x4264c653, 0x6d6f3365, 0x428fbabe, 0x6d551858, 0x42baa4e6, 0x6d3aec6e, 0x42e584c3, 0x6d20afac, 0x43105a50, 0x6d066215, 0x433b2585, 0x6cec03af, 0x4365e65b, 0x6cd1947c, 0x43909ccd, 0x6cb71482, 0x43bb48d4, 0x6c9c83c3, 0x43e5ea68, 0x6c81e245, 0x44108184, 0x6c67300b, 0x443b0e21, 0x6c4c6d1a, 0x44659039, 0x6c319975, 0x449007c4, 0x6c16b521, 0x44ba74bd, 0x6bfbc021, 0x44e4d71c, 0x6be0ba7b, 0x450f2edb, 0x6bc5a431, 0x45397bf4, 0x6baa7d49, 0x4563be60, 0x6b8f45c7, 0x458df619, 0x6b73fdae, 0x45b82318, 0x6b58a503, 0x45e24556, 0x6b3d3bcb, 0x460c5cce, 0x6b21c208, 0x46366978, 0x6b0637c1, 0x46606b4e, 0x6aea9cf8, 0x468a624a, 0x6acef1b2, 0x46b44e65, 0x6ab335f4, 0x46de2f99, 0x6a9769c1, 0x470805df, 0x6a7b8d1e, 0x4731d131, 0x6a5fa010, 0x475b9188, 0x6a43a29a, 0x478546de, 0x6a2794c1, 0x47aef12c, 0x6a0b7689, 0x47d8906d, 0x69ef47f6, 0x48022499, 0x69d3090e, 0x482badab, 0x69b6b9d3, 0x48552b9b, 0x699a5a4c, 0x487e9e64, 0x697dea7b, 0x48a805ff, 0x69616a65, 0x48d16265, 0x6944da10, 0x48fab391, 0x6928397e, 0x4923f97b, 0x690b88b5, 0x494d341e, 0x68eec7b9, 0x49766373, 0x68d1f68f, 0x499f8774, 0x68b5153a, 0x49c8a01b, 0x689823bf, 0x49f1ad61, 0x687b2224, 0x4a1aaf3f, 0x685e106c, 0x4a43a5b0, 0x6840ee9b, 0x4a6c90ad, 0x6823bcb7, 0x4a957030, 0x68067ac3, 0x4abe4433, 0x67e928c5, 0x4ae70caf, 0x67cbc6c0, 0x4b0fc99d, 0x67ae54ba, 0x4b387af9, 0x6790d2b6, 0x4b6120bb, 0x677340ba, 0x4b89badd, 0x67559eca, 0x4bb24958, 0x6737ecea, 0x4bdacc28, 0x671a2b20, 0x4c034345, 0x66fc596f, 0x4c2baea9, 0x66de77dc, 0x4c540e4e, 0x66c0866d, 0x4c7c622d, 0x66a28524, 0x4ca4aa41, 0x66847408, 0x4ccce684, 0x6666531d, 0x4cf516ee, 0x66482267, 0x4d1d3b7a, 0x6629e1ec, 0x4d455422, 0x660b91af, 0x4d6d60df, 0x65ed31b5, 0x4d9561ac, 0x65cec204, 0x4dbd5682, 0x65b0429f, 0x4de53f5a, 0x6591b38c, 0x4e0d1c30, 0x657314cf, 0x4e34ecfc, 0x6554666d, 0x4e5cb1b9, 0x6535a86b, 0x4e846a60, 0x6516dacd, 0x4eac16eb, 0x64f7fd98, 0x4ed3b755, 0x64d910d1, 0x4efb4b96, 0x64ba147d, 0x4f22d3aa, 0x649b08a0, 0x4f4a4f89, 0x647bed3f, 0x4f71bf2e, 0x645cc260, 0x4f992293, 0x643d8806, 0x4fc079b1, 0x641e3e38, 0x4fe7c483, 0x63fee4f8, 0x500f0302, 0x63df7c4d, 0x50363529, 0x63c0043b, 0x505d5af1, 0x63a07cc7, 0x50847454, 0x6380e5f6, 0x50ab814d, 0x63613fcd, 0x50d281d5, 0x63418a50, 0x50f975e6, 0x6321c585, 0x51205d7b, 0x6301f171, 0x5147388c, 0x62e20e17, 0x516e0715, 0x62c21b7e, 0x5194c910, 0x62a219aa, 0x51bb7e75, 0x628208a1, 0x51e22740, 0x6261e866, 0x5208c36a, 0x6241b8ff, 0x522f52ee, 0x62217a72, 0x5255d5c5, 0x62012cc2, 0x527c4bea, 0x61e0cff5, 0x52a2b556, 0x61c06410, 0x52c91204, 0x619fe918, 0x52ef61ee, 0x617f5f12, 0x5315a50e, 0x615ec603, 0x533bdb5d, 0x613e1df0, 0x536204d7, 0x611d66de, 0x53882175, 0x60fca0d2, 0x53ae3131, 0x60dbcbd1, 0x53d43406, 0x60bae7e1, 0x53fa29ed, 0x6099f505, 0x542012e1, 0x6078f344, 0x5445eedb, 0x6057e2a2, 0x546bbdd7, 0x6036c325, 0x54917fce, 0x601594d1, 0x54b734ba, 0x5ff457ad, 0x54dcdc96, 0x5fd30bbc, 0x5502775c, 0x5fb1b104, 0x55280505, 0x5f90478a, 0x554d858d, 0x5f6ecf53, 0x5572f8ed, 0x5f4d4865, 0x55985f20, 0x5f2bb2c5, 0x55bdb81f, 0x5f0a0e77, 0x55e303e6, 0x5ee85b82, 0x5608426e, 0x5ec699e9, 0x562d73b2, 0x5ea4c9b3, 0x565297ab, 0x5e82eae5, 0x5677ae54, 0x5e60fd84, 0x569cb7a8, 0x5e3f0194, 0x56c1b3a1, 0x5e1cf71c, 0x56e6a239, 0x5dfade20, 0x570b8369, 0x5dd8b6a7, 0x5730572e, 0x5db680b4, 0x57551d80, 0x5d943c4e, 0x5779d65b, 0x5d71e979, 0x579e81b8, 0x5d4f883b, 0x57c31f92, 0x5d2d189a, 0x57e7afe4, 0x5d0a9a9a, 0x580c32a7, 0x5ce80e41, 0x5830a7d6, 0x5cc57394, 0x58550f6c, 0x5ca2ca99, 0x58796962, 0x5c801354, 0x589db5b3, 0x5c5d4dcc, 0x58c1f45b, 0x5c3a7a05, 0x58e62552, 0x5c179806, 0x590a4893, 0x5bf4a7d2, 0x592e5e19, 0x5bd1a971, 0x595265df, 0x5bae9ce7, 0x59765fde, 0x5b8b8239, 0x599a4c12, 0x5b68596d, 0x59be2a74, 0x5b452288, 0x59e1faff, 0x5b21dd90, 0x5a05bdae, 0x5afe8a8b, 0x5a29727b, 0x5adb297d, 0x5a4d1960, 0x5ab7ba6c, 0x5a70b258, 0x5a943d5e, }; const int kbdWindowOffset[NUM_IMDCT_SIZES] PROGMEM = {0, 128}; const int kbdWindow[128 + 1024] PROGMEM = { /* 128 - format = Q31 * 2^0 */ 0x00016f63, 0x7ffffffe, 0x0003e382, 0x7ffffff1, 0x00078f64, 0x7fffffc7, 0x000cc323, 0x7fffff5d, 0x0013d9ed, 0x7ffffe76, 0x001d3a9d, 0x7ffffcaa, 0x0029581f, 0x7ffff953, 0x0038b1bd, 0x7ffff372, 0x004bd34d, 0x7fffe98b, 0x00635538, 0x7fffd975, 0x007fdc64, 0x7fffc024, 0x00a219f1, 0x7fff995b, 0x00cacad0, 0x7fff5f5b, 0x00fab72d, 0x7fff0a75, 0x0132b1af, 0x7ffe9091, 0x01739689, 0x7ffde49e, 0x01be4a63, 0x7ffcf5ef, 0x0213b910, 0x7ffbaf84, 0x0274d41e, 0x7ff9f73a, 0x02e2913a, 0x7ff7acf1, 0x035de86c, 0x7ff4a99a, 0x03e7d233, 0x7ff0be3d, 0x0481457c, 0x7febb2f1, 0x052b357c, 0x7fe545d4, 0x05e68f77, 0x7fdd2a02, 0x06b4386f, 0x7fd30695, 0x07950acb, 0x7fc675b4, 0x0889d3ef, 0x7fb703be, 0x099351e0, 0x7fa42e89, 0x0ab230e0, 0x7f8d64d8, 0x0be70923, 0x7f7205f8, 0x0d325c93, 0x7f516195, 0x0e9494ae, 0x7f2ab7d0, 0x100e0085, 0x7efd3997, 0x119ed2ef, 0x7ec8094a, 0x134720d8, 0x7e8a3ba7, 0x1506dfdc, 0x7e42d906, 0x16dde50b, 0x7df0dee4, 0x18cbe3f7, 0x7d9341b4, 0x1ad06e07, 0x7d28ef02, 0x1ceaf215, 0x7cb0cfcc, 0x1f1abc4f, 0x7c29cb20, 0x215ef677, 0x7b92c8eb, 0x23b6a867, 0x7aeab4ec, 0x2620b8ec, 0x7a3081d0, 0x289beef5, 0x79632c5a, 0x2b26f30b, 0x7881be95, 0x2dc0511f, 0x778b5304, 0x30667aa2, 0x767f17c0, 0x3317c8dd, 0x755c5178, 0x35d27f98, 0x74225e50, 0x3894cff3, 0x72d0b887, 0x3b5cdb7b, 0x7166f8e7, 0x3e28b770, 0x6fe4d8e8, 0x40f6702a, 0x6e4a3491, 0x43c40caa, 0x6c970bfc, 0x468f9231, 0x6acb8483, 0x495707f5, 0x68e7e994, 0x4c187ac7, 0x66ecad1c, 0x4ed200c5, 0x64da6797, 0x5181bcea, 0x62b1d7b7, 0x5425e28e, 0x6073e1ae, 0x56bcb8c2, 0x5e218e16, 0x59449d76, 0x5bbc0875, /* 1024 - format = Q31 * 2^0 */ 0x0009962f, 0x7fffffa4, 0x000e16fb, 0x7fffff39, 0x0011ea65, 0x7ffffebf, 0x0015750e, 0x7ffffe34, 0x0018dc74, 0x7ffffd96, 0x001c332e, 0x7ffffce5, 0x001f83f5, 0x7ffffc1f, 0x0022d59a, 0x7ffffb43, 0x00262cc2, 0x7ffffa4f, 0x00298cc4, 0x7ffff942, 0x002cf81f, 0x7ffff81a, 0x003070c4, 0x7ffff6d6, 0x0033f840, 0x7ffff573, 0x00378fd9, 0x7ffff3f1, 0x003b38a1, 0x7ffff24d, 0x003ef381, 0x7ffff085, 0x0042c147, 0x7fffee98, 0x0046a2a8, 0x7fffec83, 0x004a9847, 0x7fffea44, 0x004ea2b7, 0x7fffe7d8, 0x0052c283, 0x7fffe53f, 0x0056f829, 0x7fffe274, 0x005b4422, 0x7fffdf76, 0x005fa6dd, 0x7fffdc43, 0x006420c8, 0x7fffd8d6, 0x0068b249, 0x7fffd52f, 0x006d5bc4, 0x7fffd149, 0x00721d9a, 0x7fffcd22, 0x0076f828, 0x7fffc8b6, 0x007bebca, 0x7fffc404, 0x0080f8d9, 0x7fffbf06, 0x00861fae, 0x7fffb9bb, 0x008b609e, 0x7fffb41e, 0x0090bbff, 0x7fffae2c, 0x00963224, 0x7fffa7e1, 0x009bc362, 0x7fffa13a, 0x00a17009, 0x7fff9a32, 0x00a7386c, 0x7fff92c5, 0x00ad1cdc, 0x7fff8af0, 0x00b31da8, 0x7fff82ad, 0x00b93b21, 0x7fff79f9, 0x00bf7596, 0x7fff70cf, 0x00c5cd57, 0x7fff672a, 0x00cc42b1, 0x7fff5d05, 0x00d2d5f3, 0x7fff525c, 0x00d9876c, 0x7fff4729, 0x00e05769, 0x7fff3b66, 0x00e74638, 0x7fff2f10, 0x00ee5426, 0x7fff221f, 0x00f58182, 0x7fff148e, 0x00fcce97, 0x7fff0658, 0x01043bb3, 0x7ffef776, 0x010bc923, 0x7ffee7e2, 0x01137733, 0x7ffed795, 0x011b4631, 0x7ffec68a, 0x01233669, 0x7ffeb4ba, 0x012b4827, 0x7ffea21d, 0x01337bb8, 0x7ffe8eac, 0x013bd167, 0x7ffe7a61, 0x01444982, 0x7ffe6533, 0x014ce454, 0x7ffe4f1c, 0x0155a229, 0x7ffe3813, 0x015e834d, 0x7ffe2011, 0x0167880c, 0x7ffe070d, 0x0170b0b2, 0x7ffdecff, 0x0179fd8b, 0x7ffdd1df, 0x01836ee1, 0x7ffdb5a2, 0x018d0500, 0x7ffd9842, 0x0196c035, 0x7ffd79b3, 0x01a0a0ca, 0x7ffd59ee, 0x01aaa70a, 0x7ffd38e8, 0x01b4d341, 0x7ffd1697, 0x01bf25b9, 0x7ffcf2f2, 0x01c99ebd, 0x7ffccdee, 0x01d43e99, 0x7ffca780, 0x01df0597, 0x7ffc7f9e, 0x01e9f401, 0x7ffc563d, 0x01f50a22, 0x7ffc2b51, 0x02004844, 0x7ffbfecf, 0x020baeb1, 0x7ffbd0ab, 0x02173db4, 0x7ffba0da, 0x0222f596, 0x7ffb6f4f, 0x022ed6a1, 0x7ffb3bfd, 0x023ae11f, 0x7ffb06d8, 0x02471558, 0x7ffacfd3, 0x02537397, 0x7ffa96e0, 0x025ffc25, 0x7ffa5bf2, 0x026caf4a, 0x7ffa1efc, 0x02798d4f, 0x7ff9dfee, 0x0286967c, 0x7ff99ebb, 0x0293cb1b, 0x7ff95b55, 0x02a12b72, 0x7ff915ab, 0x02aeb7cb, 0x7ff8cdaf, 0x02bc706d, 0x7ff88351, 0x02ca559f, 0x7ff83682, 0x02d867a9, 0x7ff7e731, 0x02e6a6d2, 0x7ff7954e, 0x02f51361, 0x7ff740c8, 0x0303ad9c, 0x7ff6e98e, 0x031275ca, 0x7ff68f8f, 0x03216c30, 0x7ff632ba, 0x03309116, 0x7ff5d2fb, 0x033fe4bf, 0x7ff57042, 0x034f6773, 0x7ff50a7a, 0x035f1975, 0x7ff4a192, 0x036efb0a, 0x7ff43576, 0x037f0c78, 0x7ff3c612, 0x038f4e02, 0x7ff35353, 0x039fbfeb, 0x7ff2dd24, 0x03b06279, 0x7ff26370, 0x03c135ed, 0x7ff1e623, 0x03d23a8b, 0x7ff16527, 0x03e37095, 0x7ff0e067, 0x03f4d84e, 0x7ff057cc, 0x040671f7, 0x7fefcb40, 0x04183dd3, 0x7fef3aad, 0x042a3c22, 0x7feea5fa, 0x043c6d25, 0x7fee0d11, 0x044ed11d, 0x7fed6fda, 0x04616849, 0x7fecce3d, 0x047432eb, 0x7fec2821, 0x04873140, 0x7feb7d6c, 0x049a6388, 0x7feace07, 0x04adca01, 0x7fea19d6, 0x04c164ea, 0x7fe960c0, 0x04d53481, 0x7fe8a2aa, 0x04e93902, 0x7fe7df79, 0x04fd72aa, 0x7fe71712, 0x0511e1b6, 0x7fe6495a, 0x05268663, 0x7fe57634, 0x053b60eb, 0x7fe49d83, 0x05507189, 0x7fe3bf2b, 0x0565b879, 0x7fe2db0f, 0x057b35f4, 0x7fe1f110, 0x0590ea35, 0x7fe10111, 0x05a6d574, 0x7fe00af3, 0x05bcf7ea, 0x7fdf0e97, 0x05d351cf, 0x7fde0bdd, 0x05e9e35c, 0x7fdd02a6, 0x0600acc8, 0x7fdbf2d2, 0x0617ae48, 0x7fdadc40, 0x062ee814, 0x7fd9becf, 0x06465a62, 0x7fd89a5e, 0x065e0565, 0x7fd76eca, 0x0675e954, 0x7fd63bf1, 0x068e0662, 0x7fd501b0, 0x06a65cc3, 0x7fd3bfe4, 0x06beecaa, 0x7fd2766a, 0x06d7b648, 0x7fd1251e, 0x06f0b9d1, 0x7fcfcbda, 0x0709f775, 0x7fce6a7a, 0x07236f65, 0x7fcd00d8, 0x073d21d2, 0x7fcb8ecf, 0x07570eea, 0x7fca1439, 0x077136dd, 0x7fc890ed, 0x078b99da, 0x7fc704c7, 0x07a6380d, 0x7fc56f9d, 0x07c111a4, 0x7fc3d147, 0x07dc26cc, 0x7fc2299e, 0x07f777b1, 0x7fc07878, 0x0813047d, 0x7fbebdac, 0x082ecd5b, 0x7fbcf90f, 0x084ad276, 0x7fbb2a78, 0x086713f7, 0x7fb951bc, 0x08839206, 0x7fb76eaf, 0x08a04ccb, 0x7fb58126, 0x08bd446e, 0x7fb388f4, 0x08da7915, 0x7fb185ee, 0x08f7eae7, 0x7faf77e5, 0x09159a09, 0x7fad5ead, 0x0933869f, 0x7fab3a17, 0x0951b0cd, 0x7fa909f6, 0x097018b7, 0x7fa6ce1a, 0x098ebe7f, 0x7fa48653, 0x09ada248, 0x7fa23273, 0x09ccc431, 0x7f9fd249, 0x09ec245b, 0x7f9d65a4, 0x0a0bc2e7, 0x7f9aec53, 0x0a2b9ff3, 0x7f986625, 0x0a4bbb9e, 0x7f95d2e7, 0x0a6c1604, 0x7f933267, 0x0a8caf43, 0x7f908472, 0x0aad8776, 0x7f8dc8d5, 0x0ace9eb9, 0x7f8aff5c, 0x0aeff526, 0x7f8827d3, 0x0b118ad8, 0x7f854204, 0x0b335fe6, 0x7f824dbb, 0x0b557469, 0x7f7f4ac3, 0x0b77c879, 0x7f7c38e4, 0x0b9a5c2b, 0x7f7917e9, 0x0bbd2f97, 0x7f75e79b, 0x0be042d0, 0x7f72a7c3, 0x0c0395ec, 0x7f6f5828, 0x0c2728fd, 0x7f6bf892, 0x0c4afc16, 0x7f6888c9, 0x0c6f0f4a, 0x7f650894, 0x0c9362a8, 0x7f6177b9, 0x0cb7f642, 0x7f5dd5ff, 0x0cdcca26, 0x7f5a232a, 0x0d01de63, 0x7f565f00, 0x0d273307, 0x7f528947, 0x0d4cc81f, 0x7f4ea1c2, 0x0d729db7, 0x7f4aa835, 0x0d98b3da, 0x7f469c65, 0x0dbf0a92, 0x7f427e13, 0x0de5a1e9, 0x7f3e4d04, 0x0e0c79e7, 0x7f3a08f9, 0x0e339295, 0x7f35b1b4, 0x0e5aebfa, 0x7f3146f8, 0x0e82861a, 0x7f2cc884, 0x0eaa60fd, 0x7f28361b, 0x0ed27ca5, 0x7f238f7c, 0x0efad917, 0x7f1ed467, 0x0f237656, 0x7f1a049d, 0x0f4c5462, 0x7f151fdc, 0x0f75733d, 0x7f1025e3, 0x0f9ed2e6, 0x7f0b1672, 0x0fc8735e, 0x7f05f146, 0x0ff254a1, 0x7f00b61d, 0x101c76ae, 0x7efb64b4, 0x1046d981, 0x7ef5fcca, 0x10717d15, 0x7ef07e19, 0x109c6165, 0x7eeae860, 0x10c7866a, 0x7ee53b5b, 0x10f2ec1e, 0x7edf76c4, 0x111e9279, 0x7ed99a58, 0x114a7971, 0x7ed3a5d1, 0x1176a0fc, 0x7ecd98eb, 0x11a30910, 0x7ec77360, 0x11cfb1a1, 0x7ec134eb, 0x11fc9aa2, 0x7ebadd44, 0x1229c406, 0x7eb46c27, 0x12572dbf, 0x7eade14c, 0x1284d7bc, 0x7ea73c6c, 0x12b2c1ed, 0x7ea07d41, 0x12e0ec42, 0x7e99a382, 0x130f56a8, 0x7e92aee7, 0x133e010b, 0x7e8b9f2a, 0x136ceb59, 0x7e847402, 0x139c157b, 0x7e7d2d25, 0x13cb7f5d, 0x7e75ca4c, 0x13fb28e6, 0x7e6e4b2d, 0x142b1200, 0x7e66af7f, 0x145b3a92, 0x7e5ef6f8, 0x148ba281, 0x7e572150, 0x14bc49b4, 0x7e4f2e3b, 0x14ed300f, 0x7e471d70, 0x151e5575, 0x7e3eeea5, 0x154fb9c9, 0x7e36a18e, 0x15815ced, 0x7e2e35e2, 0x15b33ec1, 0x7e25ab56, 0x15e55f25, 0x7e1d019e, 0x1617bdf9, 0x7e14386e, 0x164a5b19, 0x7e0b4f7d, 0x167d3662, 0x7e02467e, 0x16b04fb2, 0x7df91d25, 0x16e3a6e2, 0x7defd327, 0x17173bce, 0x7de66837, 0x174b0e4d, 0x7ddcdc0a, 0x177f1e39, 0x7dd32e53, 0x17b36b69, 0x7dc95ec6, 0x17e7f5b3, 0x7dbf6d17, 0x181cbcec, 0x7db558f9, 0x1851c0e9, 0x7dab221f, 0x1887017d, 0x7da0c83c, 0x18bc7e7c, 0x7d964b05, 0x18f237b6, 0x7d8baa2b, 0x19282cfd, 0x7d80e563, 0x195e5e20, 0x7d75fc5e, 0x1994caee, 0x7d6aeed0, 0x19cb7335, 0x7d5fbc6d, 0x1a0256c2, 0x7d5464e6, 0x1a397561, 0x7d48e7ef, 0x1a70cede, 0x7d3d453b, 0x1aa86301, 0x7d317c7c, 0x1ae03195, 0x7d258d65, 0x1b183a63, 0x7d1977aa, 0x1b507d30, 0x7d0d3afc, 0x1b88f9c5, 0x7d00d710, 0x1bc1afe6, 0x7cf44b97, 0x1bfa9f58, 0x7ce79846, 0x1c33c7e0, 0x7cdabcce, 0x1c6d293f, 0x7ccdb8e4, 0x1ca6c337, 0x7cc08c39, 0x1ce0958a, 0x7cb33682, 0x1d1a9ff8, 0x7ca5b772, 0x1d54e240, 0x7c980ebd, 0x1d8f5c21, 0x7c8a3c14, 0x1dca0d56, 0x7c7c3f2e, 0x1e04f59f, 0x7c6e17bc, 0x1e4014b4, 0x7c5fc573, 0x1e7b6a53, 0x7c514807, 0x1eb6f633, 0x7c429f2c, 0x1ef2b80f, 0x7c33ca96, 0x1f2eaf9e, 0x7c24c9fa, 0x1f6adc98, 0x7c159d0d, 0x1fa73eb2, 0x7c064383, 0x1fe3d5a3, 0x7bf6bd11, 0x2020a11e, 0x7be7096c, 0x205da0d8, 0x7bd7284a, 0x209ad483, 0x7bc71960, 0x20d83bd1, 0x7bb6dc65, 0x2115d674, 0x7ba6710d, 0x2153a41b, 0x7b95d710, 0x2191a476, 0x7b850e24, 0x21cfd734, 0x7b7415ff, 0x220e3c02, 0x7b62ee59, 0x224cd28d, 0x7b5196e9, 0x228b9a82, 0x7b400f67, 0x22ca938a, 0x7b2e578a, 0x2309bd52, 0x7b1c6f0b, 0x23491783, 0x7b0a55a1, 0x2388a1c4, 0x7af80b07, 0x23c85bbf, 0x7ae58ef5, 0x2408451a, 0x7ad2e124, 0x24485d7c, 0x7ac0014e, 0x2488a48a, 0x7aacef2e, 0x24c919e9, 0x7a99aa7e, 0x2509bd3d, 0x7a8632f8, 0x254a8e29, 0x7a728858, 0x258b8c50, 0x7a5eaa5a, 0x25ccb753, 0x7a4a98b9, 0x260e0ed3, 0x7a365333, 0x264f9271, 0x7a21d983, 0x269141cb, 0x7a0d2b68, 0x26d31c80, 0x79f8489e, 0x2715222f, 0x79e330e4, 0x27575273, 0x79cde3f8, 0x2799acea, 0x79b8619a, 0x27dc3130, 0x79a2a989, 0x281ededf, 0x798cbb85, 0x2861b591, 0x7976974e, 0x28a4b4e0, 0x79603ca5, 0x28e7dc65, 0x7949ab4c, 0x292b2bb8, 0x7932e304, 0x296ea270, 0x791be390, 0x29b24024, 0x7904acb3, 0x29f6046b, 0x78ed3e30, 0x2a39eed8, 0x78d597cc, 0x2a7dff02, 0x78bdb94a, 0x2ac2347c, 0x78a5a270, 0x2b068eda, 0x788d5304, 0x2b4b0dae, 0x7874cacb, 0x2b8fb08a, 0x785c098d, 0x2bd47700, 0x78430f11, 0x2c1960a1, 0x7829db1f, 0x2c5e6cfd, 0x78106d7f, 0x2ca39ba3, 0x77f6c5fb, 0x2ce8ec23, 0x77dce45c, 0x2d2e5e0b, 0x77c2c86e, 0x2d73f0e8, 0x77a871fa, 0x2db9a449, 0x778de0cd, 0x2dff77b8, 0x777314b2, 0x2e456ac4, 0x77580d78, 0x2e8b7cf6, 0x773ccaeb, 0x2ed1addb, 0x77214cdb, 0x2f17fcfb, 0x77059315, 0x2f5e69e2, 0x76e99d69, 0x2fa4f419, 0x76cd6ba9, 0x2feb9b27, 0x76b0fda4, 0x30325e96, 0x7694532e, 0x30793dee, 0x76776c17, 0x30c038b5, 0x765a4834, 0x31074e72, 0x763ce759, 0x314e7eab, 0x761f4959, 0x3195c8e6, 0x76016e0b, 0x31dd2ca9, 0x75e35545, 0x3224a979, 0x75c4fedc, 0x326c3ed8, 0x75a66aab, 0x32b3ec4d, 0x75879887, 0x32fbb159, 0x7568884b, 0x33438d81, 0x754939d1, 0x338b8045, 0x7529acf4, 0x33d3892a, 0x7509e18e, 0x341ba7b1, 0x74e9d77d, 0x3463db5a, 0x74c98e9e, 0x34ac23a7, 0x74a906cd, 0x34f48019, 0x74883fec, 0x353cf02f, 0x746739d8, 0x3585736a, 0x7445f472, 0x35ce0949, 0x74246f9c, 0x3616b14c, 0x7402ab37, 0x365f6af0, 0x73e0a727, 0x36a835b5, 0x73be6350, 0x36f11118, 0x739bdf95, 0x3739fc98, 0x73791bdd, 0x3782f7b2, 0x7356180e, 0x37cc01e3, 0x7332d410, 0x38151aa8, 0x730f4fc9, 0x385e417e, 0x72eb8b24, 0x38a775e1, 0x72c7860a, 0x38f0b74d, 0x72a34066, 0x393a053e, 0x727eba24, 0x39835f30, 0x7259f331, 0x39ccc49e, 0x7234eb79, 0x3a163503, 0x720fa2eb, 0x3a5fafda, 0x71ea1977, 0x3aa9349e, 0x71c44f0c, 0x3af2c2ca, 0x719e439d, 0x3b3c59d7, 0x7177f71a, 0x3b85f940, 0x71516978, 0x3bcfa07e, 0x712a9aaa, 0x3c194f0d, 0x71038aa4, 0x3c630464, 0x70dc395e, 0x3cacbfff, 0x70b4a6cd, 0x3cf68155, 0x708cd2e9, 0x3d4047e1, 0x7064bdab, 0x3d8a131c, 0x703c670d, 0x3dd3e27e, 0x7013cf0a, 0x3e1db580, 0x6feaf59c, 0x3e678b9b, 0x6fc1dac1, 0x3eb16449, 0x6f987e76, 0x3efb3f01, 0x6f6ee0b9, 0x3f451b3d, 0x6f45018b, 0x3f8ef874, 0x6f1ae0eb, 0x3fd8d620, 0x6ef07edb, 0x4022b3b9, 0x6ec5db5d, 0x406c90b7, 0x6e9af675, 0x40b66c93, 0x6e6fd027, 0x410046c5, 0x6e446879, 0x414a1ec6, 0x6e18bf71, 0x4193f40d, 0x6decd517, 0x41ddc615, 0x6dc0a972, 0x42279455, 0x6d943c8d, 0x42715e45, 0x6d678e71, 0x42bb235f, 0x6d3a9f2a, 0x4304e31a, 0x6d0d6ec5, 0x434e9cf1, 0x6cdffd4f, 0x4398505b, 0x6cb24ad6, 0x43e1fcd1, 0x6c84576b, 0x442ba1cd, 0x6c56231c, 0x44753ec7, 0x6c27adfd, 0x44bed33a, 0x6bf8f81e, 0x45085e9d, 0x6bca0195, 0x4551e06b, 0x6b9aca75, 0x459b581e, 0x6b6b52d5, 0x45e4c52f, 0x6b3b9ac9, 0x462e2717, 0x6b0ba26b, 0x46777d52, 0x6adb69d3, 0x46c0c75a, 0x6aaaf11b, 0x470a04a9, 0x6a7a385c, 0x475334b9, 0x6a493fb3, 0x479c5707, 0x6a18073d, 0x47e56b0c, 0x69e68f17, 0x482e7045, 0x69b4d761, 0x4877662c, 0x6982e039, 0x48c04c3f, 0x6950a9c0, 0x490921f8, 0x691e341a, 0x4951e6d5, 0x68eb7f67, 0x499a9a51, 0x68b88bcd, 0x49e33beb, 0x68855970, 0x4a2bcb1f, 0x6851e875, 0x4a74476b, 0x681e3905, 0x4abcb04c, 0x67ea4b47, 0x4b050541, 0x67b61f63, 0x4b4d45c9, 0x6781b585, 0x4b957162, 0x674d0dd6, 0x4bdd878c, 0x67182883, 0x4c2587c6, 0x66e305b8, 0x4c6d7190, 0x66ada5a5, 0x4cb5446a, 0x66780878, 0x4cfcffd5, 0x66422e60, 0x4d44a353, 0x660c1790, 0x4d8c2e64, 0x65d5c439, 0x4dd3a08c, 0x659f348e, 0x4e1af94b, 0x656868c3, 0x4e623825, 0x6531610d, 0x4ea95c9d, 0x64fa1da3, 0x4ef06637, 0x64c29ebb, 0x4f375477, 0x648ae48d, 0x4f7e26e1, 0x6452ef53, 0x4fc4dcfb, 0x641abf46, 0x500b7649, 0x63e254a2, 0x5051f253, 0x63a9afa2, 0x5098509f, 0x6370d083, 0x50de90b3, 0x6337b784, 0x5124b218, 0x62fe64e3, 0x516ab455, 0x62c4d8e0, 0x51b096f3, 0x628b13bc, 0x51f6597b, 0x625115b8, 0x523bfb78, 0x6216df18, 0x52817c72, 0x61dc701f, 0x52c6dbf5, 0x61a1c912, 0x530c198d, 0x6166ea36, 0x535134c5, 0x612bd3d2, 0x53962d2a, 0x60f0862d, 0x53db024a, 0x60b50190, 0x541fb3b1, 0x60794644, 0x546440ef, 0x603d5494, 0x54a8a992, 0x60012cca, 0x54eced2b, 0x5fc4cf33, 0x55310b48, 0x5f883c1c, 0x5575037c, 0x5f4b73d2, 0x55b8d558, 0x5f0e76a5, 0x55fc806f, 0x5ed144e5, 0x56400452, 0x5e93dee1, 0x56836096, 0x5e5644ec, 0x56c694cf, 0x5e187757, 0x5709a092, 0x5dda7677, 0x574c8374, 0x5d9c429f, 0x578f3d0d, 0x5d5ddc24, 0x57d1ccf2, 0x5d1f435d, 0x581432bd, 0x5ce078a0, 0x58566e04, 0x5ca17c45, 0x58987e63, 0x5c624ea4, 0x58da6372, 0x5c22f016, 0x591c1ccc, 0x5be360f6, 0x595daa0d, 0x5ba3a19f, 0x599f0ad1, 0x5b63b26c, 0x59e03eb6, 0x5b2393ba, 0x5a214558, 0x5ae345e7, 0x5a621e56, 0x5aa2c951, }; /* bit reverse tables for FFT */ const uint8_t bitrevtabOffset[NUM_IMDCT_SIZES] PROGMEM = {0, 17}; const uint8_t bitrevtab[17 + 129] PROGMEM = { /* nfft = 64 */ 0x01, 0x08, 0x02, 0x04, 0x03, 0x0c, 0x05, 0x0a, 0x07, 0x0e, 0x0b, 0x0d, 0x00, 0x06, 0x09, 0x0f, 0x00, /* nfft = 512 */ 0x01, 0x40, 0x02, 0x20, 0x03, 0x60, 0x04, 0x10, 0x05, 0x50, 0x06, 0x30, 0x07, 0x70, 0x09, 0x48, 0x0a, 0x28, 0x0b, 0x68, 0x0c, 0x18, 0x0d, 0x58, 0x0e, 0x38, 0x0f, 0x78, 0x11, 0x44, 0x12, 0x24, 0x13, 0x64, 0x15, 0x54, 0x16, 0x34, 0x17, 0x74, 0x19, 0x4c, 0x1a, 0x2c, 0x1b, 0x6c, 0x1d, 0x5c, 0x1e, 0x3c, 0x1f, 0x7c, 0x21, 0x42, 0x23, 0x62, 0x25, 0x52, 0x26, 0x32, 0x27, 0x72, 0x29, 0x4a, 0x2b, 0x6a, 0x2d, 0x5a, 0x2e, 0x3a, 0x2f, 0x7a, 0x31, 0x46, 0x33, 0x66, 0x35, 0x56, 0x37, 0x76, 0x39, 0x4e, 0x3b, 0x6e, 0x3d, 0x5e, 0x3f, 0x7e, 0x43, 0x61, 0x45, 0x51, 0x47, 0x71, 0x4b, 0x69, 0x4d, 0x59, 0x4f, 0x79, 0x53, 0x65, 0x57, 0x75, 0x5b, 0x6d, 0x5f, 0x7d, 0x67, 0x73, 0x6f, 0x7b, 0x00, 0x08, 0x14, 0x1c, 0x22, 0x2a, 0x36, 0x3e, 0x41, 0x49, 0x55, 0x5d, 0x63, 0x6b, 0x77, 0x7f, 0x00, }; const uint8_t uniqueIDTab[8] = {0x5f, 0x4b, 0x43, 0x5f, 0x5f, 0x4a, 0x52, 0x5f}; const uint32_t twidTabOdd[8*6 + 32*6 + 128*6] PROGMEM = { 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x539eba45, 0xe7821d59, 0x4b418bbe, 0xf383a3e2, 0x58c542c5, 0xdc71898d, 0x5a82799a, 0xd2bec333, 0x539eba45, 0xe7821d59, 0x539eba45, 0xc4df2862, 0x539eba45, 0xc4df2862, 0x58c542c5, 0xdc71898d, 0x3248d382, 0xc13ad060, 0x40000000, 0xc0000000, 0x5a82799a, 0xd2bec333, 0x00000000, 0xd2bec333, 0x22a2f4f8, 0xc4df2862, 0x58c542c5, 0xcac933ae, 0xcdb72c7e, 0xf383a3e2, 0x00000000, 0xd2bec333, 0x539eba45, 0xc4df2862, 0xac6145bb, 0x187de2a7, 0xdd5d0b08, 0xe7821d59, 0x4b418bbe, 0xc13ad060, 0xa73abd3b, 0x3536cc52, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x45f704f7, 0xf9ba1651, 0x43103085, 0xfcdc1342, 0x48b2b335, 0xf69bf7c9, 0x4b418bbe, 0xf383a3e2, 0x45f704f7, 0xf9ba1651, 0x4fd288dc, 0xed6bf9d1, 0x4fd288dc, 0xed6bf9d1, 0x48b2b335, 0xf69bf7c9, 0x553805f2, 0xe4a2eff6, 0x539eba45, 0xe7821d59, 0x4b418bbe, 0xf383a3e2, 0x58c542c5, 0xdc71898d, 0x569cc31b, 0xe1d4a2c8, 0x4da1fab5, 0xf0730342, 0x5a6690ae, 0xd5052d97, 0x58c542c5, 0xdc71898d, 0x4fd288dc, 0xed6bf9d1, 0x5a12e720, 0xce86ff2a, 0x5a12e720, 0xd76619b6, 0x51d1dc80, 0xea70658a, 0x57cc15bc, 0xc91af976, 0x5a82799a, 0xd2bec333, 0x539eba45, 0xe7821d59, 0x539eba45, 0xc4df2862, 0x5a12e720, 0xce86ff2a, 0x553805f2, 0xe4a2eff6, 0x4da1fab5, 0xc1eb0209, 0x58c542c5, 0xcac933ae, 0x569cc31b, 0xe1d4a2c8, 0x45f704f7, 0xc04ee4b8, 0x569cc31b, 0xc78e9a1d, 0x57cc15bc, 0xdf18f0ce, 0x3cc85709, 0xc013bc39, 0x539eba45, 0xc4df2862, 0x58c542c5, 0xdc71898d, 0x3248d382, 0xc13ad060, 0x4fd288dc, 0xc2c17d52, 0x5987b08a, 0xd9e01006, 0x26b2a794, 0xc3bdbdf6, 0x4b418bbe, 0xc13ad060, 0x5a12e720, 0xd76619b6, 0x1a4608ab, 0xc78e9a1d, 0x45f704f7, 0xc04ee4b8, 0x5a6690ae, 0xd5052d97, 0x0d47d096, 0xcc983f70, 0x40000000, 0xc0000000, 0x5a82799a, 0xd2bec333, 0x00000000, 0xd2bec333, 0x396b3199, 0xc04ee4b8, 0x5a6690ae, 0xd09441bb, 0xf2b82f6a, 0xd9e01006, 0x3248d382, 0xc13ad060, 0x5a12e720, 0xce86ff2a, 0xe5b9f755, 0xe1d4a2c8, 0x2aaa7c7f, 0xc2c17d52, 0x5987b08a, 0xcc983f70, 0xd94d586c, 0xea70658a, 0x22a2f4f8, 0xc4df2862, 0x58c542c5, 0xcac933ae, 0xcdb72c7e, 0xf383a3e2, 0x1a4608ab, 0xc78e9a1d, 0x57cc15bc, 0xc91af976, 0xc337a8f7, 0xfcdc1342, 0x11a855df, 0xcac933ae, 0x569cc31b, 0xc78e9a1d, 0xba08fb09, 0x0645e9af, 0x08df1a8c, 0xce86ff2a, 0x553805f2, 0xc6250a18, 0xb25e054b, 0x0f8cfcbe, 0x00000000, 0xd2bec333, 0x539eba45, 0xc4df2862, 0xac6145bb, 0x187de2a7, 0xf720e574, 0xd76619b6, 0x51d1dc80, 0xc3bdbdf6, 0xa833ea44, 0x20e70f32, 0xee57aa21, 0xdc71898d, 0x4fd288dc, 0xc2c17d52, 0xa5ed18e0, 0x2899e64a, 0xe5b9f755, 0xe1d4a2c8, 0x4da1fab5, 0xc1eb0209, 0xa5996f52, 0x2f6bbe45, 0xdd5d0b08, 0xe7821d59, 0x4b418bbe, 0xc13ad060, 0xa73abd3b, 0x3536cc52, 0xd5558381, 0xed6bf9d1, 0x48b2b335, 0xc0b15502, 0xaac7fa0e, 0x39daf5e8, 0xcdb72c7e, 0xf383a3e2, 0x45f704f7, 0xc04ee4b8, 0xb02d7724, 0x3d3e82ae, 0xc694ce67, 0xf9ba1651, 0x43103085, 0xc013bc39, 0xb74d4ccb, 0x3f4eaafe, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x418d2621, 0xfe6deaa1, 0x40c7d2bd, 0xff36f170, 0x424ff28f, 0xfda4f351, 0x43103085, 0xfcdc1342, 0x418d2621, 0xfe6deaa1, 0x4488e37f, 0xfb4ab7db, 0x4488e37f, 0xfb4ab7db, 0x424ff28f, 0xfda4f351, 0x46aa0d6d, 0xf8f21e8e, 0x45f704f7, 0xf9ba1651, 0x43103085, 0xfcdc1342, 0x48b2b335, 0xf69bf7c9, 0x475a5c77, 0xf82a6c6a, 0x43cdd89a, 0xfc135231, 0x4aa22036, 0xf4491311, 0x48b2b335, 0xf69bf7c9, 0x4488e37f, 0xfb4ab7db, 0x4c77a88e, 0xf1fa3ecb, 0x49ffd417, 0xf50ef5de, 0x454149fc, 0xfa824bfd, 0x4e32a956, 0xefb047f2, 0x4b418bbe, 0xf383a3e2, 0x45f704f7, 0xf9ba1651, 0x4fd288dc, 0xed6bf9d1, 0x4c77a88e, 0xf1fa3ecb, 0x46aa0d6d, 0xf8f21e8e, 0x5156b6d9, 0xeb2e1dbe, 0x4da1fab5, 0xf0730342, 0x475a5c77, 0xf82a6c6a, 0x52beac9f, 0xe8f77acf, 0x4ec05432, 0xeeee2d9d, 0x4807eb4b, 0xf7630799, 0x5409ed4b, 0xe6c8d59c, 0x4fd288dc, 0xed6bf9d1, 0x48b2b335, 0xf69bf7c9, 0x553805f2, 0xe4a2eff6, 0x50d86e6d, 0xebeca36c, 0x495aada2, 0xf5d544a7, 0x56488dc5, 0xe28688a4, 0x51d1dc80, 0xea70658a, 0x49ffd417, 0xf50ef5de, 0x573b2635, 0xe0745b24, 0x52beac9f, 0xe8f77acf, 0x4aa22036, 0xf4491311, 0x580f7b19, 0xde6d1f65, 0x539eba45, 0xe7821d59, 0x4b418bbe, 0xf383a3e2, 0x58c542c5, 0xdc71898d, 0x5471e2e6, 0xe61086bc, 0x4bde1089, 0xf2beafed, 0x595c3e2a, 0xda8249b4, 0x553805f2, 0xe4a2eff6, 0x4c77a88e, 0xf1fa3ecb, 0x59d438e5, 0xd8a00bae, 0x55f104dc, 0xe3399167, 0x4d0e4de2, 0xf136580d, 0x5a2d0957, 0xd6cb76c9, 0x569cc31b, 0xe1d4a2c8, 0x4da1fab5, 0xf0730342, 0x5a6690ae, 0xd5052d97, 0x573b2635, 0xe0745b24, 0x4e32a956, 0xefb047f2, 0x5a80baf6, 0xd34dcdb4, 0x57cc15bc, 0xdf18f0ce, 0x4ec05432, 0xeeee2d9d, 0x5a7b7f1a, 0xd1a5ef90, 0x584f7b58, 0xddc29958, 0x4f4af5d1, 0xee2cbbc1, 0x5a56deec, 0xd00e2639, 0x58c542c5, 0xdc71898d, 0x4fd288dc, 0xed6bf9d1, 0x5a12e720, 0xce86ff2a, 0x592d59da, 0xdb25f566, 0x50570819, 0xecabef3d, 0x59afaf4c, 0xcd110216, 0x5987b08a, 0xd9e01006, 0x50d86e6d, 0xebeca36c, 0x592d59da, 0xcbacb0bf, 0x59d438e5, 0xd8a00bae, 0x5156b6d9, 0xeb2e1dbe, 0x588c1404, 0xca5a86c4, 0x5a12e720, 0xd76619b6, 0x51d1dc80, 0xea70658a, 0x57cc15bc, 0xc91af976, 0x5a43b190, 0xd6326a88, 0x5249daa2, 0xe9b38223, 0x56eda1a0, 0xc7ee77b3, 0x5a6690ae, 0xd5052d97, 0x52beac9f, 0xe8f77acf, 0x55f104dc, 0xc6d569be, 0x5a7b7f1a, 0xd3de9156, 0x53304df6, 0xe83c56cf, 0x54d69714, 0xc5d03118, 0x5a82799a, 0xd2bec333, 0x539eba45, 0xe7821d59, 0x539eba45, 0xc4df2862, 0x5a7b7f1a, 0xd1a5ef90, 0x5409ed4b, 0xe6c8d59c, 0x5249daa2, 0xc402a33c, 0x5a6690ae, 0xd09441bb, 0x5471e2e6, 0xe61086bc, 0x50d86e6d, 0xc33aee27, 0x5a43b190, 0xcf89e3e8, 0x54d69714, 0xe55937d5, 0x4f4af5d1, 0xc2884e6e, 0x5a12e720, 0xce86ff2a, 0x553805f2, 0xe4a2eff6, 0x4da1fab5, 0xc1eb0209, 0x59d438e5, 0xcd8bbb6d, 0x55962bc0, 0xe3edb628, 0x4bde1089, 0xc1633f8a, 0x5987b08a, 0xcc983f70, 0x55f104dc, 0xe3399167, 0x49ffd417, 0xc0f1360b, 0x592d59da, 0xcbacb0bf, 0x56488dc5, 0xe28688a4, 0x4807eb4b, 0xc0950d1d, 0x58c542c5, 0xcac933ae, 0x569cc31b, 0xe1d4a2c8, 0x45f704f7, 0xc04ee4b8, 0x584f7b58, 0xc9edeb50, 0x56eda1a0, 0xe123e6ad, 0x43cdd89a, 0xc01ed535, 0x57cc15bc, 0xc91af976, 0x573b2635, 0xe0745b24, 0x418d2621, 0xc004ef3f, 0x573b2635, 0xc8507ea7, 0x57854ddd, 0xdfc606f1, 0x3f35b59d, 0xc0013bd3, 0x569cc31b, 0xc78e9a1d, 0x57cc15bc, 0xdf18f0ce, 0x3cc85709, 0xc013bc39, 0x55f104dc, 0xc6d569be, 0x580f7b19, 0xde6d1f65, 0x3a45e1f7, 0xc03c6a07, 0x553805f2, 0xc6250a18, 0x584f7b58, 0xddc29958, 0x37af354c, 0xc07b371e, 0x5471e2e6, 0xc57d965d, 0x588c1404, 0xdd196538, 0x350536f1, 0xc0d00db6, 0x539eba45, 0xc4df2862, 0x58c542c5, 0xdc71898d, 0x3248d382, 0xc13ad060, 0x52beac9f, 0xc449d892, 0x58fb0568, 0xdbcb0cce, 0x2f7afdfc, 0xc1bb5a11, 0x51d1dc80, 0xc3bdbdf6, 0x592d59da, 0xdb25f566, 0x2c9caf6c, 0xc2517e31, 0x50d86e6d, 0xc33aee27, 0x595c3e2a, 0xda8249b4, 0x29aee694, 0xc2fd08a9, 0x4fd288dc, 0xc2c17d52, 0x5987b08a, 0xd9e01006, 0x26b2a794, 0xc3bdbdf6, 0x4ec05432, 0xc2517e31, 0x59afaf4c, 0xd93f4e9e, 0x23a8fb93, 0xc4935b3c, 0x4da1fab5, 0xc1eb0209, 0x59d438e5, 0xd8a00bae, 0x2092f05f, 0xc57d965d, 0x4c77a88e, 0xc18e18a7, 0x59f54bee, 0xd8024d59, 0x1d719810, 0xc67c1e18, 0x4b418bbe, 0xc13ad060, 0x5a12e720, 0xd76619b6, 0x1a4608ab, 0xc78e9a1d, 0x49ffd417, 0xc0f1360b, 0x5a2d0957, 0xd6cb76c9, 0x17115bc0, 0xc8b4ab32, 0x48b2b335, 0xc0b15502, 0x5a43b190, 0xd6326a88, 0x13d4ae08, 0xc9edeb50, 0x475a5c77, 0xc07b371e, 0x5a56deec, 0xd59afadb, 0x10911f04, 0xcb39edca, 0x45f704f7, 0xc04ee4b8, 0x5a6690ae, 0xd5052d97, 0x0d47d096, 0xcc983f70, 0x4488e37f, 0xc02c64a6, 0x5a72c63b, 0xd4710883, 0x09f9e6a1, 0xce0866b8, 0x43103085, 0xc013bc39, 0x5a7b7f1a, 0xd3de9156, 0x06a886a0, 0xcf89e3e8, 0x418d2621, 0xc004ef3f, 0x5a80baf6, 0xd34dcdb4, 0x0354d741, 0xd11c3142, 0x40000000, 0xc0000000, 0x5a82799a, 0xd2bec333, 0x00000000, 0xd2bec333, 0x3e68fb62, 0xc004ef3f, 0x5a80baf6, 0xd2317756, 0xfcab28bf, 0xd4710883, 0x3cc85709, 0xc013bc39, 0x5a7b7f1a, 0xd1a5ef90, 0xf9577960, 0xd6326a88, 0x3b1e5335, 0xc02c64a6, 0x5a72c63b, 0xd11c3142, 0xf606195f, 0xd8024d59, 0x396b3199, 0xc04ee4b8, 0x5a6690ae, 0xd09441bb, 0xf2b82f6a, 0xd9e01006, 0x37af354c, 0xc07b371e, 0x5a56deec, 0xd00e2639, 0xef6ee0fc, 0xdbcb0cce, 0x35eaa2c7, 0xc0b15502, 0x5a43b190, 0xcf89e3e8, 0xec2b51f8, 0xddc29958, 0x341dbfd3, 0xc0f1360b, 0x5a2d0957, 0xcf077fe1, 0xe8eea440, 0xdfc606f1, 0x3248d382, 0xc13ad060, 0x5a12e720, 0xce86ff2a, 0xe5b9f755, 0xe1d4a2c8, 0x306c2624, 0xc18e18a7, 0x59f54bee, 0xce0866b8, 0xe28e67f0, 0xe3edb628, 0x2e88013a, 0xc1eb0209, 0x59d438e5, 0xcd8bbb6d, 0xdf6d0fa1, 0xe61086bc, 0x2c9caf6c, 0xc2517e31, 0x59afaf4c, 0xcd110216, 0xdc57046d, 0xe83c56cf, 0x2aaa7c7f, 0xc2c17d52, 0x5987b08a, 0xcc983f70, 0xd94d586c, 0xea70658a, 0x28b1b544, 0xc33aee27, 0x595c3e2a, 0xcc217822, 0xd651196c, 0xecabef3d, 0x26b2a794, 0xc3bdbdf6, 0x592d59da, 0xcbacb0bf, 0xd3635094, 0xeeee2d9d, 0x24ada23d, 0xc449d892, 0x58fb0568, 0xcb39edca, 0xd0850204, 0xf136580d, 0x22a2f4f8, 0xc4df2862, 0x58c542c5, 0xcac933ae, 0xcdb72c7e, 0xf383a3e2, 0x2092f05f, 0xc57d965d, 0x588c1404, 0xca5a86c4, 0xcafac90f, 0xf5d544a7, 0x1e7de5df, 0xc6250a18, 0x584f7b58, 0xc9edeb50, 0xc850cab4, 0xf82a6c6a, 0x1c6427a9, 0xc6d569be, 0x580f7b19, 0xc9836582, 0xc5ba1e09, 0xfa824bfd, 0x1a4608ab, 0xc78e9a1d, 0x57cc15bc, 0xc91af976, 0xc337a8f7, 0xfcdc1342, 0x1823dc7d, 0xc8507ea7, 0x57854ddd, 0xc8b4ab32, 0xc0ca4a63, 0xff36f170, 0x15fdf758, 0xc91af976, 0x573b2635, 0xc8507ea7, 0xbe72d9df, 0x0192155f, 0x13d4ae08, 0xc9edeb50, 0x56eda1a0, 0xc7ee77b3, 0xbc322766, 0x03ecadcf, 0x11a855df, 0xcac933ae, 0x569cc31b, 0xc78e9a1d, 0xba08fb09, 0x0645e9af, 0x0f7944a7, 0xcbacb0bf, 0x56488dc5, 0xc730e997, 0xb7f814b5, 0x089cf867, 0x0d47d096, 0xcc983f70, 0x55f104dc, 0xc6d569be, 0xb6002be9, 0x0af10a22, 0x0b145041, 0xcd8bbb6d, 0x55962bc0, 0xc67c1e18, 0xb421ef77, 0x0d415013, 0x08df1a8c, 0xce86ff2a, 0x553805f2, 0xc6250a18, 0xb25e054b, 0x0f8cfcbe, 0x06a886a0, 0xcf89e3e8, 0x54d69714, 0xc5d03118, 0xb0b50a2f, 0x11d3443f, 0x0470ebdc, 0xd09441bb, 0x5471e2e6, 0xc57d965d, 0xaf279193, 0x14135c94, 0x0238a1c6, 0xd1a5ef90, 0x5409ed4b, 0xc52d3d18, 0xadb6255e, 0x164c7ddd, 0x00000000, 0xd2bec333, 0x539eba45, 0xc4df2862, 0xac6145bb, 0x187de2a7, 0xfdc75e3a, 0xd3de9156, 0x53304df6, 0xc4935b3c, 0xab2968ec, 0x1aa6c82b, 0xfb8f1424, 0xd5052d97, 0x52beac9f, 0xc449d892, 0xaa0efb24, 0x1cc66e99, 0xf9577960, 0xd6326a88, 0x5249daa2, 0xc402a33c, 0xa9125e60, 0x1edc1953, 0xf720e574, 0xd76619b6, 0x51d1dc80, 0xc3bdbdf6, 0xa833ea44, 0x20e70f32, 0xf4ebafbf, 0xd8a00bae, 0x5156b6d9, 0xc37b2b6a, 0xa773ebfc, 0x22e69ac8, 0xf2b82f6a, 0xd9e01006, 0x50d86e6d, 0xc33aee27, 0xa6d2a626, 0x24da0a9a, 0xf086bb59, 0xdb25f566, 0x50570819, 0xc2fd08a9, 0xa65050b4, 0x26c0b162, 0xee57aa21, 0xdc71898d, 0x4fd288dc, 0xc2c17d52, 0xa5ed18e0, 0x2899e64a, 0xec2b51f8, 0xddc29958, 0x4f4af5d1, 0xc2884e6e, 0xa5a92114, 0x2a650525, 0xea0208a8, 0xdf18f0ce, 0x4ec05432, 0xc2517e31, 0xa58480e6, 0x2c216eaa, 0xe7dc2383, 0xe0745b24, 0x4e32a956, 0xc21d0eb8, 0xa57f450a, 0x2dce88aa, 0xe5b9f755, 0xe1d4a2c8, 0x4da1fab5, 0xc1eb0209, 0xa5996f52, 0x2f6bbe45, 0xe39bd857, 0xe3399167, 0x4d0e4de2, 0xc1bb5a11, 0xa5d2f6a9, 0x30f8801f, 0xe1821a21, 0xe4a2eff6, 0x4c77a88e, 0xc18e18a7, 0xa62bc71b, 0x32744493, 0xdf6d0fa1, 0xe61086bc, 0x4bde1089, 0xc1633f8a, 0xa6a3c1d6, 0x33de87de, 0xdd5d0b08, 0xe7821d59, 0x4b418bbe, 0xc13ad060, 0xa73abd3b, 0x3536cc52, 0xdb525dc3, 0xe8f77acf, 0x4aa22036, 0xc114ccb9, 0xa7f084e7, 0x367c9a7e, 0xd94d586c, 0xea70658a, 0x49ffd417, 0xc0f1360b, 0xa8c4d9cb, 0x37af8159, 0xd74e4abc, 0xebeca36c, 0x495aada2, 0xc0d00db6, 0xa9b7723b, 0x38cf1669, 0xd5558381, 0xed6bf9d1, 0x48b2b335, 0xc0b15502, 0xaac7fa0e, 0x39daf5e8, 0xd3635094, 0xeeee2d9d, 0x4807eb4b, 0xc0950d1d, 0xabf612b5, 0x3ad2c2e8, 0xd177fec6, 0xf0730342, 0x475a5c77, 0xc07b371e, 0xad415361, 0x3bb6276e, 0xcf93d9dc, 0xf1fa3ecb, 0x46aa0d6d, 0xc063d405, 0xaea94927, 0x3c84d496, 0xcdb72c7e, 0xf383a3e2, 0x45f704f7, 0xc04ee4b8, 0xb02d7724, 0x3d3e82ae, 0xcbe2402d, 0xf50ef5de, 0x454149fc, 0xc03c6a07, 0xb1cd56aa, 0x3de2f148, 0xca155d39, 0xf69bf7c9, 0x4488e37f, 0xc02c64a6, 0xb3885772, 0x3e71e759, 0xc850cab4, 0xf82a6c6a, 0x43cdd89a, 0xc01ed535, 0xb55ddfca, 0x3eeb3347, 0xc694ce67, 0xf9ba1651, 0x43103085, 0xc013bc39, 0xb74d4ccb, 0x3f4eaafe, 0xc4e1accb, 0xfb4ab7db, 0x424ff28f, 0xc00b1a20, 0xb955f293, 0x3f9c2bfb, 0xc337a8f7, 0xfcdc1342, 0x418d2621, 0xc004ef3f, 0xbb771c81, 0x3fd39b5a, 0xc197049e, 0xfe6deaa1, 0x40c7d2bd, 0xc0013bd3, 0xbdb00d71, 0x3ff4e5e0, }; const uint32_t twidTabEven[4*6 + 16*6 + 64*6] PROGMEM = { 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x5a82799a, 0xd2bec333, 0x539eba45, 0xe7821d59, 0x539eba45, 0xc4df2862, 0x40000000, 0xc0000000, 0x5a82799a, 0xd2bec333, 0x00000000, 0xd2bec333, 0x00000000, 0xd2bec333, 0x539eba45, 0xc4df2862, 0xac6145bb, 0x187de2a7, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x4b418bbe, 0xf383a3e2, 0x45f704f7, 0xf9ba1651, 0x4fd288dc, 0xed6bf9d1, 0x539eba45, 0xe7821d59, 0x4b418bbe, 0xf383a3e2, 0x58c542c5, 0xdc71898d, 0x58c542c5, 0xdc71898d, 0x4fd288dc, 0xed6bf9d1, 0x5a12e720, 0xce86ff2a, 0x5a82799a, 0xd2bec333, 0x539eba45, 0xe7821d59, 0x539eba45, 0xc4df2862, 0x58c542c5, 0xcac933ae, 0x569cc31b, 0xe1d4a2c8, 0x45f704f7, 0xc04ee4b8, 0x539eba45, 0xc4df2862, 0x58c542c5, 0xdc71898d, 0x3248d382, 0xc13ad060, 0x4b418bbe, 0xc13ad060, 0x5a12e720, 0xd76619b6, 0x1a4608ab, 0xc78e9a1d, 0x40000000, 0xc0000000, 0x5a82799a, 0xd2bec333, 0x00000000, 0xd2bec333, 0x3248d382, 0xc13ad060, 0x5a12e720, 0xce86ff2a, 0xe5b9f755, 0xe1d4a2c8, 0x22a2f4f8, 0xc4df2862, 0x58c542c5, 0xcac933ae, 0xcdb72c7e, 0xf383a3e2, 0x11a855df, 0xcac933ae, 0x569cc31b, 0xc78e9a1d, 0xba08fb09, 0x0645e9af, 0x00000000, 0xd2bec333, 0x539eba45, 0xc4df2862, 0xac6145bb, 0x187de2a7, 0xee57aa21, 0xdc71898d, 0x4fd288dc, 0xc2c17d52, 0xa5ed18e0, 0x2899e64a, 0xdd5d0b08, 0xe7821d59, 0x4b418bbe, 0xc13ad060, 0xa73abd3b, 0x3536cc52, 0xcdb72c7e, 0xf383a3e2, 0x45f704f7, 0xc04ee4b8, 0xb02d7724, 0x3d3e82ae, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x43103085, 0xfcdc1342, 0x418d2621, 0xfe6deaa1, 0x4488e37f, 0xfb4ab7db, 0x45f704f7, 0xf9ba1651, 0x43103085, 0xfcdc1342, 0x48b2b335, 0xf69bf7c9, 0x48b2b335, 0xf69bf7c9, 0x4488e37f, 0xfb4ab7db, 0x4c77a88e, 0xf1fa3ecb, 0x4b418bbe, 0xf383a3e2, 0x45f704f7, 0xf9ba1651, 0x4fd288dc, 0xed6bf9d1, 0x4da1fab5, 0xf0730342, 0x475a5c77, 0xf82a6c6a, 0x52beac9f, 0xe8f77acf, 0x4fd288dc, 0xed6bf9d1, 0x48b2b335, 0xf69bf7c9, 0x553805f2, 0xe4a2eff6, 0x51d1dc80, 0xea70658a, 0x49ffd417, 0xf50ef5de, 0x573b2635, 0xe0745b24, 0x539eba45, 0xe7821d59, 0x4b418bbe, 0xf383a3e2, 0x58c542c5, 0xdc71898d, 0x553805f2, 0xe4a2eff6, 0x4c77a88e, 0xf1fa3ecb, 0x59d438e5, 0xd8a00bae, 0x569cc31b, 0xe1d4a2c8, 0x4da1fab5, 0xf0730342, 0x5a6690ae, 0xd5052d97, 0x57cc15bc, 0xdf18f0ce, 0x4ec05432, 0xeeee2d9d, 0x5a7b7f1a, 0xd1a5ef90, 0x58c542c5, 0xdc71898d, 0x4fd288dc, 0xed6bf9d1, 0x5a12e720, 0xce86ff2a, 0x5987b08a, 0xd9e01006, 0x50d86e6d, 0xebeca36c, 0x592d59da, 0xcbacb0bf, 0x5a12e720, 0xd76619b6, 0x51d1dc80, 0xea70658a, 0x57cc15bc, 0xc91af976, 0x5a6690ae, 0xd5052d97, 0x52beac9f, 0xe8f77acf, 0x55f104dc, 0xc6d569be, 0x5a82799a, 0xd2bec333, 0x539eba45, 0xe7821d59, 0x539eba45, 0xc4df2862, 0x5a6690ae, 0xd09441bb, 0x5471e2e6, 0xe61086bc, 0x50d86e6d, 0xc33aee27, 0x5a12e720, 0xce86ff2a, 0x553805f2, 0xe4a2eff6, 0x4da1fab5, 0xc1eb0209, 0x5987b08a, 0xcc983f70, 0x55f104dc, 0xe3399167, 0x49ffd417, 0xc0f1360b, 0x58c542c5, 0xcac933ae, 0x569cc31b, 0xe1d4a2c8, 0x45f704f7, 0xc04ee4b8, 0x57cc15bc, 0xc91af976, 0x573b2635, 0xe0745b24, 0x418d2621, 0xc004ef3f, 0x569cc31b, 0xc78e9a1d, 0x57cc15bc, 0xdf18f0ce, 0x3cc85709, 0xc013bc39, 0x553805f2, 0xc6250a18, 0x584f7b58, 0xddc29958, 0x37af354c, 0xc07b371e, 0x539eba45, 0xc4df2862, 0x58c542c5, 0xdc71898d, 0x3248d382, 0xc13ad060, 0x51d1dc80, 0xc3bdbdf6, 0x592d59da, 0xdb25f566, 0x2c9caf6c, 0xc2517e31, 0x4fd288dc, 0xc2c17d52, 0x5987b08a, 0xd9e01006, 0x26b2a794, 0xc3bdbdf6, 0x4da1fab5, 0xc1eb0209, 0x59d438e5, 0xd8a00bae, 0x2092f05f, 0xc57d965d, 0x4b418bbe, 0xc13ad060, 0x5a12e720, 0xd76619b6, 0x1a4608ab, 0xc78e9a1d, 0x48b2b335, 0xc0b15502, 0x5a43b190, 0xd6326a88, 0x13d4ae08, 0xc9edeb50, 0x45f704f7, 0xc04ee4b8, 0x5a6690ae, 0xd5052d97, 0x0d47d096, 0xcc983f70, 0x43103085, 0xc013bc39, 0x5a7b7f1a, 0xd3de9156, 0x06a886a0, 0xcf89e3e8, 0x40000000, 0xc0000000, 0x5a82799a, 0xd2bec333, 0x00000000, 0xd2bec333, 0x3cc85709, 0xc013bc39, 0x5a7b7f1a, 0xd1a5ef90, 0xf9577960, 0xd6326a88, 0x396b3199, 0xc04ee4b8, 0x5a6690ae, 0xd09441bb, 0xf2b82f6a, 0xd9e01006, 0x35eaa2c7, 0xc0b15502, 0x5a43b190, 0xcf89e3e8, 0xec2b51f8, 0xddc29958, 0x3248d382, 0xc13ad060, 0x5a12e720, 0xce86ff2a, 0xe5b9f755, 0xe1d4a2c8, 0x2e88013a, 0xc1eb0209, 0x59d438e5, 0xcd8bbb6d, 0xdf6d0fa1, 0xe61086bc, 0x2aaa7c7f, 0xc2c17d52, 0x5987b08a, 0xcc983f70, 0xd94d586c, 0xea70658a, 0x26b2a794, 0xc3bdbdf6, 0x592d59da, 0xcbacb0bf, 0xd3635094, 0xeeee2d9d, 0x22a2f4f8, 0xc4df2862, 0x58c542c5, 0xcac933ae, 0xcdb72c7e, 0xf383a3e2, 0x1e7de5df, 0xc6250a18, 0x584f7b58, 0xc9edeb50, 0xc850cab4, 0xf82a6c6a, 0x1a4608ab, 0xc78e9a1d, 0x57cc15bc, 0xc91af976, 0xc337a8f7, 0xfcdc1342, 0x15fdf758, 0xc91af976, 0x573b2635, 0xc8507ea7, 0xbe72d9df, 0x0192155f, 0x11a855df, 0xcac933ae, 0x569cc31b, 0xc78e9a1d, 0xba08fb09, 0x0645e9af, 0x0d47d096, 0xcc983f70, 0x55f104dc, 0xc6d569be, 0xb6002be9, 0x0af10a22, 0x08df1a8c, 0xce86ff2a, 0x553805f2, 0xc6250a18, 0xb25e054b, 0x0f8cfcbe, 0x0470ebdc, 0xd09441bb, 0x5471e2e6, 0xc57d965d, 0xaf279193, 0x14135c94, 0x00000000, 0xd2bec333, 0x539eba45, 0xc4df2862, 0xac6145bb, 0x187de2a7, 0xfb8f1424, 0xd5052d97, 0x52beac9f, 0xc449d892, 0xaa0efb24, 0x1cc66e99, 0xf720e574, 0xd76619b6, 0x51d1dc80, 0xc3bdbdf6, 0xa833ea44, 0x20e70f32, 0xf2b82f6a, 0xd9e01006, 0x50d86e6d, 0xc33aee27, 0xa6d2a626, 0x24da0a9a, 0xee57aa21, 0xdc71898d, 0x4fd288dc, 0xc2c17d52, 0xa5ed18e0, 0x2899e64a, 0xea0208a8, 0xdf18f0ce, 0x4ec05432, 0xc2517e31, 0xa58480e6, 0x2c216eaa, 0xe5b9f755, 0xe1d4a2c8, 0x4da1fab5, 0xc1eb0209, 0xa5996f52, 0x2f6bbe45, 0xe1821a21, 0xe4a2eff6, 0x4c77a88e, 0xc18e18a7, 0xa62bc71b, 0x32744493, 0xdd5d0b08, 0xe7821d59, 0x4b418bbe, 0xc13ad060, 0xa73abd3b, 0x3536cc52, 0xd94d586c, 0xea70658a, 0x49ffd417, 0xc0f1360b, 0xa8c4d9cb, 0x37af8159, 0xd5558381, 0xed6bf9d1, 0x48b2b335, 0xc0b15502, 0xaac7fa0e, 0x39daf5e8, 0xd177fec6, 0xf0730342, 0x475a5c77, 0xc07b371e, 0xad415361, 0x3bb6276e, 0xcdb72c7e, 0xf383a3e2, 0x45f704f7, 0xc04ee4b8, 0xb02d7724, 0x3d3e82ae, 0xca155d39, 0xf69bf7c9, 0x4488e37f, 0xc02c64a6, 0xb3885772, 0x3e71e759, 0xc694ce67, 0xf9ba1651, 0x43103085, 0xc013bc39, 0xb74d4ccb, 0x3f4eaafe, 0xc337a8f7, 0xfcdc1342, 0x418d2621, 0xc004ef3f, 0xbb771c81, 0x3fd39b5a, }; /* log2Tab[x] = floor(log2(x)), format = Q28 */ const int log2Tab[65] PROGMEM = { 0x00000000, 0x00000000, 0x10000000, 0x195c01a3, 0x20000000, 0x25269e12, 0x295c01a3, 0x2ceaecfe, 0x30000000, 0x32b80347, 0x35269e12, 0x3759d4f8, 0x395c01a3, 0x3b350047, 0x3ceaecfe, 0x3e829fb6, 0x40000000, 0x41663f6f, 0x42b80347, 0x43f782d7, 0x45269e12, 0x4646eea2, 0x4759d4f8, 0x48608280, 0x495c01a3, 0x4a4d3c25, 0x4b350047, 0x4c1404ea, 0x4ceaecfe, 0x4dba4a47, 0x4e829fb6, 0x4f446359, 0x50000000, 0x50b5d69b, 0x51663f6f, 0x52118b11, 0x52b80347, 0x5359ebc5, 0x53f782d7, 0x549101ea, 0x55269e12, 0x55b88873, 0x5646eea2, 0x56d1fafd, 0x5759d4f8, 0x57dea15a, 0x58608280, 0x58df988f, 0x595c01a3, 0x59d5d9fd, 0x5a4d3c25, 0x5ac24113, 0x5b350047, 0x5ba58feb, 0x5c1404ea, 0x5c80730b, 0x5ceaecfe, 0x5d53847a, 0x5dba4a47, 0x5e1f4e51, 0x5e829fb6, 0x5ee44cd5, 0x5f446359, 0x5fa2f045, 0x60000000 }; const HuffInfo_t huffTabSpecInfo[11] PROGMEM = { /* table 0 not used */ {11, { 1, 0, 0, 0, 8, 0, 24, 0, 24, 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0}, { 9, { 0, 0, 1, 1, 7, 24, 15, 19, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 81}, {16, { 1, 0, 0, 4, 2, 6, 3, 5, 15, 15, 8, 9, 3, 3, 5, 2, 0, 0, 0, 0}, 162}, {12, { 0, 0, 0, 10, 6, 0, 9, 21, 8, 14, 11, 2, 0, 0, 0, 0, 0, 0, 0, 0}, 243}, {13, { 1, 0, 0, 4, 4, 0, 4, 12, 12, 12, 18, 10, 4, 0, 0, 0, 0, 0, 0, 0}, 324}, {11, { 0, 0, 0, 9, 0, 16, 13, 8, 23, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 405}, {12, { 1, 0, 2, 1, 0, 4, 5, 10, 14, 15, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0}, 486}, {10, { 0, 0, 1, 5, 7, 10, 14, 15, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 550}, {15, { 1, 0, 2, 1, 0, 4, 3, 8, 11, 20, 31, 38, 32, 14, 4, 0, 0, 0, 0, 0}, 614}, {12, { 0, 0, 0, 3, 8, 14, 17, 25, 31, 41, 22, 8, 0, 0, 0, 0, 0, 0, 0, 0}, 783}, {12, { 0, 0, 0, 2, 6, 7, 16, 59, 55, 95, 43, 6, 0, 0, 0, 0, 0, 0, 0, 0}, 952}, }; const short huffTabSpec[1241] PROGMEM = { /* spectrum table 1 [81] (signed) */ 0x0000, 0x0200, 0x0e00, 0x0007, 0x0040, 0x0001, 0x0038, 0x0008, 0x01c0, 0x03c0, 0x0e40, 0x0039, 0x0078, 0x01c8, 0x000f, 0x0240, 0x003f, 0x0fc0, 0x01f8, 0x0238, 0x0047, 0x0e08, 0x0009, 0x0208, 0x01c1, 0x0048, 0x0041, 0x0e38, 0x0201, 0x0e07, 0x0207, 0x0e01, 0x01c7, 0x0278, 0x0e78, 0x03c8, 0x004f, 0x0079, 0x01c9, 0x01cf, 0x03f8, 0x0239, 0x007f, 0x0e48, 0x0e0f, 0x0fc8, 0x01f9, 0x03c1, 0x03c7, 0x0e47, 0x0ff8, 0x01ff, 0x0049, 0x020f, 0x0241, 0x0e41, 0x0248, 0x0fc1, 0x0e3f, 0x0247, 0x023f, 0x0e39, 0x0fc7, 0x0e09, 0x0209, 0x03cf, 0x0e79, 0x0e4f, 0x03f9, 0x0249, 0x0fc9, 0x027f, 0x0fcf, 0x0fff, 0x0279, 0x03c9, 0x0e49, 0x0e7f, 0x0ff9, 0x03ff, 0x024f, /* spectrum table 2 [81] (signed) */ 0x0000, 0x0200, 0x0e00, 0x0001, 0x0038, 0x0007, 0x01c0, 0x0008, 0x0040, 0x01c8, 0x0e40, 0x0078, 0x000f, 0x0047, 0x0039, 0x0e07, 0x03c0, 0x0238, 0x0fc0, 0x003f, 0x0208, 0x0201, 0x01c1, 0x0e08, 0x0041, 0x01f8, 0x0e01, 0x01c7, 0x0e38, 0x0240, 0x0048, 0x0009, 0x0207, 0x0079, 0x0239, 0x0e78, 0x01cf, 0x03c8, 0x0247, 0x0209, 0x0e48, 0x01f9, 0x0248, 0x0e0f, 0x0ff8, 0x0e39, 0x03f8, 0x0278, 0x03c1, 0x0e47, 0x0fc8, 0x0e09, 0x0fc1, 0x0fc7, 0x01ff, 0x020f, 0x023f, 0x007f, 0x0049, 0x0e41, 0x0e3f, 0x004f, 0x03c7, 0x01c9, 0x0241, 0x03cf, 0x0e79, 0x03f9, 0x0fff, 0x0e4f, 0x0e49, 0x0249, 0x0fcf, 0x03c9, 0x0e7f, 0x0fc9, 0x027f, 0x03ff, 0x0ff9, 0x0279, 0x024f, /* spectrum table 3 [81] (unsigned) */ 0x0000, 0x1200, 0x1001, 0x1040, 0x1008, 0x2240, 0x2009, 0x2048, 0x2041, 0x2208, 0x3049, 0x2201, 0x3248, 0x4249, 0x3209, 0x3241, 0x1400, 0x1002, 0x200a, 0x2440, 0x3288, 0x2011, 0x3051, 0x2280, 0x304a, 0x3448, 0x1010, 0x2088, 0x2050, 0x1080, 0x2042, 0x2408, 0x4289, 0x3089, 0x3250, 0x4251, 0x3281, 0x2210, 0x3211, 0x2081, 0x4449, 0x424a, 0x3441, 0x320a, 0x2012, 0x3052, 0x3488, 0x3290, 0x2202, 0x2401, 0x3091, 0x2480, 0x4291, 0x3242, 0x3409, 0x4252, 0x4489, 0x2090, 0x308a, 0x3212, 0x3481, 0x3450, 0x3490, 0x3092, 0x4491, 0x4451, 0x428a, 0x4292, 0x2082, 0x2410, 0x3282, 0x3411, 0x444a, 0x3442, 0x4492, 0x448a, 0x4452, 0x340a, 0x2402, 0x3482, 0x3412, /* spectrum table 4 [81] (unsigned) */ 0x4249, 0x3049, 0x3241, 0x3248, 0x3209, 0x1200, 0x2240, 0x0000, 0x2009, 0x2208, 0x2201, 0x2048, 0x1001, 0x2041, 0x1008, 0x1040, 0x4449, 0x4251, 0x4289, 0x424a, 0x3448, 0x3441, 0x3288, 0x3409, 0x3051, 0x304a, 0x3250, 0x3089, 0x320a, 0x3281, 0x3242, 0x3211, 0x2440, 0x2408, 0x2280, 0x2401, 0x2042, 0x2088, 0x200a, 0x2050, 0x2081, 0x2202, 0x2011, 0x2210, 0x1400, 0x1002, 0x1080, 0x1010, 0x4291, 0x4489, 0x4451, 0x4252, 0x428a, 0x444a, 0x3290, 0x3488, 0x3450, 0x3091, 0x3052, 0x3481, 0x308a, 0x3411, 0x3212, 0x4491, 0x3282, 0x340a, 0x3442, 0x4292, 0x4452, 0x448a, 0x2090, 0x2480, 0x2012, 0x2410, 0x2082, 0x2402, 0x4492, 0x3092, 0x3490, 0x3482, 0x3412, /* spectrum table 5 [81] (signed) */ 0x0000, 0x03e0, 0x0020, 0x0001, 0x001f, 0x003f, 0x03e1, 0x03ff, 0x0021, 0x03c0, 0x0002, 0x0040, 0x001e, 0x03df, 0x0041, 0x03fe, 0x0022, 0x03c1, 0x005f, 0x03e2, 0x003e, 0x03a0, 0x0060, 0x001d, 0x0003, 0x03bf, 0x0023, 0x0061, 0x03fd, 0x03a1, 0x007f, 0x003d, 0x03e3, 0x03c2, 0x0042, 0x03de, 0x005e, 0x03be, 0x007e, 0x03c3, 0x005d, 0x0062, 0x0043, 0x03a2, 0x03dd, 0x001c, 0x0380, 0x0081, 0x0080, 0x039f, 0x0004, 0x009f, 0x03fc, 0x0024, 0x03e4, 0x0381, 0x003c, 0x007d, 0x03bd, 0x03a3, 0x03c4, 0x039e, 0x0082, 0x005c, 0x0044, 0x0063, 0x0382, 0x03dc, 0x009e, 0x007c, 0x039d, 0x0383, 0x0064, 0x03a4, 0x0083, 0x009d, 0x03bc, 0x009c, 0x0384, 0x0084, 0x039c, /* spectrum table 6 [81] (signed) */ 0x0000, 0x0020, 0x001f, 0x0001, 0x03e0, 0x0021, 0x03e1, 0x003f, 0x03ff, 0x005f, 0x0041, 0x03c1, 0x03df, 0x03c0, 0x03e2, 0x0040, 0x003e, 0x0022, 0x001e, 0x03fe, 0x0002, 0x005e, 0x03c2, 0x03de, 0x0042, 0x03a1, 0x0061, 0x007f, 0x03e3, 0x03bf, 0x0023, 0x003d, 0x03fd, 0x0060, 0x03a0, 0x001d, 0x0003, 0x0062, 0x03be, 0x03c3, 0x0043, 0x007e, 0x005d, 0x03dd, 0x03a2, 0x0063, 0x007d, 0x03bd, 0x03a3, 0x003c, 0x03fc, 0x0081, 0x0381, 0x039f, 0x0024, 0x009f, 0x03e4, 0x001c, 0x0382, 0x039e, 0x0044, 0x03dc, 0x0380, 0x0082, 0x009e, 0x03c4, 0x0080, 0x005c, 0x0004, 0x03bc, 0x03a4, 0x007c, 0x009d, 0x0064, 0x0083, 0x0383, 0x039d, 0x0084, 0x0384, 0x039c, 0x009c, /* spectrum table 7 [64] (unsigned) */ 0x0000, 0x0420, 0x0401, 0x0821, 0x0841, 0x0822, 0x0440, 0x0402, 0x0861, 0x0823, 0x0842, 0x0460, 0x0403, 0x0843, 0x0862, 0x0824, 0x0881, 0x0825, 0x08a1, 0x0863, 0x0844, 0x0404, 0x0480, 0x0882, 0x0845, 0x08a2, 0x0405, 0x08c1, 0x04a0, 0x0826, 0x0883, 0x0865, 0x0864, 0x08a3, 0x0846, 0x08c2, 0x0827, 0x0866, 0x0406, 0x04c0, 0x0884, 0x08e1, 0x0885, 0x08e2, 0x08a4, 0x08c3, 0x0847, 0x08e3, 0x08c4, 0x08a5, 0x0886, 0x0867, 0x04e0, 0x0407, 0x08c5, 0x08a6, 0x08e4, 0x0887, 0x08a7, 0x08e5, 0x08e6, 0x08c6, 0x08c7, 0x08e7, /* spectrum table 8 [64] (unsigned) */ 0x0821, 0x0841, 0x0420, 0x0822, 0x0401, 0x0842, 0x0000, 0x0440, 0x0402, 0x0861, 0x0823, 0x0862, 0x0843, 0x0863, 0x0881, 0x0824, 0x0882, 0x0844, 0x0460, 0x0403, 0x0883, 0x0864, 0x08a2, 0x08a1, 0x0845, 0x0825, 0x08a3, 0x0865, 0x0884, 0x08a4, 0x0404, 0x0885, 0x0480, 0x0846, 0x08c2, 0x08c1, 0x0826, 0x0866, 0x08c3, 0x08a5, 0x04a0, 0x08c4, 0x0405, 0x0886, 0x08e1, 0x08e2, 0x0847, 0x08c5, 0x08e3, 0x0827, 0x08a6, 0x0867, 0x08c6, 0x08e4, 0x04c0, 0x0887, 0x0406, 0x08e5, 0x08e6, 0x08c7, 0x08a7, 0x04e0, 0x0407, 0x08e7, /* spectrum table 9 [169] (unsigned) */ 0x0000, 0x0420, 0x0401, 0x0821, 0x0841, 0x0822, 0x0440, 0x0402, 0x0861, 0x0842, 0x0823, 0x0460, 0x0403, 0x0843, 0x0862, 0x0824, 0x0881, 0x0844, 0x0825, 0x0882, 0x0863, 0x0404, 0x0480, 0x08a1, 0x0845, 0x0826, 0x0864, 0x08a2, 0x08c1, 0x0883, 0x0405, 0x0846, 0x04a0, 0x0827, 0x0865, 0x0828, 0x0901, 0x0884, 0x08a3, 0x08c2, 0x08e1, 0x0406, 0x0902, 0x0848, 0x0866, 0x0847, 0x0885, 0x0921, 0x0829, 0x08e2, 0x04c0, 0x08a4, 0x08c3, 0x0903, 0x0407, 0x0922, 0x0868, 0x0886, 0x0867, 0x0408, 0x0941, 0x08c4, 0x0849, 0x08a5, 0x0500, 0x04e0, 0x08e3, 0x0942, 0x0923, 0x0904, 0x082a, 0x08e4, 0x08c5, 0x08a6, 0x0888, 0x0887, 0x0869, 0x0961, 0x08a8, 0x0520, 0x0905, 0x0943, 0x084a, 0x0409, 0x0962, 0x0924, 0x08c6, 0x0981, 0x0889, 0x0906, 0x082b, 0x0925, 0x0944, 0x08a7, 0x08e5, 0x084b, 0x082c, 0x0982, 0x0963, 0x086a, 0x08a9, 0x08c7, 0x0907, 0x0964, 0x040a, 0x08e6, 0x0983, 0x0540, 0x0945, 0x088a, 0x08c8, 0x084c, 0x0926, 0x0927, 0x088b, 0x0560, 0x08c9, 0x086b, 0x08aa, 0x0908, 0x08e8, 0x0985, 0x086c, 0x0965, 0x08e7, 0x0984, 0x0966, 0x0946, 0x088c, 0x08e9, 0x08ab, 0x040b, 0x0986, 0x08ca, 0x0580, 0x0947, 0x08ac, 0x08ea, 0x0928, 0x040c, 0x0967, 0x0909, 0x0929, 0x0948, 0x08eb, 0x0987, 0x08cb, 0x090b, 0x0968, 0x08ec, 0x08cc, 0x090a, 0x0949, 0x090c, 0x092a, 0x092b, 0x092c, 0x094b, 0x0989, 0x094a, 0x0969, 0x0988, 0x096a, 0x098a, 0x098b, 0x094c, 0x096b, 0x096c, 0x098c, /* spectrum table 10 [169] (unsigned) */ 0x0821, 0x0822, 0x0841, 0x0842, 0x0420, 0x0401, 0x0823, 0x0862, 0x0861, 0x0843, 0x0863, 0x0440, 0x0402, 0x0844, 0x0882, 0x0824, 0x0881, 0x0000, 0x0883, 0x0864, 0x0460, 0x0403, 0x0884, 0x0845, 0x08a2, 0x0825, 0x08a1, 0x08a3, 0x0865, 0x08a4, 0x0885, 0x08c2, 0x0846, 0x08c3, 0x0480, 0x08c1, 0x0404, 0x0826, 0x0866, 0x08a5, 0x08c4, 0x0886, 0x08c5, 0x08e2, 0x0867, 0x0847, 0x08a6, 0x0902, 0x08e3, 0x04a0, 0x08e1, 0x0405, 0x0901, 0x0827, 0x0903, 0x08e4, 0x0887, 0x0848, 0x08c6, 0x08e5, 0x0828, 0x0868, 0x0904, 0x0888, 0x08a7, 0x0905, 0x08a8, 0x08e6, 0x08c7, 0x0922, 0x04c0, 0x08c8, 0x0923, 0x0869, 0x0921, 0x0849, 0x0406, 0x0906, 0x0924, 0x0889, 0x0942, 0x0829, 0x08e7, 0x0907, 0x0925, 0x08e8, 0x0943, 0x08a9, 0x0944, 0x084a, 0x0941, 0x086a, 0x0926, 0x08c9, 0x0500, 0x088a, 0x04e0, 0x0962, 0x08e9, 0x0963, 0x0946, 0x082a, 0x0961, 0x0927, 0x0407, 0x0908, 0x0945, 0x086b, 0x08aa, 0x0909, 0x0965, 0x0408, 0x0964, 0x084b, 0x08ea, 0x08ca, 0x0947, 0x088b, 0x082b, 0x0982, 0x0928, 0x0983, 0x0966, 0x08ab, 0x0984, 0x0967, 0x0985, 0x086c, 0x08cb, 0x0520, 0x0948, 0x0540, 0x0981, 0x0409, 0x088c, 0x0929, 0x0986, 0x084c, 0x090a, 0x092a, 0x082c, 0x0968, 0x0987, 0x08eb, 0x08ac, 0x08cc, 0x0949, 0x090b, 0x0988, 0x040a, 0x08ec, 0x0560, 0x094a, 0x0969, 0x096a, 0x040b, 0x096b, 0x092b, 0x094b, 0x0580, 0x090c, 0x0989, 0x094c, 0x092c, 0x096c, 0x098b, 0x040c, 0x098a, 0x098c, /* spectrum table 11 [289] (unsigned) */ 0x0000, 0x2041, 0x2410, 0x1040, 0x1001, 0x2081, 0x2042, 0x2082, 0x2043, 0x20c1, 0x20c2, 0x1080, 0x2083, 0x1002, 0x20c3, 0x2101, 0x2044, 0x2102, 0x2084, 0x2103, 0x20c4, 0x10c0, 0x1003, 0x2141, 0x2142, 0x2085, 0x2104, 0x2045, 0x2143, 0x20c5, 0x2144, 0x2105, 0x2182, 0x2086, 0x2181, 0x2183, 0x20c6, 0x2046, 0x2110, 0x20d0, 0x2405, 0x2403, 0x2404, 0x2184, 0x2406, 0x1100, 0x2106, 0x1004, 0x2090, 0x2145, 0x2150, 0x2407, 0x2402, 0x2408, 0x2087, 0x21c2, 0x20c7, 0x2185, 0x2146, 0x2190, 0x240a, 0x21c3, 0x21c1, 0x2409, 0x21d0, 0x2050, 0x2047, 0x2107, 0x240b, 0x21c4, 0x240c, 0x2210, 0x2401, 0x2186, 0x2250, 0x2088, 0x2147, 0x2290, 0x240d, 0x2203, 0x2202, 0x20c8, 0x1140, 0x240e, 0x22d0, 0x21c5, 0x2108, 0x2187, 0x21c6, 0x1005, 0x2204, 0x240f, 0x2310, 0x2048, 0x2201, 0x2390, 0x2148, 0x2350, 0x20c9, 0x2205, 0x21c7, 0x2089, 0x2206, 0x2242, 0x2243, 0x23d0, 0x2109, 0x2188, 0x1180, 0x2244, 0x2149, 0x2207, 0x21c8, 0x2049, 0x2283, 0x1006, 0x2282, 0x2241, 0x2245, 0x210a, 0x208a, 0x2246, 0x20ca, 0x2189, 0x2284, 0x2208, 0x2285, 0x2247, 0x22c3, 0x204a, 0x11c0, 0x2286, 0x21c9, 0x20cb, 0x214a, 0x2281, 0x210b, 0x22c2, 0x2342, 0x218a, 0x2343, 0x208b, 0x1400, 0x214b, 0x22c5, 0x22c4, 0x2248, 0x21ca, 0x2209, 0x1010, 0x210d, 0x1007, 0x20cd, 0x22c6, 0x2341, 0x2344, 0x2303, 0x208d, 0x2345, 0x220a, 0x218b, 0x2288, 0x2287, 0x2382, 0x2304, 0x204b, 0x210c, 0x22c1, 0x20cc, 0x204d, 0x2302, 0x21cb, 0x20ce, 0x214c, 0x214d, 0x2384, 0x210e, 0x22c7, 0x2383, 0x2305, 0x2346, 0x2306, 0x1200, 0x22c8, 0x208c, 0x2249, 0x2385, 0x218d, 0x228a, 0x23c2, 0x220b, 0x224a, 0x2386, 0x2289, 0x214e, 0x22c9, 0x2381, 0x208e, 0x218c, 0x204c, 0x2348, 0x1008, 0x2347, 0x21cc, 0x2307, 0x21cd, 0x23c3, 0x2301, 0x218e, 0x208f, 0x23c5, 0x23c4, 0x204e, 0x224b, 0x210f, 0x2387, 0x220d, 0x2349, 0x220c, 0x214f, 0x20cf, 0x228b, 0x22ca, 0x2308, 0x23c6, 0x23c7, 0x220e, 0x23c1, 0x21ce, 0x1240, 0x1009, 0x224d, 0x224c, 0x2309, 0x2388, 0x228d, 0x2389, 0x230a, 0x218f, 0x21cf, 0x224e, 0x23c8, 0x22cb, 0x22ce, 0x204f, 0x228c, 0x228e, 0x234b, 0x234a, 0x22cd, 0x22cc, 0x220f, 0x238b, 0x234c, 0x230d, 0x23c9, 0x238a, 0x1280, 0x230b, 0x224f, 0x100a, 0x230c, 0x12c0, 0x230e, 0x228f, 0x234d, 0x100d, 0x238c, 0x23ca, 0x23cb, 0x22cf, 0x238d, 0x1340, 0x100b, 0x234e, 0x23cc, 0x23cd, 0x230f, 0x1380, 0x238e, 0x234f, 0x1300, 0x238f, 0x100e, 0x100c, 0x23ce, 0x13c0, 0x100f, 0x23cf, }; /* coefficient table 4.A.87, format = Q31 * reordered as cTab[0], cTab[64], cTab[128], ... cTab[576], cTab[1], cTab[65], cTab[129], ... cTab[639] * keeping full table (not using symmetry) to allow sequential access in synth filter inner loop * format = Q31 */ const uint32_t cTabS[640] PROGMEM = { 0x00000000, 0x0055dba1, 0x01b2e41d, 0x09015651, 0x2e3a7532, 0x6d474e1d, 0xd1c58ace, 0x09015651, 0xfe4d1be3, 0x0055dba1, 0xffede50e, 0x005b5371, 0x01d78bfc, 0x08d3e41b, 0x2faa221c, 0x6d41d963, 0xd3337b3d, 0x09299ead, 0xfe70b8d1, 0x0050b177, 0xffed978a, 0x006090c4, 0x01fd3ba0, 0x08a24899, 0x311af3a4, 0x6d32730f, 0xd49fd55f, 0x094d7ec2, 0xfe933dc0, 0x004b6c46, 0xffefc9b9, 0x0065fde5, 0x02244a24, 0x086b1eeb, 0x328cc6f0, 0x6d18520e, 0xd60a46e5, 0x096d0e21, 0xfeb48d0d, 0x00465348, 0xfff0065d, 0x006b47fa, 0x024bf7a1, 0x082f552e, 0x33ff670e, 0x6cf4073e, 0xd7722f04, 0x09881dc5, 0xfed4bec3, 0x004103f4, 0xffeff6ca, 0x0070c8a5, 0x0274ba43, 0x07ee507c, 0x3572ec70, 0x6cc59bab, 0xd8d7f21f, 0x099ec3dc, 0xfef3f6ab, 0x003c1fa4, 0xffef7b8b, 0x0075fded, 0x029e35b4, 0x07a8127d, 0x36e69691, 0x6c8c4c7a, 0xda3b176a, 0x09b18a1d, 0xff120d70, 0x003745f9, 0xffeedfa4, 0x007b3875, 0x02c89901, 0x075ca90c, 0x385a49c4, 0x6c492217, 0xdb9b5b12, 0x09c018ce, 0xff2ef725, 0x00329ab6, 0xffee1650, 0x00807994, 0x02f3e48d, 0x070bbf58, 0x39ce0477, 0x6bfbdd98, 0xdcf898fb, 0x09caeb0f, 0xff4aabc8, 0x002d8e42, 0xffed651d, 0x0085c217, 0x03201116, 0x06b559c3, 0x3b415115, 0x6ba4629f, 0xde529086, 0x09d1fa23, 0xff6542d1, 0x00293718, 0xffecc31b, 0x008a7dd7, 0x034d01f0, 0x06593912, 0x3cb41219, 0x6b42a864, 0xdfa93ab5, 0x09d5560b, 0xff7ee3f1, 0x0024dd50, 0xffebe77b, 0x008f4bfc, 0x037ad438, 0x05f7fb90, 0x3e25b17e, 0x6ad73e8d, 0xe0fc421e, 0x09d52709, 0xff975c01, 0x002064f8, 0xffeb50b2, 0x009424c6, 0x03a966bb, 0x0590a67d, 0x3f962fb8, 0x6a619c5e, 0xe24b8f66, 0x09d19ca9, 0xffaea5d6, 0x001c3549, 0xffea9192, 0x0098b855, 0x03d8afe6, 0x05237f9d, 0x41058bc6, 0x69e29784, 0xe396a45d, 0x09cab9f2, 0xffc4e365, 0x0018703f, 0xffe9ca76, 0x009d10bf, 0x04083fec, 0x04b0adcb, 0x4272a385, 0x6959709d, 0xe4de0cb0, 0x09c0e59f, 0xffda17f2, 0x001471f8, 0xffe940f4, 0x00a1039c, 0x043889c6, 0x0437fb0a, 0x43de620a, 0x68c7269b, 0xe620c476, 0x09b3d77f, 0xffee183b, 0x0010bc63, 0xffe88ba8, 0x00a520bb, 0x04694101, 0x03b8f8dc, 0x4547daea, 0x682b39a4, 0xe75f8bb8, 0x09a3e163, 0x0000e790, 0x000d31b5, 0xffe83a07, 0x00a8739d, 0x049aa82f, 0x03343533, 0x46aea856, 0x6785c24d, 0xe89971b7, 0x099140a7, 0x00131c75, 0x0009aa3f, 0xffe79e16, 0x00abe79e, 0x04cc2fcf, 0x02a99097, 0x4812f848, 0x66d76725, 0xe9cea84a, 0x097c1ee8, 0x0023b989, 0x0006b1cf, 0xffe7746e, 0x00af374c, 0x04fe20be, 0x02186a91, 0x4973fef1, 0x661fd6b8, 0xeafee7f1, 0x0963ed46, 0x0033b927, 0x00039609, 0xffe6d466, 0x00b1978d, 0x05303f87, 0x01816e06, 0x4ad237a2, 0x655f63f2, 0xec2a3f5f, 0x0949eaac, 0x00426f36, 0x00007134, 0xffe6afee, 0x00b3d15c, 0x05626209, 0x00e42fa2, 0x4c2ca3df, 0x64964063, 0xed50a31d, 0x092d7970, 0x00504f41, 0xfffdfa25, 0xffe65416, 0x00b5c867, 0x05950122, 0x0040c496, 0x4d83976c, 0x63c45243, 0xee71b2fe, 0x090ec1fc, 0x005d36df, 0xfffb42b0, 0xffe681c6, 0x00b74c37, 0x05c76fed, 0xff96db90, 0x4ed62be3, 0x62ea6474, 0xef8d4d7b, 0x08edfeaa, 0x006928a0, 0xfff91fca, 0xffe66dd0, 0x00b8394b, 0x05f9c051, 0xfee723c6, 0x5024d70e, 0x6207f220, 0xf0a3959f, 0x08cb4e23, 0x007400b8, 0xfff681d6, 0xffe66fac, 0x00b8fe0d, 0x062bf5ec, 0xfe310657, 0x516eefb9, 0x611d58a3, 0xf1b461ab, 0x08a75da4, 0x007e0393, 0xfff48700, 0xffe69423, 0x00b8c6b0, 0x065dd56a, 0xfd7475d8, 0x52b449de, 0x602b0c7f, 0xf2bf6ea4, 0x0880ffdd, 0x00872c63, 0xfff294c3, 0xffe6fed4, 0x00b85f70, 0x068f8b44, 0xfcb1d740, 0x53f495aa, 0x5f30ff5f, 0xf3c4e887, 0x08594887, 0x008f87aa, 0xfff0e7ef, 0xffe75361, 0x00b73ab0, 0x06c0f0c0, 0xfbe8f5bd, 0x552f8ff7, 0x5e2f6367, 0xf4c473c6, 0x08303897, 0x0096dcc2, 0xffef2395, 0xffe80414, 0x00b58c8c, 0x06f1825d, 0xfb19b7bd, 0x56654bdd, 0x5d26be9b, 0xf5be0fa9, 0x08061671, 0x009da526, 0xffedc418, 0xffe85b4b, 0x00b36acd, 0x0721bf22, 0xfa44a069, 0x579505f5, 0x5c16d0ae, 0xf6b1f3c3, 0x07da2b7f, 0x00a3508f, 0xffec8409, 0xffe954d0, 0x00b06b68, 0x075112a2, 0xf96916f5, 0x58befacd, 0x5b001db8, 0xf79fa13a, 0x07ad8c26, 0x00a85e94, 0xffeb3849, 0xffea353a, 0x00acbd2f, 0x077fedb3, 0xf887507c, 0x59e2f69e, 0x59e2f69e, 0xf887507c, 0x077fedb3, 0x00acbd2f, 0xffea353a, 0xffeb3849, 0x00a85e94, 0x07ad8c26, 0xf79fa13a, 0x5b001db8, 0x58befacd, 0xf96916f5, 0x075112a2, 0x00b06b68, 0xffe954d0, 0xffec8409, 0x00a3508f, 0x07da2b7f, 0xf6b1f3c3, 0x5c16d0ae, 0x579505f5, 0xfa44a069, 0x0721bf22, 0x00b36acd, 0xffe85b4b, 0xffedc418, 0x009da526, 0x08061671, 0xf5be0fa9, 0x5d26be9b, 0x56654bdd, 0xfb19b7bd, 0x06f1825d, 0x00b58c8c, 0xffe80414, 0xffef2395, 0x0096dcc2, 0x08303897, 0xf4c473c6, 0x5e2f6367, 0x552f8ff7, 0xfbe8f5bd, 0x06c0f0c0, 0x00b73ab0, 0xffe75361, 0xfff0e7ef, 0x008f87aa, 0x08594887, 0xf3c4e887, 0x5f30ff5f, 0x53f495aa, 0xfcb1d740, 0x068f8b44, 0x00b85f70, 0xffe6fed4, 0xfff294c3, 0x00872c63, 0x0880ffdd, 0xf2bf6ea4, 0x602b0c7f, 0x52b449de, 0xfd7475d8, 0x065dd56a, 0x00b8c6b0, 0xffe69423, 0xfff48700, 0x007e0393, 0x08a75da4, 0xf1b461ab, 0x611d58a3, 0x516eefb9, 0xfe310657, 0x062bf5ec, 0x00b8fe0d, 0xffe66fac, 0xfff681d6, 0x007400b8, 0x08cb4e23, 0xf0a3959f, 0x6207f220, 0x5024d70e, 0xfee723c6, 0x05f9c051, 0x00b8394b, 0xffe66dd0, 0xfff91fca, 0x006928a0, 0x08edfeaa, 0xef8d4d7b, 0x62ea6474, 0x4ed62be3, 0xff96db90, 0x05c76fed, 0x00b74c37, 0xffe681c6, 0xfffb42b0, 0x005d36df, 0x090ec1fc, 0xee71b2fe, 0x63c45243, 0x4d83976c, 0x0040c496, 0x05950122, 0x00b5c867, 0xffe65416, 0xfffdfa25, 0x00504f41, 0x092d7970, 0xed50a31d, 0x64964063, 0x4c2ca3df, 0x00e42fa2, 0x05626209, 0x00b3d15c, 0xffe6afee, 0x00007134, 0x00426f36, 0x0949eaac, 0xec2a3f5f, 0x655f63f2, 0x4ad237a2, 0x01816e06, 0x05303f87, 0x00b1978d, 0xffe6d466, 0x00039609, 0x0033b927, 0x0963ed46, 0xeafee7f1, 0x661fd6b8, 0x4973fef1, 0x02186a91, 0x04fe20be, 0x00af374c, 0xffe7746e, 0x0006b1cf, 0x0023b989, 0x097c1ee8, 0xe9cea84a, 0x66d76725, 0x4812f848, 0x02a99097, 0x04cc2fcf, 0x00abe79e, 0xffe79e16, 0x0009aa3f, 0x00131c75, 0x099140a7, 0xe89971b7, 0x6785c24d, 0x46aea856, 0x03343533, 0x049aa82f, 0x00a8739d, 0xffe83a07, 0x000d31b5, 0x0000e790, 0x09a3e163, 0xe75f8bb8, 0x682b39a4, 0x4547daea, 0x03b8f8dc, 0x04694101, 0x00a520bb, 0xffe88ba8, 0x0010bc63, 0xffee183b, 0x09b3d77f, 0xe620c476, 0x68c7269b, 0x43de620a, 0x0437fb0a, 0x043889c6, 0x00a1039c, 0xffe940f4, 0x001471f8, 0xffda17f2, 0x09c0e59f, 0xe4de0cb0, 0x6959709d, 0x4272a385, 0x04b0adcb, 0x04083fec, 0x009d10bf, 0xffe9ca76, 0x0018703f, 0xffc4e365, 0x09cab9f2, 0xe396a45d, 0x69e29784, 0x41058bc6, 0x05237f9d, 0x03d8afe6, 0x0098b855, 0xffea9192, 0x001c3549, 0xffaea5d6, 0x09d19ca9, 0xe24b8f66, 0x6a619c5e, 0x3f962fb8, 0x0590a67d, 0x03a966bb, 0x009424c6, 0xffeb50b2, 0x002064f8, 0xff975c01, 0x09d52709, 0xe0fc421e, 0x6ad73e8d, 0x3e25b17e, 0x05f7fb90, 0x037ad438, 0x008f4bfc, 0xffebe77b, 0x0024dd50, 0xff7ee3f1, 0x09d5560b, 0xdfa93ab5, 0x6b42a864, 0x3cb41219, 0x06593912, 0x034d01f0, 0x008a7dd7, 0xffecc31b, 0x00293718, 0xff6542d1, 0x09d1fa23, 0xde529086, 0x6ba4629f, 0x3b415115, 0x06b559c3, 0x03201116, 0x0085c217, 0xffed651d, 0x002d8e42, 0xff4aabc8, 0x09caeb0f, 0xdcf898fb, 0x6bfbdd98, 0x39ce0477, 0x070bbf58, 0x02f3e48d, 0x00807994, 0xffee1650, 0x00329ab6, 0xff2ef725, 0x09c018ce, 0xdb9b5b12, 0x6c492217, 0x385a49c4, 0x075ca90c, 0x02c89901, 0x007b3875, 0xffeedfa4, 0x003745f9, 0xff120d70, 0x09b18a1d, 0xda3b176a, 0x6c8c4c7a, 0x36e69691, 0x07a8127d, 0x029e35b4, 0x0075fded, 0xffef7b8b, 0x003c1fa4, 0xfef3f6ab, 0x099ec3dc, 0xd8d7f21f, 0x6cc59bab, 0x3572ec70, 0x07ee507c, 0x0274ba43, 0x0070c8a5, 0xffeff6ca, 0x004103f4, 0xfed4bec3, 0x09881dc5, 0xd7722f04, 0x6cf4073e, 0x33ff670e, 0x082f552e, 0x024bf7a1, 0x006b47fa, 0xfff0065d, 0x00465348, 0xfeb48d0d, 0x096d0e21, 0xd60a46e5, 0x6d18520e, 0x328cc6f0, 0x086b1eeb, 0x02244a24, 0x0065fde5, 0xffefc9b9, 0x004b6c46, 0xfe933dc0, 0x094d7ec2, 0xd49fd55f, 0x6d32730f, 0x311af3a4, 0x08a24899, 0x01fd3ba0, 0x006090c4, 0xffed978a, 0x0050b177, 0xfe70b8d1, 0x09299ead, 0xd3337b3d, 0x6d41d963, 0x2faa221c, 0x08d3e41b, 0x01d78bfc, 0x005b5371, 0xffede50f, }; const HuffInfo_t huffTabScaleFactInfo PROGMEM = {19, { 1, 0, 1, 3, 2, 4, 3, 5, 4, 6, 6, 6, 5, 8, 4, 7, 3, 7, 46, 0}, 0}; /* note - includes offset of -60 (4.6.2.3 in spec) */ const short huffTabScaleFact[121] PROGMEM = { /* scale factor table [121] */ 0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, 6, -6, 7, -7, 8, -8, 9, -9, 10, -10, -11, 11, 12, -12, 13, -13, 14, -14, 16, 15, 17, 18, -15, -17, -16, 19, -18, -19, 20, -20, 21, -21, 22, -22, 23, -23, -25, 25, -27, -24, -26, 24, -28, 27, 29, -30, -29, 26, -31, -34, -33, -32, -36, 28, -35, -38, -37, 30, -39, -41, -57, -59, -58, -60, 38, 39, 40, 41, 42, 57, 37, 31, 32, 33, 34, 35, 36, 44, 51, 52, 53, 54, 55, 56, 50, 45, 46, 47, 48, 49, 58, -54, -52, -51, -50, -55, 43, 60, 59, -56, -53, -45, -44, -42, -40, -43, -49, -48, -46, -47, }; /* noise table 4.A.88, format = Q31 */ const uint32_t noiseTab[512*2] PROGMEM = { 0x8010fd38, 0xb3dc7948, 0x7c4e2301, 0xa9904192, 0x121622a7, 0x86489625, 0xc3d53d25, 0xd0343fa9, 0x674d6f70, 0x25f4e9fd, 0xce1a8c8b, 0x72a726c5, 0xfea6efc6, 0xaa4adb1a, 0x8b2dd628, 0xf14029e4, 0x46321c1a, 0x604889a0, 0x33363b63, 0x815ed069, 0x802b4315, 0x8f2bf7f3, 0x85b86073, 0x745cfb46, 0xc57886b3, 0xb76731f0, 0xa2a66772, 0x828ca631, 0x60cc145e, 0x1ad1010f, 0x090c83d4, 0x9bd7ba87, 0x5f5aeea2, 0x8b4dbd99, 0x848e7b1e, 0x86bb9fa2, 0x26f18ae5, 0xc0b81194, 0x553407bf, 0x52c17953, 0x755f468d, 0x166b04f8, 0xa5687981, 0x4343248b, 0xa6558d5e, 0xc5f6fab7, 0x80a4fb8c, 0x8cb53cb7, 0x7da68a54, 0x9cd8df8a, 0xba05376c, 0xfcb58ee2, 0xfdd657a4, 0x005e35ca, 0x91c75c55, 0x367651e6, 0x816abf85, 0x8f831c4f, 0x423f9c9c, 0x55aa919e, 0x80779834, 0xb59f4244, 0x800a095c, 0x7de9e0cc, 0x46bda5cb, 0x4c184464, 0x2c438f71, 0x797216b5, 0x5035cee6, 0xa0c3a26e, 0x9d3f95fa, 0xd4a100c0, 0x8ac30dac, 0x04b87397, 0x9e5ac516, 0x8b0b442e, 0x66210ad6, 0x88ba7598, 0x45b9bd33, 0xf0be5087, 0x9261b85e, 0x364f6a31, 0x891c4b50, 0x23ad08ce, 0xf10366a6, 0x80414276, 0x1b562e06, 0x8be21591, 0x9e798195, 0x7fb4045c, 0x7d9506cf, 0x854e691f, 0x9207f092, 0x7a94c9d5, 0x88911536, 0x3f45cc61, 0x27059279, 0xa5b57109, 0x6d2bb67b, 0x3bdc5379, 0x74e662d8, 0x80348f8c, 0xf875e638, 0x5a8caea1, 0x2459ae75, 0x2c54b939, 0x79ee3203, 0xb9bc8683, 0x9b6f630c, 0x9f45b351, 0x8563b2b9, 0xe5dbba41, 0x697c7d0d, 0x7bb7c90e, 0xac900866, 0x8e6b5177, 0x8822dd37, 0x7fd5a91e, 0x7506da05, 0x82302aca, 0xa5e4be04, 0x4b4288eb, 0x00b8bc9f, 0x4f1033e4, 0x7200d612, 0x43900c8c, 0xa815b900, 0x676ed1d4, 0x5c5f23b2, 0xa758ee11, 0xaf73abfa, 0x11714ec0, 0x265239e0, 0xc50de679, 0x8a84e341, 0xa1438354, 0x7f1a341f, 0x343ec96b, 0x696e71b0, 0xa13bde39, 0x81e75094, 0x80091111, 0x853a73bf, 0x80f9c1ee, 0xe4980086, 0x886a8e28, 0xa7e89426, 0xdd93edd7, 0x7592100d, 0x0bfa8123, 0x850a26d4, 0x2e34f395, 0x421b6c00, 0xa4a462e4, 0x4e3f5090, 0x3c189f4c, 0x3c971a56, 0xdd0376d2, 0x747a5367, 0x7bcbc9d7, 0x3966be6a, 0x7efda616, 0x55445e15, 0x7ba2ab3f, 0x5fe684f2, 0x8cf42af9, 0x808c61c3, 0x4390c27b, 0x7cac62ff, 0xea6cab22, 0x5d0902ad, 0xc27b7208, 0x7a27389d, 0x5820a357, 0xa29bbe59, 0x9df0f1fd, 0x92bd67e5, 0x7195b587, 0x97cac65b, 0x8339807e, 0x8f72d832, 0x5fad8685, 0xa462d9d3, 0x81d46214, 0x6ae93e1d, 0x6b23a5b9, 0xc2732874, 0x81795268, 0x7c568cb6, 0x668513ea, 0x428d024e, 0x66b78b3a, 0xfee9ef03, 0x9ddcbb82, 0xa605f07e, 0x46dc55e0, 0x85415054, 0xc89ec271, 0x7c42edfb, 0x0befe59b, 0x89b8f607, 0x6d732a1a, 0xa7081ebd, 0x7e403258, 0x21feeb7b, 0x5dd7a1e7, 0x23e3a31a, 0x129bc896, 0xa11a6b54, 0x7f1e031c, 0xfdc1a4d1, 0x96402e53, 0xb9700f1a, 0x8168ecd6, 0x7d63d3cc, 0x87a70d65, 0x81075a7a, 0x55c8caa7, 0xa95d00b5, 0x102b1652, 0x0bb30215, 0xe5b63237, 0xa446ca44, 0x82d4c333, 0x67b2e094, 0x44c3d661, 0x33fd6036, 0xde1ea2a1, 0xa95e8e47, 0x78f66eb9, 0x6f2aef1e, 0xe8887247, 0x80a3b70e, 0xfca0d9d3, 0x6bf0fd20, 0x0d5226de, 0xf4341c87, 0x5902df05, 0x7ff1a38d, 0xf02e5a5b, 0x99f129af, 0x8ac63d01, 0x7b53f599, 0x7bb32532, 0x99ac59b0, 0x5255a80f, 0xf1320a41, 0x2497aa5c, 0xcce60bd8, 0x787c634b, 0x7ed58c5b, 0x8a28eb3a, 0x24a5e647, 0x8b79a2c1, 0x955f5ce5, 0xa9d12bc4, 0x7a1e20c6, 0x3eeda7ac, 0xf7be823a, 0x042924ce, 0x808b3f03, 0x364248da, 0xac2895e5, 0x69a8b5fa, 0x97fe8b63, 0xbdeac9aa, 0x8073e0ad, 0x6c25dba7, 0x005e51d2, 0x52e74389, 0x59d3988c, 0xe5d1f39c, 0x7b57dc91, 0x341adbe7, 0xa7d42b8d, 0x74e9f335, 0xd35bf7d8, 0x5b7c0a4b, 0x75bc0874, 0x552129bf, 0x8144b70d, 0x6de93bbb, 0x5825f14b, 0x473ec5ca, 0x80a8f37c, 0xe6552d69, 0x7898360b, 0x806379b0, 0xa9b59339, 0x3f6bf60c, 0xc367d731, 0x920ade99, 0x125592f7, 0x877e5ed1, 0xda895d95, 0x075f2ece, 0x380e5f5e, 0x9b006b62, 0xd17a6dd2, 0x530a0e13, 0xf4cc9a14, 0x7d0a0ed4, 0x847c6e3f, 0xbaee4975, 0x47131163, 0x64fb2cac, 0x5e2100a6, 0x7b756a42, 0xd87609f4, 0x98bfe48c, 0x0493745e, 0x836c5784, 0x7e5ccb40, 0x3df6b476, 0x97700d28, 0x8bbd93fd, 0x56de9cdb, 0x680b4e65, 0xebc3d90e, 0x6d286793, 0x6753712e, 0xe05c98a7, 0x3d2b6b85, 0xc4b18ddb, 0x7b59b869, 0x31435688, 0x811888e9, 0xe011ee7a, 0x6a5844f9, 0x86ae35ea, 0xb4cbc10b, 0x01a6f5d6, 0x7a49ed64, 0x927caa49, 0x847ddaed, 0xae0d9bb6, 0x836bdb04, 0x0fd810a6, 0x74fe126b, 0x4a346b5f, 0x80184d36, 0x5afd153c, 0x90cc8102, 0xe606d0e6, 0xde69aa58, 0xa89f1222, 0xe06df715, 0x8fd16144, 0x0317c3e8, 0x22ce92fc, 0x690c3eca, 0x93166f02, 0x71573414, 0x8d43cffb, 0xe8bd0bb6, 0xde86770f, 0x0bf99a41, 0x4633a661, 0xba064108, 0x7adafae3, 0x2f6cde5d, 0xb350a52c, 0xa5ebfb0b, 0x74c57b46, 0xd3b603b5, 0x80b70892, 0xa7f7fa53, 0xd94b566c, 0xdda3fd86, 0x6a635793, 0x3ed005ca, 0xc5f087d8, 0x31e3a746, 0x7a4278f9, 0x82def1f9, 0x06caa2b2, 0xe9d2c349, 0x8940e7f7, 0x7feef8dd, 0x4a9b01f0, 0xacde69f8, 0x57ddc280, 0xf09e4ba4, 0xb6d9f729, 0xb48c18f2, 0xd3654aa9, 0xca7a03c8, 0x14d57545, 0x7fda87a5, 0x0e411366, 0xb77d0df0, 0x8c2aa467, 0x787f2590, 0x2d292db1, 0x9f12682c, 0x44ac364d, 0x1a4b31a6, 0x871f7ded, 0x7ff99167, 0x6630a1d5, 0x25385eb9, 0x2d4dd549, 0xaf8a7004, 0x319ebe0f, 0x379ab730, 0x81dc56a4, 0x822d8523, 0x1ae8554c, 0x18fa0786, 0x875f7de4, 0x85ca350f, 0x7de818dc, 0x7786a38f, 0xa5456355, 0x92e60f88, 0xf5526122, 0x916039bc, 0xc561e2de, 0x31c42042, 0x7c82e290, 0x75d158b2, 0xb015bda1, 0x7220c750, 0x46565441, 0xd0da1fdd, 0x7b777481, 0x782e73c6, 0x8cd72b7b, 0x7f1006aa, 0xfb30e51e, 0x87994818, 0x34e7c7db, 0x7faae06b, 0xea74fbc0, 0xd20c7af4, 0xc44f396b, 0x06b4234e, 0xdf2e2a93, 0x2efb07c8, 0xce861911, 0x7550ea05, 0xd8d90bbb, 0x58522eec, 0x746b3520, 0xce844ce9, 0x7f5cacc3, 0xda8f17e0, 0x2fedf9cb, 0xb2f77ec4, 0x6f13f4c0, 0x834de085, 0x7b7ace4b, 0x713b16ac, 0x499c5ab0, 0x06a7961d, 0x1b39a48a, 0xbb853e6e, 0x7c781cc1, 0xc0baebf5, 0x7dace394, 0x815ceebc, 0xcc7b27d4, 0x8274b181, 0xa2be40a2, 0xdd01d5dc, 0x7fefeb14, 0x0813ec78, 0xba3077cc, 0xe5cf1e1c, 0xedcfacae, 0x54c43a9b, 0x5cd62a42, 0x93806b55, 0x03095c5b, 0x8e076ae3, 0x71bfcd2a, 0x7ac1989b, 0x623bc71a, 0x5e15d4d2, 0xfb341dd1, 0xd75dfbca, 0xd0da32be, 0xd4569063, 0x337869da, 0x3d30606a, 0xcd89cca2, 0x7dd2ae36, 0x028c03cd, 0xd85e052c, 0xe8dc9ec5, 0x7ffd9241, 0xde5bf4c6, 0x88c4b235, 0x8228be2e, 0x7fe6ec64, 0x996abe6a, 0xdeb0666d, 0x9eb86611, 0xd249b922, 0x18b3e26b, 0x80211168, 0x5f8bb99c, 0x6ecb0dd2, 0x4728ff8d, 0x2ac325b8, 0x6e5169d2, 0x7ebbd68d, 0x05e41d17, 0xaaa19f28, 0x8ab238a6, 0x51f105be, 0x140809cc, 0x7f7345d9, 0x3aae5a9d, 0xaecec6e4, 0x1afb3473, 0xf6229ed1, 0x8d55f467, 0x7e32003a, 0x70f30c14, 0x6686f33f, 0xd0d45ed8, 0x644fab57, 0x3a3fbbd3, 0x0b255fc4, 0x679a1701, 0x90e17b6e, 0x325d537b, 0xcd7b9b87, 0xaa7be2a2, 0x7d47c966, 0xa33dbce5, 0x8659c3bb, 0x72a41367, 0x15c446e0, 0x45fe8b0a, 0x9d8ddf26, 0x84d47643, 0x7fabe0da, 0x36a70122, 0x7a28ebfe, 0x7c29b8b8, 0x7f760406, 0xbabe4672, 0x23ea216e, 0x92bcc50a, 0x6d20dba2, 0xad5a7c7e, 0xbf3897f5, 0xabb793e1, 0x8391fc7e, 0xe270291c, 0x7a248d58, 0x80f8fd15, 0x83ef19f3, 0x5e6ece7d, 0x278430c1, 0x35239f4d, 0xe09c073b, 0x50e78cb5, 0xd4b811bd, 0xce834ee0, 0xf88aaa34, 0xf71da5a9, 0xe2b0a1d5, 0x7c3aef31, 0xe84eabca, 0x3ce25964, 0xf29336d3, 0x8fa78b2c, 0xa3fc3415, 0x63e1313d, 0x7fbc74e0, 0x7340bc93, 0x49ae583b, 0x8b79de4b, 0x25011ce9, 0x7b462279, 0x36007db0, 0x3da1599c, 0x77780772, 0xc845c9bb, 0x83ba68be, 0x6ee507d1, 0x2f0159b8, 0x5392c4ed, 0x98336ff6, 0x0b3c7f11, 0xde697aac, 0x893fc8d0, 0x6b83f8f3, 0x47799a0d, 0x801d9dfc, 0x8516a83e, 0x5f8d22ec, 0x0f8ba384, 0xa049dc4b, 0xdd920b05, 0x7a99bc9f, 0x9ad19344, 0x7a345dba, 0xf501a13f, 0x3e58bf19, 0x7fffaf9a, 0x3b4e1511, 0x0e08b991, 0x9e157620, 0x7230a326, 0x4977f9ff, 0x2d2bbae1, 0x607aa7fc, 0x7bc85d5f, 0xb441bbbe, 0x8d8fa5f2, 0x601cce26, 0xda1884f2, 0x81c82d64, 0x200b709c, 0xcbd36abe, 0x8cbdddd3, 0x55ab61d3, 0x7e3ee993, 0x833f18aa, 0xffc1aaea, 0x7362e16a, 0x7fb85db2, 0x904ee04c, 0x7f04dca6, 0x8ad7a046, 0xebe7d8f7, 0xfbc4c687, 0xd0609458, 0x093ed977, 0x8e546085, 0x7f5b8236, 0x7c47e118, 0xa01f2641, 0x7ffb3e48, 0x05de7cda, 0x7fc281b9, 0x8e0278fc, 0xd74e6d07, 0x94c24450, 0x7cf9e641, 0x2ad27871, 0x919fa815, 0x805fd205, 0x7758397f, 0xe2c7e02c, 0x1828e194, 0x5613d6fe, 0xfb55359f, 0xf9699516, 0x8978ee26, 0x7feebad9, 0x77d71d82, 0x55b28b60, 0x7e997600, 0x80821a6b, 0xc6d78af1, 0x691822ab, 0x7f6982a0, 0x7ef56f99, 0x5c307f40, 0xac6f8b76, 0x42cc8ba4, 0x782c61d9, 0xa0224dd0, 0x7bd234d1, 0x74576e3b, 0xe38cfe9a, 0x491e66ef, 0xc78291c5, 0x895bb87f, 0x924f7889, 0x71b89394, 0x757b779d, 0xc4a9c604, 0x5cdf7829, 0x8020e9df, 0x805e8245, 0x4a82c398, 0x6360bd62, 0x78bb60fc, 0x09e0d014, 0x4b0ea180, 0xb841978b, 0x69a0e864, 0x7df35977, 0x3284b0dd, 0x3cdc2efd, 0x57d31f5e, 0x541069cc, 0x1776e92e, 0x04309ea3, 0xa015eb2d, 0xce7bfabc, 0x41b638f8, 0x8365932e, 0x846ab44c, 0xbbcc80cb, 0x8afa6cac, 0x7fc422ea, 0x4e403fc0, 0xbfac9aee, 0x8e4c6709, 0x028e01fb, 0x6d160a9b, 0x7fe93004, 0x790f9cdc, 0x6a1f37a0, 0xf7e7ef30, 0xb4ea0f04, 0x7bf4c8e6, 0xe981701f, 0xc258a9d3, 0x6acbbfba, 0xef5479c7, 0x079c8bd8, 0x1a410f56, 0x6853b799, 0x86cd4f01, 0xc66e23b6, 0x34585565, 0x8d1fe00d, 0x7fcdba1a, 0x32c9717b, 0xa02f9f48, 0xf64940db, 0x5ed7d8f1, 0x61b823b2, 0x356f8918, 0xa0a7151e, 0x793fc969, 0x530beaeb, 0x34e93270, 0x4fc4ddb5, 0x88d58b6c, 0x36094774, 0xf620ac80, 0x03763a72, 0xf910c9a6, 0x6666fb2d, 0x752c8be8, 0x9a6dfdd8, 0xd1a7117d, 0x51c1b1d4, 0x0a67773d, 0x43b32a79, 0x4cdcd085, 0x5f067d30, 0x05bfe92a, 0x7ed7d203, 0xe71a3c85, 0x99127ce2, 0x8eb3cac4, 0xad4bbcea, 0x5c6a0fd0, 0x0eec04af, 0x94e95cd4, 0x8654f921, 0x83eabb5d, 0xb058d7ca, 0x69f12d3c, 0x03d881b2, 0x80558ef7, 0x82938cb3, 0x2ec0e1d6, 0x80044422, 0xd1e47051, 0x720fc6ff, 0x82b20316, 0x0d527b02, 0x63049a15, 0x7ad5b9ad, 0xd2a4641d, 0x41144f86, 0x7b04917a, 0x15c4a2c0, 0x9da07916, 0x211df54a, 0x7fdd09af, 0xfe924f3f, 0x7e132cfe, 0x9a1d18d6, 0x7c56508b, 0x80f0f0af, 0x8095ced6, 0x8037d0d7, 0x026719d1, 0xa55fec43, 0x2b1c7cb7, 0xa5cd5ac1, 0x77639fad, 0x7fcd8b62, 0x81a18c27, 0xaee4912e, 0xeae9eebe, 0xeb3081de, 0x8532aada, 0xc822362e, 0x86a649a9, 0x8031a71d, 0x7b319dc6, 0xea8022e6, 0x814bc5a9, 0x8f62f7a1, 0xa430ea17, 0x388deafb, 0x883b5185, 0x776fe13c, 0x801c683f, 0x87c11b98, 0xb7cbc644, 0x8e9ad3e8, 0x3cf5a10c, 0x7ff6a634, 0x949ef096, 0x9f84aa7c, 0x010af13f, 0x782d1de8, 0xf18e492a, 0x6cf63b01, 0x4301cd81, 0x32d15c9e, 0x68ad8cef, 0xd09bd2d6, 0x908c5c15, 0xd1e36260, 0x2c5bfdd0, 0x88765a99, 0x93deba1e, 0xac6ae342, 0xe865b84c, 0x0f4f2847, 0x7fdf0499, 0x78b1c9b3, 0x6a73261e, 0x601a96f6, 0xd2847933, 0x489aa888, 0xe12e8093, 0x3bfa5a5f, 0xd96ba5f7, 0x7c8f4c8d, 0x80940c6f, 0xcef9dd1a, 0x7e1a055f, 0x3483558b, 0x02b59cc4, 0x0c56333e, 0x05a5b813, 0x92d66287, 0x7516b679, 0x71bfe03f, 0x8056bf68, 0xc24d0724, 0x8416bcf3, 0x234afbdb, 0x4b0d6f9c, 0xaba97333, 0x4b4f42b6, 0x7e8343ab, 0x7ffe2603, 0xe590f73c, 0x45e10c76, 0xb07a6a78, 0xb35609d3, 0x1a027dfd, 0x90cb6e20, 0x82d3fe38, 0x7b409257, 0x0e395afa, 0x1b802093, 0xcb0c6c59, 0x241e17e7, 0x1ee3ea0a, 0x41a82302, 0xab04350a, 0xf570beb7, 0xbb444b9b, 0x83021459, 0x838d65dc, 0x1c439c84, 0x6fdcc454, 0xef9ef325, 0x18626c1c, 0x020d251f, 0xc4aae786, 0x8614cb48, 0xf6f53ca6, 0x8710dbab, 0x89abec0d, 0xf29d41c1, 0x94b50336, 0xfdd49178, 0x604658d1, 0x800e85be, 0xca1bb079, 0x7fa48eeb, 0xa3b7fafe, 0xd330436b, 0x64eb604c, 0x43a658ae, 0x7caa1337, 0xddd445e6, 0x7efbf955, 0xb706ec71, 0x624a6b53, 0x9e0e231f, 0x97097248, 0xa1e1a17a, 0x68dd2e44, 0x7f9d2e14, 0xddcc7074, 0x58324197, 0xc88fc426, 0x6d3640ae, 0x7ef83600, 0x759a0270, 0x98b6d854, 0xd63c9b84, 0x372474a2, 0xe3f18cfd, 0x56ab0bdb, 0x85c9be7e, 0x47dfcfeb, 0xa5830d41, 0x0ddd6283, 0xf4f480ad, 0x74c60e38, 0xab8943c3, 0xc1508fe7, 0x480cdc39, 0x8e097362, 0xa44793be, 0x538b7e18, 0x545f5b41, 0x56529175, 0x9771a97e, 0xc2da7421, 0xea8265f2, 0x805d1163, 0x883c5d28, 0x8ba94c48, 0x4f676e65, 0xf78735b3, 0xe1853671, 0x7f454f53, 0x18147f85, 0x7d09e15d, 0xdb4f3494, 0x795c8973, 0x83310632, 0x85d8061c, 0x9a1a0ebf, 0xc125583c, 0x2a1b1a95, 0x7fd9103f, 0x71e98c72, 0x40932ed7, 0x91ed227a, 0x3c5e560e, 0xe816dee9, 0xb0891b80, 0x600038ba, 0xc7d9a80d, 0x7fff5e09, 0x7e3f4351, 0xbb6b4424, 0xb14448d4, 0x8d6bb7e1, 0xfb153626, 0xa68ad537, 0xd9782006, 0xf62f6991, 0x359ba8c1, 0x02ccff0b, 0x91bf2256, 0x7ea71c4d, 0x560ce5df, 0xeeba289b, 0xa574c4e7, 0x9e04f6ee, 0x7860a5ec, 0x0b8db4a2, 0x968ba3d7, 0x0b6c77df, 0xd6f3157d, 0x402eff1a, 0x49b820b3, 0x8152aebb, 0xd180b0b6, 0x098604d4, 0x7ff92224, 0xede9c996, 0x89c58061, 0x829624c4, 0xc6e71ea7, 0xba94d915, 0x389c3cf6, 0x5b4c5a06, 0x04b335e6, 0x516a8aab, 0x42c8d7d9, 0x92b12af6, 0x86c8549f, 0xfda98acf, 0x819673b6, 0x69545dac, 0x6feaa230, 0x726e6d3f, 0x886ebdfe, 0x34f5730a, 0x7af63ba2, 0x77307bbf, 0x7cd80630, 0x6e45efe0, 0x7f8ad7eb, 0x59d7df99, 0x86c70946, 0xda233629, 0x753f6cbf, 0x825eeb40, }; /* sample rates (table 4.5.1) */ const int sampRateTab[12] PROGMEM = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000 }; /* max scalefactor band for prediction (main profile only) */ const uint8_t predSFBMax[12] PROGMEM = { 33, 33, 38, 40, 40, 40, 41, 41, 37, 37, 37, 34 }; /* channel mapping (table 1.6.3.4) (-1 = unknown, so need to determine mapping based on rules in 8.5.1) */ const int8_t channelMapTab[8] PROGMEM = { -1, 1, 2, 3, 4, 5, 6, 8 }; /* number of channels in each element (SCE, CPE, etc.) * see AACElementID in aaccommon.h */ const uint8_t elementNumChans[8] PROGMEM = { 1, 2, 0, 1, 0, 0, 0, 0 }; /* total number of scale factor bands in one window */ const uint8_t /*char*/ sfBandTotalShort[12] PROGMEM = { 12, 12, 12, 14, 14, 14, 15, 15, 15, 15, 15, 15 }; const uint8_t /*char*/ sfBandTotalLong[12] PROGMEM = { 41, 41, 47, 49, 49, 51, 47, 47, 43, 43, 43, 40 }; /* scale factor band tables */ const uint8_t sfBandTabShortOffset[12] PROGMEM = {0, 0, 0, 13, 13, 13, 28, 28, 44, 44, 44, 60}; const uint16_t sfBandTabShort[76] PROGMEM = { /* short block 64, 88, 96 kHz [13] (tables 4.5.24, 4.5.26) */ 0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 92, 128, /* short block 32, 44, 48 kHz [15] (table 4.5.15) */ 0, 4, 8, 12, 16, 20, 28, 36, 44, 56, 68, 80, 96, 112, 128, /* short block 22, 24 kHz [16] (table 4.5.22) */ 0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 64, 76, 92, 108, 128, /* short block 11, 12, 16 kHz [16] (table 4.5.20) */ 0, 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 60, 72, 88, 108, 128, /* short block 8 kHz [16] (table 4.5.18) */ 0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 60, 72, 88, 108, 128 }; const uint16_t sfBandTabLongOffset[12] PROGMEM = {0, 0, 42, 90, 90, 140, 192, 192, 240, 240, 240, 284}; const uint16_t sfBandTabLong[325] PROGMEM = { /* long block 88, 96 kHz [42] (table 4.5.25) */ 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, 276, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960, 1024, /* long block 64 kHz [48] (table 4.5.13) */ 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64, 72, 80, 88, 100, 112, 124, 140, 156, 172, 192, 216, 240, 268, 304, 344, 384, 424, 464, 504, 544, 584, 624, 664, 704, 744, 784, 824, 864, 904, 944, 984, 1024, /* long block 44, 48 kHz [50] (table 4.5.14) */ 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, /* long block 32 kHz [52] (table 4.5.16) */ 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, /* long block 22, 24 kHz [48] (table 4.5.21) */ 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, /* long block 11, 12, 16 kHz [44] (table 4.5.19) */ 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, /* long block 8 kHz [41] (table 4.5.17) */ 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 }; /* TNS max bands (table 4.139) and max order (table 4.138) */ const uint8_t tnsMaxBandsShortOffset[3] PROGMEM = {0, 0, 12}; const uint16_t tnsMaxBandsShort[2*12] PROGMEM = { 9, 9, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, /* short block, Main/LC */ 7, 7, 7, 6, 6, 6, 7, 7, 8, 8, 8, 7 /* short block, SSR */ }; const uint8_t tnsMaxOrderShort[3] PROGMEM = {7, 7, 7}; const uint8_t tnsMaxBandsLongOffset[3] PROGMEM = {0, 0, 12}; const uint16_t tnsMaxBandsLong[2*12] PROGMEM = { 31, 31, 34, 40, 42, 51, 46, 46, 42, 42, 42, 39, /* long block, Main/LC */ 28, 28, 27, 26, 26, 26, 29, 29, 23, 23, 23, 19, /* long block, SSR */ }; const uint8_t tnsMaxOrderLong[3] PROGMEM = {20, 12, 12}; /* k0Tab[sampRateIdx][k] = k0 = startMin + offset(bs_start_freq) for given sample rate (4.6.18.3.2.1) * downsampled (single-rate) SBR not currently supported */ const uint8_t k0Tab[NUM_SAMPLE_RATES_SBR][16] = { { 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 23, 27, 31 }, /* 96 kHz */ { 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 23, 27, 31 }, /* 88 kHz */ { 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 21, 23, 26, 30 }, /* 64 kHz */ { 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 27, 31 }, /* 48 kHz */ { 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 23, 25, 28, 32 }, /* 44 kHz */ { 10, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29, 32 }, /* 32 kHz */ { 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29, 32 }, /* 24 kHz */ { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 28, 30 }, /* 22 kHz */ { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }, /* 16 kHz */ }; /* k2Tab[sampRateIdx][k] = stopVector(bs_stop_freq) for given sample rate, bs_stop_freq = [0, 13] (4.6.18.3.2.1) * generated with Matlab script calc_stopvec.m * downsampled (single-rate) SBR not currently supported */ const uint8_t k2Tab[NUM_SAMPLE_RATES_SBR][14] = { { 13, 15, 17, 19, 21, 24, 27, 31, 35, 39, 44, 50, 57, 64 }, /* 96 kHz */ { 15, 17, 19, 21, 23, 26, 29, 33, 37, 41, 46, 51, 57, 64 }, /* 88 kHz */ { 20, 22, 24, 26, 28, 31, 34, 37, 41, 45, 49, 54, 59, 64 }, /* 64 kHz */ { 21, 23, 25, 27, 29, 32, 35, 38, 41, 45, 49, 54, 59, 64 }, /* 48 kHz */ { 23, 25, 27, 29, 31, 34, 37, 40, 43, 47, 51, 55, 59, 64 }, /* 44 kHz */ { 32, 34, 36, 38, 40, 42, 44, 46, 49, 52, 55, 58, 61, 64 }, /* 32 kHz */ { 32, 34, 36, 38, 40, 42, 44, 46, 49, 52, 55, 58, 61, 64 }, /* 24 kHz */ { 35, 36, 38, 40, 42, 44, 46, 48, 50, 52, 55, 58, 61, 64 }, /* 22 kHz */ { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 62, 64 }, /* 16 kHz */ }; const HuffInfo_t huffTabSBRInfo[10] PROGMEM = { {19, { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 2, 7, 4, 8, 72, 0}, 0}, {20, { 0, 2, 2, 2, 2, 2, 1, 3, 3, 2, 4, 4, 4, 3, 2, 5, 6, 13, 15, 46}, 121}, {17, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 0, 0, 1, 25, 10, 0, 0, 0}, 242}, {19, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 1, 0, 1, 1, 2, 1, 29, 2, 0}, 291}, {19, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 1, 2, 5, 1, 4, 2, 3, 34, 0}, 340}, {20, { 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 1, 2, 3, 4, 4, 7, 10, 16}, 403}, {14, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 13, 2, 0, 0, 0, 0, 0, 0}, 466}, {14, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 6, 8, 0, 0, 0, 0, 0, 0}, 491}, {14, { 1, 1, 1, 1, 1, 1, 0, 2, 0, 1, 1, 0, 51, 2, 0, 0, 0, 0, 0, 0}, 516}, { 8, { 1, 1, 1, 0, 1, 1, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 579}, }; /* Huffman tables from appendix 4.A.6.1, includes offset of -LAV[i] for table i */ const short huffTabSBR[604] PROGMEM = { /* SBR table sbr_tenv15 [121] (signed) */ 0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, 6, -7, 7, -8, -9, 8, -10, 9, -11, 10, -12, -13, 11, -14, 12, -15, -16, 13, -19, -18, -17, 14, -24, -20, 16, -26, -21, 15, -23, -25, -22, -60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, /* SBR table sbr_fenv15 [121] (signed) */ 0, -1, 1, -2, -3, 2, -4, 3, -5, 4, -6, 5, -7, 6, -8, 7, -9, 8, -10, 9, -11, 10, 11, -12, 12, -13, 13, 14, -14, -15, 15, 16, 17, -16, -17, -18, -19, 18, 19, -20, -21, 20, 21, -24, -23, -22, -26, -28, 22, 23, 25, -41, -25, 26, 27, -30, -27, 24, 28, 44, -51, -46, -44, -43, -37, -33, -31, -29, 30, 37, 42, 47, 48, -60, -59, -58, -57, -56, -55, -54, -53, -52, -50, -49, -48, -47, -45, -42, -40, -39, -38, -36, -35, -34, -32, 29, 31, 32, 33, 34, 35, 36, 38, 39, 40, 41, 43, 45, 46, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, /* SBR table sbr_tenv15b [49] (signed) */ 0, 1, -1, 2, -2, 3, -3, 4, -4, -5, 5, -6, 6, 7, -7, 8, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, /* SBR table sbr_fenv15b [49] (signed) */ 0, -1, 1, -2, 2, 3, -3, -4, 4, -5, 5, -6, 6, -7, 7, 8, -9, -8, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, /* SBR table sbr_tenv30 [63] (signed) */ 0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, -7, 6, -8, 7, -9, -10, 8, 9, 10, -13, -11, -12, -14, 11, 12, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* SBR table sbr_fenv30 [63] (signed) */ 0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, 6, -7, 7, -8, 8, 9, -9, -10, 10, 11, -11, -12, 12, 13, -13, -15, 14, 15, -14, 18, -18, -24, -19, 16, 17, -22, -21, -16, 20, 21, 22, 25, -23, -20, 24, -31, -30, -29, -28, -27, -26, -25, -17, 19, 23, 26, 27, 28, 29, 30, 31, /* SBR table sbr_tenv30b [25] (signed) */ 0, 1, -1, -2, 2, 3, -3, -4, 4, -5, -12, -11, -10, -9, -8, -7, -6, 5, 6, 7, 8, 9, 10, 11, 12, /* SBR table sbr_fenv30b [25] (signed) */ 0, -1, 1, -2, 2, 3, -3, -4, 4, -5, 5, 6, -12, -11, -10, -9, -8, -7, -6, 7, 8, 9, 10, 11, 12, /* SBR table sbr_tnoise30 [63] (signed) */ 0, 1, -1, -2, 2, -3, 3, -4, 4, -5, 5, 11, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* SBR table sbr_tnoise30b [25] (signed) */ 0, -1, 1, -2, 2, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, }; /* newBWTab[prev invfMode][curr invfMode], format = Q31 (table 4.158) * sample file which uses all of these: al_sbr_sr_64_2_fsaac32.aac */ static const int newBWTab[4][4] PROGMEM = { {0x00000000, 0x4ccccccd, 0x73333333, 0x7d70a3d7}, {0x4ccccccd, 0x60000000, 0x73333333, 0x7d70a3d7}, {0x00000000, 0x60000000, 0x73333333, 0x7d70a3d7}, {0x00000000, 0x60000000, 0x73333333, 0x7d70a3d7}, }; /* NINT(2.048E6 / Fs) (figure 4.47) * downsampled (single-rate) SBR not currently supported */ const uint8_t goalSBTab[NUM_SAMPLE_RATES_SBR] = { 21, 23, 32, 43, 46, 64, 85, 93, 128 }; /* twiddle table for radix 4 pass, format = Q31 */ static const uint32_t twidTabOdd32[8*6] = { 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x539eba45, 0xe7821d59, 0x4b418bbe, 0xf383a3e2, 0x58c542c5, 0xdc71898d, 0x5a82799a, 0xd2bec333, 0x539eba45, 0xe7821d59, 0x539eba45, 0xc4df2862, 0x539eba45, 0xc4df2862, 0x58c542c5, 0xdc71898d, 0x3248d382, 0xc13ad060, 0x40000000, 0xc0000000, 0x5a82799a, 0xd2bec333, 0x00000000, 0xd2bec333, 0x22a2f4f8, 0xc4df2862, 0x58c542c5, 0xcac933ae, 0xcdb72c7e, 0xf383a3e2, 0x00000000, 0xd2bec333, 0x539eba45, 0xc4df2862, 0xac6145bb, 0x187de2a7, 0xdd5d0b08, 0xe7821d59, 0x4b418bbe, 0xc13ad060, 0xa73abd3b, 0x3536cc52, }; /* PostMultiply64() table * format = Q30 * reordered for sequential access * * for (i = 0; i <= (32/2); i++) { * angle = i * M_PI / 64; * x = (cos(angle) + sin(angle)); * x = sin(angle); * } */ static const int cos1sin1tab64[34] PROGMEM = { 0x40000000, 0x00000000, 0x43103085, 0x0323ecbe, 0x45f704f7, 0x0645e9af, 0x48b2b335, 0x09640837, 0x4b418bbe, 0x0c7c5c1e, 0x4da1fab5, 0x0f8cfcbe, 0x4fd288dc, 0x1294062f, 0x51d1dc80, 0x158f9a76, 0x539eba45, 0x187de2a7, 0x553805f2, 0x1b5d100a, 0x569cc31b, 0x1e2b5d38, 0x57cc15bc, 0x20e70f32, 0x58c542c5, 0x238e7673, 0x5987b08a, 0x261feffa, 0x5a12e720, 0x2899e64a, 0x5a6690ae, 0x2afad269, 0x5a82799a, 0x2d413ccd, }; /* coefficient table 4.A.87, format = Q31 * reordered as: * cTab[0], cTab[64], cTab[128], cTab[192], cTab[256], * cTab[2], cTab[66], cTab[130], cTab[194], cTab[258], * ... * cTab[64], cTab[128], cTab[192], cTab[256], cTab[320] * * NOTE: cTab[1, 2, ... , 318, 319] = cTab[639, 638, ... 322, 321] * except cTab[384] = -cTab[256], cTab[512] = -cTab[128] */ const uint32_t cTabA[165] PROGMEM = { 0x00000000, 0x0055dba1, 0x01b2e41d, 0x09015651, 0x2e3a7532, 0xffed978a, 0x006090c4, 0x01fd3ba0, 0x08a24899, 0x311af3a4, 0xfff0065d, 0x006b47fa, 0x024bf7a1, 0x082f552e, 0x33ff670e, 0xffef7b8b, 0x0075fded, 0x029e35b4, 0x07a8127d, 0x36e69691, 0xffee1650, 0x00807994, 0x02f3e48d, 0x070bbf58, 0x39ce0477, 0xffecc31b, 0x008a7dd7, 0x034d01f0, 0x06593912, 0x3cb41219, 0xffeb50b2, 0x009424c6, 0x03a966bb, 0x0590a67d, 0x3f962fb8, 0xffe9ca76, 0x009d10bf, 0x04083fec, 0x04b0adcb, 0x4272a385, 0xffe88ba8, 0x00a520bb, 0x04694101, 0x03b8f8dc, 0x4547daea, 0xffe79e16, 0x00abe79e, 0x04cc2fcf, 0x02a99097, 0x4812f848, 0xffe6d466, 0x00b1978d, 0x05303f87, 0x01816e06, 0x4ad237a2, 0xffe65416, 0x00b5c867, 0x05950122, 0x0040c496, 0x4d83976c, 0xffe66dd0, 0x00b8394b, 0x05f9c051, 0xfee723c6, 0x5024d70e, 0xffe69423, 0x00b8c6b0, 0x065dd56a, 0xfd7475d8, 0x52b449de, 0xffe75361, 0x00b73ab0, 0x06c0f0c0, 0xfbe8f5bd, 0x552f8ff7, 0xffe85b4b, 0x00b36acd, 0x0721bf22, 0xfa44a069, 0x579505f5, 0xffea353a, 0x00acbd2f, 0x077fedb3, 0xf887507c, 0x59e2f69e, 0xffec8409, 0x00a3508f, 0x07da2b7f, 0xf6b1f3c3, 0x5c16d0ae, 0xffef2395, 0x0096dcc2, 0x08303897, 0xf4c473c6, 0x5e2f6367, 0xfff294c3, 0x00872c63, 0x0880ffdd, 0xf2bf6ea4, 0x602b0c7f, 0xfff681d6, 0x007400b8, 0x08cb4e23, 0xf0a3959f, 0x6207f220, 0xfffb42b0, 0x005d36df, 0x090ec1fc, 0xee71b2fe, 0x63c45243, 0x00007134, 0x00426f36, 0x0949eaac, 0xec2a3f5f, 0x655f63f2, 0x0006b1cf, 0x0023b989, 0x097c1ee8, 0xe9cea84a, 0x66d76725, 0x000d31b5, 0x0000e790, 0x09a3e163, 0xe75f8bb8, 0x682b39a4, 0x001471f8, 0xffda17f2, 0x09c0e59f, 0xe4de0cb0, 0x6959709d, 0x001c3549, 0xffaea5d6, 0x09d19ca9, 0xe24b8f66, 0x6a619c5e, 0x0024dd50, 0xff7ee3f1, 0x09d5560b, 0xdfa93ab5, 0x6b42a864, 0x002d8e42, 0xff4aabc8, 0x09caeb0f, 0xdcf898fb, 0x6bfbdd98, 0x003745f9, 0xff120d70, 0x09b18a1d, 0xda3b176a, 0x6c8c4c7a, 0x004103f4, 0xfed4bec3, 0x09881dc5, 0xd7722f04, 0x6cf4073e, 0x004b6c46, 0xfe933dc0, 0x094d7ec2, 0xd49fd55f, 0x6d32730f, 0x0055dba1, 0x01b2e41d, 0x09015651, 0x2e3a7532, 0x6d474e1d, }; /* PreMultiply64() table * format = Q30 * reordered for sequential access * * for (i = 0; i < 64/4; i++) { * angle = (i + 0.25) * M_PI / nmdct; * x = (cos(angle) + sin(angle)); * x = sin(angle); * * angle = (nmdct/2 - 1 - i + 0.25) * M_PI / nmdct; * x = (cos(angle) + sin(angle)); * x = sin(angle); * } */ static const int cos4sin4tab64[64] PROGMEM = { 0x40c7d2bd, 0x00c90e90, 0x424ff28f, 0x3ff4e5e0, 0x43cdd89a, 0x03ecadcf, 0x454149fc, 0x3fc395f9, 0x46aa0d6d, 0x070de172, 0x4807eb4b, 0x3f6af2e3, 0x495aada2, 0x0a2abb59, 0x4aa22036, 0x3eeb3347, 0x4bde1089, 0x0d415013, 0x4d0e4de2, 0x3e44a5ef, 0x4e32a956, 0x104fb80e, 0x4f4af5d1, 0x3d77b192, 0x50570819, 0x135410c3, 0x5156b6d9, 0x3c84d496, 0x5249daa2, 0x164c7ddd, 0x53304df6, 0x3b6ca4c4, 0x5409ed4b, 0x19372a64, 0x54d69714, 0x3a2fcee8, 0x55962bc0, 0x1c1249d8, 0x56488dc5, 0x38cf1669, 0x56eda1a0, 0x1edc1953, 0x57854ddd, 0x374b54ce, 0x580f7b19, 0x2192e09b, 0x588c1404, 0x35a5793c, 0x58fb0568, 0x2434f332, 0x595c3e2a, 0x33de87de, 0x59afaf4c, 0x26c0b162, 0x59f54bee, 0x31f79948, 0x5a2d0957, 0x29348937, 0x5a56deec, 0x2ff1d9c7, 0x5a72c63b, 0x2b8ef77d, 0x5a80baf6, 0x2dce88aa, }; /* invBandTab[i] = 1.0 / (i + 1), Q31 */ static const int invBandTab[64] PROGMEM = { 0x7fffffff, 0x40000000, 0x2aaaaaab, 0x20000000, 0x1999999a, 0x15555555, 0x12492492, 0x10000000, 0x0e38e38e, 0x0ccccccd, 0x0ba2e8ba, 0x0aaaaaab, 0x09d89d8a, 0x09249249, 0x08888889, 0x08000000, 0x07878788, 0x071c71c7, 0x06bca1af, 0x06666666, 0x06186186, 0x05d1745d, 0x0590b216, 0x05555555, 0x051eb852, 0x04ec4ec5, 0x04bda12f, 0x04924925, 0x0469ee58, 0x04444444, 0x04210842, 0x04000000, 0x03e0f83e, 0x03c3c3c4, 0x03a83a84, 0x038e38e4, 0x03759f23, 0x035e50d8, 0x03483483, 0x03333333, 0x031f3832, 0x030c30c3, 0x02fa0be8, 0x02e8ba2f, 0x02d82d83, 0x02c8590b, 0x02b93105, 0x02aaaaab, 0x029cbc15, 0x028f5c29, 0x02828283, 0x02762762, 0x026a439f, 0x025ed098, 0x0253c825, 0x02492492, 0x023ee090, 0x0234f72c, 0x022b63cc, 0x02222222, 0x02192e2a, 0x02108421, 0x02082082, 0x02000000, }; static const uint32_t poly43lo[5] PROGMEM = { 0x29a0bda9, 0xb02e4828, 0x5957aa1b, 0x236c498d, 0xff581859 }; static const uint32_t poly43hi[5] PROGMEM = { 0x10852163, 0xd333f6a4, 0x46e9408b, 0x27c2cef0, 0xfef577b4 }; /* pow2exp[i] = pow(2, i*4/3) exponent */ static const uint16_t pow2exp[8] PROGMEM = { 14, 13, 11, 10, 9, 7, 6, 5 }; /* pow2exp[i] = pow(2, i*4/3) fraction */ static const int pow2frac[8] PROGMEM = { 0x6597fa94, 0x50a28be6, 0x7fffffff, 0x6597fa94, 0x50a28be6, 0x7fffffff, 0x6597fa94, 0x50a28be6 }; /* pow(2, i/4.0) for i = [0,1,2,3], format = Q30 */ static const int pow14[4] PROGMEM = { 0x40000000, 0x4c1bf829, 0x5a82799a, 0x6ba27e65 }; /* pow(2, i/4.0) * pow(j, 4.0/3.0) for i = [0,1,2,3], j = [0,1,2,...,15] * format = Q28 for j = [0-3], Q25 for j = [4-15] */ static const uint32_t pow43_14[4][16] PROGMEM = { { 0x00000000, 0x10000000, 0x285145f3, 0x453a5cdb, /* Q28 */ 0x0cb2ff53, 0x111989d6, 0x15ce31c8, 0x1ac7f203, /* Q25 */ 0x20000000, 0x257106b9, 0x2b16b4a3, 0x30ed74b4, /* Q25 */ 0x36f23fa5, 0x3d227bd3, 0x437be656, 0x49fc823c, /* Q25 */ }, { 0x00000000, 0x1306fe0a, 0x2ff221af, 0x52538f52, 0x0f1a1bf4, 0x1455ccc2, 0x19ee62a8, 0x1fd92396, 0x260dfc14, 0x2c8694d8, 0x333dcb29, 0x3a2f5c7a, 0x4157aed5, 0x48b3aaa3, 0x50409f76, 0x57fc3010, }, { 0x00000000, 0x16a09e66, 0x39047c0f, 0x61e734aa, 0x11f59ac4, 0x182ec633, 0x1ed66a45, 0x25dfc55a, 0x2d413ccd, 0x34f3462d, 0x3cefc603, 0x4531ab69, 0x4db4adf8, 0x56752054, 0x5f6fcfcd, 0x68a1eca1, }, { 0x00000000, 0x1ae89f99, 0x43ce3e4b, 0x746d57b2, 0x155b8109, 0x1cc21cdc, 0x24ac1839, 0x2d0a479e, 0x35d13f33, 0x3ef80748, 0x48775c93, 0x524938cd, 0x5c68841d, 0x66d0df0a, 0x717e7bfe, 0x7c6e0305, }, }; /* pow(j, 4.0 / 3.0) for j = [16,17,18,...,63], format = Q23 */ static const int pow43[48] PROGMEM = { 0x1428a2fa, 0x15db1bd6, 0x1796302c, 0x19598d85, 0x1b24e8bb, 0x1cf7fcfa, 0x1ed28af2, 0x20b4582a, 0x229d2e6e, 0x248cdb55, 0x26832fda, 0x28800000, 0x2a832287, 0x2c8c70a8, 0x2e9bc5d8, 0x30b0ff99, 0x32cbfd4a, 0x34eca001, 0x3712ca62, 0x393e6088, 0x3b6f47e0, 0x3da56717, 0x3fe0a5fc, 0x4220ed72, 0x44662758, 0x46b03e7c, 0x48ff1e87, 0x4b52b3f3, 0x4daaebfd, 0x5007b497, 0x5268fc62, 0x54ceb29c, 0x5738c721, 0x59a72a59, 0x5c19cd35, 0x5e90a129, 0x610b9821, 0x638aa47f, 0x660db90f, 0x6894c90b, 0x6b1fc80c, 0x6daeaa0d, 0x70416360, 0x72d7e8b0, 0x75722ef9, 0x78102b85, 0x7ab1d3ec, 0x7d571e09, }; /* invTab[x] = 1/(x+1), format = Q30 */ static const int invTab[5] PROGMEM = {0x40000000, 0x20000000, 0x15555555, 0x10000000, 0x0ccccccd}; /* inverse quantization tables for TNS filter coefficients, format = Q31 * see bottom of file for table generation * negative (vs. spec) since we use MADD for filter kernel */ static const uint32_t invQuant3[16] PROGMEM = { 0x00000000, 0xc8767f65, 0x9becf22c, 0x83358feb, 0x83358feb, 0x9becf22c, 0xc8767f65, 0x00000000, 0x2bc750e9, 0x5246dd49, 0x6ed9eba1, 0x7e0e2e32, 0x7e0e2e32, 0x6ed9eba1, 0x5246dd49, 0x2bc750e9, }; static const uint32_t invQuant4[16] PROGMEM = { 0x00000000, 0xe5632654, 0xcbf00dbe, 0xb4c373ee, 0xa0e0a15f, 0x9126145f, 0x8643c7b3, 0x80b381ac, 0x7f7437ad, 0x7b1d1a49, 0x7294b5f2, 0x66256db2, 0x563ba8aa, 0x4362210e, 0x2e3d2abb, 0x17851aad, }; static const int8_t sgnMask[3] = {0x02, 0x04, 0x08}; static const int8_t negMask[3] = {~0x03, ~0x07, ~0x0f}; /*********************************************************************************************************************** * Function: AACDecoder_AllocateBuffers * * Description: allocate all the memory needed for the AAC decoder * try heap first, because it's faster * * Inputs: none * * Outputs: none * * Return: false if not enough memory, otherwise true * **********************************************************************************************************************/ bool AACDecoder_AllocateBuffers(void){ if(!m_AACDecInfo) {m_AACDecInfo = (AACDecInfo_t*) malloc(sizeof(AACDecInfo_t));} if(!m_PSInfoBase) {m_PSInfoBase = (PSInfoBase_t*) malloc(sizeof(PSInfoBase_t));} if(!m_pce[0]) {m_pce[0] = (ProgConfigElement_t*) malloc(sizeof(ProgConfigElement_t)*16);} if(!m_AACDecInfo || !m_PSInfoBase || !m_pce[0]) { log_i("heap is too small, try PSRAM"); AACDecoder_FreeBuffers(); } else{ goto nextStep; } if(psramFound()) { // PSRAM found, Buffer will be allocated in PSRAM if(!m_AACDecInfo) {m_AACDecInfo = (AACDecInfo_t*) ps_calloc(sizeof(AACDecInfo_t), sizeof(uint8_t));} if(!m_PSInfoBase) {m_PSInfoBase = (PSInfoBase_t*) ps_calloc(sizeof(PSInfoBase_t), sizeof(uint8_t));} if(!m_pce[0]) {m_pce[0] = (ProgConfigElement_t*) ps_calloc(sizeof(ProgConfigElement_t)*16, sizeof(uint8_t));} } if(!m_AACDecInfo || !m_PSInfoBase || !m_pce[0]) { log_e("not enough memory to allocate aacdecoder buffers"); AACDecoder_FreeBuffers(); return false; } log_i("AAC buffers allocated in PSRAM"); nextStep: #ifdef AAC_ENABLE_SBR // can't allocated in PSRAM, because PSRAM ist too slow if(!m_PSInfoSBR) {m_PSInfoSBR = (PSInfoSBR_t*)malloc(sizeof(PSInfoSBR_t));} if(!m_PSInfoSBR) { log_e("OOM in SBR, can't allocate %d bytes\n", sizeof(PSInfoSBR_t)); return false; // ERR_AAC_SBR_INIT; } #endif // Clear Buffer memset( m_AACDecInfo, 0, sizeof(AACDecInfo_t)); //Clear AACDecInfo memset( m_PSInfoBase, 0, sizeof(PSInfoBase_t)); //Clear PSInfoBase memset(&m_AACFrameInfo, 0, sizeof(AACFrameInfo_t)); //Clear AACFrameInfo memset(&m_fhADTS, 0, sizeof(ADTSHeader_t)); //Clear fhADTS memset(&m_fhADIF, 0, sizeof(ADIFHeader_t)); //Clear fhADIS memset( m_pce[0], 0, sizeof(ProgConfigElement_t) * 16); //Clear ProgConfigElement memset(&m_pulseInfo[0], 0, sizeof(PulseInfo_t) *2); //Clear PulseInfo memset(&m_aac_BitStreamInfo, 0, sizeof(aac_BitStreamInfo_t)); //Clear aac_BitStreamInfo #ifdef AAC_ENABLE_SBR memset( m_PSInfoSBR, 0, sizeof(PSInfoSBR_t)); //Clear PSInfoSBR InitSBRState(); #endif m_AACDecInfo->prevBlockID = AAC_ID_INVALID; m_AACDecInfo->currBlockID = AAC_ID_INVALID; m_AACDecInfo->currInstTag = -1; for(int ch = 0; ch < MAX_NCHANS_ELEM; ch++) m_AACDecInfo->sbDeinterleaveReqd[ch] = 0; m_AACDecInfo->adtsBlocksLeft = 0; m_AACDecInfo->tnsUsed = 0; m_AACDecInfo->pnsUsed = 0; return true; } /************************************************************************************** * Function: AACFlushCodec * * Description: flush internal codec state (after seeking, for example) * * Inputs: valid AAC decoder instance pointer (HAACDecoder) * * Outputs: updated state variables in aacDecInfo * * Return: 0 if successful, error code (< 0) if error **************************************************************************************/ int AACFlushCodec() { int ch; if (!m_AACDecInfo) return ERR_AAC_NULL_POINTER; /* reset common state variables which change per-frame * don't touch state variables which are (usually) constant for entire clip * (nChans, sampRate, profile, format, sbrEnabled) */ m_AACDecInfo->prevBlockID = AAC_ID_INVALID; m_AACDecInfo->currBlockID = AAC_ID_INVALID; m_AACDecInfo->currInstTag = -1; for (ch = 0; ch < MAX_NCHANS_ELEM; ch++) m_AACDecInfo->sbDeinterleaveReqd[ch] = 0; m_AACDecInfo->adtsBlocksLeft = 0; m_AACDecInfo->tnsUsed = 0; m_AACDecInfo->pnsUsed = 0; /* reset internal codec state (flush overlap buffers, etc.) */ memset(m_PSInfoBase->overlap, 0, AAC_MAX_NCHANS * AAC_MAX_NSAMPS * sizeof(int)); memset(m_PSInfoBase->prevWinShape, 0, AAC_MAX_NCHANS * sizeof(int)); return ERR_AAC_NONE; } /*********************************************************************************************************************** * Function: AACDecoder_FreeBuffers * * Description: allocate all the memory needed for the AAC decoder * * Inputs: none * * Outputs: none * * Return: none **********************************************************************************************************************/ void AACDecoder_FreeBuffers(void) { // uint32_t i = ESP.getFreeHeap(); if(m_AACDecInfo) {free(m_AACDecInfo); m_AACDecInfo=NULL;} if(m_PSInfoBase) {free(m_PSInfoBase); m_PSInfoBase=NULL;} if(m_pce[0]) {for(int i=0; i<16; i++) free(m_pce[i]); m_pce[0]=NULL;} #ifdef AAC_ENABLE_SBR if(m_PSInfoSBR) {free(m_PSInfoSBR); m_PSInfoSBR=NULL;} //Clear AACDecInfo #endif // log_i("AACDecoder: %lu bytes memory was freed", ESP.getFreeHeap() - i); } /*********************************************************************************************************************** * Function: AACDecoder_IsInit * * Description: returns AAC decoder initialization status * * Inputs: none * * Outputs: none * * Return: true if buffers allocated, otherwise false **********************************************************************************************************************/ bool AACDecoder_IsInit(void) { if(m_AACDecInfo && m_PSInfoBase && m_pce[0]){ return true; } return false; } /*********************************************************************************************************************** * Function: AACDecoder_FreeBuffers * * Description: allocate all the memory needed for the AAC decoder * * Inputs: none * * Outputs: none * * Return: none **********************************************************************************************************************/ /*********************************************************************************************************************** * Function: AACFindSyncWord * * Description: locate the next byte-alinged sync word in the raw AAC stream * * Inputs: buffer to search for sync word * max number of bytes to search in buffer * * Outputs: none * * Return: offset to first sync word (bytes from start of buf) * -1 if sync not found after searching nBytes **********************************************************************************************************************/ int AACFindSyncWord(uint8_t *buf, int nBytes) { int i; /* find byte-aligned syncword (12 bits = 0xFFF) */ for (i = 0; i < nBytes - 1; i++) { if ( (buf[i+0] & SYNCWORDH) == SYNCWORDH && (buf[i+1] & SYNCWORDL) == SYNCWORDL ) return i; } return -1; } //************************************************************************************** int AACGetSampRate(){return m_AACDecInfo->sampRate * (m_AACDecInfo->sbrEnabled ? 2 : 1);} int AACGetChannels(){return m_AACDecInfo->nChans;} int AACGetBitsPerSample(){return 16;} int AACGetID() {return m_AACDecInfo->id;} // 0-MPEG4, 1-MPEG2 uint8_t AACGetProfile() {return (uint8_t)m_AACDecInfo->profile;} // 0-Main, 1-LC, 2-SSR, 3-reserved uint8_t AACGetFormat() {return (uint8_t)m_AACDecInfo->format;} // 0-unknown 1-ADTS 2-ADIF, 3-RAW int AACGetOutputSamps(){return m_AACDecInfo->nChans * AAC_MAX_NSAMPS * (m_AACDecInfo->sbrEnabled ? 2 : 1);} int AACGetBitrate() { uint32_t br = AACGetBitsPerSample() * AACGetChannels() * AACGetSampRate(); return (br / m_AACDecInfo->compressionRatio); } /************************************************************************************** * Function: AACSetRawBlockParams * * Description: set internal state variables for decoding a stream of raw data blocks * * Inputs: flag indicating source of parameters * nChans, sampRate, * and profile 0 = main, 1 = LC, 2 = SSR, 3 = reserved * optionally filled-in * * Outputs: updated codec state * * Return: 0 if successful, error code (< 0) if error * * Notes: if copyLast == 1, then the codec sets up its internal state (for * decoding raw blocks) based on previously-decoded ADTS header info * if copyLast == 0, then the codec uses the values passed in * aacFrameInfo to configure its internal state (useful when the * source is MP4 format, for example) **************************************************************************************/ int AACSetRawBlockParams(int copyLast, int nChans, int sampRateCore, int profile) { if (!m_AACDecInfo) return ERR_AAC_NULL_POINTER; m_AACDecInfo->format = AAC_FF_RAW; if (copyLast) return SetRawBlockParams(1, 0, 0, 0); else return SetRawBlockParams(0, nChans, sampRateCore, profile); } /*********************************************************************************************************************** * Function: AACDecode * * Description: decode AAC frame * * Inputs: double pointer to buffer of AAC data * pointer to number of valid bytes remaining in inbuf * pointer to outbuf, big enough to hold one frame of decoded PCM samples * * Outputs: PCM data in outbuf, interleaved LRLRLR... if stereo * number of output samples = 1024 per channel * updated inbuf pointer * updated bytesLeft * * Return: 0 if successful, error code (< 0) if error * * Notes: inbuf pointer and bytesLeft are not updated until whole frame is * successfully decoded, so if ERR_AAC_INDATA_UNDERFLOW is returned * just call AACDecode again with more data in inbuf **********************************************************************************************************************/ int AACDecode(uint8_t *inbuf, int *bytesLeft, short *outbuf) { int err, offset, bitOffset, bitsAvail; int ch, baseChan, elementChans; uint8_t *inptr; #ifdef AAC_ENABLE_SBR int baseChanSBR, elementChansSBR; #endif /* make local copies (see "Notes" above) */ inptr = inbuf; bitOffset = 0; bitsAvail = (*bytesLeft) << 3; /* first time through figure out what the file format is */ if (m_AACDecInfo->format == AAC_FF_Unknown) { if (bitsAvail < 32) return ERR_AAC_INDATA_UNDERFLOW; if ((inptr)[0] == 'A' && (inptr)[1] == 'D' && (inptr)[2] == 'I' && (inptr)[3] == 'F') { /* unpack ADIF header */ m_AACDecInfo->format = AAC_FF_ADIF; err = UnpackADIFHeader(&inptr, &bitOffset, &bitsAvail); if (err) return err; } else { /* assume ADTS by default */ m_AACDecInfo->format = AAC_FF_ADTS; } } /* if ADTS, search for start of next frame */ if (m_AACDecInfo->format == AAC_FF_ADTS) { /* can have 1-4 raw data blocks per ADTS frame (header only present for first one) */ if (m_AACDecInfo->adtsBlocksLeft == 0) { offset = AACFindSyncWord(inptr, bitsAvail >> 3); if (offset < 0) return ERR_AAC_INDATA_UNDERFLOW; inptr += offset; bitsAvail -= (offset << 3); err = UnpackADTSHeader(&inptr, &bitOffset, &bitsAvail); if (err) return err; if (m_AACDecInfo->nChans == -1) { /* figure out implicit channel mapping if necessary */ err = GetADTSChannelMapping(inptr, bitOffset, bitsAvail); if (err) return err; } } m_AACDecInfo->adtsBlocksLeft--; } else if (m_AACDecInfo->format == AAC_FF_RAW) { err = PrepareRawBlock(); if (err) return err; } /* check for valid number of channels */ if (m_AACDecInfo->nChans > AAC_MAX_NCHANS || m_AACDecInfo->nChans <= 0) return ERR_AAC_NCHANS_TOO_HIGH; /* will be set later if active in this frame */ m_AACDecInfo->tnsUsed = 0; m_AACDecInfo->pnsUsed = 0; bitOffset = 0; baseChan = 0; #ifdef AAC_ENABLE_SBR baseChanSBR = 0; #endif do { /* parse next syntactic element */ err = DecodeNextElement(&inptr, &bitOffset, &bitsAvail); if (err) return err; elementChans = elementNumChans[m_AACDecInfo->currBlockID]; if (baseChan + elementChans > AAC_MAX_NCHANS) return ERR_AAC_NCHANS_TOO_HIGH; /* noiseless decoder and dequantizer */ for (ch = 0; ch < elementChans; ch++) { err = DecodeNoiselessData(&inptr, &bitOffset, &bitsAvail, ch); if (err) return err; if (AACDequantize(ch)) return ERR_AAC_DEQUANT; } /* mid-side and intensity stereo */ if (m_AACDecInfo->currBlockID == AAC_ID_CPE) { if (StereoProcess()) return ERR_AAC_STEREO_PROCESS; } /* PNS, TNS, inverse transform */ for (ch = 0; ch < elementChans; ch++) { if (PNS(ch)) return ERR_AAC_PNS; if (m_AACDecInfo->sbDeinterleaveReqd[ch]) { /* deinterleave short blocks, if required */ if (DeinterleaveShortBlocks(ch)) return ERR_AAC_SHORT_BLOCK_DEINT; m_AACDecInfo->sbDeinterleaveReqd[ch] = 0; } if (TNSFilter(ch)) return ERR_AAC_TNS; if (IMDCT(ch, baseChan + ch, outbuf)) return ERR_AAC_IMDCT; } #ifdef AAC_ENABLE_SBR if (m_AACDecInfo->sbrEnabled && (m_AACDecInfo->currBlockID == AAC_ID_FIL || m_AACDecInfo->currBlockID == AAC_ID_LFE)) { if (m_AACDecInfo->currBlockID == AAC_ID_LFE) elementChansSBR = elementNumChans[AAC_ID_LFE]; else if (m_AACDecInfo->currBlockID == AAC_ID_FIL && (m_AACDecInfo->prevBlockID == AAC_ID_SCE || m_AACDecInfo->prevBlockID == AAC_ID_CPE)) elementChansSBR = elementNumChans[m_AACDecInfo->prevBlockID]; else elementChansSBR = 0; if (baseChanSBR + elementChansSBR > AAC_MAX_NCHANS) return ERR_AAC_SBR_NCHANS_TOO_HIGH; /* parse SBR extension data if present (contained in a fill element) */ if (DecodeSBRBitstream(baseChanSBR)) return ERR_AAC_SBR_BITSTREAM; /* apply SBR */ if (DecodeSBRData(baseChanSBR, outbuf)) return ERR_AAC_SBR_DATA; baseChanSBR += elementChansSBR; } #endif baseChan += elementChans; } while (m_AACDecInfo->currBlockID != AAC_ID_END); /* byte align after each raw_data_block */ if (bitOffset) { inptr++; bitsAvail -= (8-bitOffset); bitOffset = 0; if (bitsAvail < 0) return ERR_AAC_INDATA_UNDERFLOW; } m_AACDecInfo->compressionRatio = (float)(AACGetOutputSamps()) * 2 / (inptr - inbuf); /* update pointers */ m_AACDecInfo->frameCount++; *bytesLeft -= (inptr - inbuf); inbuf = inptr; return ERR_AAC_NONE; } /*********************************************************************************************************************** * Function: DecodeLPCCoefs * * Description: decode LPC coefficients for TNS * * Inputs: order of TNS filter * resolution of coefficients (3 or 4 bits) * coefficients unpacked from bitstream * scratch buffer (b) of size >= order * * Outputs: LPC coefficients in Q(FBITS_LPC_COEFS), in 'a' * * Return: none * * Notes: assumes no guard bits in input transform coefficients * a[i] = Q(FBITS_LPC_COEFS), don't store a0 = 1.0 * (so a[0] = first delay tap, etc.) * max abs(a[i]) < log2(order), so for max order = 20 a[i] < 4.4 * (up to 3 bits of gain) so a[i] has at least 31 - FBITS_LPC_COEFS - 3 * guard bits * to ensure no intermediate overflow in all-pole filter, set * FBITS_LPC_COEFS such that number of guard bits >= log2(max order) **********************************************************************************************************************/ void DecodeLPCCoefs(int order, int res, int8_t *filtCoef, int *a, int *b) { int i, m, t; const uint32_t *invQuantTab; if (res == 3) invQuantTab = invQuant3; else if (res == 4) invQuantTab = invQuant4; else return; for (m = 0; m < order; m++) { t = invQuantTab[filtCoef[m] & 0x0f]; /* t = Q31 */ for (i = 0; i < m; i++) b[i] = a[i] - (MULSHIFT32(t, a[m-i-1]) << 1); for (i = 0; i < m; i++) a[i] = b[i]; a[m] = t >> (31 - FBITS_LPC_COEFS); } } /*********************************************************************************************************************** * Function: FilterRegion * * Description: apply LPC filter to one region of coefficients * * Inputs: number of transform coefficients in this region * direction flag (forward = 1, backward = -1) * order of filter * 'size' transform coefficients * 'order' LPC coefficients in Q(FBITS_LPC_COEFS) * scratch buffer for history (must be >= order samples long) * * Outputs: filtered transform coefficients * * Return: guard bit mask (OR of abs value of all filtered transform coefs) * * Notes: assumes no guard bits in input transform coefficients * gains 0 int bits * history buffer does not need to be preserved between regions **********************************************************************************************************************/ int FilterRegion(int size, int dir, int order, int *audioCoef, int *a, int *hist) { int i, j, y, hi32, inc, gbMask; U64 sum64; /* init history to 0 every time */ for (i = 0; i < order; i++) hist[i] = 0; sum64.w64 = 0; /* avoid warning */ gbMask = 0; inc = (dir ? -1 : 1); do { /* sum64 = a0*y[n] = 1.0*y[n] */ y = *audioCoef; sum64.r.hi32 = y >> (32 - FBITS_LPC_COEFS); sum64.r.lo32 = y << FBITS_LPC_COEFS; /* sum64 += (a1*y[n-1] + a2*y[n-2] + ... + a[order-1]*y[n-(order-1)]) */ for (j = order - 1; j > 0; j--) { sum64.w64 = MADD64(sum64.w64, hist[j], a[j]); hist[j] = hist[j-1]; } sum64.w64 = MADD64(sum64.w64, hist[0], a[0]); y = (sum64.r.hi32 << (32 - FBITS_LPC_COEFS)) | (sum64.r.lo32 >> FBITS_LPC_COEFS); /* clip output (rare) */ hi32 = sum64.r.hi32; if ((hi32 >> 31) != (hi32 >> (FBITS_LPC_COEFS-1))) y = (hi32 >> 31) ^ 0x7fffffff; hist[0] = y; *audioCoef = y; audioCoef += inc; gbMask |= FASTABS(y); } while (--size); return gbMask; } /*********************************************************************************************************************** * Function: TNSFilter * * Description: apply temporal noise shaping, if enabled * * Inputs: index of current channel * * Outputs: updated transform coefficients * updated minimum guard bit count for this channel * * Return: 0 if successful, -1 if error **********************************************************************************************************************/ int TNSFilter(int ch) { int win, winLen, nWindows, nSFB, filt, bottom, top, order, maxOrder, dir; int start, end, size, tnsMaxBand, numFilt, gbMask; int *audioCoef; uint8_t *filtLength, *filtOrder, *filtRes, *filtDir; int8_t *filtCoef; const uint16_t *tnsMaxBandTab; const uint16_t *sfbTab; ICSInfo_t *icsInfo; TNSInfo_t *ti; icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); ti = &m_PSInfoBase->tnsInfo[ch]; if (!ti->tnsDataPresent) return 0; if (icsInfo->winSequence == 2) { nWindows = NWINDOWS_SHORT; winLen = NSAMPS_SHORT; nSFB = sfBandTotalShort[m_PSInfoBase->sampRateIdx]; maxOrder = tnsMaxOrderShort[m_AACDecInfo->profile]; sfbTab = sfBandTabShort + sfBandTabShortOffset[m_PSInfoBase->sampRateIdx]; tnsMaxBandTab = tnsMaxBandsShort + tnsMaxBandsShortOffset[m_AACDecInfo->profile]; tnsMaxBand = tnsMaxBandTab[m_PSInfoBase->sampRateIdx]; } else { nWindows = NWINDOWS_LONG; winLen = NSAMPS_LONG; nSFB = sfBandTotalLong[m_PSInfoBase->sampRateIdx]; maxOrder = tnsMaxOrderLong[m_AACDecInfo->profile]; sfbTab = sfBandTabLong + sfBandTabLongOffset[m_PSInfoBase->sampRateIdx]; tnsMaxBandTab = tnsMaxBandsLong + tnsMaxBandsLongOffset[m_AACDecInfo->profile]; tnsMaxBand = tnsMaxBandTab[m_PSInfoBase->sampRateIdx]; } if (tnsMaxBand > icsInfo->maxSFB) tnsMaxBand = icsInfo->maxSFB; filtRes = ti->coefRes; filtLength = ti->length; filtOrder = ti->order; filtDir = ti->dir; filtCoef = ti->coef; gbMask = 0; audioCoef = m_PSInfoBase->coef[ch]; for (win = 0; win < nWindows; win++) { bottom = nSFB; numFilt = ti->numFilt[win]; for (filt = 0; filt < numFilt; filt++) { top = bottom; bottom = top - *filtLength++; bottom = MAX(bottom, 0); order = *filtOrder++; order = MIN(order, maxOrder); if (order) { start = sfbTab[MIN(bottom, tnsMaxBand)]; end = sfbTab[MIN(top, tnsMaxBand)]; size = end - start; if (size > 0) { dir = *filtDir++; if (dir) start = end - 1; DecodeLPCCoefs(order, filtRes[win], filtCoef, m_PSInfoBase->tnsLPCBuf, m_PSInfoBase->tnsWorkBuf); gbMask |= FilterRegion(size, dir, order, audioCoef + start, m_PSInfoBase->tnsLPCBuf, m_PSInfoBase->tnsWorkBuf); } filtCoef += order; } } audioCoef += winLen; } /* update guard bit count if necessary */ size = CLZ(gbMask) - 1; if (m_PSInfoBase->gbCurrent[ch] > size) m_PSInfoBase->gbCurrent[ch] = size; return 0; } /*********************************************************************************************************************** * Function: DecodeSingleChannelElement * * Description: decode one SCE * * Inputs: none * * Outputs: updated element instance tag * * Return: 0 if successful, -1 if error * * Notes: doesn't decode individual channel stream (part of DecodeNoiselessData) **********************************************************************************************************************/ int DecodeSingleChannelElement() { /* read instance tag */ m_AACDecInfo->currInstTag = GetBits(NUM_INST_TAG_BITS); return 0; } /*********************************************************************************************************************** * Function: DecodeChannelPairElement * * Description: decode one CPE * * Inputs: none * * Outputs: updated element instance tag * updated commonWin * updated ICS info, if commonWin == 1 * updated mid-side stereo info, if commonWin == 1 * * Return: 0 if successful, -1 if error * * Notes: doesn't decode individual channel stream (part of DecodeNoiselessData) **********************************************************************************************************************/ int DecodeChannelPairElement() { int sfb, gp, maskOffset; uint8_t currBit, *maskPtr; ICSInfo_t *icsInfo; icsInfo = m_PSInfoBase->icsInfo; /* read instance tag */ m_AACDecInfo->currInstTag = GetBits(NUM_INST_TAG_BITS); /* read common window flag and mid-side info (if present) * store msMask bits in m_PSInfoBase->msMaskBits[] as follows: * long blocks - pack bits for each SFB in range [0, maxSFB) starting with lsb of msMaskBits[0] * short blocks - pack bits for each SFB in range [0, maxSFB), for each group [0, 7] * msMaskPresent = 0 means no M/S coding * = 1 means m_PSInfoBase->msMaskBits contains 1 bit per SFB to toggle M/S coding * = 2 means all SFB's are M/S coded (so m_PSInfoBase->msMaskBits is not needed) */ m_PSInfoBase->commonWin = GetBits(1); if (m_PSInfoBase->commonWin) { DecodeICSInfo(icsInfo, m_PSInfoBase->sampRateIdx); m_PSInfoBase->msMaskPresent = GetBits(2); if (m_PSInfoBase->msMaskPresent == 1) { maskPtr = m_PSInfoBase->msMaskBits; *maskPtr = 0; maskOffset = 0; for (gp = 0; gp < icsInfo->numWinGroup; gp++) { for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) { currBit = (uint8_t)GetBits(1); *maskPtr |= currBit << maskOffset; if (++maskOffset == 8) { maskPtr++; *maskPtr = 0; maskOffset = 0; } } } } } return 0; } /*********************************************************************************************************************** * Function: DecodeLFEChannelElement * * Description: decode one LFE * * Inputs: none * * Outputs: updated element instance tag * * Return: 0 if successful, -1 if error * * Notes: doesn't decode individual channel stream (part of DecodeNoiselessData) **********************************************************************************************************************/ int DecodeLFEChannelElement() { /* read instance tag */ m_AACDecInfo->currInstTag = GetBits( NUM_INST_TAG_BITS); return 0; } /*********************************************************************************************************************** * Function: DecodeDataStreamElement * * Description: decode one DSE * * Inputs: none * * Outputs: updated element instance tag * filled in data stream buffer * * Return: 0 if successful, -1 if error **********************************************************************************************************************/ int DecodeDataStreamElement() { uint32_t byteAlign, dataCount; uint8_t *dataBuf; m_AACDecInfo->currInstTag = GetBits( NUM_INST_TAG_BITS); byteAlign = GetBits(1); dataCount = GetBits(8); if (dataCount == 255) dataCount += GetBits(8); if (byteAlign) ByteAlignBitstream(); m_PSInfoBase->dataCount = dataCount; dataBuf = m_PSInfoBase->dataBuf; while (dataCount--) *dataBuf++ = GetBits(8); return 0; } /*********************************************************************************************************************** * Function: DecodeProgramConfigElement * * Description: decode one PCE * * Inputs: none * * Outputs: filled-in ProgConfigElement_t struct * updated aac_BitStreamInfo_t struct * * Return: 0 if successful, error code (< 0) if error * * Notes: #define KEEP_PCE_COMMENTS to save the comment field of the PCE * (otherwise we just skip it in the bitstream, to save memory) **********************************************************************************************************************/ int DecodeProgramConfigElement(uint8_t idx) { int i; m_pce[idx]->elemInstTag = GetBits(4); m_pce[idx]->profile = GetBits(2); m_pce[idx]->sampRateIdx = GetBits(4); m_pce[idx]->numFCE = GetBits(4); m_pce[idx]->numSCE = GetBits(4); m_pce[idx]->numBCE = GetBits(4); m_pce[idx]->numLCE = GetBits(2); m_pce[idx]->numADE = GetBits(3); m_pce[idx]->numCCE = GetBits(4); m_pce[idx]->monoMixdown = GetBits(1) << 4; /* present flag */ if (m_pce[idx]->monoMixdown) m_pce[idx]->monoMixdown |= GetBits(4); /* element number */ m_pce[idx]->stereoMixdown = GetBits(1) << 4; /* present flag */ if (m_pce[idx]->stereoMixdown) m_pce[idx]->stereoMixdown |= GetBits(4); /* element number */ m_pce[idx]->matrixMixdown = GetBits(1) << 4; /* present flag */ if (m_pce[idx]->matrixMixdown) { m_pce[idx]->matrixMixdown |= GetBits(2) << 1; /* index */ m_pce[idx]->matrixMixdown |= GetBits(1); /* pseudo-surround enable */ } for (i = 0; i < m_pce[idx]->numFCE; i++) { m_pce[idx]->fce[i] = GetBits(1) << 4; /* is_cpe flag */ m_pce[idx]->fce[i] |= GetBits(4); /* tag select */ } for (i = 0; i < m_pce[idx]->numSCE; i++) { m_pce[idx]->sce[i] = GetBits(1) << 4; /* is_cpe flag */ m_pce[idx]->sce[i] |= GetBits(4); /* tag select */ } for (i = 0; i < m_pce[idx]->numBCE; i++) { m_pce[idx]->bce[i] = GetBits(1) << 4; /* is_cpe flag */ m_pce[idx]->bce[i] |= GetBits(4); /* tag select */ } for (i = 0; i < m_pce[idx]->numLCE; i++) m_pce[idx]->lce[i] = GetBits(4); /* tag select */ for (i = 0; i < m_pce[idx]->numADE; i++) m_pce[idx]->ade[i] = GetBits(4); /* tag select */ for (i = 0; i < m_pce[idx]->numCCE; i++) { m_pce[idx]->cce[i] = GetBits(1) << 4; /* independent/dependent flag */ m_pce[idx]->cce[i] |= GetBits(4); /* tag select */ } ByteAlignBitstream(); /* eat comment bytes and throw away */ i = GetBits(8); while (i--) GetBits(8); return 0; } /*********************************************************************************************************************** * Function: DecodeFillElement * * Description: decode one fill element * * Inputs: none * (14496-3, table 4.4.11) * * Outputs: updated element instance tag * unpacked extension payload * * Return: 0 if successful, -1 if error **********************************************************************************************************************/ int DecodeFillElement() { unsigned int fillCount; uint8_t *fillBuf; fillCount = GetBits(4); if (fillCount == 15) fillCount += (GetBits(8) - 1); m_PSInfoBase->fillCount = fillCount; fillBuf = m_PSInfoBase->fillBuf; while (fillCount--) *fillBuf++ = GetBits(8); m_AACDecInfo->currInstTag = -1; /* fill elements don't have instance tag */ m_AACDecInfo->fillExtType = 0; #ifdef AAC_ENABLE_SBR /* check for SBR * aacDecInfo->sbrEnabled is sticky (reset each raw_data_block), so for multichannel * need to verify that all SCE/CPE/ICCE have valid SBR fill element following, and * must upsample by 2 for LFE */ if (m_PSInfoBase->fillCount > 0) { m_AACDecInfo->fillExtType = (int)((m_PSInfoBase->fillBuf[0] >> 4) & 0x0f); if (m_AACDecInfo->fillExtType == EXT_SBR_DATA || m_AACDecInfo->fillExtType == EXT_SBR_DATA_CRC) m_AACDecInfo->sbrEnabled = 1; } #endif m_AACDecInfo->fillBuf = m_PSInfoBase->fillBuf; m_AACDecInfo->fillCount = m_PSInfoBase->fillCount; return 0; } /*********************************************************************************************************************** * Function: DecodeNextElement * * Description: decode next syntactic element in AAC frame * * Inputs: double pointer to buffer containing next element * pointer to bit offset * pointer to number of valid bits remaining in buf * * Outputs: type of element decoded (aacDecInfo->currBlockID) * type of element decoded last time (aacDecInfo->prevBlockID) * updated aacDecInfo state, depending on which element was decoded * updated buffer pointer * updated bit offset * updated number of available bits * * Return: 0 if successful, error code (< 0) if error **********************************************************************************************************************/ int DecodeNextElement(uint8_t **buf, int *bitOffset, int *bitsAvail) { int err, bitsUsed; /* init bitstream reader */ SetBitstreamPointer((*bitsAvail + 7) >> 3, *buf); GetBits(*bitOffset); m_AACDecInfo->prevBlockID = m_AACDecInfo->currBlockID; m_AACDecInfo->currBlockID = GetBits(NUM_SYN_ID_BITS); /* set defaults (could be overwritten by DecodeXXXElement(), depending on currBlockID) */ m_PSInfoBase->commonWin = 0; err = 0; switch (m_AACDecInfo->currBlockID) { case AAC_ID_SCE: err = DecodeSingleChannelElement(); break; case AAC_ID_CPE: err = DecodeChannelPairElement(); break; case AAC_ID_CCE: break; case AAC_ID_LFE: err = DecodeLFEChannelElement(); break; case AAC_ID_DSE: err = DecodeDataStreamElement(); break; case AAC_ID_PCE: err = DecodeProgramConfigElement(0); break; case AAC_ID_FIL: err = DecodeFillElement(); break; case AAC_ID_END: break; } if (err) return ERR_AAC_SYNTAX_ELEMENT; /* update bitstream reader */ bitsUsed = CalcBitsUsed(*buf, *bitOffset); *buf += (bitsUsed + *bitOffset) >> 3; *bitOffset = (bitsUsed + *bitOffset) & 0x07; *bitsAvail -= bitsUsed; if (*bitsAvail < 0) return ERR_AAC_INDATA_UNDERFLOW; return ERR_AAC_NONE; } /*********************************************************************************************************************** * Function: PreMultiply * * Description: pre-twiddle stage of DCT4 * * Inputs: table index (for transform size) * buffer of nmdct samples * * Outputs: processed samples in same buffer * * Return: none * * Notes: minimum 1 GB in, 2 GB out, gains 5 (short) or 8 (long) frac bits * i.e. gains 2-7= -5 int bits (short) or 2-10 = -8 int bits (long) * normalization by -1/N is rolled into tables here (see trigtabs.c) * uses 3-mul, 3-add butterflies instead of 4-mul, 2-add **********************************************************************************************************************/ void PreMultiply(int tabidx, int *zbuf1) { int i, nmdct, ar1, ai1, ar2, ai2, z1, z2; int t, cms2, cps2a, sin2a, cps2b, sin2b; int *zbuf2; const uint32_t *csptr; nmdct = nmdctTab[tabidx]; zbuf2 = zbuf1 + nmdct - 1; csptr = cos4sin4tab + cos4sin4tabOffset[tabidx]; /* whole thing should fit in registers - verify that compiler does this */ for (i = nmdct >> 2; i != 0; i--) { /* cps2 = (cos+sin), sin2 = sin, cms2 = (cos-sin) */ cps2a = *csptr++; sin2a = *csptr++; cps2b = *csptr++; sin2b = *csptr++; ar1 = *(zbuf1 + 0); ai2 = *(zbuf1 + 1); ai1 = *(zbuf2 + 0); ar2 = *(zbuf2 - 1); /* gain 2 ints bit from MULSHIFT32 by Q30, but drop 7 or 10 int bits from table scaling of 1/M * max per-sample gain (ignoring implicit scaling) = MAX(sin(angle)+cos(angle)) = 1.414 * i.e. gain 1 GB since worst case is sin(angle) = cos(angle) = 0.707 (Q30), gain 2 from * extra sign bits, and eat one in adding */ t = MULSHIFT32(sin2a, ar1 + ai1); z2 = MULSHIFT32(cps2a, ai1) - t; cms2 = cps2a - 2*sin2a; z1 = MULSHIFT32(cms2, ar1) + t; *zbuf1++ = z1; /* cos*ar1 + sin*ai1 */ *zbuf1++ = z2; /* cos*ai1 - sin*ar1 */ t = MULSHIFT32(sin2b, ar2 + ai2); z2 = MULSHIFT32(cps2b, ai2) - t; cms2 = cps2b - 2*sin2b; z1 = MULSHIFT32(cms2, ar2) + t; *zbuf2-- = z2; /* cos*ai2 - sin*ar2 */ *zbuf2-- = z1; /* cos*ar2 + sin*ai2 */ } } /*********************************************************************************************************************** * Function: PostMultiply * * Description: post-twiddle stage of DCT4 * * Inputs: table index (for transform size) * buffer of nmdct samples * * Outputs: processed samples in same buffer * * Return: none * * Notes: minimum 1 GB in, 2 GB out - gains 2 int bits * uses 3-mul, 3-add butterflies instead of 4-mul, 2-add **********************************************************************************************************************/ void PostMultiply(int tabidx, int *fft1) { int i, nmdct, ar1, ai1, ar2, ai2, skipFactor; int t, cms2, cps2, sin2; int *fft2; const int *csptr; nmdct = nmdctTab[tabidx]; csptr = cos1sin1tab; skipFactor = postSkip[tabidx]; fft2 = fft1 + nmdct - 1; /* load coeffs for first pass * cps2 = (cos+sin), sin2 = sin, cms2 = (cos-sin) */ cps2 = *csptr++; sin2 = *csptr; csptr += skipFactor; cms2 = cps2 - 2*sin2; for (i = nmdct >> 2; i != 0; i--) { ar1 = *(fft1 + 0); ai1 = *(fft1 + 1); ar2 = *(fft2 - 1); ai2 = *(fft2 + 0); /* gain 2 ints bit from MULSHIFT32 by Q30 * max per-sample gain = MAX(sin(angle)+cos(angle)) = 1.414 * i.e. gain 1 GB since worst case is sin(angle) = cos(angle) = 0.707 (Q30), gain 2 from * extra sign bits, and eat one in adding */ t = MULSHIFT32(sin2, ar1 + ai1); *fft2-- = t - MULSHIFT32(cps2, ai1); /* sin*ar1 - cos*ai1 */ *fft1++ = t + MULSHIFT32(cms2, ar1); /* cos*ar1 + sin*ai1 */ cps2 = *csptr++; sin2 = *csptr; csptr += skipFactor; ai2 = -ai2; t = MULSHIFT32(sin2, ar2 + ai2); *fft2-- = t - MULSHIFT32(cps2, ai2); /* sin*ar1 - cos*ai1 */ cms2 = cps2 - 2*sin2; *fft1++ = t + MULSHIFT32(cms2, ar2); /* cos*ar1 + sin*ai1 */ } } /*********************************************************************************************************************** * Function: PreMultiplyRescale * * Description: pre-twiddle stage of DCT4, with rescaling for extra guard bits * * Inputs: table index (for transform size) * buffer of nmdct samples * number of guard bits to add to input before processing * * Outputs: processed samples in same buffer * * Return: none * * Notes: see notes on PreMultiply(), above **********************************************************************************************************************/ void PreMultiplyRescale(int tabidx, int *zbuf1, int es) { int i, nmdct, ar1, ai1, ar2, ai2, z1, z2; int t, cms2, cps2a, sin2a, cps2b, sin2b; int *zbuf2; const uint32_t *csptr; nmdct = nmdctTab[tabidx]; zbuf2 = zbuf1 + nmdct - 1; csptr = cos4sin4tab + cos4sin4tabOffset[tabidx]; /* whole thing should fit in registers - verify that compiler does this */ for (i = nmdct >> 2; i != 0; i--) { /* cps2 = (cos+sin), sin2 = sin, cms2 = (cos-sin) */ cps2a = *csptr++; sin2a = *csptr++; cps2b = *csptr++; sin2b = *csptr++; ar1 = *(zbuf1 + 0) >> es; ai1 = *(zbuf2 + 0) >> es; ai2 = *(zbuf1 + 1) >> es; t = MULSHIFT32(sin2a, ar1 + ai1); z2 = MULSHIFT32(cps2a, ai1) - t; cms2 = cps2a - 2*sin2a; z1 = MULSHIFT32(cms2, ar1) + t; *zbuf1++ = z1; *zbuf1++ = z2; ar2 = *(zbuf2 - 1) >> es; /* do here to free up register used for es */ t = MULSHIFT32(sin2b, ar2 + ai2); z2 = MULSHIFT32(cps2b, ai2) - t; cms2 = cps2b - 2*sin2b; z1 = MULSHIFT32(cms2, ar2) + t; *zbuf2-- = z2; *zbuf2-- = z1; } } /*********************************************************************************************************************** * Function: PostMultiplyRescale * * Description: post-twiddle stage of DCT4, with rescaling for extra guard bits * * Inputs: table index (for transform size) * buffer of nmdct samples * number of guard bits to remove from output * * Outputs: processed samples in same buffer * * Return: none * * Notes: clips output to [-2^30, 2^30 - 1], guaranteeing at least 1 guard bit * see notes on PostMultiply(), above **********************************************************************************************************************/ void PostMultiplyRescale(int tabidx, int *fft1, int es) { int i, nmdct, ar1, ai1, ar2, ai2, skipFactor, z; int t, cs2, sin2; int *fft2; const int *csptr; nmdct = nmdctTab[tabidx]; csptr = cos1sin1tab; skipFactor = postSkip[tabidx]; fft2 = fft1 + nmdct - 1; /* load coeffs for first pass * cps2 = (cos+sin), sin2 = sin, cms2 = (cos-sin) */ cs2 = *csptr++; sin2 = *csptr; csptr += skipFactor; for (i = nmdct >> 2; i != 0; i--) { ar1 = *(fft1 + 0); ai1 = *(fft1 + 1); ai2 = *(fft2 + 0); t = MULSHIFT32(sin2, ar1 + ai1); z = t - MULSHIFT32(cs2, ai1); {int sign = (z) >> 31; if (sign != (z) >> (30 - (es))) {(z) = sign ^ (0x3fffffff);} else {(z) = (z) << (es);}} *fft2-- = z; cs2 -= 2*sin2; z = t + MULSHIFT32(cs2, ar1); {int sign = (z) >> 31; if (sign != (z) >> (30 - (es))) {(z) = sign ^ (0x3fffffff);} else {(z) = (z) << (es);}} *fft1++ = z; cs2 = *csptr++; sin2 = *csptr; csptr += skipFactor; ar2 = *fft2; ai2 = -ai2; t = MULSHIFT32(sin2, ar2 + ai2); z = t - MULSHIFT32(cs2, ai2); {int sign = (z) >> 31; if (sign != (z) >> (30 - (es))) {(z) = sign ^ (0x3fffffff);} else {(z) = (z) << (es);}} *fft2-- = z; cs2 -= 2*sin2; z = t + MULSHIFT32(cs2, ar2); {int sign = (z) >> 31; if (sign != (z) >> (30 - (es))) {(z) = sign ^ (0x3fffffff);} else {(z) = (z) << (es);}} *fft1++ = z; cs2 += 2*sin2; } } /*********************************************************************************************************************** * Function: DCT4 * * Description: type-IV DCT * * Inputs: table index (for transform size) * buffer of nmdct samples * number of guard bits in the input buffer * * Outputs: processed samples in same buffer * * Return: none * * Notes: operates in-place * if number of guard bits in input is < GBITS_IN_DCT4, the input is * scaled (>>) before the DCT4 and rescaled (<<, with clipping) after * the DCT4 (rare) * the output has FBITS_LOST_DCT4 fewer fraction bits than the input * the output will always have at least 1 guard bit (GBITS_IN_DCT4 >= 4) * int bits gained per stage (PreMul + FFT + PostMul) * short blocks = (-5 + 4 + 2) = 1 total * long blocks = (-8 + 7 + 2) = 1 total **********************************************************************************************************************/ void DCT4(int tabidx, int *coef, int gb) { int es; /* fast in-place DCT-IV - adds guard bits if necessary */ if (gb < GBITS_IN_DCT4) { es = GBITS_IN_DCT4 - gb; PreMultiplyRescale(tabidx, coef, es); R4FFT(tabidx, coef); PostMultiplyRescale(tabidx, coef, es); } else { PreMultiply(tabidx, coef); R4FFT(tabidx, coef); PostMultiply(tabidx, coef); } } /*********************************************************************************************************************** * Function: BitReverse * * Description: Ken's fast in-place bit reverse, using super-small table * * Inputs: buffer of samples * table index (for transform size) * * Outputs: bit-reversed samples in same buffer * * Return: none **********************************************************************************************************************/ void BitReverse(int *inout, int tabidx) { int *part0, *part1; int a,b, t; const uint8_t* tab = bitrevtab + bitrevtabOffset[tabidx]; int nbits = nfftlog2Tab[tabidx]; part0 = inout; part1 = inout + (1 << nbits); while ((a = pgm_read_byte(tab++)) != 0) { b = pgm_read_byte(tab++); t=part0[4*a+0]; part0[4*a+0]=part0[4*b+0]; part0[4*b+0]=t; /* 0xxx0 <-> 0yyy0 */ t=part0[4*a+1]; part0[4*a+1]=part0[4*b+1]; part0[4*b+1]=t; t=part0[4*a+2]; part0[4*a+2]=part1[4*b+0]; part1[4*b+0]=t; /* 0xxx0 <-> 0yyy0 */ t=part0[4*a+3]; part0[4*a+3]=part1[4*b+1]; part1[4*b+1]=t; t=part1[4*a+0]; part1[4*a+0]=part0[4*b+2]; part0[4*b+2]=t; /* 1xxx0 <-> 0yyy1 */ t=part1[4*a+1]; part1[4*a+1]=part0[4*b+3]; part0[4*b+3]=t; t=part1[4*a+2]; part1[4*a+2]=part1[4*b+2]; part1[4*b+2]=t; /* 1xxx1 <-> 1yyy1 */ t=part1[4*a+3]; part1[4*a+3]=part1[4*b+3]; part1[4*b+3]=t; } do { t=part0[4*a+2]; part0[4*a+2]=part1[4*a+0]; part1[4*a+0]=t; /* 0xxx1 <-> 1xxx0 */ t=part0[4*a+3]; part0[4*a+3]=part1[4*a+1]; part1[4*a+1]=t; } while ((a = pgm_read_byte(tab++)) != 0); } /*********************************************************************************************************************** * Function: R4FirstPass * * Description: radix-4 trivial pass for decimation-in-time FFT * * Inputs: buffer of (bit-reversed) samples * number of R4 butterflies per group (i.e. nfft / 4) * * Outputs: processed samples in same buffer * * Return: none * * Notes: assumes 2 guard bits, gains no integer bits, * guard bits out = guard bits in - 2 **********************************************************************************************************************/ void R4FirstPass(int *x, int bg) { int ar, ai, br, bi, cr, ci, dr, di; for (; bg != 0; bg--) { ar = x[0] + x[2]; br = x[0] - x[2]; ai = x[1] + x[3]; bi = x[1] - x[3]; cr = x[4] + x[6]; dr = x[4] - x[6]; ci = x[5] + x[7]; di = x[5] - x[7]; /* max per-sample gain = 4.0 (adding 4 inputs together) */ x[0] = ar + cr; x[4] = ar - cr; x[1] = ai + ci; x[5] = ai - ci; x[2] = br + di; x[6] = br - di; x[3] = bi - dr; x[7] = bi + dr; x += 8; } } /*********************************************************************************************************************** * Function: R8FirstPass * * Description: radix-8 trivial pass for decimation-in-time FFT * * Inputs: buffer of (bit-reversed) samples * number of R8 butterflies per group (i.e. nfft / 8) * * Outputs: processed samples in same buffer * * Return: none * * Notes: assumes 3 guard bits, gains 1 integer bit * guard bits out = guard bits in - 3 (if inputs are full scale) * or guard bits in - 2 (if inputs bounded to +/- sqrt(2)/2) * see scaling comments in code **********************************************************************************************************************/ void R8FirstPass(int *x, int bg) { int ar, ai, br, bi, cr, ci, dr, di; int sr, si, tr, ti, ur, ui, vr, vi; int wr, wi, xr, xi, yr, yi, zr, zi; for (; bg != 0; bg--) { ar = x[0] + x[2]; br = x[0] - x[2]; ai = x[1] + x[3]; bi = x[1] - x[3]; cr = x[4] + x[6]; dr = x[4] - x[6]; ci = x[5] + x[7]; di = x[5] - x[7]; sr = ar + cr; ur = ar - cr; si = ai + ci; ui = ai - ci; tr = br - di; vr = br + di; ti = bi + dr; vi = bi - dr; ar = x[ 8] + x[10]; br = x[ 8] - x[10]; ai = x[ 9] + x[11]; bi = x[ 9] - x[11]; cr = x[12] + x[14]; dr = x[12] - x[14]; ci = x[13] + x[15]; di = x[13] - x[15]; /* max gain of wr/wi/yr/yi vs input = 2 * (sum of 4 samples >> 1) */ wr = (ar + cr) >> 1; yr = (ar - cr) >> 1; wi = (ai + ci) >> 1; yi = (ai - ci) >> 1; /* max gain of output vs input = 4 * (sum of 4 samples >> 1 + sum of 4 samples >> 1) */ x[ 0] = (sr >> 1) + wr; x[ 8] = (sr >> 1) - wr; x[ 1] = (si >> 1) + wi; x[ 9] = (si >> 1) - wi; x[ 4] = (ur >> 1) + yi; x[12] = (ur >> 1) - yi; x[ 5] = (ui >> 1) - yr; x[13] = (ui >> 1) + yr; ar = br - di; cr = br + di; ai = bi + dr; ci = bi - dr; /* max gain of xr/xi/zr/zi vs input = 4*sqrt(2)/2 = 2*sqrt(2) * (sum of 8 samples, multiply by sqrt(2)/2, implicit >> 1 from Q31) */ xr = MULSHIFT32(SQRTHALF, ar - ai); xi = MULSHIFT32(SQRTHALF, ar + ai); zr = MULSHIFT32(SQRTHALF, cr - ci); zi = MULSHIFT32(SQRTHALF, cr + ci); /* max gain of output vs input = (2 + 2*sqrt(2) ~= 4.83) * (sum of 4 samples >> 1, plus xr/xi/zr/zi with gain of 2*sqrt(2)) * in absolute terms, we have max gain of appx 9.656 (4 + 0.707*8) * but we also gain 1 int bit (from MULSHIFT32 or from explicit >> 1) */ x[ 6] = (tr >> 1) - xr; x[14] = (tr >> 1) + xr; x[ 7] = (ti >> 1) - xi; x[15] = (ti >> 1) + xi; x[ 2] = (vr >> 1) + zi; x[10] = (vr >> 1) - zi; x[ 3] = (vi >> 1) - zr; x[11] = (vi >> 1) + zr; x += 16; } } /*********************************************************************************************************************** * Function: R4Core * * Description: radix-4 pass for decimation-in-time FFT * * Inputs: buffer of samples * number of R4 butterflies per group * number of R4 groups per pass * pointer to twiddle factors tables * * Outputs: processed samples in same buffer * * Return: none * * Notes: gain 2 integer bits per pass (see scaling comments in code) * min 1 GB in * gbOut = gbIn - 1 (short block) or gbIn - 2 (long block) * uses 3-mul, 3-add butterflies instead of 4-mul, 2-add **********************************************************************************************************************/ void R4Core(int *x, int bg, int gp, int *wtab) { int ar, ai, br, bi, cr, ci, dr, di, tr, ti; int wd, ws, wi; int i, j, step; int *xptr, *wptr; for (; bg != 0; gp <<= 2, bg >>= 2) { step = 2*gp; xptr = x; /* max per-sample gain, per group < 1 + 3*sqrt(2) ~= 5.25 if inputs x are full-scale * do 3 groups for long block, 2 groups for short block (gain 2 int bits per group) * * very conservative scaling: * group 1: max gain = 5.25, int bits gained = 2, gb used = 1 (2^3 = 8) * group 2: max gain = 5.25^2 = 27.6, int bits gained = 4, gb used = 1 (2^5 = 32) * group 3: max gain = 5.25^3 = 144.7, int bits gained = 6, gb used = 2 (2^8 = 256) */ for (i = bg; i != 0; i--) { wptr = wtab; for (j = gp; j != 0; j--) { ar = xptr[0]; ai = xptr[1]; xptr += step; /* gain 2 int bits for br/bi, cr/ci, dr/di (MULSHIFT32 by Q30) * gain 1 net GB */ ws = wptr[0]; wi = wptr[1]; br = xptr[0]; bi = xptr[1]; wd = ws + 2*wi; tr = MULSHIFT32(wi, br + bi); br = MULSHIFT32(wd, br) - tr; /* cos*br + sin*bi */ bi = MULSHIFT32(ws, bi) + tr; /* cos*bi - sin*br */ xptr += step; ws = wptr[2]; wi = wptr[3]; cr = xptr[0]; ci = xptr[1]; wd = ws + 2*wi; tr = MULSHIFT32(wi, cr + ci); cr = MULSHIFT32(wd, cr) - tr; ci = MULSHIFT32(ws, ci) + tr; xptr += step; ws = wptr[4]; wi = wptr[5]; dr = xptr[0]; di = xptr[1]; wd = ws + 2*wi; tr = MULSHIFT32(wi, dr + di); dr = MULSHIFT32(wd, dr) - tr; di = MULSHIFT32(ws, di) + tr; wptr += 6; tr = ar; ti = ai; ar = (tr >> 2) - br; ai = (ti >> 2) - bi; br = (tr >> 2) + br; bi = (ti >> 2) + bi; tr = cr; ti = ci; cr = tr + dr; ci = di - ti; dr = tr - dr; di = di + ti; xptr[0] = ar + ci; xptr[1] = ai + dr; xptr -= step; xptr[0] = br - cr; xptr[1] = bi - di; xptr -= step; xptr[0] = ar - ci; xptr[1] = ai - dr; xptr -= step; xptr[0] = br + cr; xptr[1] = bi + di; xptr += 2; } xptr += 3*step; } wtab += 3*step; } } /*********************************************************************************************************************** * Function: R4FFT * * Description: Ken's very fast in-place radix-4 decimation-in-time FFT * * Inputs: table index (for transform size) * buffer of samples (non bit-reversed) * * Outputs: processed samples in same buffer * * Return: none * * Notes: assumes 5 guard bits in for nfft <= 512 * gbOut = gbIn - 4 (assuming input is from PreMultiply) * gains log2(nfft) - 2 int bits total * so gain 7 int bits (LONG), 4 int bits (SHORT) **********************************************************************************************************************/ void R4FFT(int tabidx, int *x) { int order = nfftlog2Tab[tabidx]; int nfft = nfftTab[tabidx]; /* decimation in time */ BitReverse(x, tabidx); if (order & 0x1) { /* long block: order = 9, nfft = 512 */ R8FirstPass(x, nfft >> 3); /* gain 1 int bit, lose 2 GB */ R4Core(x, nfft >> 5, 8, (int *)twidTabOdd); /* gain 6 int bits, lose 2 GB */ } else { /* short block: order = 6, nfft = 64 */ R4FirstPass(x, nfft >> 2); /* gain 0 int bits, lose 2 GB */ R4Core(x, nfft >> 4, 4, (int *)twidTabEven); /* gain 4 int bits, lose 1 GB */ } } /*********************************************************************************************************************** * Function: UnpackZeros * * Description: fill a section of coefficients with zeros * * Inputs: number of coefficients * * Outputs: nVals zeros, starting at coef * * Return: none * * Notes: assumes nVals is always a multiple of 4 because all scalefactor bands * are a multiple of 4 coefficients long **********************************************************************************************************************/ void UnpackZeros(int nVals, int *coef) { while (nVals > 0) { *coef++ = 0; *coef++ = 0; *coef++ = 0; *coef++ = 0; nVals -= 4; } } /*********************************************************************************************************************** * Function: UnpackQuads * * Description: decode a section of 4-way vector Huffman coded coefficients * * Inputs index of Huffman codebook * number of coefficients * * Outputs: nVals coefficients, starting at coef * * Return: none * * Notes: assumes nVals is always a multiple of 4 because all scalefactor bands * are a multiple of 4 coefficients long **********************************************************************************************************************/ void UnpackQuads(int cb, int nVals, int *coef) { int w, x, y, z, maxBits, nCodeBits, nSignBits, val; uint32_t bitBuf; maxBits = huffTabSpecInfo[cb - HUFFTAB_SPEC_OFFSET].maxBits + 4; while (nVals > 0) { /* decode quad */ bitBuf = GetBitsNoAdvance(maxBits) << (32 - maxBits); nCodeBits = DecodeHuffmanScalar(huffTabSpec, &huffTabSpecInfo[cb - HUFFTAB_SPEC_OFFSET], bitBuf, &val); w = (((int32_t)(val) << 20) >> 29); /* bits 11-9, sign-extend */ x = (((int32_t)(val) << 23) >> 29); /* bits 8-6, sign-extend */ y = (((int32_t)(val) << 26) >> 29); /* bits 5-3, sign-extend */ z = (((int32_t)(val) << 29) >> 29); /* bits 2-0, sign-extend */ bitBuf <<= nCodeBits; nSignBits = (int)(((uint32_t)(val) << 17) >> 29); /* bits 14-12, unsigned */ AdvanceBitstream(nCodeBits + nSignBits); if (nSignBits) { if (w) {w ^= ((int32_t)bitBuf >> 31); w -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} if (x) {x ^= ((int32_t)bitBuf >> 31); x -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} if (y) {y ^= ((int32_t)bitBuf >> 31); y -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} if (z) {z ^= ((int32_t)bitBuf >> 31); z -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} } *coef++ = w; *coef++ = x; *coef++ = y; *coef++ = z; nVals -= 4; } } /*********************************************************************************************************************** * Function: UnpackPairsNoEsc * * Description: decode a section of 2-way vector Huffman coded coefficients, * using non-esc tables (5 through 10) * * Inputs index of Huffman codebook (must not be the escape codebook) * number of coefficients * * Outputs: nVals coefficients, starting at coef * * Return: none * * Notes: assumes nVals is always a multiple of 2 because all scalefactor bands * are a multiple of 4 coefficients long **********************************************************************************************************************/ void UnpackPairsNoEsc(int cb, int nVals, int *coef) { int y, z, maxBits, nCodeBits, nSignBits, val; uint32_t bitBuf; maxBits = huffTabSpecInfo[cb - HUFFTAB_SPEC_OFFSET].maxBits + 2; while (nVals > 0) { /* decode pair */ bitBuf = GetBitsNoAdvance(maxBits) << (32 - maxBits); nCodeBits = DecodeHuffmanScalar(huffTabSpec, &huffTabSpecInfo[cb-HUFFTAB_SPEC_OFFSET], bitBuf, &val); y = (((int32_t)(val) << 22) >> 27); /* bits 9-5, sign-extend */ z = (((int32_t)(val) << 27) >> 27); /* bits 4-0, sign-extend */ bitBuf <<= nCodeBits; nSignBits = (((uint32_t)(val) << 20) >> 30); /* bits 11-10, unsigned */ AdvanceBitstream(nCodeBits + nSignBits); if (nSignBits) { if (y) {y ^= ((int32_t)bitBuf >> 31); y -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} if (z) {z ^= ((int32_t)bitBuf >> 31); z -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} } *coef++ = y; *coef++ = z; nVals -= 2; } } /*********************************************************************************************************************** * Function: UnpackPairsEsc * * Description: decode a section of 2-way vector Huffman coded coefficients, * using esc table (11) * * Inputs index of Huffman codebook (must be the escape codebook) * number of coefficients * * Outputs: nVals coefficients, starting at coef * * Return: none * * Notes: assumes nVals is always a multiple of 2 because all scalefactor bands * are a multiple of 4 coefficients long **********************************************************************************************************************/ void UnpackPairsEsc(int cb, int nVals, int *coef) { int y, z, maxBits, nCodeBits, nSignBits, n, val; uint32_t bitBuf; maxBits = huffTabSpecInfo[cb - HUFFTAB_SPEC_OFFSET].maxBits + 2; while (nVals > 0) { /* decode pair with escape value */ bitBuf = GetBitsNoAdvance(maxBits) << (32 - maxBits); nCodeBits = DecodeHuffmanScalar(huffTabSpec, &huffTabSpecInfo[cb-HUFFTAB_SPEC_OFFSET], bitBuf, &val); y = (((int32_t)(val) << 20) >> 26); /* bits 11-6, sign-extend */ z = (((int32_t)(val) << 26) >> 26); /* bits 5-0, sign-extend */ bitBuf <<= nCodeBits; nSignBits = (((uint32_t)(val) << 18) >> 30); /* bits 13-12, unsigned */ AdvanceBitstream(nCodeBits + nSignBits); if (y == 16) { n = 4; while (GetBits(1) == 1) n++; y = (1 << n) + GetBits(n); } if (z == 16) { n = 4; while (GetBits(1) == 1) n++; z = (1 << n) + GetBits(n); } if (nSignBits) { if (y) {y ^= ((int32_t)bitBuf >> 31); y -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} if (z) {z ^= ((int32_t)bitBuf >> 31); z -= ((int32_t)bitBuf >> 31); bitBuf <<= 1;} } *coef++ = y; *coef++ = z; nVals -= 2; } } /*********************************************************************************************************************** * Function: DecodeSpectrumLong * * Description: decode transform coefficients for frame with one long block * * Inputs: index of current channel * * Outputs: decoded, quantized coefficients for this channel * * Return: none * * Notes: adds in pulse data if present * fills coefficient buffer with zeros in any region not coded with * codebook in range [1, 11] (including sfb's above sfbMax) **********************************************************************************************************************/ void DecodeSpectrumLong(int ch) { int i, sfb, cb, nVals, offset; const uint16_t *sfbTab; uint8_t *sfbCodeBook; int *coef; ICSInfo_t *icsInfo; coef = m_PSInfoBase->coef[ch]; icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); /* decode long block */ sfbTab = sfBandTabLong + sfBandTabLongOffset[m_PSInfoBase->sampRateIdx]; sfbCodeBook = m_PSInfoBase->sfbCodeBook[ch]; for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) { cb = *sfbCodeBook++; nVals = sfbTab[sfb+1] - sfbTab[sfb]; if (cb == 0) UnpackZeros(nVals, coef); else if (cb <= 4) UnpackQuads(cb, nVals, coef); else if (cb <= 10) UnpackPairsNoEsc(cb, nVals, coef); else if (cb == 11) UnpackPairsEsc(cb, nVals, coef); else UnpackZeros(nVals, coef); coef += nVals; } /* fill with zeros above maxSFB */ nVals = NSAMPS_LONG - sfbTab[sfb]; UnpackZeros(nVals, coef); /* add pulse data, if present */ if (m_pulseInfo[ch].pulseDataPresent) { coef = m_PSInfoBase->coef[ch]; offset = sfbTab[m_pulseInfo[ch].startSFB]; for (i = 0; i < m_pulseInfo[ch].numPulse; i++) { offset += m_pulseInfo[ch].offset[i]; if (coef[offset] > 0) coef[offset] += m_pulseInfo[ch].amp[i]; else coef[offset] -= m_pulseInfo[ch].amp[i]; } ASSERT(offset < NSAMPS_LONG); } } /*********************************************************************************************************************** * Function: DecodeSpectrumShort * * Description: decode transform coefficients for frame with eight short blocks * * Inputs: index of current channel * * Outputs: decoded, quantized coefficients for this channel * * Return: none * * Notes: fills coefficient buffer with zeros in any region not coded with * codebook in range [1, 11] (including sfb's above sfbMax) * deinterleaves window groups into 8 windows **********************************************************************************************************************/ void DecodeSpectrumShort(int ch) { int gp, cb, nVals=0, win, offset, sfb; const uint16_t *sfbTab; uint8_t *sfbCodeBook; int *coef; ICSInfo_t *icsInfo; coef = m_PSInfoBase->coef[ch]; icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); /* decode short blocks, deinterleaving in-place */ sfbTab = sfBandTabShort + sfBandTabShortOffset[m_PSInfoBase->sampRateIdx]; sfbCodeBook = m_PSInfoBase->sfbCodeBook[ch]; for (gp = 0; gp < icsInfo->numWinGroup; gp++) { for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) { nVals = sfbTab[sfb+1] - sfbTab[sfb]; cb = *sfbCodeBook++; for (win = 0; win < icsInfo->winGroupLen[gp]; win++) { offset = win*NSAMPS_SHORT; if (cb == 0) UnpackZeros(nVals, coef + offset); else if (cb <= 4) UnpackQuads(cb, nVals, coef + offset); else if (cb <= 10) UnpackPairsNoEsc(cb, nVals, coef + offset); else if (cb == 11) UnpackPairsEsc(cb, nVals, coef + offset); else UnpackZeros(nVals, coef + offset); } coef += nVals; } /* fill with zeros above maxSFB */ for (win = 0; win < icsInfo->winGroupLen[gp]; win++) { offset = win*NSAMPS_SHORT; nVals = NSAMPS_SHORT - sfbTab[sfb]; UnpackZeros(nVals, coef + offset); } coef += nVals; coef += (icsInfo->winGroupLen[gp] - 1)*NSAMPS_SHORT; } ASSERT(coef == m_PSInfoBase->coef[ch] + NSAMPS_LONG); } #ifndef AAC_ENABLE_SBR /*********************************************************************************************************************** * Function: DecWindowOverlap * * Description: apply synthesis window, do overlap-add, clip to 16-bit PCM, * for winSequence LONG-LONG * * Inputs: input buffer (output of type-IV DCT) * overlap buffer (saved from last time) * number of channels * window type (sin or KBD) for input buffer * window type (sin or KBD) for overlap buffer * * Outputs: one channel, one frame of 16-bit PCM, interleaved by nChans * * Return: none * * Notes: this processes one channel at a time, but skips every other sample in * the output buffer (pcm) for stereo interleaving * this should fit in registers on ARM * **********************************************************************************************************************/ void DecWindowOverlap(int *buf0, int *over0, short *pcm0, int nChans, int winTypeCurr, int winTypePrev) { int in, w0, w1, f0, f1; int *buf1, *over1; short *pcm1; const int *wndCurr, *wndPrev; buf0 += (1024 >> 1); buf1 = buf0 - 1; pcm1 = pcm0 + (1024 - 1) * nChans; over1 = over0 + 1024 - 1; wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); if (winTypeCurr == winTypePrev) { /* cut window loads in half since current and overlap sections use same symmetric window */ do { w0 = *wndPrev++; w1 = *wndPrev++; in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *over0; *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm0 += nChans; in = *over1; *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm1 -= nChans; in = *buf1--; *over1-- = MULSHIFT32(w0, in); *over0++ = MULSHIFT32(w1, in); } while (over0 < over1); } else { /* different windows for current and overlap parts - should still fit in registers on ARM w/o stack spill */ wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); do { w0 = *wndPrev++; w1 = *wndPrev++; in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *over0; *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm0 += nChans; in = *over1; *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm1 -= nChans; w0 = *wndCurr++; w1 = *wndCurr++; in = *buf1--; *over1-- = MULSHIFT32(w0, in); *over0++ = MULSHIFT32(w1, in); } while (over0 < over1); } } /*********************************************************************************************************************** * Function: DecWindowOverlapLongStart * * Description: apply synthesis window, do overlap-add, clip to 16-bit PCM, * for winSequence LONG-START * * Inputs: input buffer (output of type-IV DCT) * overlap buffer (saved from last time) * number of channels * window type (sin or KBD) for input buffer * window type (sin or KBD) for overlap buffer * * Outputs: one channel, one frame of 16-bit PCM, interleaved by nChans * * Return: none * * Notes: this processes one channel at a time, but skips every other sample in * the output buffer (pcm) for stereo interleaving * this should fit in registers on ARM **********************************************************************************************************************/ void DecWindowOverlapLongStart(int *buf0, int *over0, short *pcm0, int nChans, int winTypeCurr, int winTypePrev) { int i, in, w0, w1, f0, f1; int *buf1, *over1; short *pcm1; const int *wndPrev, *wndCurr; buf0 += (1024 >> 1); buf1 = buf0 - 1; pcm1 = pcm0 + (1024 - 1) * nChans; over1 = over0 + 1024 - 1; wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); i = 448; /* 2 outputs, 2 overlaps per loop */ do { w0 = *wndPrev++; w1 = *wndPrev++; in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *over0; *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm0 += nChans; in = *over1; *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm1 -= nChans; in = *buf1--; *over1-- = 0; /* Wn = 0 for n = (2047, 2046, ... 1600) */ *over0++ = in >> 1; /* Wn = 1 for n = (1024, 1025, ... 1471) */ } while (--i); wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); /* do 64 more loops - 2 outputs, 2 overlaps per loop */ do { w0 = *wndPrev++; w1 = *wndPrev++; in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *over0; *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm0 += nChans; in = *over1; *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm1 -= nChans; w0 = *wndCurr++; /* W[0], W[1], ... --> W[255], W[254], ... */ w1 = *wndCurr++; /* W[127], W[126], ... --> W[128], W[129], ... */ in = *buf1--; *over1-- = MULSHIFT32(w0, in); /* Wn = short window for n = (1599, 1598, ... , 1536) */ *over0++ = MULSHIFT32(w1, in); /* Wn = short window for n = (1472, 1473, ... , 1535) */ } while (over0 < over1); } /*********************************************************************************************************************** * Function: DecWindowOverlapLongStop * * Description: apply synthesis window, do overlap-add, clip to 16-bit PCM, * for winSequence LONG-STOP * * Inputs: input buffer (output of type-IV DCT) * overlap buffer (saved from last time) * number of channels * window type (sin or KBD) for input buffer * window type (sin or KBD) for overlap buffer * * Outputs: one channel, one frame of 16-bit PCM, interleaved by nChans * * Return: none * * Notes: this processes one channel at a time, but skips every other sample in * the output buffer (pcm) for stereo interleaving * this should fit in registers on ARM **********************************************************************************************************************/ void DecWindowOverlapLongStop(int *buf0, int *over0, short *pcm0, int nChans, int winTypeCurr, int winTypePrev) { int i, in, w0, w1, f0, f1; int *buf1, *over1; short *pcm1; const int *wndPrev, *wndCurr; buf0 += (1024 >> 1); buf1 = buf0 - 1; pcm1 = pcm0 + (1024 - 1) * nChans; over1 = over0 + 1024 - 1; wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); i = 448; /* 2 outputs, 2 overlaps per loop */ do { /* Wn = 0 for n = (0, 1, ... 447) */ /* Wn = 1 for n = (576, 577, ... 1023) */ in = *buf0++; f1 = in >> 1; /* scale since skipping multiply by Q31 */ in = *over0; *pcm0 = CLIPTOSHORT( (in + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm0 += nChans; in = *over1; *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm1 -= nChans; w0 = *wndCurr++; w1 = *wndCurr++; in = *buf1--; *over1-- = MULSHIFT32(w0, in); *over0++ = MULSHIFT32(w1, in); } while (--i); /* do 64 more loops - 2 outputs, 2 overlaps per loop */ do { w0 = *wndPrev++; /* W[0], W[1], ...W[63] */ w1 = *wndPrev++; /* W[127], W[126], ... W[64] */ in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *over0; *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm0 += nChans; in = *over1; *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm1 -= nChans; w0 = *wndCurr++; w1 = *wndCurr++; in = *buf1--; *over1-- = MULSHIFT32(w0, in); *over0++ = MULSHIFT32(w1, in); } while (over0 < over1); } /*********************************************************************************************************************** * Function: DecWindowOverlapShort * * Description: apply synthesis window, do overlap-add, clip to 16-bit PCM, * for winSequence EIGHT-SHORT (does all 8 short blocks) * * Inputs: input buffer (output of type-IV DCT) * overlap buffer (saved from last time) * number of channels * window type (sin or KBD) for input buffer * window type (sin or KBD) for overlap buffer * * Outputs: one channel, one frame of 16-bit PCM, interleaved by nChans * * Return: none * * Notes: this processes one channel at a time, but skips every other sample in * the output buffer (pcm) for stereo interleaving * this should fit in registers on ARM **********************************************************************************************************************/ void DecWindowOverlapShort(int *buf0, int *over0, short *pcm0, int nChans, int winTypeCurr, int winTypePrev) { int i, in, w0, w1, f0, f1; int *buf1, *over1; short *pcm1; const int *wndPrev, *wndCurr; wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); /* pcm[0-447] = 0 + overlap[0-447] */ i = 448; do { f0 = *over0++; f1 = *over0++; *pcm0 = CLIPTOSHORT( (f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm0 += nChans; *pcm0 = CLIPTOSHORT( (f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm0 += nChans; i -= 2; } while (i); /* pcm[448-575] = Wp[0-127] * block0[0-127] + overlap[448-575] */ pcm1 = pcm0 + (128 - 1) * nChans; over1 = over0 + 128 - 1; buf0 += 64; buf1 = buf0 - 1; do { w0 = *wndPrev++; /* W[0], W[1], ...W[63] */ w1 = *wndPrev++; /* W[127], W[126], ... W[64] */ in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *over0; *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm0 += nChans; in = *over1; *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm1 -= nChans; w0 = *wndCurr++; w1 = *wndCurr++; in = *buf1--; /* save over0/over1 for next short block, in the slots just vacated */ *over1-- = MULSHIFT32(w0, in); *over0++ = MULSHIFT32(w1, in); } while (over0 < over1); /* pcm[576-703] = Wc[128-255] * block0[128-255] + Wc[0-127] * block1[0-127] + overlap[576-703] * pcm[704-831] = Wc[128-255] * block1[128-255] + Wc[0-127] * block2[0-127] + overlap[704-831] * pcm[832-959] = Wc[128-255] * block2[128-255] + Wc[0-127] * block3[0-127] + overlap[832-959] */ for (i = 0; i < 3; i++) { pcm0 += 64 * nChans; pcm1 = pcm0 + (128 - 1) * nChans; over0 += 64; over1 = over0 + 128 - 1; buf0 += 64; buf1 = buf0 - 1; wndCurr -= 128; do { w0 = *wndCurr++; /* W[0], W[1], ...W[63] */ w1 = *wndCurr++; /* W[127], W[126], ... W[64] */ in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *(over0 - 128); /* from last short block */ in += *(over0 + 0); /* from last full frame */ *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm0 += nChans; in = *(over1 - 128); /* from last short block */ in += *(over1 + 0); /* from last full frame */ *pcm1 = CLIPTOSHORT( (in + f1 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm1 -= nChans; /* save over0/over1 for next short block, in the slots just vacated */ in = *buf1--; *over1-- = MULSHIFT32(w0, in); *over0++ = MULSHIFT32(w1, in); } while (over0 < over1); } /* pcm[960-1023] = Wc[128-191] * block3[128-191] + Wc[0-63] * block4[0-63] + overlap[960-1023] * over[0-63] = Wc[192-255] * block3[192-255] + Wc[64-127] * block4[64-127] */ pcm0 += 64 * nChans; over0 -= 832; /* points at overlap[64] */ over1 = over0 + 128 - 1; /* points at overlap[191] */ buf0 += 64; buf1 = buf0 - 1; wndCurr -= 128; do { w0 = *wndCurr++; /* W[0], W[1], ...W[63] */ w1 = *wndCurr++; /* W[127], W[126], ... W[64] */ in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *(over0 + 768); /* from last short block */ in += *(over0 + 896); /* from last full frame */ *pcm0 = CLIPTOSHORT( (in - f0 + (1 << (FBITS_OUT_IMDCT-1))) >> FBITS_OUT_IMDCT ); pcm0 += nChans; in = *(over1 + 768); /* from last short block */ *(over1 - 128) = in + f1; in = *buf1--; *over1-- = MULSHIFT32(w0, in); /* save in overlap[128-191] */ *over0++ = MULSHIFT32(w1, in); /* save in overlap[64-127] */ } while (over0 < over1); /* over0 now points at overlap[128] */ /* over[64-191] = Wc[128-255] * block4[128-255] + Wc[0-127] * block5[0-127] * over[192-319] = Wc[128-255] * block5[128-255] + Wc[0-127] * block6[0-127] * over[320-447] = Wc[128-255] * block6[128-255] + Wc[0-127] * block7[0-127] * over[448-576] = Wc[128-255] * block7[128-255] */ for (i = 0; i < 3; i++) { over0 += 64; over1 = over0 + 128 - 1; buf0 += 64; buf1 = buf0 - 1; wndCurr -= 128; do { w0 = *wndCurr++; /* W[0], W[1], ...W[63] */ w1 = *wndCurr++; /* W[127], W[126], ... W[64] */ in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); /* from last short block */ *(over0 - 128) -= f0; *(over1 - 128)+= f1; in = *buf1--; *over1-- = MULSHIFT32(w0, in); *over0++ = MULSHIFT32(w1, in); } while (over0 < over1); } /* over[576-1024] = 0 */ i = 448; over0 += 64; do { *over0++ = 0; *over0++ = 0; *over0++ = 0; *over0++ = 0; i -= 4; } while (i); } #endif /* !AAC_ENABLE_SBR */ /*********************************************************************************************************************** * Function: IMDCT * * Description: inverse transform and convert to 16-bit PCM * * Inputs: index of current channel (0 for SCE/LFE, 0 or 1 for CPE) * output channel (range = [0, nChans-1]) * * Outputs: complete frame of decoded PCM, after inverse transform * * Return: 0 if successful, -1 if error * * Notes: If AAC_ENABLE_SBR is defined at compile time then window + overlap * does NOT clip to 16-bit PCM and does NOT interleave channels * If AAC_ENABLE_SBR is NOT defined at compile time, then window + overlap * does clip to 16-bit PCM and interleaves channels * If SBR is enabled at compile time, but we don't know whether it is * actually used for this frame (e.g. the first frame of a stream), * we need to produce both clipped 16-bit PCM in outbuf AND * unclipped 32-bit PCM in the SBR input buffer. In this case we make * a separate pass over the 32-bit PCM to produce 16-bit PCM output. * This inflicts a slight performance hit when decoding non-SBR files. **********************************************************************************************************************/ int IMDCT(int ch, int chOut, short *outbuf) { int i; ICSInfo_t *icsInfo; icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); outbuf += chOut; /* optimized type-IV DCT (operates inplace) */ if (icsInfo->winSequence == 2) { /* 8 short blocks */ for (i = 0; i < 8; i++) DCT4(0, m_PSInfoBase->coef[ch] + i*128, m_PSInfoBase->gbCurrent[ch]); } else { /* 1 long block */ DCT4(1, m_PSInfoBase->coef[ch], m_PSInfoBase->gbCurrent[ch]); } #ifdef AAC_ENABLE_SBR /* window, overlap-add, don't clip to short (send to SBR decoder) * store the decoded 32-bit samples in top half (second AAC_MAX_NSAMPS samples) of coef buffer */ if (icsInfo->winSequence == 0) DecWindowOverlapNoClip(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], m_PSInfoBase->sbrWorkBuf[ch], icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); else if (icsInfo->winSequence == 1) DecWindowOverlapLongStartNoClip(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], m_PSInfoBase->sbrWorkBuf[ch], icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); else if (icsInfo->winSequence == 2) DecWindowOverlapShortNoClip(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], m_PSInfoBase->sbrWorkBuf[ch], icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); else if (icsInfo->winSequence == 3) DecWindowOverlapLongStopNoClip(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], m_PSInfoBase->sbrWorkBuf[ch], icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); if (!m_AACDecInfo->sbrEnabled) { for (i = 0; i < AAC_MAX_NSAMPS; i++) { *outbuf = CLIPTOSHORT((m_PSInfoBase->sbrWorkBuf[ch][i] + RND_VAL) >> FBITS_OUT_IMDCT); outbuf += m_AACDecInfo->nChans; } } m_AACDecInfo->rawSampleBuf[ch] = m_PSInfoBase->sbrWorkBuf[ch]; m_AACDecInfo->rawSampleBytes = sizeof(int); m_AACDecInfo->rawSampleFBits = FBITS_OUT_IMDCT; #else /* window, overlap-add, round to PCM - optimized for each window sequence */ if (icsInfo->winSequence == 0) DecWindowOverlap(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], outbuf, m_AACDecInfo->nChans, icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); else if (icsInfo->winSequence == 1) DecWindowOverlapLongStart(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], outbuf, m_AACDecInfo->nChans, icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); else if (icsInfo->winSequence == 2) DecWindowOverlapShort(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], outbuf, m_AACDecInfo->nChans, icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); else if (icsInfo->winSequence == 3) DecWindowOverlapLongStop(m_PSInfoBase->coef[ch], m_PSInfoBase->overlap[chOut], outbuf, m_AACDecInfo->nChans, icsInfo->winShape, m_PSInfoBase->prevWinShape[chOut]); m_AACDecInfo->rawSampleBuf[ch] = 0; m_AACDecInfo->rawSampleBytes = 0; m_AACDecInfo->rawSampleFBits = 0; #endif m_PSInfoBase->prevWinShape[chOut] = icsInfo->winShape; return 0; } /*********************************************************************************************************************** * Function: DecodeICSInfo * * Description: decode individual channel stream info * * Inputs: sample rate index * * Outputs: updated icsInfo struct * * Return: none **********************************************************************************************************************/ void DecodeICSInfo(ICSInfo_t *icsInfo, int sampRateIdx) { int sfb, g, mask; icsInfo->icsResBit = GetBits(1); icsInfo->winSequence = GetBits(2); icsInfo->winShape = GetBits(1); if (icsInfo->winSequence == 2) { /* short block */ icsInfo->maxSFB = GetBits(4); icsInfo->sfGroup = GetBits(7); icsInfo->numWinGroup = 1; icsInfo->winGroupLen[0] = 1; mask = 0x40; /* start with bit 6 */ for (g = 0; g < 7; g++) { if (icsInfo->sfGroup & mask) { icsInfo->winGroupLen[icsInfo->numWinGroup - 1]++; } else { icsInfo->numWinGroup++; icsInfo->winGroupLen[icsInfo->numWinGroup - 1] = 1; } mask >>= 1; } } else { /* long block */ icsInfo->maxSFB = GetBits(6); icsInfo->predictorDataPresent = GetBits(1); if (icsInfo->predictorDataPresent) { icsInfo->predictorReset = GetBits(1); if (icsInfo->predictorReset) icsInfo->predictorResetGroupNum = GetBits(5); for (sfb = 0; sfb < MIN(icsInfo->maxSFB, predSFBMax[sampRateIdx]); sfb++) icsInfo->predictionUsed[sfb] = GetBits(1); } icsInfo->numWinGroup = 1; icsInfo->winGroupLen[0] = 1; } } /*********************************************************************************************************************** * Function: DecodeSectionData * * Description: decode section data (scale factor band groupings and * associated Huffman codebooks) * * Inputs: window sequence (short or long blocks) * number of window groups (1 for long blocks, 1-8 for short blocks) * max coded scalefactor band * * Outputs: index of Huffman codebook for each scalefactor band in each section * * Return: none * * Notes: sectCB, sectEnd, sfbCodeBook, ordered by window groups for short blocks **********************************************************************************************************************/ void DecodeSectionData(int winSequence, int numWinGrp, int maxSFB, uint8_t *sfbCodeBook) { int g, cb, sfb; int sectLen, sectLenBits, sectLenIncr, sectEscapeVal; sectLenBits = (winSequence == 2 ? 3 : 5); sectEscapeVal = (1 << sectLenBits) - 1; for (g = 0; g < numWinGrp; g++) { sfb = 0; while (sfb < maxSFB) { cb = GetBits(4); /* next section codebook */ sectLen = 0; do { sectLenIncr = GetBits(sectLenBits); sectLen += sectLenIncr; } while (sectLenIncr == sectEscapeVal); sfb += sectLen; while (sectLen--) *sfbCodeBook++ = (uint8_t)cb; } ASSERT(sfb == maxSFB); } } /*********************************************************************************************************************** * Function: DecodeOneScaleFactor * * Description: decode one scalefactor using scalefactor Huffman codebook * * Inputs: none * * Outputs: none * * Return: one decoded scalefactor, including index_offset of -60 **********************************************************************************************************************/ int DecodeOneScaleFactor() { int nBits, val; uint32_t bitBuf; /* decode next scalefactor from bitstream */ bitBuf = GetBitsNoAdvance(huffTabScaleFactInfo.maxBits) << (32 - huffTabScaleFactInfo.maxBits); nBits = DecodeHuffmanScalar(huffTabScaleFact, &huffTabScaleFactInfo, bitBuf, &val); AdvanceBitstream(nBits); return val; } /*********************************************************************************************************************** * Function: DecodeScaleFactors * * Description: decode scalefactors, PNS energy, and intensity stereo weights * * Inputs: number of window groups (1 for long blocks, 1-8 for short blocks) * max coded scalefactor band * global gain (starting value for differential scalefactor coding) * index of Huffman codebook for each scalefactor band in each section * * Outputs: decoded scalefactor for each section * * Return: none * * Notes: sfbCodeBook, scaleFactors ordered by window groups for short blocks * for section with codebook 13, scaleFactors buffer has decoded PNS * energy instead of regular scalefactor * for section with codebook 14 or 15, scaleFactors buffer has intensity * stereo weight instead of regular scalefactor **********************************************************************************************************************/ void DecodeScaleFactors(int numWinGrp, int maxSFB, int globalGain, uint8_t *sfbCodeBook, short *scaleFactors) { int g, sfbCB, nrg, npf, val, sf, is; /* starting values for differential coding */ sf = globalGain; is = 0; nrg = globalGain - 90 - 256; npf = 1; for (g = 0; g < numWinGrp * maxSFB; g++) { sfbCB = *sfbCodeBook++; if (sfbCB == 14 || sfbCB == 15) { /* intensity stereo - differential coding */ val = DecodeOneScaleFactor(); is += val; *scaleFactors++ = (short)is; } else if (sfbCB == 13) { /* PNS - first energy is directly coded, rest are Huffman coded (npf = noise_pcm_flag) */ if (npf) { val = GetBits(9); npf = 0; } else { val = DecodeOneScaleFactor(); } nrg += val; *scaleFactors++ = (short)nrg; } else if (sfbCB >= 1 && sfbCB <= 11) { /* regular (non-zero) region - differential coding */ val = DecodeOneScaleFactor(); sf += val; *scaleFactors++ = (short)sf; } else { /* inactive scalefactor band if codebook 0 */ *scaleFactors++ = 0; } } } /*********************************************************************************************************************** * Function: DecodePulseInfo * * Description: decode pulse information * * Inputs: none * * Outputs: updated PulseInfo_t struct * * Return: none **********************************************************************************************************************/ void DecodePulseInfo(uint8_t ch) { int i; m_pulseInfo[ch].numPulse = GetBits(2) + 1; /* add 1 here */ m_pulseInfo[ch].startSFB = GetBits(6); for (i = 0; i < m_pulseInfo[ch].numPulse; i++) { m_pulseInfo[ch].offset[i] = GetBits(5); m_pulseInfo[ch].amp[i] = GetBits(4); } } /*********************************************************************************************************************** * Function: DecodeTNSInfo * * Description: decode TNS filter information * * Inputs: window sequence (short or long blocks) * * Outputs: updated TNSInfo_t struct * buffer of decoded (signed) TNS filter coefficients * * Return: none **********************************************************************************************************************/ void DecodeTNSInfo(int winSequence, TNSInfo_t *ti, int8_t *tnsCoef) { int i, w, f, coefBits, compress; int8_t c, s, n; uint8_t *filtLength, *filtOrder, *filtDir; filtLength = ti->length; filtOrder = ti->order; filtDir = ti->dir; if (winSequence == 2) { /* short blocks */ for (w = 0; w < NWINDOWS_SHORT; w++) { ti->numFilt[w] = GetBits(1); if (ti->numFilt[w]) { ti->coefRes[w] = GetBits(1) + 3; *filtLength = GetBits(4); *filtOrder = GetBits(3); if (*filtOrder) { *filtDir++ = GetBits(1); compress = GetBits(1); coefBits = (int)ti->coefRes[w] - compress; /* 2, 3, or 4 */ s = sgnMask[coefBits - 2]; n = negMask[coefBits - 2]; for (i = 0; i < *filtOrder; i++) { c = GetBits(coefBits); if (c & s) c |= n; *tnsCoef++ = c; } } filtLength++; filtOrder++; } } } else { /* long blocks */ ti->numFilt[0] = GetBits(2); if (ti->numFilt[0]) ti->coefRes[0] = GetBits(1) + 3; for (f = 0; f < ti->numFilt[0]; f++) { *filtLength = GetBits(6); *filtOrder = GetBits(5); if (*filtOrder) { *filtDir++ = GetBits(1); compress = GetBits(1); coefBits = (int)ti->coefRes[0] - compress; /* 2, 3, or 4 */ s = sgnMask[coefBits - 2]; n = negMask[coefBits - 2]; for (i = 0; i < *filtOrder; i++) { c = GetBits(coefBits); if (c & s) c |= n; *tnsCoef++ = c; } } filtLength++; filtOrder++; } } } /* bitstream field lengths for gain control data: * gainBits[winSequence][0] = maxWindow (how many gain windows there are) * gainBits[winSequence][1] = locBitsZero (bits for alocCode if window == 0) * gainBits[winSequence][2] = locBits (bits for alocCode if window != 0) */ static const uint8_t gainBits[4][3] = { {1, 5, 5}, /* long */ {2, 4, 2}, /* start */ {8, 2, 2}, /* short */ {2, 4, 5}, /* stop */ }; /*********************************************************************************************************************** * Function: DecodeGainControlInfo * * Description: decode gain control information (SSR profile only) * * Inputs: window sequence (short or long blocks) * * Outputs: updated GainControlInfo_t struct * * Return: none **********************************************************************************************************************/ void DecodeGainControlInfo(int winSequence, GainControlInfo_t *gi) { int bd, wd, ad; int locBits, locBitsZero, maxWin; gi->maxBand = GetBits(2); maxWin = (int)gainBits[winSequence][0]; locBitsZero = (int)gainBits[winSequence][1]; locBits = (int)gainBits[winSequence][2]; for (bd = 1; bd <= gi->maxBand; bd++) { for (wd = 0; wd < maxWin; wd++) { gi->adjNum[bd][wd] = GetBits(3); for (ad = 0; ad < gi->adjNum[bd][wd]; ad++) { gi->alevCode[bd][wd][ad] = GetBits(4); gi->alocCode[bd][wd][ad] = GetBits(wd == 0 ? locBitsZero : locBits); } } } } /*********************************************************************************************************************** * Function: DecodeICS * * Description: decode individual channel stream * * Inputs: index of current channel * * Outputs: updated section data, scale factor data, pulse data, TNS data, * and gain control data * * Return: none **********************************************************************************************************************/ void DecodeICS(int ch) { int globalGain; ICSInfo_t *icsInfo; TNSInfo_t *ti; GainControlInfo_t *gi; icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); globalGain = GetBits(8); if (!m_PSInfoBase->commonWin) DecodeICSInfo(icsInfo, m_PSInfoBase->sampRateIdx); DecodeSectionData(icsInfo->winSequence, icsInfo->numWinGroup, icsInfo->maxSFB, m_PSInfoBase->sfbCodeBook[ch]); DecodeScaleFactors(icsInfo->numWinGroup, icsInfo->maxSFB, globalGain, m_PSInfoBase->sfbCodeBook[ch], m_PSInfoBase->scaleFactors[ch]); m_pulseInfo[ch].pulseDataPresent = GetBits(1); if (m_pulseInfo[ch].pulseDataPresent) DecodePulseInfo(ch); ti = &m_PSInfoBase->tnsInfo[ch]; ti->tnsDataPresent = GetBits(1); if (ti->tnsDataPresent) DecodeTNSInfo(icsInfo->winSequence, ti, ti->coef); gi = &m_PSInfoBase->gainControlInfo[ch]; gi->gainControlDataPresent = GetBits(1); if (gi->gainControlDataPresent) DecodeGainControlInfo(icsInfo->winSequence, gi); } /*********************************************************************************************************************** * Function: DecodeNoiselessData * * Description: decode noiseless data (side info and transform coefficients) * * Inputs: double pointer to buffer pointing to start of individual channel stream * (14496-3, table 4.4.24) * pointer to bit offset * pointer to number of valid bits remaining in buf * index of current channel * * Outputs: updated global gain, section data, scale factor data, pulse data, * TNS data, gain control data, and spectral data * * Return: 0 if successful, error code (< 0) if error **********************************************************************************************************************/ int DecodeNoiselessData(uint8_t **buf, int *bitOffset, int *bitsAvail, int ch) { int bitsUsed; ICSInfo_t *icsInfo; icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); SetBitstreamPointer((*bitsAvail+7) >> 3, *buf); GetBits(*bitOffset); DecodeICS(ch); if (icsInfo->winSequence == 2) DecodeSpectrumShort(ch); else DecodeSpectrumLong(ch); bitsUsed = CalcBitsUsed(*buf, *bitOffset); *buf += ((bitsUsed + *bitOffset) >> 3); *bitOffset = ((bitsUsed + *bitOffset) & 0x07); *bitsAvail -= bitsUsed; m_AACDecInfo->sbDeinterleaveReqd[ch] = 0; m_AACDecInfo->tnsUsed |= m_PSInfoBase->tnsInfo[ch].tnsDataPresent; /* set flag if TNS used for any channel */ return ERR_AAC_NONE; } /*********************************************************************************************************************** * Function: DecodeHuffmanScalar * * Description: decode one Huffman symbol from bitstream * * Inputs: pointers to Huffman table and info struct * left-aligned bit buffer with >= huffTabInfo->maxBits bits * * Outputs: decoded symbol in *val * * Return: number of bits in symbol * * Notes: assumes canonical Huffman codes: * first CW always 0, we have "count" CW's of length "nBits" bits * starting CW for codes of length nBits+1 = * (startCW[nBits] + count[nBits]) << 1 * if there are no codes at nBits, then we just keep << 1 each time * (since count[nBits] = 0) **********************************************************************************************************************/ int DecodeHuffmanScalar(const signed short *huffTab, const HuffInfo_t *huffTabInfo, uint32_t bitBuf, int32_t *val) { uint32_t count, start, shift, t; const uint8_t *countPtr; const signed short *map; map = huffTab + huffTabInfo->offset; countPtr = huffTabInfo->count; start = 0; count = 0; shift = 32; do { start += count; start <<= 1; map += count; count = *countPtr++; shift--; t = (bitBuf >> shift) - start; } while (t >= count); *val = (int32_t)map[t]; return (countPtr - huffTabInfo->count); } /*********************************************************************************************************************** * Function: UnpackADTSHeader * * Description: parse the ADTS frame header and initialize decoder state, Audio Data Transport Stream * * Inputs: double pointer to buffer with complete ADTS frame header (byte aligned) * header size = 7 bytes, plus 2 if CRC * * Outputs: filled in ADTS struct * updated buffer pointer * updated bit offset * updated number of available bits * * Return: 0 if successful, error code (< 0) if error * verify that fixed fields don't change between frames ***********************************************************************************************************************/ int UnpackADTSHeader(uint8_t **buf, int *bitOffset, int *bitsAvail) { int bitsUsed; /* init bitstream reader */ SetBitstreamPointer((*bitsAvail + 7) >> 3, *buf); GetBits(*bitOffset); /* verify that first 12 bits of header are syncword */ if (GetBits(12) != 0x0fff) { return ERR_AAC_INVALID_ADTS_HEADER; } /* fixed fields - should not change from frame to frame */ m_fhADTS.id = GetBits(1); m_fhADTS.layer = GetBits(2); m_fhADTS.protectBit = GetBits(1); m_fhADTS.profile = GetBits(2); m_fhADTS.sampRateIdx = GetBits(4); m_fhADTS.privateBit = GetBits(1); m_fhADTS.channelConfig = GetBits(3); m_fhADTS.origCopy = GetBits(1); m_fhADTS.home = GetBits(1); /* variable fields - can change from frame to frame */ m_fhADTS.copyBit = GetBits(1); m_fhADTS.copyStart = GetBits(1); m_fhADTS.frameLength = GetBits(13); m_fhADTS.bufferFull = GetBits(11); m_fhADTS.numRawDataBlocks = GetBits(2) + 1; /* note - MPEG4 spec, correction 1 changes how CRC is handled when protectBit == 0 and numRawDataBlocks > 1 */ if (m_fhADTS.protectBit == 0) m_fhADTS.crcCheckWord = GetBits(16); /* byte align */ ByteAlignBitstream(); /* should always be aligned anyway */ /* check validity of header */ if (m_fhADTS.layer != 0 || m_fhADTS.profile != AAC_PROFILE_LC || m_fhADTS.sampRateIdx >= NUM_SAMPLE_RATES || m_fhADTS.channelConfig >= NUM_DEF_CHAN_MAPS) return ERR_AAC_INVALID_ADTS_HEADER; #ifndef AAC_ENABLE_MPEG4 if (m_fhADTS.id != 1) return ERR_AAC_MPEG4_UNSUPPORTED; #endif /* update codec info */ m_PSInfoBase->sampRateIdx = m_fhADTS.sampRateIdx; if (!m_PSInfoBase->useImpChanMap) m_PSInfoBase->nChans = channelMapTab[m_fhADTS.channelConfig]; /* syntactic element fields will be read from bitstream for each element */ m_AACDecInfo->prevBlockID = AAC_ID_INVALID; m_AACDecInfo->currBlockID = AAC_ID_INVALID; m_AACDecInfo->currInstTag = -1; /* fill in user-accessible data */ m_AACDecInfo->bitRate = 0; m_AACDecInfo->nChans = m_PSInfoBase->nChans; m_AACDecInfo->sampRate = sampRateTab[m_PSInfoBase->sampRateIdx]; m_AACDecInfo->id = m_fhADTS.id; m_AACDecInfo->profile = m_fhADTS.profile; m_AACDecInfo->sbrEnabled = 0; m_AACDecInfo->adtsBlocksLeft = m_fhADTS.numRawDataBlocks; /* update bitstream reader */ bitsUsed = CalcBitsUsed(*buf, *bitOffset); *buf += (bitsUsed + *bitOffset) >> 3; *bitOffset = (bitsUsed + *bitOffset) & 0x07; *bitsAvail -= bitsUsed ; if (*bitsAvail < 0) return ERR_AAC_INDATA_UNDERFLOW; return ERR_AAC_NONE; } /*********************************************************************************************************************** * Function: GetADTSChannelMapping * * Description: determine the number of channels from implicit mapping rules * * Inputs: pointer to start of raw_data_block * bit offset * bits available * * Outputs: updated number of channels * * Return: 0 if successful, error code (< 0) if error * * Notes: calculates total number of channels using rules in 14496-3, 4.5.1.2.1 * does not attempt to deduce speaker geometry ***********************************************************************************************************************/ int GetADTSChannelMapping(uint8_t *buf, int bitOffset, int bitsAvail) { int ch, nChans, elementChans, err; nChans = 0; do { /* parse next syntactic element */ err = DecodeNextElement(&buf, &bitOffset, &bitsAvail); if (err) return err; elementChans = elementNumChans[m_AACDecInfo->currBlockID]; nChans += elementChans; for (ch = 0; ch < elementChans; ch++) { err = DecodeNoiselessData(&buf, &bitOffset, &bitsAvail, ch); if (err) return err; } } while (m_AACDecInfo->currBlockID != AAC_ID_END); if (nChans <= 0) return ERR_AAC_CHANNEL_MAP; /* update number of channels in codec state and user-accessible info structs */ m_PSInfoBase->nChans = nChans; m_AACDecInfo->nChans = m_PSInfoBase->nChans; m_PSInfoBase->useImpChanMap = 1; return ERR_AAC_NONE; } /*********************************************************************************************************************** * Function: GetNumChannelsADIF * * Description: get number of channels from program config elements in an ADIF file * * Inputs: array of filled-in program config element structures * number of PCE's * * Outputs: none * * Return: total number of channels in file * -1 if error (invalid number of PCE's or unsupported mode) ***********************************************************************************************************************/ int GetNumChannelsADIF(int nPCE) { int i, j, nChans; if (nPCE < 1 || nPCE > MAX_NUM_PCE_ADIF) return -1; nChans = 0; for (i = 0; i < nPCE; i++) { /* for now: only support LC, no channel coupling */ if (m_pce[i]->profile != AAC_PROFILE_LC || m_pce[i]->numCCE > 0) return -1; /* add up number of channels in all channel elements (assume all single-channel) */ nChans += m_pce[i]->numFCE; nChans += m_pce[i]->numSCE; nChans += m_pce[i]->numBCE; nChans += m_pce[i]->numLCE; /* add one more for every element which is a channel pair */ for (j = 0; j < m_pce[i]->numFCE; j++) { if ((m_pce[i]->fce[j] & 0x10) >> 4) /* bit 4 = SCE/CPE flag */ nChans++; } for (j = 0; j < m_pce[i]->numSCE; j++) { if ((m_pce[i]->sce[j] & 0x10) >> 4) /* bit 4 = SCE/CPE flag */ nChans++; } for (j = 0; j < m_pce[i]->numBCE; j++) { if ((m_pce[i]->bce[j] & 0x10) >> 4) /* bit 4 = SCE/CPE flag */ nChans++; } } return nChans; } /*********************************************************************************************************************** * Function: GetSampleRateIdxADIF * * Description: get sampling rate index from program config elements in an ADIF file * * Inputs: array of filled-in program config element structures * number of PCE's * * Outputs: none * * Return: sample rate of file * -1 if error (invalid number of PCE's or sample rate mismatch) ***********************************************************************************************************************/ int GetSampleRateIdxADIF(int nPCE) { int i, idx; if (nPCE < 1 || nPCE > MAX_NUM_PCE_ADIF) return -1; /* make sure all PCE's have the same sample rate */ idx = m_pce[0]->sampRateIdx; for (i = 1; i < nPCE; i++) { if (m_pce[i]->sampRateIdx != idx) return -1; } return idx; } /*********************************************************************************************************************** * Function: UnpackADIFHeader * * Description: parse the ADIF file header and initialize decoder state * * Inputs: double pointer to buffer with complete ADIF header * (starting at 'A' in 'ADIF' tag) * pointer to bit offset * pointer to number of valid bits remaining in inbuf * * Outputs: filled-in ADIF struct * updated buffer pointer * updated bit offset * updated number of available bits * * Return: 0 if successful, error code (< 0) if error ***********************************************************************************************************************/ int UnpackADIFHeader(uint8_t **buf, int *bitOffset, int *bitsAvail) { uint8_t i; int bitsUsed; /* init bitstream reader */ SetBitstreamPointer((*bitsAvail + 7) >> 3, *buf); GetBits(*bitOffset); /* verify that first 32 bits of header are "ADIF" */ if (GetBits(8) != 'A' || GetBits(8) != 'D' || GetBits(8) != 'I' || GetBits(8) != 'F') return ERR_AAC_INVALID_ADIF_HEADER; /* read ADIF header fields */ m_fhADIF.copyBit = GetBits(1); if (m_fhADIF.copyBit) { for (i = 0; i < ADIF_COPYID_SIZE; i++) m_fhADIF.copyID[i] = GetBits(8); } m_fhADIF.origCopy = GetBits(1); m_fhADIF.home = GetBits(1); m_fhADIF.bsType = GetBits(1); m_fhADIF.bitRate = GetBits(23); m_fhADIF.numPCE = GetBits(4) + 1; /* add 1 (so range = [1, 16]) */ if (m_fhADIF.bsType == 0) m_fhADIF.bufferFull = GetBits(20); /* parse all program config elements */ for (i = 0; i < m_fhADIF.numPCE; i++) DecodeProgramConfigElement(i); /* byte align */ ByteAlignBitstream(); /* update codec info */ m_PSInfoBase->nChans = GetNumChannelsADIF(m_fhADIF.numPCE); m_PSInfoBase->sampRateIdx = GetSampleRateIdxADIF(m_fhADIF.numPCE); /* check validity of header */ if (m_PSInfoBase->nChans < 0 || m_PSInfoBase->sampRateIdx < 0 || m_PSInfoBase->sampRateIdx >= NUM_SAMPLE_RATES) return ERR_AAC_INVALID_ADIF_HEADER; /* syntactic element fields will be read from bitstream for each element */ m_AACDecInfo->prevBlockID = AAC_ID_INVALID; m_AACDecInfo->currBlockID = AAC_ID_INVALID; m_AACDecInfo->currInstTag = -1; /* fill in user-accessible data */ m_AACDecInfo->bitRate = 0; m_AACDecInfo->nChans = m_PSInfoBase->nChans; m_AACDecInfo->sampRate = sampRateTab[m_PSInfoBase->sampRateIdx]; m_AACDecInfo->profile = m_pce[0]->profile; m_AACDecInfo->sbrEnabled = 0; /* update bitstream reader */ bitsUsed = CalcBitsUsed(*buf, *bitOffset); *buf += (bitsUsed + *bitOffset) >> 3; *bitOffset = (bitsUsed + *bitOffset) & 0x07; *bitsAvail -= bitsUsed ; if (*bitsAvail < 0) return ERR_AAC_INDATA_UNDERFLOW; return ERR_AAC_NONE; } /*********************************************************************************************************************** * Function: SetRawBlockParams * * Description: set internal state variables for decoding a stream of raw data blocks * * Inputs: flag indicating source of parameters (from previous headers or passed * explicitly by caller) * number of channels * sample rate * profile ID * * Outputs: updated state variables in aacDecInfo * * Return: 0 if successful, error code (< 0) if error * * Notes: if copyLast == 1, then m_PSInfoBase->nChans, m_PSInfoBase->sampRateIdx, and * aacDecInfo->profile are not changed (it's assumed that we already * set them, such as by a previous call to UnpackADTSHeader()) * if copyLast == 0, then the parameters we passed in are used instead ***********************************************************************************************************************/ int SetRawBlockParams(int copyLast, int nChans, int sampRate, int profile) { int idx; if (!copyLast) { m_AACDecInfo->profile = profile; m_PSInfoBase->nChans = nChans; for (idx = 0; idx < NUM_SAMPLE_RATES; idx++) { if (sampRate == sampRateTab[idx]) { m_PSInfoBase->sampRateIdx = idx; break; } } if (idx == NUM_SAMPLE_RATES) return ERR_AAC_INVALID_FRAME; } m_AACDecInfo->nChans = m_PSInfoBase->nChans; m_AACDecInfo->sampRate = sampRateTab[m_PSInfoBase->sampRateIdx]; /* check validity of header */ if (m_PSInfoBase->sampRateIdx >= NUM_SAMPLE_RATES || m_PSInfoBase->sampRateIdx < 0 || m_AACDecInfo->profile != AAC_PROFILE_LC) return ERR_AAC_RAWBLOCK_PARAMS; return ERR_AAC_NONE; } /*********************************************************************************************************************** * Function: PrepareRawBlock * * Description: reset per-block state variables for raw blocks (no ADTS/ADIF headers) * * Inputs: none * * Outputs: updated state variables in aacDecInfo * * Return: 0 if successful, error code (< 0) if error ***********************************************************************************************************************/ int PrepareRawBlock() { /* syntactic element fields will be read from bitstream for each element */ m_AACDecInfo->prevBlockID = AAC_ID_INVALID; m_AACDecInfo->currBlockID = AAC_ID_INVALID; m_AACDecInfo->currInstTag = -1; /* fill in user-accessible data */ m_AACDecInfo->bitRate = 0; m_AACDecInfo->sbrEnabled = 0; return ERR_AAC_NONE; } /*********************************************************************************************************************** * Function: DequantBlock * * Description: dequantize one block of transform coefficients (in-place) * * Inputs: quantized transform coefficients, range = [0, 8191] * number of samples to dequantize * scalefactor for this block of data, range = [0, 256] * * Outputs: dequantized transform coefficients in Q(FBITS_OUT_DQ_OFF) * * Return: guard bit mask (OR of abs value of all dequantized coefs) * * Notes: applies dequant formula y = pow(x, 4.0/3.0) * pow(2, (scale - 100)/4.0) * * pow(2, FBITS_OUT_DQ_OFF) * clips outputs to Q(FBITS_OUT_DQ_OFF) * output has no minimum number of guard bits **********************************************************************************************************************/ int DequantBlock(int *inbuf, int nSamps, int scale) { int iSamp, scalef, scalei, x, y, gbMask, shift, tab4[4]; const uint32_t *tab16, *coef; if (nSamps <= 0) return 0; scale -= SF_OFFSET; /* new range = [-100, 156] */ /* with two's complement numbers, scalei/scalef factorization works for pos and neg values of scale: * [+4...+7] >> 2 = +1, [ 0...+3] >> 2 = 0, [-4...-1] >> 2 = -1, [-8...-5] >> 2 = -2 ... * (-1 & 0x3) = 3, (-2 & 0x3) = 2, (-3 & 0x3) = 1, (0 & 0x3) = 0 * * Example: 2^(-5/4) = 2^(-1) * 2^(-1/4) = 2^-2 * 2^(3/4) */ tab16 = pow43_14[scale & 0x3]; scalef = pow14[scale & 0x3]; scalei = (scale >> 2) + FBITS_OUT_DQ_OFF; /* cache first 4 values: * tab16[j] = Q28 for j = [0,3] * tab4[x] = x^(4.0/3.0) * 2^(0.25*scale), Q(FBITS_OUT_DQ_OFF) */ shift = 28 - scalei; if (shift > 31) { tab4[0] = tab4[1] = tab4[2] = tab4[3] = 0; } else if (shift <= 0) { shift = -shift; if (shift > 31) shift = 31; for (x = 0; x < 4; x++) { y = tab16[x]; if (y > (0x7fffffff >> shift)) y = 0x7fffffff; /* clip (rare) */ else y <<= shift; tab4[x] = y; } } else { tab4[0] = 0; tab4[1] = tab16[1] >> shift; tab4[2] = tab16[2] >> shift; tab4[3] = tab16[3] >> shift; } gbMask = 0; do { iSamp = *inbuf; x = FASTABS(iSamp); if (x < 4) { y = tab4[x]; } else { if (x < 16) { /* result: y = Q25 (tab16 = Q25) */ y = tab16[x]; shift = 25 - scalei; } else if (x < 64) { /* result: y = Q21 (pow43tab[j] = Q23, scalef = Q30) */ y = pow43[x-16]; shift = 21 - scalei; y = MULSHIFT32(y, scalef); } else { /* normalize to [0x40000000, 0x7fffffff] * input x = [64, 8191] = [64, 2^13-1] * ranges: * shift = 7: 64 - 127 * shift = 6: 128 - 255 * shift = 5: 256 - 511 * shift = 4: 512 - 1023 * shift = 3: 1024 - 2047 * shift = 2: 2048 - 4095 * shift = 1: 4096 - 8191 */ x <<= 17; shift = 0; if (x < 0x08000000) x <<= 4, shift += 4; if (x < 0x20000000) x <<= 2, shift += 2; if (x < 0x40000000) x <<= 1, shift += 1; coef = (x < SQRTHALF) ? poly43lo : poly43hi; /* polynomial */ y = coef[0]; y = MULSHIFT32(y, x) + coef[1]; y = MULSHIFT32(y, x) + coef[2]; y = MULSHIFT32(y, x) + coef[3]; y = MULSHIFT32(y, x) + coef[4]; y = MULSHIFT32(y, pow2frac[shift]) << 3; /* fractional scale * result: y = Q21 (pow43tab[j] = Q23, scalef = Q30) */ y = MULSHIFT32(y, scalef); /* now y is Q24 */ shift = 24 - scalei - pow2exp[shift]; } /* integer scale */ if (shift <= 0) { shift = -shift; if (shift > 31) shift = 31; if (y > (0x7fffffff >> shift)) y = 0x7fffffff; /* clip (rare) */ else y <<= shift; } else { if (shift > 31) shift = 31; y >>= shift; } } /* sign and store (gbMask used to count GB's) */ gbMask |= y; /* apply sign */ iSamp >>= 31; y ^= iSamp; y -= iSamp; *inbuf++ = y; } while (--nSamps); return gbMask; } /*********************************************************************************************************************** * Function: AACDequantize * * Description: dequantize all transform coefficients for one channel * * Inputs: index of current channel * * Outputs: dequantized coefficients, including short-block deinterleaving * flags indicating if intensity and/or PNS is active * minimum guard bit count for dequantized coefficients * * Return: 0 if successful, error code (< 0) if error **********************************************************************************************************************/ int AACDequantize(int ch) { int gp, cb, sfb, win, width, nSamps, gbMask; int *coef; const uint16_t *sfbTab; uint8_t *sfbCodeBook; short *scaleFactors; ICSInfo_t *icsInfo; icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); if (icsInfo->winSequence == 2) { sfbTab = sfBandTabShort + sfBandTabShortOffset[m_PSInfoBase->sampRateIdx]; nSamps = NSAMPS_SHORT; } else { sfbTab = sfBandTabLong + sfBandTabLongOffset[m_PSInfoBase->sampRateIdx]; nSamps = NSAMPS_LONG; } coef = m_PSInfoBase->coef[ch]; sfbCodeBook = m_PSInfoBase->sfbCodeBook[ch]; scaleFactors = m_PSInfoBase->scaleFactors[ch]; m_PSInfoBase->intensityUsed[ch] = 0; m_PSInfoBase->pnsUsed[ch] = 0; gbMask = 0; for (gp = 0; gp < icsInfo->numWinGroup; gp++) { for (win = 0; win < icsInfo->winGroupLen[gp]; win++) { for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) { /* dequantize one scalefactor band (not necessary if codebook is intensity or PNS) * for zero codebook, still run dequantizer in case non-zero pulse data was added */ cb = (int)(sfbCodeBook[sfb]); width = sfbTab[sfb+1] - sfbTab[sfb]; if (cb >= 0 && cb <= 11) gbMask |= DequantBlock(coef, width, scaleFactors[sfb]); else if (cb == 13) m_PSInfoBase->pnsUsed[ch] = 1; else if (cb == 14 || cb == 15) m_PSInfoBase->intensityUsed[ch] = 1; /* should only happen if ch == 1 */ coef += width; } coef += (nSamps - sfbTab[icsInfo->maxSFB]); } sfbCodeBook += icsInfo->maxSFB; scaleFactors += icsInfo->maxSFB; } m_AACDecInfo->pnsUsed |= m_PSInfoBase->pnsUsed[ch]; /* set flag if PNS used for any channel */ /* calculate number of guard bits in dequantized data */ m_PSInfoBase->gbCurrent[ch] = CLZ(gbMask) - 1; return ERR_AAC_NONE; } /*********************************************************************************************************************** * Function: DeinterleaveShortBlocks * * Description: deinterleave transform coefficients in short blocks for one channel * * Inputs: index of current channel * * Outputs: deinterleaved coefficients (window groups into 8 separate windows) * * Return: 0 if successful, error code (< 0) if error * * Notes: only necessary if deinterleaving not part of Huffman decoding **********************************************************************************************************************/ int DeinterleaveShortBlocks(int ch) { // (void)aacDecInfo; // (void)ch; /* not used for this implementation - short block deinterleaving performed during Huffman decoding */ return ERR_AAC_NONE; } /*********************************************************************************************************************** * Function: Get32BitVal * * Description: generate 32-bit unsigned random number * * Inputs: last number calculated (seed, first time through) * * Outputs: new number, saved in *last * * Return: 32-bit number, uniformly distributed between [0, 2^32) * * Notes: uses simple linear congruential generator **********************************************************************************************************************/ unsigned int Get32BitVal(unsigned int *last) { uint32_t r = *last; /* use same coefs as MPEG reference code (classic LCG) * use unsigned multiply to force reliable wraparound behavior in C (mod 2^32) */ r = (1664525U * r) + 1013904223U; *last = r; return r; } /*********************************************************************************************************************** * Function: InvRootR * * Description: use Newton's method to solve for x = 1/sqrt(r) * * Inputs: r in Q30 format, range = [0.25, 1] (normalize inputs to this range) * * Outputs: none * * Return: x = Q29, range = (1, 2) * * Notes: guaranteed to converge and not overflow for any r in this range * * xn+1 = xn - f(xn)/f'(xn) * f(x) = 1/sqrt(r) - x = 0 (find root) * = 1/x^2 - r * f'(x) = -2/x^3 * * so xn+1 = xn/2 * (3 - r*xn^2) * * NUM_ITER_INVSQRT = 3, maxDiff = 1.3747e-02 * NUM_ITER_INVSQRT = 4, maxDiff = 3.9832e-04 **********************************************************************************************************************/ int InvRootR(int r) { int i, xn, t; /* use linear equation for initial guess * x0 = -2*r + 3 (so x0 always >= correct answer in range [0.25, 1)) * xn = Q29 (at every step) */ xn = (MULSHIFT32(r, X0_COEF_2) << 2) + X0_OFF_2; for (i = 0; i < NUM_ITER_INVSQRT; i++) { t = MULSHIFT32(xn, xn); /* Q26 = Q29*Q29 */ t = Q26_3 - (MULSHIFT32(r, t) << 2); /* Q26 = Q26 - (Q31*Q26 << 1) */ xn = MULSHIFT32(xn, t) << (6 - 1); /* Q29 = (Q29*Q26 << 6), and -1 for division by 2 */ } /* clip to range (1.0, 2.0) * (because of rounding, this can converge to xn slightly > 2.0 when r is near 0.25) */ if (xn >> 30) xn = (1 << 30) - 1; return xn; } /*********************************************************************************************************************** * Function: ScaleNoiseVector * * Description: apply scaling to vector of noise coefficients for one scalefactor band * * Inputs: unscaled coefficients * number of coefficients in vector (one scalefactor band of coefs) * scalefactor for this band (i.e. noise energy) * * Outputs: nVals coefficients in Q(FBITS_OUT_DQ_OFF) * * Return: guard bit mask (OR of abs value of all noise coefs) **********************************************************************************************************************/ int ScaleNoiseVector(int *coef, int nVals, int sf) { /* pow(2, i/4.0) for i = [0,1,2,3], format = Q30 */ static const int pow14[4] PROGMEM = { 0x40000000, 0x4c1bf829, 0x5a82799a, 0x6ba27e65 }; int i, c, spec, energy, sq, scalef, scalei, invSqrtEnergy, z, gbMask; energy = 0; for (i = 0; i < nVals; i++) { spec = coef[i]; /* max nVals = max SFB width = 96, so energy can gain < 2^7 bits in accumulation */ sq = (spec * spec) >> 8; /* spec*spec range = (-2^30, 2^30) */ energy += sq; } /* unless nVals == 1 (or the number generator is broken...), this should not happen */ if (energy == 0) return 0; /* coef[i] must = 0 for i = [0, nVals-1], so gbMask = 0 */ /* pow(2, sf/4) * pow(2, FBITS_OUT_DQ_OFF) */ scalef = pow14[sf & 0x3]; scalei = (sf >> 2) + FBITS_OUT_DQ_OFF; /* energy has implied factor of 2^-8 since we shifted the accumulator * normalize energy to range [0.25, 1.0), calculate 1/sqrt(1), and denormalize * i.e. divide input by 2^(30-z) and convert to Q30 * output of 1/sqrt(i) now has extra factor of 2^((30-z)/2) * for energy > 0, z is an even number between 0 and 28 * final scaling of invSqrtEnergy: * 2^(15 - z/2) to compensate for implicit 2^(30-z) factor in input * +4 to compensate for implicit 2^-8 factor in input */ z = CLZ(energy) - 2; /* energy has at least 2 leading zeros (see acc loop) */ z &= 0xfffffffe; /* force even */ invSqrtEnergy = InvRootR(energy << z); /* energy << z must be in range [0x10000000, 0x40000000] */ scalei -= (15 - z/2 + 4); /* nInt = 1/sqrt(energy) in Q29 */ /* normalize for final scaling */ z = CLZ(invSqrtEnergy) - 1; invSqrtEnergy <<= z; scalei -= (z - 3 - 2); /* -2 for scalef, z-3 for invSqrtEnergy */ scalef = MULSHIFT32(scalef, invSqrtEnergy); /* scalef (input) = Q30, invSqrtEnergy = Q29 * 2^z */ gbMask = 0; if (scalei < 0) { scalei = -scalei; if (scalei > 31) scalei = 31; for (i = 0; i < nVals; i++) { c = MULSHIFT32(coef[i], scalef) >> scalei; gbMask |= FASTABS(c); coef[i] = c; } } else { /* for scalei <= 16, no clipping possible (coef[i] is < 2^15 before scaling) * for scalei > 16, just saturate exponent (rare) * scalef is close to full-scale (since we normalized invSqrtEnergy) * remember, we are just producing noise here */ if (scalei > 16) scalei = 16; for (i = 0; i < nVals; i++) { c = MULSHIFT32(coef[i] << scalei, scalef); coef[i] = c; gbMask |= FASTABS(c); } } return gbMask; } /*********************************************************************************************************************** * Function: GenerateNoiseVector * * Description: create vector of noise coefficients for one scalefactor band * * Inputs: seed for number generator * number of coefficients to generate * * Outputs: buffer of nVals coefficients, range = [-2^15, 2^15) * updated seed for number generator * * Return: none **********************************************************************************************************************/ void GenerateNoiseVector(int *coef, int *last, int nVals) { int i; for (i = 0; i < nVals; i++) coef[i] = ((int32_t)Get32BitVal((uint32_t *)last)) >> 16; } /*********************************************************************************************************************** * Function: CopyNoiseVector * * Description: copy vector of noise coefficients for one scalefactor band from L to R * * Inputs: buffer of left coefficients * number of coefficients to copy * * Outputs: buffer of right coefficients * * Return: none **********************************************************************************************************************/ void CopyNoiseVector(int *coefL, int *coefR, int nVals) { int i; for (i = 0; i < nVals; i++) coefR[i] = coefL[i]; } /*********************************************************************************************************************** * Function: PNS * * Description: apply perceptual noise substitution, if enabled (MPEG-4 only) * * Inputs: index of current channel * * Outputs: shaped noise in scalefactor bands where PNS is active * updated minimum guard bit count for this channel * * Return: 0 if successful, -1 if error **********************************************************************************************************************/ int PNS(int ch) { int gp, sfb, win, width, nSamps, gb, gbMask; int *coef; const uint16_t *sfbTab; uint8_t *sfbCodeBook; short *scaleFactors; int msMaskOffset, checkCorr, genNew; uint8_t msMask; uint8_t *msMaskPtr; ICSInfo_t *icsInfo; icsInfo = (ch == 1 && m_PSInfoBase->commonWin == 1) ? &(m_PSInfoBase->icsInfo[0]) : &(m_PSInfoBase->icsInfo[ch]); if (!m_PSInfoBase->pnsUsed[ch]) return 0; if (icsInfo->winSequence == 2) { sfbTab = sfBandTabShort + sfBandTabShortOffset[m_PSInfoBase->sampRateIdx]; nSamps = NSAMPS_SHORT; } else { sfbTab = sfBandTabLong + sfBandTabLongOffset[m_PSInfoBase->sampRateIdx]; nSamps = NSAMPS_LONG; } coef = m_PSInfoBase->coef[ch]; sfbCodeBook = m_PSInfoBase->sfbCodeBook[ch]; scaleFactors = m_PSInfoBase->scaleFactors[ch]; checkCorr = (m_AACDecInfo->currBlockID == AAC_ID_CPE && m_PSInfoBase->commonWin == 1 ? 1 : 0); gbMask = 0; for (gp = 0; gp < icsInfo->numWinGroup; gp++) { for (win = 0; win < icsInfo->winGroupLen[gp]; win++) { msMaskPtr = m_PSInfoBase->msMaskBits + ((gp*icsInfo->maxSFB) >> 3); msMaskOffset = ((gp*icsInfo->maxSFB) & 0x07); msMask = (*msMaskPtr++) >> msMaskOffset; for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) { width = sfbTab[sfb+1] - sfbTab[sfb]; if (sfbCodeBook[sfb] == 13) { if (ch == 0) { /* generate new vector, copy into ch 1 if it's possible that the channels will be correlated * if ch 1 has PNS enabled for this SFB but it's uncorrelated (i.e. ms_used == 0), * the copied values will be overwritten when we process ch 1 */ GenerateNoiseVector(coef, &m_PSInfoBase->pnsLastVal, width); if (checkCorr && m_PSInfoBase->sfbCodeBook[1][gp*icsInfo->maxSFB + sfb] == 13) CopyNoiseVector(coef, m_PSInfoBase->coef[1] + (coef - m_PSInfoBase->coef[0]), width); } else { /* generate new vector if no correlation between channels */ genNew = 1; if (checkCorr && m_PSInfoBase->sfbCodeBook[0][gp*icsInfo->maxSFB + sfb] == 13) { if((m_PSInfoBase->msMaskPresent==1 && (msMask & 0x01)) || m_PSInfoBase->msMaskPresent == 2 ) genNew = 0; } if (genNew) GenerateNoiseVector(coef, &m_PSInfoBase->pnsLastVal, width); } gbMask |= ScaleNoiseVector(coef, width, m_PSInfoBase->scaleFactors[ch][gp*icsInfo->maxSFB + sfb]); } coef += width; /* get next mask bit (should be branchless on ARM) */ msMask >>= 1; if (++msMaskOffset == 8) { msMask = *msMaskPtr++; msMaskOffset = 0; } } coef += (nSamps - sfbTab[icsInfo->maxSFB]); } sfbCodeBook += icsInfo->maxSFB; scaleFactors += icsInfo->maxSFB; } /* update guard bit count if necessary */ gb = CLZ(gbMask) - 1; if (m_PSInfoBase->gbCurrent[ch] > gb) m_PSInfoBase->gbCurrent[ch] = gb; return 0; } /*********************************************************************************************************************** * Function: GetSampRateIdx * * Description: get index of given sample rate * * Inputs: sample rate (in Hz) * * Outputs: none * * Return: index of sample rate (table 1.15 in 14496-3:2001(E)) * -1 if sample rate not found in table **********************************************************************************************************************/ int GetSampRateIdx(int sampRate) { int idx; for (idx = 0; idx < NUM_SAMPLE_RATES; idx++) { if (sampRate == sampRateTab[idx]) return idx; } return -1; } /*********************************************************************************************************************** * Function: StereoProcessGroup * * Description: apply mid-side and intensity stereo to group of transform coefficients * * Inputs: dequantized transform coefficients for both channels * pointer to appropriate scalefactor band table * mid-side mask enabled flag * buffer with mid-side mask (one bit for each scalefactor band) * bit offset into mid-side mask buffer * max coded scalefactor band * buffer of codebook indices for right channel * buffer of scalefactors for right channel, range = [0, 256] * * Outputs: updated transform coefficients in Q(FBITS_OUT_DQ_OFF) * updated minimum guard bit count for both channels * * Return: none * * Notes: assume no guard bits in input * gains 0 int bits **********************************************************************************************************************/ void StereoProcessGroup(int *coefL, int *coefR, const uint16_t *sfbTab, int msMaskPres, uint8_t *msMaskPtr, int msMaskOffset, int maxSFB, uint8_t *cbRight, short *sfRight, int *gbCurrent) { //fb static const uint32_t pow14[2][4] PROGMEM = { { 0xc0000000, 0xb3e407d7, 0xa57d8666, 0x945d819b }, { 0x40000000, 0x4c1bf829, 0x5a82799a, 0x6ba27e65 } }; int sfb, width, cbIdx, sf, cl, cr, scalef, scalei; int gbMaskL, gbMaskR; uint8_t msMask; msMask = (*msMaskPtr++) >> msMaskOffset; gbMaskL = 0; gbMaskR = 0; for (sfb = 0; sfb < maxSFB; sfb++) { width = sfbTab[sfb+1] - sfbTab[sfb]; /* assume >= 0 (see sfBandTabLong/sfBandTabShort) */ cbIdx = cbRight[sfb]; if (cbIdx == 14 || cbIdx == 15) { /* intensity stereo */ if (msMaskPres == 1 && (msMask & 0x01)) cbIdx ^= 0x01; /* invert_intensity(): 14 becomes 15, or 15 becomes 14 */ sf = -sfRight[sfb]; /* negative since we use identity 0.5^(x) = 2^(-x) (see spec) */ cbIdx &= 0x01; /* choose - or + scale factor */ scalef = pow14[cbIdx][sf & 0x03]; scalei = (sf >> 2) + 2; /* +2 to compensate for scalef = Q30 */ if (scalei > 0) { if (scalei > 30) scalei = 30; do { cr = MULSHIFT32(*coefL++, scalef); {int sign = (cr) >> 31; if (sign != (cr) >> (31-scalei)) {(cr) = sign ^ ((1 << (31-scalei)) - 1);}} cr <<= scalei; gbMaskR |= FASTABS(cr); *coefR++ = cr; } while (--width); } else { scalei = -scalei; if (scalei > 31) scalei = 31; do { cr = MULSHIFT32(*coefL++, scalef) >> scalei; gbMaskR |= FASTABS(cr); *coefR++ = cr; } while (--width); } } else if ( cbIdx != 13 && ((msMaskPres == 1 && (msMask & 0x01)) || msMaskPres == 2) ) { /* mid-side stereo (assumes no GB in inputs) */ do { cl = *coefL; cr = *coefR; if ( (FASTABS(cl) | FASTABS(cr)) >> 30 ) { /* avoid overflow (rare) */ cl >>= 1; sf = cl + (cr >> 1); {int sign = (sf) >> 31; if (sign != (sf) >> (30)) {(sf) = sign ^ ((1 << (30)) - 1);}} sf <<= 1; cl = cl - (cr >> 1); {int sign = (cl) >> 31; if (sign != (cl) >> (30)) {(cl) = sign ^ ((1 << (30)) - 1);}} cl <<= 1; } else { /* usual case */ sf = cl + cr; cl -= cr; } *coefL++ = sf; gbMaskL |= FASTABS(sf); *coefR++ = cl; gbMaskR |= FASTABS(cl); } while (--width); } else { /* nothing to do */ coefL += width; coefR += width; } /* get next mask bit (should be branchless on ARM) */ msMask >>= 1; if (++msMaskOffset == 8) { msMask = *msMaskPtr++; msMaskOffset = 0; } } cl = CLZ(gbMaskL) - 1; if (gbCurrent[0] > cl) gbCurrent[0] = cl; cr = CLZ(gbMaskR) - 1; if (gbCurrent[1] > cr) gbCurrent[1] = cr; return; } /*********************************************************************************************************************** * Function: StereoProcess * * Description: apply mid-side and intensity stereo, if enabled * * Inputs: none * * Outputs: updated transform coefficients in Q(FBITS_OUT_DQ_OFF) * updated minimum guard bit count for both channels * * Return: 0 if successful, -1 if error **********************************************************************************************************************/ int StereoProcess() { ICSInfo_t *icsInfo; int gp, win, nSamps, msMaskOffset; int *coefL, *coefR; uint8_t *msMaskPtr; const uint16_t *sfbTab; /* mid-side and intensity stereo require common_window == 1 (see MPEG4 spec, Correction 2, 2004) */ if (m_PSInfoBase->commonWin != 1 || m_AACDecInfo->currBlockID != AAC_ID_CPE) return 0; /* nothing to do */ if (!m_PSInfoBase->msMaskPresent && !m_PSInfoBase->intensityUsed[1]) return 0; icsInfo = &(m_PSInfoBase->icsInfo[0]); if (icsInfo->winSequence == 2) { sfbTab = sfBandTabShort + sfBandTabShortOffset[m_PSInfoBase->sampRateIdx]; nSamps = NSAMPS_SHORT; } else { sfbTab = sfBandTabLong + sfBandTabLongOffset[m_PSInfoBase->sampRateIdx]; nSamps = NSAMPS_LONG; } coefL = m_PSInfoBase->coef[0]; coefR = m_PSInfoBase->coef[1]; /* do fused mid-side/intensity processing for each block (one long or eight short) */ msMaskOffset = 0; msMaskPtr = m_PSInfoBase->msMaskBits; for (gp = 0; gp < icsInfo->numWinGroup; gp++) { for (win = 0; win < icsInfo->winGroupLen[gp]; win++) { StereoProcessGroup(coefL, coefR, sfbTab, m_PSInfoBase->msMaskPresent, msMaskPtr, msMaskOffset, icsInfo->maxSFB, m_PSInfoBase->sfbCodeBook[1] + gp*icsInfo->maxSFB, m_PSInfoBase->scaleFactors[1] + gp*icsInfo->maxSFB, m_PSInfoBase->gbCurrent); coefL += nSamps; coefR += nSamps; } /* we use one bit per sfb, so there are maxSFB bits for each window group */ msMaskPtr += (msMaskOffset + icsInfo->maxSFB) >> 3; msMaskOffset = (msMaskOffset + icsInfo->maxSFB) & 0x07; } ASSERT(coefL == m_PSInfoBase->coef[0] + 1024); ASSERT(coefR == m_PSInfoBase->coef[1] + 1024); return 0; } /*********************************************************************************************************************** * Function: RatioPowInv * * Description: use Taylor (MacLaurin) series expansion to calculate (a/b) ^ (1/c) * * Inputs: a = [1, 64], b = [1, 64], c = [1, 64], a >= b * * Outputs: none * * Return: y = Q24, range ~= [0.015625, 64] **********************************************************************************************************************/ int RatioPowInv(int a, int b, int c) { int lna, lnb, i, p, t, y; if (a < 1 || b < 1 || c < 1 || a > 64 || b > 64 || c > 64 || a < b) return 0; lna = MULSHIFT32(log2Tab[a], LOG2_EXP_INV) << 1; /* ln(a), Q28 */ lnb = MULSHIFT32(log2Tab[b], LOG2_EXP_INV) << 1; /* ln(b), Q28 */ p = (lna - lnb) / c; /* Q28 */ /* sum in Q24 */ y = (1 << 24); t = p >> 4; /* t = p^1 * 1/1! (Q24)*/ y += t; for (i = 2; i <= NUM_TERMS_RPI; i++) { t = MULSHIFT32(invTab[i-1], t) << 2; t = MULSHIFT32(p, t) << 4; /* t = p^i * 1/i! (Q24) */ y += t; } return y; } /*********************************************************************************************************************** * Function: SqrtFix * * Description: use binary search to calculate sqrt(q) * * Inputs: q = Q30 * number of fraction bits in input * * Outputs: number of fraction bits in output * * Return: lo = Q(fBitsOut) * * Notes: absolute precision varies depending on fBitsIn * normalizes input to range [0x200000000, 0x7fffffff] and takes * floor(sqrt(input)), and sets fBitsOut appropriately **********************************************************************************************************************/ int SqrtFix(int q, int fBitsIn, int *fBitsOut) { int z, lo, hi, mid; if (q <= 0) { *fBitsOut = fBitsIn; return 0; } /* force even fBitsIn */ z = fBitsIn & 0x01; q >>= z; fBitsIn -= z; /* for max precision, normalize to [0x20000000, 0x7fffffff] */ z = (CLZ(q) - 1); z >>= 1; q <<= (2*z); /* choose initial bounds */ lo = 1; if (q >= 0x10000000) lo = 16384; /* (int)sqrt(0x10000000) */ hi = 46340; /* (int)sqrt(0x7fffffff) */ /* do binary search with 32x32->32 multiply test */ do { mid = (lo + hi) >> 1; if (mid*mid > q) hi = mid - 1; else lo = mid + 1; } while (hi >= lo); lo--; *fBitsOut = ((fBitsIn + 2*z) >> 1); return lo; } /*********************************************************************************************************************** * Function: InvRNormalized * * Description: use Newton's method to solve for x = 1/r * * Inputs: r = Q31, range = [0.5, 1) (normalize your inputs to this range) * * Outputs: none * * Return: x = Q29, range ~= [1.0, 2.0] * * Notes: guaranteed to converge and not overflow for any r in [0.5, 1) * * xn+1 = xn - f(xn)/f'(xn) * f(x) = 1/r - x = 0 (find root) * = 1/x - r * f'(x) = -1/x^2 * * so xn+1 = xn - (1/xn - r) / (-1/xn^2) * = xn * (2 - r*xn) * * NUM_ITER_IRN = 2, maxDiff = 6.2500e-02 (precision of about 4 bits) * NUM_ITER_IRN = 3, maxDiff = 3.9063e-03 (precision of about 8 bits) * NUM_ITER_IRN = 4, maxDiff = 1.5288e-05 (precision of about 16 bits) * NUM_ITER_IRN = 5, maxDiff = 3.0034e-08 (precision of about 24 bits) **********************************************************************************************************************/ int InvRNormalized(int r) { int i, xn, t; /* r = [0.5, 1.0) * 1/r = (1.0, 2.0] * so use 1.5 as initial guess */ xn = Q28_15; /* xn = xn*(2.0 - r*xn) */ for (i = NUM_ITER_IRN; i != 0; i--) { t = MULSHIFT32(r, xn); /* Q31*Q29 = Q28 */ t = Q28_2 - t; /* Q28 */ xn = MULSHIFT32(xn, t) << 4; /* Q29*Q28 << 4 = Q29 */ } return xn; } /*********************************************************************************************************************** * Function: BitReverse32 * * Description: Ken's fast in-place bit reverse * * Inputs: buffer of 32 complex samples * * Outputs: bit-reversed samples in same buffer * * Return: none ***********************************************************************************************************************/ void BitReverse32(int *inout) { int t; t=inout[2] ; inout[2]=inout[32]; inout[32]=t; t=inout[3] ; inout[3]=inout[33]; inout[33]=t; t=inout[4] ; inout[4]=inout[16]; inout[16]=t; t=inout[5] ; inout[5]=inout[17]; inout[17]=t; t=inout[6] ; inout[6]=inout[48]; inout[48]=t; t=inout[7] ; inout[7]=inout[49]; inout[49]=t; t=inout[10]; inout[10]=inout[40]; inout[40]=t; t=inout[11]; inout[11]=inout[41]; inout[41]=t; t=inout[12]; inout[12]=inout[24]; inout[24]=t; t=inout[13]; inout[13]=inout[25]; inout[25]=t; t=inout[14]; inout[14]=inout[56]; inout[56]=t; t=inout[15]; inout[15]=inout[57]; inout[57]=t; t=inout[18]; inout[18]=inout[36]; inout[36]=t; t=inout[19]; inout[19]=inout[37]; inout[37]=t; t=inout[22]; inout[22]=inout[52]; inout[52]=t; t=inout[23]; inout[23]=inout[53]; inout[53]=t; t=inout[26]; inout[26]=inout[44]; inout[44]=t; t=inout[27]; inout[27]=inout[45]; inout[45]=t; t=inout[30]; inout[30]=inout[60]; inout[60]=t; t=inout[31]; inout[31]=inout[61]; inout[61]=t; t=inout[38]; inout[38]=inout[50]; inout[50]=t; t=inout[39]; inout[39]=inout[51]; inout[51]=t; t=inout[46]; inout[46]=inout[58]; inout[58]=t; t=inout[47]; inout[47]=inout[59]; inout[59]=t; } /*********************************************************************************************************************** * Function: R8FirstPass32 * * Description: radix-8 trivial pass for decimation-in-time FFT (log2(N) = 5) * * Inputs: buffer of (bit-reversed) samples * * Outputs: processed samples in same buffer * * Return: none * * Notes: assumes 3 guard bits, gains 1 integer bit * guard bits out = guard bits in - 3 (if inputs are full scale) * or guard bits in - 2 (if inputs bounded to +/- sqrt(2)/2) * see scaling comments in fft.c for base AAC * should compile with no stack spills on ARM (verify compiled output) * current instruction count (per pass): 16 LDR, 16 STR, 4 SMULL, 61 ALU **********************************************************************************************************************/ void R8FirstPass32(int *r0) { int r1, r2, r3, r4, r5, r6, r7; int r8, r9, r10, r11, r12, r14; /* number of passes = fft size / 8 = 32 / 8 = 4 */ r1 = (32 >> 3); do { r2 = r0[8]; r3 = r0[9]; r4 = r0[10]; r5 = r0[11]; r6 = r0[12]; r7 = r0[13]; r8 = r0[14]; r9 = r0[15]; r10 = r2 + r4; r11 = r3 + r5; r12 = r6 + r8; r14 = r7 + r9; r2 -= r4; r3 -= r5; r6 -= r8; r7 -= r9; r4 = r2 - r7; r5 = r2 + r7; r8 = r3 - r6; r9 = r3 + r6; r2 = r4 - r9; r3 = r4 + r9; r6 = r5 - r8; r7 = r5 + r8; r2 = MULSHIFT32(SQRTHALF, r2); /* can use r4, r5, r8, or r9 for constant and lo32 scratch reg */ r3 = MULSHIFT32(SQRTHALF, r3); r6 = MULSHIFT32(SQRTHALF, r6); r7 = MULSHIFT32(SQRTHALF, r7); r4 = r10 + r12; r5 = r10 - r12; r8 = r11 + r14; r9 = r11 - r14; r10 = r0[0]; r11 = r0[2]; r12 = r0[4]; r14 = r0[6]; r10 += r11; r12 += r14; r4 >>= 1; r10 += r12; r4 += (r10 >> 1); r0[ 0] = r4; r4 -= (r10 >> 1); r4 = (r10 >> 1) - r4; r0[ 8] = r4; r9 >>= 1; r10 -= 2*r12; r4 = (r10 >> 1) + r9; r0[ 4] = r4; r4 = (r10 >> 1) - r9; r0[12] = r4; r10 += r12; r10 -= 2*r11; r12 -= 2*r14; r4 = r0[1]; r9 = r0[3]; r11 = r0[5]; r14 = r0[7]; r4 += r9; r11 += r14; r8 >>= 1; r4 += r11; r8 += (r4 >> 1); r0[ 1] = r8; r8 -= (r4 >> 1); r8 = (r4 >> 1) - r8; r0[ 9] = r8; r5 >>= 1; r4 -= 2*r11; r8 = (r4 >> 1) - r5; r0[ 5] = r8; r8 = (r4 >> 1) + r5; r0[13] = r8; r4 += r11; r4 -= 2*r9; r11 -= 2*r14; r9 = r10 - r11; r10 += r11; r14 = r4 + r12; r4 -= r12; r5 = (r10 >> 1) + r7; r8 = (r4 >> 1) - r6; r0[ 2] = r5; r0[ 3] = r8; r5 = (r9 >> 1) - r2; r8 = (r14 >> 1) - r3; r0[ 6] = r5; r0[ 7] = r8; r5 = (r10 >> 1) - r7; r8 = (r4 >> 1) + r6; r0[10] = r5; r0[11] = r8; r5 = (r9 >> 1) + r2; r8 = (r14 >> 1) + r3; r0[14] = r5; r0[15] = r8; r0 += 16; r1--; } while (r1 != 0); } /*********************************************************************************************************************** * Function: R4Core32 * * Description: radix-4 pass for 32-point decimation-in-time FFT * * Inputs: buffer of samples * * Outputs: processed samples in same buffer * * Return: none * * Notes: gain 2 integer bits * guard bits out = guard bits in - 1 (if inputs are full scale) * see scaling comments in fft.c for base AAC * uses 3-mul, 3-add butterflies instead of 4-mul, 2-add * should compile with no stack spills on ARM (verify compiled output) * current instruction count (per pass): 16 LDR, 16 STR, 4 SMULL, 61 ALU **********************************************************************************************************************/ void R4Core32(int *r0) { int r2, r3, r4, r5, r6, r7; int r8, r9, r10, r12, r14; int *r1; r1 = (int *)twidTabOdd32; r10 = 8; do { /* can use r14 for lo32 scratch register in all MULSHIFT32 */ r2 = r1[0]; r3 = r1[1]; r4 = r0[16]; r5 = r0[17]; r12 = r4 + r5; r12 = MULSHIFT32(r3, r12); r5 = MULSHIFT32(r2, r5) + r12; r2 += 2*r3; r4 = MULSHIFT32(r2, r4) - r12; r2 = r1[2]; r3 = r1[3]; r6 = r0[32]; r7 = r0[33]; r12 = r6 + r7; r12 = MULSHIFT32(r3, r12); r7 = MULSHIFT32(r2, r7) + r12; r2 += 2*r3; r6 = MULSHIFT32(r2, r6) - r12; r2 = r1[4]; r3 = r1[5]; r8 = r0[48]; r9 = r0[49]; r12 = r8 + r9; r12 = MULSHIFT32(r3, r12); r9 = MULSHIFT32(r2, r9) + r12; r2 += 2*r3; r8 = MULSHIFT32(r2, r8) - r12; r2 = r0[0]; r3 = r0[1]; r12 = r6 + r8; r8 = r6 - r8; r14 = r9 - r7; r9 = r9 + r7; r6 = (r2 >> 2) - r4; r7 = (r3 >> 2) - r5; r4 += (r2 >> 2); r5 += (r3 >> 2); r2 = r4 + r12; r3 = r5 + r9; r0[0] = r2; r0[1] = r3; r2 = r6 - r14; r3 = r7 - r8; r0[16] = r2; r0[17] = r3; r2 = r4 - r12; r3 = r5 - r9; r0[32] = r2; r0[33] = r3; r2 = r6 + r14; r3 = r7 + r8; r0[48] = r2; r0[49] = r3; r0 += 2; r1 += 6; r10--; } while (r10 != 0); } /*********************************************************************************************************************** * Function: FFT32C * * Description: Ken's very fast in-place radix-4 decimation-in-time FFT * * Inputs: buffer of 32 complex samples (before bit-reversal) * * Outputs: processed samples in same buffer * * Return: none * * Notes: assumes 3 guard bits in, gains 3 integer bits * guard bits out = guard bits in - 2 * (guard bit analysis includes assumptions about steps immediately * before and after, i.e. PreMul and PostMul for DCT) **********************************************************************************************************************/ void FFT32C(int *x) { /* decimation in time */ BitReverse32(x); /* 32-point complex FFT */ R8FirstPass32(x); /* gain 1 int bit, lose 2 GB (making assumptions about input) */ R4Core32(x); /* gain 2 int bits, lose 0 GB (making assumptions about input) */ } /*********************************************************************************************************************** * Function: CVKernel1 * * Description: kernel of covariance matrix calculation for p01, p11, p12, p22 * * Inputs: buffer of low-freq samples, starting at time index = 0, * freq index = patch subband * * Outputs: 64-bit accumulators for p01re, p01im, p12re, p12im, p11re, p22re * stored in accBuf * * Return: none * * Notes: this is carefully written to be efficient on ARM * use the assembly code version in sbrcov.s when building for ARM! **********************************************************************************************************************/ void CVKernel1(int *XBuf, int *accBuf) { U64 p01re, p01im, p12re, p12im, p11re, p22re; int n, x0re, x0im, x1re, x1im; x0re = XBuf[0]; x0im = XBuf[1]; XBuf += (2*64); x1re = XBuf[0]; x1im = XBuf[1]; XBuf += (2*64); p01re.w64 = p01im.w64 = 0; p12re.w64 = p12im.w64 = 0; p11re.w64 = 0; p22re.w64 = 0; p12re.w64 = MADD64(p12re.w64, x1re, x0re); p12re.w64 = MADD64(p12re.w64, x1im, x0im); p12im.w64 = MADD64(p12im.w64, x0re, x1im); p12im.w64 = MADD64(p12im.w64, -x0im, x1re); p22re.w64 = MADD64(p22re.w64, x0re, x0re); p22re.w64 = MADD64(p22re.w64, x0im, x0im); for (n = (NUM_TIME_SLOTS*SAMPLES_PER_SLOT + 6); n != 0; n--) { /* 4 input, 3*2 acc, 1 ptr, 1 loop counter = 12 registers (use same for x0im, -x0im) */ x0re = x1re; x0im = x1im; x1re = XBuf[0]; x1im = XBuf[1]; p01re.w64 = MADD64(p01re.w64, x1re, x0re); p01re.w64 = MADD64(p01re.w64, x1im, x0im); p01im.w64 = MADD64(p01im.w64, x0re, x1im); p01im.w64 = MADD64(p01im.w64, -x0im, x1re); p11re.w64 = MADD64(p11re.w64, x0re, x0re); p11re.w64 = MADD64(p11re.w64, x0im, x0im); XBuf += (2*64); } /* these can be derived by slight changes to account for boundary conditions */ p12re.w64 += p01re.w64; p12re.w64 = MADD64(p12re.w64, x1re, -x0re); p12re.w64 = MADD64(p12re.w64, x1im, -x0im); p12im.w64 += p01im.w64; p12im.w64 = MADD64(p12im.w64, x0re, -x1im); p12im.w64 = MADD64(p12im.w64, x0im, x1re); p22re.w64 += p11re.w64; p22re.w64 = MADD64(p22re.w64, x0re, -x0re); p22re.w64 = MADD64(p22re.w64, x0im, -x0im); accBuf[0] = p01re.r.lo32; accBuf[1] = p01re.r.hi32; accBuf[2] = p01im.r.lo32; accBuf[3] = p01im.r.hi32; accBuf[4] = p11re.r.lo32; accBuf[5] = p11re.r.hi32; accBuf[6] = p12re.r.lo32; accBuf[7] = p12re.r.hi32; accBuf[8] = p12im.r.lo32; accBuf[9] = p12im.r.hi32; accBuf[10] = p22re.r.lo32; accBuf[11] = p22re.r.hi32; } /*********************************************************************************************************************** * Function: CVKernel2 * * Description: kernel of covariance matrix calculation for p02 * * Inputs: buffer of low-freq samples, starting at time index = 0, * freq index = patch subband * * Outputs: 64-bit accumulators for p02re, p02im stored in accBuf * * Return: none * * Notes: this is carefully written to be efficient on ARM * use the assembly code version in sbrcov.s when building for ARM! **********************************************************************************************************************/ void CVKernel2(int *XBuf, int *accBuf) { U64 p02re, p02im; int n, x0re, x0im, x1re, x1im, x2re, x2im; p02re.w64 = p02im.w64 = 0; x0re = XBuf[0]; x0im = XBuf[1]; XBuf += (2*64); x1re = XBuf[0]; x1im = XBuf[1]; XBuf += (2*64); for (n = (NUM_TIME_SLOTS*SAMPLES_PER_SLOT + 6); n != 0; n--) { /* 6 input, 2*2 acc, 1 ptr, 1 loop counter = 12 registers (use same for x0im, -x0im) */ x2re = XBuf[0]; x2im = XBuf[1]; p02re.w64 = MADD64(p02re.w64, x2re, x0re); p02re.w64 = MADD64(p02re.w64, x2im, x0im); p02im.w64 = MADD64(p02im.w64, x0re, x2im); p02im.w64 = MADD64(p02im.w64, -x0im, x2re); x0re = x1re; x0im = x1im; x1re = x2re; x1im = x2im; XBuf += (2*64); } accBuf[0] = p02re.r.lo32; accBuf[1] = p02re.r.hi32; accBuf[2] = p02im.r.lo32; accBuf[3] = p02im.r.hi32; } /*********************************************************************************************************************** * Function: SetBitstreamPointer * * Description: initialize bitstream reader * * Inputs: number of bytes in bitstream * pointer to byte-aligned buffer of data to read from * * Outputs: initialized bitstream info struct * * Return: none **********************************************************************************************************************/ void SetBitstreamPointer(int nBytes, uint8_t *buf) { /* init bitstream */ m_aac_BitStreamInfo.bytePtr = buf; m_aac_BitStreamInfo.iCache = 0; /* 4-byte uint32_t */ m_aac_BitStreamInfo.cachedBits = 0; /* i.e. zero bits in cache */ m_aac_BitStreamInfo.nBytes = nBytes; } /*********************************************************************************************************************** * Function: RefillBitstreamCache * * Description: read new data from bitstream buffer into 32-bit cache * * Inputs: none * * Outputs: updated bitstream info struct * * Return: none * * Notes: only call when iCache is completely drained (resets bitOffset to 0) * always loads 4 new bytes except when bsi->nBytes < 4 (end of buffer) * stores data as big-endian in cache, regardless of machine endian-ness **********************************************************************************************************************/ //Optimized for REV16, REV32 (FB) inline void RefillBitstreamCache() { int nBytes = m_aac_BitStreamInfo.nBytes; if (nBytes >= 4) { /* optimize for common case, independent of machine endian-ness */ m_aac_BitStreamInfo.iCache = (*m_aac_BitStreamInfo.bytePtr++) << 24; m_aac_BitStreamInfo.iCache |= (*m_aac_BitStreamInfo.bytePtr++) << 16; m_aac_BitStreamInfo.iCache |= (*m_aac_BitStreamInfo.bytePtr++) << 8; m_aac_BitStreamInfo.iCache |= (*m_aac_BitStreamInfo.bytePtr++); m_aac_BitStreamInfo.cachedBits = 32; m_aac_BitStreamInfo.nBytes -= 4; } else { m_aac_BitStreamInfo.iCache = 0; while (nBytes--) { m_aac_BitStreamInfo.iCache |= (*m_aac_BitStreamInfo.bytePtr++); m_aac_BitStreamInfo.iCache <<= 8; } m_aac_BitStreamInfo.iCache <<= ((3 - m_aac_BitStreamInfo.nBytes)*8); m_aac_BitStreamInfo.cachedBits = 8*m_aac_BitStreamInfo.nBytes; m_aac_BitStreamInfo.nBytes = 0; } } /*********************************************************************************************************************** * Function: GetBits * * Description: get bits from bitstream, advance bitstream pointer * * Inputs: pointer to initialized aac_BitStreamInfo_t struct * number of bits to get from bitstream * * Outputs: updated bitstream info struct * * Return: the next nBits bits of data from bitstream buffer * * Notes: nBits must be in range [0, 31], nBits outside this range masked by 0x1f * for speed, does not indicate error if you overrun bit buffer * if nBits == 0, returns 0 **********************************************************************************************************************/ unsigned int GetBits(int nBits) { uint32_t data, lowBits; nBits &= 0x1f; /* nBits mod 32 to avoid unpredictable results like >> by negative amount */ data = m_aac_BitStreamInfo.iCache >> (31 - nBits); /* unsigned >> so zero-extend */ data >>= 1; /* do as >> 31, >> 1 so that nBits = 0 works okay (returns 0) */ m_aac_BitStreamInfo.iCache <<= nBits; /* left-justify cache */ m_aac_BitStreamInfo.cachedBits -= nBits; /* how many bits have we drawn from the cache so far */ /* if we cross an int boundary, refill the cache */ if (m_aac_BitStreamInfo.cachedBits < 0) { lowBits = -m_aac_BitStreamInfo.cachedBits; RefillBitstreamCache(); data |= m_aac_BitStreamInfo.iCache >> (32 - lowBits); /* get the low-order bits */ m_aac_BitStreamInfo.cachedBits -= lowBits; /* how many bits have we drawn from the cache so far */ m_aac_BitStreamInfo.iCache <<= lowBits; /* left-justify cache */ } return data; } /*********************************************************************************************************************** * Function: GetBitsNoAdvance * * Description: get bits from bitstream, do not advance bitstream pointer * * Inputs: pointer to initialized aac_BitStreamInfo_t struct * number of bits to get from bitstream * * Outputs: none (state of aac_BitStreamInfo_t struct left unchanged) * * Return: the next nBits bits of data from bitstream buffer * * Notes: nBits must be in range [0, 31], nBits outside this range masked by 0x1f * for speed, does not indicate error if you overrun bit buffer * if nBits == 0, returns 0 **********************************************************************************************************************/ unsigned int GetBitsNoAdvance(int nBits) { uint8_t *buf; uint32_t data, iCache; int32_t lowBits; nBits &= 0x1f; /* nBits mod 32 to avoid unpredictable results like >> by negative amount */ data = m_aac_BitStreamInfo.iCache >> (31 - nBits); /* unsigned >> so zero-extend */ data >>= 1; /* do as >> 31, >> 1 so that nBits = 0 works okay (returns 0) */ lowBits = nBits - m_aac_BitStreamInfo.cachedBits; /* how many bits do we have left to read */ /* if we cross an int boundary, read next bytes in buffer */ if (lowBits > 0) { iCache = 0; buf = m_aac_BitStreamInfo.bytePtr; while (lowBits > 0) { iCache <<= 8; if (buf < m_aac_BitStreamInfo.bytePtr + m_aac_BitStreamInfo.nBytes) iCache |= (uint32_t)*buf++; lowBits -= 8; } lowBits = -lowBits; data |= iCache >> lowBits; } return data; } /*********************************************************************************************************************** * Function: AdvanceBitstream * * Description: move bitstream pointer ahead * * Inputs: number of bits to advance bitstream * * Outputs: updated bitstream info struct * * Return: none * * Notes: generally used following GetBitsNoAdvance(bsi, maxBits) **********************************************************************************************************************/ void AdvanceBitstream(int nBits) { nBits &= 0x1f; if (nBits > m_aac_BitStreamInfo.cachedBits) { nBits -= m_aac_BitStreamInfo.cachedBits; RefillBitstreamCache(); } m_aac_BitStreamInfo.iCache <<= nBits; m_aac_BitStreamInfo.cachedBits -= nBits; } /*********************************************************************************************************************** * Function: CalcBitsUsed * * Description: calculate how many bits have been read from bitstream * * Inputs: pointer to start of bitstream buffer * bit offset into first byte of startBuf (0-7) * * Outputs: none * * Return: number of bits read from bitstream, as offset from startBuf:startOffset **********************************************************************************************************************/ int CalcBitsUsed(uint8_t *startBuf, int startOffset) { int bitsUsed; bitsUsed = (m_aac_BitStreamInfo.bytePtr - startBuf) * 8; bitsUsed -= m_aac_BitStreamInfo.cachedBits; bitsUsed -= startOffset; return bitsUsed; } /*********************************************************************************************************************** * Function: ByteAlignBitstream * * Description: bump bitstream pointer to start of next byte * * Inputs: none * * Outputs: byte-aligned bitstream aac_BitStreamInfo_t struct * * Return: none * * Notes: if bitstream is already byte-aligned, do nothing **********************************************************************************************************************/ void ByteAlignBitstream(){ int offset; offset = m_aac_BitStreamInfo.cachedBits & 0x07; AdvanceBitstream(offset); } #ifdef AAC_ENABLE_SBR /************************************************************************************** * Function: InitSBRState * * Description: initialize PSInfoSBR struct at start of stream or after flush * * Inputs: valid AACDecInfo struct * * Outputs: PSInfoSBR struct with proper initial state * * Return: none **************************************************************************************/ void InitSBRState() { int i, ch; uint8_t *c; if (!m_PSInfoSBR) return; /* clear SBR state structure */ c = (uint8_t *)m_PSInfoSBR; for (i = 0; i < (int)sizeof(m_PSInfoSBR); i++) *c++ = 0; /* initialize non-zero state variables */ for (ch = 0; ch < AAC_MAX_NCHANS; ch++) { m_PSInfoSBR->sbrChan[ch].reset = 1; m_PSInfoSBR->sbrChan[ch].laPrev = -1; } } #endif /*********************************************************************************************************************** * Function: DecodeSBRBitstream * * Description: decode sideband information for SBR * * Inputs: base output channel (range = [0, nChans-1]) * * Outputs: initialized state structs (SBRHdr, SBRGrid, SBRFreq, SBRChan) * * Return: 0 if successful, error code (< 0) if error * * Notes: SBR payload should be in aacDecInfo->fillBuf * returns with no error if fill buffer is not an SBR extension block, * or if current block is not a fill block (e.g. for LFE upsampling) **********************************************************************************************************************/ int DecodeSBRBitstream(int chBase) { int headerFlag; if(m_AACDecInfo->currBlockID != AAC_ID_FIL || (m_AACDecInfo->fillExtType != EXT_SBR_DATA && m_AACDecInfo->fillExtType != EXT_SBR_DATA_CRC)) return ERR_AAC_NONE; SetBitstreamPointer(m_AACDecInfo->fillCount, m_AACDecInfo->fillBuf); if(GetBits(4) != (unsigned int) m_AACDecInfo->fillExtType) return ERR_AAC_SBR_BITSTREAM; if(m_AACDecInfo->fillExtType == EXT_SBR_DATA_CRC) m_PSInfoSBR->crcCheckWord = GetBits(10); headerFlag = GetBits(1); if(headerFlag) { /* get sample rate index for output sample rate (2x base rate) */ m_PSInfoSBR->sampRateIdx = GetSampRateIdx(2 * m_AACDecInfo->sampRate); if(m_PSInfoSBR->sampRateIdx < 0 || m_PSInfoSBR->sampRateIdx >= NUM_SAMPLE_RATES) return ERR_AAC_SBR_BITSTREAM; else if(m_PSInfoSBR->sampRateIdx >= NUM_SAMPLE_RATES_SBR) return ERR_AAC_SBR_SINGLERATE_UNSUPPORTED; /* reset flag = 1 if header values changed */ if(UnpackSBRHeader(&(m_PSInfoSBR->sbrHdr[chBase]))) m_PSInfoSBR->sbrChan[chBase].reset = 1; /* first valid SBR header should always trigger CalcFreqTables(), since psi->reset was set in InitSBR() */ if(m_PSInfoSBR->sbrChan[chBase].reset) CalcFreqTables(&(m_PSInfoSBR->sbrHdr[chBase + 0]), &(m_PSInfoSBR->sbrFreq[chBase]), m_PSInfoSBR->sampRateIdx); /* copy and reset state to right channel for CPE */ if(m_AACDecInfo->prevBlockID == AAC_ID_CPE) m_PSInfoSBR->sbrChan[chBase + 1].reset = m_PSInfoSBR->sbrChan[chBase + 0].reset; } /* if no header has been received, upsample only */ if(m_PSInfoSBR->sbrHdr[chBase].count == 0) return ERR_AAC_NONE; if(m_AACDecInfo->prevBlockID == AAC_ID_SCE) { UnpackSBRSingleChannel(chBase); } else if(m_AACDecInfo->prevBlockID == AAC_ID_CPE) { UnpackSBRChannelPair(chBase); } else { return ERR_AAC_SBR_BITSTREAM; } ByteAlignBitstream(); return ERR_AAC_NONE; } #ifdef AAC_ENABLE_SBR /*********************************************************************************************************************** * Function: DecodeSBRData * * Description: apply SBR to one frame of PCM data * * Inputs: 1024 samples of decoded 32-bit PCM, before SBR * size of input PCM samples (must be 4 bytes) * number of fraction bits in input PCM samples * base output channel (range = [0, nChans-1]) * initialized state structs (SBRHdr, SBRGrid, SBRFreq, SBRChan) * * Outputs: 2048 samples of decoded 16-bit PCM, after SBR * * Return: 0 if successful, error code (< 0) if error **********************************************************************************************************************/ int DecodeSBRData(int chBase, short *outbuf) { int k, l, ch, chBlock, qmfaBands, qmfsBands; int upsampleOnly, gbIdx, gbMask; int *inbuf; short *outptr; SBRHeader *sbrHdr; SBRGrid *sbrGrid; SBRFreq *sbrFreq; SBRChan *sbrChan; /* same header and freq tables for both channels in CPE */ sbrHdr = &(m_PSInfoSBR->sbrHdr[chBase]); sbrFreq = &(m_PSInfoSBR->sbrFreq[chBase]); /* upsample only if we haven't received an SBR header yet or if we have an LFE block */ if(m_AACDecInfo->currBlockID == AAC_ID_LFE) { chBlock = 1; upsampleOnly = 1; } else if(m_AACDecInfo->currBlockID == AAC_ID_FIL) { if(m_AACDecInfo->prevBlockID == AAC_ID_SCE) chBlock = 1; else if(m_AACDecInfo->prevBlockID == AAC_ID_CPE) chBlock = 2; else return ERR_AAC_NONE; upsampleOnly = (sbrHdr->count == 0 ? 1 : 0); if(m_AACDecInfo->fillExtType != EXT_SBR_DATA && m_AACDecInfo->fillExtType != EXT_SBR_DATA_CRC) return ERR_AAC_NONE; } else { /* ignore non-SBR blocks */ return ERR_AAC_NONE; } if(upsampleOnly) { sbrFreq->kStart = 32; sbrFreq->numQMFBands = 0; } for(ch = 0; ch < chBlock; ch++) { sbrGrid = &(m_PSInfoSBR->sbrGrid[chBase + ch]); sbrChan = &(m_PSInfoSBR->sbrChan[chBase + ch]); if(m_AACDecInfo->rawSampleBuf[ch] == 0 || m_AACDecInfo->rawSampleBytes != 4) return ERR_AAC_SBR_PCM_FORMAT; inbuf = (int*) m_AACDecInfo->rawSampleBuf[ch]; outptr = outbuf + chBase + ch; /* restore delay buffers (could use ring buffer or keep in temp buffer for nChans == 1) */ for(l = 0; l < HF_GEN; l++) { for(k = 0; k < 64; k++) { m_PSInfoSBR->XBuf[l][k][0] = m_PSInfoSBR->XBufDelay[chBase + ch][l][k][0]; m_PSInfoSBR->XBuf[l][k][1] = m_PSInfoSBR->XBufDelay[chBase + ch][l][k][1]; } } /* step 1 - analysis QMF */ qmfaBands = sbrFreq->kStart; for(l = 0; l < 32; l++) { gbMask = QMFAnalysis(inbuf + l * 32, m_PSInfoSBR->delayQMFA[chBase + ch], m_PSInfoSBR->XBuf[l + HF_GEN][0], m_AACDecInfo->rawSampleFBits, &(m_PSInfoSBR->delayIdxQMFA[chBase + ch]), qmfaBands); gbIdx = ((l + HF_GEN) >> 5) & 0x01; sbrChan->gbMask[gbIdx] |= gbMask; /* gbIdx = (0 if i < 32), (1 if i >= 32) */ } if(upsampleOnly) { /* no SBR - just run synthesis QMF to upsample by 2x */ qmfsBands = 32; for(l = 0; l < 32; l++) { /* step 4 - synthesis QMF */ QMFSynthesis(m_PSInfoSBR->XBuf[l + HF_ADJ][0], m_PSInfoSBR->delayQMFS[chBase + ch], &(m_PSInfoSBR->delayIdxQMFS[chBase + ch]), qmfsBands, outptr, m_AACDecInfo->nChans); outptr += 64 * m_AACDecInfo->nChans; } } else { /* if previous frame had lower SBR starting freq than current, zero out the synthesized QMF * bands so they aren't used as sources for patching * after patch generation, restore from delay buffer * can only happen after header reset */ for(k = sbrFreq->kStartPrev; k < sbrFreq->kStart; k++) { for(l = 0; l < sbrGrid->envTimeBorder[0] + HF_ADJ; l++) { m_PSInfoSBR->XBuf[l][k][0] = 0; m_PSInfoSBR->XBuf[l][k][1] = 0; } } /* step 2 - HF generation */ GenerateHighFreq(sbrGrid, sbrFreq, sbrChan, ch); /* restore SBR bands that were cleared before patch generation (time slots 0, 1 no longer needed) */ for(k = sbrFreq->kStartPrev; k < sbrFreq->kStart; k++) { for(l = HF_ADJ; l < sbrGrid->envTimeBorder[0] + HF_ADJ; l++) { m_PSInfoSBR->XBuf[l][k][0] = m_PSInfoSBR->XBufDelay[chBase + ch][l][k][0]; m_PSInfoSBR->XBuf[l][k][1] = m_PSInfoSBR->XBufDelay[chBase + ch][l][k][1]; } } /* step 3 - HF adjustment */ AdjustHighFreq(sbrHdr, sbrGrid, sbrFreq, sbrChan, ch); /* step 4 - synthesis QMF */ qmfsBands = sbrFreq->kStartPrev + sbrFreq->numQMFBandsPrev; for(l = 0; l < sbrGrid->envTimeBorder[0]; l++) { /* if new envelope starts mid-frame, use old settings until start of first envelope in this frame */ QMFSynthesis(m_PSInfoSBR->XBuf[l + HF_ADJ][0], m_PSInfoSBR->delayQMFS[chBase + ch], &(m_PSInfoSBR->delayIdxQMFS[chBase + ch]), qmfsBands, outptr, m_AACDecInfo->nChans); outptr += 64 * m_AACDecInfo->nChans; } qmfsBands = sbrFreq->kStart + sbrFreq->numQMFBands; for(; l < 32; l++) { /* use new settings for rest of frame (usually the entire frame, unless the first envelope starts mid-frame) */ QMFSynthesis(m_PSInfoSBR->XBuf[l + HF_ADJ][0], m_PSInfoSBR->delayQMFS[chBase + ch], &(m_PSInfoSBR->delayIdxQMFS[chBase + ch]), qmfsBands, outptr, m_AACDecInfo->nChans); outptr += 64 * m_AACDecInfo->nChans; } } /* save delay */ for(l = 0; l < HF_GEN; l++) { for(k = 0; k < 64; k++) { m_PSInfoSBR->XBufDelay[chBase + ch][l][k][0] = m_PSInfoSBR->XBuf[l + 32][k][0]; m_PSInfoSBR->XBufDelay[chBase + ch][l][k][1] = m_PSInfoSBR->XBuf[l + 32][k][1]; } } sbrChan->gbMask[0] = sbrChan->gbMask[1]; sbrChan->gbMask[1] = 0; if(sbrHdr->count > 0) sbrChan->reset = 0; } sbrFreq->kStartPrev = sbrFreq->kStart; sbrFreq->numQMFBandsPrev = sbrFreq->numQMFBands; if(m_AACDecInfo->nChans > 0 && (chBase + ch) == m_AACDecInfo->nChans) m_PSInfoSBR->frameCount++; return ERR_AAC_NONE; } #endif /*********************************************************************************************************************** * Function: BubbleSort * * Description: in-place sort of uint8_ts * * Inputs: buffer of elements to sort * number of elements to sort * * Outputs: sorted buffer * * Return: none **********************************************************************************************************************/ void BubbleSort(uint8_t *v, int nItems) { int i; uint8_t t; while(nItems >= 2) { for(i = 0; i < nItems - 1; i++) { if(v[i + 1] < v[i]) { t = v[i + 1]; v[i + 1] = v[i]; v[i] = t; } } nItems--; } } /*********************************************************************************************************************** * Function: VMin * * Description: find smallest element in a buffer of uint8_ts * * Inputs: buffer of elements to search * number of elements to search * * Outputs: none * * Return: smallest element in buffer **********************************************************************************************************************/ uint8_t VMin(uint8_t *v, int nItems) { int i; uint8_t vMin; vMin = v[0]; for(i = 1; i < nItems; i++) { if(v[i] < vMin) vMin = v[i]; } return vMin; } /*********************************************************************************************************************** * Function: VMax * * Description: find largest element in a buffer of uint8_ts * * Inputs: buffer of elements to search * number of elements to search * * Outputs: none * * Return: largest element in buffer **********************************************************************************************************************/ uint8_t VMax(uint8_t *v, int nItems) { int i; uint8_t vMax; vMax = v[0]; for(i = 1; i < nItems; i++) { if(v[i] > vMax) vMax = v[i]; } return vMax; } /*********************************************************************************************************************** * Function: CalcFreqMasterScaleZero * * Description: calculate master frequency table when freqScale == 0 * (4.6.18.3.2.1, figure 4.39) * * Inputs: alterScale flag * index of first QMF subband in master freq table (k0) * index of last QMF subband (k2) * * Outputs: master frequency table * * Return: number of bands in master frequency table * * Notes: assumes k2 - k0 <= 48 and k2 >= k0 (4.6.18.3.6) **********************************************************************************************************************/ int CalcFreqMasterScaleZero(uint8_t *freqMaster, int alterScale, int k0, int k2) { int nMaster, k, nBands, k2Achieved, dk, vDk[64], k2Diff; if(alterScale) { dk = 2; nBands = 2 * ((k2 - k0 + 2) >> 2); } else { dk = 1; nBands = 2 * ((k2 - k0) >> 1); } if(nBands <= 0) return 0; k2Achieved = k0 + nBands * dk; k2Diff = k2 - k2Achieved; for(k = 0; k < nBands; k++) vDk[k] = dk; if(k2Diff > 0) { k = nBands - 1; while(k2Diff) { vDk[k]++; k--; k2Diff--; } } else if(k2Diff < 0) { k = 0; while(k2Diff) { vDk[k]--; k++; k2Diff++; } } nMaster = nBands; freqMaster[0] = k0; for(k = 1; k <= nBands; k++) freqMaster[k] = freqMaster[k - 1] + vDk[k - 1]; return nMaster; } /* mBandTab[i] = temp1[i] / 2 */ static const int mBandTab[3] PROGMEM = {6, 5, 4}; /* invWarpTab[i] = 1.0 / temp2[i], Q30 (see 4.6.18.3.2.1) */ static const int invWarpTab[2] PROGMEM = {0x40000000, 0x313b13b1}; /*********************************************************************************************************************** * Function: CalcFreqMasterScale * * Description: calculate master frequency table when freqScale > 0 * (4.6.18.3.2.1, figure 4.39) * * Inputs: alterScale flag * freqScale flag * index of first QMF subband in master freq table (k0) * index of last QMF subband (k2) * * Outputs: master frequency table * * Return: number of bands in master frequency table * * Notes: assumes k2 - k0 <= 48 and k2 >= k0 (4.6.18.3.6) **********************************************************************************************************************/ int CalcFreqMaster(uint8_t *freqMaster, int freqScale, int alterScale, int k0, int k2) { int bands, twoRegions, k, k1, t, vLast, vCurr, pCurr; int invWarp, nBands0, nBands1, change; uint8_t vDk1Min, vDk0Max; uint8_t *vDelta; if(freqScale < 1 || freqScale > 3) return -1; bands = mBandTab[freqScale - 1]; invWarp = invWarpTab[alterScale]; /* tested for all k0 = [5, 64], k2 = [k0, 64] */ if(k2 * 10000 > 22449 * k0) { twoRegions = 1; k1 = 2 * k0; } else { twoRegions = 0; k1 = k2; } /* tested for all k0 = [5, 64], k1 = [k0, 64], freqScale = [1,3] */ t = (log2Tab[k1] - log2Tab[k0]) >> 3; /* log2(k1/k0), Q28 to Q25 */ nBands0 = 2 * (((bands * t) + (1 << 24)) >> 25); /* multiply by bands/2, round to nearest int (mBandTab has factor of 1/2 rolled in) */ /* tested for all valid combinations of k0, k1, nBands (from sampRate, freqScale, alterScale) * roundoff error can be a problem with fixpt (e.g. pCurr = 12.499999 instead of 12.50003) * because successive multiplication always undershoots a little bit, but this * doesn't occur in any of the ratios we encounter from the valid k0/k1 bands in the spec */ t = RatioPowInv(k1, k0, nBands0); pCurr = k0 << 24; vLast = k0; vDelta = freqMaster + 1; /* operate in-place */ for(k = 0; k < nBands0; k++) { pCurr = MULSHIFT32(pCurr, t) << 8; /* keep in Q24 */ vCurr = (pCurr + (1 << 23)) >> 24; vDelta[k] = (vCurr - vLast); vLast = vCurr; } /* sort the deltas and find max delta for first region */ BubbleSort(vDelta, nBands0); vDk0Max = VMax(vDelta, nBands0); /* fill master frequency table with bands from first region */ freqMaster[0] = k0; for(k = 1; k <= nBands0; k++) freqMaster[k] += freqMaster[k - 1]; /* if only one region, then the table is complete */ if(!twoRegions) return nBands0; /* tested for all k1 = [10, 64], k2 = [k0, 64], freqScale = [1,3] */ t = (log2Tab[k2] - log2Tab[k1]) >> 3; /* log2(k1/k0), Q28 to Q25 */ t = MULSHIFT32(bands * t, invWarp) << 2; /* multiply by bands/2, divide by warp factor, keep Q25 */ nBands1 = 2 * ((t + (1 << 24)) >> 25); /* round to nearest int */ /* see comments above for calculations in first region */ t = RatioPowInv(k2, k1, nBands1); pCurr = k1 << 24; vLast = k1; vDelta = freqMaster + nBands0 + 1; /* operate in-place */ for(k = 0; k < nBands1; k++) { pCurr = MULSHIFT32(pCurr, t) << 8; /* keep in Q24 */ vCurr = (pCurr + (1 << 23)) >> 24; vDelta[k] = (vCurr - vLast); vLast = vCurr; } /* sort the deltas, adjusting first and last if the second region has smaller deltas than the first */ vDk1Min = VMin(vDelta, nBands1); if(vDk1Min < vDk0Max) { BubbleSort(vDelta, nBands1); change = vDk0Max - vDelta[0]; if(change > ((vDelta[nBands1 - 1] - vDelta[0]) >> 1)) change = ((vDelta[nBands1 - 1] - vDelta[0]) >> 1); vDelta[0] += change; vDelta[nBands1 - 1] -= change; } BubbleSort(vDelta, nBands1); /* fill master frequency table with bands from second region * Note: freqMaster[nBands0] = k1 */ for(k = 1; k <= nBands1; k++) freqMaster[k + nBands0] += freqMaster[k + nBands0 - 1]; return (nBands0 + nBands1); } /*********************************************************************************************************************** * Function: CalcFreqHigh * * Description: calculate high resolution frequency table (4.6.18.3.2.2) * * Inputs: master frequency table * number of bands in master frequency table * crossover band from header * * Outputs: high resolution frequency table * * Return: number of bands in high resolution frequency table **********************************************************************************************************************/ int CalcFreqHigh(uint8_t *freqHigh, uint8_t *freqMaster, int nMaster, int crossOverBand) { int k, nHigh; nHigh = nMaster - crossOverBand; for(k = 0; k <= nHigh; k++) freqHigh[k] = freqMaster[k + crossOverBand]; return nHigh; } /*********************************************************************************************************************** * Function: CalcFreqLow * * Description: calculate low resolution frequency table (4.6.18.3.2.2) * * Inputs: high resolution frequency table * number of bands in high resolution frequency table * * Outputs: low resolution frequency table * * Return: number of bands in low resolution frequency table **********************************************************************************************************************/ int CalcFreqLow(uint8_t *freqLow, uint8_t *freqHigh, int nHigh) { int k, nLow, oddFlag; nLow = nHigh - (nHigh >> 1); freqLow[0] = freqHigh[0]; oddFlag = nHigh & 0x01; for(k = 1; k <= nLow; k++) freqLow[k] = freqHigh[2 * k - oddFlag]; return nLow; } /*********************************************************************************************************************** * Function: CalcFreqNoise * * Description: calculate noise floor frequency table (4.6.18.3.2.2) * * Inputs: low resolution frequency table * number of bands in low resolution frequency table * index of starting QMF subband for SBR (kStart) * index of last QMF subband (k2) * number of noise bands * * Outputs: noise floor frequency table * * Return: number of bands in noise floor frequency table **********************************************************************************************************************/ int CalcFreqNoise(uint8_t *freqNoise, uint8_t *freqLow, int nLow, int kStart, int k2, int noiseBands) { int i, iLast, k, nQ, lTop, lBottom; lTop = log2Tab[k2]; lBottom = log2Tab[kStart]; nQ = noiseBands * ((lTop - lBottom) >> 2); /* Q28 to Q26, noiseBands = [0,3] */ nQ = (nQ + (1 << 25)) >> 26; if(nQ < 1) nQ = 1; ASSERT(nQ <= MAX_NUM_NOISE_FLOOR_BANDS); /* required from 4.6.18.3.6 */ iLast = 0; freqNoise[0] = freqLow[0]; for(k = 1; k <= nQ; k++) { i = iLast + (nLow - iLast) / (nQ + 1 - k); /* truncating division */ freqNoise[k] = freqLow[i]; iLast = i; } return nQ; } /*********************************************************************************************************************** * Function: BuildPatches * * Description: build high frequency patches (4.6.18.6.3) * * Inputs: master frequency table * number of bands in low resolution frequency table * index of first QMF subband in master freq table (k0) * index of starting QMF subband for SBR (kStart) * number of QMF bands in high resolution frequency table * sample rate index * * Outputs: starting subband for each patch * number of subbands in each patch * * Return: number of patches **********************************************************************************************************************/ int BuildPatches(uint8_t *patchNumSubbands, uint8_t *patchStartSubband, uint8_t *freqMaster, int nMaster, int k0, int kStart, int numQMFBands, int sampRateIdx) { int i, j, k; int msb, sb, usb, numPatches, goalSB, oddFlag; msb = k0; usb = kStart; numPatches = 0; goalSB = goalSBTab[sampRateIdx]; if(nMaster == 0) { patchNumSubbands[0] = 0; patchStartSubband[0] = 0; return 0; } if(goalSB < kStart + numQMFBands) { k = 0; for(i = 0; freqMaster[i] < goalSB; i++) k = i + 1; } else { k = nMaster; } do { j = k + 1; do { j--; sb = freqMaster[j]; oddFlag = (sb - 2 + k0) & 0x01; } while(sb > k0 - 1 + msb - oddFlag); patchNumSubbands[numPatches] = MAX(sb - usb, 0); patchStartSubband[numPatches] = k0 - oddFlag - patchNumSubbands[numPatches]; /* from MPEG reference code - slightly different from spec */ if((patchNumSubbands[numPatches] < 3) && (numPatches > 0)) break; if(patchNumSubbands[numPatches] > 0) { usb = sb; msb = sb; numPatches++; } else { msb = kStart; } if(freqMaster[k] - sb < 3) k = nMaster; } while(sb != (kStart + numQMFBands) && numPatches <= MAX_NUM_PATCHES); return numPatches; } /*********************************************************************************************************************** * Function: FindFreq * * Description: search buffer of uint8_ts for a specific value * * Inputs: buffer of elements to search * number of elements to search * value to search for * * Outputs: none * * Return: non-zero if the value is found anywhere in the buffer, zero otherwise **********************************************************************************************************************/ int FindFreq(uint8_t *freq, int nFreq, uint8_t val) { int k; for(k = 0; k < nFreq; k++) { if(freq[k] == val) return 1; } return 0; } /*********************************************************************************************************************** * Function: RemoveFreq * * Description: remove one element from a buffer of uint8_ts * * Inputs: buffer of elements * number of elements * index of element to remove * * Outputs: new buffer of length nFreq-1 * * Return: none **********************************************************************************************************************/ void RemoveFreq(uint8_t *freq, int nFreq, int removeIdx) { int k; if(removeIdx >= nFreq) return; for(k = removeIdx; k < nFreq - 1; k++) freq[k] = freq[k + 1]; } /*********************************************************************************************************************** * Function: CalcFreqLimiter * * Description: calculate limiter frequency table (4.6.18.3.2.3) * * Inputs: number of subbands in each patch * low resolution frequency table * number of bands in low resolution frequency table * index of starting QMF subband for SBR (kStart) * number of limiter bands * number of patches * * Outputs: limiter frequency table * * Return: number of bands in limiter frequency table **********************************************************************************************************************/ int CalcFreqLimiter(uint8_t *freqLimiter, uint8_t *patchNumSubbands, uint8_t *freqLow, int nLow, int kStart, int limiterBands, int numPatches) { int k, bands, nLimiter, nOctaves; int limBandsPerOctave[3] = { 120, 200, 300 }; /* [1.2, 2.0, 3.0] * 100 */ uint8_t patchBorders[MAX_NUM_PATCHES + 1]; /* simple case */ if(limiterBands == 0) { freqLimiter[0] = freqLow[0] - kStart; freqLimiter[1] = freqLow[nLow] - kStart; return 1; } bands = limBandsPerOctave[limiterBands - 1]; patchBorders[0] = kStart; /* from MPEG reference code - slightly different from spec (top border) */ for(k = 1; k < numPatches; k++) patchBorders[k] = patchBorders[k - 1] + patchNumSubbands[k - 1]; patchBorders[k] = freqLow[nLow]; for(k = 0; k <= nLow; k++) freqLimiter[k] = freqLow[k]; for(k = 1; k < numPatches; k++) freqLimiter[k + nLow] = patchBorders[k]; k = 1; nLimiter = nLow + numPatches - 1; BubbleSort(freqLimiter, nLimiter + 1); while(k <= nLimiter) { nOctaves = log2Tab[freqLimiter[k]] - log2Tab[freqLimiter[k - 1]]; /* Q28 */ nOctaves = (nOctaves >> 9) * bands; /* Q19, max bands = 300 < 2^9 */ if(nOctaves < (49 << 19)) { /* compare with 0.49*100, in Q19 */ if(freqLimiter[k] == freqLimiter[k - 1] || FindFreq(patchBorders, numPatches + 1, freqLimiter[k]) == 0) { RemoveFreq(freqLimiter, nLimiter + 1, k); nLimiter--; } else if(FindFreq(patchBorders, numPatches + 1, freqLimiter[k - 1]) == 0) { RemoveFreq(freqLimiter, nLimiter + 1, k - 1); nLimiter--; } else { k++; } } else { k++; } } /* store limiter boundaries as offsets from kStart */ for(k = 0; k <= nLimiter; k++) freqLimiter[k] -= kStart; return nLimiter; } /*********************************************************************************************************************** * Function: CalcFreqTables * * Description: calulate master and derived frequency tables, and patches * * Inputs: initialized SBRHeader struct for this SCE/CPE block * initialized SBRFreq struct for this SCE/CPE block * sample rate index of output sample rate (after SBR) * * Outputs: master and derived frequency tables, and patches * * Return: non-zero if error, zero otherwise **********************************************************************************************************************/ int CalcFreqTables(SBRHeader *sbrHdr, SBRFreq *sbrFreq, int sampRateIdx) { int k0, k2; k0 = k0Tab[sampRateIdx][sbrHdr->startFreq]; if(sbrHdr->stopFreq == 14) k2 = 2 * k0; else if(sbrHdr->stopFreq == 15) k2 = 3 * k0; else k2 = k2Tab[sampRateIdx][sbrHdr->stopFreq]; if(k2 > 64) k2 = 64; /* calculate master frequency table */ if(sbrHdr->freqScale == 0) sbrFreq->nMaster = CalcFreqMasterScaleZero(sbrFreq->freqMaster, sbrHdr->alterScale, k0, k2); else sbrFreq->nMaster = CalcFreqMaster(sbrFreq->freqMaster, sbrHdr->freqScale, sbrHdr->alterScale, k0, k2); /* calculate high frequency table and related parameters */ sbrFreq->nHigh = CalcFreqHigh(sbrFreq->freqHigh, sbrFreq->freqMaster, sbrFreq->nMaster, sbrHdr->crossOverBand); sbrFreq->numQMFBands = sbrFreq->freqHigh[sbrFreq->nHigh] - sbrFreq->freqHigh[0]; sbrFreq->kStart = sbrFreq->freqHigh[0]; /* calculate low frequency table */ sbrFreq->nLow = CalcFreqLow(sbrFreq->freqLow, sbrFreq->freqHigh, sbrFreq->nHigh); /* calculate noise floor frequency table */ sbrFreq->numNoiseFloorBands = CalcFreqNoise(sbrFreq->freqNoise, sbrFreq->freqLow, sbrFreq->nLow, sbrFreq->kStart, k2, sbrHdr->noiseBands); /* calculate limiter table */ sbrFreq->numPatches = BuildPatches(sbrFreq->patchNumSubbands, sbrFreq->patchStartSubband, sbrFreq->freqMaster, sbrFreq->nMaster, k0, sbrFreq->kStart, sbrFreq->numQMFBands, sampRateIdx); sbrFreq->nLimiter = CalcFreqLimiter(sbrFreq->freqLimiter, sbrFreq->patchNumSubbands, sbrFreq->freqLow, sbrFreq->nLow, sbrFreq->kStart, sbrHdr->limiterBands, sbrFreq->numPatches); return 0; } /*********************************************************************************************************************** * Function: EstimateEnvelope * * Description: estimate power of generated HF QMF bands in one time-domain envelope * (4.6.18.7.3) * * Inputs: initialized PSInfoSBR struct * initialized SBRHeader struct for this SCE/CPE block * initialized SBRGrid struct for this channel * initialized SBRFreq struct for this SCE/CPE block * index of current envelope * * Outputs: power of each QMF subband, stored as integer (Q0) * 2^N, N >= 0 * * Return: none **********************************************************************************************************************/ void EstimateEnvelope(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, int env) { int i, m, iStart, iEnd, xre, xim, nScale, expMax; int p, n, mStart, mEnd, invFact, t; int *XBuf; U64 eCurr; uint8_t *freqBandTab; /* estimate current envelope */ iStart = sbrGrid->envTimeBorder[env] + HF_ADJ; iEnd = sbrGrid->envTimeBorder[env + 1] + HF_ADJ; if(sbrGrid->freqRes[env]) { n = sbrFreq->nHigh; freqBandTab = sbrFreq->freqHigh; } else { n = sbrFreq->nLow; freqBandTab = sbrFreq->freqLow; } /* ADS should inline MADD64 (smlal) properly, but check to make sure */ expMax = 0; if(sbrHdr->interpFreq) { for(m = 0; m < sbrFreq->numQMFBands; m++) { eCurr.w64 = 0; XBuf = m_PSInfoSBR->XBuf[iStart][sbrFreq->kStart + m]; for(i = iStart; i < iEnd; i++) { /* scale to int before calculating power (precision not critical, and avoids overflow) */ xre = (*XBuf) >> FBITS_OUT_QMFA; XBuf += 1; xim = (*XBuf) >> FBITS_OUT_QMFA; XBuf += (2 * 64 - 1); eCurr.w64 = MADD64(eCurr.w64, xre, xre); eCurr.w64 = MADD64(eCurr.w64, xim, xim); } /* eCurr.w64 is now Q(64 - 2*FBITS_OUT_QMFA) (64-bit word) * if energy is too big to fit in 32-bit word (> 2^31) scale down by power of 2 */ nScale = 0; if(eCurr.r.hi32) { nScale = (32 - CLZ(eCurr.r.hi32)) + 1; t = (int) (eCurr.r.lo32 >> nScale); /* logical (unsigned) >> */ t |= eCurr.r.hi32 << (32 - nScale); } else if(eCurr.r.lo32 >> 31) { nScale = 1; t = (int) (eCurr.r.lo32 >> nScale); /* logical (unsigned) >> */ } else { t = (int) eCurr.r.lo32; } invFact = invBandTab[(iEnd - iStart) - 1]; m_PSInfoSBR->eCurr[m] = MULSHIFT32(t, invFact); m_PSInfoSBR->eCurrExp[m] = nScale + 1; /* +1 for invFact = Q31 */ if(m_PSInfoSBR->eCurrExp[m] > expMax) expMax = m_PSInfoSBR->eCurrExp[m]; } } else { for(p = 0; p < n; p++) { mStart = freqBandTab[p]; mEnd = freqBandTab[p + 1]; eCurr.w64 = 0; for(i = iStart; i < iEnd; i++) { XBuf = m_PSInfoSBR->XBuf[i][mStart]; for(m = mStart; m < mEnd; m++) { xre = (*XBuf++) >> FBITS_OUT_QMFA; xim = (*XBuf++) >> FBITS_OUT_QMFA; eCurr.w64 = MADD64(eCurr.w64, xre, xre); eCurr.w64 = MADD64(eCurr.w64, xim, xim); } } nScale = 0; if(eCurr.r.hi32) { nScale = (32 - CLZ(eCurr.r.hi32)) + 1; t = (int) (eCurr.r.lo32 >> nScale); /* logical (unsigned) >> */ t |= eCurr.r.hi32 << (32 - nScale); } else if(eCurr.r.lo32 >> 31) { nScale = 1; t = (int) (eCurr.r.lo32 >> nScale); /* logical (unsigned) >> */ } else { t = (int) eCurr.r.lo32; } invFact = invBandTab[(iEnd - iStart) - 1]; invFact = MULSHIFT32(invBandTab[(mEnd - mStart) - 1], invFact) << 1; t = MULSHIFT32(t, invFact); for(m = mStart; m < mEnd; m++) { m_PSInfoSBR->eCurr[m - sbrFreq->kStart] = t; m_PSInfoSBR->eCurrExp[m - sbrFreq->kStart] = nScale + 1; /* +1 for invFact = Q31 */ } if(m_PSInfoSBR->eCurrExp[mStart - sbrFreq->kStart] > expMax) expMax = m_PSInfoSBR->eCurrExp[mStart - sbrFreq->kStart]; } } m_PSInfoSBR->eCurrExpMax = expMax; } /*********************************************************************************************************************** * Function: GetSMapped * * Description: calculate SMapped (4.6.18.7.2) * * Inputs: initialized SBRGrid struct for this channel * initialized SBRFreq struct for this SCE/CPE block * initialized SBRChan struct for this channel * index of current envelope * index of current QMF band * la flag for this envelope * * Outputs: none * * Return: 1 if a sinusoid is present in this band, 0 if not **********************************************************************************************************************/ int GetSMapped(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int env, int band, int la) { int bandStart, bandEnd, oddFlag, r; if (sbrGrid->freqRes[env]) { /* high resolution */ bandStart = band; bandEnd = band+1; } else { /* low resolution (see CalcFreqLow() for mapping) */ oddFlag = sbrFreq->nHigh & 0x01; bandStart = (band > 0 ? 2*band - oddFlag : 0); /* starting index for freqLow[band] */ bandEnd = 2*(band+1) - oddFlag; /* ending index for freqLow[band+1] */ } /* sMapped = 1 if sIndexMapped == 1 for any frequency in this band */ for (band = bandStart; band < bandEnd; band++) { if (sbrChan->addHarmonic[1][band]) { r = ((sbrFreq->freqHigh[band+1] + sbrFreq->freqHigh[band]) >> 1); if (env >= la || sbrChan->addHarmonic[0][r] == 1) return 1; } } return 0; } #define GBOOST_MAX 0x2830afd3 /* Q28, 1.584893192 squared */ #define ACC_SCALE 6 /* squared version of table in 4.6.18.7.5 */ /* Q30 (0x80000000 = sentinel for GMAX) */ static const uint32_t limGainTab[4] PROGMEM = {0x20138ca7, 0x40000000, 0x7fb27dce, 0x80000000}; /*********************************************************************************************************************** * Function: CalcMaxGain * * Description: calculate max gain in one limiter band (4.6.18.7.5) * * Inputs: initialized SBRHeader struct for this SCE/CPE block * initialized SBRGrid struct for this channel * initialized SBRFreq struct for this SCE/CPE block * index of current channel (0 for SCE, 0 or 1 for CPE) * index of current envelope * index of current limiter band * number of fraction bits in dequantized envelope * (max = Q(FBITS_OUT_DQ_ENV - 6) = Q23, can go negative) * * Outputs: updated gainMax, gainMaxFBits, and sumEOrigMapped in PSInfoSBR struct * * Return: none **********************************************************************************************************************/ void CalcMaxGain(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, int ch, int env, int lim, int fbitsDQ) { int m, mStart, mEnd, q, z, r; int sumEOrigMapped, sumECurr, gainMax, eOMGainMax, envBand; uint8_t eCurrExpMax; uint8_t *freqBandTab; mStart = sbrFreq->freqLimiter[lim]; /* these are offsets from kStart */ mEnd = sbrFreq->freqLimiter[lim + 1]; freqBandTab = (sbrGrid->freqRes[env] ? sbrFreq->freqHigh : sbrFreq->freqLow); /* calculate max gain to apply to signal in this limiter band */ sumECurr = 0; sumEOrigMapped = 0; eCurrExpMax = m_PSInfoSBR->eCurrExpMax; eOMGainMax = m_PSInfoSBR->eOMGainMax; envBand = m_PSInfoSBR->envBand; for(m = mStart; m < mEnd; m++) { /* map current QMF band to appropriate envelope band */ if(m == freqBandTab[envBand + 1] - sbrFreq->kStart) { envBand++; eOMGainMax = m_PSInfoSBR->envDataDequant[ch][env][envBand] >> ACC_SCALE; /* summing max 48 bands */ } sumEOrigMapped += eOMGainMax; /* easy test for overflow on ARM */ sumECurr += (m_PSInfoSBR->eCurr[m] >> (eCurrExpMax - m_PSInfoSBR->eCurrExp[m])); if(sumECurr >> 30) { sumECurr >>= 1; eCurrExpMax++; } } m_PSInfoSBR->eOMGainMax = eOMGainMax; m_PSInfoSBR->envBand = envBand; m_PSInfoSBR->gainMaxFBits = 30; /* Q30 tables */ if(sumECurr == 0) { /* any non-zero numerator * 1/EPS_0 is > G_MAX */ gainMax = (sumEOrigMapped == 0 ? (int) limGainTab[sbrHdr->limiterGains] : (int) 0x80000000); } else if(sumEOrigMapped == 0) { /* 1/(any non-zero denominator) * EPS_0 * limGainTab[x] is appx. 0 */ gainMax = 0; } else { /* sumEOrigMapped = Q(fbitsDQ - ACC_SCALE), sumECurr = Q(-eCurrExpMax) */ gainMax = limGainTab[sbrHdr->limiterGains]; if(sbrHdr->limiterGains != 3) { q = MULSHIFT32(sumEOrigMapped, gainMax); /* Q(fbitsDQ - ACC_SCALE - 2), gainMax = Q30 */ z = CLZ(sumECurr) - 1; r = InvRNormalized(sumECurr << z); /* in = Q(z - eCurrExpMax), out = Q(29 + 31 - z + eCurrExpMax) */ gainMax = MULSHIFT32(q, r); /* Q(29 + 31 - z + eCurrExpMax + fbitsDQ - ACC_SCALE - 2 - 32) */ m_PSInfoSBR->gainMaxFBits = 26 - z + eCurrExpMax + fbitsDQ - ACC_SCALE; } } m_PSInfoSBR->sumEOrigMapped = sumEOrigMapped; m_PSInfoSBR->gainMax = gainMax; } /*********************************************************************************************************************** * Function: CalcNoiseDivFactors * * Description: calculate 1/(1+Q) and Q/(1+Q) (4.6.18.7.4; 4.6.18.7.5) * * Inputs: dequantized noise floor scalefactor * * Outputs: 1/(1+Q) and Q/(1+Q), format = Q31 * * Return: none **********************************************************************************************************************/ void CalcNoiseDivFactors(int q, int *qp1Inv, int *qqp1Inv) { int z, qp1, t, s; /* 1 + Q_orig */ qp1 = (q >> 1); qp1 += (1 << (FBITS_OUT_DQ_NOISE - 1)); /* >> 1 to avoid overflow when adding 1.0 */ z = CLZ(qp1) - 1; /* z <= 31 - FBITS_OUT_DQ_NOISE */ qp1 <<= z; /* Q(FBITS_OUT_DQ_NOISE + z) = Q31 * 2^-(31 - (FBITS_OUT_DQ_NOISE + z)) */ t = InvRNormalized(qp1) << 1; /* Q30 * 2^(31 - (FBITS_OUT_DQ_NOISE + z)), guaranteed not to overflow */ /* normalize to Q31 */ s = (31 - (FBITS_OUT_DQ_NOISE - 1) - z - 1); /* clearly z >= 0, z <= (30 - (FBITS_OUT_DQ_NOISE - 1)) */ *qp1Inv = (t >> s); /* s = [0, 31 - FBITS_OUT_DQ_NOISE] */ *qqp1Inv = MULSHIFT32(t, q) << (32 - FBITS_OUT_DQ_NOISE - s); } /*********************************************************************************************************************** * Function: CalcComponentGains * * Description: calculate gain of envelope, sinusoids, and noise in one limiter band * (4.6.18.7.5) * * Inputs: initialized SBRHeader struct for this SCE/CPE block * initialized SBRGrid struct for this channel * initialized SBRFreq struct for this SCE/CPE block * initialized SBRChan struct for this channel * index of current channel (0 for SCE, 0 or 1 for CPE) * index of current envelope * index of current limiter band * number of fraction bits in dequantized envelope * * Outputs: gains for envelope, sinusoids and noise * number of fraction bits for envelope gain * sum of the total gain for each component in this band * other updated state variables * * Return: none **********************************************************************************************************************/ void CalcComponentGains(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch, int env, int lim, int fbitsDQ) { int d, m, mStart, mEnd, q, qm, noiseFloor, sIndexMapped; int shift, eCurr, maxFlag, gainMax, gainMaxFBits; int gain, sm, z, r, fbitsGain, gainScale; uint8_t *freqBandTab; mStart = sbrFreq->freqLimiter[lim]; /* these are offsets from kStart */ mEnd = sbrFreq->freqLimiter[lim + 1]; gainMax = m_PSInfoSBR->gainMax; gainMaxFBits = m_PSInfoSBR->gainMaxFBits; d = (env == m_PSInfoSBR->la || env == sbrChan->laPrev ? 0 : 1); freqBandTab = (sbrGrid->freqRes[env] ? sbrFreq->freqHigh : sbrFreq->freqLow); /* figure out which noise floor this envelope is in (only 1 or 2 noise floors allowed) */ noiseFloor = 0; if(sbrGrid->numNoiseFloors == 2 && sbrGrid->noiseTimeBorder[1] <= sbrGrid->envTimeBorder[env]) noiseFloor++; m_PSInfoSBR->sumECurrGLim = 0; m_PSInfoSBR->sumSM = 0; m_PSInfoSBR->sumQM = 0; /* calculate energy of noise to add in this limiter band */ for(m = mStart; m < mEnd; m++) { if(m == sbrFreq->freqNoise[m_PSInfoSBR->noiseFloorBand + 1] - sbrFreq->kStart) { /* map current QMF band to appropriate noise floor band (NOTE: freqLimiter[0] == freqLow[0] = freqHigh[0]) */ m_PSInfoSBR->noiseFloorBand++; CalcNoiseDivFactors(m_PSInfoSBR->noiseDataDequant[ch][noiseFloor][m_PSInfoSBR->noiseFloorBand], &(m_PSInfoSBR->qp1Inv), &(m_PSInfoSBR->qqp1Inv)); } if(m == sbrFreq->freqHigh[m_PSInfoSBR->highBand + 1] - sbrFreq->kStart) m_PSInfoSBR->highBand++; if(m == freqBandTab[m_PSInfoSBR->sBand + 1] - sbrFreq->kStart) { m_PSInfoSBR->sBand++; m_PSInfoSBR->sMapped = GetSMapped(sbrGrid, sbrFreq, sbrChan, env, m_PSInfoSBR->sBand, m_PSInfoSBR->la); } /* get sIndexMapped for this QMF subband */ sIndexMapped = 0; r = ((sbrFreq->freqHigh[m_PSInfoSBR->highBand + 1] + sbrFreq->freqHigh[m_PSInfoSBR->highBand]) >> 1); if(m + sbrFreq->kStart == r) { /* r = center frequency, deltaStep = (env >= la || sIndexMapped'(r, numEnv'-1) == 1) */ if(env >= m_PSInfoSBR->la || sbrChan->addHarmonic[0][r] == 1) sIndexMapped = sbrChan->addHarmonic[1][m_PSInfoSBR->highBand]; } /* save sine flags from last envelope in this frame: * addHarmonic[0][0...63] = saved sine present flag from previous frame, for each QMF subband * addHarmonic[1][0...nHigh-1] = addHarmonic bit from current frame, for each high-res frequency band * from MPEG reference code - slightly different from spec * (sIndexMapped'(m,LE'-1) can still be 0 when numEnv == psi->la) */ if(env == sbrGrid->numEnv - 1) { if(m + sbrFreq->kStart == r) sbrChan->addHarmonic[0][m + sbrFreq->kStart] = sbrChan->addHarmonic[1][m_PSInfoSBR->highBand]; else sbrChan->addHarmonic[0][m + sbrFreq->kStart] = 0; } gain = m_PSInfoSBR->envDataDequant[ch][env][m_PSInfoSBR->sBand]; qm = MULSHIFT32(gain, m_PSInfoSBR->qqp1Inv) << 1; sm = (sIndexMapped ? MULSHIFT32(gain, m_PSInfoSBR->qp1Inv) << 1 : 0); /* three cases: (sMapped == 0 && delta == 1), (sMapped == 0 && delta == 0), (sMapped == 1) */ if(d == 1 && m_PSInfoSBR->sMapped == 0) gain = MULSHIFT32(m_PSInfoSBR->qp1Inv, gain) << 1; else if(m_PSInfoSBR->sMapped != 0) gain = MULSHIFT32(m_PSInfoSBR->qqp1Inv, gain) << 1; /* gain, qm, sm = Q(fbitsDQ), gainMax = Q(fbitsGainMax) */ eCurr = m_PSInfoSBR->eCurr[m]; if(eCurr) { z = CLZ(eCurr) - 1; r = InvRNormalized(eCurr << z); /* in = Q(z - eCurrExp), out = Q(29 + 31 - z + eCurrExp) */ gainScale = MULSHIFT32(gain, r); /* out = Q(29 + 31 - z + eCurrExp + fbitsDQ - 32) */ fbitsGain = 29 + 31 - z + m_PSInfoSBR->eCurrExp[m] + fbitsDQ - 32; } else { /* if eCurr == 0, then gain is unchanged (divide by EPS = 1) */ gainScale = gain; fbitsGain = fbitsDQ; } /* see if gain for this band exceeds max gain */ maxFlag = 0; if(gainMax != (int) 0x80000000) { if(fbitsGain >= gainMaxFBits) { shift = MIN(fbitsGain - gainMaxFBits, 31); maxFlag = ((gainScale >> shift) > gainMax ? 1 : 0); } else { shift = MIN(gainMaxFBits - fbitsGain, 31); maxFlag = (gainScale > (gainMax >> shift) ? 1 : 0); } } if(maxFlag) { /* gainScale > gainMax, calculate ratio with 32/16 division */ q = 0; r = gainScale; /* guaranteed > 0, else maxFlag could not have been set */ z = CLZ(r); if(z < 16) { q = 16 - z; r >>= q; /* out = Q(fbitsGain - q) */ } z = CLZ(gainMax) - 1; r = (gainMax << z) / r; /* out = Q((fbitsGainMax + z) - (fbitsGain - q)) */ q = (gainMaxFBits + z) - (fbitsGain - q); /* r = Q(q) */ if(q > 30) { r >>= MIN(q - 30, 31); } else { z = MIN(30 - q, 30); r = CLIP_2N_SHIFT30(r, z); /* let r = Q30 since range = [0.0, 1.0) (clip to 0x3fffffff = 0.99999) */ } qm = MULSHIFT32(qm, r) << 2; gain = MULSHIFT32(gain, r) << 2; m_PSInfoSBR->gLimBuf[m] = gainMax; m_PSInfoSBR->gLimFbits[m] = gainMaxFBits; } else { m_PSInfoSBR->gLimBuf[m] = gainScale; m_PSInfoSBR->gLimFbits[m] = fbitsGain; } /* sumSM, sumQM, sumECurrGLim = Q(fbitsDQ - ACC_SCALE) */ m_PSInfoSBR->smBuf[m] = sm; m_PSInfoSBR->sumSM += (sm >> ACC_SCALE); m_PSInfoSBR->qmLimBuf[m] = qm; if(env != m_PSInfoSBR->la && env != sbrChan->laPrev && sm == 0) m_PSInfoSBR->sumQM += (qm >> ACC_SCALE); /* eCurr * gain^2 same as gain^2, before division by eCurr * (but note that gain != 0 even if eCurr == 0, since it's divided by eps) */ if(eCurr) m_PSInfoSBR->sumECurrGLim += (gain >> ACC_SCALE); } } /*********************************************************************************************************************** * Function: ApplyBoost * * Description: calculate and apply boost factor for envelope, sinusoids, and noise * in this limiter band (4.6.18.7.5) * * Inputs: initialized SBRFreq struct for this SCE/CPE block * index of current limiter band * number of fraction bits in dequantized envelope * * Outputs: envelope gain, sinusoids and noise after scaling by gBoost * format = Q(FBITS_GLIM_BOOST) for envelope gain, * = Q(FBITS_QLIM_BOOST) for noise * = Q(FBITS_OUT_QMFA) for sinusoids * * Return: none * * Notes: after scaling, each component has at least 1 GB **********************************************************************************************************************/ void ApplyBoost(SBRFreq *sbrFreq, int lim, int fbitsDQ) { int m, mStart, mEnd, q, z, r; int sumEOrigMapped, gBoost; mStart = sbrFreq->freqLimiter[lim]; /* these are offsets from kStart */ mEnd = sbrFreq->freqLimiter[lim + 1]; sumEOrigMapped = m_PSInfoSBR->sumEOrigMapped >> 1; r = (m_PSInfoSBR->sumECurrGLim >> 1) + (m_PSInfoSBR->sumSM >> 1) + (m_PSInfoSBR->sumQM >> 1); /* 1 GB fine (sm and qm are mutually exclusive in acc) */ if(r < (1 << (31 - 28))) { /* any non-zero numerator * 1/EPS_0 is > GBOOST_MAX * round very small r to zero to avoid scaling problems */ gBoost = (sumEOrigMapped == 0 ? (1 << 28) : GBOOST_MAX); z = 0; } else if(sumEOrigMapped == 0) { /* 1/(any non-zero denominator) * EPS_0 is appx. 0 */ gBoost = 0; z = 0; } else { /* numerator (sumEOrigMapped) and denominator (r) have same Q format (before << z) */ z = CLZ(r) - 1; /* z = [0, 27] */ r = InvRNormalized(r << z); gBoost = MULSHIFT32(sumEOrigMapped, r); } /* gBoost = Q(28 - z) */ if(gBoost > (GBOOST_MAX >> z)) { gBoost = GBOOST_MAX; z = 0; } gBoost <<= z; /* gBoost = Q28, minimum 1 GB */ /* convert gain, noise, sinusoids to fixed Q format, clipping if necessary * (rare, usually only happens at very low bitrates, introduces slight * distortion into final HF mapping, but should be inaudible) */ for(m = mStart; m < mEnd; m++) { /* let gLimBoost = Q24, since in practice the max values are usually 16 to 20 * unless limiterGains == 3 (limiter off) and eCurr ~= 0 (i.e. huge gain, but only * because the envelope has 0 power anyway) */ q = MULSHIFT32(m_PSInfoSBR->gLimBuf[m], gBoost) << 2; /* Q(gLimFbits) * Q(28) --> Q(gLimFbits[m]-2) */ r = SqrtFix(q, m_PSInfoSBR->gLimFbits[m] - 2, &z); z -= FBITS_GLIM_BOOST; if(z >= 0) { m_PSInfoSBR->gLimBoost[m] = r >> MIN(z, 31); } else { z = MIN(30, -z); r = CLIP_2N_SHIFT30(r, z); m_PSInfoSBR->gLimBoost[m] = r; } q = MULSHIFT32(m_PSInfoSBR->qmLimBuf[m], gBoost) << 2; /* Q(fbitsDQ) * Q(28) --> Q(fbitsDQ-2) */ r = SqrtFix(q, fbitsDQ - 2, &z); z -= FBITS_QLIM_BOOST; /* << by 14, since integer sqrt of x < 2^16, and we want to leave 1 GB */ if(z >= 0) { m_PSInfoSBR->qmLimBoost[m] = r >> MIN(31, z); } else { z = MIN(30, -z); r = CLIP_2N_SHIFT30(r, z); m_PSInfoSBR->qmLimBoost[m] = r; } q = MULSHIFT32(m_PSInfoSBR->smBuf[m], gBoost) << 2; /* Q(fbitsDQ) * Q(28) --> Q(fbitsDQ-2) */ r = SqrtFix(q, fbitsDQ - 2, &z); z -= FBITS_OUT_QMFA; /* justify for adding to signal (xBuf) later */ if(z >= 0) { m_PSInfoSBR->smBoost[m] = r >> MIN(31, z); } else { z = MIN(30, -z); r = CLIP_2N_SHIFT30(r, z); m_PSInfoSBR->smBoost[m] = r; } } } /*********************************************************************************************************************** * Function: CalcGain * * Description: calculate and apply proper gain to HF components in one envelope * (4.6.18.7.5) * * Inputs: initialized SBRHeader struct for this SCE/CPE block * initialized SBRGrid struct for this channel * initialized SBRFreq struct for this SCE/CPE block * initialized SBRChan struct for this channel * index of current channel (0 for SCE, 0 or 1 for CPE) * index of current envelope * * Outputs: envelope gain, sinusoids and noise after scaling * * Return: none **********************************************************************************************************************/ void CalcGain(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch, int env) { int lim, fbitsDQ; /* initialize to -1 so that mapping limiter bands to env/noise bands works right on first pass */ m_PSInfoSBR->envBand = -1; m_PSInfoSBR->noiseFloorBand = -1; m_PSInfoSBR->sBand = -1; m_PSInfoSBR->highBand = -1; fbitsDQ = (FBITS_OUT_DQ_ENV - m_PSInfoSBR->envDataDequantScale[ch][env]); /* Q(29 - optional scalefactor) */ for(lim = 0; lim < sbrFreq->nLimiter; lim++) { /* the QMF bands are divided into lim regions (consecutive, non-overlapping) */ CalcMaxGain(sbrHdr, sbrGrid, sbrFreq, ch, env, lim, fbitsDQ); CalcComponentGains(sbrGrid, sbrFreq, sbrChan, ch, env, lim, fbitsDQ); ApplyBoost(sbrFreq, lim, fbitsDQ); } } /* hSmooth table from 4.7.18.7.6, format = Q31 */ static const int hSmoothCoef[MAX_NUM_SMOOTH_COEFS] PROGMEM = { 0x2aaaaaab, 0x2697a512, 0x1becfa68, 0x0ebdb043, 0x04130598, }; /*********************************************************************************************************************** * Function: MapHF * * Description: map HF components to proper QMF bands, with optional gain smoothing * filter (4.6.18.7.6) * * Inputs: initialized SBRHeader struct for this SCE/CPE block * initialized SBRGrid struct for this channel * initialized SBRFreq struct for this SCE/CPE block * initialized SBRChan struct for this channel * index of current envelope * reset flag (can be non-zero for first envelope only) * * Outputs: complete reconstructed subband QMF samples for this envelope * * Return: none * * Notes: ensures that output has >= MIN_GBITS_IN_QMFS guard bits, * so it's not necessary to check anything in the synth QMF **********************************************************************************************************************/ void MapHF(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int env, int hfReset) { int noiseTabIndex, sinIndex, gainNoiseIndex, hSL; int i, iStart, iEnd, m, idx, j, s, n, smre, smim; int gFilt, qFilt, xre, xim, gbMask, gbIdx; int *XBuf; noiseTabIndex = sbrChan->noiseTabIndex; sinIndex = sbrChan->sinIndex; gainNoiseIndex = sbrChan->gainNoiseIndex; /* oldest entries in filter delay buffer */ if(hfReset) noiseTabIndex = 2; /* starts at 1, double since complex */ hSL = (sbrHdr->smoothMode ? 0 : 4); if(hfReset) { for(i = 0; i < hSL; i++) { for(m = 0; m < sbrFreq->numQMFBands; m++) { sbrChan->gTemp[gainNoiseIndex][m] = m_PSInfoSBR->gLimBoost[m]; sbrChan->qTemp[gainNoiseIndex][m] = m_PSInfoSBR->qmLimBoost[m]; } gainNoiseIndex++; if(gainNoiseIndex == MAX_NUM_SMOOTH_COEFS) gainNoiseIndex = 0; } ASSERT(env == 0); /* should only be reset when env == 0 */ } iStart = sbrGrid->envTimeBorder[env]; iEnd = sbrGrid->envTimeBorder[env + 1]; for(i = iStart; i < iEnd; i++) { /* save new values in temp buffers (delay) * we only store MAX_NUM_SMOOTH_COEFS most recent values, * so don't keep storing the same value over and over */ if(i - iStart < MAX_NUM_SMOOTH_COEFS) { for(m = 0; m < sbrFreq->numQMFBands; m++) { sbrChan->gTemp[gainNoiseIndex][m] = m_PSInfoSBR->gLimBoost[m]; sbrChan->qTemp[gainNoiseIndex][m] = m_PSInfoSBR->qmLimBoost[m]; } } /* see 4.6.18.7.6 */ XBuf = m_PSInfoSBR->XBuf[i + HF_ADJ][sbrFreq->kStart]; gbMask = 0; for(m = 0; m < sbrFreq->numQMFBands; m++) { if(env == m_PSInfoSBR->la || env == sbrChan->laPrev) { /* no smoothing filter for gain, and qFilt = 0 (only need to do once) */ if(i == iStart) { m_PSInfoSBR->gFiltLast[m] = sbrChan->gTemp[gainNoiseIndex][m]; m_PSInfoSBR->qFiltLast[m] = 0; } } else if(hSL == 0) { /* no smoothing filter for gain, (only need to do once) */ if(i == iStart) { m_PSInfoSBR->gFiltLast[m] = sbrChan->gTemp[gainNoiseIndex][m]; m_PSInfoSBR->qFiltLast[m] = sbrChan->qTemp[gainNoiseIndex][m]; } } else { /* apply smoothing filter to gain and noise (after MAX_NUM_SMOOTH_COEFS, it's always the same) */ if(i - iStart < MAX_NUM_SMOOTH_COEFS) { gFilt = 0; qFilt = 0; idx = gainNoiseIndex; for(j = 0; j < MAX_NUM_SMOOTH_COEFS; j++) { /* sum(abs(hSmoothCoef[j])) for all j < 1.0 */ gFilt += MULSHIFT32(sbrChan->gTemp[idx][m], hSmoothCoef[j]); qFilt += MULSHIFT32(sbrChan->qTemp[idx][m], hSmoothCoef[j]); idx--; if(idx < 0) idx += MAX_NUM_SMOOTH_COEFS; } m_PSInfoSBR->gFiltLast[m] = gFilt << 1; /* restore to Q(FBITS_GLIM_BOOST) (gain of filter < 1.0, so no overflow) */ m_PSInfoSBR->qFiltLast[m] = qFilt << 1; /* restore to Q(FBITS_QLIM_BOOST) */ } } if(m_PSInfoSBR->smBoost[m] != 0) { /* add scaled signal and sinusoid, don't add noise (qFilt = 0) */ smre = m_PSInfoSBR->smBoost[m]; smim = smre; /* sinIndex: [0] xre += sm [1] xim += sm*s [2] xre -= sm [3] xim -= sm*s */ s = (sinIndex >> 1); /* if 2 or 3, flip sign to subtract sm */ s <<= 31; smre ^= (s >> 31); smre -= (s >> 31); s ^= ((m + sbrFreq->kStart) << 31); smim ^= (s >> 31); smim -= (s >> 31); /* if sinIndex == 0 or 2, smim = 0; if sinIndex == 1 or 3, smre = 0 */ s = sinIndex << 31; smim &= (s >> 31); s ^= 0x80000000; smre &= (s >> 31); noiseTabIndex += 2; /* noise filtered by 0, but still need to bump index */ } else { /* add scaled signal and scaled noise */ qFilt = m_PSInfoSBR->qFiltLast[m]; n = noiseTab[noiseTabIndex++]; smre = MULSHIFT32(n, qFilt) >> (FBITS_QLIM_BOOST - 1 - FBITS_OUT_QMFA); n = noiseTab[noiseTabIndex++]; smim = MULSHIFT32(n, qFilt) >> (FBITS_QLIM_BOOST - 1 - FBITS_OUT_QMFA); } noiseTabIndex &= 1023; /* 512 complex numbers */ gFilt = m_PSInfoSBR->gFiltLast[m]; xre = MULSHIFT32(gFilt, XBuf[0]); xim = MULSHIFT32(gFilt, XBuf[1]); xre = CLIP_2N_SHIFT30(xre, 32 - FBITS_GLIM_BOOST); xim = CLIP_2N_SHIFT30(xim, 32 - FBITS_GLIM_BOOST); xre += smre; *XBuf++ = xre; xim += smim; *XBuf++ = xim; gbMask |= FASTABS(xre); gbMask |= FASTABS(xim); } /* update circular buffer index */ gainNoiseIndex++; if(gainNoiseIndex == MAX_NUM_SMOOTH_COEFS) gainNoiseIndex = 0; sinIndex++; sinIndex &= 3; /* ensure MIN_GBITS_IN_QMFS guard bits in output * almost never occurs in practice, but checking here makes synth QMF logic very simple */ if(gbMask >> (31 - MIN_GBITS_IN_QMFS)) { XBuf = m_PSInfoSBR->XBuf[i + HF_ADJ][sbrFreq->kStart]; for(m = 0; m < sbrFreq->numQMFBands; m++) { xre = XBuf[0]; xim = XBuf[1]; xre = CLIP_2N(xre, (31 - MIN_GBITS_IN_QMFS)); xim = CLIP_2N(xim, (31 - MIN_GBITS_IN_QMFS)); *XBuf++ = xre; *XBuf++ = xim; } gbMask = CLIP_2N(gbMask, (31 - MIN_GBITS_IN_QMFS)); } gbIdx = ((i + HF_ADJ) >> 5) & 0x01; sbrChan->gbMask[gbIdx] |= gbMask; } sbrChan->noiseTabIndex = noiseTabIndex; sbrChan->sinIndex = sinIndex; sbrChan->gainNoiseIndex = gainNoiseIndex; } /*********************************************************************************************************************** * Function: AdjustHighFreq * * Description: adjust high frequencies and add noise and sinusoids (4.6.18.7) * * Inputs: initialized SBRHeader struct for this SCE/CPE block * initialized SBRGrid struct for this channel * initialized SBRFreq struct for this SCE/CPE block * initialized SBRChan struct for this channel * index of current channel (0 for SCE, 0 or 1 for CPE) * * Outputs: complete reconstructed subband QMF samples for this channel * * Return: none **********************************************************************************************************************/ void AdjustHighFreq(SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch) { int i, env, hfReset; uint8_t frameClass, pointer; frameClass = sbrGrid->frameClass; pointer = sbrGrid->pointer; /* derive la from table 4.159 */ if ((frameClass == SBR_GRID_FIXVAR || frameClass == SBR_GRID_VARVAR) && pointer > 0) m_PSInfoSBR->la = sbrGrid->numEnv + 1 - pointer; else if (frameClass == SBR_GRID_VARFIX && pointer > 1) m_PSInfoSBR->la = pointer - 1; else m_PSInfoSBR->la = -1; /* for each envelope, estimate gain and adjust SBR QMF bands */ hfReset = sbrChan->reset; for (env = 0; env < sbrGrid->numEnv; env++) { EstimateEnvelope(sbrHdr, sbrGrid, sbrFreq, env); CalcGain(sbrHdr, sbrGrid, sbrFreq, sbrChan, ch, env); MapHF(sbrHdr, sbrGrid, sbrFreq, sbrChan, env, hfReset); hfReset = 0; /* only set for first envelope after header reset */ } /* set saved sine flags to 0 for QMF bands outside of current frequency range */ for (i = 0; i < sbrFreq->freqLimiter[0] + sbrFreq->kStart; i++) sbrChan->addHarmonic[0][i] = 0; for (i = sbrFreq->freqLimiter[sbrFreq->nLimiter] + sbrFreq->kStart; i < 64; i++) sbrChan->addHarmonic[0][i] = 0; sbrChan->addHarmonicFlag[0] = sbrChan->addHarmonicFlag[1]; /* save la for next frame */ if (m_PSInfoSBR->la == sbrGrid->numEnv) sbrChan->laPrev = 0; else sbrChan->laPrev = -1; } /*********************************************************************************************************************** * Function: CalcCovariance1 * * Description: calculate covariance matrix for p01, p12, p11, p22 (4.6.18.6.2) * * Inputs: buffer of low-freq samples, starting at time index 0, * freq index = patch subband * * Outputs: complex covariance elements p01re, p01im, p12re, p12im, p11re, p22re * (p11im = p22im = 0) * format = integer (Q0) * 2^N, with scalefactor N >= 0 * * Return: scalefactor N * * Notes: outputs are normalized to have 1 GB (sign in at least top 2 bits) **********************************************************************************************************************/ int CalcCovariance1(int *XBuf, int *p01reN, int *p01imN, int *p12reN, int *p12imN, int *p11reN, int *p22reN) { int accBuf[2*6]; int n, z, s, loShift, hiShift, gbMask; U64 p01re, p01im, p12re, p12im, p11re, p22re; CVKernel1(XBuf, accBuf); p01re.r.lo32 = accBuf[0]; p01re.r.hi32 = accBuf[1]; p01im.r.lo32 = accBuf[2]; p01im.r.hi32 = accBuf[3]; p11re.r.lo32 = accBuf[4]; p11re.r.hi32 = accBuf[5]; p12re.r.lo32 = accBuf[6]; p12re.r.hi32 = accBuf[7]; p12im.r.lo32 = accBuf[8]; p12im.r.hi32 = accBuf[9]; p22re.r.lo32 = accBuf[10]; p22re.r.hi32 = accBuf[11]; /* 64-bit accumulators now have 2*FBITS_OUT_QMFA fraction bits * want to scale them down to integers (32-bit signed, Q0) * with scale factor of 2^n, n >= 0 * leave 2 GB's for calculating determinant, so take top 30 non-zero bits */ gbMask = ((p01re.r.hi32) ^ (p01re.r.hi32 >> 31)) | ((p01im.r.hi32) ^ (p01im.r.hi32 >> 31)); gbMask |= ((p12re.r.hi32) ^ (p12re.r.hi32 >> 31)) | ((p12im.r.hi32) ^ (p12im.r.hi32 >> 31)); gbMask |= ((p11re.r.hi32) ^ (p11re.r.hi32 >> 31)) | ((p22re.r.hi32) ^ (p22re.r.hi32 >> 31)); if (gbMask == 0) { s = p01re.r.hi32 >> 31; gbMask = (p01re.r.lo32 ^ s) - s; s = p01im.r.hi32 >> 31; gbMask |= (p01im.r.lo32 ^ s) - s; s = p12re.r.hi32 >> 31; gbMask |= (p12re.r.lo32 ^ s) - s; s = p12im.r.hi32 >> 31; gbMask |= (p12im.r.lo32 ^ s) - s; s = p11re.r.hi32 >> 31; gbMask |= (p11re.r.lo32 ^ s) - s; s = p22re.r.hi32 >> 31; gbMask |= (p22re.r.lo32 ^ s) - s; z = 32 + CLZ(gbMask); } else { gbMask = FASTABS(p01re.r.hi32) | FASTABS(p01im.r.hi32); gbMask |= FASTABS(p12re.r.hi32) | FASTABS(p12im.r.hi32); gbMask |= FASTABS(p11re.r.hi32) | FASTABS(p22re.r.hi32); z = CLZ(gbMask); } n = 64 - z; /* number of non-zero bits in bottom of 64-bit word */ if (n <= 30) { loShift = (30 - n); *p01reN = p01re.r.lo32 << loShift; *p01imN = p01im.r.lo32 << loShift; *p12reN = p12re.r.lo32 << loShift; *p12imN = p12im.r.lo32 << loShift; *p11reN = p11re.r.lo32 << loShift; *p22reN = p22re.r.lo32 << loShift; return -(loShift + 2*FBITS_OUT_QMFA); } else if (n < 32 + 30) { loShift = (n - 30); hiShift = 32 - loShift; *p01reN = (p01re.r.hi32 << hiShift) | (p01re.r.lo32 >> loShift); *p01imN = (p01im.r.hi32 << hiShift) | (p01im.r.lo32 >> loShift); *p12reN = (p12re.r.hi32 << hiShift) | (p12re.r.lo32 >> loShift); *p12imN = (p12im.r.hi32 << hiShift) | (p12im.r.lo32 >> loShift); *p11reN = (p11re.r.hi32 << hiShift) | (p11re.r.lo32 >> loShift); *p22reN = (p22re.r.hi32 << hiShift) | (p22re.r.lo32 >> loShift); return (loShift - 2*FBITS_OUT_QMFA); } else { hiShift = n - (32 + 30); *p01reN = p01re.r.hi32 >> hiShift; *p01imN = p01im.r.hi32 >> hiShift; *p12reN = p12re.r.hi32 >> hiShift; *p12imN = p12im.r.hi32 >> hiShift; *p11reN = p11re.r.hi32 >> hiShift; *p22reN = p22re.r.hi32 >> hiShift; return (32 - 2*FBITS_OUT_QMFA - hiShift); } return 0; } /*********************************************************************************************************************** * Function: CalcCovariance2 * * Description: calculate covariance matrix for p02 (4.6.18.6.2) * * Inputs: buffer of low-freq samples, starting at time index = 0, * freq index = patch subband * * Outputs: complex covariance element p02re, p02im * format = integer (Q0) * 2^N, with scalefactor N >= 0 * * Return: scalefactor N * * Notes: outputs are normalized to have 1 GB (sign in at least top 2 bits) **********************************************************************************************************************/ int CalcCovariance2(int *XBuf, int *p02reN, int *p02imN) { U64 p02re, p02im; int n, z, s, loShift, hiShift, gbMask; int accBuf[2*2]; CVKernel2(XBuf, accBuf); p02re.r.lo32 = accBuf[0]; p02re.r.hi32 = accBuf[1]; p02im.r.lo32 = accBuf[2]; p02im.r.hi32 = accBuf[3]; /* 64-bit accumulators now have 2*FBITS_OUT_QMFA fraction bits * want to scale them down to integers (32-bit signed, Q0) * with scale factor of 2^n, n >= 0 * leave 1 GB for calculating determinant, so take top 30 non-zero bits */ gbMask = ((p02re.r.hi32) ^ (p02re.r.hi32 >> 31)) | ((p02im.r.hi32) ^ (p02im.r.hi32 >> 31)); if (gbMask == 0) { s = p02re.r.hi32 >> 31; gbMask = (p02re.r.lo32 ^ s) - s; s = p02im.r.hi32 >> 31; gbMask |= (p02im.r.lo32 ^ s) - s; z = 32 + CLZ(gbMask); } else { gbMask = FASTABS(p02re.r.hi32) | FASTABS(p02im.r.hi32); z = CLZ(gbMask); } n = 64 - z; /* number of non-zero bits in bottom of 64-bit word */ if (n <= 30) { loShift = (30 - n); *p02reN = p02re.r.lo32 << loShift; *p02imN = p02im.r.lo32 << loShift; return -(loShift + 2*FBITS_OUT_QMFA); } else if (n < 32 + 30) { loShift = (n - 30); hiShift = 32 - loShift; *p02reN = (p02re.r.hi32 << hiShift) | (p02re.r.lo32 >> loShift); *p02imN = (p02im.r.hi32 << hiShift) | (p02im.r.lo32 >> loShift); return (loShift - 2*FBITS_OUT_QMFA); } else { hiShift = n - (32 + 30); *p02reN = p02re.r.hi32 >> hiShift; *p02imN = p02im.r.hi32 >> hiShift; return (32 - 2*FBITS_OUT_QMFA - hiShift); } return 0; } /*********************************************************************************************************************** * Function: CalcLPCoefs * * Description: calculate linear prediction coefficients for one subband (4.6.18.6.2) * * Inputs: buffer of low-freq samples, starting at time index = 0, * freq index = patch subband * number of guard bits in input sample buffer * * Outputs: complex LP coefficients a0re, a0im, a1re, a1im, format = Q29 * * Return: none * * Notes: output coefficients (a0re, a0im, a1re, a1im) clipped to range (-4, 4) * if the comples coefficients have magnitude >= 4.0, they are all * set to 0 (see spec) **********************************************************************************************************************/ void CalcLPCoefs(int *XBuf, int *a0re, int *a0im, int *a1re, int *a1im, int gb) { int zFlag, n1, n2, nd, d, dInv, tre, tim; int p01re, p01im, p02re, p02im, p12re, p12im, p11re, p22re; /* pre-scale to avoid overflow - probably never happens in practice (see QMFA) * max bit growth per accumulator = 38*2 = 76 mul-adds (X * X) * using 64-bit MADD, so if X has n guard bits, X*X has 2n+1 guard bits * gain 1 extra sign bit per multiply, so ensure ceil(log2(76/2) / 2) = 3 guard bits on inputs */ if (gb < 3) { nd = 3 - gb; for (n1 = (NUM_TIME_SLOTS*SAMPLES_PER_SLOT + 6 + 2); n1 != 0; n1--) { XBuf[0] >>= nd; XBuf[1] >>= nd; XBuf += (2*64); } XBuf -= (2*64*(NUM_TIME_SLOTS*SAMPLES_PER_SLOT + 6 + 2)); } /* calculate covariance elements */ n1 = CalcCovariance1(XBuf, &p01re, &p01im, &p12re, &p12im, &p11re, &p22re); n2 = CalcCovariance2(XBuf, &p02re, &p02im); /* normalize everything to larger power of 2 scalefactor, call it n1 */ if (n1 < n2) { nd = MIN(n2 - n1, 31); p01re >>= nd; p01im >>= nd; p12re >>= nd; p12im >>= nd; p11re >>= nd; p22re >>= nd; n1 = n2; } else if (n1 > n2) { nd = MIN(n1 - n2, 31); p02re >>= nd; p02im >>= nd; } /* calculate determinant of covariance matrix (at least 1 GB in pXX) */ d = MULSHIFT32(p12re, p12re) + MULSHIFT32(p12im, p12im); d = MULSHIFT32(d, RELAX_COEF) << 1; d = MULSHIFT32(p11re, p22re) - d; ASSERT(d >= 0); /* should never be < 0 */ zFlag = 0; *a0re = *a0im = 0; *a1re = *a1im = 0; if (d > 0) { /* input = Q31 d = Q(-2*n1 - 32 + nd) = Q31 * 2^(31 + 2*n1 + 32 - nd) * inverse = Q29 dInv = Q29 * 2^(-31 - 2*n1 - 32 + nd) = Q(29 + 31 + 2*n1 + 32 - nd) * * numerator has same Q format as d, since it's sum of normalized squares * so num * inverse = Q(-2*n1 - 32) * Q(29 + 31 + 2*n1 + 32 - nd) * = Q(29 + 31 - nd), drop low 32 in MULSHIFT32 * = Q(29 + 31 - 32 - nd) = Q(28 - nd) */ nd = CLZ(d) - 1; d <<= nd; dInv = InvRNormalized(d); /* 1 GB in pXX */ tre = MULSHIFT32(p01re, p12re) - MULSHIFT32(p01im, p12im) - MULSHIFT32(p02re, p11re); tre = MULSHIFT32(tre, dInv); tim = MULSHIFT32(p01re, p12im) + MULSHIFT32(p01im, p12re) - MULSHIFT32(p02im, p11re); tim = MULSHIFT32(tim, dInv); /* if d is extremely small, just set coefs to 0 (would have poor precision anyway) */ if (nd > 28 || (FASTABS(tre) >> (28 - nd)) >= 4 || (FASTABS(tim) >> (28 - nd)) >= 4) { zFlag = 1; } else { *a1re = tre << (FBITS_LPCOEFS - 28 + nd); /* i.e. convert Q(28 - nd) to Q(29) */ *a1im = tim << (FBITS_LPCOEFS - 28 + nd); } } if (p11re) { /* input = Q31 p11re = Q(-n1 + nd) = Q31 * 2^(31 + n1 - nd) * inverse = Q29 dInv = Q29 * 2^(-31 - n1 + nd) = Q(29 + 31 + n1 - nd) * * numerator is Q(-n1 - 3) * so num * inverse = Q(-n1 - 3) * Q(29 + 31 + n1 - nd) * = Q(29 + 31 - 3 - nd), drop low 32 in MULSHIFT32 * = Q(29 + 31 - 3 - 32 - nd) = Q(25 - nd) */ nd = CLZ(p11re) - 1; /* assume positive */ p11re <<= nd; dInv = InvRNormalized(p11re); /* a1re, a1im = Q29, so scaled by (n1 + 3) */ tre = (p01re >> 3) + MULSHIFT32(p12re, *a1re) + MULSHIFT32(p12im, *a1im); tre = -MULSHIFT32(tre, dInv); tim = (p01im >> 3) - MULSHIFT32(p12im, *a1re) + MULSHIFT32(p12re, *a1im); tim = -MULSHIFT32(tim, dInv); if (nd > 25 || (FASTABS(tre) >> (25 - nd)) >= 4 || (FASTABS(tim) >> (25 - nd)) >= 4) { zFlag = 1; } else { *a0re = tre << (FBITS_LPCOEFS - 25 + nd); /* i.e. convert Q(25 - nd) to Q(29) */ *a0im = tim << (FBITS_LPCOEFS - 25 + nd); } } /* see 4.6.18.6.2 - if magnitude of a0 or a1 >= 4 then a0 = a1 = 0 * i.e. a0re < 4, a0im < 4, a1re < 4, a1im < 4 * Q29*Q29 = Q26 */ if (zFlag || MULSHIFT32(*a0re, *a0re) + MULSHIFT32(*a0im, *a0im) >= MAG_16 || MULSHIFT32(*a1re, *a1re) + MULSHIFT32(*a1im, *a1im) >= MAG_16) { *a0re = *a0im = 0; *a1re = *a1im = 0; } /* no need to clip - we never changed the XBuf data, just used it to calculate a0 and a1 */ if (gb < 3) { nd = 3 - gb; for (n1 = (NUM_TIME_SLOTS*SAMPLES_PER_SLOT + 6 + 2); n1 != 0; n1--) { XBuf[0] <<= nd; XBuf[1] <<= nd; XBuf += (2*64); } } } /*********************************************************************************************************************** * Function: GenerateHighFreq * * Description: generate high frequencies with SBR (4.6.18.6) * * Inputs: initialized SBRGrid struct for this channel * initialized SBRFreq struct for this SCE/CPE block * initialized SBRChan struct for this channel * index of current channel (0 for SCE, 0 or 1 for CPE) * * Outputs: new high frequency samples starting at frequency kStart * * Return: none **********************************************************************************************************************/ void GenerateHighFreq(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch) { int band, newBW, c, t, gb, gbMask, gbIdx; int currPatch, p, x, k, g, i, iStart, iEnd, bw, bwsq; int a0re, a0im, a1re, a1im; int x1re, x1im, x2re, x2im; int ACCre, ACCim; int *XBufLo, *XBufHi; (void) ch; /* calculate array of chirp factors */ for (band = 0; band < sbrFreq->numNoiseFloorBands; band++) { c = sbrChan->chirpFact[band]; /* previous (bwArray') */ newBW = newBWTab[sbrChan->invfMode[0][band]][sbrChan->invfMode[1][band]]; /* weighted average of new and old (can't overflow - total gain = 1.0) */ if (newBW < c) t = MULSHIFT32(newBW, 0x60000000) + MULSHIFT32(0x20000000, c); /* new is smaller: 0.75*new + 0.25*old */ else t = MULSHIFT32(newBW, 0x74000000) + MULSHIFT32(0x0c000000, c); /* new is larger: 0.90625*new + 0.09375*old */ t <<= 1; if (t < 0x02000000) /* below 0.015625, clip to 0 */ t = 0; if (t > 0x7f800000) /* clip to 0.99609375 */ t = 0x7f800000; /* save curr as prev for next time */ sbrChan->chirpFact[band] = t; sbrChan->invfMode[0][band] = sbrChan->invfMode[1][band]; } iStart = sbrGrid->envTimeBorder[0] + HF_ADJ; iEnd = sbrGrid->envTimeBorder[sbrGrid->numEnv] + HF_ADJ; /* generate new high freqs from low freqs, patches, and chirp factors */ k = sbrFreq->kStart; g = 0; bw = sbrChan->chirpFact[g]; bwsq = MULSHIFT32(bw, bw) << 1; gbMask = (sbrChan->gbMask[0] | sbrChan->gbMask[1]); /* older 32 | newer 8 */ gb = CLZ(gbMask) - 1; for (currPatch = 0; currPatch < sbrFreq->numPatches; currPatch++) { for (x = 0; x < sbrFreq->patchNumSubbands[currPatch]; x++) { /* map k to corresponding noise floor band */ if (k >= sbrFreq->freqNoise[g+1]) { g++; bw = sbrChan->chirpFact[g]; /* Q31 */ bwsq = MULSHIFT32(bw, bw) << 1; /* Q31 */ } p = sbrFreq->patchStartSubband[currPatch] + x; /* low QMF band */ XBufHi = m_PSInfoSBR->XBuf[iStart][k]; if (bw) { CalcLPCoefs(m_PSInfoSBR->XBuf[0][p], &a0re, &a0im, &a1re, &a1im, gb); a0re = MULSHIFT32(bw, a0re); /* Q31 * Q29 = Q28 */ a0im = MULSHIFT32(bw, a0im); a1re = MULSHIFT32(bwsq, a1re); a1im = MULSHIFT32(bwsq, a1im); XBufLo = m_PSInfoSBR->XBuf[iStart-2][p]; x2re = XBufLo[0]; /* RE{XBuf[n-2]} */ x2im = XBufLo[1]; /* IM{XBuf[n-2]} */ XBufLo += (64*2); x1re = XBufLo[0]; /* RE{XBuf[n-1]} */ x1im = XBufLo[1]; /* IM{XBuf[n-1]} */ XBufLo += (64*2); for (i = iStart; i < iEnd; i++) { /* a0re/im, a1re/im are Q28 with at least 1 GB, * so the summing for AACre/im is fine (1 GB in, plus 1 from MULSHIFT32) */ ACCre = MULSHIFT32(x2re, a1re) - MULSHIFT32(x2im, a1im); ACCim = MULSHIFT32(x2re, a1im) + MULSHIFT32(x2im, a1re); x2re = x1re; x2im = x1im; ACCre += MULSHIFT32(x1re, a0re) - MULSHIFT32(x1im, a0im); ACCim += MULSHIFT32(x1re, a0im) + MULSHIFT32(x1im, a0re); x1re = XBufLo[0]; /* RE{XBuf[n]} */ x1im = XBufLo[1]; /* IM{XBuf[n]} */ XBufLo += (64*2); /* lost 4 fbits when scaling by a0re/im, a1re/im (Q28) */ ACCre = CLIP_2N_SHIFT30(ACCre, 4); ACCre += x1re; ACCim = CLIP_2N_SHIFT30(ACCim, 4); ACCim += x1im; XBufHi[0] = ACCre; XBufHi[1] = ACCim; XBufHi += (64*2); /* update guard bit masks */ gbMask = FASTABS(ACCre); gbMask |= FASTABS(ACCim); gbIdx = (i >> 5) & 0x01; /* 0 if i < 32, 1 if i >= 32 */ sbrChan->gbMask[gbIdx] |= gbMask; } } else { XBufLo = (int *)m_PSInfoSBR->XBuf[iStart][p]; for (i = iStart; i < iEnd; i++) { XBufHi[0] = XBufLo[0]; XBufHi[1] = XBufLo[1]; XBufLo += (64*2); XBufHi += (64*2); } } k++; /* high QMF band */ } } } /*********************************************************************************************************************** * Function: DecodeHuffmanScalar * * Description: decode one Huffman symbol from bitstream * * Inputs: pointers to Huffman table and info struct * left-aligned bit buffer with >= huffTabInfo->maxBits bits * * Outputs: decoded symbol in *val * * Return: number of bits in symbol * * Notes: assumes canonical Huffman codes: * first CW always 0, we have "count" CW's of length "nBits" bits * starting CW for codes of length nBits+1 = * (startCW[nBits] + count[nBits]) << 1 * if there are no codes at nBits, then we just keep << 1 each time * (since count[nBits] = 0) **********************************************************************************************************************/ int DecodeHuffmanScalar(const signed int *huffTab, const HuffInfo_t *huffTabInfo, unsigned int bitBuf, signed int *val) { unsigned int count, start, shift, t; const uint8_t *countPtr; const signed int /*short*/*map; map = huffTab + huffTabInfo->offset; countPtr = huffTabInfo->count; start = 0; count = 0; shift = 32; do { start += count; start <<= 1; map += count; count = *countPtr++; shift--; t = (bitBuf >> shift) - start; } while(t >= count); *val = (signed int) map[t]; return (countPtr - huffTabInfo->count); } /*********************************************************************************************************************** * Function: DecodeOneSymbol * * Description: dequantize one Huffman symbol from bitstream, * using table huffTabSBR[huffTabIndex] * * Inputs: index of Huffman table * * Outputs: bitstream advanced by number of bits in codeword * * Return: one decoded symbol **********************************************************************************************************************/ int DecodeOneSymbol(int huffTabIndex) { int nBits, val; unsigned int bitBuf; const HuffInfo_t *hi; hi = &(huffTabSBRInfo[huffTabIndex]); bitBuf = GetBitsNoAdvance(hi->maxBits) << (32 - hi->maxBits); nBits = DecodeHuffmanScalar(huffTabSBR, hi, bitBuf, &val); AdvanceBitstream(nBits); return val; } /* [1.0, sqrt(2)], format = Q29 (one guard bit for decoupling) */ static const int envDQTab[2] PROGMEM = {0x20000000, 0x2d413ccc}; /*********************************************************************************************************************** * Function: DequantizeEnvelope * * Description: dequantize envelope scalefactors * * Inputs: number of scalefactors to process * amplitude resolution flag for this frame (0 or 1) * quantized envelope scalefactors * * Outputs: dequantized envelope scalefactors * * Return: extra int bits in output (6 + expMax) * in other words, output format = Q(FBITS_OUT_DQ_ENV - (6 + expMax)) * * Notes: dequantized scalefactors have at least 2 GB **********************************************************************************************************************/ int DequantizeEnvelope(int nBands, int ampRes, int8_t *envQuant, int *envDequant) { int exp, expMax, i, scalei; if(nBands <= 0) return 0; /* scan for largest dequant value (do separately from envelope decoding to keep code cleaner) */ expMax = 0; for(i = 0; i < nBands; i++) { if(envQuant[i] > expMax) expMax = envQuant[i]; } /* dequantized envelope gains * envDequant = 64*2^(envQuant / alpha) = 2^(6 + envQuant / alpha) * if ampRes == 0, alpha = 2 and range of envQuant = [0, 127] * if ampRes == 1, alpha = 1 and range of envQuant = [0, 63] * also if coupling is on, envDequant is scaled by something in range [0, 2] * so range of envDequant = [2^6, 2^69] (no coupling), [2^6, 2^70] (with coupling) * * typical range (from observation) of envQuant/alpha = [0, 27] --> largest envQuant ~= 2^33 * output: Q(29 - (6 + expMax)) * * reference: 14496-3:2001(E)/4.6.18.3.5 and 14496-4:200X/FPDAM8/5.6.5.1.2.1.5 */ if(ampRes) { do { exp = *envQuant++; scalei = MIN(expMax - exp, 31); *envDequant++ = envDQTab[0] >> scalei; } while(--nBands); return (6 + expMax); } else { expMax >>= 1; do { exp = *envQuant++; scalei = MIN(expMax - (exp >> 1), 31); *envDequant++ = envDQTab[exp & 0x01] >> scalei; } while(--nBands); return (6 + expMax); } } /*********************************************************************************************************************** * Function: DequantizeNoise * * Description: dequantize noise scalefactors * * Inputs: number of scalefactors to process * quantized noise scalefactors * * Outputs: dequantized noise scalefactors, format = Q(FBITS_OUT_DQ_NOISE) * * Return: none * * Notes: dequantized scalefactors have at least 2 GB **********************************************************************************************************************/ void DequantizeNoise(int nBands, int8_t *noiseQuant, int *noiseDequant) { int exp, scalei; if(nBands <= 0) return; /* dequantize noise floor gains (4.6.18.3.5): * noiseDequant = 2^(NOISE_FLOOR_OFFSET - noiseQuant) * * range of noiseQuant = [0, 30] (see 4.6.18.3.6), NOISE_FLOOR_OFFSET = 6 * so range of noiseDequant = [2^-24, 2^6] */ do { exp = *noiseQuant++; scalei = NOISE_FLOOR_OFFSET - exp + FBITS_OUT_DQ_NOISE; /* 6 + 24 - exp, exp = [0,30] */ if(scalei < 0) *noiseDequant++ = 0; else if(scalei < 30) *noiseDequant++ = 1 << scalei; else *noiseDequant++ = 0x3fffffff; /* leave 2 GB */ } while(--nBands); } /*********************************************************************************************************************** * Function: DecodeSBREnvelope * * Description: decode delta Huffman coded envelope scalefactors from bitstream * * Inputs: initialized SBRGrid struct for this channel * initialized SBRFreq struct for this SCE/CPE block * initialized SBRChan struct for this channel * index of current channel (0 for SCE, 0 or 1 for CPE) * * Outputs: dequantized env scalefactors for left channel (before decoupling) * dequantized env scalefactors for right channel (if coupling off) * or raw decoded env scalefactors for right channel (if coupling on) * * Return: none **********************************************************************************************************************/ void DecodeSBREnvelope(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch) { int huffIndexTime, huffIndexFreq, env, envStartBits, band, nBands, sf, lastEnv; int freqRes, freqResPrev, dShift, i; if(m_PSInfoSBR->couplingFlag && ch) { dShift = 1; if(sbrGrid->ampResFrame) { huffIndexTime = HuffTabSBR_tEnv30b; huffIndexFreq = HuffTabSBR_fEnv30b; envStartBits = 5; } else { huffIndexTime = HuffTabSBR_tEnv15b; huffIndexFreq = HuffTabSBR_fEnv15b; envStartBits = 6; } } else { dShift = 0; if(sbrGrid->ampResFrame) { huffIndexTime = HuffTabSBR_tEnv30; huffIndexFreq = HuffTabSBR_fEnv30; envStartBits = 6; } else { huffIndexTime = HuffTabSBR_tEnv15; huffIndexFreq = HuffTabSBR_fEnv15; envStartBits = 7; } } /* range of envDataQuant[] = [0, 127] (see comments in DequantizeEnvelope() for reference) */ for(env = 0; env < sbrGrid->numEnv; env++) { nBands = (sbrGrid->freqRes[env] ? sbrFreq->nHigh : sbrFreq->nLow); freqRes = (sbrGrid->freqRes[env]); freqResPrev = (env == 0 ? sbrGrid->freqResPrev : sbrGrid->freqRes[env - 1]); lastEnv = (env == 0 ? sbrGrid->numEnvPrev - 1 : env - 1); if(lastEnv < 0) lastEnv = 0; /* first frame */ ASSERT(nBands <= MAX_QMF_BANDS); if(sbrChan->deltaFlagEnv[env] == 0) { /* delta coding in freq */ sf = GetBits(envStartBits) << dShift; sbrChan->envDataQuant[env][0] = sf; for(band = 1; band < nBands; band++) { sf = DecodeOneSymbol(huffIndexFreq) << dShift; sbrChan->envDataQuant[env][band] = sf + sbrChan->envDataQuant[env][band - 1]; } } else if(freqRes == freqResPrev) { /* delta coding in time - same freq resolution for both frames */ for(band = 0; band < nBands; band++) { sf = DecodeOneSymbol(huffIndexTime) << dShift; sbrChan->envDataQuant[env][band] = sf + sbrChan->envDataQuant[lastEnv][band]; } } else if(freqRes == 0 && freqResPrev == 1) { /* delta coding in time - low freq resolution for new frame, high freq resolution for old frame */ for(band = 0; band < nBands; band++) { sf = DecodeOneSymbol(huffIndexTime) << dShift; sbrChan->envDataQuant[env][band] = sf; for(i = 0; i < sbrFreq->nHigh; i++) { if(sbrFreq->freqHigh[i] == sbrFreq->freqLow[band]) { sbrChan->envDataQuant[env][band] += sbrChan->envDataQuant[lastEnv][i]; break; } } } } else if(freqRes == 1 && freqResPrev == 0) { /* delta coding in time - high freq resolution for new frame, low freq resolution for old frame */ for(band = 0; band < nBands; band++) { sf = DecodeOneSymbol(huffIndexTime) << dShift; sbrChan->envDataQuant[env][band] = sf; for(i = 0; i < sbrFreq->nLow; i++) { if(sbrFreq->freqLow[i] <= sbrFreq->freqHigh[band] && sbrFreq->freqHigh[band] < sbrFreq->freqLow[i + 1]) { sbrChan->envDataQuant[env][band] += sbrChan->envDataQuant[lastEnv][i]; break; } } } } /* skip coupling channel */ if(ch != 1 || m_PSInfoSBR->couplingFlag != 1) m_PSInfoSBR->envDataDequantScale[ch][env] = DequantizeEnvelope(nBands, sbrGrid->ampResFrame, sbrChan->envDataQuant[env], m_PSInfoSBR->envDataDequant[ch][env]); } sbrGrid->numEnvPrev = sbrGrid->numEnv; sbrGrid->freqResPrev = sbrGrid->freqRes[sbrGrid->numEnv - 1]; } /*********************************************************************************************************************** * Function: DecodeSBRNoise * * Description: decode delta Huffman coded noise scalefactors from bitstream * * Inputs: initialized SBRGrid struct for this channel * initialized SBRFreq struct for this SCE/CPE block * initialized SBRChan struct for this channel * index of current channel (0 for SCE, 0 or 1 for CPE) * * Outputs: dequantized noise scalefactors for left channel (before decoupling) * dequantized noise scalefactors for right channel (if coupling off) * or raw decoded noise scalefactors for right channel (if coupling on) * * Return: none **********************************************************************************************************************/ void DecodeSBRNoise(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch) { int huffIndexTime, huffIndexFreq, noiseFloor, band, dShift, sf, lastNoiseFloor; if(m_PSInfoSBR->couplingFlag && ch) { dShift = 1; huffIndexTime = HuffTabSBR_tNoise30b; huffIndexFreq = HuffTabSBR_fNoise30b; } else { dShift = 0; huffIndexTime = HuffTabSBR_tNoise30; huffIndexFreq = HuffTabSBR_fNoise30; } for(noiseFloor = 0; noiseFloor < sbrGrid->numNoiseFloors; noiseFloor++) { lastNoiseFloor = (noiseFloor == 0 ? sbrGrid->numNoiseFloorsPrev - 1 : noiseFloor - 1); if(lastNoiseFloor < 0) lastNoiseFloor = 0; /* first frame */ ASSERT(sbrFreq->numNoiseFloorBands <= MAX_QMF_BANDS); if(sbrChan->deltaFlagNoise[noiseFloor] == 0) { /* delta coding in freq */ sbrChan->noiseDataQuant[noiseFloor][0] = GetBits(5) << dShift; for(band = 1; band < sbrFreq->numNoiseFloorBands; band++) { sf = DecodeOneSymbol(huffIndexFreq) << dShift; sbrChan->noiseDataQuant[noiseFloor][band] = sf + sbrChan->noiseDataQuant[noiseFloor][band - 1]; } } else { /* delta coding in time */ for(band = 0; band < sbrFreq->numNoiseFloorBands; band++) { sf = DecodeOneSymbol(huffIndexTime) << dShift; sbrChan->noiseDataQuant[noiseFloor][band] = sf + sbrChan->noiseDataQuant[lastNoiseFloor][band]; } } /* skip coupling channel */ if(ch != 1 || m_PSInfoSBR->couplingFlag != 1) DequantizeNoise(sbrFreq->numNoiseFloorBands, sbrChan->noiseDataQuant[noiseFloor], m_PSInfoSBR->noiseDataDequant[ch][noiseFloor]); } sbrGrid->numNoiseFloorsPrev = sbrGrid->numNoiseFloors; } /* dqTabCouple[i] = 2 / (1 + 2^(12 - i)), format = Q30 */ static const int dqTabCouple[25] PROGMEM = { 0x0007ff80, 0x000ffe00, 0x001ff802, 0x003fe010, 0x007f8080, 0x00fe03f8, 0x01f81f82, 0x03e0f83e, 0x07878788, 0x0e38e38e, 0x1999999a, 0x2aaaaaab, 0x40000000, 0x55555555, 0x66666666, 0x71c71c72, 0x78787878, 0x7c1f07c2, 0x7e07e07e, 0x7f01fc08, 0x7f807f80, 0x7fc01ff0, 0x7fe007fe, 0x7ff00200, 0x7ff80080, }; /*********************************************************************************************************************** * Function: UncoupleSBREnvelope * * Description: scale dequantized envelope scalefactors according to channel * coupling rules * * Inputs: initialized SBRGrid struct for this channel * initialized SBRFreq struct for this SCE/CPE block * initialized SBRChan struct for right channel including * quantized envelope scalefactors * * Outputs: dequantized envelope data for left channel (after decoupling) * dequantized envelope data for right channel (after decoupling) * * Return: none **********************************************************************************************************************/ void UncoupleSBREnvelope(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChanR) { int env, band, nBands, scalei, E_1; scalei = (sbrGrid->ampResFrame ? 0 : 1); for(env = 0; env < sbrGrid->numEnv; env++) { nBands = (sbrGrid->freqRes[env] ? sbrFreq->nHigh : sbrFreq->nLow); m_PSInfoSBR->envDataDequantScale[1][env] = m_PSInfoSBR->envDataDequantScale[0][env]; for(band = 0; band < nBands; band++) { /* clip E_1 to [0, 24] (scalefactors approach 0 or 2) */ E_1 = sbrChanR->envDataQuant[env][band] >> scalei; if(E_1 < 0) E_1 = 0; if(E_1 > 24) E_1 = 24; /* envDataDequant[0] has 1 GB, so << by 2 is okay */ m_PSInfoSBR->envDataDequant[1][env][band] = MULSHIFT32(m_PSInfoSBR->envDataDequant[0][env][band], dqTabCouple[24 - E_1]) << 2; m_PSInfoSBR->envDataDequant[0][env][band] = MULSHIFT32(m_PSInfoSBR->envDataDequant[0][env][band], dqTabCouple[E_1]) << 2; } } } /*********************************************************************************************************************** * Function: UncoupleSBRNoise * * Description: scale dequantized noise floor scalefactors according to channel * coupling rules * * Inputs: initialized SBRGrid struct for this channel * initialized SBRFreq struct for this SCE/CPE block * initialized SBRChan struct for this channel including * quantized noise scalefactors * * Outputs: dequantized noise data for left channel (after decoupling) * dequantized noise data for right channel (after decoupling) * * Return: none **********************************************************************************************************************/ void UncoupleSBRNoise(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChanR) { int noiseFloor, band, Q_1; for (noiseFloor = 0; noiseFloor < sbrGrid->numNoiseFloors; noiseFloor++) { for (band = 0; band < sbrFreq->numNoiseFloorBands; band++) { /* Q_1 should be in range [0, 24] according to 4.6.18.3.6, but check to make sure */ Q_1 = sbrChanR->noiseDataQuant[noiseFloor][band]; if (Q_1 < 0) Q_1 = 0; if (Q_1 > 24) Q_1 = 24; /* noiseDataDequant[0] has 1 GB, so << by 2 is okay */ m_PSInfoSBR->noiseDataDequant[1][noiseFloor][band] = MULSHIFT32(m_PSInfoSBR->noiseDataDequant[0][noiseFloor][band], dqTabCouple[24 - Q_1]) << 2; m_PSInfoSBR->noiseDataDequant[0][noiseFloor][band] = MULSHIFT32(m_PSInfoSBR->noiseDataDequant[0][noiseFloor][band], dqTabCouple[Q_1]) << 2; } } } /*********************************************************************************************************************** * Function: DecWindowOverlapNoClip * * Description: apply synthesis window, do overlap-add without clipping, * for winSequence LONG-LONG * * Inputs: input buffer (output of type-IV DCT) * overlap buffer (saved from last time) * window type (sin or KBD) for input buffer * window type (sin or KBD) for overlap buffer * * Outputs: one channel, one frame of 32-bit PCM, non-interleaved * * Return: none * * Notes: use this function when the decoded PCM is going to the SBR decoder **********************************************************************************************************************/ void DecWindowOverlapNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev) { int in, w0, w1, f0, f1; int *buf1, *over1, *out1; const int *wndPrev, *wndCurr; buf0 += (1024 >> 1); buf1 = buf0 - 1; out1 = out0 + 1024 - 1; over1 = over0 + 1024 - 1; wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); if (winTypeCurr == winTypePrev) { /* cut window loads in half since current and overlap sections use same symmetric window */ do { w0 = *wndPrev++; w1 = *wndPrev++; in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *over0; *out0++ = in - f0; in = *over1; *out1-- = in + f1; in = *buf1--; *over1-- = MULSHIFT32(w0, in); *over0++ = MULSHIFT32(w1, in); } while (over0 < over1); } else { /* different windows for current and overlap parts - should still fit in registers on ARM w/o stack spill */ wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); do { w0 = *wndPrev++; w1 = *wndPrev++; in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *over0; *out0++ = in - f0; in = *over1; *out1-- = in + f1; w0 = *wndCurr++; w1 = *wndCurr++; in = *buf1--; *over1-- = MULSHIFT32(w0, in); *over0++ = MULSHIFT32(w1, in); } while (over0 < over1); } } /*********************************************************************************************************************** * Function: DecWindowOverlapLongStart * * Description: apply synthesis window, do overlap-add, without clipping * for winSequence LONG-START * * Inputs: input buffer (output of type-IV DCT) * overlap buffer (saved from last time) * window type (sin or KBD) for input buffer * window type (sin or KBD) for overlap buffer * * Outputs: one channel, one frame of 32-bit PCM, non-interleaved * * Return: none * * Notes: use this function when the decoded PCM is going to the SBR decoder **********************************************************************************************************************/ void DecWindowOverlapLongStartNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev) { int i, in, w0, w1, f0, f1; int *buf1, *over1, *out1; const int *wndPrev, *wndCurr; buf0 += (1024 >> 1); buf1 = buf0 - 1; out1 = out0 + 1024 - 1; over1 = over0 + 1024 - 1; wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); i = 448; /* 2 outputs, 2 overlaps per loop */ do { w0 = *wndPrev++; w1 = *wndPrev++; in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *over0; *out0++ = in - f0; in = *over1; *out1-- = in + f1; in = *buf1--; *over1-- = 0; /* Wn = 0 for n = (2047, 2046, ... 1600) */ *over0++ = in >> 1; /* Wn = 1 for n = (1024, 1025, ... 1471) */ } while (--i); wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); /* do 64 more loops - 2 outputs, 2 overlaps per loop */ do { w0 = *wndPrev++; w1 = *wndPrev++; in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *over0; *out0++ = in - f0; in = *over1; *out1-- = in + f1; w0 = *wndCurr++; /* W[0], W[1], ... --> W[255], W[254], ... */ w1 = *wndCurr++; /* W[127], W[126], ... --> W[128], W[129], ... */ in = *buf1--; *over1-- = MULSHIFT32(w0, in); /* Wn = short window for n = (1599, 1598, ... , 1536) */ *over0++ = MULSHIFT32(w1, in); /* Wn = short window for n = (1472, 1473, ... , 1535) */ } while (over0 < over1); } /*********************************************************************************************************************** * Function: DecWindowOverlapLongStop * * Description: apply synthesis window, do overlap-add, without clipping * for winSequence LONG-STOP * * Inputs: input buffer (output of type-IV DCT) * overlap buffer (saved from last time) * window type (sin or KBD) for input buffer * window type (sin or KBD) for overlap buffer * * Outputs: one channel, one frame of 32-bit PCM, non-interleaved * * Return: none * * Notes: use this function when the decoded PCM is going to the SBR decoder **********************************************************************************************************************/ void DecWindowOverlapLongStopNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev) { int i, in, w0, w1, f0, f1; int *buf1, *over1, *out1; const int *wndPrev, *wndCurr; buf0 += (1024 >> 1); buf1 = buf0 - 1; out1 = out0 + 1024 - 1; over1 = over0 + 1024 - 1; wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]); i = 448; /* 2 outputs, 2 overlaps per loop */ do { /* Wn = 0 for n = (0, 1, ... 447) */ /* Wn = 1 for n = (576, 577, ... 1023) */ in = *buf0++; f1 = in >> 1; /* scale since skipping multiply by Q31 */ in = *over0; *out0++ = in; in = *over1; *out1-- = in + f1; w0 = *wndCurr++; w1 = *wndCurr++; in = *buf1--; *over1-- = MULSHIFT32(w0, in); *over0++ = MULSHIFT32(w1, in); } while (--i); /* do 64 more loops - 2 outputs, 2 overlaps per loop */ do { w0 = *wndPrev++; /* W[0], W[1], ...W[63] */ w1 = *wndPrev++; /* W[127], W[126], ... W[64] */ in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *over0; *out0++ = in - f0; in = *over1; *out1-- = in + f1; w0 = *wndCurr++; w1 = *wndCurr++; in = *buf1--; *over1-- = MULSHIFT32(w0, in); *over0++ = MULSHIFT32(w1, in); } while (over0 < over1); } /*********************************************************************************************************************** * Function: DecWindowOverlapShort * * Description: apply synthesis window, do overlap-add, without clipping * for winSequence EIGHT-SHORT (does all 8 short blocks) * * Inputs: input buffer (output of type-IV DCT) * overlap buffer (saved from last time) * window type (sin or KBD) for input buffer * window type (sin or KBD) for overlap buffer * * Outputs: one channel, one frame of 32-bit PCM, non-interleaved * * Return: none * * Notes: use this function when the decoded PCM is going to the SBR decoder **********************************************************************************************************************/ void DecWindowOverlapShortNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev) { int i, in, w0, w1, f0, f1; int *buf1, *over1, *out1; const int *wndPrev, *wndCurr; wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]); /* pcm[0-447] = 0 + overlap[0-447] */ i = 448; do { f0 = *over0++; f1 = *over0++; *out0++ = f0; *out0++ = f1; i -= 2; } while (i); /* pcm[448-575] = Wp[0-127] * block0[0-127] + overlap[448-575] */ out1 = out0 + (128 - 1); over1 = over0 + 128 - 1; buf0 += 64; buf1 = buf0 - 1; do { w0 = *wndPrev++; /* W[0], W[1], ...W[63] */ w1 = *wndPrev++; /* W[127], W[126], ... W[64] */ in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *over0; *out0++ = in - f0; in = *over1; *out1-- = in + f1; w0 = *wndCurr++; w1 = *wndCurr++; in = *buf1--; /* save over0/over1 for next short block, in the slots just vacated */ *over1-- = MULSHIFT32(w0, in); *over0++ = MULSHIFT32(w1, in); } while (over0 < over1); /* pcm[576-703] = Wc[128-255] * block0[128-255] + Wc[0-127] * block1[0-127] + overlap[576-703] * pcm[704-831] = Wc[128-255] * block1[128-255] + Wc[0-127] * block2[0-127] + overlap[704-831] * pcm[832-959] = Wc[128-255] * block2[128-255] + Wc[0-127] * block3[0-127] + overlap[832-959] */ for (i = 0; i < 3; i++) { out0 += 64; out1 = out0 + 128 - 1; over0 += 64; over1 = over0 + 128 - 1; buf0 += 64; buf1 = buf0 - 1; wndCurr -= 128; do { w0 = *wndCurr++; /* W[0], W[1], ...W[63] */ w1 = *wndCurr++; /* W[127], W[126], ... W[64] */ in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *(over0 - 128); /* from last short block */ in += *(over0 + 0); /* from last full frame */ *out0++ = in - f0; in = *(over1 - 128); /* from last short block */ in += *(over1 + 0); /* from last full frame */ *out1-- = in + f1; /* save over0/over1 for next short block, in the slots just vacated */ in = *buf1--; *over1-- = MULSHIFT32(w0, in); *over0++ = MULSHIFT32(w1, in); } while (over0 < over1); } /* pcm[960-1023] = Wc[128-191] * block3[128-191] + Wc[0-63] * block4[0-63] + overlap[960-1023] * over[0-63] = Wc[192-255] * block3[192-255] + Wc[64-127] * block4[64-127] */ out0 += 64; over0 -= 832; /* points at overlap[64] */ over1 = over0 + 128 - 1; /* points at overlap[191] */ buf0 += 64; buf1 = buf0 - 1; wndCurr -= 128; do { w0 = *wndCurr++; /* W[0], W[1], ...W[63] */ w1 = *wndCurr++; /* W[127], W[126], ... W[64] */ in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); in = *(over0 + 768); /* from last short block */ in += *(over0 + 896); /* from last full frame */ *out0++ = in - f0; in = *(over1 + 768); /* from last short block */ *(over1 - 128) = in + f1; in = *buf1--; *over1-- = MULSHIFT32(w0, in); /* save in overlap[128-191] */ *over0++ = MULSHIFT32(w1, in); /* save in overlap[64-127] */ } while (over0 < over1); /* over0 now points at overlap[128] */ /* over[64-191] = Wc[128-255] * block4[128-255] + Wc[0-127] * block5[0-127] * over[192-319] = Wc[128-255] * block5[128-255] + Wc[0-127] * block6[0-127] * over[320-447] = Wc[128-255] * block6[128-255] + Wc[0-127] * block7[0-127] * over[448-576] = Wc[128-255] * block7[128-255] */ for (i = 0; i < 3; i++) { over0 += 64; over1 = over0 + 128 - 1; buf0 += 64; buf1 = buf0 - 1; wndCurr -= 128; do { w0 = *wndCurr++; /* W[0], W[1], ...W[63] */ w1 = *wndCurr++; /* W[127], W[126], ... W[64] */ in = *buf0++; f0 = MULSHIFT32(w0, in); f1 = MULSHIFT32(w1, in); /* from last short block */ *(over0 - 128) -= f0; *(over1 - 128)+= f1; in = *buf1--; *over1-- = MULSHIFT32(w0, in); *over0++ = MULSHIFT32(w1, in); } while (over0 < over1); } /* over[576-1024] = 0 */ i = 448; over0 += 64; do { *over0++ = 0; *over0++ = 0; *over0++ = 0; *over0++ = 0; i -= 4; } while (i); } /*********************************************************************************************************************** * Function: PreMultiply64 * * Description: pre-twiddle stage of 64-point DCT-IV * * Inputs: buffer of 64 samples * * Outputs: processed samples in same buffer * * Return: none * * Notes: minimum 1 GB in, 2 GB out, gains 2 int bits * gbOut = gbIn + 1 * output is limited to sqrt(2)/2 plus GB in full GB * uses 3-mul, 3-add butterflies instead of 4-mul, 2-add **********************************************************************************************************************/ void PreMultiply64(int *zbuf1) { int i, ar1, ai1, ar2, ai2, z1, z2; int t, cms2, cps2a, sin2a, cps2b, sin2b; int *zbuf2; const int *csptr; zbuf2 = zbuf1 + 64 - 1; csptr = cos4sin4tab64; /* whole thing should fit in registers - verify that compiler does this */ for (i = 64 >> 2; i != 0; i--) { /* cps2 = (cos+sin), sin2 = sin, cms2 = (cos-sin) */ cps2a = *csptr++; sin2a = *csptr++; cps2b = *csptr++; sin2b = *csptr++; ar1 = *(zbuf1 + 0); ai2 = *(zbuf1 + 1); ai1 = *(zbuf2 + 0); ar2 = *(zbuf2 - 1); /* gain 2 ints bit from MULSHIFT32 by Q30 * max per-sample gain (ignoring implicit scaling) = MAX(sin(angle)+cos(angle)) = 1.414 * i.e. gain 1 GB since worst case is sin(angle) = cos(angle) = 0.707 (Q30), gain 2 from * extra sign bits, and eat one in adding */ t = MULSHIFT32(sin2a, ar1 + ai1); z2 = MULSHIFT32(cps2a, ai1) - t; cms2 = cps2a - 2*sin2a; z1 = MULSHIFT32(cms2, ar1) + t; *zbuf1++ = z1; /* cos*ar1 + sin*ai1 */ *zbuf1++ = z2; /* cos*ai1 - sin*ar1 */ t = MULSHIFT32(sin2b, ar2 + ai2); z2 = MULSHIFT32(cps2b, ai2) - t; cms2 = cps2b - 2*sin2b; z1 = MULSHIFT32(cms2, ar2) + t; *zbuf2-- = z2; /* cos*ai2 - sin*ar2 */ *zbuf2-- = z1; /* cos*ar2 + sin*ai2 */ } } /*********************************************************************************************************************** * Function: PostMultiply64 * * Description: post-twiddle stage of 64-point type-IV DCT * * Inputs: buffer of 64 samples * number of output samples to calculate * * Outputs: processed samples in same buffer * * Return: none * * Notes: minimum 1 GB in, 2 GB out, gains 2 int bits * gbOut = gbIn + 1 * output is limited to sqrt(2)/2 plus GB in full GB * nSampsOut is rounded up to next multiple of 4, since we calculate * 4 samples per loop **********************************************************************************************************************/ void PostMultiply64(int *fft1, int nSampsOut) { int i, ar1, ai1, ar2, ai2; int t, cms2, cps2, sin2; int *fft2; const int *csptr; csptr = cos1sin1tab64; fft2 = fft1 + 64 - 1; /* load coeffs for first pass * cps2 = (cos+sin)/2, sin2 = sin/2, cms2 = (cos-sin)/2 */ cps2 = *csptr++; sin2 = *csptr++; cms2 = cps2 - 2*sin2; for (i = (nSampsOut + 3) >> 2; i != 0; i--) { ar1 = *(fft1 + 0); ai1 = *(fft1 + 1); ar2 = *(fft2 - 1); ai2 = *(fft2 + 0); /* gain 2 int bits (multiplying by Q30), max gain = sqrt(2) */ t = MULSHIFT32(sin2, ar1 + ai1); *fft2-- = t - MULSHIFT32(cps2, ai1); *fft1++ = t + MULSHIFT32(cms2, ar1); cps2 = *csptr++; sin2 = *csptr++; ai2 = -ai2; t = MULSHIFT32(sin2, ar2 + ai2); *fft2-- = t - MULSHIFT32(cps2, ai2); cms2 = cps2 - 2*sin2; *fft1++ = t + MULSHIFT32(cms2, ar2); } } /*********************************************************************************************************************** * Function: QMFAnalysisConv * * Description: convolution kernel for analysis QMF * * Inputs: pointer to coefficient table, reordered for sequential access * delay buffer of size 32*10 = 320 real-valued PCM samples * index for delay ring buffer (range = [0, 9]) * * Outputs: 64 consecutive 32-bit samples * * Return: none * * Notes: this is carefully written to be efficient on ARM * use the assembly code version in sbrqmfak.s when building for ARM! **********************************************************************************************************************/ void QMFAnalysisConv(int *cTab, int *delay, int dIdx, int *uBuf) { int k, dOff; int *cPtr0, *cPtr1; U64 u64lo, u64hi; dOff = dIdx*32 + 31; cPtr0 = cTab; cPtr1 = cTab + 33*5 - 1; /* special first pass since we need to flip sign to create cTab[384], cTab[512] */ u64lo.w64 = 0; u64hi.w64 = 0; u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64hi.w64 = MADD64(u64hi.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64hi.w64 = MADD64(u64hi.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64lo.w64 = MADD64(u64lo.w64, -(*cPtr1--), delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64lo.w64 = MADD64(u64lo.w64, -(*cPtr1--), delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} uBuf[0] = u64lo.r.hi32; uBuf[32] = u64hi.r.hi32; uBuf++; dOff--; /* max gain for any sample in uBuf, after scaling by cTab, ~= 0.99 * so we can just sum the uBuf values with no overflow problems */ for (k = 1; k <= 31; k++) { u64lo.w64 = 0; u64hi.w64 = 0; u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64hi.w64 = MADD64(u64hi.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64hi.w64 = MADD64(u64hi.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64lo.w64 = MADD64(u64lo.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64lo.w64 = MADD64(u64lo.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;} uBuf[0] = u64lo.r.hi32; uBuf[32] = u64hi.r.hi32; uBuf++; dOff--; } } /*********************************************************************************************************************** * Function: QMFAnalysis * * Description: 32-subband analysis QMF (4.6.18.4.1) * * Inputs: 32 consecutive samples of decoded 32-bit PCM, format = Q(fBitsIn) * delay buffer of size 32*10 = 320 PCM samples * number of fraction bits in input PCM * index for delay ring buffer (range = [0, 9]) * number of subbands to calculate (range = [0, 32]) * * Outputs: qmfaBands complex subband samples, format = Q(FBITS_OUT_QMFA) * updated delay buffer * updated delay index * * Return: guard bit mask * * Notes: output stored as RE{X0}, IM{X0}, RE{X1}, IM{X1}, ... RE{X31}, IM{X31} * output stored in int buffer of size 64*2 = 128 * (zero-filled from XBuf[2*qmfaBands] to XBuf[127]) **********************************************************************************************************************/ int QMFAnalysis(int *inbuf, int *delay, int *XBuf, int fBitsIn, int *delayIdx, int qmfaBands) { int n, y, shift, gbMask; int *delayPtr, *uBuf, *tBuf; /* use XBuf[128] as temp buffer for reordering */ uBuf = XBuf; /* first 64 samples */ tBuf = XBuf + 64; /* second 64 samples */ /* overwrite oldest PCM with new PCM * delay[n] has 1 GB after shifting (either << or >>) */ delayPtr = delay + (*delayIdx * 32); if (fBitsIn > FBITS_IN_QMFA) { shift = MIN(fBitsIn - FBITS_IN_QMFA, 31); for (n = 32; n != 0; n--) { y = (*inbuf) >> shift; inbuf++; *delayPtr++ = y; } } else { shift = MIN(FBITS_IN_QMFA - fBitsIn, 30); for (n = 32; n != 0; n--) { y = *inbuf++; y = CLIP_2N_SHIFT30(y, shift); *delayPtr++ = y; } } QMFAnalysisConv((int *)cTabA, delay, *delayIdx, uBuf); /* uBuf has at least 2 GB right now (1 from clipping to Q(FBITS_IN_QMFA), one from * the scaling by cTab (MULSHIFT32(*delayPtr--, *cPtr++), with net gain of < 1.0) */ tBuf[2*0 + 0] = uBuf[0]; tBuf[2*0 + 1] = uBuf[1]; for (n = 1; n < 31; n++) { tBuf[2*n + 0] = -uBuf[64-n]; tBuf[2*n + 1] = uBuf[n+1]; } tBuf[2*31 + 1] = uBuf[32]; tBuf[2*31 + 0] = -uBuf[33]; /* fast in-place DCT-IV - only need 2*qmfaBands output samples */ PreMultiply64(tBuf); /* 2 GB in, 3 GB out */ FFT32C(tBuf); /* 3 GB in, 1 GB out */ PostMultiply64(tBuf, qmfaBands*2); /* 1 GB in, 2 GB out */ gbMask = 0; for (n = 0; n < qmfaBands; n++) { XBuf[2*n+0] = tBuf[ n + 0]; /* implicit scaling of 2 in our output Q format */ gbMask |= FASTABS(XBuf[2*n+0]); XBuf[2*n+1] = -tBuf[63 - n]; gbMask |= FASTABS(XBuf[2*n+1]); } /* fill top section with zeros for HF generation */ for ( ; n < 64; n++) { XBuf[2*n+0] = 0; XBuf[2*n+1] = 0; } *delayIdx = (*delayIdx == NUM_QMF_DELAY_BUFS - 1 ? 0 : *delayIdx + 1); /* minimum of 2 GB in output */ return gbMask; } /*********************************************************************************************************************** * Function: QMFSynthesisConv * * Description: final convolution kernel for synthesis QMF * * Inputs: pointer to coefficient table, reordered for sequential access * delay buffer of size 64*10 = 640 complex samples (1280 ints) * index for delay ring buffer (range = [0, 9]) * number of QMF subbands to process (range = [0, 64]) * number of channels * * Outputs: 64 consecutive 16-bit PCM samples, interleaved by factor of nChans * * Return: none * * Notes: this is carefully written to be efficient on ARM * use the assembly code version in sbrqmfsk.s when building for ARM! **********************************************************************************************************************/ void QMFSynthesisConv(int *cPtr, int *delay, int dIdx, short *outbuf, int nChans) { int k, dOff0, dOff1; U64 sum64; dOff0 = (dIdx)*128; dOff1 = dOff0 - 1; if (dOff1 < 0) dOff1 += 1280; /* scaling note: total gain of coefs (cPtr[0]-cPtr[9] for any k) is < 2.0, so 1 GB in delay values is adequate */ for (k = 0; k <= 63; k++) { sum64.w64 = 0; sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff0]); dOff0 -= 256; if (dOff0 < 0) {dOff0 += 1280;} sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff1]); dOff1 -= 256; if (dOff1 < 0) {dOff1 += 1280;} sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff0]); dOff0 -= 256; if (dOff0 < 0) {dOff0 += 1280;} sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff1]); dOff1 -= 256; if (dOff1 < 0) {dOff1 += 1280;} sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff0]); dOff0 -= 256; if (dOff0 < 0) {dOff0 += 1280;} sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff1]); dOff1 -= 256; if (dOff1 < 0) {dOff1 += 1280;} sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff0]); dOff0 -= 256; if (dOff0 < 0) {dOff0 += 1280;} sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff1]); dOff1 -= 256; if (dOff1 < 0) {dOff1 += 1280;} sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff0]); dOff0 -= 256; if (dOff0 < 0) {dOff0 += 1280;} sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff1]); dOff1 -= 256; if (dOff1 < 0) {dOff1 += 1280;} dOff0++; dOff1--; *outbuf = CLIPTOSHORT((sum64.r.hi32 + RND_VAL) >> FBITS_OUT_QMFS); outbuf += nChans; } } /*********************************************************************************************************************** * Function: QMFSynthesis * * Description: 64-subband synthesis QMF (4.6.18.4.2) * * Inputs: 64 consecutive complex subband QMF samples, format = Q(FBITS_IN_QMFS) * delay buffer of size 64*10 = 640 complex samples (1280 ints) * index for delay ring buffer (range = [0, 9]) * number of QMF subbands to process (range = [0, 64]) * number of channels * * Outputs: 64 consecutive 16-bit PCM samples, interleaved by factor of nChans * updated delay buffer * updated delay index * * Return: none * * Notes: assumes MIN_GBITS_IN_QMFS guard bits in input, either from * QMFAnalysis (if upsampling only) or from MapHF (if SBR on) **********************************************************************************************************************/ void QMFSynthesis(int *inbuf, int *delay, int *delayIdx, int qmfsBands, short *outbuf, int nChans) { int n, a0, a1, b0, b1, dOff0, dOff1, dIdx; int *tBufLo, *tBufHi; dIdx = *delayIdx; tBufLo = delay + dIdx*128 + 0; tBufHi = delay + dIdx*128 + 127; /* reorder inputs to DCT-IV, only use first qmfsBands (complex) samples */ for (n = 0; n < qmfsBands >> 1; n++) { a0 = *inbuf++; b0 = *inbuf++; a1 = *inbuf++; b1 = *inbuf++; *tBufLo++ = a0; *tBufLo++ = a1; *tBufHi-- = b0; *tBufHi-- = b1; } if (qmfsBands & 0x01) { a0 = *inbuf++; b0 = *inbuf++; *tBufLo++ = a0; *tBufHi-- = b0; *tBufLo++ = 0; *tBufHi-- = 0; n++; } for ( ; n < 32; n++) { *tBufLo++ = 0; *tBufHi-- = 0; *tBufLo++ = 0; *tBufHi-- = 0; } tBufLo = delay + dIdx*128 + 0; tBufHi = delay + dIdx*128 + 64; /* 2 GB in, 3 GB out */ PreMultiply64(tBufLo); PreMultiply64(tBufHi); /* 3 GB in, 1 GB out */ FFT32C(tBufLo); FFT32C(tBufHi); /* 1 GB in, 2 GB out */ PostMultiply64(tBufLo, 64); PostMultiply64(tBufHi, 64); /* could fuse with PostMultiply64 to avoid separate pass */ dOff0 = dIdx*128; dOff1 = dIdx*128 + 64; for (n = 32; n != 0; n--) { a0 = (*tBufLo++); a1 = (*tBufLo++); b0 = (*tBufHi++); b1 = -(*tBufHi++); delay[dOff0++] = (b0 - a0); delay[dOff0++] = (b1 - a1); delay[dOff1++] = (b0 + a0); delay[dOff1++] = (b1 + a1); } QMFSynthesisConv((int *)cTabS, delay, dIdx, outbuf, nChans); *delayIdx = (*delayIdx == NUM_QMF_DELAY_BUFS - 1 ? 0 : *delayIdx + 1); } /*********************************************************************************************************************** * Function: UnpackSBRHeader * * Description: unpack SBR header (table 4.56) * * Inputs: BitStreamInfo struct pointing to start of SBR header * * Outputs: initialized SBRHeader struct for this SCE/CPE block * * Return: non-zero if frame reset is triggered, zero otherwise **********************************************************************************************************************/ int UnpackSBRHeader(SBRHeader *sbrHdr) { SBRHeader sbrHdrPrev; /* save previous values so we know whether to reset decoder */ sbrHdrPrev.startFreq = sbrHdr->startFreq; sbrHdrPrev.stopFreq = sbrHdr->stopFreq; sbrHdrPrev.freqScale = sbrHdr->freqScale; sbrHdrPrev.alterScale = sbrHdr->alterScale; sbrHdrPrev.crossOverBand = sbrHdr->crossOverBand; sbrHdrPrev.noiseBands = sbrHdr->noiseBands; sbrHdr->ampRes = GetBits(1); sbrHdr->startFreq = GetBits(4); sbrHdr->stopFreq = GetBits(4); sbrHdr->crossOverBand = GetBits(3); sbrHdr->resBitsHdr = GetBits(2); sbrHdr->hdrExtra1 = GetBits(1); sbrHdr->hdrExtra2 = GetBits(1); if (sbrHdr->hdrExtra1) { sbrHdr->freqScale = GetBits(2); sbrHdr->alterScale = GetBits(1); sbrHdr->noiseBands = GetBits(2); } else { /* defaults */ sbrHdr->freqScale = 2; sbrHdr->alterScale = 1; sbrHdr->noiseBands = 2; } if (sbrHdr->hdrExtra2) { sbrHdr->limiterBands = GetBits(2); sbrHdr->limiterGains = GetBits(2); sbrHdr->interpFreq = GetBits(1); sbrHdr->smoothMode = GetBits(1); } else { /* defaults */ sbrHdr->limiterBands = 2; sbrHdr->limiterGains = 2; sbrHdr->interpFreq = 1; sbrHdr->smoothMode = 1; } sbrHdr->count++; /* if any of these have changed from previous frame, reset the SBR module */ if (sbrHdr->startFreq != sbrHdrPrev.startFreq || sbrHdr->stopFreq != sbrHdrPrev.stopFreq || sbrHdr->freqScale != sbrHdrPrev.freqScale || sbrHdr->alterScale != sbrHdrPrev.alterScale || sbrHdr->crossOverBand != sbrHdrPrev.crossOverBand || sbrHdr->noiseBands != sbrHdrPrev.noiseBands ) return -1; else return 0; } /* cLog2[i] = ceil(log2(i)) (disregard i == 0) */ static const uint8_t cLog2[9] = {0, 0, 1, 2, 2, 3, 3, 3, 3}; /*********************************************************************************************************************** * Function: UnpackSBRGrid * * Description: unpack SBR grid (table 4.62) * * Inputs: BitStreamInfo struct pointing to start of SBR grid * initialized SBRHeader struct for this SCE/CPE block * * Outputs: initialized SBRGrid struct for this channel * * Return: none **********************************************************************************************************************/ void UnpackSBRGrid(SBRHeader *sbrHdr, SBRGrid *sbrGrid) { int numEnvRaw, env, rel, pBits, border, middleBorder = 0; uint8_t relBordLead[MAX_NUM_ENV], relBordTrail[MAX_NUM_ENV]; uint8_t relBorder0[3], relBorder1[3], relBorder[3]; uint8_t numRelBorder0, numRelBorder1, numRelBorder, numRelLead = 0, numRelTrail; uint8_t absBordLead = 0, absBordTrail = 0, absBorder; sbrGrid->ampResFrame = sbrHdr->ampRes; sbrGrid->frameClass = GetBits(2); switch(sbrGrid->frameClass){ case SBR_GRID_FIXFIX: numEnvRaw = GetBits(2); sbrGrid->numEnv = (1 << numEnvRaw); if(sbrGrid->numEnv == 1) sbrGrid->ampResFrame = 0; ASSERT(sbrGrid->numEnv == 1 || sbrGrid->numEnv == 2 || sbrGrid->numEnv == 4); sbrGrid->freqRes[0] = GetBits(1); for(env = 1; env < sbrGrid->numEnv; env++) sbrGrid->freqRes[env] = sbrGrid->freqRes[0]; absBordLead = 0; absBordTrail = NUM_TIME_SLOTS; numRelLead = sbrGrid->numEnv - 1; numRelTrail = 0; /* numEnv = 1, 2, or 4 */ if(sbrGrid->numEnv == 1) border = NUM_TIME_SLOTS / 1; else if(sbrGrid->numEnv == 2) border = NUM_TIME_SLOTS / 2; else border = NUM_TIME_SLOTS / 4; for(rel = 0; rel < numRelLead; rel++) relBordLead[rel] = border; middleBorder = (sbrGrid->numEnv >> 1); break; case SBR_GRID_FIXVAR: absBorder = GetBits(2) + NUM_TIME_SLOTS; numRelBorder = GetBits(2); sbrGrid->numEnv = numRelBorder + 1; for(rel = 0; rel < numRelBorder; rel++) relBorder[rel] = 2 * GetBits(2) + 2; pBits = cLog2[sbrGrid->numEnv + 1]; sbrGrid->pointer = GetBits(pBits); for(env = sbrGrid->numEnv - 1; env >= 0; env--) sbrGrid->freqRes[env] = GetBits(1); absBordLead = 0; absBordTrail = absBorder; numRelLead = 0; numRelTrail = numRelBorder; for(rel = 0; rel < numRelTrail; rel++) relBordTrail[rel] = relBorder[rel]; if(sbrGrid->pointer > 1) middleBorder = sbrGrid->numEnv + 1 - sbrGrid->pointer; else middleBorder = sbrGrid->numEnv - 1; break; case SBR_GRID_VARFIX: absBorder = GetBits(2); numRelBorder = GetBits(2); sbrGrid->numEnv = numRelBorder + 1; for(rel = 0; rel < numRelBorder; rel++) relBorder[rel] = 2 * GetBits(2) + 2; pBits = cLog2[sbrGrid->numEnv + 1]; sbrGrid->pointer = GetBits(pBits); for(env = 0; env < sbrGrid->numEnv; env++) sbrGrid->freqRes[env] = GetBits(1); absBordLead = absBorder; absBordTrail = NUM_TIME_SLOTS; numRelLead = numRelBorder; numRelTrail = 0; for(rel = 0; rel < numRelLead; rel++) relBordLead[rel] = relBorder[rel]; if(sbrGrid->pointer == 0) middleBorder = 1; else if(sbrGrid->pointer == 1) middleBorder = sbrGrid->numEnv - 1; else middleBorder = sbrGrid->pointer - 1; break; case SBR_GRID_VARVAR: absBordLead = GetBits(2); /* absBorder0 */ absBordTrail = GetBits(2) + NUM_TIME_SLOTS; /* absBorder1 */ numRelBorder0 = GetBits(2); numRelBorder1 = GetBits(2); sbrGrid->numEnv = numRelBorder0 + numRelBorder1 + 1; ASSERT(sbrGrid->numEnv <= 5); for(rel = 0; rel < numRelBorder0; rel++) relBorder0[rel] = 2 * GetBits(2) + 2; for(rel = 0; rel < numRelBorder1; rel++) relBorder1[rel] = 2 * GetBits(2) + 2; pBits = cLog2[numRelBorder0 + numRelBorder1 + 2]; sbrGrid->pointer = GetBits(pBits); for(env = 0; env < sbrGrid->numEnv; env++) sbrGrid->freqRes[env] = GetBits(1); numRelLead = numRelBorder0; numRelTrail = numRelBorder1; for(rel = 0; rel < numRelLead; rel++) relBordLead[rel] = relBorder0[rel]; for(rel = 0; rel < numRelTrail; rel++) relBordTrail[rel] = relBorder1[rel]; if(sbrGrid->pointer > 1) middleBorder = sbrGrid->numEnv + 1 - sbrGrid->pointer; else middleBorder = sbrGrid->numEnv - 1; break; } /* build time border vector */ sbrGrid->envTimeBorder[0] = absBordLead * SAMPLES_PER_SLOT; rel = 0; border = absBordLead; for(env = 1; env <= numRelLead; env++) { border += relBordLead[rel++]; sbrGrid->envTimeBorder[env] = border * SAMPLES_PER_SLOT; } rel = 0; border = absBordTrail; for(env = sbrGrid->numEnv - 1; env > numRelLead; env--) { border -= relBordTrail[rel++]; sbrGrid->envTimeBorder[env] = border * SAMPLES_PER_SLOT; } sbrGrid->envTimeBorder[sbrGrid->numEnv] = absBordTrail * SAMPLES_PER_SLOT; if(sbrGrid->numEnv > 1) { sbrGrid->numNoiseFloors = 2; sbrGrid->noiseTimeBorder[0] = sbrGrid->envTimeBorder[0]; sbrGrid->noiseTimeBorder[1] = sbrGrid->envTimeBorder[middleBorder]; sbrGrid->noiseTimeBorder[2] = sbrGrid->envTimeBorder[sbrGrid->numEnv]; } else { sbrGrid->numNoiseFloors = 1; sbrGrid->noiseTimeBorder[0] = sbrGrid->envTimeBorder[0]; sbrGrid->noiseTimeBorder[1] = sbrGrid->envTimeBorder[1]; } } /*********************************************************************************************************************** * Function: UnpackDeltaTimeFreq * * Description: unpack time/freq flags for delta coding of SBR envelopes (table 4.63) * * Inputs: BitStreamInfo struct pointing to start of dt/df flags * number of envelopes * number of noise floors * * Outputs: delta flags for envelope and noise floors * * Return: none **********************************************************************************************************************/ void UnpackDeltaTimeFreq(int numEnv, uint8_t *deltaFlagEnv, int numNoiseFloors, uint8_t *deltaFlagNoise) { int env, noiseFloor; for (env = 0; env < numEnv; env++) deltaFlagEnv[env] = GetBits(1); for (noiseFloor = 0; noiseFloor < numNoiseFloors; noiseFloor++) deltaFlagNoise[noiseFloor] = GetBits(1); } /*********************************************************************************************************************** * Function: UnpackInverseFilterMode * * Description: unpack invf flags for chirp factor calculation (table 4.64) * * Inputs: BitStreamInfo struct pointing to start of invf flags * number of noise floor bands * * Outputs: invf flags for noise floor bands * * Return: none **********************************************************************************************************************/ void UnpackInverseFilterMode(int numNoiseFloorBands, uint8_t *mode) { int n; for (n = 0; n < numNoiseFloorBands; n++) mode[n] = GetBits(2); } /*********************************************************************************************************************** * Function: UnpackSinusoids * * Description: unpack sinusoid (harmonic) flags for each SBR subband (table 4.67) * * Inputs: BitStreamInfo struct pointing to start of sinusoid flags * number of high resolution SBR subbands (nHigh) * * Outputs: sinusoid flags for each SBR subband, zero-filled above nHigh * * Return: none **********************************************************************************************************************/ void UnpackSinusoids(int nHigh, int addHarmonicFlag, uint8_t *addHarmonic) { int n; n = 0; if(addHarmonicFlag) { for(; n < nHigh; n++) addHarmonic[n] = GetBits(1); } /* zero out unused bands */ for(; n < MAX_QMF_BANDS; n++) addHarmonic[n] = 0; } /*********************************************************************************************************************** * Function: CopyCouplingGrid * * Description: copy grid parameters from left to right for channel coupling * * Inputs: initialized SBRGrid struct for left channel * * Outputs: initialized SBRGrid struct for right channel * * Return: none **********************************************************************************************************************/ void CopyCouplingGrid(SBRGrid *sbrGridLeft, SBRGrid *sbrGridRight) { int env, noiseFloor; sbrGridRight->frameClass = sbrGridLeft->frameClass; sbrGridRight->ampResFrame = sbrGridLeft->ampResFrame; sbrGridRight->pointer = sbrGridLeft->pointer; sbrGridRight->numEnv = sbrGridLeft->numEnv; for(env = 0; env < sbrGridLeft->numEnv; env++) { sbrGridRight->envTimeBorder[env] = sbrGridLeft->envTimeBorder[env]; sbrGridRight->freqRes[env] = sbrGridLeft->freqRes[env]; } sbrGridRight->envTimeBorder[env] = sbrGridLeft->envTimeBorder[env]; /* borders are [0, numEnv] inclusive */ sbrGridRight->numNoiseFloors = sbrGridLeft->numNoiseFloors; for(noiseFloor = 0; noiseFloor <= sbrGridLeft->numNoiseFloors; noiseFloor++) sbrGridRight->noiseTimeBorder[noiseFloor] = sbrGridLeft->noiseTimeBorder[noiseFloor]; /* numEnvPrev, numNoiseFloorsPrev, freqResPrev are updated in DecodeSBREnvelope() and DecodeSBRNoise() */ } /*********************************************************************************************************************** * Function: CopyCouplingInverseFilterMode * * Description: copy invf flags from left to right for channel coupling * * Inputs: invf flags for left channel * number of noise floor bands * * Outputs: invf flags for right channel * * Return: none **********************************************************************************************************************/ void CopyCouplingInverseFilterMode(int numNoiseFloorBands, uint8_t *modeLeft, uint8_t *modeRight) { int band; for(band = 0; band < numNoiseFloorBands; band++) modeRight[band] = modeLeft[band]; } /*********************************************************************************************************************** * Function: UnpackSBRSingleChannel * * Description: unpack sideband info (grid, delta flags, invf flags, envelope and * noise floor configuration, sinusoids) for a single channel * * Inputs: BitStreamInfo struct pointing to start of sideband info * initialized PSInfoSBR struct (after parsing SBR header and building * frequency tables) * base output channel (range = [0, nChans-1]) * * Outputs: updated PSInfoSBR struct (SBRGrid and SBRChan) * * Return: none **********************************************************************************************************************/ void UnpackSBRSingleChannel(int chBase) { int bitsLeft; SBRHeader *sbrHdr = &(m_PSInfoSBR->sbrHdr[chBase]); SBRGrid *sbrGridL = &(m_PSInfoSBR->sbrGrid[chBase + 0]); SBRFreq *sbrFreq = &(m_PSInfoSBR->sbrFreq[chBase]); SBRChan *sbrChanL = &(m_PSInfoSBR->sbrChan[chBase + 0]); m_PSInfoSBR->dataExtra = GetBits(1); if(m_PSInfoSBR->dataExtra) m_PSInfoSBR->resBitsData = GetBits(4); UnpackSBRGrid(sbrHdr, sbrGridL); UnpackDeltaTimeFreq(sbrGridL->numEnv, sbrChanL->deltaFlagEnv, sbrGridL->numNoiseFloors, sbrChanL->deltaFlagNoise); UnpackInverseFilterMode(sbrFreq->numNoiseFloorBands, sbrChanL->invfMode[1]); DecodeSBREnvelope(sbrGridL, sbrFreq, sbrChanL, 0); DecodeSBRNoise(sbrGridL, sbrFreq, sbrChanL, 0); sbrChanL->addHarmonicFlag[1] = GetBits(1); UnpackSinusoids(sbrFreq->nHigh, sbrChanL->addHarmonicFlag[1], sbrChanL->addHarmonic[1]); m_PSInfoSBR->extendedDataPresent = GetBits(1); if(m_PSInfoSBR->extendedDataPresent) { m_PSInfoSBR->extendedDataSize = GetBits(4); if(m_PSInfoSBR->extendedDataSize == 15) m_PSInfoSBR->extendedDataSize += GetBits(8); bitsLeft = 8 * m_PSInfoSBR->extendedDataSize; /* get ID, unpack extension info, do whatever is necessary with it... */ while(bitsLeft > 0) { GetBits(8); bitsLeft -= 8; } } } /*********************************************************************************************************************** * Function: UnpackSBRChannelPair * * Description: unpack sideband info (grid, delta flags, invf flags, envelope and * noise floor configuration, sinusoids) for a channel pair * * Inputs: base output channel (range = [0, nChans-1]) * * Outputs: updated PSInfoSBR struct (SBRGrid and SBRChan for both channels) * * Return: none **********************************************************************************************************************/ void UnpackSBRChannelPair(int chBase) { int bitsLeft; SBRHeader *sbrHdr = &(m_PSInfoSBR->sbrHdr[chBase]); SBRGrid *sbrGridL = &(m_PSInfoSBR->sbrGrid[chBase + 0]), *sbrGridR = &(m_PSInfoSBR->sbrGrid[chBase + 1]); SBRFreq *sbrFreq = &(m_PSInfoSBR->sbrFreq[chBase]); SBRChan *sbrChanL = &(m_PSInfoSBR->sbrChan[chBase + 0]), *sbrChanR = &(m_PSInfoSBR->sbrChan[chBase + 1]); m_PSInfoSBR->dataExtra = GetBits(1); if(m_PSInfoSBR->dataExtra) { m_PSInfoSBR->resBitsData = GetBits(4); m_PSInfoSBR->resBitsData = GetBits(4); } m_PSInfoSBR->couplingFlag = GetBits(1); if(m_PSInfoSBR->couplingFlag) { UnpackSBRGrid(sbrHdr, sbrGridL); CopyCouplingGrid(sbrGridL, sbrGridR); UnpackDeltaTimeFreq(sbrGridL->numEnv, sbrChanL->deltaFlagEnv, sbrGridL->numNoiseFloors, sbrChanL->deltaFlagNoise); UnpackDeltaTimeFreq(sbrGridR->numEnv, sbrChanR->deltaFlagEnv, sbrGridR->numNoiseFloors, sbrChanR->deltaFlagNoise); UnpackInverseFilterMode(sbrFreq->numNoiseFloorBands, sbrChanL->invfMode[1]); CopyCouplingInverseFilterMode(sbrFreq->numNoiseFloorBands, sbrChanL->invfMode[1], sbrChanR->invfMode[1]); DecodeSBREnvelope(sbrGridL, sbrFreq, sbrChanL, 0); DecodeSBRNoise(sbrGridL, sbrFreq, sbrChanL, 0); DecodeSBREnvelope(sbrGridR, sbrFreq, sbrChanR, 1); DecodeSBRNoise(sbrGridR, sbrFreq, sbrChanR, 1); /* pass RIGHT sbrChan struct */ UncoupleSBREnvelope(sbrGridL, sbrFreq, sbrChanR); UncoupleSBRNoise(sbrGridL, sbrFreq, sbrChanR); } else { UnpackSBRGrid(sbrHdr, sbrGridL); UnpackSBRGrid(sbrHdr, sbrGridR); UnpackDeltaTimeFreq(sbrGridL->numEnv, sbrChanL->deltaFlagEnv, sbrGridL->numNoiseFloors, sbrChanL->deltaFlagNoise); UnpackDeltaTimeFreq(sbrGridR->numEnv, sbrChanR->deltaFlagEnv, sbrGridR->numNoiseFloors, sbrChanR->deltaFlagNoise); UnpackInverseFilterMode(sbrFreq->numNoiseFloorBands, sbrChanL->invfMode[1]); UnpackInverseFilterMode(sbrFreq->numNoiseFloorBands, sbrChanR->invfMode[1]); DecodeSBREnvelope(sbrGridL, sbrFreq, sbrChanL, 0); DecodeSBREnvelope(sbrGridR, sbrFreq, sbrChanR, 1); DecodeSBRNoise(sbrGridL, sbrFreq, sbrChanL, 0); DecodeSBRNoise(sbrGridR, sbrFreq, sbrChanR, 1); } sbrChanL->addHarmonicFlag[1] = GetBits(1); UnpackSinusoids(sbrFreq->nHigh, sbrChanL->addHarmonicFlag[1], sbrChanL->addHarmonic[1]); sbrChanR->addHarmonicFlag[1] = GetBits(1); UnpackSinusoids(sbrFreq->nHigh, sbrChanR->addHarmonicFlag[1], sbrChanR->addHarmonic[1]); m_PSInfoSBR->extendedDataPresent = GetBits(1); if(m_PSInfoSBR->extendedDataPresent) { m_PSInfoSBR->extendedDataSize = GetBits(4); if(m_PSInfoSBR->extendedDataSize == 15) m_PSInfoSBR->extendedDataSize += GetBits(8); bitsLeft = 8 * m_PSInfoSBR->extendedDataSize; /* get ID, unpack extension info, do whatever is necessary with it... */ while(bitsLeft > 0) { GetBits(8); bitsLeft -= 8; } } }