mirror of
https://github.com/mstorsjo/fdk-aac.git
synced 2025-02-09 08:08:40 +01:00
9ab67882ec
Bug: 71430241 Bug: 79220129 Test: cts-tradefed run commandAndExit cts-dev -m CtsMediaTestCases -t android.media.cts.DecoderTestXheAac cts-tradefed run commandAndExit cts-dev -m CtsMediaTestCases -t android.media.cts.DecoderTestAacDrc Add restriction to call intensity stereo tool only for applicable configurations Change-Id: I30ec6640bd484c56cc9d5b8b35186fc1c875e021 Fix high band energy calculation in sbr encoder Change-Id: I964dd46fab2ed797c440a983512bbab7e1aff98a Fix out-of-bounds read access in noiseless coder Change-Id: I9a669435dbdca421ff9e4affec57811002d75b3b Use temporary buffer for dummy parsing to check presence of audioPreroll data Change-Id: I2d42c5c8deddde34351c3d2858b9fe196b3a0906 Set applyAsc to 1 in case that the ASC parsing fails Change-Id: I552a8b960270bc18cae459ad28a3ba241035668e Parametric stereo together with mps not supported Change-Id: Icde14a2774a4303bb0c41046861a59d04b624365 Align ssc callback error path for drm Change-Id: Ie8ecbfa42c702e6df81c1aec532a9ff1e653dac9 Ensure that the bit counter starts at a multiple of TPDEC_SYNCSKIP Change-Id: I08d69ec361b2e2ed800282e333fd248b4b3ca245 Allow flushing only when audioPreroll is enabled in current and new config Change-Id: I52e95d75de4bbed692be922a59a23bda58870625 Omit reverse channel mapping in pass through mode Change-Id: I335e209c29a700cc091be069f1d08e4288b40793
1251 lines
50 KiB
C++
1251 lines
50 KiB
C++
/* -----------------------------------------------------------------------------
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|