~ubuntu-branches/ubuntu/saucy/vo-aacenc/saucy

« back to all changes in this revision

Viewing changes to aacenc/src/adj_thr.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2011-03-29 16:49:56 UTC
  • Revision ID: james.westby@ubuntu.com-20110329164956-k8bf19t3tybn1hh2
Tags: upstream-0.1.0~rc1
ImportĀ upstreamĀ versionĀ 0.1.0~rc1

Show diffs side-by-side

added added

removed removed

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