• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  ** Copyright 2003-2010, VisualOn, Inc.
3  **
4  ** Licensed under the Apache License, Version 2.0 (the "License");
5  ** you may not use this file except in compliance with the License.
6  ** You may obtain a copy of the License at
7  **
8  **     http://www.apache.org/licenses/LICENSE-2.0
9  **
10  ** Unless required by applicable law or agreed to in writing, software
11  ** distributed under the License is distributed on an "AS IS" BASIS,
12  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  ** See the License for the specific language governing permissions and
14  ** limitations under the License.
15  */
16 /*******************************************************************************
17 	File:		adj_thr.c
18 
19 	Content:	Threshold compensation functions
20 
21 *******************************************************************************/
22 
23 /* Include system headers before local headers - the local headers
24  * redefine __inline, which can mess up definitions in libc headers if
25  * they happen to use __inline. */
26 #include <string.h>
27 #include "basic_op.h"
28 #include "oper_32b.h"
29 #include "adj_thr_data.h"
30 #include "adj_thr.h"
31 #include "qc_data.h"
32 #include "line_pe.h"
33 
34 
35 #define  minSnrLimit    0x6666 /* 1 dB */
36 #define  PEBITS_COEF	0x170a /* 0.18*(1 << 15)*/
37 
38 #define  HOLE_THR_LONG	0x2873	/* 0.316*(1 << 15) */
39 #define  HOLE_THR_SHORT 0x4000  /* 0.5  *(1 << 15) */
40 
41 #define  MS_THRSPREAD_COEF 0x7333  /* 0.9 * (1 << 15) */
42 
43 #define	 MIN_SNR_COEF	   0x651f  /* 3.16* (1 << (15 - 2)) */
44 
45 /* values for avoid hole flag */
46 enum _avoid_hole_state {
47   NO_AH              =0,
48   AH_INACTIVE        =1,
49   AH_ACTIVE          =2
50 };
51 
52 /********************************************************************************
53 *
54 * function name:bits2pe
55 * description: convert from bits to pe
56 *			   pe = 1.18*desiredBits
57 *
58 **********************************************************************************/
bits2pe(const Word16 bits)59 Word16 bits2pe(const Word16 bits) {
60   return (bits + ((PEBITS_COEF * bits) >> 15));
61 }
62 
63 /********************************************************************************
64 *
65 * function name:calcThreshExp
66 * description: loudness calculation (threshold to the power of redExp)
67 *			   thr(n)^0.25
68 *
69 **********************************************************************************/
calcThreshExp(Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],const Word16 nChannels)70 static void calcThreshExp(Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
71                           PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],
72                           const Word16 nChannels)
73 {
74   Word16 ch, sfb, sfbGrp;
75   Word32 *pthrExp = NULL, *psfbThre;
76   for (ch=0; ch<nChannels; ch++) {
77     PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
78 	 for(sfbGrp = 0; sfbGrp < psyOutChan->sfbCnt; sfbGrp+= psyOutChan->sfbPerGroup)
79 	  pthrExp = &(thrExp[ch][sfbGrp]);
80 	  psfbThre = psyOutChan->sfbThreshold + sfbGrp;
81 	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
82 		*pthrExp = rsqrt(rsqrt(*psfbThre,INT_BITS),INT_BITS);
83 		pthrExp++; psfbThre++;
84       }
85   }
86 }
87 
88 /********************************************************************************
89 *
90 * function name:adaptMinSnr
91 * description: reduce minSnr requirements for bands with relative low energies
92 *
93 **********************************************************************************/
adaptMinSnr(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],MINSNR_ADAPT_PARAM * msaParam,const Word16 nChannels)94 static void adaptMinSnr(PSY_OUT_CHANNEL     psyOutChannel[MAX_CHANNELS],
95                         Word16              logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
96                         MINSNR_ADAPT_PARAM *msaParam,
97                         const Word16        nChannels)
98 {
99   Word16 ch, sfb, sfbOffs;
100   Word32 nSfb, avgEn;
101   Word16 log_avgEn = 0;
102   Word32 startRatio_x_avgEn = 0;
103 
104 
105   for (ch=0; ch<nChannels; ch++) {
106     PSY_OUT_CHANNEL* psyOutChan = &psyOutChannel[ch];
107 
108     /* calc average energy per scalefactor band */
109     avgEn = 0;
110     nSfb = 0;
111     for (sfbOffs=0; sfbOffs<psyOutChan->sfbCnt; sfbOffs+=psyOutChan->sfbPerGroup) {
112       for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
113         avgEn = L_add(avgEn, psyOutChan->sfbEnergy[sfbOffs+sfb]);
114         nSfb = nSfb + 1;
115       }
116     }
117 
118     if (nSfb > 0) {
119 	  avgEn = avgEn / nSfb;
120 
121       log_avgEn = iLog4(avgEn);
122       startRatio_x_avgEn = fixmul(msaParam->startRatio, avgEn);
123     }
124 
125 
126     /* reduce minSnr requirement by minSnr^minSnrRed dependent on avgEn/sfbEn */
127     for (sfbOffs=0; sfbOffs<psyOutChan->sfbCnt; sfbOffs+=psyOutChan->sfbPerGroup) {
128       for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
129         if (psyOutChan->sfbEnergy[sfbOffs+sfb] < startRatio_x_avgEn) {
130           Word16 dbRatio, minSnrRed;
131           Word32 snrRed;
132           Word16 newMinSnr;
133 
134           dbRatio = log_avgEn - logSfbEnergy[ch][sfbOffs+sfb];
135           dbRatio = dbRatio + (dbRatio << 1);
136 
137           minSnrRed = 110 - ((dbRatio + (dbRatio << 1)) >> 2);
138           minSnrRed = max(minSnrRed, 20); /* 110: (0.375(redOffs)+1)*80,
139                                                3: 0.00375(redRatioFac)*80
140                                                20: 0.25(maxRed) * 80 */
141 
142           snrRed = minSnrRed * iLog4((psyOutChan->sfbMinSnr[sfbOffs+sfb] << 16));
143           /*
144              snrRedI si now scaled by 80 (minSnrRed) and 4 (ffr_iLog4)
145           */
146 
147           newMinSnr = round16(pow2_xy(snrRed,80*4));
148 
149           psyOutChan->sfbMinSnr[sfbOffs+sfb] = min(newMinSnr, minSnrLimit);
150         }
151       }
152     }
153   }
154 
155 }
156 
157 
158 /********************************************************************************
159 *
160 * function name:initAvoidHoleFlag
161 * description: determine bands where avoid hole is not necessary resp. possible
162 *
163 **********************************************************************************/
initAvoidHoleFlag(Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],PSY_OUT_ELEMENT * psyOutElement,const Word16 nChannels,AH_PARAM * ahParam)164 static void initAvoidHoleFlag(Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
165                               PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
166                               PSY_OUT_ELEMENT* psyOutElement,
167                               const Word16 nChannels,
168                               AH_PARAM *ahParam)
169 {
170   Word16 ch, sfb, sfbGrp, shift;
171   Word32 threshold;
172   Word32* psfbSpreadEn;
173 
174   for (ch=0; ch<nChannels; ch++) {
175     PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
176 
177     if (psyOutChan->windowSequence != SHORT_WINDOW) {
178       for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
179          psfbSpreadEn = psyOutChan->sfbSpreadedEnergy + sfbGrp;
180 		 for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
181 			*psfbSpreadEn = *psfbSpreadEn >> 1;  /* 0.5 */
182 			++psfbSpreadEn;
183         }
184       }
185     }
186     else {
187       for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
188 		psfbSpreadEn = psyOutChan->sfbSpreadedEnergy + sfbGrp;
189         for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
190           *psfbSpreadEn = (*psfbSpreadEn >> 1) + (*psfbSpreadEn >> 3);  /* 0.63 */
191 		  ++psfbSpreadEn;
192         }
193       }
194     }
195   }
196 
197   /* increase minSnr for local peaks, decrease it for valleys */
198   if (ahParam->modifyMinSnr) {
199     for(ch=0; ch<nChannels; ch++) {
200       PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
201 
202       if (psyOutChan->windowSequence != SHORT_WINDOW)
203         threshold = HOLE_THR_LONG;
204       else
205         threshold = HOLE_THR_SHORT;
206 
207       for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
208         Word16 *psfbMinSnr = psyOutChan->sfbMinSnr + sfbGrp;
209 		for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
210           Word32 sfbEn, sfbEnm1, sfbEnp1, avgEn;
211 
212           if (sfb > 0)
213             sfbEnm1 = psyOutChan->sfbEnergy[sfbGrp+sfb-1];
214           else
215             sfbEnm1 = psyOutChan->sfbEnergy[sfbGrp];
216 
217           if (sfb < (psyOutChan->maxSfbPerGroup-1))
218             sfbEnp1 = psyOutChan->sfbEnergy[sfbGrp+sfb+1];
219           else
220             sfbEnp1 = psyOutChan->sfbEnergy[sfbGrp+sfb];
221           avgEn = (sfbEnm1 + sfbEnp1) >> 1;
222           sfbEn = psyOutChan->sfbEnergy[sfbGrp+sfb];
223 
224           if (sfbEn > avgEn && avgEn > 0) {
225             Word32 tmpMinSnr;
226             shift = norm_l(sfbEn);
227 			tmpMinSnr = Div_32(L_mpy_ls(avgEn, minSnrLimit) << shift, sfbEn << shift );
228             tmpMinSnr = max(tmpMinSnr, HOLE_THR_LONG);
229             tmpMinSnr = max(tmpMinSnr, threshold);
230             *psfbMinSnr = min(*psfbMinSnr, tmpMinSnr);
231           }
232           /* valley ? */
233 
234           if ((sfbEn < (avgEn >> 1)) && (sfbEn > 0)) {
235             Word32 tmpMinSnr;
236             Word32 minSnrEn = L_mpy_wx(avgEn, *psfbMinSnr);
237 
238             if(minSnrEn < sfbEn) {
239 			  shift = norm_l(sfbEn);
240               tmpMinSnr = Div_32( minSnrEn << shift, sfbEn<<shift);
241             }
242             else {
243               tmpMinSnr = MAX_16;
244             }
245             tmpMinSnr = min(minSnrLimit, tmpMinSnr);
246 
247             *psfbMinSnr =
248               (min((tmpMinSnr >>  2), mult(*psfbMinSnr, MIN_SNR_COEF)) << 2);
249           }
250 		  psfbMinSnr++;
251         }
252       }
253     }
254   }
255 
256   /* stereo: adapt the minimum requirements sfbMinSnr of mid and
257      side channels */
258 
259   if (nChannels == 2) {
260     PSY_OUT_CHANNEL *psyOutChanM = &psyOutChannel[0];
261     PSY_OUT_CHANNEL *psyOutChanS = &psyOutChannel[1];
262     for (sfb=0; sfb<psyOutChanM->sfbCnt; sfb++) {
263       if (psyOutElement->toolsInfo.msMask[sfb]) {
264         Word32 sfbEnM = psyOutChanM->sfbEnergy[sfb];
265         Word32 sfbEnS = psyOutChanS->sfbEnergy[sfb];
266         Word32 maxSfbEn = max(sfbEnM, sfbEnS);
267         Word32 maxThr = L_mpy_wx(maxSfbEn, psyOutChanM->sfbMinSnr[sfb]) >> 1;
268 
269         if(maxThr >= sfbEnM) {
270           psyOutChanM->sfbMinSnr[sfb] = MAX_16;
271         }
272         else {
273           shift = norm_l(sfbEnM);
274 		  psyOutChanM->sfbMinSnr[sfb] = min(max(psyOutChanM->sfbMinSnr[sfb],
275 			  round16(Div_32(maxThr<<shift, sfbEnM << shift))), minSnrLimit);
276         }
277 
278         if(maxThr >= sfbEnS) {
279           psyOutChanS->sfbMinSnr[sfb] = MAX_16;
280         }
281         else {
282 		  shift = norm_l(sfbEnS);
283           psyOutChanS->sfbMinSnr[sfb] = min(max(psyOutChanS->sfbMinSnr[sfb],
284 			  round16(Div_32(maxThr << shift, sfbEnS << shift))), minSnrLimit);
285         }
286 
287 
288         if (sfbEnM > psyOutChanM->sfbSpreadedEnergy[sfb])
289           psyOutChanS->sfbSpreadedEnergy[sfb] = L_mpy_ls(sfbEnS, MS_THRSPREAD_COEF);
290 
291         if (sfbEnS > psyOutChanS->sfbSpreadedEnergy[sfb])
292           psyOutChanM->sfbSpreadedEnergy[sfb] = L_mpy_ls(sfbEnM, MS_THRSPREAD_COEF);
293       }
294     }
295   }
296 
297 
298   /* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */
299   for(ch=0; ch<nChannels; ch++) {
300     PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
301     for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
302       Word16 *pahFlag = ahFlag[ch] + sfbGrp;
303 	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
304 
305         if ((psyOutChan->sfbSpreadedEnergy[sfbGrp+sfb] > psyOutChan->sfbEnergy[sfbGrp+sfb]) ||
306             (psyOutChan->sfbEnergy[sfbGrp+sfb] <= psyOutChan->sfbThreshold[sfbGrp+sfb]) ||
307             (psyOutChan->sfbMinSnr[sfbGrp+sfb] == MAX_16)) {
308           *pahFlag++ = NO_AH;
309         }
310         else {
311           *pahFlag++ = AH_INACTIVE;
312         }
313       }
314       for (sfb=psyOutChan->maxSfbPerGroup; sfb<psyOutChan->sfbPerGroup; sfb++) {
315         *pahFlag++ = NO_AH;
316       }
317     }
318   }
319 }
320 
321 /********************************************************************************
322 *
323 * function name:calcPeNoAH
324 * description: sum the pe data only for bands where avoid hole is inactive
325 *
326 **********************************************************************************/
calcPeNoAH(Word16 * pe,Word16 * constPart,Word16 * nActiveLines,PE_DATA * peData,Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],const Word16 nChannels)327 static void calcPeNoAH(Word16          *pe,
328                        Word16          *constPart,
329                        Word16          *nActiveLines,
330                        PE_DATA         *peData,
331                        Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
332                        PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
333                        const Word16     nChannels)
334 {
335   Word16 ch, sfb, sfbGrp;
336   int ipe, iconstPart, inActiveLines;
337 
338   ipe = 0;
339   iconstPart = 0;
340   inActiveLines = 0;
341   for(ch=0; ch<nChannels; ch++) {
342     PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
343     PE_CHANNEL_DATA *peChanData = &peData->peChannelData[ch];
344     for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
345       for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
346 
347         if (ahFlag[ch][sfbGrp+sfb] < AH_ACTIVE) {
348           ipe = ipe + peChanData->sfbPe[sfbGrp+sfb];
349           iconstPart = iconstPart + peChanData->sfbConstPart[sfbGrp+sfb];
350           inActiveLines = inActiveLines + peChanData->sfbNActiveLines[sfbGrp+sfb];
351         }
352       }
353     }
354   }
355 
356   *pe = saturate(ipe);
357   *constPart = saturate(iconstPart);
358   *nActiveLines = saturate(inActiveLines);
359 }
360 
361 /********************************************************************************
362 *
363 * function name:reduceThresholds
364 * description: apply reduction formula
365 *
366 **********************************************************************************/
reduceThresholds(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],const Word16 nChannels,const Word32 redVal)367 static void reduceThresholds(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
368                              Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
369                              Word32           thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
370                              const Word16     nChannels,
371                              const Word32     redVal)
372 {
373   Word32 sfbThrReduced;
374   Word32 *psfbEn, *psfbThr;
375   Word16 ch, sfb, sfbGrp;
376 
377   for(ch=0; ch<nChannels; ch++) {
378     PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
379     for(sfbGrp=0; sfbGrp<psyOutChan->sfbCnt; sfbGrp+=psyOutChan->sfbPerGroup) {
380  	  psfbEn  = psyOutChan->sfbEnergy + sfbGrp;
381       psfbThr = psyOutChan->sfbThreshold + sfbGrp;
382 	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
383 
384         if (*psfbEn > *psfbThr) {
385           /* threshold reduction formula */
386           Word32 tmp = thrExp[ch][sfbGrp+sfb] + redVal;
387           tmp = fixmul(tmp, tmp);
388           sfbThrReduced = fixmul(tmp, tmp);
389           /* avoid holes */
390           tmp = L_mpy_ls(*psfbEn, psyOutChan->sfbMinSnr[sfbGrp+sfb]);
391 
392           if ((sfbThrReduced > tmp) &&
393               (ahFlag[ch][sfbGrp+sfb] != NO_AH)){
394             sfbThrReduced = max(tmp, *psfbThr);
395             ahFlag[ch][sfbGrp+sfb] = AH_ACTIVE;
396           }
397 		  *psfbThr = sfbThrReduced;
398         }
399 
400 		psfbEn++;  psfbThr++;
401       }
402     }
403   }
404 }
405 
406 
407 /********************************************************************************
408 *
409 * function name:correctThresh
410 * description: if pe difference deltaPe between desired pe and real pe is small enough,
411 *             the difference can be distributed among the scale factor bands.
412 *
413 **********************************************************************************/
correctThresh(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],PE_DATA * peData,Word32 thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],const Word32 redVal,const Word16 nChannels,const Word32 deltaPe)414 static void correctThresh(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
415                           Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
416                           PE_DATA          *peData,
417                           Word32           thrExp[MAX_CHANNELS][MAX_GROUPED_SFB],
418                           const Word32     redVal,
419                           const Word16     nChannels,
420                           const Word32     deltaPe)
421 {
422   Word16 ch, sfb, sfbGrp,shift;
423   PSY_OUT_CHANNEL *psyOutChan;
424   PE_CHANNEL_DATA *peChanData;
425   Word32 deltaSfbPe;
426   Word32 normFactor;
427   Word32 *psfbPeFactors;
428   Word16 *psfbNActiveLines, *pahFlag;
429   Word32 sfbEn, sfbThr;
430   Word32 sfbThrReduced;
431 
432   /* for each sfb calc relative factors for pe changes */
433   normFactor = 1;
434   for(ch=0; ch<nChannels; ch++) {
435     psyOutChan = &psyOutChannel[ch];
436     peChanData = &peData->peChannelData[ch];
437     for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
438       psfbPeFactors = peData->sfbPeFactors[ch] + sfbGrp;
439 	  psfbNActiveLines = peChanData->sfbNActiveLines + sfbGrp;
440 	  pahFlag = ahFlag[ch] + sfbGrp;
441 	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
442         Word32 redThrExp = thrExp[ch][sfbGrp+sfb] + redVal;
443 
444         if (((*pahFlag < AH_ACTIVE) || (deltaPe > 0)) && (redThrExp > 0) && (redThrExp >= *psfbNActiveLines)) {
445 
446           *psfbPeFactors = (*psfbNActiveLines) * (0x7fffffff / redThrExp);
447           normFactor = L_add(normFactor, *psfbPeFactors);
448         }
449         else {
450           *psfbPeFactors = 0;
451         }
452 		psfbPeFactors++;
453 		pahFlag++; psfbNActiveLines++;
454       }
455     }
456   }
457 
458 
459   /* calculate new thresholds */
460   for(ch=0; ch<nChannels; ch++) {
461     psyOutChan = &psyOutChannel[ch];
462     peChanData = &peData->peChannelData[ch];
463     for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
464       psfbPeFactors = peData->sfbPeFactors[ch] + sfbGrp;
465 	  psfbNActiveLines = peChanData->sfbNActiveLines + sfbGrp;
466 	  pahFlag = ahFlag[ch] + sfbGrp;
467 	  for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
468         /* pe difference for this sfb */
469         deltaSfbPe = *psfbPeFactors * deltaPe;
470 
471 		/* thr3(n) = thr2(n)*2^deltaSfbPe/b(n) */
472         if (*psfbNActiveLines > 0 && (normFactor* (*psfbNActiveLines)) != 0) {
473           /* new threshold */
474           Word32 thrFactor;
475           sfbEn  = psyOutChan->sfbEnergy[sfbGrp+sfb];
476           sfbThr = psyOutChan->sfbThreshold[sfbGrp+sfb];
477 
478            if(deltaSfbPe >= 0){
479             /*
480               reduce threshold
481             */
482             thrFactor = pow2_xy(L_negate(deltaSfbPe), (normFactor* (*psfbNActiveLines)));
483 
484             sfbThrReduced = L_mpy_ls(sfbThr, round16(thrFactor));
485           }
486           else {
487             /*
488               increase threshold
489             */
490             thrFactor = pow2_xy(deltaSfbPe, (normFactor * (*psfbNActiveLines)));
491 
492 
493             if(thrFactor > sfbThr) {
494               shift = norm_l(thrFactor);
495 			  sfbThrReduced = Div_32( sfbThr << shift, thrFactor<<shift );
496             }
497             else {
498               sfbThrReduced = MAX_32;
499             }
500 
501           }
502 
503           /* avoid hole */
504           sfbEn = L_mpy_ls(sfbEn, psyOutChan->sfbMinSnr[sfbGrp+sfb]);
505 
506           if ((sfbThrReduced > sfbEn) &&
507               (*pahFlag == AH_INACTIVE)) {
508             sfbThrReduced = max(sfbEn, sfbThr);
509             *pahFlag = AH_ACTIVE;
510           }
511 
512           psyOutChan->sfbThreshold[sfbGrp+sfb] = sfbThrReduced;
513         }
514 
515 		pahFlag++; psfbNActiveLines++; psfbPeFactors++;
516       }
517     }
518   }
519 }
520 
521 
522 /********************************************************************************
523 *
524 * function name:reduceMinSnr
525 * description: if the desired pe can not be reached, reduce pe by reducing minSnr
526 *
527 **********************************************************************************/
reduceMinSnr(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],PE_DATA * peData,Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],const Word16 nChannels,const Word16 desiredPe)528 static void reduceMinSnr(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
529                          PE_DATA         *peData,
530                          Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
531                          const Word16     nChannels,
532                          const Word16     desiredPe)
533 {
534   Word16 ch, sfb, sfbSubWin;
535   Word16 deltaPe;
536 
537   /* start at highest freq down to 0 */
538   sfbSubWin = psyOutChannel[0].maxSfbPerGroup;
539   while (peData->pe > desiredPe && sfbSubWin > 0) {
540 
541     sfbSubWin = sfbSubWin - 1;
542     /* loop over all subwindows */
543     for (sfb=sfbSubWin; sfb<psyOutChannel[0].sfbCnt;
544         sfb+=psyOutChannel[0].sfbPerGroup) {
545       /* loop over all channels */
546 		PE_CHANNEL_DATA* peChan = peData->peChannelData;
547 		PSY_OUT_CHANNEL* psyOutCh = psyOutChannel;
548 		for (ch=0; ch<nChannels; ch++) {
549         if (ahFlag[ch][sfb] != NO_AH &&
550             psyOutCh->sfbMinSnr[sfb] < minSnrLimit) {
551           psyOutCh->sfbMinSnr[sfb] = minSnrLimit;
552           psyOutCh->sfbThreshold[sfb] =
553             L_mpy_ls(psyOutCh->sfbEnergy[sfb], psyOutCh->sfbMinSnr[sfb]);
554 
555           /* calc new pe */
556           deltaPe = ((peChan->sfbNLines4[sfb] + (peChan->sfbNLines4[sfb] >> 1)) >> 2) -
557               peChan->sfbPe[sfb];
558           peData->pe = peData->pe + deltaPe;
559           peChan->pe = peChan->pe + deltaPe;
560         }
561 		peChan += 1; psyOutCh += 1;
562       }
563       /* stop if enough has been saved */
564 
565       if (peData->pe <= desiredPe)
566         break;
567     }
568   }
569 }
570 
571 /********************************************************************************
572 *
573 * function name:allowMoreHoles
574 * description: if the desired pe can not be reached, some more scalefactor bands
575 *              have to be quantized to zero
576 *
577 **********************************************************************************/
allowMoreHoles(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],PSY_OUT_ELEMENT * psyOutElement,PE_DATA * peData,Word16 ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],const AH_PARAM * ahParam,const Word16 nChannels,const Word16 desiredPe)578 static void allowMoreHoles(PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
579                            PSY_OUT_ELEMENT *psyOutElement,
580                            PE_DATA         *peData,
581                            Word16           ahFlag[MAX_CHANNELS][MAX_GROUPED_SFB],
582                            const AH_PARAM  *ahParam,
583                            const Word16     nChannels,
584                            const Word16     desiredPe)
585 {
586   Word16 ch, sfb;
587   Word16 actPe, shift;
588 
589   actPe = peData->pe;
590 
591   /* for MS allow hole in the channel with less energy */
592 
593   if (nChannels==2 &&
594       psyOutChannel[0].windowSequence==psyOutChannel[1].windowSequence) {
595     PSY_OUT_CHANNEL *psyOutChanL = &psyOutChannel[0];
596     PSY_OUT_CHANNEL *psyOutChanR = &psyOutChannel[1];
597     for (sfb=0; sfb<psyOutChanL->sfbCnt; sfb++) {
598       Word32 minEn;
599 
600       if (psyOutElement->toolsInfo.msMask[sfb]) {
601         /* allow hole in side channel ? */
602         minEn = L_mpy_ls(psyOutChanL->sfbEnergy[sfb], (minSnrLimit * psyOutChanL->sfbMinSnr[sfb]) >> 16);
603 
604         if (ahFlag[1][sfb] != NO_AH &&
605             minEn > psyOutChanR->sfbEnergy[sfb]) {
606           ahFlag[1][sfb] = NO_AH;
607           psyOutChanR->sfbThreshold[sfb] = L_add(psyOutChanR->sfbEnergy[sfb], psyOutChanR->sfbEnergy[sfb]);
608           actPe = actPe - peData->peChannelData[1].sfbPe[sfb];
609         }
610         /* allow hole in mid channel ? */
611         else {
612         minEn = L_mpy_ls(psyOutChanR->sfbEnergy[sfb], (minSnrLimit * psyOutChanR->sfbMinSnr[sfb]) >> 16);
613 
614           if (ahFlag[0][sfb]!= NO_AH &&
615               minEn > psyOutChanL->sfbEnergy[sfb]) {
616             ahFlag[0][sfb] = NO_AH;
617             psyOutChanL->sfbThreshold[sfb] = L_add(psyOutChanL->sfbEnergy[sfb], psyOutChanL->sfbEnergy[sfb]);
618             actPe = actPe - peData->peChannelData[0].sfbPe[sfb];
619           }
620         }
621 
622         if (actPe < desiredPe)
623           break;
624       }
625     }
626   }
627 
628   /* subsequently erase bands */
629   if (actPe > desiredPe) {
630     Word16 startSfb[2];
631     Word32 avgEn, minEn;
632     Word16 ahCnt;
633     Word16 enIdx;
634     Word16 enDiff;
635     Word32 en[4];
636     Word16 minSfb, maxSfb;
637     Flag   done;
638 
639     /* do not go below startSfb */
640     for (ch=0; ch<nChannels; ch++) {
641 
642       if (psyOutChannel[ch].windowSequence != SHORT_WINDOW)
643         startSfb[ch] = ahParam->startSfbL;
644       else
645         startSfb[ch] = ahParam->startSfbS;
646     }
647 
648     avgEn = 0;
649     minEn = MAX_32;
650     ahCnt = 0;
651     for (ch=0; ch<nChannels; ch++) {
652       PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
653       for (sfb=startSfb[ch]; sfb<psyOutChan->sfbCnt; sfb++) {
654 
655         if ((ahFlag[ch][sfb] != NO_AH) &&
656             (psyOutChan->sfbEnergy[sfb] > psyOutChan->sfbThreshold[sfb])) {
657           minEn = min(minEn, psyOutChan->sfbEnergy[sfb]);
658           avgEn = L_add(avgEn, psyOutChan->sfbEnergy[sfb]);
659           ahCnt++;
660         }
661       }
662     }
663 
664     if(ahCnt) {
665       Word32 iahCnt;
666       shift = norm_l(ahCnt);
667 	  iahCnt = Div_32( 1 << shift, ahCnt << shift );
668       avgEn = fixmul(avgEn, iahCnt);
669     }
670 
671     enDiff = iLog4(avgEn) - iLog4(minEn);
672     /* calc some energy borders between minEn and avgEn */
673     for (enIdx=0; enIdx<4; enIdx++) {
674       Word32 enFac;
675       enFac = ((6-(enIdx << 1)) * enDiff);
676       en[enIdx] = fixmul(avgEn, pow2_xy(L_negate(enFac),7*4));
677     }
678 
679     /* start with lowest energy border at highest sfb */
680     maxSfb = psyOutChannel[0].sfbCnt - 1;
681     minSfb = startSfb[0];
682 
683     if (nChannels == 2) {
684       maxSfb = max(maxSfb, (psyOutChannel[1].sfbCnt - 1));
685       minSfb = min(minSfb, startSfb[1]);
686     }
687 
688     sfb = maxSfb;
689     enIdx = 0;
690     done = 0;
691     while (!done) {
692 
693       for (ch=0; ch<nChannels; ch++) {
694         PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
695 
696         if (sfb>=startSfb[ch] && sfb<psyOutChan->sfbCnt) {
697           /* sfb energy below border ? */
698 
699           if (ahFlag[ch][sfb] != NO_AH && psyOutChan->sfbEnergy[sfb] < en[enIdx]){
700             /* allow hole */
701             ahFlag[ch][sfb] = NO_AH;
702             psyOutChan->sfbThreshold[sfb] = L_add(psyOutChan->sfbEnergy[sfb], psyOutChan->sfbEnergy[sfb]);
703             actPe = actPe - peData->peChannelData[ch].sfbPe[sfb];
704           }
705 
706           if (actPe < desiredPe) {
707             done = 1;
708             break;
709           }
710         }
711       }
712       sfb = sfb - 1;
713 
714       if (sfb < minSfb) {
715         /* restart with next energy border */
716         sfb = maxSfb;
717         enIdx = enIdx + 1;
718 
719         if (enIdx - 4 >= 0)
720           done = 1;
721       }
722     }
723   }
724 }
725 
726 /********************************************************************************
727 *
728 * function name:adaptThresholdsToPe
729 * description: two guesses for the reduction value and one final correction of the
730 *              thresholds
731 *
732 **********************************************************************************/
adaptThresholdsToPe(PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],PSY_OUT_ELEMENT * psyOutElement,Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],PE_DATA * peData,const Word16 nChannels,const Word16 desiredPe,AH_PARAM * ahParam,MINSNR_ADAPT_PARAM * msaParam)733 static void adaptThresholdsToPe(PSY_OUT_CHANNEL     psyOutChannel[MAX_CHANNELS],
734                                 PSY_OUT_ELEMENT    *psyOutElement,
735                                 Word16              logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
736                                 PE_DATA            *peData,
737                                 const Word16        nChannels,
738                                 const Word16        desiredPe,
739                                 AH_PARAM           *ahParam,
740                                 MINSNR_ADAPT_PARAM *msaParam)
741 {
742   Word16 noRedPe, redPe, redPeNoAH;
743   Word16 constPart, constPartNoAH;
744   Word16 nActiveLines, nActiveLinesNoAH;
745   Word16 desiredPeNoAH;
746   Word32 redVal, avgThrExp;
747   Word32 iter;
748 
749   calcThreshExp(peData->thrExp, psyOutChannel, nChannels);
750 
751   adaptMinSnr(psyOutChannel, logSfbEnergy, msaParam, nChannels);
752 
753   initAvoidHoleFlag(peData->ahFlag, psyOutChannel, psyOutElement, nChannels, ahParam);
754 
755   noRedPe = peData->pe;
756   constPart = peData->constPart;
757   nActiveLines = peData->nActiveLines;
758 
759   /* first guess of reduction value t^0.25 = 2^((a-pen)/4*b) */
760   avgThrExp = pow2_xy((constPart - noRedPe), (nActiveLines << 2));
761 
762   /* r1 = 2^((a-per)/4*b) - t^0.25 */
763   redVal = pow2_xy((constPart - desiredPe), (nActiveLines << 2)) - avgThrExp;
764 
765   /* reduce thresholds */
766   reduceThresholds(psyOutChannel, peData->ahFlag, peData->thrExp, nChannels, redVal);
767 
768   /* pe after first guess */
769   calcSfbPe(peData, psyOutChannel, nChannels);
770   redPe = peData->pe;
771 
772   iter = 0;
773   do {
774     /* pe for bands where avoid hole is inactive */
775     calcPeNoAH(&redPeNoAH, &constPartNoAH, &nActiveLinesNoAH,
776                peData, peData->ahFlag, psyOutChannel, nChannels);
777 
778     desiredPeNoAH = desiredPe -(redPe - redPeNoAH);
779 
780     if (desiredPeNoAH < 0) {
781       desiredPeNoAH = 0;
782     }
783 
784     /* second guess */
785 
786     if (nActiveLinesNoAH > 0) {
787 
788 		avgThrExp = pow2_xy((constPartNoAH - redPeNoAH), (nActiveLinesNoAH << 2));
789 
790 		redVal = (redVal + pow2_xy((constPartNoAH - desiredPeNoAH), (nActiveLinesNoAH << 2))) - avgThrExp;
791 
792 		/* reduce thresholds */
793 		reduceThresholds(psyOutChannel, peData->ahFlag, peData->thrExp, nChannels, redVal);
794     }
795 
796     calcSfbPe(peData, psyOutChannel, nChannels);
797     redPe = peData->pe;
798 
799     iter = iter+1;
800 
801   } while ((20 * abs_s(redPe - desiredPe) > desiredPe) && (iter < 2));
802 
803 
804   if ((100 * redPe < 115 * desiredPe)) {
805     correctThresh(psyOutChannel, peData->ahFlag, peData, peData->thrExp, redVal,
806                   nChannels, desiredPe - redPe);
807   }
808   else {
809     Word16 desiredPe105 = (105 * desiredPe) / 100;
810     reduceMinSnr(psyOutChannel, peData, peData->ahFlag,
811                  nChannels, desiredPe105);
812     allowMoreHoles(psyOutChannel, psyOutElement, peData, peData->ahFlag,
813                    ahParam, nChannels, desiredPe105);
814   }
815 }
816 
817 
818 /*****************************************************************************
819 *
820 * function name: calcBitSave
821 * description:  Calculates percentage of bit save, see figure below
822 * returns:
823 * input:        parameters and bitres-fullness
824 * output:       percentage of bit save
825 *
826 *****************************************************************************/
calcBitSave(Word16 fillLevel,const Word16 clipLow,const Word16 clipHigh,const Word16 minBitSave,const Word16 maxBitSave)827 static Word16 calcBitSave(Word16 fillLevel,
828                           const Word16 clipLow,
829                           const Word16 clipHigh,
830                           const Word16 minBitSave,
831                           const Word16 maxBitSave)
832 {
833   Word16 bitsave = 0;
834 
835   fillLevel = max(fillLevel, clipLow);
836   fillLevel = min(fillLevel, clipHigh);
837 
838   if(clipHigh-clipLow)
839   bitsave = (maxBitSave - (((maxBitSave-minBitSave)*(fillLevel-clipLow))/
840                               (clipHigh-clipLow)));
841 
842   return (bitsave);
843 }
844 
845 
846 
847 /*****************************************************************************
848 *
849 * function name: calcBitSpend
850 * description:  Calculates percentage of bit spend, see figure below
851 * returns:
852 * input:        parameters and bitres-fullness
853 * output:       percentage of bit spend
854 *
855 *****************************************************************************/
calcBitSpend(Word16 fillLevel,const Word16 clipLow,const Word16 clipHigh,const Word16 minBitSpend,const Word16 maxBitSpend)856 static Word16 calcBitSpend(Word16 fillLevel,
857                            const Word16 clipLow,
858                            const Word16 clipHigh,
859                            const Word16 minBitSpend,
860                            const Word16 maxBitSpend)
861 {
862   Word16 bitspend = 1;
863 
864   fillLevel = max(fillLevel, clipLow);
865   fillLevel = min(fillLevel, clipHigh);
866 
867   if(clipHigh-clipLow)
868   bitspend = (minBitSpend + ((maxBitSpend - minBitSpend)*(fillLevel - clipLow) /
869                                 (clipHigh-clipLow)));
870 
871   return (bitspend);
872 }
873 
874 
875 /*****************************************************************************
876 *
877 * function name: adjustPeMinMax()
878 * description:  adjusts peMin and peMax parameters over time
879 * returns:
880 * input:        current pe, peMin, peMax
881 * output:       adjusted peMin/peMax
882 *
883 *****************************************************************************/
adjustPeMinMax(const Word16 currPe,Word16 * peMin,Word16 * peMax)884 static void adjustPeMinMax(const Word16 currPe,
885                            Word16      *peMin,
886                            Word16      *peMax)
887 {
888   Word16 minFacHi, maxFacHi, minFacLo, maxFacLo;
889   Word16 diff;
890   Word16 minDiff = extract_l(currPe / 6);
891   minFacHi = 30;
892   maxFacHi = 100;
893   minFacLo = 14;
894   maxFacLo = 7;
895 
896   diff = currPe - *peMax ;
897 
898   if (diff > 0) {
899     *peMin = *peMin + ((diff * minFacHi) / 100);
900     *peMax = *peMax + ((diff * maxFacHi) / 100);
901   } else {
902     diff = *peMin - currPe;
903 
904     if (diff > 0) {
905       *peMin = *peMin - ((diff * minFacLo) / 100);
906       *peMax = *peMax - ((diff * maxFacLo) / 100);
907     } else {
908       *peMin = *peMin + ((currPe - *peMin) * minFacHi / 100);
909       *peMax = *peMax - ((*peMax - currPe) * maxFacLo / 100);
910     }
911   }
912 
913 
914   if ((*peMax - *peMin) < minDiff) {
915     Word16 partLo, partHi;
916 
917     partLo = max(0, (currPe - *peMin));
918     partHi = max(0, (*peMax - currPe));
919 
920     *peMax = currPe + ((partHi * minDiff) / (partLo + partHi));
921     *peMin = currPe - ((partLo * minDiff) / (partLo + partHi));
922     *peMin = max(0, *peMin);
923   }
924 }
925 
926 
927 /*****************************************************************************
928 *
929 * function name: BitresCalcBitFac
930 * description:  calculates factor of spending bits for one frame
931 *                1.0 : take all frame dynpart bits
932 *                >1.0 : take all frame dynpart bits + bitres
933 *                <1.0 : put bits in bitreservoir
934 *  returns:      BitFac*100
935 *  input:        bitres-fullness, pe, blockType, parameter-settings
936 *  output:
937 *
938 *****************************************************************************/
bitresCalcBitFac(const Word16 bitresBits,const Word16 maxBitresBits,const Word16 pe,const Word16 windowSequence,const Word16 avgBits,const Word16 maxBitFac,ADJ_THR_STATE * AdjThr,ATS_ELEMENT * adjThrChan)939 static Word16 bitresCalcBitFac( const Word16   bitresBits,
940                                 const Word16   maxBitresBits,
941                                 const Word16   pe,
942                                 const Word16   windowSequence,
943                                 const Word16   avgBits,
944                                 const Word16   maxBitFac,
945                                 ADJ_THR_STATE *AdjThr,
946                                 ATS_ELEMENT   *adjThrChan)
947 {
948   BRES_PARAM *bresParam;
949   Word16 pex;
950   Word16 fillLevel;
951   Word16 bitSave, bitSpend, bitresFac;
952 
953   fillLevel = extract_l((100* bitresBits) / maxBitresBits);
954 
955   if (windowSequence != SHORT_WINDOW)
956     bresParam = &(AdjThr->bresParamLong);
957   else
958     bresParam = &(AdjThr->bresParamShort);
959 
960   pex = max(pe, adjThrChan->peMin);
961   pex = min(pex,adjThrChan->peMax);
962 
963   bitSave = calcBitSave(fillLevel,
964                         bresParam->clipSaveLow, bresParam->clipSaveHigh,
965                         bresParam->minBitSave, bresParam->maxBitSave);
966 
967   bitSpend = calcBitSpend(fillLevel,
968                           bresParam->clipSpendLow, bresParam->clipSpendHigh,
969                           bresParam->minBitSpend, bresParam->maxBitSpend);
970 
971   if(adjThrChan->peMax != adjThrChan->peMin)
972 	bitresFac = (100 - bitSave) + extract_l(((bitSpend + bitSave) * (pex - adjThrChan->peMin)) /
973                     (adjThrChan->peMax - adjThrChan->peMin));
974   else
975 	bitresFac = 0x7fff;
976 
977   bitresFac = min(bitresFac,
978                     (100-30 + extract_l((100 * bitresBits) / avgBits)));
979 
980   bitresFac = min(bitresFac, maxBitFac);
981 
982   adjustPeMinMax(pe, &adjThrChan->peMin, &adjThrChan->peMax);
983 
984   return bitresFac;
985 }
986 
987 /*****************************************************************************
988 *
989 * function name: AdjThrInit
990 * description:  init thresholds parameter
991 *
992 *****************************************************************************/
AdjThrInit(ADJ_THR_STATE * hAdjThr,const Word32 meanPe,Word32 chBitrate)993 void AdjThrInit(ADJ_THR_STATE *hAdjThr,
994                 const Word32   meanPe,
995                 Word32         chBitrate)
996 {
997   ATS_ELEMENT* atsElem = &hAdjThr->adjThrStateElem;
998   MINSNR_ADAPT_PARAM *msaParam = &atsElem->minSnrAdaptParam;
999 
1000   /* common for all elements: */
1001   /* parameters for bitres control */
1002   hAdjThr->bresParamLong.clipSaveLow   =  20;
1003   hAdjThr->bresParamLong.clipSaveHigh  =  95;
1004   hAdjThr->bresParamLong.minBitSave    =  -5;
1005   hAdjThr->bresParamLong.maxBitSave    =  30;
1006   hAdjThr->bresParamLong.clipSpendLow  =  20;
1007   hAdjThr->bresParamLong.clipSpendHigh =  95;
1008   hAdjThr->bresParamLong.minBitSpend   = -10;
1009   hAdjThr->bresParamLong.maxBitSpend   =  40;
1010 
1011   hAdjThr->bresParamShort.clipSaveLow   =  20;
1012   hAdjThr->bresParamShort.clipSaveHigh  =  75;
1013   hAdjThr->bresParamShort.minBitSave    =   0;
1014   hAdjThr->bresParamShort.maxBitSave    =  20;
1015   hAdjThr->bresParamShort.clipSpendLow  =  20;
1016   hAdjThr->bresParamShort.clipSpendHigh =  75;
1017   hAdjThr->bresParamShort.minBitSpend   = -5;
1018   hAdjThr->bresParamShort.maxBitSpend   =  50;
1019 
1020   /* specific for each element: */
1021 
1022   /* parameters for bitres control */
1023   atsElem->peMin = extract_l(((80*meanPe) / 100));
1024   atsElem->peMax = extract_l(((120*meanPe) / 100));
1025 
1026   /* additional pe offset to correct pe2bits for low bitrates */
1027   atsElem->peOffset = 0;
1028   if (chBitrate < 32000) {
1029     atsElem->peOffset = max(50, (100 - extract_l((100 * chBitrate) / 32000)));
1030   }
1031 
1032   /* avoid hole parameters */
1033   if (chBitrate > 20000) {
1034     atsElem->ahParam.modifyMinSnr = TRUE;
1035     atsElem->ahParam.startSfbL = 15;
1036     atsElem->ahParam.startSfbS = 3;
1037   }
1038   else {
1039     atsElem->ahParam.modifyMinSnr = FALSE;
1040     atsElem->ahParam.startSfbL = 0;
1041     atsElem->ahParam.startSfbS = 0;
1042   }
1043 
1044   /* minSnr adaptation */
1045   /* maximum reduction of minSnr goes down to minSnr^maxRed */
1046   msaParam->maxRed = 0x20000000;     /* *0.25f */
1047   /* start adaptation of minSnr for avgEn/sfbEn > startRatio */
1048   msaParam->startRatio = 0x0ccccccd; /* 10 */
1049   /* maximum minSnr reduction to minSnr^maxRed is reached for
1050      avgEn/sfbEn >= maxRatio */
1051   msaParam->maxRatio =  0x0020c49c; /* 1000 */
1052   /* helper variables to interpolate minSnr reduction for
1053      avgEn/sfbEn between startRatio and maxRatio */
1054 
1055   msaParam->redRatioFac = 0xfb333333; /* -0.75/20 */
1056 
1057   msaParam->redOffs = 0x30000000;  /* msaParam->redRatioFac * 10*log10(msaParam->startRatio) */
1058 
1059 
1060   /* pe correction */
1061   atsElem->peLast = 0;
1062   atsElem->dynBitsLast = 0;
1063   atsElem->peCorrectionFactor = 100; /* 1.0 */
1064 
1065 }
1066 
1067 /*****************************************************************************
1068 *
1069 * function name: calcPeCorrection
1070 * description:  calculates the desired perceptual entropy factor
1071 *				It is between 0.85 and 1.15
1072 *
1073 *****************************************************************************/
calcPeCorrection(Word16 * correctionFac,const Word16 peAct,const Word16 peLast,const Word16 bitsLast)1074 static void calcPeCorrection(Word16 *correctionFac,
1075                              const Word16 peAct,
1076                              const Word16 peLast,
1077                              const Word16 bitsLast)
1078 {
1079   Word32 peAct100 = 100 * peAct;
1080   Word32 peLast100 = 100 * peLast;
1081   Word16 peBitsLast = bits2pe(bitsLast);
1082 
1083   if ((bitsLast > 0) &&
1084       (peAct100 < (150 * peLast)) &&  (peAct100 > (70 * peLast)) &&
1085       ((120 * peBitsLast) > peLast100 ) && (( 65 * peBitsLast) < peLast100))
1086     {
1087       Word16 newFac = (100 * peLast) / peBitsLast;
1088       /* dead zone */
1089 
1090       if (newFac < 100) {
1091         newFac = min(((110 * newFac) / 100), 100);
1092         newFac = max(newFac, 85);
1093       }
1094       else {
1095         newFac = max(((90 * newFac) / 100), 100);
1096         newFac = min(newFac, 115);
1097       }
1098 
1099       if ((newFac > 100 && *correctionFac < 100) ||
1100           (newFac < 100 && *correctionFac > 100)) {
1101         *correctionFac = 100;
1102       }
1103       /* faster adaptation towards 1.0, slower in the other direction */
1104 
1105       if ((*correctionFac < 100 && newFac < *correctionFac) ||
1106           (*correctionFac > 100 && newFac > *correctionFac))
1107         *correctionFac = (85 * *correctionFac + 15 * newFac) / 100;
1108       else
1109         *correctionFac = (70 * *correctionFac + 30 * newFac) / 100;
1110       *correctionFac = min(*correctionFac, 115);
1111       *correctionFac = max(*correctionFac, 85);
1112     }
1113   else {
1114     *correctionFac = 100;
1115   }
1116 }
1117 
1118 /********************************************************************************
1119 *
1120 * function name: AdjustThresholds
1121 * description:  Adjust thresholds to the desired bitrate
1122 *
1123 **********************************************************************************/
AdjustThresholds(ADJ_THR_STATE * adjThrState,ATS_ELEMENT * AdjThrStateElement,PSY_OUT_CHANNEL psyOutChannel[MAX_CHANNELS],PSY_OUT_ELEMENT * psyOutElement,Word16 * chBitDistribution,Word16 logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],Word16 sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB],QC_OUT_ELEMENT * qcOE,ELEMENT_BITS * elBits,const Word16 nChannels,const Word16 maxBitFac)1124 void AdjustThresholds(ADJ_THR_STATE   *adjThrState,
1125                       ATS_ELEMENT     *AdjThrStateElement,
1126                       PSY_OUT_CHANNEL  psyOutChannel[MAX_CHANNELS],
1127                       PSY_OUT_ELEMENT *psyOutElement,
1128                       Word16          *chBitDistribution,
1129                       Word16           logSfbEnergy[MAX_CHANNELS][MAX_GROUPED_SFB],
1130                       Word16           sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB],
1131                       QC_OUT_ELEMENT  *qcOE,
1132 					  ELEMENT_BITS	  *elBits,
1133 					  const Word16     nChannels,
1134                       const Word16     maxBitFac)
1135 {
1136   PE_DATA peData;
1137   Word16 noRedPe, grantedPe, grantedPeCorr;
1138   Word16 curWindowSequence;
1139   Word16 bitFactor;
1140   Word16 avgBits = (elBits->averageBits - (qcOE->staticBitsUsed + qcOE->ancBitsUsed));
1141   Word16 bitresBits = elBits->bitResLevel;
1142   Word16 maxBitresBits = elBits->maxBits;
1143   Word16 sideInfoBits = (qcOE->staticBitsUsed + qcOE->ancBitsUsed);
1144   Word16 ch;
1145   memset(&peData, 0, sizeof(peData));
1146 
1147   prepareSfbPe(&peData, psyOutChannel, logSfbEnergy, sfbNRelevantLines, nChannels, AdjThrStateElement->peOffset);
1148 
1149   /* pe without reduction */
1150   calcSfbPe(&peData, psyOutChannel, nChannels);
1151   noRedPe = peData.pe;
1152 
1153 
1154   curWindowSequence = LONG_WINDOW;
1155 
1156   if (nChannels == 2) {
1157 
1158     if ((psyOutChannel[0].windowSequence == SHORT_WINDOW) ||
1159         (psyOutChannel[1].windowSequence == SHORT_WINDOW)) {
1160       curWindowSequence = SHORT_WINDOW;
1161     }
1162   }
1163   else {
1164     curWindowSequence = psyOutChannel[0].windowSequence;
1165   }
1166 
1167 
1168   /* bit factor */
1169   bitFactor = bitresCalcBitFac(bitresBits, maxBitresBits, noRedPe+5*sideInfoBits,
1170                                curWindowSequence, avgBits, maxBitFac,
1171                                adjThrState,
1172                                AdjThrStateElement);
1173 
1174   /* desired pe */
1175   grantedPe = ((bitFactor * bits2pe(avgBits)) / 100);
1176 
1177   /* correction of pe value */
1178   calcPeCorrection(&(AdjThrStateElement->peCorrectionFactor),
1179                    min(grantedPe, noRedPe),
1180                    AdjThrStateElement->peLast,
1181                    AdjThrStateElement->dynBitsLast);
1182   grantedPeCorr = (grantedPe * AdjThrStateElement->peCorrectionFactor) / 100;
1183 
1184 
1185   if (grantedPeCorr < noRedPe && noRedPe > peData.offset) {
1186     /* calc threshold necessary for desired pe */
1187     adaptThresholdsToPe(psyOutChannel,
1188                         psyOutElement,
1189                         logSfbEnergy,
1190                         &peData,
1191                         nChannels,
1192                         grantedPeCorr,
1193                         &AdjThrStateElement->ahParam,
1194                         &AdjThrStateElement->minSnrAdaptParam);
1195   }
1196 
1197   /* calculate relative distribution */
1198   for (ch=0; ch<nChannels; ch++) {
1199     Word16 peOffsDiff = peData.pe - peData.offset;
1200     chBitDistribution[ch] = 200;
1201 
1202     if (peOffsDiff > 0) {
1203       Word32 temp = 1000 - (nChannels * 200);
1204       chBitDistribution[ch] = chBitDistribution[ch] +
1205 		  (temp * peData.peChannelData[ch].pe) / peOffsDiff;
1206     }
1207   }
1208 
1209   /* store pe */
1210   qcOE->pe = noRedPe;
1211 
1212   /* update last pe */
1213   AdjThrStateElement->peLast = grantedPe;
1214 }
1215 
1216 /********************************************************************************
1217 *
1218 * function name: AdjThrUpdate
1219 * description:  save dynBitsUsed for correction of bits2pe relation
1220 *
1221 **********************************************************************************/
AdjThrUpdate(ATS_ELEMENT * AdjThrStateElement,const Word16 dynBitsUsed)1222 void AdjThrUpdate(ATS_ELEMENT *AdjThrStateElement,
1223                   const Word16 dynBitsUsed)
1224 {
1225   AdjThrStateElement->dynBitsLast = dynBitsUsed;
1226 }
1227 
1228 
1229