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
23b5325c8a8fff4d735c24d9a8138e4213ee0833d5Martin Storsjo/* Include system headers before local headers - the local headers
24b5325c8a8fff4d735c24d9a8138e4213ee0833d5Martin Storsjo * redefine __inline, which can mess up definitions in libc headers if
25b5325c8a8fff4d735c24d9a8138e4213ee0833d5Martin Storsjo * they happen to use __inline. */
26b5325c8a8fff4d735c24d9a8138e4213ee0833d5Martin Storsjo#include <string.h>
27e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard#include "basic_op.h"
28956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong#include "oper_32b.h"
29956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong#include "adj_thr_data.h"
30956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong#include "adj_thr.h"
31956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong#include "qc_data.h"
32956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong#include "line_pe.h"
33956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
34956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
35956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong#define  minSnrLimit    0x6666 /* 1 dB */
36e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard#define  PEBITS_COEF	0x170a /* 0.18*(1 << 15)*/
37e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard
38e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard#define  HOLE_THR_LONG	0x2873	/* 0.316*(1 << 15) */
39e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard#define  HOLE_THR_SHORT 0x4000  /* 0.5  *(1 << 15) */
40e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard
41e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard#define  MS_THRSPREAD_COEF 0x7333  /* 0.9 * (1 << 15) */
42e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard
43e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard#define	 MIN_SNR_COEF	   0x651f  /* 3.16* (1 << (15 - 2)) */
44956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
45956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/* values for avoid hole flag */
46956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongenum _avoid_hole_state {
47956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  NO_AH              =0,
48956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  AH_INACTIVE        =1,
49956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  AH_ACTIVE          =2
50956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong};
51956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
52956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
53956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
54956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:bits2pe
55956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: convert from bits to pe
56956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*			   pe = 1.18*desiredBits
57956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
58956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
59956c553ab0ce72f8074ad0fda2ffd66a0305700cJames DongWord16 bits2pe(const Word16 bits) {
60956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  return (bits + ((PEBITS_COEF * bits) >> 15));
61956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
62956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
63956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
64956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
65956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:calcThreshExp
66956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: loudness calculation (threshold to the power of redExp)
67956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*			   thr(n)^0.25
68956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
69956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
70956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void calcThreshExp(Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
71956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
72956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word16 nChannels)
73956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
74e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  Word16 ch, sfb, sfbGrp;
75d411b4ca2945cd8974a3a78199fce94646950128Andreas Huber  Word32 *pthrExp = NULL, *psfbThre;
76956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for (ch=0; ch<nChannels; ch++) {
77e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard    PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
78b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard	 for(sfbGrp = 0; sfbGrp < psyOutChan->sfbCnt; sfbGrp+= psyOutChan->sfbPerGroup)
79e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	  pthrExp = &(thrExp[ch][sfbGrp]);
80e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	  psfbThre = psyOutChan->sfbThreshold + sfbGrp;
81956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
82e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard		*pthrExp = rsqrt(rsqrt(*psfbThre,INT_BITS),INT_BITS);
83956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		pthrExp++; psfbThre++;
84956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
85956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
86956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
87956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
88956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
89956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
90956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:adaptMinSnr
91956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: reduce minSnr requirements for bands with relative low energies
92956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
93956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
94956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void adaptMinSnr(PSY_OUT_CHANNEL     psyOutChannel[MAX_CHANNELS],
95956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        Word16              logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
96956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        MINSNR_ADAPT_PARAM *msaParam,
97956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        const Word16        nChannels)
98956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
99b3f9759c8c9437c45b9a34519ce2ea38a8314d4eAndreas Gampe  Word16 ch, sfb, sfbOffs;
100956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 nSfb, avgEn;
101956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 log_avgEn = 0;
102956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 startRatio_x_avgEn = 0;
103b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
104956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
105956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for (ch=0; ch<nChannels; ch++) {
106956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL* psyOutChan = &psyOutChannel[ch];
107956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
108956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* calc average energy per scalefactor band */
109b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    avgEn = 0;
110b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    nSfb = 0;
111956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (sfbOffs=0; sfbOffs<psyOutChan->sfbCnt; sfbOffs+=psyOutChan->sfbPerGroup) {
112956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
113956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        avgEn = L_add(avgEn, psyOutChan->sfbEnergy[sfbOffs+sfb]);
114956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        nSfb = nSfb + 1;
115956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
116956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
117b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
118956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if (nSfb > 0) {
119e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	  avgEn = avgEn / nSfb;
120956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
121956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      log_avgEn = iLog4(avgEn);
122956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      startRatio_x_avgEn = fixmul(msaParam->startRatio, avgEn);
123956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
124956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
125b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
126956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* reduce minSnr requirement by minSnr^minSnrRed dependent on avgEn/sfbEn */
127956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (sfbOffs=0; sfbOffs<psyOutChan->sfbCnt; sfbOffs+=psyOutChan->sfbPerGroup) {
128956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
129956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (psyOutChan->sfbEnergy[sfbOffs+sfb] < startRatio_x_avgEn) {
130956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          Word16 dbRatio, minSnrRed;
131956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          Word32 snrRed;
132956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          Word16 newMinSnr;
133b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
134956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          dbRatio = log_avgEn - logSfbEnergy[ch][sfbOffs+sfb];
135956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          dbRatio = dbRatio + (dbRatio << 1);
136956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
137956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          minSnrRed = 110 - ((dbRatio + (dbRatio << 1)) >> 2);
138b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          minSnrRed = max(minSnrRed, 20); /* 110: (0.375(redOffs)+1)*80,
139956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                               3: 0.00375(redRatioFac)*80
140956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                               20: 0.25(maxRed) * 80 */
141956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
142b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          snrRed = minSnrRed * iLog4((psyOutChan->sfbMinSnr[sfbOffs+sfb] << 16));
143b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          /*
144956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong             snrRedI si now scaled by 80 (minSnrRed) and 4 (ffr_iLog4)
145956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          */
146b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
147956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          newMinSnr = round16(pow2_xy(snrRed,80*4));
148b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
149956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          psyOutChan->sfbMinSnr[sfbOffs+sfb] = min(newMinSnr, minSnrLimit);
150956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
151956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
152956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
153956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
154956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
155956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
156956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
157956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
158956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
159956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
160956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:initAvoidHoleFlag
161956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: determine bands where avoid hole is not necessary resp. possible
162956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
163956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
164956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void initAvoidHoleFlag(Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
165956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                              PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
166956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                              PSY_OUT_ELEMENT* psyOutElement,
167956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                              const Word16 nChannels,
168956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                              AH_PARAM *ahParam)
169956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
170956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 ch, sfb, sfbGrp, shift;
171956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 threshold;
172956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32* psfbSpreadEn;
173956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
174956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for (ch=0; ch<nChannels; ch++) {
175956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
176b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
177956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if (psyOutChan->windowSequence != SHORT_WINDOW) {
178956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
179e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard         psfbSpreadEn = psyOutChan->sfbSpreadedEnergy + sfbGrp;
180956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		 for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
181e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard			*psfbSpreadEn = *psfbSpreadEn >> 1;  /* 0.5 */
182956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong			++psfbSpreadEn;
183956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
184956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
185956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
186956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    else {
187e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard      for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
188956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		psfbSpreadEn = psyOutChan->sfbSpreadedEnergy + sfbGrp;
189956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
190e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard          *psfbSpreadEn = (*psfbSpreadEn >> 1) + (*psfbSpreadEn >> 3);  /* 0.63 */
191956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		  ++psfbSpreadEn;
192956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
193956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
194956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
195956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
196956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
197956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* increase minSnr for local peaks, decrease it for valleys */
198956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (ahParam->modifyMinSnr) {
199956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for(ch=0; ch<nChannels; ch++) {
200956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
201b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
202956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if (psyOutChan->windowSequence != SHORT_WINDOW)
203956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        threshold = HOLE_THR_LONG;
204956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      else
205956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        threshold = HOLE_THR_SHORT;
206956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
207956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
208e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard        Word16 *psfbMinSnr = psyOutChan->sfbMinSnr + sfbGrp;
209956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
210956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          Word32 sfbEn, sfbEnm1, sfbEnp1, avgEn;
211b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
212956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if (sfb > 0)
213956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            sfbEnm1 = psyOutChan->sfbEnergy[sfbGrp+sfb-1];
214956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          else
215956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            sfbEnm1 = psyOutChan->sfbEnergy[sfbGrp];
216b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
217956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if (sfb < (psyOutChan->maxSfbPerGroup-1))
218956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            sfbEnp1 = psyOutChan->sfbEnergy[sfbGrp+sfb+1];
219956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          else
220956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            sfbEnp1 = psyOutChan->sfbEnergy[sfbGrp+sfb];
221956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          avgEn = (sfbEnm1 + sfbEnp1) >> 1;
222b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          sfbEn = psyOutChan->sfbEnergy[sfbGrp+sfb];
223b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
224956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if (sfbEn > avgEn && avgEn > 0) {
225956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            Word32 tmpMinSnr;
226e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard            shift = norm_l(sfbEn);
227956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong			tmpMinSnr = Div_32(L_mpy_ls(avgEn, minSnrLimit) << shift, sfbEn << shift );
228b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard            tmpMinSnr = max(tmpMinSnr, HOLE_THR_LONG);
229956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            tmpMinSnr = max(tmpMinSnr, threshold);
230956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            *psfbMinSnr = min(*psfbMinSnr, tmpMinSnr);
231956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
232956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          /* valley ? */
233b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
234956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if ((sfbEn < (avgEn >> 1)) && (sfbEn > 0)) {
235956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            Word32 tmpMinSnr;
236b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard            Word32 minSnrEn = L_mpy_wx(avgEn, *psfbMinSnr);
237b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
238e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard            if(minSnrEn < sfbEn) {
239956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong			  shift = norm_l(sfbEn);
240956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              tmpMinSnr = Div_32( minSnrEn << shift, sfbEn<<shift);
241956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            }
242956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            else {
243b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard              tmpMinSnr = MAX_16;
244956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            }
245956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            tmpMinSnr = min(minSnrLimit, tmpMinSnr);
246956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
247956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            *psfbMinSnr =
248956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              (min((tmpMinSnr >>  2), mult(*psfbMinSnr, MIN_SNR_COEF)) << 2);
249e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard          }
250956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		  psfbMinSnr++;
251956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
252956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
253956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
254956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
255956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
256956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* stereo: adapt the minimum requirements sfbMinSnr of mid and
257956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong     side channels */
258b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
259956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (nChannels == 2) {
260956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChanM = &psyOutChannel[0];
261956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChanS = &psyOutChannel[1];
262956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (sfb=0; sfb<psyOutChanM->sfbCnt; sfb++) {
263956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if (psyOutElement->toolsInfo.msMask[sfb]) {
264956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        Word32 sfbEnM = psyOutChanM->sfbEnergy[sfb];
265956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        Word32 sfbEnS = psyOutChanS->sfbEnergy[sfb];
266956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        Word32 maxSfbEn = max(sfbEnM, sfbEnS);
267b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard        Word32 maxThr = L_mpy_wx(maxSfbEn, psyOutChanM->sfbMinSnr[sfb]) >> 1;
268b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
269956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if(maxThr >= sfbEnM) {
270b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          psyOutChanM->sfbMinSnr[sfb] = MAX_16;
271956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
272956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        else {
273b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          shift = norm_l(sfbEnM);
274b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard		  psyOutChanM->sfbMinSnr[sfb] = min(max(psyOutChanM->sfbMinSnr[sfb],
275956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong			  round16(Div_32(maxThr<<shift, sfbEnM << shift))), minSnrLimit);
276956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
277b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
278956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if(maxThr >= sfbEnS) {
279956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          psyOutChanS->sfbMinSnr[sfb] = MAX_16;
280956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
281e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard        else {
282956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		  shift = norm_l(sfbEnS);
283b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          psyOutChanS->sfbMinSnr[sfb] = min(max(psyOutChanS->sfbMinSnr[sfb],
284956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong			  round16(Div_32(maxThr << shift, sfbEnS << shift))), minSnrLimit);
285956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
286956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
287b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
288956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (sfbEnM > psyOutChanM->sfbSpreadedEnergy[sfb])
289956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          psyOutChanS->sfbSpreadedEnergy[sfb] = L_mpy_ls(sfbEnS, MS_THRSPREAD_COEF);
290b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
291956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (sfbEnS > psyOutChanS->sfbSpreadedEnergy[sfb])
292956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          psyOutChanM->sfbSpreadedEnergy[sfb] = L_mpy_ls(sfbEnM, MS_THRSPREAD_COEF);
293956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
294956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
295956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
296956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
297956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
298956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */
299956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for(ch=0; ch<nChannels; ch++) {
300956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
301956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
302e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard      Word16 *pahFlag = ahFlag[ch] + sfbGrp;
303956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
304b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
305956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if ((psyOutChan->sfbSpreadedEnergy[sfbGrp+sfb] > psyOutChan->sfbEnergy[sfbGrp+sfb]) ||
306956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            (psyOutChan->sfbEnergy[sfbGrp+sfb] <= psyOutChan->sfbThreshold[sfbGrp+sfb]) ||
307956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            (psyOutChan->sfbMinSnr[sfbGrp+sfb] == MAX_16)) {
308956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          *pahFlag++ = NO_AH;
309956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
310956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        else {
311956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          *pahFlag++ = AH_INACTIVE;
312956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
313956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
314956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for (sfb=psyOutChan->maxSfbPerGroup; sfb<psyOutChan->sfbPerGroup; sfb++) {
315b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard        *pahFlag++ = NO_AH;
316956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
317956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
318956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
319956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
320956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
321956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
322956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
323956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:calcPeNoAH
324956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: sum the pe data only for bands where avoid hole is inactive
325956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
326956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
327956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void calcPeNoAH(Word16          *pe,
328956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                       Word16          *constPart,
329956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                       Word16          *nActiveLines,
330956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                       PE_DATA         *peData,
331956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                       Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
332956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                       PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
333956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                       const Word16     nChannels)
334956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
335e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  Word16 ch, sfb, sfbGrp;
336956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  int ipe, iconstPart, inActiveLines;
337956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
338b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  ipe = 0;
339b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  iconstPart = 0;
340b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  inActiveLines = 0;
341956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for(ch=0; ch<nChannels; ch++) {
342956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
343956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PE_CHANNEL_DATA *peChanData = &peData->peChannelData[ch];
344956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
345956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
346b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
347956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (ahFlag[ch][sfbGrp+sfb] < AH_ACTIVE) {
348956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          ipe = ipe + peChanData->sfbPe[sfbGrp+sfb];
349956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          iconstPart = iconstPart + peChanData->sfbConstPart[sfbGrp+sfb];
350956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          inActiveLines = inActiveLines + peChanData->sfbNActiveLines[sfbGrp+sfb];
351956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
352956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
353956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
354e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  }
355956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
356b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  *pe = saturate(ipe);
357b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  *constPart = saturate(iconstPart);
358b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  *nActiveLines = saturate(inActiveLines);
359956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
360956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
361956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
362956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
363956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:reduceThresholds
364956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: apply reduction formula
365956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
366956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
367956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void reduceThresholds(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
368956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                             Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
369956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                             Word32           thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
370956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                             const Word16     nChannels,
371956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                             const Word32     redVal)
372956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
373956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 sfbThrReduced;
374b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  Word32 *psfbEn, *psfbThr;
375e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  Word16 ch, sfb, sfbGrp;
376956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
377956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for(ch=0; ch<nChannels; ch++) {
378956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
379956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for(sfbGrp=0; sfbGrp<psyOutChan->sfbCnt; sfbGrp+=psyOutChan->sfbPerGroup) {
380b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard 	  psfbEn  = psyOutChan->sfbEnergy + sfbGrp;
381e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard      psfbThr = psyOutChan->sfbThreshold + sfbGrp;
382956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
383b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
384956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (*psfbEn > *psfbThr) {
385956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          /* threshold reduction formula */
386956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          Word32 tmp = thrExp[ch][sfbGrp+sfb] + redVal;
387956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          tmp = fixmul(tmp, tmp);
388956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          sfbThrReduced = fixmul(tmp, tmp);
389956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          /* avoid holes */
390956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          tmp = L_mpy_ls(*psfbEn, psyOutChan->sfbMinSnr[sfbGrp+sfb]);
391b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
392b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          if ((sfbThrReduced > tmp) &&
393956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              (ahFlag[ch][sfbGrp+sfb] != NO_AH)){
394956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            sfbThrReduced = max(tmp, *psfbThr);
395b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard            ahFlag[ch][sfbGrp+sfb] = AH_ACTIVE;
396956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
397956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		  *psfbThr = sfbThrReduced;
398e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard        }
399e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard
400956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		psfbEn++;  psfbThr++;
401956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
402956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
403956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
404956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
405956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
406956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
407956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
408956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
409956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:correctThresh
410956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: if pe difference deltaPe between desired pe and real pe is small enough,
411956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*             the difference can be distributed among the scale factor bands.
412956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
413956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
414956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void correctThresh(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
415956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
416956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          PE_DATA          *peData,
417956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          Word32           thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
418956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word32     redVal,
419956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word16     nChannels,
420956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word32     deltaPe)
421956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
422956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 ch, sfb, sfbGrp,shift;
423956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  PSY_OUT_CHANNEL *psyOutChan;
424956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  PE_CHANNEL_DATA *peChanData;
425956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 deltaSfbPe;
426e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  Word32 normFactor;
427e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  Word32 *psfbPeFactors;
428956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 *psfbNActiveLines, *pahFlag;
429956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 sfbEn, sfbThr;
430956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 sfbThrReduced;
431956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
432956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* for each sfb calc relative factors for pe changes */
433b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  normFactor = 1;
434956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for(ch=0; ch<nChannels; ch++) {
435956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    psyOutChan = &psyOutChannel[ch];
436956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    peChanData = &peData->peChannelData[ch];
437956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
438e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard      psfbPeFactors = peData->sfbPeFactors[ch] + sfbGrp;
439e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	  psfbNActiveLines = peChanData->sfbNActiveLines + sfbGrp;
440e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	  pahFlag = ahFlag[ch] + sfbGrp;
441956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
442956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        Word32 redThrExp = thrExp[ch][sfbGrp+sfb] + redVal;
443b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
444dcdfc1ad27cb64bcb51a864b020b846ba22ce2a7Martin Storsjo        if (((*pahFlag < AH_ACTIVE) || (deltaPe > 0)) && (redThrExp > 0) && (redThrExp >= *psfbNActiveLines)) {
445b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
446956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          *psfbPeFactors = (*psfbNActiveLines) * (0x7fffffff / redThrExp);
447956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          normFactor = L_add(normFactor, *psfbPeFactors);
448956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
449956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        else {
450b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          *psfbPeFactors = 0;
451e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard        }
452b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard		psfbPeFactors++;
453956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		pahFlag++; psfbNActiveLines++;
454956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
455956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
456956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
457956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
458b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
459956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* calculate new thresholds */
460956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for(ch=0; ch<nChannels; ch++) {
461956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    psyOutChan = &psyOutChannel[ch];
462956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    peChanData = &peData->peChannelData[ch];
463956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
464e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard      psfbPeFactors = peData->sfbPeFactors[ch] + sfbGrp;
465e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	  psfbNActiveLines = peChanData->sfbNActiveLines + sfbGrp;
466e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard	  pahFlag = ahFlag[ch] + sfbGrp;
467956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
468956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        /* pe difference for this sfb */
469956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        deltaSfbPe = *psfbPeFactors * deltaPe;
470956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
471b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard		/* thr3(n) = thr2(n)*2^deltaSfbPe/b(n) */
47201e29ede19cd7d85bfef38896de8e71e569cd211Martin Storsjo        if (*psfbNActiveLines > 0 && (normFactor* (*psfbNActiveLines)) != 0) {
473956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          /* new threshold */
474956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          Word32 thrFactor;
475956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          sfbEn  = psyOutChan->sfbEnergy[sfbGrp+sfb];
476956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          sfbThr = psyOutChan->sfbThreshold[sfbGrp+sfb];
477956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
478956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong           if(deltaSfbPe >= 0){
479956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            /*
480956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              reduce threshold
481956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            */
482956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            thrFactor = pow2_xy(L_negate(deltaSfbPe), (normFactor* (*psfbNActiveLines)));
483b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
484956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            sfbThrReduced = L_mpy_ls(sfbThr, round16(thrFactor));
485956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
486956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          else {
487956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            /*
488956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              increase threshold
489956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            */
490956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            thrFactor = pow2_xy(deltaSfbPe, (normFactor * (*psfbNActiveLines)));
491b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
492b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
493956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            if(thrFactor > sfbThr) {
494e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard              shift = norm_l(thrFactor);
495956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong			  sfbThrReduced = Div_32( sfbThr << shift, thrFactor<<shift );
496956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            }
497956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            else {
498b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard              sfbThrReduced = MAX_32;
499956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            }
500956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
501956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
502b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
503956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          /* avoid hole */
504956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          sfbEn = L_mpy_ls(sfbEn, psyOutChan->sfbMinSnr[sfbGrp+sfb]);
505b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
506956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if ((sfbThrReduced > sfbEn) &&
507956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              (*pahFlag == AH_INACTIVE)) {
508956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            sfbThrReduced = max(sfbEn, sfbThr);
509b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard            *pahFlag = AH_ACTIVE;
510956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
511956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
512b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          psyOutChan->sfbThreshold[sfbGrp+sfb] = sfbThrReduced;
513e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard        }
514e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard
515956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		pahFlag++; psfbNActiveLines++; psfbPeFactors++;
516956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
517956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
518956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
519956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
520956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
521956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
522956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
523956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
524956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:reduceMinSnr
525956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: if the desired pe can not be reached, reduce pe by reducing minSnr
526956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
527956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
528b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgardstatic void reduceMinSnr(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
529b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard                         PE_DATA         *peData,
530956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                         Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
531956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                         const Word16     nChannels,
532956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                         const Word16     desiredPe)
533956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
534956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 ch, sfb, sfbSubWin;
535956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 deltaPe;
536956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
537956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* start at highest freq down to 0 */
538b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  sfbSubWin = psyOutChannel[0].maxSfbPerGroup;
539956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  while (peData->pe > desiredPe && sfbSubWin > 0) {
540b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
541956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    sfbSubWin = sfbSubWin - 1;
542956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* loop over all subwindows */
543956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (sfb=sfbSubWin; sfb<psyOutChannel[0].sfbCnt;
544956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        sfb+=psyOutChannel[0].sfbPerGroup) {
545956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      /* loop over all channels */
546e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard		PE_CHANNEL_DATA* peChan = peData->peChannelData;
547e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard		PSY_OUT_CHANNEL* psyOutCh = psyOutChannel;
548b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard		for (ch=0; ch<nChannels; ch++) {
549956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (ahFlag[ch][sfb] != NO_AH &&
550956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            psyOutCh->sfbMinSnr[sfb] < minSnrLimit) {
551b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          psyOutCh->sfbMinSnr[sfb] = minSnrLimit;
552956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          psyOutCh->sfbThreshold[sfb] =
553956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            L_mpy_ls(psyOutCh->sfbEnergy[sfb], psyOutCh->sfbMinSnr[sfb]);
554956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
555956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          /* calc new pe */
556956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          deltaPe = ((peChan->sfbNLines4[sfb] + (peChan->sfbNLines4[sfb] >> 1)) >> 2) -
557956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              peChan->sfbPe[sfb];
558956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          peData->pe = peData->pe + deltaPe;
559b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          peChan->pe = peChan->pe + deltaPe;
560e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard        }
561956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		peChan += 1; psyOutCh += 1;
562956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
563956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      /* stop if enough has been saved */
564b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
565956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if (peData->pe <= desiredPe)
566956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        break;
567956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
568956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
569956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
570956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
571956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
572956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
573956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:allowMoreHoles
574b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard* description: if the desired pe can not be reached, some more scalefactor bands
575956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*              have to be quantized to zero
576956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
577956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
578b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgardstatic void allowMoreHoles(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
579956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           PSY_OUT_ELEMENT *psyOutElement,
580b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard                           PE_DATA         *peData,
581956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
582956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           const AH_PARAM  *ahParam,
583956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           const Word16     nChannels,
584956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           const Word16     desiredPe)
585956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
586956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 ch, sfb;
587956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 actPe, shift;
588956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
589b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  actPe = peData->pe;
590956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
591956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* for MS allow hole in the channel with less energy */
592b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
593956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (nChannels==2 &&
594956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      psyOutChannel[0].windowSequence==psyOutChannel[1].windowSequence) {
595956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChanL = &psyOutChannel[0];
596956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    PSY_OUT_CHANNEL *psyOutChanR = &psyOutChannel[1];
597956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (sfb=0; sfb<psyOutChanL->sfbCnt; sfb++) {
598956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      Word32 minEn;
599b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
600956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if (psyOutElement->toolsInfo.msMask[sfb]) {
601956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        /* allow hole in side channel ? */
602956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        minEn = L_mpy_ls(psyOutChanL->sfbEnergy[sfb], (minSnrLimit * psyOutChanL->sfbMinSnr[sfb]) >> 16);
603b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
604956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (ahFlag[1][sfb] != NO_AH &&
605956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            minEn > psyOutChanR->sfbEnergy[sfb]) {
606b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          ahFlag[1][sfb] = NO_AH;
607956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          psyOutChanR->sfbThreshold[sfb] = L_add(psyOutChanR->sfbEnergy[sfb], psyOutChanR->sfbEnergy[sfb]);
608956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          actPe = actPe - peData->peChannelData[1].sfbPe[sfb];
609956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
610956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        /* allow hole in mid channel ? */
611956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        else {
612956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        minEn = L_mpy_ls(psyOutChanR->sfbEnergy[sfb], (minSnrLimit * psyOutChanR->sfbMinSnr[sfb]) >> 16);
613b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
614956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if (ahFlag[0][sfb]!= NO_AH &&
615956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong              minEn > psyOutChanL->sfbEnergy[sfb]) {
616b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard            ahFlag[0][sfb] = NO_AH;
617956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            psyOutChanL->sfbThreshold[sfb] = L_add(psyOutChanL->sfbEnergy[sfb], psyOutChanL->sfbEnergy[sfb]);
618956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            actPe = actPe - peData->peChannelData[0].sfbPe[sfb];
619956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
620956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
621b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
622956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (actPe < desiredPe)
623956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          break;
624956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
625956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
626956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
627956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
628b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  /* subsequently erase bands */
629956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (actPe > desiredPe) {
630956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 startSfb[2];
631956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word32 avgEn, minEn;
632956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 ahCnt;
633956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 enIdx;
634956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 enDiff;
635956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word32 en[4];
636956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 minSfb, maxSfb;
637956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Flag   done;
638956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
639956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* do not go below startSfb */
640956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (ch=0; ch<nChannels; ch++) {
641b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
642956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if (psyOutChannel[ch].windowSequence != SHORT_WINDOW)
643956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        startSfb[ch] = ahParam->startSfbL;
644956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      else
645956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        startSfb[ch] = ahParam->startSfbS;
646956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
647956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
648b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    avgEn = 0;
649b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    minEn = MAX_32;
650b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    ahCnt = 0;
651956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (ch=0; ch<nChannels; ch++) {
652956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
653956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for (sfb=startSfb[ch]; sfb<psyOutChan->sfbCnt; sfb++) {
654b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
655956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if ((ahFlag[ch][sfb] != NO_AH) &&
656956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            (psyOutChan->sfbEnergy[sfb] > psyOutChan->sfbThreshold[sfb])) {
657956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          minEn = min(minEn, psyOutChan->sfbEnergy[sfb]);
658956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          avgEn = L_add(avgEn, psyOutChan->sfbEnergy[sfb]);
659956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          ahCnt++;
660956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
661956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
662956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
663b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
664956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if(ahCnt) {
665956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      Word32 iahCnt;
666e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard      shift = norm_l(ahCnt);
667956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	  iahCnt = Div_32( 1 << shift, ahCnt << shift );
668956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      avgEn = fixmul(avgEn, iahCnt);
669956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
670956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
671956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    enDiff = iLog4(avgEn) - iLog4(minEn);
672956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* calc some energy borders between minEn and avgEn */
673956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    for (enIdx=0; enIdx<4; enIdx++) {
674956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      Word32 enFac;
675956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      enFac = ((6-(enIdx << 1)) * enDiff);
676956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      en[enIdx] = fixmul(avgEn, pow2_xy(L_negate(enFac),7*4));
677956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
678956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
679956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* start with lowest energy border at highest sfb */
680956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    maxSfb = psyOutChannel[0].sfbCnt - 1;
681b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    minSfb = startSfb[0];
682b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
683956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if (nChannels == 2) {
684956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      maxSfb = max(maxSfb, (psyOutChannel[1].sfbCnt - 1));
685956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      minSfb = min(minSfb, startSfb[1]);
686956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
687956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
688b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    sfb = maxSfb;
689b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    enIdx = 0;
690b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    done = 0;
691956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    while (!done) {
692b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
693956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      for (ch=0; ch<nChannels; ch++) {
694956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
695b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
696956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (sfb>=startSfb[ch] && sfb<psyOutChan->sfbCnt) {
697956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          /* sfb energy below border ? */
698b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
699956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if (ahFlag[ch][sfb] != NO_AH && psyOutChan->sfbEnergy[sfb] < en[enIdx]){
700956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            /* allow hole */
701b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard            ahFlag[ch][sfb] = NO_AH;
702956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            psyOutChan->sfbThreshold[sfb] = L_add(psyOutChan->sfbEnergy[sfb], psyOutChan->sfbEnergy[sfb]);
703956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            actPe = actPe - peData->peChannelData[ch].sfbPe[sfb];
704956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
705b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
706956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          if (actPe < desiredPe) {
707b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard            done = 1;
708956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong            break;
709956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          }
710956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        }
711956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
712956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      sfb = sfb - 1;
713b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
714956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if (sfb < minSfb) {
715956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        /* restart with next energy border */
716b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard        sfb = maxSfb;
717956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        enIdx = enIdx + 1;
718b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
719956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        if (enIdx - 4 >= 0)
720b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard          done = 1;
721956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
722956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
723956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
724956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
725956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
726956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
727956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
728956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name:adaptThresholdsToPe
729956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description: two guesses for the reduction value and one final correction of the
730956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*              thresholds
731956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
732956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
733956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void adaptThresholdsToPe(PSY_OUT_CHANNEL     psyOutChannel[MAX_CHANNELS],
734956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                PSY_OUT_ELEMENT    *psyOutElement,
735956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                Word16              logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
736956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                PE_DATA            *peData,
737956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                const Word16        nChannels,
738956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                const Word16        desiredPe,
739956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                AH_PARAM           *ahParam,
740956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                MINSNR_ADAPT_PARAM *msaParam)
741956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
742956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 noRedPe, redPe, redPeNoAH;
743956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 constPart, constPartNoAH;
744956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 nActiveLines, nActiveLinesNoAH;
745956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 desiredPeNoAH;
746956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 redVal, avgThrExp;
747956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 iter;
748956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
749956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  calcThreshExp(peData->thrExp, psyOutChannel, nChannels);
750956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
751956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  adaptMinSnr(psyOutChannel, logSfbEnergy, msaParam, nChannels);
752956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
753956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  initAvoidHoleFlag(peData->ahFlag, psyOutChannel, psyOutElement, nChannels, ahParam);
754956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
755b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  noRedPe = peData->pe;
756b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  constPart = peData->constPart;
757b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  nActiveLines = peData->nActiveLines;
758956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
759956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* first guess of reduction value t^0.25 = 2^((a-pen)/4*b) */
760956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  avgThrExp = pow2_xy((constPart - noRedPe), (nActiveLines << 2));
761b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
762956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* r1 = 2^((a-per)/4*b) - t^0.25 */
763956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  redVal = pow2_xy((constPart - desiredPe), (nActiveLines << 2)) - avgThrExp;
764956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
765956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* reduce thresholds */
766956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  reduceThresholds(psyOutChannel, peData->ahFlag, peData->thrExp, nChannels, redVal);
767956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
768956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* pe after first guess */
769956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  calcSfbPe(peData, psyOutChannel, nChannels);
770b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  redPe = peData->pe;
771956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
772b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  iter = 0;
773956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  do {
774956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* pe for bands where avoid hole is inactive */
775956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    calcPeNoAH(&redPeNoAH, &constPartNoAH, &nActiveLinesNoAH,
776956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong               peData, peData->ahFlag, psyOutChannel, nChannels);
777956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
778956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    desiredPeNoAH = desiredPe -(redPe - redPeNoAH);
779b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
780956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if (desiredPeNoAH < 0) {
781b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard      desiredPeNoAH = 0;
782956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
783956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
784956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* second guess */
785b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
786956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if (nActiveLinesNoAH > 0) {
787b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
788956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		avgThrExp = pow2_xy((constPartNoAH - redPeNoAH), (nActiveLinesNoAH << 2));
789b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
790956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		redVal = (redVal + pow2_xy((constPartNoAH - desiredPeNoAH), (nActiveLinesNoAH << 2))) - avgThrExp;
791b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
792956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		/* reduce thresholds */
793956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		reduceThresholds(psyOutChannel, peData->ahFlag, peData->thrExp, nChannels, redVal);
794956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
795956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
796956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    calcSfbPe(peData, psyOutChannel, nChannels);
797b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    redPe = peData->pe;
798956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
799956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    iter = iter+1;
800b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
801956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  } while ((20 * abs_s(redPe - desiredPe) > desiredPe) && (iter < 2));
802956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
803b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
804956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if ((100 * redPe < 115 * desiredPe)) {
805956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    correctThresh(psyOutChannel, peData->ahFlag, peData, peData->thrExp, redVal,
806956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                  nChannels, desiredPe - redPe);
807956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
808956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  else {
809956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 desiredPe105 = (105 * desiredPe) / 100;
810956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    reduceMinSnr(psyOutChannel, peData, peData->ahFlag,
811956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                 nChannels, desiredPe105);
812956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    allowMoreHoles(psyOutChannel, psyOutElement, peData, peData->ahFlag,
813956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                   ahParam, nChannels, desiredPe105);
814956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
815956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
816956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
817956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
818956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/*****************************************************************************
819956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
820956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: calcBitSave
821956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  Calculates percentage of bit save, see figure below
822956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* returns:
823956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* input:        parameters and bitres-fullness
824956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* output:       percentage of bit save
825956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
826956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*****************************************************************************/
827956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic Word16 calcBitSave(Word16 fillLevel,
828956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word16 clipLow,
829956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word16 clipHigh,
830956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word16 minBitSave,
831956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          const Word16 maxBitSave)
832956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
833956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 bitsave = 0;
834956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
835956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  fillLevel = max(fillLevel, clipLow);
836956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  fillLevel = min(fillLevel, clipHigh);
837956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
838e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  if(clipHigh-clipLow)
839956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  bitsave = (maxBitSave - (((maxBitSave-minBitSave)*(fillLevel-clipLow))/
840956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                              (clipHigh-clipLow)));
841956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
842956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  return (bitsave);
843956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
844956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
845956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
846956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
847956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/*****************************************************************************
848956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
849956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: calcBitSpend
850956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  Calculates percentage of bit spend, see figure below
851956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* returns:
852956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* input:        parameters and bitres-fullness
853956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* output:       percentage of bit spend
854956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
855956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*****************************************************************************/
856956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic Word16 calcBitSpend(Word16 fillLevel,
857956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           const Word16 clipLow,
858956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           const Word16 clipHigh,
859956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           const Word16 minBitSpend,
860956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           const Word16 maxBitSpend)
861956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
862956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 bitspend = 1;
863956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
864956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  fillLevel = max(fillLevel, clipLow);
865956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  fillLevel = min(fillLevel, clipHigh);
866956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
867e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  if(clipHigh-clipLow)
868956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  bitspend = (minBitSpend + ((maxBitSpend - minBitSpend)*(fillLevel - clipLow) /
869956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                (clipHigh-clipLow)));
870b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
871956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  return (bitspend);
872956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
873956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
874956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
875956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/*****************************************************************************
876956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
877956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: adjustPeMinMax()
878956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  adjusts peMin and peMax parameters over time
879956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* returns:
880956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* input:        current pe, peMin, peMax
881956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* output:       adjusted peMin/peMax
882956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
883956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*****************************************************************************/
884956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void adjustPeMinMax(const Word16 currPe,
885956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           Word16      *peMin,
886956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                           Word16      *peMax)
887956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
888956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 minFacHi, maxFacHi, minFacLo, maxFacLo;
889956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 diff;
890956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 minDiff = extract_l(currPe / 6);
891b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  minFacHi = 30;
892b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  maxFacHi = 100;
893b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  minFacLo = 14;
894b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  maxFacLo = 7;
895956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
896956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  diff = currPe - *peMax ;
897b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
898956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (diff > 0) {
899956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    *peMin = *peMin + ((diff * minFacHi) / 100);
900956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    *peMax = *peMax + ((diff * maxFacHi) / 100);
901956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  } else {
902956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    diff = *peMin - currPe;
903b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
904956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if (diff > 0) {
905956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      *peMin = *peMin - ((diff * minFacLo) / 100);
906956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      *peMax = *peMax - ((diff * maxFacLo) / 100);
907956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    } else {
908956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      *peMin = *peMin + ((currPe - *peMin) * minFacHi / 100);
909956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      *peMax = *peMax - ((*peMax - currPe) * maxFacLo / 100);
910956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
911956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
912956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
913b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
914956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if ((*peMax - *peMin) < minDiff) {
915956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 partLo, partHi;
916956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
917956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    partLo = max(0, (currPe - *peMin));
918956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    partHi = max(0, (*peMax - currPe));
919956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
920956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    *peMax = currPe + ((partHi * minDiff) / (partLo + partHi));
921956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    *peMin = currPe - ((partLo * minDiff) / (partLo + partHi));
922956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    *peMin = max(0, *peMin);
923956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
924956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
925956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
926956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
927956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/*****************************************************************************
928956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
929956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: BitresCalcBitFac
930956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  calculates factor of spending bits for one frame
931956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*                1.0 : take all frame dynpart bits
932956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*                >1.0 : take all frame dynpart bits + bitres
933956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*                <1.0 : put bits in bitreservoir
934956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*  returns:      BitFac*100
935956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*  input:        bitres-fullness, pe, blockType, parameter-settings
936956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*  output:
937956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
938956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*****************************************************************************/
939956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic Word16 bitresCalcBitFac( const Word16   bitresBits,
940956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                const Word16   maxBitresBits,
941956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                const Word16   pe,
942956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                const Word16   windowSequence,
943956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                const Word16   avgBits,
944956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                const Word16   maxBitFac,
945956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                ADJ_THR_STATE *AdjThr,
946956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                                ATS_ELEMENT   *adjThrChan)
947956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
948956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  BRES_PARAM *bresParam;
949956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 pex;
950956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 fillLevel;
951956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 bitSave, bitSpend, bitresFac;
952956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
953956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  fillLevel = extract_l((100* bitresBits) / maxBitresBits);
954956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
955956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (windowSequence != SHORT_WINDOW)
956956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    bresParam = &(AdjThr->bresParamLong);
957956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  else
958956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    bresParam = &(AdjThr->bresParamShort);
959956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
960956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  pex = max(pe, adjThrChan->peMin);
961956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  pex = min(pex,adjThrChan->peMax);
962956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
963956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  bitSave = calcBitSave(fillLevel,
964956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        bresParam->clipSaveLow, bresParam->clipSaveHigh,
965956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        bresParam->minBitSave, bresParam->maxBitSave);
966956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
967956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  bitSpend = calcBitSpend(fillLevel,
968956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          bresParam->clipSpendLow, bresParam->clipSpendHigh,
969956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                          bresParam->minBitSpend, bresParam->maxBitSpend);
970956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
971e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard  if(adjThrChan->peMax != adjThrChan->peMin)
972956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	bitresFac = (100 - bitSave) + extract_l(((bitSpend + bitSave) * (pex - adjThrChan->peMin)) /
973956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                    (adjThrChan->peMax - adjThrChan->peMin));
974956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  else
975956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong	bitresFac = 0x7fff;
976b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
977956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  bitresFac = min(bitresFac,
978956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                    (100-30 + extract_l((100 * bitresBits) / avgBits)));
979956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
980956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  bitresFac = min(bitresFac, maxBitFac);
981956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
982956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  adjustPeMinMax(pe, &adjThrChan->peMin, &adjThrChan->peMax);
983956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
984956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  return bitresFac;
985956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
986956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
987956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/*****************************************************************************
988956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
989956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: AdjThrInit
990956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  init thresholds parameter
991956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
992956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*****************************************************************************/
993956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongvoid AdjThrInit(ADJ_THR_STATE *hAdjThr,
994956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                const Word32   meanPe,
995956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                Word32         chBitrate)
996956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
997956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  ATS_ELEMENT* atsElem = &hAdjThr->adjThrStateElem;
998956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  MINSNR_ADAPT_PARAM *msaParam = &atsElem->minSnrAdaptParam;
999956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1000956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* common for all elements: */
1001956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* parameters for bitres control */
1002b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.clipSaveLow   =  20;
1003b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.clipSaveHigh  =  95;
1004b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.minBitSave    =  -5;
1005b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.maxBitSave    =  30;
1006b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.clipSpendLow  =  20;
1007b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.clipSpendHigh =  95;
1008b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.minBitSpend   = -10;
1009b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamLong.maxBitSpend   =  40;
1010b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1011b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.clipSaveLow   =  20;
1012b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.clipSaveHigh  =  75;
1013b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.minBitSave    =   0;
1014b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.maxBitSave    =  20;
1015b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.clipSpendLow  =  20;
1016b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.clipSpendHigh =  75;
1017b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.minBitSpend   = -5;
1018b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  hAdjThr->bresParamShort.maxBitSpend   =  50;
1019956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1020956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* specific for each element: */
1021956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1022956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* parameters for bitres control */
1023956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  atsElem->peMin = extract_l(((80*meanPe) / 100));
1024956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  atsElem->peMax = extract_l(((120*meanPe) / 100));
1025956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1026956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* additional pe offset to correct pe2bits for low bitrates */
1027b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  atsElem->peOffset = 0;
1028956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (chBitrate < 32000) {
1029956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    atsElem->peOffset = max(50, (100 - extract_l((100 * chBitrate) / 32000)));
1030956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1031956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1032956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* avoid hole parameters */
1033956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (chBitrate > 20000) {
1034956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    atsElem->ahParam.modifyMinSnr = TRUE;
1035956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    atsElem->ahParam.startSfbL = 15;
1036956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    atsElem->ahParam.startSfbS = 3;
1037956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1038956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  else {
1039956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    atsElem->ahParam.modifyMinSnr = FALSE;
1040956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    atsElem->ahParam.startSfbL = 0;
1041956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    atsElem->ahParam.startSfbS = 0;
1042956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1043956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1044956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* minSnr adaptation */
1045956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* maximum reduction of minSnr goes down to minSnr^maxRed */
104660866592ed6953f2b0e12cefcd58f1ced26546d0Martin Storsjo  msaParam->maxRed = 0x20000000;     /* *0.25f */
1047956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* start adaptation of minSnr for avgEn/sfbEn > startRatio */
1048b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  msaParam->startRatio = 0x0ccccccd; /* 10 */
1049956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* maximum minSnr reduction to minSnr^maxRed is reached for
1050956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong     avgEn/sfbEn >= maxRatio */
1051b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  msaParam->maxRatio =  0x0020c49c; /* 1000 */
1052956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* helper variables to interpolate minSnr reduction for
1053956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong     avgEn/sfbEn between startRatio and maxRatio */
1054956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1055b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  msaParam->redRatioFac = 0xfb333333; /* -0.75/20 */
1056b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1057b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  msaParam->redOffs = 0x30000000;  /* msaParam->redRatioFac * 10*log10(msaParam->startRatio) */
1058956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1059956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1060956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* pe correction */
1061b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  atsElem->peLast = 0;
1062b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  atsElem->dynBitsLast = 0;
1063b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  atsElem->peCorrectionFactor = 100; /* 1.0 */
1064956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1065956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
1066956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1067956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/*****************************************************************************
1068956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
1069956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: calcPeCorrection
1070956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  calculates the desired perceptual entropy factor
1071956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*				It is between 0.85 and 1.15
1072956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
1073956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*****************************************************************************/
1074956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongstatic void calcPeCorrection(Word16 *correctionFac,
1075956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                             const Word16 peAct,
1076b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard                             const Word16 peLast,
1077b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard                             const Word16 bitsLast)
1078956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
1079956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 peAct100 = 100 * peAct;
1080956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word32 peLast100 = 100 * peLast;
1081956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 peBitsLast = bits2pe(bitsLast);
1082b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1083956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if ((bitsLast > 0) &&
1084956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      (peAct100 < (150 * peLast)) &&  (peAct100 > (70 * peLast)) &&
1085956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      ((120 * peBitsLast) > peLast100 ) && (( 65 * peBitsLast) < peLast100))
1086956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    {
1087956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      Word16 newFac = (100 * peLast) / peBitsLast;
1088956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      /* dead zone */
1089b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1090956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if (newFac < 100) {
1091956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        newFac = min(((110 * newFac) / 100), 100);
1092956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        newFac = max(newFac, 85);
1093956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
1094956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      else {
1095956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        newFac = max(((90 * newFac) / 100), 100);
1096956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        newFac = min(newFac, 115);
1097956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
1098b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1099956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if ((newFac > 100 && *correctionFac < 100) ||
1100956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          (newFac < 100 && *correctionFac > 100)) {
1101b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard        *correctionFac = 100;
1102956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      }
1103956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      /* faster adaptation towards 1.0, slower in the other direction */
1104b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1105956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      if ((*correctionFac < 100 && newFac < *correctionFac) ||
1106956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong          (*correctionFac > 100 && newFac > *correctionFac))
1107956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        *correctionFac = (85 * *correctionFac + 15 * newFac) / 100;
1108956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      else
1109956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        *correctionFac = (70 * *correctionFac + 30 * newFac) / 100;
1110956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      *correctionFac = min(*correctionFac, 115);
1111956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      *correctionFac = max(*correctionFac, 85);
1112956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
1113956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  else {
1114b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    *correctionFac = 100;
1115956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1116956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
1117956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1118956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
1119956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
1120956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: AdjustThresholds
1121956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  Adjust thresholds to the desired bitrate
1122956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
1123956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
1124956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongvoid AdjustThresholds(ADJ_THR_STATE   *adjThrState,
1125956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                      ATS_ELEMENT     *AdjThrStateElement,
1126956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                      PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
1127956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                      PSY_OUT_ELEMENT *psyOutElement,
1128956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                      Word16          *chBitDistribution,
1129956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                      Word16           logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
1130b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard                      Word16           sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB],
1131956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                      QC_OUT_ELEMENT  *qcOE,
1132956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong					  ELEMENT_BITS	  *elBits,
1133956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong					  const Word16     nChannels,
1134956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                      const Word16     maxBitFac)
1135956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
1136b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  PE_DATA peData;
1137956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 noRedPe, grantedPe, grantedPeCorr;
1138956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 curWindowSequence;
1139956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 bitFactor;
1140956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 avgBits = (elBits->averageBits - (qcOE->staticBitsUsed + qcOE->ancBitsUsed));
1141b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  Word16 bitresBits = elBits->bitResLevel;
1142956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 maxBitresBits = elBits->maxBits;
1143956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 sideInfoBits = (qcOE->staticBitsUsed + qcOE->ancBitsUsed);
1144956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  Word16 ch;
1145132e42c04a58e623efa6cd6ca43641cd80db0f05Martin Storsjo  memset(&peData, 0, sizeof(peData));
1146b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1147956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  prepareSfbPe(&peData, psyOutChannel, logSfbEnergy, sfbNRelevantLines, nChannels, AdjThrStateElement->peOffset);
1148b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1149956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* pe without reduction */
1150956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  calcSfbPe(&peData, psyOutChannel, nChannels);
1151b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  noRedPe = peData.pe;
1152956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1153956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1154b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  curWindowSequence = LONG_WINDOW;
1155b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1156956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (nChannels == 2) {
1157b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1158956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if ((psyOutChannel[0].windowSequence == SHORT_WINDOW) ||
1159956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong        (psyOutChannel[1].windowSequence == SHORT_WINDOW)) {
1160b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard      curWindowSequence = SHORT_WINDOW;
1161956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
1162956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1163956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  else {
1164b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    curWindowSequence = psyOutChannel[0].windowSequence;
1165956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1166956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1167956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1168956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* bit factor */
1169956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  bitFactor = bitresCalcBitFac(bitresBits, maxBitresBits, noRedPe+5*sideInfoBits,
1170956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                               curWindowSequence, avgBits, maxBitFac,
1171956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                               adjThrState,
1172956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                               AdjThrStateElement);
1173956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1174956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* desired pe */
1175956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  grantedPe = ((bitFactor * bits2pe(avgBits)) / 100);
1176956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1177956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* correction of pe value */
1178b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  calcPeCorrection(&(AdjThrStateElement->peCorrectionFactor),
1179956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                   min(grantedPe, noRedPe),
1180b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard                   AdjThrStateElement->peLast,
1181956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                   AdjThrStateElement->dynBitsLast);
1182956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  grantedPeCorr = (grantedPe * AdjThrStateElement->peCorrectionFactor) / 100;
1183956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1184b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1185956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  if (grantedPeCorr < noRedPe && noRedPe > peData.offset) {
1186956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    /* calc threshold necessary for desired pe */
1187956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    adaptThresholdsToPe(psyOutChannel,
1188956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        psyOutElement,
1189956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        logSfbEnergy,
1190956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        &peData,
1191956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        nChannels,
1192956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        grantedPeCorr,
1193956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        &AdjThrStateElement->ahParam,
1194956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                        &AdjThrStateElement->minSnrAdaptParam);
1195956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1196956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1197956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* calculate relative distribution */
1198956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  for (ch=0; ch<nChannels; ch++) {
1199956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    Word16 peOffsDiff = peData.pe - peData.offset;
1200b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard    chBitDistribution[ch] = 200;
1201b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard
1202956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    if (peOffsDiff > 0) {
1203956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      Word32 temp = 1000 - (nChannels * 200);
1204e2e838afcf03e603a41a0455846eaf9614537c16Mans Rullgard      chBitDistribution[ch] = chBitDistribution[ch] +
1205956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong		  (temp * peData.peChannelData[ch].pe) / peOffsDiff;
1206956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    }
1207956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  }
1208956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1209956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* store pe */
1210b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  qcOE->pe = noRedPe;
1211956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1212956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong  /* update last pe */
1213b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  AdjThrStateElement->peLast = grantedPe;
1214956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
1215956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1216956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong/********************************************************************************
1217956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
1218956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* function name: AdjThrUpdate
1219956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong* description:  save dynBitsUsed for correction of bits2pe relation
1220956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong*
1221956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong**********************************************************************************/
1222956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dongvoid AdjThrUpdate(ATS_ELEMENT *AdjThrStateElement,
1223956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong                  const Word16 dynBitsUsed)
1224956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong{
1225b676a05348e4c516fa8b57e33b10548e6142c3f8Mans Rullgard  AdjThrStateElement->dynBitsLast = dynBitsUsed;
1226956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong}
1227956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1228956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong
1229