adj_thr.c revision 01e29ede19cd7d85bfef38896de8e71e569cd211
1e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard/*
2e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard ** Copyright 2003-2010, VisualOn, Inc.
3e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard **
4e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard ** Licensed under the Apache License, Version 2.0 (the "License");
5e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard ** you may not use this file except in compliance with the License.
6e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard ** You may obtain a copy of the License at
7e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard **
8e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard **     http://www.apache.org/licenses/LICENSE-2.0
9e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard **
10e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard ** Unless required by applicable law or agreed to in writing, software
11e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard ** distributed under the License is distributed on an "AS IS" BASIS,
12e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard ** See the License for the specific language governing permissions and
14e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard ** limitations under the License.
15e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard */
16e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard/*******************************************************************************
17e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	File:		adj_thr.c
18e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard
19e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	Content:	Threshold compensation functions
20e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard
21956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*******************************************************************************/
22956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
23e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard#include "basic_op.h"
24956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong#include "oper_32b.h"
25956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong#include "adj_thr_data.h"
26956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong#include "adj_thr.h"
27956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong#include "qc_data.h"
28956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong#include "line_pe.h"
29956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
30956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
31956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong#define  minSnrLimit    0x6666 /* 1 dB */
32e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard#define  PEBITS_COEF	0x170a /* 0.18*(1 << 15)*/
33e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard
34e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard#define  HOLE_THR_LONG	0x2873	/* 0.316*(1 << 15) */
35e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard#define  HOLE_THR_SHORT 0x4000  /* 0.5  *(1 << 15) */
36e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard
37e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard#define  MS_THRSPREAD_COEF 0x7333  /* 0.9 * (1 << 15) */
38e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard
39e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard#define	 MIN_SNR_COEF	   0x651f  /* 3.16* (1 << (15 - 2)) */
40956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
41956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/* values for avoid hole flag */
42956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongenum _avoid_hole_state {
43956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  NO_AH              =0,
44956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  AH_INACTIVE        =1,
45956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  AH_ACTIVE          =2
46956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong};
47956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
48956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
49956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
50956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:bits2pe
51956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: convert from bits to pe
52956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*			   pe = 1.18*desiredBits
53956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
54956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
55956c553ab0ce72f8074ad0fda2ffd66a0305700cJames DongWord16 bits2pe(const Word16 bits) {
56956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  return (bits + ((PEBITS_COEF * bits) >> 15));
57956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
58956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
59956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
60956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
61956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:calcThreshExp
62956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: loudness calculation (threshold to the power of redExp)
63956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*			   thr(n)^0.25
64956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
65956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
66956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void calcThreshExp(Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
67956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
68956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word16 nChannels)
69956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
70e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  Word16 ch, sfb, sfbGrp;
71956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 *pthrExp, *psfbThre;
72956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for (ch=0; ch<nChannels; ch++) {
73e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard    PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
74b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard	 for(sfbGrp = 0; sfbGrp < psyOutChan->sfbCnt; sfbGrp+= psyOutChan->sfbPerGroup)
75e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	  pthrExp = &(thrExp[ch][sfbGrp]);
76e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	  psfbThre = psyOutChan->sfbThreshold + sfbGrp;
77956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
78e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard		*pthrExp = rsqrt(rsqrt(*psfbThre,INT_BITS),INT_BITS);
79956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		pthrExp++; psfbThre++;
80956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
81956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
82956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
83956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
84956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
85956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
86956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:adaptMinSnr
87956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: reduce minSnr requirements for bands with relative low energies
88956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
89956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
90956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void adaptMinSnr(PSY_OUT_CHANNEL     psyOutChannel[MAX_CHANNELS],
91956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        Word16              logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
92956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        MINSNR_ADAPT_PARAM *msaParam,
93956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        const Word16        nChannels)
94956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
95956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 ch, sfb, sfbOffs, shift;
96956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 nSfb, avgEn;
97956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 log_avgEn = 0;
98956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 startRatio_x_avgEn = 0;
99b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
100956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
101956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for (ch=0; ch<nChannels; ch++) {
102956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL* psyOutChan = &psyOutChannel[ch];
103956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
104956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* calc average energy per scalefactor band */
105b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    avgEn = 0;
106b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    nSfb = 0;
107956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (sfbOffs=0; sfbOffs<psyOutChan->sfbCnt; sfbOffs+=psyOutChan->sfbPerGroup) {
108956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
109956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        avgEn = L_add(avgEn, psyOutChan->sfbEnergy[sfbOffs+sfb]);
110956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        nSfb = nSfb + 1;
111956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
112956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
113b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
114956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if (nSfb > 0) {
115e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	  avgEn = avgEn / nSfb;
116956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
117956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      log_avgEn = iLog4(avgEn);
118956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      startRatio_x_avgEn = fixmul(msaParam->startRatio, avgEn);
119956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
120956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
121b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
122956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* reduce minSnr requirement by minSnr^minSnrRed dependent on avgEn/sfbEn */
123956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (sfbOffs=0; sfbOffs<psyOutChan->sfbCnt; sfbOffs+=psyOutChan->sfbPerGroup) {
124956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
125956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (psyOutChan->sfbEnergy[sfbOffs+sfb] < startRatio_x_avgEn) {
126956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          Word16 dbRatio, minSnrRed;
127956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          Word32 snrRed;
128956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          Word16 newMinSnr;
129b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
130956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          dbRatio = log_avgEn - logSfbEnergy[ch][sfbOffs+sfb];
131956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          dbRatio = dbRatio + (dbRatio << 1);
132956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
133956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          minSnrRed = 110 - ((dbRatio + (dbRatio << 1)) >> 2);
134b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          minSnrRed = max(minSnrRed, 20); /* 110: (0.375(redOffs)+1)*80,
135956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                               3: 0.00375(redRatioFac)*80
136956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                               20: 0.25(maxRed) * 80 */
137956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
138b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          snrRed = minSnrRed * iLog4((psyOutChan->sfbMinSnr[sfbOffs+sfb] << 16));
139b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          /*
140956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong             snrRedI si now scaled by 80 (minSnrRed) and 4 (ffr_iLog4)
141956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          */
142b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
143956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          newMinSnr = round16(pow2_xy(snrRed,80*4));
144b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
145956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          psyOutChan->sfbMinSnr[sfbOffs+sfb] = min(newMinSnr, minSnrLimit);
146956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
147956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
148956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
149956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
150956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
151956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
152956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
153956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
154956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
155956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
156956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:initAvoidHoleFlag
157956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: determine bands where avoid hole is not necessary resp. possible
158956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
159956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
160956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void initAvoidHoleFlag(Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
161956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                              PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
162956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                              PSY_OUT_ELEMENT* psyOutElement,
163956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                              const Word16 nChannels,
164956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                              AH_PARAM *ahParam)
165956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
166956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 ch, sfb, sfbGrp, shift;
167956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 threshold;
168956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32* psfbSpreadEn;
169956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
170956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for (ch=0; ch<nChannels; ch++) {
171956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
172b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
173956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if (psyOutChan->windowSequence != SHORT_WINDOW) {
174956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
175e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard         psfbSpreadEn = psyOutChan->sfbSpreadedEnergy + sfbGrp;
176956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		 for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
177e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard			*psfbSpreadEn = *psfbSpreadEn >> 1;  /* 0.5 */
178956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong			++psfbSpreadEn;
179956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
180956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
181956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
182956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    else {
183e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard      for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
184956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		psfbSpreadEn = psyOutChan->sfbSpreadedEnergy + sfbGrp;
185956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
186e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard          *psfbSpreadEn = (*psfbSpreadEn >> 1) + (*psfbSpreadEn >> 3);  /* 0.63 */
187956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		  ++psfbSpreadEn;
188956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
189956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
190956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
191956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
192956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
193956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* increase minSnr for local peaks, decrease it for valleys */
194956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (ahParam->modifyMinSnr) {
195956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for(ch=0; ch<nChannels; ch++) {
196956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
197b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
198956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if (psyOutChan->windowSequence != SHORT_WINDOW)
199956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        threshold = HOLE_THR_LONG;
200956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      else
201956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        threshold = HOLE_THR_SHORT;
202956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
203956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
204e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard        Word16 *psfbMinSnr = psyOutChan->sfbMinSnr + sfbGrp;
205956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
206956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          Word32 sfbEn, sfbEnm1, sfbEnp1, avgEn;
207b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
208956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if (sfb > 0)
209956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            sfbEnm1 = psyOutChan->sfbEnergy[sfbGrp+sfb-1];
210956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          else
211956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            sfbEnm1 = psyOutChan->sfbEnergy[sfbGrp];
212b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
213956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if (sfb < (psyOutChan->maxSfbPerGroup-1))
214956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            sfbEnp1 = psyOutChan->sfbEnergy[sfbGrp+sfb+1];
215956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          else
216956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            sfbEnp1 = psyOutChan->sfbEnergy[sfbGrp+sfb];
217956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          avgEn = (sfbEnm1 + sfbEnp1) >> 1;
218b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          sfbEn = psyOutChan->sfbEnergy[sfbGrp+sfb];
219b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
220956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if (sfbEn > avgEn && avgEn > 0) {
221956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            Word32 tmpMinSnr;
222e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard            shift = norm_l(sfbEn);
223956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong			tmpMinSnr = Div_32(L_mpy_ls(avgEn, minSnrLimit) << shift, sfbEn << shift );
224b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard            tmpMinSnr = max(tmpMinSnr, HOLE_THR_LONG);
225956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            tmpMinSnr = max(tmpMinSnr, threshold);
226956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            *psfbMinSnr = min(*psfbMinSnr, tmpMinSnr);
227956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
228956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          /* valley ? */
229b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
230956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if ((sfbEn < (avgEn >> 1)) && (sfbEn > 0)) {
231956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            Word32 tmpMinSnr;
232b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard            Word32 minSnrEn = L_mpy_wx(avgEn, *psfbMinSnr);
233b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
234e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard            if(minSnrEn < sfbEn) {
235956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong			  shift = norm_l(sfbEn);
236956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              tmpMinSnr = Div_32( minSnrEn << shift, sfbEn<<shift);
237956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            }
238956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            else {
239b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard              tmpMinSnr = MAX_16;
240956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            }
241956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            tmpMinSnr = min(minSnrLimit, tmpMinSnr);
242956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
243956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            *psfbMinSnr =
244956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              (min((tmpMinSnr >>  2), mult(*psfbMinSnr, MIN_SNR_COEF)) << 2);
245e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard          }
246956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		  psfbMinSnr++;
247956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
248956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
249956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
250956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
251956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
252956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* stereo: adapt the minimum requirements sfbMinSnr of mid and
253956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong     side channels */
254b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
255956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (nChannels == 2) {
256956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChanM = &psyOutChannel[0];
257956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChanS = &psyOutChannel[1];
258956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (sfb=0; sfb<psyOutChanM->sfbCnt; sfb++) {
259956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if (psyOutElement->toolsInfo.msMask[sfb]) {
260956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        Word32 sfbEnM = psyOutChanM->sfbEnergy[sfb];
261956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        Word32 sfbEnS = psyOutChanS->sfbEnergy[sfb];
262956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        Word32 maxSfbEn = max(sfbEnM, sfbEnS);
263b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard        Word32 maxThr = L_mpy_wx(maxSfbEn, psyOutChanM->sfbMinSnr[sfb]) >> 1;
264b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
265956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if(maxThr >= sfbEnM) {
266b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          psyOutChanM->sfbMinSnr[sfb] = MAX_16;
267956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
268956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        else {
269b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          shift = norm_l(sfbEnM);
270b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard		  psyOutChanM->sfbMinSnr[sfb] = min(max(psyOutChanM->sfbMinSnr[sfb],
271956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong			  round16(Div_32(maxThr<<shift, sfbEnM << shift))), minSnrLimit);
272956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
273b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
274956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if(maxThr >= sfbEnS) {
275956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          psyOutChanS->sfbMinSnr[sfb] = MAX_16;
276956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
277e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard        else {
278956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		  shift = norm_l(sfbEnS);
279b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          psyOutChanS->sfbMinSnr[sfb] = min(max(psyOutChanS->sfbMinSnr[sfb],
280956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong			  round16(Div_32(maxThr << shift, sfbEnS << shift))), minSnrLimit);
281956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
282956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
283b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
284956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (sfbEnM > psyOutChanM->sfbSpreadedEnergy[sfb])
285956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          psyOutChanS->sfbSpreadedEnergy[sfb] = L_mpy_ls(sfbEnS, MS_THRSPREAD_COEF);
286b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
287956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (sfbEnS > psyOutChanS->sfbSpreadedEnergy[sfb])
288956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          psyOutChanM->sfbSpreadedEnergy[sfb] = L_mpy_ls(sfbEnM, MS_THRSPREAD_COEF);
289956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
290956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
291956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
292956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
293956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
294956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */
295956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for(ch=0; ch<nChannels; ch++) {
296956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
297956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
298e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard      Word16 *pahFlag = ahFlag[ch] + sfbGrp;
299956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
300b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
301956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if ((psyOutChan->sfbSpreadedEnergy[sfbGrp+sfb] > psyOutChan->sfbEnergy[sfbGrp+sfb]) ||
302956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            (psyOutChan->sfbEnergy[sfbGrp+sfb] <= psyOutChan->sfbThreshold[sfbGrp+sfb]) ||
303956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            (psyOutChan->sfbMinSnr[sfbGrp+sfb] == MAX_16)) {
304956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          *pahFlag++ = NO_AH;
305956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
306956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        else {
307956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          *pahFlag++ = AH_INACTIVE;
308956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
309956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
310956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for (sfb=psyOutChan->maxSfbPerGroup; sfb<psyOutChan->sfbPerGroup; sfb++) {
311b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard        *pahFlag++ = NO_AH;
312956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
313956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
314956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
315956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
316956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
317956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
318956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
319956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:calcPeNoAH
320956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: sum the pe data only for bands where avoid hole is inactive
321956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
322956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
323956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void calcPeNoAH(Word16          *pe,
324956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                       Word16          *constPart,
325956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                       Word16          *nActiveLines,
326956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                       PE_DATA         *peData,
327956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                       Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
328956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                       PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
329956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                       const Word16     nChannels)
330956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
331e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  Word16 ch, sfb, sfbGrp;
332956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  int ipe, iconstPart, inActiveLines;
333956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
334b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  ipe = 0;
335b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  iconstPart = 0;
336b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  inActiveLines = 0;
337956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for(ch=0; ch<nChannels; ch++) {
338956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
339956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PE_CHANNEL_DATA *peChanData = &peData->peChannelData[ch];
340956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
341956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
342b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
343956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (ahFlag[ch][sfbGrp+sfb] < AH_ACTIVE) {
344956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          ipe = ipe + peChanData->sfbPe[sfbGrp+sfb];
345956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          iconstPart = iconstPart + peChanData->sfbConstPart[sfbGrp+sfb];
346956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          inActiveLines = inActiveLines + peChanData->sfbNActiveLines[sfbGrp+sfb];
347956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
348956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
349956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
350e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  }
351956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
352b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  *pe = saturate(ipe);
353b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  *constPart = saturate(iconstPart);
354b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  *nActiveLines = saturate(inActiveLines);
355956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
356956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
357956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
358956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
359956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:reduceThresholds
360956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: apply reduction formula
361956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
362956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
363956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void reduceThresholds(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
364956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                             Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
365956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                             Word32           thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
366956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                             const Word16     nChannels,
367956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                             const Word32     redVal)
368956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
369956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 sfbThrReduced;
370b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  Word32 *psfbEn, *psfbThr;
371e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  Word16 ch, sfb, sfbGrp;
372956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
373956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for(ch=0; ch<nChannels; ch++) {
374956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
375956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for(sfbGrp=0; sfbGrp<psyOutChan->sfbCnt; sfbGrp+=psyOutChan->sfbPerGroup) {
376b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard 	  psfbEn  = psyOutChan->sfbEnergy + sfbGrp;
377e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard      psfbThr = psyOutChan->sfbThreshold + sfbGrp;
378956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
379b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
380956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (*psfbEn > *psfbThr) {
381956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          /* threshold reduction formula */
382956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          Word32 tmp = thrExp[ch][sfbGrp+sfb] + redVal;
383956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          tmp = fixmul(tmp, tmp);
384956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          sfbThrReduced = fixmul(tmp, tmp);
385956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          /* avoid holes */
386956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          tmp = L_mpy_ls(*psfbEn, psyOutChan->sfbMinSnr[sfbGrp+sfb]);
387b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
388b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          if ((sfbThrReduced > tmp) &&
389956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              (ahFlag[ch][sfbGrp+sfb] != NO_AH)){
390956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            sfbThrReduced = max(tmp, *psfbThr);
391b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard            ahFlag[ch][sfbGrp+sfb] = AH_ACTIVE;
392956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
393956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		  *psfbThr = sfbThrReduced;
394e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard        }
395e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard
396956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		psfbEn++;  psfbThr++;
397956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
398956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
399956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
400956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
401956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
402956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
403956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
404956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
405956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:correctThresh
406956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: if pe difference deltaPe between desired pe and real pe is small enough,
407956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*             the difference can be distributed among the scale factor bands.
408956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
409956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
410956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void correctThresh(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
411956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
412956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          PE_DATA          *peData,
413956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          Word32           thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
414956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word32     redVal,
415956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word16     nChannels,
416956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word32     deltaPe)
417956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
418956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 ch, sfb, sfbGrp,shift;
419956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  PSY_OUT_CHANNEL *psyOutChan;
420956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  PE_CHANNEL_DATA *peChanData;
421956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 deltaSfbPe;
422e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  Word32 normFactor;
423e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  Word32 *psfbPeFactors;
424956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 *psfbNActiveLines, *pahFlag;
425956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 sfbEn, sfbThr;
426956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 sfbThrReduced;
427956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
428956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* for each sfb calc relative factors for pe changes */
429b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  normFactor = 1;
430956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for(ch=0; ch<nChannels; ch++) {
431956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    psyOutChan = &psyOutChannel[ch];
432956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    peChanData = &peData->peChannelData[ch];
433956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
434e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard      psfbPeFactors = peData->sfbPeFactors[ch] + sfbGrp;
435e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	  psfbNActiveLines = peChanData->sfbNActiveLines + sfbGrp;
436e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	  pahFlag = ahFlag[ch] + sfbGrp;
437956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
438956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        Word32 redThrExp = thrExp[ch][sfbGrp+sfb] + redVal;
439b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
440956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (((*pahFlag < AH_ACTIVE) || (deltaPe > 0)) && (redThrExp > 0) ) {
441b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
442956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          *psfbPeFactors = (*psfbNActiveLines) * (0x7fffffff / redThrExp);
443956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          normFactor = L_add(normFactor, *psfbPeFactors);
444956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
445956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        else {
446b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          *psfbPeFactors = 0;
447e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard        }
448b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard		psfbPeFactors++;
449956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		pahFlag++; psfbNActiveLines++;
450956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
451956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
452956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
453956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
454b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
455956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* calculate new thresholds */
456956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for(ch=0; ch<nChannels; ch++) {
457956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    psyOutChan = &psyOutChannel[ch];
458956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    peChanData = &peData->peChannelData[ch];
459956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
460e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard      psfbPeFactors = peData->sfbPeFactors[ch] + sfbGrp;
461e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	  psfbNActiveLines = peChanData->sfbNActiveLines + sfbGrp;
462e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	  pahFlag = ahFlag[ch] + sfbGrp;
463956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
464956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        /* pe difference for this sfb */
465956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        deltaSfbPe = *psfbPeFactors * deltaPe;
466956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
467b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard		/* thr3(n) = thr2(n)*2^deltaSfbPe/b(n) */
46801e29ede19cd7d85bfef38896de8e71e569cd211Martin Storsjo        if (*psfbNActiveLines > 0 && (normFactor* (*psfbNActiveLines)) != 0) {
469956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          /* new threshold */
470956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          Word32 thrFactor;
471956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          sfbEn  = psyOutChan->sfbEnergy[sfbGrp+sfb];
472956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          sfbThr = psyOutChan->sfbThreshold[sfbGrp+sfb];
473956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
474956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong           if(deltaSfbPe >= 0){
475956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            /*
476956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              reduce threshold
477956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            */
478956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            thrFactor = pow2_xy(L_negate(deltaSfbPe), (normFactor* (*psfbNActiveLines)));
479b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
480956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            sfbThrReduced = L_mpy_ls(sfbThr, round16(thrFactor));
481956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
482956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          else {
483956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            /*
484956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              increase threshold
485956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            */
486956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            thrFactor = pow2_xy(deltaSfbPe, (normFactor * (*psfbNActiveLines)));
487b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
488b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
489956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            if(thrFactor > sfbThr) {
490e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard              shift = norm_l(thrFactor);
491956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong			  sfbThrReduced = Div_32( sfbThr << shift, thrFactor<<shift );
492956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            }
493956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            else {
494b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard              sfbThrReduced = MAX_32;
495956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            }
496956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
497956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
498b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
499956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          /* avoid hole */
500956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          sfbEn = L_mpy_ls(sfbEn, psyOutChan->sfbMinSnr[sfbGrp+sfb]);
501b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
502956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if ((sfbThrReduced > sfbEn) &&
503956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              (*pahFlag == AH_INACTIVE)) {
504956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            sfbThrReduced = max(sfbEn, sfbThr);
505b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard            *pahFlag = AH_ACTIVE;
506956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
507956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
508b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          psyOutChan->sfbThreshold[sfbGrp+sfb] = sfbThrReduced;
509e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard        }
510e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard
511956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		pahFlag++; psfbNActiveLines++; psfbPeFactors++;
512956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
513956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
514956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
515956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
516956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
517956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
518956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
519956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
520956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:reduceMinSnr
521956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: if the desired pe can not be reached, reduce pe by reducing minSnr
522956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
523956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
524b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgardstatic void reduceMinSnr(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
525b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard                         PE_DATA         *peData,
526956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                         Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
527956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                         const Word16     nChannels,
528956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                         const Word16     desiredPe)
529956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
530956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 ch, sfb, sfbSubWin;
531956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 deltaPe;
532956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
533956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* start at highest freq down to 0 */
534b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  sfbSubWin = psyOutChannel[0].maxSfbPerGroup;
535956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  while (peData->pe > desiredPe && sfbSubWin > 0) {
536b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
537956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    sfbSubWin = sfbSubWin - 1;
538956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* loop over all subwindows */
539956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (sfb=sfbSubWin; sfb<psyOutChannel[0].sfbCnt;
540956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        sfb+=psyOutChannel[0].sfbPerGroup) {
541956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      /* loop over all channels */
542e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard		PE_CHANNEL_DATA* peChan = peData->peChannelData;
543e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard		PSY_OUT_CHANNEL* psyOutCh = psyOutChannel;
544b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard		for (ch=0; ch<nChannels; ch++) {
545956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (ahFlag[ch][sfb] != NO_AH &&
546956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            psyOutCh->sfbMinSnr[sfb] < minSnrLimit) {
547b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          psyOutCh->sfbMinSnr[sfb] = minSnrLimit;
548956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          psyOutCh->sfbThreshold[sfb] =
549956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            L_mpy_ls(psyOutCh->sfbEnergy[sfb], psyOutCh->sfbMinSnr[sfb]);
550956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
551956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          /* calc new pe */
552956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          deltaPe = ((peChan->sfbNLines4[sfb] + (peChan->sfbNLines4[sfb] >> 1)) >> 2) -
553956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              peChan->sfbPe[sfb];
554956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          peData->pe = peData->pe + deltaPe;
555b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          peChan->pe = peChan->pe + deltaPe;
556e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard        }
557956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		peChan += 1; psyOutCh += 1;
558956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
559956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      /* stop if enough has been saved */
560b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
561956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if (peData->pe <= desiredPe)
562956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        break;
563956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
564956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
565956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
566956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
567956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
568956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
569956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:allowMoreHoles
570b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard* description: if the desired pe can not be reached, some more scalefactor bands
571956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*              have to be quantized to zero
572956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
573956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
574b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgardstatic void allowMoreHoles(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
575956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           PSY_OUT_ELEMENT *psyOutElement,
576b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard                           PE_DATA         *peData,
577956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
578956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           const AH_PARAM  *ahParam,
579956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           const Word16     nChannels,
580956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           const Word16     desiredPe)
581956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
582956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 ch, sfb;
583956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 actPe, shift;
584956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
585b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  actPe = peData->pe;
586956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
587956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* for MS allow hole in the channel with less energy */
588b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
589956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (nChannels==2 &&
590956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      psyOutChannel[0].windowSequence==psyOutChannel[1].windowSequence) {
591956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChanL = &psyOutChannel[0];
592956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChanR = &psyOutChannel[1];
593956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (sfb=0; sfb<psyOutChanL->sfbCnt; sfb++) {
594956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      Word32 minEn;
595b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
596956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if (psyOutElement->toolsInfo.msMask[sfb]) {
597956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        /* allow hole in side channel ? */
598956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        minEn = L_mpy_ls(psyOutChanL->sfbEnergy[sfb], (minSnrLimit * psyOutChanL->sfbMinSnr[sfb]) >> 16);
599b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
600956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (ahFlag[1][sfb] != NO_AH &&
601956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            minEn > psyOutChanR->sfbEnergy[sfb]) {
602b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          ahFlag[1][sfb] = NO_AH;
603956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          psyOutChanR->sfbThreshold[sfb] = L_add(psyOutChanR->sfbEnergy[sfb], psyOutChanR->sfbEnergy[sfb]);
604956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          actPe = actPe - peData->peChannelData[1].sfbPe[sfb];
605956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
606956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        /* allow hole in mid channel ? */
607956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        else {
608956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        minEn = L_mpy_ls(psyOutChanR->sfbEnergy[sfb], (minSnrLimit * psyOutChanR->sfbMinSnr[sfb]) >> 16);
609b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
610956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if (ahFlag[0][sfb]!= NO_AH &&
611956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              minEn > psyOutChanL->sfbEnergy[sfb]) {
612b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard            ahFlag[0][sfb] = NO_AH;
613956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            psyOutChanL->sfbThreshold[sfb] = L_add(psyOutChanL->sfbEnergy[sfb], psyOutChanL->sfbEnergy[sfb]);
614956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            actPe = actPe - peData->peChannelData[0].sfbPe[sfb];
615956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
616956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
617b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
618956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (actPe < desiredPe)
619956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          break;
620956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
621956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
622956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
623956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
624b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  /* subsequently erase bands */
625956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (actPe > desiredPe) {
626956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 startSfb[2];
627956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word32 avgEn, minEn;
628956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 ahCnt;
629956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 enIdx;
630956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 enDiff;
631956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word32 en[4];
632956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 minSfb, maxSfb;
633956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Flag   done;
634956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
635956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* do not go below startSfb */
636956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (ch=0; ch<nChannels; ch++) {
637b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
638956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if (psyOutChannel[ch].windowSequence != SHORT_WINDOW)
639956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        startSfb[ch] = ahParam->startSfbL;
640956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      else
641956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        startSfb[ch] = ahParam->startSfbS;
642956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
643956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
644b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    avgEn = 0;
645b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    minEn = MAX_32;
646b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    ahCnt = 0;
647956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (ch=0; ch<nChannels; ch++) {
648956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
649956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for (sfb=startSfb[ch]; sfb<psyOutChan->sfbCnt; sfb++) {
650b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
651956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if ((ahFlag[ch][sfb] != NO_AH) &&
652956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            (psyOutChan->sfbEnergy[sfb] > psyOutChan->sfbThreshold[sfb])) {
653956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          minEn = min(minEn, psyOutChan->sfbEnergy[sfb]);
654956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          avgEn = L_add(avgEn, psyOutChan->sfbEnergy[sfb]);
655956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          ahCnt++;
656956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
657956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
658956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
659b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
660956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if(ahCnt) {
661956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      Word32 iahCnt;
662e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard      shift = norm_l(ahCnt);
663956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	  iahCnt = Div_32( 1 << shift, ahCnt << shift );
664956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      avgEn = fixmul(avgEn, iahCnt);
665956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
666956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
667956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    enDiff = iLog4(avgEn) - iLog4(minEn);
668956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* calc some energy borders between minEn and avgEn */
669956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (enIdx=0; enIdx<4; enIdx++) {
670956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      Word32 enFac;
671956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      enFac = ((6-(enIdx << 1)) * enDiff);
672956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      en[enIdx] = fixmul(avgEn, pow2_xy(L_negate(enFac),7*4));
673956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
674956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
675956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* start with lowest energy border at highest sfb */
676956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    maxSfb = psyOutChannel[0].sfbCnt - 1;
677b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    minSfb = startSfb[0];
678b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
679956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if (nChannels == 2) {
680956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      maxSfb = max(maxSfb, (psyOutChannel[1].sfbCnt - 1));
681956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      minSfb = min(minSfb, startSfb[1]);
682956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
683956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
684b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    sfb = maxSfb;
685b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    enIdx = 0;
686b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    done = 0;
687956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    while (!done) {
688b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
689956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for (ch=0; ch<nChannels; ch++) {
690956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
691b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
692956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (sfb>=startSfb[ch] && sfb<psyOutChan->sfbCnt) {
693956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          /* sfb energy below border ? */
694b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
695956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if (ahFlag[ch][sfb] != NO_AH && psyOutChan->sfbEnergy[sfb] < en[enIdx]){
696956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            /* allow hole */
697b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard            ahFlag[ch][sfb] = NO_AH;
698956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            psyOutChan->sfbThreshold[sfb] = L_add(psyOutChan->sfbEnergy[sfb], psyOutChan->sfbEnergy[sfb]);
699956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            actPe = actPe - peData->peChannelData[ch].sfbPe[sfb];
700956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
701b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
702956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if (actPe < desiredPe) {
703b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard            done = 1;
704956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            break;
705956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
706956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
707956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
708956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      sfb = sfb - 1;
709b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
710956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if (sfb < minSfb) {
711956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        /* restart with next energy border */
712b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard        sfb = maxSfb;
713956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        enIdx = enIdx + 1;
714b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
715956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (enIdx - 4 >= 0)
716b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          done = 1;
717956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
718956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
719956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
720956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
721956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
722956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
723956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
724956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:adaptThresholdsToPe
725956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: two guesses for the reduction value and one final correction of the
726956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*              thresholds
727956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
728956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
729956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void adaptThresholdsToPe(PSY_OUT_CHANNEL     psyOutChannel[MAX_CHANNELS],
730956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                PSY_OUT_ELEMENT    *psyOutElement,
731956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                Word16              logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
732956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                PE_DATA            *peData,
733956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                const Word16        nChannels,
734956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                const Word16        desiredPe,
735956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                AH_PARAM           *ahParam,
736956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                MINSNR_ADAPT_PARAM *msaParam)
737956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
738956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 noRedPe, redPe, redPeNoAH;
739956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 constPart, constPartNoAH;
740956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 nActiveLines, nActiveLinesNoAH;
741956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 desiredPeNoAH;
742956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 redVal, avgThrExp;
743956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 iter;
744956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
745956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  calcThreshExp(peData->thrExp, psyOutChannel, nChannels);
746956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
747956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  adaptMinSnr(psyOutChannel, logSfbEnergy, msaParam, nChannels);
748956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
749956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  initAvoidHoleFlag(peData->ahFlag, psyOutChannel, psyOutElement, nChannels, ahParam);
750956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
751b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  noRedPe = peData->pe;
752b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  constPart = peData->constPart;
753b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  nActiveLines = peData->nActiveLines;
754956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
755956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* first guess of reduction value t^0.25 = 2^((a-pen)/4*b) */
756956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  avgThrExp = pow2_xy((constPart - noRedPe), (nActiveLines << 2));
757b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
758956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* r1 = 2^((a-per)/4*b) - t^0.25 */
759956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  redVal = pow2_xy((constPart - desiredPe), (nActiveLines << 2)) - avgThrExp;
760956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
761956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* reduce thresholds */
762956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  reduceThresholds(psyOutChannel, peData->ahFlag, peData->thrExp, nChannels, redVal);
763956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
764956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* pe after first guess */
765956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  calcSfbPe(peData, psyOutChannel, nChannels);
766b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  redPe = peData->pe;
767956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
768b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  iter = 0;
769956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  do {
770956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* pe for bands where avoid hole is inactive */
771956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    calcPeNoAH(&redPeNoAH, &constPartNoAH, &nActiveLinesNoAH,
772956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong               peData, peData->ahFlag, psyOutChannel, nChannels);
773956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
774956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    desiredPeNoAH = desiredPe -(redPe - redPeNoAH);
775b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
776956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if (desiredPeNoAH < 0) {
777b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard      desiredPeNoAH = 0;
778956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
779956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
780956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* second guess */
781b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
782956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if (nActiveLinesNoAH > 0) {
783b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
784956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		avgThrExp = pow2_xy((constPartNoAH - redPeNoAH), (nActiveLinesNoAH << 2));
785b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
786956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		redVal = (redVal + pow2_xy((constPartNoAH - desiredPeNoAH), (nActiveLinesNoAH << 2))) - avgThrExp;
787b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
788956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		/* reduce thresholds */
789956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		reduceThresholds(psyOutChannel, peData->ahFlag, peData->thrExp, nChannels, redVal);
790956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
791956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
792956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    calcSfbPe(peData, psyOutChannel, nChannels);
793b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    redPe = peData->pe;
794956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
795956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    iter = iter+1;
796b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
797956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  } while ((20 * abs_s(redPe - desiredPe) > desiredPe) && (iter < 2));
798956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
799b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
800956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if ((100 * redPe < 115 * desiredPe)) {
801956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    correctThresh(psyOutChannel, peData->ahFlag, peData, peData->thrExp, redVal,
802956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                  nChannels, desiredPe - redPe);
803956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
804956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  else {
805956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 desiredPe105 = (105 * desiredPe) / 100;
806956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    reduceMinSnr(psyOutChannel, peData, peData->ahFlag,
807956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                 nChannels, desiredPe105);
808956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    allowMoreHoles(psyOutChannel, psyOutElement, peData, peData->ahFlag,
809956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                   ahParam, nChannels, desiredPe105);
810956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
811956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
812956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
813956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
814956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/*****************************************************************************
815956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
816956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: calcBitSave
817956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  Calculates percentage of bit save, see figure below
818956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* returns:
819956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* input:        parameters and bitres-fullness
820956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* output:       percentage of bit save
821956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
822956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*****************************************************************************/
823956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic Word16 calcBitSave(Word16 fillLevel,
824956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word16 clipLow,
825956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word16 clipHigh,
826956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word16 minBitSave,
827956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word16 maxBitSave)
828956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
829956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 bitsave = 0;
830956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
831956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  fillLevel = max(fillLevel, clipLow);
832956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  fillLevel = min(fillLevel, clipHigh);
833956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
834e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  if(clipHigh-clipLow)
835956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  bitsave = (maxBitSave - (((maxBitSave-minBitSave)*(fillLevel-clipLow))/
836956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                              (clipHigh-clipLow)));
837956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
838956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  return (bitsave);
839956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
840956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
841956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
842956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
843956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/*****************************************************************************
844956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
845956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: calcBitSpend
846956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  Calculates percentage of bit spend, see figure below
847956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* returns:
848956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* input:        parameters and bitres-fullness
849956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* output:       percentage of bit spend
850956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
851956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*****************************************************************************/
852956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic Word16 calcBitSpend(Word16 fillLevel,
853956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           const Word16 clipLow,
854956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           const Word16 clipHigh,
855956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           const Word16 minBitSpend,
856956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           const Word16 maxBitSpend)
857956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
858956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 bitspend = 1;
859956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
860956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  fillLevel = max(fillLevel, clipLow);
861956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  fillLevel = min(fillLevel, clipHigh);
862956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
863e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  if(clipHigh-clipLow)
864956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  bitspend = (minBitSpend + ((maxBitSpend - minBitSpend)*(fillLevel - clipLow) /
865956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                (clipHigh-clipLow)));
866b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
867956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  return (bitspend);
868956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
869956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
870956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
871956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/*****************************************************************************
872956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
873956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: adjustPeMinMax()
874956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  adjusts peMin and peMax parameters over time
875956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* returns:
876956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* input:        current pe, peMin, peMax
877956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* output:       adjusted peMin/peMax
878956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
879956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*****************************************************************************/
880956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void adjustPeMinMax(const Word16 currPe,
881956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           Word16      *peMin,
882956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           Word16      *peMax)
883956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
884956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 minFacHi, maxFacHi, minFacLo, maxFacLo;
885956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 diff;
886956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 minDiff = extract_l(currPe / 6);
887b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  minFacHi = 30;
888b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  maxFacHi = 100;
889b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  minFacLo = 14;
890b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  maxFacLo = 7;
891956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
892956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  diff = currPe - *peMax ;
893b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
894956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (diff > 0) {
895956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    *peMin = *peMin + ((diff * minFacHi) / 100);
896956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    *peMax = *peMax + ((diff * maxFacHi) / 100);
897956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  } else {
898956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    diff = *peMin - currPe;
899b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
900956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if (diff > 0) {
901956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      *peMin = *peMin - ((diff * minFacLo) / 100);
902956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      *peMax = *peMax - ((diff * maxFacLo) / 100);
903956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    } else {
904956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      *peMin = *peMin + ((currPe - *peMin) * minFacHi / 100);
905956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      *peMax = *peMax - ((*peMax - currPe) * maxFacLo / 100);
906956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
907956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
908956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
909b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
910956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if ((*peMax - *peMin) < minDiff) {
911956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 partLo, partHi;
912956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
913956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    partLo = max(0, (currPe - *peMin));
914956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    partHi = max(0, (*peMax - currPe));
915956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
916956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    *peMax = currPe + ((partHi * minDiff) / (partLo + partHi));
917956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    *peMin = currPe - ((partLo * minDiff) / (partLo + partHi));
918956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    *peMin = max(0, *peMin);
919956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
920956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
921956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
922956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
923956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/*****************************************************************************
924956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
925956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: BitresCalcBitFac
926956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  calculates factor of spending bits for one frame
927956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*                1.0 : take all frame dynpart bits
928956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*                >1.0 : take all frame dynpart bits + bitres
929956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*                <1.0 : put bits in bitreservoir
930956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*  returns:      BitFac*100
931956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*  input:        bitres-fullness, pe, blockType, parameter-settings
932956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*  output:
933956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
934956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*****************************************************************************/
935956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic Word16 bitresCalcBitFac( const Word16   bitresBits,
936956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                const Word16   maxBitresBits,
937956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                const Word16   pe,
938956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                const Word16   windowSequence,
939956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                const Word16   avgBits,
940956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                const Word16   maxBitFac,
941956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                ADJ_THR_STATE *AdjThr,
942956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                ATS_ELEMENT   *adjThrChan)
943956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
944956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  BRES_PARAM *bresParam;
945956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 pex;
946956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 fillLevel;
947956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 bitSave, bitSpend, bitresFac;
948956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
949956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  fillLevel = extract_l((100* bitresBits) / maxBitresBits);
950956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
951956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (windowSequence != SHORT_WINDOW)
952956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    bresParam = &(AdjThr->bresParamLong);
953956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  else
954956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    bresParam = &(AdjThr->bresParamShort);
955956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
956956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  pex = max(pe, adjThrChan->peMin);
957956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  pex = min(pex,adjThrChan->peMax);
958956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
959956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  bitSave = calcBitSave(fillLevel,
960956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        bresParam->clipSaveLow, bresParam->clipSaveHigh,
961956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        bresParam->minBitSave, bresParam->maxBitSave);
962956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
963956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  bitSpend = calcBitSpend(fillLevel,
964956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          bresParam->clipSpendLow, bresParam->clipSpendHigh,
965956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          bresParam->minBitSpend, bresParam->maxBitSpend);
966956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
967e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  if(adjThrChan->peMax != adjThrChan->peMin)
968956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	bitresFac = (100 - bitSave) + extract_l(((bitSpend + bitSave) * (pex - adjThrChan->peMin)) /
969956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                    (adjThrChan->peMax - adjThrChan->peMin));
970956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  else
971956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	bitresFac = 0x7fff;
972b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
973956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  bitresFac = min(bitresFac,
974956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                    (100-30 + extract_l((100 * bitresBits) / avgBits)));
975956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
976956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  bitresFac = min(bitresFac, maxBitFac);
977956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
978956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  adjustPeMinMax(pe, &adjThrChan->peMin, &adjThrChan->peMax);
979956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
980956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  return bitresFac;
981956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
982956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
983956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/*****************************************************************************
984956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
985956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: AdjThrInit
986956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  init thresholds parameter
987956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
988956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*****************************************************************************/
989956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongvoid AdjThrInit(ADJ_THR_STATE *hAdjThr,
990956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                const Word32   meanPe,
991956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                Word32         chBitrate)
992956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
993956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  ATS_ELEMENT* atsElem = &hAdjThr->adjThrStateElem;
994956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  MINSNR_ADAPT_PARAM *msaParam = &atsElem->minSnrAdaptParam;
995956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
996956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* common for all elements: */
997956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* parameters for bitres control */
998b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.clipSaveLow   =  20;
999b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.clipSaveHigh  =  95;
1000b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.minBitSave    =  -5;
1001b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.maxBitSave    =  30;
1002b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.clipSpendLow  =  20;
1003b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.clipSpendHigh =  95;
1004b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.minBitSpend   = -10;
1005b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.maxBitSpend   =  40;
1006b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1007b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.clipSaveLow   =  20;
1008b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.clipSaveHigh  =  75;
1009b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.minBitSave    =   0;
1010b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.maxBitSave    =  20;
1011b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.clipSpendLow  =  20;
1012b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.clipSpendHigh =  75;
1013b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.minBitSpend   = -5;
1014b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.maxBitSpend   =  50;
1015956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1016956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* specific for each element: */
1017956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1018956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* parameters for bitres control */
1019956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  atsElem->peMin = extract_l(((80*meanPe) / 100));
1020956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  atsElem->peMax = extract_l(((120*meanPe) / 100));
1021956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1022956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* additional pe offset to correct pe2bits for low bitrates */
1023b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  atsElem->peOffset = 0;
1024956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (chBitrate < 32000) {
1025956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    atsElem->peOffset = max(50, (100 - extract_l((100 * chBitrate) / 32000)));
1026956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1027956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1028956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* avoid hole parameters */
1029956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (chBitrate > 20000) {
1030956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    atsElem->ahParam.modifyMinSnr = TRUE;
1031956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    atsElem->ahParam.startSfbL = 15;
1032956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    atsElem->ahParam.startSfbS = 3;
1033956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1034956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  else {
1035956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    atsElem->ahParam.modifyMinSnr = FALSE;
1036956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    atsElem->ahParam.startSfbL = 0;
1037956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    atsElem->ahParam.startSfbS = 0;
1038956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1039956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1040956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* minSnr adaptation */
1041956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* maximum reduction of minSnr goes down to minSnr^maxRed */
104260866592ed6953f2b0e12cefcd58f1ced26546d0Martin Storsjo  msaParam->maxRed = 0x20000000;     /* *0.25f */
1043956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* start adaptation of minSnr for avgEn/sfbEn > startRatio */
1044b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  msaParam->startRatio = 0x0ccccccd; /* 10 */
1045956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* maximum minSnr reduction to minSnr^maxRed is reached for
1046956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong     avgEn/sfbEn >= maxRatio */
1047b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  msaParam->maxRatio =  0x0020c49c; /* 1000 */
1048956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* helper variables to interpolate minSnr reduction for
1049956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong     avgEn/sfbEn between startRatio and maxRatio */
1050956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1051b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  msaParam->redRatioFac = 0xfb333333; /* -0.75/20 */
1052b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1053b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  msaParam->redOffs = 0x30000000;  /* msaParam->redRatioFac * 10*log10(msaParam->startRatio) */
1054956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1055956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1056956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* pe correction */
1057b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  atsElem->peLast = 0;
1058b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  atsElem->dynBitsLast = 0;
1059b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  atsElem->peCorrectionFactor = 100; /* 1.0 */
1060956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1061956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
1062956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1063956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/*****************************************************************************
1064956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
1065956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: calcPeCorrection
1066956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  calculates the desired perceptual entropy factor
1067956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*				It is between 0.85 and 1.15
1068956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
1069956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*****************************************************************************/
1070956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void calcPeCorrection(Word16 *correctionFac,
1071956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                             const Word16 peAct,
1072b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard                             const Word16 peLast,
1073b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard                             const Word16 bitsLast)
1074956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
1075956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 peAct100 = 100 * peAct;
1076956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 peLast100 = 100 * peLast;
1077956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 peBitsLast = bits2pe(bitsLast);
1078b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1079956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if ((bitsLast > 0) &&
1080956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      (peAct100 < (150 * peLast)) &&  (peAct100 > (70 * peLast)) &&
1081956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      ((120 * peBitsLast) > peLast100 ) && (( 65 * peBitsLast) < peLast100))
1082956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    {
1083956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      Word16 newFac = (100 * peLast) / peBitsLast;
1084956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      /* dead zone */
1085b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1086956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if (newFac < 100) {
1087956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        newFac = min(((110 * newFac) / 100), 100);
1088956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        newFac = max(newFac, 85);
1089956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
1090956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      else {
1091956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        newFac = max(((90 * newFac) / 100), 100);
1092956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        newFac = min(newFac, 115);
1093956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
1094b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1095956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if ((newFac > 100 && *correctionFac < 100) ||
1096956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          (newFac < 100 && *correctionFac > 100)) {
1097b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard        *correctionFac = 100;
1098956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
1099956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      /* faster adaptation towards 1.0, slower in the other direction */
1100b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1101956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if ((*correctionFac < 100 && newFac < *correctionFac) ||
1102956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          (*correctionFac > 100 && newFac > *correctionFac))
1103956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        *correctionFac = (85 * *correctionFac + 15 * newFac) / 100;
1104956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      else
1105956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        *correctionFac = (70 * *correctionFac + 30 * newFac) / 100;
1106956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      *correctionFac = min(*correctionFac, 115);
1107956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      *correctionFac = max(*correctionFac, 85);
1108956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
1109956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  else {
1110b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    *correctionFac = 100;
1111956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1112956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
1113956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1114956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
1115956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
1116956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: AdjustThresholds
1117956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  Adjust thresholds to the desired bitrate
1118956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
1119956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
1120956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongvoid AdjustThresholds(ADJ_THR_STATE   *adjThrState,
1121956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                      ATS_ELEMENT     *AdjThrStateElement,
1122956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                      PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
1123956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                      PSY_OUT_ELEMENT *psyOutElement,
1124956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                      Word16          *chBitDistribution,
1125956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                      Word16           logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
1126b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard                      Word16           sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB],
1127956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                      QC_OUT_ELEMENT  *qcOE,
1128956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong					  ELEMENT_BITS	  *elBits,
1129956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong					  const Word16     nChannels,
1130956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                      const Word16     maxBitFac)
1131956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
1132b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  PE_DATA peData;
1133956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 noRedPe, grantedPe, grantedPeCorr;
1134956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 curWindowSequence;
1135956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 bitFactor;
1136956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 avgBits = (elBits->averageBits - (qcOE->staticBitsUsed + qcOE->ancBitsUsed));
1137b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  Word16 bitresBits = elBits->bitResLevel;
1138956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 maxBitresBits = elBits->maxBits;
1139956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 sideInfoBits = (qcOE->staticBitsUsed + qcOE->ancBitsUsed);
1140956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 ch;
1141b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1142956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  prepareSfbPe(&peData, psyOutChannel, logSfbEnergy, sfbNRelevantLines, nChannels, AdjThrStateElement->peOffset);
1143b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1144956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* pe without reduction */
1145956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  calcSfbPe(&peData, psyOutChannel, nChannels);
1146b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  noRedPe = peData.pe;
1147956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1148956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1149b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  curWindowSequence = LONG_WINDOW;
1150b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1151956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (nChannels == 2) {
1152b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1153956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if ((psyOutChannel[0].windowSequence == SHORT_WINDOW) ||
1154956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        (psyOutChannel[1].windowSequence == SHORT_WINDOW)) {
1155b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard      curWindowSequence = SHORT_WINDOW;
1156956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
1157956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1158956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  else {
1159b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    curWindowSequence = psyOutChannel[0].windowSequence;
1160956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1161956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1162956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1163956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* bit factor */
1164956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  bitFactor = bitresCalcBitFac(bitresBits, maxBitresBits, noRedPe+5*sideInfoBits,
1165956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                               curWindowSequence, avgBits, maxBitFac,
1166956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                               adjThrState,
1167956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                               AdjThrStateElement);
1168956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1169956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* desired pe */
1170956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  grantedPe = ((bitFactor * bits2pe(avgBits)) / 100);
1171956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1172956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* correction of pe value */
1173b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  calcPeCorrection(&(AdjThrStateElement->peCorrectionFactor),
1174956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                   min(grantedPe, noRedPe),
1175b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard                   AdjThrStateElement->peLast,
1176956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                   AdjThrStateElement->dynBitsLast);
1177956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  grantedPeCorr = (grantedPe * AdjThrStateElement->peCorrectionFactor) / 100;
1178956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1179b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1180956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (grantedPeCorr < noRedPe && noRedPe > peData.offset) {
1181956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* calc threshold necessary for desired pe */
1182956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    adaptThresholdsToPe(psyOutChannel,
1183956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        psyOutElement,
1184956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        logSfbEnergy,
1185956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        &peData,
1186956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        nChannels,
1187956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        grantedPeCorr,
1188956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        &AdjThrStateElement->ahParam,
1189956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        &AdjThrStateElement->minSnrAdaptParam);
1190956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1191956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1192956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* calculate relative distribution */
1193956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for (ch=0; ch<nChannels; ch++) {
1194956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 peOffsDiff = peData.pe - peData.offset;
1195b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    chBitDistribution[ch] = 200;
1196b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1197956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if (peOffsDiff > 0) {
1198956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      Word32 temp = 1000 - (nChannels * 200);
1199e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard      chBitDistribution[ch] = chBitDistribution[ch] +
1200956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		  (temp * peData.peChannelData[ch].pe) / peOffsDiff;
1201956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
1202956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1203956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1204956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* store pe */
1205b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  qcOE->pe = noRedPe;
1206956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1207956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* update last pe */
1208b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  AdjThrStateElement->peLast = grantedPe;
1209956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
1210956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1211956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
1212956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
1213956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: AdjThrUpdate
1214956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  save dynBitsUsed for correction of bits2pe relation
1215956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
1216956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
1217956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongvoid AdjThrUpdate(ATS_ELEMENT *AdjThrStateElement,
1218956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                  const Word16 dynBitsUsed)
1219956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
1220b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  AdjThrStateElement->dynBitsLast = dynBitsUsed;
1221956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
1222956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1223956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1224