| /* ----------------------------------------------------------------------------- |
| Software License for The Fraunhofer FDK AAC Codec Library for Android |
| |
| © Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten |
| Forschung e.V. All rights reserved. |
| |
| 1. INTRODUCTION |
| The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software |
| that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding |
| scheme for digital audio. This FDK AAC Codec software is intended to be used on |
| a wide variety of Android devices. |
| |
| AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient |
| general perceptual audio codecs. AAC-ELD is considered the best-performing |
| full-bandwidth communications codec by independent studies and is widely |
| deployed. AAC has been standardized by ISO and IEC as part of the MPEG |
| specifications. |
| |
| Patent licenses for necessary patent claims for the FDK AAC Codec (including |
| those of Fraunhofer) may be obtained through Via Licensing |
| (www.vialicensing.com) or through the respective patent owners individually for |
| the purpose of encoding or decoding bit streams in products that are compliant |
| with the ISO/IEC MPEG audio standards. Please note that most manufacturers of |
| Android devices already license these patent claims through Via Licensing or |
| directly from the patent owners, and therefore FDK AAC Codec software may |
| already be covered under those patent licenses when it is used for those |
| licensed purposes only. |
| |
| Commercially-licensed AAC software libraries, including floating-point versions |
| with enhanced sound quality, are also available from Fraunhofer. Users are |
| encouraged to check the Fraunhofer website for additional applications |
| information and documentation. |
| |
| 2. COPYRIGHT LICENSE |
| |
| Redistribution and use in source and binary forms, with or without modification, |
| are permitted without payment of copyright license fees provided that you |
| satisfy the following conditions: |
| |
| You must retain the complete text of this software license in redistributions of |
| the FDK AAC Codec or your modifications thereto in source code form. |
| |
| You must retain the complete text of this software license in the documentation |
| and/or other materials provided with redistributions of the FDK AAC Codec or |
| your modifications thereto in binary form. You must make available free of |
| charge copies of the complete source code of the FDK AAC Codec and your |
| modifications thereto to recipients of copies in binary form. |
| |
| The name of Fraunhofer may not be used to endorse or promote products derived |
| from this library without prior written permission. |
| |
| You may not charge copyright license fees for anyone to use, copy or distribute |
| the FDK AAC Codec software or your modifications thereto. |
| |
| Your modified versions of the FDK AAC Codec must carry prominent notices stating |
| that you changed the software and the date of any change. For modified versions |
| of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" |
| must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK |
| AAC Codec Library for Android." |
| |
| 3. NO PATENT LICENSE |
| |
| NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without |
| limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. |
| Fraunhofer provides no warranty of patent non-infringement with respect to this |
| software. |
| |
| You may use this FDK AAC Codec software or modifications thereto only for |
| purposes that are authorized by appropriate patent licenses. |
| |
| 4. DISCLAIMER |
| |
| This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright |
| holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, |
| including but not limited to the implied warranties of merchantability and |
| fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
| CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, |
| or consequential damages, including but not limited to procurement of substitute |
| goods or services; loss of use, data, or profits, or business interruption, |
| however caused and on any theory of liability, whether in contract, strict |
| liability, or tort (including negligence), arising in any way out of the use of |
| this software, even if advised of the possibility of such damage. |
| |
| 5. CONTACT INFORMATION |
| |
| Fraunhofer Institute for Integrated Circuits IIS |
| Attention: Audio and Multimedia Departments - FDK AAC LL |
| Am Wolfsmantel 33 |
| 91058 Erlangen, Germany |
| |
| www.iis.fraunhofer.de/amm |
| amm-info@iis.fraunhofer.de |
| ----------------------------------------------------------------------------- */ |
| |
| /**************************** AAC decoder library ****************************** |
| |
| Author(s): Josef Hoepfl |
| |
| Description: joint stereo processing |
| |
| *******************************************************************************/ |
| |
| #include "stereo.h" |
| |
| #include "aac_rom.h" |
| #include "FDK_bitstream.h" |
| #include "channelinfo.h" |
| #include "FDK_audio.h" |
| |
| enum { L = 0, R = 1 }; |
| |
| #include "block.h" |
| |
| int CJointStereo_Read(HANDLE_FDK_BITSTREAM bs, |
| CJointStereoData *pJointStereoData, |
| const int windowGroups, |
| const int scaleFactorBandsTransmitted, |
| const int max_sfb_ste_clear, |
| CJointStereoPersistentData *pJointStereoPersistentData, |
| CCplxPredictionData *cplxPredictionData, |
| int cplxPredictionActiv, int scaleFactorBandsTotal, |
| int windowSequence, const UINT flags) { |
| int group, band; |
| |
| pJointStereoData->MsMaskPresent = (UCHAR)FDKreadBits(bs, 2); |
| |
| FDKmemclear(pJointStereoData->MsUsed, |
| scaleFactorBandsTransmitted * sizeof(UCHAR)); |
| |
| pJointStereoData->cplx_pred_flag = 0; |
| if (cplxPredictionActiv) { |
| cplxPredictionData->pred_dir = 0; |
| cplxPredictionData->complex_coef = 0; |
| cplxPredictionData->use_prev_frame = 0; |
| cplxPredictionData->igf_pred_dir = 0; |
| } |
| |
| switch (pJointStereoData->MsMaskPresent) { |
| case 0: /* no M/S */ |
| /* all flags are already cleared */ |
| break; |
| |
| case 1: /* read ms_used */ |
| for (group = 0; group < windowGroups; group++) { |
| for (band = 0; band < scaleFactorBandsTransmitted; band++) { |
| pJointStereoData->MsUsed[band] |= (FDKreadBits(bs, 1) << group); |
| } |
| } |
| break; |
| |
| case 2: /* full spectrum M/S */ |
| for (band = 0; band < scaleFactorBandsTransmitted; band++) { |
| pJointStereoData->MsUsed[band] = 255; /* set all flags to 1 */ |
| } |
| break; |
| |
| case 3: |
| /* M/S coding is disabled, complex stereo prediction is enabled */ |
| if (flags & (AC_USAC | AC_RSVD50 | AC_RSV603DA)) { |
| if (cplxPredictionActiv) { /* 'if (stereoConfigIndex == 0)' */ |
| |
| pJointStereoData->cplx_pred_flag = 1; |
| |
| /* cplx_pred_data() cp. ISO/IEC FDIS 23003-3:2011(E) Table 26 */ |
| int cplx_pred_all = 0; /* local use only */ |
| cplx_pred_all = FDKreadBits(bs, 1); |
| |
| if (cplx_pred_all) { |
| for (group = 0; group < windowGroups; group++) { |
| UCHAR groupmask = ((UCHAR)1 << group); |
| for (band = 0; band < scaleFactorBandsTransmitted; band++) { |
| pJointStereoData->MsUsed[band] |= groupmask; |
| } |
| } |
| } else { |
| for (group = 0; group < windowGroups; group++) { |
| for (band = 0; band < scaleFactorBandsTransmitted; |
| band += SFB_PER_PRED_BAND) { |
| pJointStereoData->MsUsed[band] |= (FDKreadBits(bs, 1) << group); |
| if ((band + 1) < scaleFactorBandsTotal) { |
| pJointStereoData->MsUsed[band + 1] |= |
| (pJointStereoData->MsUsed[band] & ((UCHAR)1 << group)); |
| } |
| } |
| } |
| } |
| } else { |
| return -1; |
| } |
| } |
| break; |
| } |
| |
| if (cplxPredictionActiv) { |
| /* If all sfb are MS-ed then no complex prediction */ |
| if (pJointStereoData->MsMaskPresent == 3) { |
| if (pJointStereoData->cplx_pred_flag) { |
| int delta_code_time = 0; |
| |
| /* set pointer to Huffman codebooks */ |
| const CodeBookDescription *hcb = &AACcodeBookDescriptionTable[BOOKSCL]; |
| /* set predictors to zero in case of a transition from long to short |
| * window sequences and vice versa */ |
| if (((windowSequence == BLOCK_SHORT) && |
| (pJointStereoPersistentData->winSeqPrev != BLOCK_SHORT)) || |
| ((pJointStereoPersistentData->winSeqPrev == BLOCK_SHORT) && |
| (windowSequence != BLOCK_SHORT))) { |
| FDKmemclear(pJointStereoPersistentData->alpha_q_re_prev, |
| JointStereoMaximumGroups * JointStereoMaximumBands * |
| sizeof(SHORT)); |
| FDKmemclear(pJointStereoPersistentData->alpha_q_im_prev, |
| JointStereoMaximumGroups * JointStereoMaximumBands * |
| sizeof(SHORT)); |
| } |
| { |
| FDKmemclear(cplxPredictionData->alpha_q_re, |
| JointStereoMaximumGroups * JointStereoMaximumBands * |
| sizeof(SHORT)); |
| FDKmemclear(cplxPredictionData->alpha_q_im, |
| JointStereoMaximumGroups * JointStereoMaximumBands * |
| sizeof(SHORT)); |
| } |
| |
| /* 0 = mid->side prediction, 1 = side->mid prediction */ |
| cplxPredictionData->pred_dir = FDKreadBits(bs, 1); |
| cplxPredictionData->complex_coef = FDKreadBits(bs, 1); |
| |
| if (cplxPredictionData->complex_coef) { |
| if (flags & AC_INDEP) { |
| cplxPredictionData->use_prev_frame = 0; |
| } else { |
| cplxPredictionData->use_prev_frame = FDKreadBits(bs, 1); |
| } |
| } |
| |
| if (flags & AC_INDEP) { |
| delta_code_time = 0; |
| } else { |
| delta_code_time = FDKreadBits(bs, 1); |
| } |
| |
| { |
| int last_alpha_q_re = 0, last_alpha_q_im = 0; |
| |
| for (group = 0; group < windowGroups; group++) { |
| for (band = 0; band < scaleFactorBandsTransmitted; |
| band += SFB_PER_PRED_BAND) { |
| if (delta_code_time == 1) { |
| if (group > 0) { |
| last_alpha_q_re = |
| cplxPredictionData->alpha_q_re[group - 1][band]; |
| last_alpha_q_im = |
| cplxPredictionData->alpha_q_im[group - 1][band]; |
| } else if ((windowSequence == BLOCK_SHORT) && |
| (pJointStereoPersistentData->winSeqPrev == |
| BLOCK_SHORT)) { |
| /* Included for error-robustness */ |
| if (pJointStereoPersistentData->winGroupsPrev == 0) return -1; |
| |
| last_alpha_q_re = |
| pJointStereoPersistentData->alpha_q_re_prev |
| [pJointStereoPersistentData->winGroupsPrev - 1][band]; |
| last_alpha_q_im = |
| pJointStereoPersistentData->alpha_q_im_prev |
| [pJointStereoPersistentData->winGroupsPrev - 1][band]; |
| } else { |
| last_alpha_q_re = |
| pJointStereoPersistentData->alpha_q_re_prev[group][band]; |
| last_alpha_q_im = |
| pJointStereoPersistentData->alpha_q_im_prev[group][band]; |
| } |
| |
| } else { |
| if (band > 0) { |
| last_alpha_q_re = |
| cplxPredictionData->alpha_q_re[group][band - 1]; |
| last_alpha_q_im = |
| cplxPredictionData->alpha_q_im[group][band - 1]; |
| } else { |
| last_alpha_q_re = 0; |
| last_alpha_q_im = 0; |
| } |
| |
| } /* if (delta_code_time == 1) */ |
| |
| if (pJointStereoData->MsUsed[band] & ((UCHAR)1 << group)) { |
| int dpcm_alpha_re, dpcm_alpha_im; |
| |
| dpcm_alpha_re = CBlock_DecodeHuffmanWord(bs, hcb); |
| dpcm_alpha_re -= 60; |
| dpcm_alpha_re *= -1; |
| |
| cplxPredictionData->alpha_q_re[group][band] = |
| dpcm_alpha_re + last_alpha_q_re; |
| |
| if (cplxPredictionData->complex_coef) { |
| dpcm_alpha_im = CBlock_DecodeHuffmanWord(bs, hcb); |
| dpcm_alpha_im -= 60; |
| dpcm_alpha_im *= -1; |
| |
| cplxPredictionData->alpha_q_im[group][band] = |
| dpcm_alpha_im + last_alpha_q_im; |
| } else { |
| cplxPredictionData->alpha_q_im[group][band] = 0; |
| } |
| |
| } else { |
| cplxPredictionData->alpha_q_re[group][band] = 0; |
| cplxPredictionData->alpha_q_im[group][band] = 0; |
| } /* if (pJointStereoData->MsUsed[band] & ((UCHAR)1 << group)) */ |
| |
| if ((band + 1) < |
| scaleFactorBandsTransmitted) { /* <= this should be the |
| correct way (cp. |
| ISO_IEC_FDIS_23003-0(E) */ |
| /* 7.7.2.3.2 Decoding of prediction coefficients) */ |
| cplxPredictionData->alpha_q_re[group][band + 1] = |
| cplxPredictionData->alpha_q_re[group][band]; |
| cplxPredictionData->alpha_q_im[group][band + 1] = |
| cplxPredictionData->alpha_q_im[group][band]; |
| } /* if ((band+1)<scaleFactorBandsTotal) */ |
| |
| pJointStereoPersistentData->alpha_q_re_prev[group][band] = |
| cplxPredictionData->alpha_q_re[group][band]; |
| pJointStereoPersistentData->alpha_q_im_prev[group][band] = |
| cplxPredictionData->alpha_q_im[group][band]; |
| } |
| |
| for (band = scaleFactorBandsTransmitted; band < max_sfb_ste_clear; |
| band++) { |
| cplxPredictionData->alpha_q_re[group][band] = 0; |
| cplxPredictionData->alpha_q_im[group][band] = 0; |
| pJointStereoPersistentData->alpha_q_re_prev[group][band] = 0; |
| pJointStereoPersistentData->alpha_q_im_prev[group][band] = 0; |
| } |
| } |
| } |
| } |
| } else { |
| for (group = 0; group < windowGroups; group++) { |
| for (band = 0; band < max_sfb_ste_clear; band++) { |
| pJointStereoPersistentData->alpha_q_re_prev[group][band] = 0; |
| pJointStereoPersistentData->alpha_q_im_prev[group][band] = 0; |
| } |
| } |
| } |
| |
| pJointStereoPersistentData->winGroupsPrev = windowGroups; |
| } |
| |
| return 0; |
| } |
| |
| static void CJointStereo_filterAndAdd( |
| FIXP_DBL *in, int len, int windowLen, const FIXP_FILT *coeff, FIXP_DBL *out, |
| UCHAR isCurrent /* output values with even index get a |
| positve addon (=1) or a negative addon |
| (=0) */ |
| ) { |
| int i, j; |
| |
| int indices_1[] = {2, 1, 0, 1, 2, 3}; |
| int indices_2[] = {1, 0, 0, 2, 3, 4}; |
| int indices_3[] = {0, 0, 1, 3, 4, 5}; |
| |
| int subtr_1[] = {6, 5, 4, 2, 1, 1}; |
| int subtr_2[] = {5, 4, 3, 1, 1, 2}; |
| int subtr_3[] = {4, 3, 2, 1, 2, 3}; |
| |
| if (isCurrent == 1) { |
| /* exploit the symmetry of the table: coeff[6] = - coeff[0], |
| coeff[5] = - coeff[1], |
| coeff[4] = - coeff[2], |
| coeff[3] = 0 |
| */ |
| |
| for (i = 0; i < 3; i++) { |
| out[0] -= (FIXP_DBL)fMultDiv2(coeff[i], in[indices_1[i]]) >> SR_FNA_OUT; |
| out[0] += |
| (FIXP_DBL)fMultDiv2(coeff[i], in[indices_1[5 - i]]) >> SR_FNA_OUT; |
| } |
| |
| for (i = 0; i < 3; i++) { |
| out[1] -= (FIXP_DBL)fMultDiv2(coeff[i], in[indices_2[i]]) >> SR_FNA_OUT; |
| out[1] += |
| (FIXP_DBL)fMultDiv2(coeff[i], in[indices_2[5 - i]]) >> SR_FNA_OUT; |
| } |
| |
| for (i = 0; i < 3; i++) { |
| out[2] -= (FIXP_DBL)fMultDiv2(coeff[i], in[indices_3[i]]) >> SR_FNA_OUT; |
| out[2] += |
| (FIXP_DBL)fMultDiv2(coeff[i], in[indices_3[5 - i]]) >> SR_FNA_OUT; |
| } |
| |
| for (j = 3; j < (len - 3); j++) { |
| for (i = 0; i < 3; i++) { |
| out[j] -= (FIXP_DBL)fMultDiv2(coeff[i], in[j - 3 + i]) >> SR_FNA_OUT; |
| out[j] += (FIXP_DBL)fMultDiv2(coeff[i], in[j + 3 - i]) >> SR_FNA_OUT; |
| } |
| } |
| |
| for (i = 0; i < 3; i++) { |
| out[len - 3] -= |
| (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_1[i]]) >> SR_FNA_OUT; |
| out[len - 3] += |
| (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_1[5 - i]]) >> SR_FNA_OUT; |
| } |
| |
| for (i = 0; i < 3; i++) { |
| out[len - 2] -= |
| (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_2[i]]) >> SR_FNA_OUT; |
| out[len - 2] += |
| (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_2[5 - i]]) >> SR_FNA_OUT; |
| } |
| |
| for (i = 0; i < 3; i++) { |
| out[len - 1] -= |
| (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_3[i]]) >> SR_FNA_OUT; |
| out[len - 1] += |
| (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_3[5 - i]]) >> SR_FNA_OUT; |
| } |
| |
| } else { |
| /* exploit the symmetry of the table: coeff[6] = coeff[0], |
| coeff[5] = coeff[1], |
| coeff[4] = coeff[2] |
| */ |
| |
| for (i = 0; i < 3; i++) { |
| out[0] -= (FIXP_DBL)fMultDiv2(coeff[i], in[indices_1[i]] >> SR_FNA_OUT); |
| out[0] -= |
| (FIXP_DBL)fMultDiv2(coeff[i], in[indices_1[5 - i]] >> SR_FNA_OUT); |
| } |
| out[0] -= (FIXP_DBL)fMultDiv2(coeff[3], in[0] >> SR_FNA_OUT); |
| |
| for (i = 0; i < 3; i++) { |
| out[1] += (FIXP_DBL)fMultDiv2(coeff[i], in[indices_2[i]] >> SR_FNA_OUT); |
| out[1] += |
| (FIXP_DBL)fMultDiv2(coeff[i], in[indices_2[5 - i]] >> SR_FNA_OUT); |
| } |
| out[1] += (FIXP_DBL)fMultDiv2(coeff[3], in[1] >> SR_FNA_OUT); |
| |
| for (i = 0; i < 3; i++) { |
| out[2] -= (FIXP_DBL)fMultDiv2(coeff[i], in[indices_3[i]] >> SR_FNA_OUT); |
| out[2] -= |
| (FIXP_DBL)fMultDiv2(coeff[i], in[indices_3[5 - i]] >> SR_FNA_OUT); |
| } |
| out[2] -= (FIXP_DBL)fMultDiv2(coeff[3], in[2] >> SR_FNA_OUT); |
| |
| for (j = 3; j < (len - 4); j++) { |
| for (i = 0; i < 3; i++) { |
| out[j] += (FIXP_DBL)fMultDiv2(coeff[i], in[j - 3 + i] >> SR_FNA_OUT); |
| out[j] += (FIXP_DBL)fMultDiv2(coeff[i], in[j + 3 - i] >> SR_FNA_OUT); |
| } |
| out[j] += (FIXP_DBL)fMultDiv2(coeff[3], in[j] >> SR_FNA_OUT); |
| |
| j++; |
| |
| for (i = 0; i < 3; i++) { |
| out[j] -= (FIXP_DBL)fMultDiv2(coeff[i], in[j - 3 + i] >> SR_FNA_OUT); |
| out[j] -= (FIXP_DBL)fMultDiv2(coeff[i], in[j + 3 - i] >> SR_FNA_OUT); |
| } |
| out[j] -= (FIXP_DBL)fMultDiv2(coeff[3], in[j] >> SR_FNA_OUT); |
| } |
| |
| for (i = 0; i < 3; i++) { |
| out[len - 3] += |
| (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_1[i]] >> SR_FNA_OUT); |
| out[len - 3] += |
| (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_1[5 - i]] >> SR_FNA_OUT); |
| } |
| out[len - 3] += (FIXP_DBL)fMultDiv2(coeff[3], in[len - 3] >> SR_FNA_OUT); |
| |
| for (i = 0; i < 3; i++) { |
| out[len - 2] -= |
| (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_2[i]] >> SR_FNA_OUT); |
| out[len - 2] -= |
| (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_2[5 - i]] >> SR_FNA_OUT); |
| } |
| out[len - 2] -= (FIXP_DBL)fMultDiv2(coeff[3], in[len - 2] >> SR_FNA_OUT); |
| |
| for (i = 0; i < 3; i++) { |
| out[len - 1] += |
| (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_3[i]] >> SR_FNA_OUT); |
| out[len - 1] += |
| (FIXP_DBL)fMultDiv2(coeff[i], in[len - subtr_3[5 - i]] >> SR_FNA_OUT); |
| } |
| out[len - 1] += (FIXP_DBL)fMultDiv2(coeff[3], in[len - 1] >> SR_FNA_OUT); |
| } |
| } |
| |
| static inline void CJointStereo_GenerateMSOutput(FIXP_DBL *pSpecLCurrBand, |
| FIXP_DBL *pSpecRCurrBand, |
| UINT leftScale, |
| UINT rightScale, |
| UINT nSfbBands) { |
| unsigned int i; |
| |
| FIXP_DBL leftCoefficient0; |
| FIXP_DBL leftCoefficient1; |
| FIXP_DBL leftCoefficient2; |
| FIXP_DBL leftCoefficient3; |
| |
| FIXP_DBL rightCoefficient0; |
| FIXP_DBL rightCoefficient1; |
| FIXP_DBL rightCoefficient2; |
| FIXP_DBL rightCoefficient3; |
| |
| for (i = nSfbBands; i > 0; i -= 4) { |
| leftCoefficient0 = pSpecLCurrBand[i - 4]; |
| leftCoefficient1 = pSpecLCurrBand[i - 3]; |
| leftCoefficient2 = pSpecLCurrBand[i - 2]; |
| leftCoefficient3 = pSpecLCurrBand[i - 1]; |
| |
| rightCoefficient0 = pSpecRCurrBand[i - 4]; |
| rightCoefficient1 = pSpecRCurrBand[i - 3]; |
| rightCoefficient2 = pSpecRCurrBand[i - 2]; |
| rightCoefficient3 = pSpecRCurrBand[i - 1]; |
| |
| /* MS output generation */ |
| leftCoefficient0 >>= leftScale; |
| leftCoefficient1 >>= leftScale; |
| leftCoefficient2 >>= leftScale; |
| leftCoefficient3 >>= leftScale; |
| |
| rightCoefficient0 >>= rightScale; |
| rightCoefficient1 >>= rightScale; |
| rightCoefficient2 >>= rightScale; |
| rightCoefficient3 >>= rightScale; |
| |
| pSpecLCurrBand[i - 4] = leftCoefficient0 + rightCoefficient0; |
| pSpecLCurrBand[i - 3] = leftCoefficient1 + rightCoefficient1; |
| pSpecLCurrBand[i - 2] = leftCoefficient2 + rightCoefficient2; |
| pSpecLCurrBand[i - 1] = leftCoefficient3 + rightCoefficient3; |
| |
| pSpecRCurrBand[i - 4] = leftCoefficient0 - rightCoefficient0; |
| pSpecRCurrBand[i - 3] = leftCoefficient1 - rightCoefficient1; |
| pSpecRCurrBand[i - 2] = leftCoefficient2 - rightCoefficient2; |
| pSpecRCurrBand[i - 1] = leftCoefficient3 - rightCoefficient3; |
| } |
| } |
| |
| void CJointStereo_ApplyMS( |
| CAacDecoderChannelInfo *pAacDecoderChannelInfo[2], |
| CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo[2], |
| FIXP_DBL *spectrumL, FIXP_DBL *spectrumR, SHORT *SFBleftScale, |
| SHORT *SFBrightScale, SHORT *specScaleL, SHORT *specScaleR, |
| const SHORT *pScaleFactorBandOffsets, const UCHAR *pWindowGroupLength, |
| const int windowGroups, const int max_sfb_ste_outside, |
| const int scaleFactorBandsTransmittedL, |
| const int scaleFactorBandsTransmittedR, FIXP_DBL *store_dmx_re_prev, |
| SHORT *store_dmx_re_prev_e, const int mainband_flag) { |
| int window, group, band; |
| UCHAR groupMask; |
| CJointStereoData *pJointStereoData = |
| &pAacDecoderChannelInfo[L]->pComData->jointStereoData; |
| CCplxPredictionData *cplxPredictionData = |
| pAacDecoderChannelInfo[L]->pComStaticData->cplxPredictionData; |
| |
| int max_sfb_ste = |
| fMax(scaleFactorBandsTransmittedL, scaleFactorBandsTransmittedR); |
| int min_sfb_ste = |
| fMin(scaleFactorBandsTransmittedL, scaleFactorBandsTransmittedR); |
| int scaleFactorBandsTransmitted = min_sfb_ste; |
| |
| if (pJointStereoData->cplx_pred_flag) { |
| int windowLen, groupwin, frameMaxScale; |
| CJointStereoPersistentData *pJointStereoPersistentData = |
| &pAacDecoderStaticChannelInfo[L] |
| ->pCpeStaticData->jointStereoPersistentData; |
| FIXP_DBL *const staticSpectralCoeffsL = |
| pAacDecoderStaticChannelInfo[L] |
| ->pCpeStaticData->jointStereoPersistentData.spectralCoeffs[L]; |
| FIXP_DBL *const staticSpectralCoeffsR = |
| pAacDecoderStaticChannelInfo[L] |
| ->pCpeStaticData->jointStereoPersistentData.spectralCoeffs[R]; |
| SHORT *const staticSpecScaleL = |
| pAacDecoderStaticChannelInfo[L] |
| ->pCpeStaticData->jointStereoPersistentData.specScale[L]; |
| SHORT *const staticSpecScaleR = |
| pAacDecoderStaticChannelInfo[L] |
| ->pCpeStaticData->jointStereoPersistentData.specScale[R]; |
| |
| FIXP_DBL *dmx_re = |
| pAacDecoderStaticChannelInfo[L] |
| ->pCpeStaticData->jointStereoPersistentData.scratchBuffer; |
| FIXP_DBL *dmx_re_prev = |
| pAacDecoderStaticChannelInfo[L] |
| ->pCpeStaticData->jointStereoPersistentData.scratchBuffer + |
| 1024; |
| |
| /* When MS is applied over the main band this value gets computed. Otherwise |
| * (for the tiles) it uses the assigned value */ |
| SHORT dmx_re_prev_e = *store_dmx_re_prev_e; |
| |
| const FIXP_FILT *pCoeff; |
| const FIXP_FILT *pCoeffPrev; |
| int coeffPointerOffset; |
| |
| int previousShape = (int)pJointStereoPersistentData->winShapePrev; |
| int currentShape = (int)pAacDecoderChannelInfo[L]->icsInfo.WindowShape; |
| |
| /* complex stereo prediction */ |
| |
| /* 0. preparations */ |
| |
| /* 0.0. get scratch buffer for downmix MDST */ |
| C_AALLOC_SCRATCH_START(dmx_im, FIXP_DBL, 1024); |
| |
| /* 0.1. window lengths */ |
| |
| /* get length of short window for current configuration */ |
| windowLen = |
| pAacDecoderChannelInfo[L]->granuleLength; /* framelength 768 => 96, |
| framelength 1024 => 128 */ |
| |
| /* if this is no short-block set length for long-block */ |
| if (pAacDecoderChannelInfo[L]->icsInfo.WindowSequence != BLOCK_SHORT) { |
| windowLen *= 8; |
| } |
| |
| /* 0.2. set pointer to filter-coefficients for MDST excitation including |
| * previous frame portions */ |
| /* cp. ISO/IEC FDIS 23003-3:2011(E) table 125 */ |
| |
| /* set pointer to default-position */ |
| pCoeffPrev = mdst_filt_coef_prev[previousShape]; |
| |
| if (cplxPredictionData->complex_coef == 1) { |
| switch (pAacDecoderChannelInfo[L] |
| ->icsInfo.WindowSequence) { /* current window sequence */ |
| case BLOCK_SHORT: |
| case BLOCK_LONG: |
| pCoeffPrev = mdst_filt_coef_prev[previousShape]; |
| break; |
| |
| case BLOCK_START: |
| if ((pJointStereoPersistentData->winSeqPrev == BLOCK_SHORT) || |
| (pJointStereoPersistentData->winSeqPrev == BLOCK_START)) { |
| /* a stop-start-sequence can only follow on an eight-short-sequence |
| * or a start-sequence */ |
| pCoeffPrev = mdst_filt_coef_prev[2 + previousShape]; |
| } else { |
| pCoeffPrev = mdst_filt_coef_prev[previousShape]; |
| } |
| break; |
| |
| case BLOCK_STOP: |
| pCoeffPrev = mdst_filt_coef_prev[2 + previousShape]; |
| break; |
| |
| default: |
| pCoeffPrev = mdst_filt_coef_prev[previousShape]; |
| break; |
| } |
| } |
| |
| /* 0.3. set pointer to filter-coefficients for MDST excitation */ |
| |
| /* define offset of pointer to filter-coefficients for MDST exitation |
| * employing only the current frame */ |
| if ((previousShape == SHAPE_SINE) && (currentShape == SHAPE_SINE)) { |
| coeffPointerOffset = 0; |
| } else if ((previousShape == SHAPE_SINE) && (currentShape == SHAPE_KBD)) { |
| coeffPointerOffset = 2; |
| } else if ((previousShape == SHAPE_KBD) && (currentShape == SHAPE_KBD)) { |
| coeffPointerOffset = 1; |
| } else /* if ( (previousShape == SHAPE_KBD) && (currentShape == SHAPE_SINE) |
| ) */ |
| { |
| coeffPointerOffset = 3; |
| } |
| |
| /* set pointer to filter-coefficient table cp. ISO/IEC FDIS 23003-3:2011(E) |
| * table 124 */ |
| switch (pAacDecoderChannelInfo[L] |
| ->icsInfo.WindowSequence) { /* current window sequence */ |
| case BLOCK_SHORT: |
| case BLOCK_LONG: |
| pCoeff = mdst_filt_coef_curr[coeffPointerOffset]; |
| break; |
| |
| case BLOCK_START: |
| if ((pJointStereoPersistentData->winSeqPrev == BLOCK_SHORT) || |
| (pJointStereoPersistentData->winSeqPrev == BLOCK_START)) { |
| /* a stop-start-sequence can only follow on an eight-short-sequence or |
| * a start-sequence */ |
| pCoeff = mdst_filt_coef_curr[12 + coeffPointerOffset]; |
| } else { |
| pCoeff = mdst_filt_coef_curr[4 + coeffPointerOffset]; |
| } |
| break; |
| |
| case BLOCK_STOP: |
| pCoeff = mdst_filt_coef_curr[8 + coeffPointerOffset]; |
| break; |
| |
| default: |
| pCoeff = mdst_filt_coef_curr[coeffPointerOffset]; |
| } |
| |
| /* 0.4. find maximum common (l/r) band-scaling-factor for whole sequence |
| * (all windows) */ |
| frameMaxScale = 0; |
| for (window = 0, group = 0; group < windowGroups; group++) { |
| for (groupwin = 0; groupwin < pWindowGroupLength[group]; |
| groupwin++, window++) { |
| SHORT *leftScale = &SFBleftScale[window * 16]; |
| SHORT *rightScale = &SFBrightScale[window * 16]; |
| int windowMaxScale = 0; |
| |
| /* find maximum scaling factor of all bands in this window */ |
| for (band = 0; band < min_sfb_ste; band++) { |
| int lScale = leftScale[band]; |
| int rScale = rightScale[band]; |
| int commonScale = ((lScale > rScale) ? lScale : rScale); |
| windowMaxScale = |
| (windowMaxScale < commonScale) ? commonScale : windowMaxScale; |
| } |
| if (scaleFactorBandsTransmittedL > |
| min_sfb_ste) { /* i.e. scaleFactorBandsTransmittedL == max_sfb_ste |
| */ |
| for (; band < max_sfb_ste; band++) { |
| int lScale = leftScale[band]; |
| windowMaxScale = |
| (windowMaxScale < lScale) ? lScale : windowMaxScale; |
| } |
| } else { |
| if (scaleFactorBandsTransmittedR > |
| min_sfb_ste) { /* i.e. scaleFactorBandsTransmittedR == max_sfb_ste |
| */ |
| for (; band < max_sfb_ste; band++) { |
| int rScale = rightScale[band]; |
| windowMaxScale = |
| (windowMaxScale < rScale) ? rScale : windowMaxScale; |
| } |
| } |
| } |
| |
| /* find maximum common SF of all windows */ |
| frameMaxScale = |
| (frameMaxScale < windowMaxScale) ? windowMaxScale : frameMaxScale; |
| } |
| } |
| |
| /* add some headroom for overflow protection during filter and add operation |
| */ |
| frameMaxScale += 2; |
| |
| /* process on window-basis (i.e. iterate over all groups and corresponding |
| * windows) */ |
| for (window = 0, group = 0; group < windowGroups; group++) { |
| groupMask = 1 << group; |
| |
| for (groupwin = 0; groupwin < pWindowGroupLength[group]; |
| groupwin++, window++) { |
| /* initialize the MDST with zeros */ |
| FDKmemclear(&dmx_im[windowLen * window], windowLen * sizeof(FIXP_DBL)); |
| |
| /* 1. calculate the previous downmix MDCT. We do this once just for the |
| * Main band. */ |
| if (cplxPredictionData->complex_coef == 1) { |
| if ((cplxPredictionData->use_prev_frame == 1) && (mainband_flag)) { |
| /* if this is a long-block or the first window of a short-block |
| calculate the downmix MDCT of the previous frame. |
| use_prev_frame is assumed not to change during a frame! |
| */ |
| |
| /* first determine shiftfactors to scale left and right channel */ |
| if ((pAacDecoderChannelInfo[L]->icsInfo.WindowSequence != |
| BLOCK_SHORT) || |
| (window == 0)) { |
| int index_offset = 0; |
| int srLeftChan = 0; |
| int srRightChan = 0; |
| if (pAacDecoderChannelInfo[L]->icsInfo.WindowSequence == |
| BLOCK_SHORT) { |
| /* use the last window of the previous frame for MDCT |
| * calculation if this is a short-block. */ |
| index_offset = windowLen * 7; |
| if (staticSpecScaleL[7] > staticSpecScaleR[7]) { |
| srRightChan = staticSpecScaleL[7] - staticSpecScaleR[7]; |
| dmx_re_prev_e = staticSpecScaleL[7]; |
| } else { |
| srLeftChan = staticSpecScaleR[7] - staticSpecScaleL[7]; |
| dmx_re_prev_e = staticSpecScaleR[7]; |
| } |
| } else { |
| if (staticSpecScaleL[0] > staticSpecScaleR[0]) { |
| srRightChan = staticSpecScaleL[0] - staticSpecScaleR[0]; |
| dmx_re_prev_e = staticSpecScaleL[0]; |
| } else { |
| srLeftChan = staticSpecScaleR[0] - staticSpecScaleL[0]; |
| dmx_re_prev_e = staticSpecScaleR[0]; |
| } |
| } |
| |
| /* now scale channels and determine downmix MDCT of previous frame |
| */ |
| if (pAacDecoderStaticChannelInfo[L] |
| ->pCpeStaticData->jointStereoPersistentData |
| .clearSpectralCoeffs == 1) { |
| FDKmemclear(dmx_re_prev, windowLen * sizeof(FIXP_DBL)); |
| dmx_re_prev_e = 0; |
| } else { |
| if (cplxPredictionData->pred_dir == 0) { |
| for (int i = 0; i < windowLen; i++) { |
| dmx_re_prev[i] = |
| ((staticSpectralCoeffsL[index_offset + i] >> |
| srLeftChan) + |
| (staticSpectralCoeffsR[index_offset + i] >> |
| srRightChan)) >> |
| 1; |
| } |
| } else { |
| for (int i = 0; i < windowLen; i++) { |
| dmx_re_prev[i] = |
| ((staticSpectralCoeffsL[index_offset + i] >> |
| srLeftChan) - |
| (staticSpectralCoeffsR[index_offset + i] >> |
| srRightChan)) >> |
| 1; |
| } |
| } |
| } |
| |
| /* In case that we use INF we have to preserve the state of the |
| "dmx_re_prev" (original or computed). This is necessary because we |
| have to apply MS over the separate IGF tiles. */ |
| FDKmemcpy(store_dmx_re_prev, &dmx_re_prev[0], |
| windowLen * sizeof(FIXP_DBL)); |
| |
| /* Particular exponent of the computed/original "dmx_re_prev" must |
| * be kept for the tile MS calculations if necessary.*/ |
| *store_dmx_re_prev_e = dmx_re_prev_e; |
| |
| } /* if ( (pAacDecoderChannelInfo[L]->icsInfo.WindowSequence != |
| BLOCK_SHORT) || (window == 0) ) */ |
| |
| } /* if ( pJointStereoData->use_prev_frame == 1 ) */ |
| |
| } /* if ( pJointStereoData->complex_coef == 1 ) */ |
| |
| /* 2. calculate downmix MDCT of current frame */ |
| |
| /* set pointer to scale-factor-bands of current window */ |
| SHORT *leftScale = &SFBleftScale[window * 16]; |
| SHORT *rightScale = &SFBrightScale[window * 16]; |
| |
| specScaleL[window] = specScaleR[window] = frameMaxScale; |
| |
| /* adapt scaling-factors to previous frame */ |
| if (cplxPredictionData->use_prev_frame == 1) { |
| if (window == 0) { |
| if (dmx_re_prev_e < frameMaxScale) { |
| if (mainband_flag == 0) { |
| scaleValues(dmx_re_prev, store_dmx_re_prev, windowLen, |
| -(frameMaxScale - dmx_re_prev_e)); |
| } else { |
| for (int i = 0; i < windowLen; i++) { |
| dmx_re_prev[i] >>= (frameMaxScale - dmx_re_prev_e); |
| } |
| } |
| } else { |
| if (mainband_flag == 0) { |
| FDKmemcpy(dmx_re_prev, store_dmx_re_prev, |
| windowLen * sizeof(FIXP_DBL)); |
| } |
| specScaleL[0] = dmx_re_prev_e; |
| specScaleR[0] = dmx_re_prev_e; |
| } |
| } else { /* window != 0 */ |
| FDK_ASSERT(pAacDecoderChannelInfo[L]->icsInfo.WindowSequence == |
| BLOCK_SHORT); |
| if (specScaleL[window - 1] < frameMaxScale) { |
| for (int i = 0; i < windowLen; i++) { |
| dmx_re[windowLen * (window - 1) + i] >>= |
| (frameMaxScale - specScaleL[window - 1]); |
| } |
| } else { |
| specScaleL[window] = specScaleL[window - 1]; |
| specScaleR[window] = specScaleR[window - 1]; |
| } |
| } |
| } /* if ( pJointStereoData->use_prev_frame == 1 ) */ |
| |
| /* scaling factors of both channels ought to be equal now */ |
| FDK_ASSERT(specScaleL[window] == specScaleR[window]); |
| |
| /* rescale signal and calculate downmix MDCT */ |
| for (band = 0; band < max_sfb_ste; band++) { |
| /* first adapt scaling of current band to scaling of current window => |
| * shift signal right */ |
| int lScale = leftScale[band]; |
| int rScale = rightScale[band]; |
| |
| lScale = fMin(DFRACT_BITS - 1, specScaleL[window] - lScale); |
| rScale = fMin(DFRACT_BITS - 1, |
| specScaleL[window] - rScale); /* L or R doesn't |
| matter, |
| specScales are |
| equal at this |
| point */ |
| |
| /* Write back to sfb scale to cover the case when max_sfb_ste < |
| * max_sfb */ |
| leftScale[band] = rightScale[band] = specScaleL[window]; |
| |
| for (int i = pScaleFactorBandOffsets[band]; |
| i < pScaleFactorBandOffsets[band + 1]; i++) { |
| spectrumL[windowLen * window + i] >>= lScale; |
| spectrumR[windowLen * window + i] >>= rScale; |
| } |
| |
| /* now calculate downmix MDCT */ |
| if (pJointStereoData->MsUsed[band] & groupMask) { |
| for (int i = pScaleFactorBandOffsets[band]; |
| i < pScaleFactorBandOffsets[band + 1]; i++) { |
| dmx_re[windowLen * window + i] = |
| spectrumL[windowLen * window + i]; |
| } |
| } else { |
| if (cplxPredictionData->pred_dir == 0) { |
| for (int i = pScaleFactorBandOffsets[band]; |
| i < pScaleFactorBandOffsets[band + 1]; i++) { |
| dmx_re[windowLen * window + i] = |
| (spectrumL[windowLen * window + i] + |
| spectrumR[windowLen * window + i]) >> |
| 1; |
| } |
| } else { |
| for (int i = pScaleFactorBandOffsets[band]; |
| i < pScaleFactorBandOffsets[band + 1]; i++) { |
| dmx_re[windowLen * window + i] = |
| (spectrumL[windowLen * window + i] - |
| spectrumR[windowLen * window + i]) >> |
| 1; |
| } |
| } |
| } |
| |
| } /* for ( band=0; band<max_sfb_ste; band++ ) */ |
| /* Clean until the end */ |
| for (int i = pScaleFactorBandOffsets[max_sfb_ste_outside]; |
| i < windowLen; i++) { |
| dmx_re[windowLen * window + i] = (FIXP_DBL)0; |
| } |
| |
| /* 3. calculate MDST-portion corresponding to the current frame. */ |
| if (cplxPredictionData->complex_coef == 1) { |
| { |
| /* 3.1 move pointer in filter-coefficient table in case of short |
| * window sequence */ |
| /* (other coefficients are utilized for the last 7 short |
| * windows) */ |
| if ((pAacDecoderChannelInfo[L]->icsInfo.WindowSequence == |
| BLOCK_SHORT) && |
| (window != 0)) { |
| pCoeff = mdst_filt_coef_curr[currentShape]; |
| pCoeffPrev = mdst_filt_coef_prev[currentShape]; |
| } |
| |
| /* The length of the filter processing must be extended because of |
| * filter boundary problems */ |
| int extended_band = fMin( |
| pScaleFactorBandOffsets[max_sfb_ste_outside] + 7, windowLen); |
| |
| /* 3.2. estimate downmix MDST from current frame downmix MDCT */ |
| if ((pAacDecoderChannelInfo[L]->icsInfo.WindowSequence == |
| BLOCK_SHORT) && |
| (window != 0)) { |
| CJointStereo_filterAndAdd(&dmx_re[windowLen * window], |
| extended_band, windowLen, pCoeff, |
| &dmx_im[windowLen * window], 1); |
| |
| CJointStereo_filterAndAdd(&dmx_re[windowLen * (window - 1)], |
| extended_band, windowLen, pCoeffPrev, |
| &dmx_im[windowLen * window], 0); |
| } else { |
| CJointStereo_filterAndAdd(dmx_re, extended_band, windowLen, |
| pCoeff, dmx_im, 1); |
| |
| if (cplxPredictionData->use_prev_frame == 1) { |
| CJointStereo_filterAndAdd(dmx_re_prev, extended_band, windowLen, |
| pCoeffPrev, |
| &dmx_im[windowLen * window], 0); |
| } |
| } |
| |
| } /* if(pAacDecoderChannelInfo[L]->transform_splitting_active) */ |
| } /* if ( pJointStereoData->complex_coef == 1 ) */ |
| |
| /* 4. upmix process */ |
| INT pred_dir = cplxPredictionData->pred_dir ? -1 : 1; |
| /* 0.1 in Q-3.34 */ |
| const FIXP_DBL pointOne = 0x66666666; /* 0.8 */ |
| /* Shift value for the downmix */ |
| const INT shift_dmx = SF_FNA_COEFFS + 1; |
| |
| for (band = 0; band < max_sfb_ste_outside; band++) { |
| if (pJointStereoData->MsUsed[band] & groupMask) { |
| FIXP_SGL tempRe = |
| (FIXP_SGL)cplxPredictionData->alpha_q_re[group][band]; |
| FIXP_SGL tempIm = |
| (FIXP_SGL)cplxPredictionData->alpha_q_im[group][band]; |
| |
| /* Find the minimum common headroom for alpha_re and alpha_im */ |
| int alpha_re_headroom = CountLeadingBits((INT)tempRe) - 16; |
| if (tempRe == (FIXP_SGL)0) alpha_re_headroom = 15; |
| int alpha_im_headroom = CountLeadingBits((INT)tempIm) - 16; |
| if (tempIm == (FIXP_SGL)0) alpha_im_headroom = 15; |
| int val = fMin(alpha_re_headroom, alpha_im_headroom); |
| |
| /* Multiply alpha by 0.1 with maximum precision */ |
| FDK_ASSERT(val >= 0); |
| FIXP_DBL alpha_re_tmp = fMult((FIXP_SGL)(tempRe << val), pointOne); |
| FIXP_DBL alpha_im_tmp = fMult((FIXP_SGL)(tempIm << val), pointOne); |
| |
| /* Calculate alpha exponent */ |
| /* (Q-3.34 * Q15.0) shifted left by "val" */ |
| int alpha_re_exp = -3 + 15 - val; |
| |
| int help3_shift = alpha_re_exp + 1; |
| |
| FIXP_DBL *p2CoeffL = &( |
| spectrumL[windowLen * window + pScaleFactorBandOffsets[band]]); |
| FIXP_DBL *p2CoeffR = &( |
| spectrumR[windowLen * window + pScaleFactorBandOffsets[band]]); |
| FIXP_DBL *p2dmxIm = |
| &(dmx_im[windowLen * window + pScaleFactorBandOffsets[band]]); |
| FIXP_DBL *p2dmxRe = |
| &(dmx_re[windowLen * window + pScaleFactorBandOffsets[band]]); |
| |
| for (int i = pScaleFactorBandOffsets[band]; |
| i < pScaleFactorBandOffsets[band + 1]; i++) { |
| /* Calculating helper term: |
| side = specR[i] - alpha_re[i] * dmx_re[i] - alpha_im[i] * |
| dmx_im[i]; |
| |
| Here "dmx_re" may be the same as "specL" or alternatively keep |
| the downmix. "dmx_re" and "specL" are two different pointers |
| pointing to separate arrays, which may or may not contain the |
| same data (with different scaling). |
| */ |
| |
| /* help1: alpha_re[i] * dmx_re[i] */ |
| FIXP_DBL help1 = fMultDiv2(alpha_re_tmp, *p2dmxRe++); |
| |
| /* tmp: dmx_im[i] */ |
| FIXP_DBL tmp = (*p2dmxIm++) << shift_dmx; |
| |
| /* help2: alpha_im[i] * dmx_im[i] */ |
| FIXP_DBL help2 = fMultDiv2(alpha_im_tmp, tmp); |
| |
| /* help3: alpha_re[i] * dmx_re[i] + alpha_im[i] * dmx_im[i] */ |
| FIXP_DBL help3 = help1 + help2; |
| |
| /* side (= help4) = specR[i] - (dmx_re[i] * specL[i] + alpha_im[i] |
| * * dmx_im[i]) */ |
| FIXP_DBL help4 = *p2CoeffR - scaleValue(help3, help3_shift); |
| |
| /* We calculate the left and right output by using the helper |
| * function */ |
| /* specR[i] = -/+ (specL[i] - side); */ |
| *p2CoeffR = |
| (FIXP_DBL)((LONG)(*p2CoeffL - help4) * (LONG)pred_dir); |
| p2CoeffR++; |
| |
| /* specL[i] = specL[i] + side; */ |
| *p2CoeffL = *p2CoeffL + help4; |
| p2CoeffL++; |
| } |
| } |
| |
| } /* for ( band=0; band < max_sfb_ste; band++ ) */ |
| } /* for ( groupwin=0; groupwin<pWindowGroupLength[group]; groupwin++, |
| window++ ) */ |
| |
| } /* for ( window = 0, group = 0; group < windowGroups; group++ ) */ |
| |
| /* free scratch buffer */ |
| C_AALLOC_SCRATCH_END(dmx_im, FIXP_DBL, 1024); |
| |
| } else { |
| /* MS stereo */ |
| |
| for (window = 0, group = 0; group < windowGroups; group++) { |
| groupMask = 1 << group; |
| |
| for (int groupwin = 0; groupwin < pWindowGroupLength[group]; |
| groupwin++, window++) { |
| FIXP_DBL *leftSpectrum, *rightSpectrum; |
| SHORT *leftScale = &SFBleftScale[window * 16]; |
| SHORT *rightScale = &SFBrightScale[window * 16]; |
| |
| leftSpectrum = |
| SPEC(spectrumL, window, pAacDecoderChannelInfo[L]->granuleLength); |
| rightSpectrum = |
| SPEC(spectrumR, window, pAacDecoderChannelInfo[R]->granuleLength); |
| |
| for (band = 0; band < max_sfb_ste_outside; band++) { |
| if (pJointStereoData->MsUsed[band] & groupMask) { |
| int lScale = leftScale[band]; |
| int rScale = rightScale[band]; |
| int commonScale = lScale > rScale ? lScale : rScale; |
| unsigned int offsetCurrBand, offsetNextBand; |
| |
| /* ISO/IEC 14496-3 Chapter 4.6.8.1.1 : |
| M/S joint channel coding can only be used if common_window is 1. |
| */ |
| FDK_ASSERT(GetWindowSequence(&pAacDecoderChannelInfo[L]->icsInfo) == |
| GetWindowSequence(&pAacDecoderChannelInfo[R]->icsInfo)); |
| FDK_ASSERT(GetWindowShape(&pAacDecoderChannelInfo[L]->icsInfo) == |
| GetWindowShape(&pAacDecoderChannelInfo[R]->icsInfo)); |
| |
| commonScale++; |
| leftScale[band] = commonScale; |
| rightScale[band] = commonScale; |
| |
| lScale = fMin(DFRACT_BITS - 1, commonScale - lScale); |
| rScale = fMin(DFRACT_BITS - 1, commonScale - rScale); |
| |
| FDK_ASSERT(lScale >= 0 && rScale >= 0); |
| |
| offsetCurrBand = pScaleFactorBandOffsets[band]; |
| offsetNextBand = pScaleFactorBandOffsets[band + 1]; |
| |
| CJointStereo_GenerateMSOutput(&(leftSpectrum[offsetCurrBand]), |
| &(rightSpectrum[offsetCurrBand]), |
| lScale, rScale, |
| offsetNextBand - offsetCurrBand); |
| } |
| } |
| if (scaleFactorBandsTransmittedL > scaleFactorBandsTransmitted) { |
| for (; band < scaleFactorBandsTransmittedL; band++) { |
| if (pJointStereoData->MsUsed[band] & groupMask) { |
| rightScale[band] = leftScale[band]; |
| |
| for (int index = pScaleFactorBandOffsets[band]; |
| index < pScaleFactorBandOffsets[band + 1]; index++) { |
| FIXP_DBL leftCoefficient = leftSpectrum[index]; |
| /* FIXP_DBL rightCoefficient = (FIXP_DBL)0; */ |
| rightSpectrum[index] = leftCoefficient; |
| } |
| } |
| } |
| } else if (scaleFactorBandsTransmittedR > scaleFactorBandsTransmitted) { |
| for (; band < scaleFactorBandsTransmittedR; band++) { |
| if (pJointStereoData->MsUsed[band] & groupMask) { |
| leftScale[band] = rightScale[band]; |
| |
| for (int index = pScaleFactorBandOffsets[band]; |
| index < pScaleFactorBandOffsets[band + 1]; index++) { |
| /* FIXP_DBL leftCoefficient = (FIXP_DBL)0; */ |
| FIXP_DBL rightCoefficient = rightSpectrum[index]; |
| |
| leftSpectrum[index] = rightCoefficient; |
| rightSpectrum[index] = -rightCoefficient; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /* Reset MsUsed flags if no explicit signalling was transmitted. Necessary |
| for intensity coding. PNS correlation signalling was mapped before |
| calling CJointStereo_ApplyMS(). */ |
| if (pJointStereoData->MsMaskPresent == 2) { |
| FDKmemclear(pJointStereoData->MsUsed, |
| JointStereoMaximumBands * sizeof(UCHAR)); |
| } |
| } |
| } |
| |
| void CJointStereo_ApplyIS(CAacDecoderChannelInfo *pAacDecoderChannelInfo[2], |
| const SHORT *pScaleFactorBandOffsets, |
| const UCHAR *pWindowGroupLength, |
| const int windowGroups, |
| const int scaleFactorBandsTransmitted) { |
| CJointStereoData *pJointStereoData = |
| &pAacDecoderChannelInfo[L]->pComData->jointStereoData; |
| |
| for (int window = 0, group = 0; group < windowGroups; group++) { |
| UCHAR *CodeBook; |
| SHORT *ScaleFactor; |
| UCHAR groupMask = 1 << group; |
| |
| CodeBook = &pAacDecoderChannelInfo[R]->pDynData->aCodeBook[group * 16]; |
| ScaleFactor = |
| &pAacDecoderChannelInfo[R]->pDynData->aScaleFactor[group * 16]; |
| |
| for (int groupwin = 0; groupwin < pWindowGroupLength[group]; |
| groupwin++, window++) { |
| FIXP_DBL *leftSpectrum, *rightSpectrum; |
| SHORT *leftScale = |
| &pAacDecoderChannelInfo[L]->pDynData->aSfbScale[window * 16]; |
| SHORT *rightScale = |
| &pAacDecoderChannelInfo[R]->pDynData->aSfbScale[window * 16]; |
| int band; |
| |
| leftSpectrum = SPEC(pAacDecoderChannelInfo[L]->pSpectralCoefficient, |
| window, pAacDecoderChannelInfo[L]->granuleLength); |
| rightSpectrum = SPEC(pAacDecoderChannelInfo[R]->pSpectralCoefficient, |
| window, pAacDecoderChannelInfo[R]->granuleLength); |
| |
| for (band = 0; band < scaleFactorBandsTransmitted; band++) { |
| if ((CodeBook[band] == INTENSITY_HCB) || |
| (CodeBook[band] == INTENSITY_HCB2)) { |
| int bandScale = -(ScaleFactor[band] + 100); |
| |
| int msb = bandScale >> 2; |
| int lsb = bandScale & 0x03; |
| |
| /* exponent of MantissaTable[lsb][0] is 1, thus msb+1 below. */ |
| FIXP_DBL scale = MantissaTable[lsb][0]; |
| |
| /* ISO/IEC 14496-3 Chapter 4.6.8.2.3 : |
| The use of intensity stereo coding is signaled by the use of the |
| pseudo codebooks INTENSITY_HCB and INTENSITY_HCB2 (15 and 14) only |
| in the right channel of a channel_pair_element() having a common |
| ics_info() (common_window == 1). */ |
| FDK_ASSERT(GetWindowSequence(&pAacDecoderChannelInfo[L]->icsInfo) == |
| GetWindowSequence(&pAacDecoderChannelInfo[R]->icsInfo)); |
| FDK_ASSERT(GetWindowShape(&pAacDecoderChannelInfo[L]->icsInfo) == |
| GetWindowShape(&pAacDecoderChannelInfo[R]->icsInfo)); |
| |
| rightScale[band] = leftScale[band] + msb + 1; |
| |
| if (pJointStereoData->MsUsed[band] & groupMask) { |
| if (CodeBook[band] == INTENSITY_HCB) /* _NOT_ in-phase */ |
| { |
| scale = -scale; |
| } |
| } else { |
| if (CodeBook[band] == INTENSITY_HCB2) /* out-of-phase */ |
| { |
| scale = -scale; |
| } |
| } |
| |
| for (int index = pScaleFactorBandOffsets[band]; |
| index < pScaleFactorBandOffsets[band + 1]; index++) { |
| rightSpectrum[index] = fMult(leftSpectrum[index], scale); |
| } |
| } |
| } |
| } |
| } |
| } |