summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/codecs/aacenc/src/block_switch.c
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/codecs/aacenc/src/block_switch.c')
-rw-r--r--media/libstagefright/codecs/aacenc/src/block_switch.c431
1 files changed, 431 insertions, 0 deletions
diff --git a/media/libstagefright/codecs/aacenc/src/block_switch.c b/media/libstagefright/codecs/aacenc/src/block_switch.c
new file mode 100644
index 0000000..c0054f7
--- /dev/null
+++ b/media/libstagefright/codecs/aacenc/src/block_switch.c
@@ -0,0 +1,431 @@
+/*
+ ** Copyright 2003-2010, VisualOn, Inc.
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+/*******************************************************************************
+ File: block_switch.c
+
+ Content: Block switching functions
+
+*******************************************************************************/
+
+#include "typedef.h"
+#include "basic_op.h"
+#include "oper_32b.h"
+#include "psy_const.h"
+#include "block_switch.h"
+
+
+#define ENERGY_SHIFT (8 - 1)
+
+/**************** internal function prototypes ***********/
+static Word16
+IIRFilter(const Word16 in, const Word32 coeff[], Word32 states[]);
+
+static Word32
+SrchMaxWithIndex(const Word32 *in, Word16 *index, Word16 n);
+
+
+Word32
+CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *blockSwitchingControl,
+ Word16 *timeSignal,
+ Word16 chIncrement,
+ Word16 windowLen);
+
+
+
+/****************** Constants *****************************/
+
+
+/*
+ IIR high pass coeffs
+*/
+Word32 hiPassCoeff[BLOCK_SWITCHING_IIR_LEN] = {
+ 0xbec8b439, 0x609d4952 /* -0.5095f, 0.7548f */
+};
+
+static const Word32 accWindowNrgFac = 0x26666666; /* factor for accumulating filtered window energies 0.3 */
+static const Word32 oneMinusAccWindowNrgFac = 0x5999999a; /* 0.7 */
+static const Word32 invAttackRatioHighBr = 0x0ccccccd; /* inverted lower ratio limit for attacks 0.1*/
+static const Word32 invAttackRatioLowBr = 0x072b020c; /* 0.056 */
+static const Word32 minAttackNrg = 0x00001e84; /* minimum energy for attacks 1e+6 */
+
+
+/****************** Routines ****************************/
+
+
+/*****************************************************************************
+*
+* function name: InitBlockSwitching
+* description: init Block Switching parameter.
+* returns: TRUE if success
+*
+**********************************************************************************/
+Word16 InitBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl,
+ const Word32 bitRate, const Word16 nChannels)
+{
+ /* select attackRatio */
+
+ if ((sub(nChannels,1)==0 && L_sub(bitRate, 24000) > 0) ||
+ (sub(nChannels,1)>0 && bitRate > (nChannels * 16000))) {
+ blockSwitchingControl->invAttackRatio = invAttackRatioHighBr;
+ }
+ else {
+ blockSwitchingControl->invAttackRatio = invAttackRatioLowBr;
+ }
+
+ return(TRUE);
+}
+
+static Word16 suggestedGroupingTable[TRANS_FAC][MAX_NO_OF_GROUPS] = {
+ /* Attack in Window 0 */ {1, 3, 3, 1},
+ /* Attack in Window 1 */ {1, 1, 3, 3},
+ /* Attack in Window 2 */ {2, 1, 3, 2},
+ /* Attack in Window 3 */ {3, 1, 3, 1},
+ /* Attack in Window 4 */ {3, 1, 1, 3},
+ /* Attack in Window 5 */ {3, 2, 1, 2},
+ /* Attack in Window 6 */ {3, 3, 1, 1},
+ /* Attack in Window 7 */ {3, 3, 1, 1}
+};
+
+/*****************************************************************************
+*
+* function name: BlockSwitching
+* description: detect this frame whether there is an attack
+* returns: TRUE if success
+*
+**********************************************************************************/
+Word16 BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl,
+ Word16 *timeSignal,
+ Word32 sampleRate,
+ Word16 chIncrement)
+{
+ Word32 i, w;
+ Word32 enM1, enMax;
+
+ /* Reset grouping info */
+ for (i=0; i<TRANS_FAC; i++) {
+ blockSwitchingControl->groupLen[i] = 0;
+ }
+
+
+ /* Search for position and amplitude of attack in last frame (1 windows delay) */
+ blockSwitchingControl->maxWindowNrg = SrchMaxWithIndex( &blockSwitchingControl->windowNrg[0][BLOCK_SWITCH_WINDOWS-1],
+ &blockSwitchingControl->attackIndex,
+ BLOCK_SWITCH_WINDOWS);
+
+ blockSwitchingControl->attackIndex = blockSwitchingControl->lastAttackIndex;
+
+ /* Set grouping info */
+ blockSwitchingControl->noOfGroups = MAX_NO_OF_GROUPS;
+
+ for (i=0; i<MAX_NO_OF_GROUPS; i++) {
+ blockSwitchingControl->groupLen[i] = suggestedGroupingTable[blockSwitchingControl->attackIndex][i];
+ }
+
+ /* if the samplerate is less than 16000, it should be all the short block, avoid pre&post echo */
+ if(sampleRate >= 16000) {
+ /* Save current window energy as last window energy */
+ for (w=0; w<BLOCK_SWITCH_WINDOWS; w++) {
+ blockSwitchingControl->windowNrg[0][w] = blockSwitchingControl->windowNrg[1][w];
+ blockSwitchingControl->windowNrgF[0][w] = blockSwitchingControl->windowNrgF[1][w];
+ }
+
+
+ /* Calculate unfiltered and filtered energies in subwindows and combine to segments */
+ CalcWindowEnergy(blockSwitchingControl, timeSignal, chIncrement, BLOCK_SWITCH_WINDOW_LEN);
+
+ /* reset attack */
+ blockSwitchingControl->attack = FALSE;
+
+ enMax = 0;
+ enM1 = blockSwitchingControl->windowNrgF[0][BLOCK_SWITCH_WINDOWS-1];
+
+ for (w=0; w<BLOCK_SWITCH_WINDOWS; w++) {
+ Word32 enM1_Tmp, accWindowNrg_Tmp, windowNrgF_Tmp;
+ Word16 enM1_Shf, accWindowNrg_Shf, windowNrgF_Shf;
+
+ accWindowNrg_Shf = norm_l(blockSwitchingControl->accWindowNrg);
+ enM1_Shf = norm_l(enM1);
+ windowNrgF_Shf = norm_l(blockSwitchingControl->windowNrgF[1][w]);
+
+ accWindowNrg_Tmp = blockSwitchingControl->accWindowNrg << accWindowNrg_Shf;
+ enM1_Tmp = enM1 << enM1_Shf;
+ windowNrgF_Tmp = blockSwitchingControl->windowNrgF[1][w] << windowNrgF_Shf;
+
+ /* a sliding average of the previous energies */
+ blockSwitchingControl->accWindowNrg = (fixmul(oneMinusAccWindowNrgFac, accWindowNrg_Tmp) >> accWindowNrg_Shf) +
+ (fixmul(accWindowNrgFac, enM1_Tmp) >> enM1_Shf);
+
+
+ /* if the energy with the ratio is bigger than the average, and the attack and short block */
+ if ((fixmul(windowNrgF_Tmp, blockSwitchingControl->invAttackRatio) >> windowNrgF_Shf) >
+ blockSwitchingControl->accWindowNrg ) {
+ blockSwitchingControl->attack = TRUE;
+ blockSwitchingControl->lastAttackIndex = w;
+ }
+ enM1 = blockSwitchingControl->windowNrgF[1][w];
+ enMax = max(enMax, enM1);
+ }
+
+ if (enMax < minAttackNrg) {
+ blockSwitchingControl->attack = FALSE;
+ }
+ }
+ else
+ {
+ blockSwitchingControl->attack = TRUE;
+ }
+
+ /* Check if attack spreads over frame border */
+ if ((!blockSwitchingControl->attack) && (blockSwitchingControl->lastattack)) {
+
+ if (blockSwitchingControl->attackIndex == TRANS_FAC-1) {
+ blockSwitchingControl->attack = TRUE;
+ }
+
+ blockSwitchingControl->lastattack = FALSE;
+ }
+ else {
+ blockSwitchingControl->lastattack = blockSwitchingControl->attack;
+ }
+
+ blockSwitchingControl->windowSequence = blockSwitchingControl->nextwindowSequence;
+
+
+ if (blockSwitchingControl->attack) {
+ blockSwitchingControl->nextwindowSequence = SHORT_WINDOW;
+ }
+ else {
+ blockSwitchingControl->nextwindowSequence = LONG_WINDOW;
+ }
+
+ /* update short block group */
+ if (blockSwitchingControl->nextwindowSequence == SHORT_WINDOW) {
+
+ if (blockSwitchingControl->windowSequence== LONG_WINDOW) {
+ blockSwitchingControl->windowSequence = START_WINDOW;
+ }
+
+ if (blockSwitchingControl->windowSequence == STOP_WINDOW) {
+ blockSwitchingControl->windowSequence = SHORT_WINDOW;
+ blockSwitchingControl->noOfGroups = 3;
+ blockSwitchingControl->groupLen[0] = 3;
+ blockSwitchingControl->groupLen[1] = 3;
+ blockSwitchingControl->groupLen[2] = 2;
+ }
+ }
+
+ /* update block type */
+ if (blockSwitchingControl->nextwindowSequence == LONG_WINDOW) {
+
+ if (blockSwitchingControl->windowSequence == SHORT_WINDOW) {
+ blockSwitchingControl->nextwindowSequence = STOP_WINDOW;
+ }
+ }
+
+ return(TRUE);
+}
+
+
+/*****************************************************************************
+*
+* function name: SrchMaxWithIndex
+* description: search for the biggest value in an array
+* returns: the max value
+*
+**********************************************************************************/
+static Word32 SrchMaxWithIndex(const Word32 in[], Word16 *index, Word16 n)
+{
+ Word32 max;
+ Word32 i, idx;
+
+ /* Search maximum value in array and return index and value */
+ max = 0;
+ idx = 0;
+
+ for (i = 0; i < n; i++) {
+
+ if (in[i+1] > max) {
+ max = in[i+1];
+ idx = i;
+ }
+ }
+ *index = idx;
+
+ return(max);
+}
+
+/*****************************************************************************
+*
+* function name: CalcWindowEnergy
+* description: calculate the energy before iir-filter and after irr-filter
+* returns: TRUE if success
+*
+**********************************************************************************/
+#ifndef ARMV5E
+Word32 CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *blockSwitchingControl,
+ Word16 *timeSignal,
+ Word16 chIncrement,
+ Word16 windowLen)
+{
+ Word32 w, i, wOffset, tidx, ch;
+ Word32 accuUE, accuFE;
+ Word32 tempUnfiltered;
+ Word32 tempFiltered;
+ Word32 states0, states1;
+ Word32 Coeff0, Coeff1;
+
+
+ states0 = blockSwitchingControl->iirStates[0];
+ states1 = blockSwitchingControl->iirStates[1];
+ Coeff0 = hiPassCoeff[0];
+ Coeff1 = hiPassCoeff[1];
+ tidx = 0;
+ for (w=0; w < BLOCK_SWITCH_WINDOWS; w++) {
+
+ accuUE = 0;
+ accuFE = 0;
+
+ for(i=0; i<windowLen; i++) {
+ Word32 accu1, accu2, accu3;
+ Word32 out;
+ tempUnfiltered = timeSignal[tidx];
+ tidx = tidx + chIncrement;
+
+ accu1 = L_mpy_ls(Coeff1, tempUnfiltered);
+ accu2 = fixmul( Coeff0, states1 );
+ accu3 = accu1 - states0;
+ out = accu3 - accu2;
+
+ states0 = accu1;
+ states1 = out;
+
+ tempFiltered = extract_h(out);
+ accuUE += (tempUnfiltered * tempUnfiltered) >> ENERGY_SHIFT;
+ accuFE += (tempFiltered * tempFiltered) >> ENERGY_SHIFT;
+ }
+
+ blockSwitchingControl->windowNrg[1][w] = accuUE;
+ blockSwitchingControl->windowNrgF[1][w] = accuFE;
+
+ }
+
+ blockSwitchingControl->iirStates[0] = states0;
+ blockSwitchingControl->iirStates[1] = states1;
+
+ return(TRUE);
+}
+#endif
+
+/*****************************************************************************
+*
+* function name: IIRFilter
+* description: calculate the iir-filter for an array
+* returns: the result after iir-filter
+*
+**********************************************************************************/
+static Word16 IIRFilter(const Word16 in, const Word32 coeff[], Word32 states[])
+{
+ Word32 accu1, accu2, accu3;
+ Word32 out;
+
+ accu1 = L_mpy_ls(coeff[1], in);
+ accu3 = accu1 - states[0];
+ accu2 = fixmul( coeff[0], states[1] );
+ out = accu3 - accu2;
+
+ states[0] = accu1;
+ states[1] = out;
+
+ return round16(out);
+}
+
+
+static Word16 synchronizedBlockTypeTable[4][4] = {
+ /* LONG_WINDOW START_WINDOW SHORT_WINDOW STOP_WINDOW */
+ /* LONG_WINDOW */{LONG_WINDOW, START_WINDOW, SHORT_WINDOW, STOP_WINDOW},
+ /* START_WINDOW */{START_WINDOW, START_WINDOW, SHORT_WINDOW, SHORT_WINDOW},
+ /* SHORT_WINDOW */{SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW},
+ /* STOP_WINDOW */{STOP_WINDOW, SHORT_WINDOW, SHORT_WINDOW, STOP_WINDOW}
+};
+
+
+/*****************************************************************************
+*
+* function name: SyncBlockSwitching
+* description: update block type and group value
+* returns: TRUE if success
+*
+**********************************************************************************/
+Word16 SyncBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControlLeft,
+ BLOCK_SWITCHING_CONTROL *blockSwitchingControlRight,
+ const Word16 nChannels)
+{
+ Word16 i;
+ Word16 patchType = LONG_WINDOW;
+
+
+ if (nChannels == 1) { /* Mono */
+ if (blockSwitchingControlLeft->windowSequence != SHORT_WINDOW) {
+ blockSwitchingControlLeft->noOfGroups = 1;
+ blockSwitchingControlLeft->groupLen[0] = 1;
+
+ for (i=1; i<TRANS_FAC; i++) {
+ blockSwitchingControlLeft->groupLen[i] = 0;
+ }
+ }
+ }
+ else { /* Stereo common Window */
+ patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlLeft->windowSequence];
+ patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlRight->windowSequence];
+
+ /* Set synchronized Blocktype */
+ blockSwitchingControlLeft->windowSequence = patchType;
+ blockSwitchingControlRight->windowSequence = patchType;
+
+ /* Synchronize grouping info */
+ if(patchType != SHORT_WINDOW) { /* Long Blocks */
+ /* Set grouping info */
+ blockSwitchingControlLeft->noOfGroups = 1;
+ blockSwitchingControlRight->noOfGroups = 1;
+ blockSwitchingControlLeft->groupLen[0] = 1;
+ blockSwitchingControlRight->groupLen[0] = 1;
+
+ for (i=1; i<TRANS_FAC; i++) {
+ blockSwitchingControlLeft->groupLen[i] = 0;
+ blockSwitchingControlRight->groupLen[i] = 0;
+ }
+ }
+ else {
+
+ if (blockSwitchingControlLeft->maxWindowNrg > blockSwitchingControlRight->maxWindowNrg) {
+ /* Left Channel wins */
+ blockSwitchingControlRight->noOfGroups = blockSwitchingControlLeft->noOfGroups;
+ for (i=0; i<TRANS_FAC; i++) {
+ blockSwitchingControlRight->groupLen[i] = blockSwitchingControlLeft->groupLen[i];
+ }
+ }
+ else {
+ /* Right Channel wins */
+ blockSwitchingControlLeft->noOfGroups = blockSwitchingControlRight->noOfGroups;
+ for (i=0; i<TRANS_FAC; i++) {
+ blockSwitchingControlLeft->groupLen[i] = blockSwitchingControlRight->groupLen[i];
+ }
+ }
+ }
+ } /*endif Mono or Stereo */
+
+ return(TRUE);
+}