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:		quantize.c
18
19	Content:	quantization functions
20
21*******************************************************************************/
22
23#include "typedef.h"
24#include "basic_op.h"
25#include "oper_32b.h"
26#include "quantize.h"
27#include "aac_rom.h"
28
29#define MANT_DIGITS 9
30#define MANT_SIZE   (1<<MANT_DIGITS)
31
32static const Word32 XROUND = 0x33e425af; /* final rounding constant (-0.0946f+ 0.5f) */
33
34
35/*****************************************************************************
36*
37* function name:pow34
38* description: calculate $x^{\frac{3}{4}}, for 0.5 < x < 1.0$.
39*
40*****************************************************************************/
41__inline Word32 pow34(Word32 x)
42{
43  /* index table using MANT_DIGITS bits, but mask out the sign bit and the MSB
44     which is always one */
45  return mTab_3_4[(x >> (INT_BITS-2-MANT_DIGITS)) & (MANT_SIZE-1)];
46}
47
48
49/*****************************************************************************
50*
51* function name:quantizeSingleLine
52* description: quantizes spectrum
53*              quaSpectrum = mdctSpectrum^3/4*2^(-(3/16)*gain)
54*
55*****************************************************************************/
56static Word16 quantizeSingleLine(const Word16 gain, const Word32 absSpectrum)
57{
58  Word32 e, minusFinalExp, finalShift;
59  Word32 x;
60  Word16 qua = 0;
61
62
63  if (absSpectrum) {
64    e = norm_l(absSpectrum);
65    x = pow34(absSpectrum << e);
66
67    /* calculate the final fractional exponent times 16 (was 3*(4*e + gain) + (INT_BITS-1)*16) */
68    minusFinalExp = (e << 2) + gain;
69    minusFinalExp = (minusFinalExp << 1) + minusFinalExp;
70    minusFinalExp = minusFinalExp + ((INT_BITS-1) << 4);
71
72    /* separate the exponent into a shift, and a multiply */
73    finalShift = minusFinalExp >> 4;
74
75    if (finalShift < INT_BITS) {
76      x = L_mpy_wx(x, pow2tominusNover16[minusFinalExp & 15]);
77
78      x += XROUND >> (INT_BITS - finalShift);
79
80      /* shift and quantize */
81	  finalShift--;
82
83	  if(finalShift >= 0)
84		  x >>= finalShift;
85	  else
86		  x <<= (-finalShift);
87
88	  qua = saturate(x);
89    }
90  }
91
92  return qua;
93}
94
95/*****************************************************************************
96*
97* function name:quantizeLines
98* description: quantizes spectrum lines
99*              quaSpectrum = mdctSpectrum^3/4*2^(-(3/16)*gain)
100*  input: global gain, number of lines to process, spectral data
101*  output: quantized spectrum
102*
103*****************************************************************************/
104static void quantizeLines(const Word16 gain,
105                          const Word16 noOfLines,
106                          const Word32 *mdctSpectrum,
107                          Word16 *quaSpectrum)
108{
109  Word32 line;
110  Word32 m = gain&3;
111  Word32 g = (gain >> 2) + 4;
112  Word32 mdctSpeL;
113  const Word16 *pquat;
114    /* gain&3 */
115
116  pquat = quantBorders[m];
117
118  g += 16;
119
120  if(g >= 0)
121  {
122	for (line=0; line<noOfLines; line++) {
123	  Word32 qua;
124	  qua = 0;
125
126	  mdctSpeL = mdctSpectrum[line];
127
128	  if (mdctSpeL) {
129		Word32 sa;
130		Word32 saShft;
131
132        sa = L_abs(mdctSpeL);
133        //saShft = L_shr(sa, 16 + g);
134	    saShft = sa >> g;
135
136        if (saShft > pquat[0]) {
137
138          if (saShft < pquat[1]) {
139
140            qua = mdctSpeL>0 ? 1 : -1;
141		  }
142          else {
143
144            if (saShft < pquat[2]) {
145
146              qua = mdctSpeL>0 ? 2 : -2;
147			}
148            else {
149
150              if (saShft < pquat[3]) {
151
152                qua = mdctSpeL>0 ? 3 : -3;
153			  }
154              else {
155                qua = quantizeSingleLine(gain, sa);
156                /* adjust the sign. Since 0 < qua < 1, this cannot overflow. */
157
158                if (mdctSpeL < 0)
159                  qua = -qua;
160			  }
161			}
162		  }
163		}
164	  }
165      quaSpectrum[line] = qua ;
166	}
167  }
168  else
169  {
170	for (line=0; line<noOfLines; line++) {
171	  Word32 qua;
172	  qua = 0;
173
174	  mdctSpeL = mdctSpectrum[line];
175
176	  if (mdctSpeL) {
177		Word32 sa;
178		Word32 saShft;
179
180        sa = L_abs(mdctSpeL);
181        saShft = sa << g;
182
183        if (saShft > pquat[0]) {
184
185          if (saShft < pquat[1]) {
186
187            qua = mdctSpeL>0 ? 1 : -1;
188		  }
189          else {
190
191            if (saShft < pquat[2]) {
192
193              qua = mdctSpeL>0 ? 2 : -2;
194			}
195            else {
196
197              if (saShft < pquat[3]) {
198
199                qua = mdctSpeL>0 ? 3 : -3;
200			  }
201              else {
202                qua = quantizeSingleLine(gain, sa);
203                /* adjust the sign. Since 0 < qua < 1, this cannot overflow. */
204
205                if (mdctSpeL < 0)
206                  qua = -qua;
207			  }
208			}
209		  }
210		}
211	  }
212      quaSpectrum[line] = qua ;
213	}
214  }
215
216}
217
218
219/*****************************************************************************
220*
221* function name:iquantizeLines
222* description: iquantizes spectrum lines without sign
223*              mdctSpectrum = iquaSpectrum^4/3 *2^(0.25*gain)
224* input: global gain, number of lines to process,quantized spectrum
225* output: spectral data
226*
227*****************************************************************************/
228static void iquantizeLines(const Word16 gain,
229                           const Word16 noOfLines,
230                           const Word16 *quantSpectrum,
231                           Word32 *mdctSpectrum)
232{
233  Word32   iquantizermod;
234  Word32   iquantizershift;
235  Word32   line;
236
237  iquantizermod = gain & 3;
238  iquantizershift = gain >> 2;
239
240  for (line=0; line<noOfLines; line++) {
241
242    if( quantSpectrum[line] != 0 ) {
243      Word32 accu;
244      Word32 ex;
245	  Word32 tabIndex;
246      Word32 specExp;
247      Word32 s,t;
248
249      accu = quantSpectrum[line];
250
251      ex = norm_l(accu);
252      accu = accu << ex;
253      specExp = INT_BITS-1 - ex;
254
255      tabIndex = (accu >> (INT_BITS-2-MANT_DIGITS)) & (~MANT_SIZE);
256
257      /* calculate "mantissa" ^4/3 */
258      s = mTab_4_3[tabIndex];
259
260      /* get approperiate exponent multiplier for specExp^3/4 combined with scfMod */
261      t = specExpMantTableComb_enc[iquantizermod][specExp];
262
263      /* multiply "mantissa" ^4/3 with exponent multiplier */
264      accu = MULHIGH(s, t);
265
266      /* get approperiate exponent shifter */
267      specExp = specExpTableComb_enc[iquantizermod][specExp];
268
269      specExp += iquantizershift + 1;
270	  if(specExp >= 0)
271		  mdctSpectrum[line] = accu << specExp;
272	  else
273		  mdctSpectrum[line] = accu >> (-specExp);
274    }
275    else {
276      mdctSpectrum[line] = 0;
277    }
278  }
279}
280
281/*****************************************************************************
282*
283* function name: QuantizeSpectrum
284* description: quantizes the entire spectrum
285* returns:
286* input: number of scalefactor bands to be quantized, ...
287* output: quantized spectrum
288*
289*****************************************************************************/
290void QuantizeSpectrum(Word16 sfbCnt,
291                      Word16 maxSfbPerGroup,
292                      Word16 sfbPerGroup,
293                      Word16 *sfbOffset,
294                      Word32 *mdctSpectrum,
295                      Word16 globalGain,
296                      Word16 *scalefactors,
297                      Word16 *quantizedSpectrum)
298{
299  Word32 sfbOffs, sfb;
300
301  for(sfbOffs=0;sfbOffs<sfbCnt;sfbOffs+=sfbPerGroup) {
302    Word32 sfbNext ;
303    for (sfb = 0; sfb < maxSfbPerGroup; sfb = sfbNext) {
304      Word16 scalefactor = scalefactors[sfbOffs+sfb];
305      /* coalesce sfbs with the same scalefactor */
306      for (sfbNext = sfb+1;
307           sfbNext < maxSfbPerGroup && scalefactor == scalefactors[sfbOffs+sfbNext];
308           sfbNext++) ;
309
310      quantizeLines(globalGain - scalefactor,
311                    sfbOffset[sfbOffs+sfbNext] - sfbOffset[sfbOffs+sfb],
312                    mdctSpectrum + sfbOffset[sfbOffs+sfb],
313                    quantizedSpectrum + sfbOffset[sfbOffs+sfb]);
314    }
315  }
316}
317
318
319/*****************************************************************************
320*
321* function name:calcSfbDist
322* description: quantizes and requantizes lines to calculate distortion
323* input:  number of lines to be quantized, ...
324* output: distortion
325*
326*****************************************************************************/
327Word32 calcSfbDist(const Word32 *spec,
328                   Word16  sfbWidth,
329                   Word16  gain)
330{
331  Word32 line;
332  Word32 dist;
333  Word32 m = gain&3;
334  Word32 g = (gain >> 2) + 4;
335  Word32 g2 = (g << 1) + 1;
336  const Word16 *pquat, *repquat;
337    /* gain&3 */
338
339  pquat = quantBorders[m];
340  repquat = quantRecon[m];
341
342  dist = 0;
343  g += 16;
344  if(g2 < 0 && g >= 0)
345  {
346	  g2 = -g2;
347	  for(line=0; line<sfbWidth; line++) {
348		  if (spec[line]) {
349			  Word32 diff;
350			  Word32 distSingle;
351			  Word32 sa;
352			  Word32 saShft;
353			  sa = L_abs(spec[line]);
354			  //saShft = round16(L_shr(sa, g));
355			  //saShft = L_shr(sa, 16+g);
356			  saShft = sa >> g;
357
358			  if (saShft < pquat[0]) {
359				  distSingle = (saShft * saShft) >> g2;
360			  }
361			  else {
362
363				  if (saShft < pquat[1]) {
364					  diff = saShft - repquat[0];
365					  distSingle = (diff * diff) >> g2;
366				  }
367				  else {
368
369					  if (saShft < pquat[2]) {
370						  diff = saShft - repquat[1];
371						  distSingle = (diff * diff) >> g2;
372					  }
373					  else {
374
375						  if (saShft < pquat[3]) {
376							  diff = saShft - repquat[2];
377							  distSingle = (diff * diff) >> g2;
378						  }
379						  else {
380							  Word16 qua = quantizeSingleLine(gain, sa);
381							  Word32 iqval, diff32;
382							  /* now that we have quantized x, re-quantize it. */
383							  iquantizeLines(gain, 1, &qua, &iqval);
384							  diff32 = sa - iqval;
385							  distSingle = fixmul(diff32, diff32);
386						  }
387					  }
388				  }
389			  }
390
391			  dist = L_add(dist, distSingle);
392		  }
393	  }
394  }
395  else
396  {
397	  for(line=0; line<sfbWidth; line++) {
398		  if (spec[line]) {
399			  Word32 diff;
400			  Word32 distSingle;
401			  Word32 sa;
402			  Word32 saShft;
403			  sa = L_abs(spec[line]);
404			  //saShft = round16(L_shr(sa, g));
405			  saShft = L_shr(sa, g);
406
407			  if (saShft < pquat[0]) {
408				  distSingle = L_shl((saShft * saShft), g2);
409			  }
410			  else {
411
412				  if (saShft < pquat[1]) {
413					  diff = saShft - repquat[0];
414					  distSingle = L_shl((diff * diff), g2);
415				  }
416				  else {
417
418					  if (saShft < pquat[2]) {
419						  diff = saShft - repquat[1];
420						  distSingle = L_shl((diff * diff), g2);
421					  }
422					  else {
423
424						  if (saShft < pquat[3]) {
425							  diff = saShft - repquat[2];
426							  distSingle = L_shl((diff * diff), g2);
427						  }
428						  else {
429							  Word16 qua = quantizeSingleLine(gain, sa);
430							  Word32 iqval, diff32;
431							  /* now that we have quantized x, re-quantize it. */
432							  iquantizeLines(gain, 1, &qua, &iqval);
433							  diff32 = sa - iqval;
434							  distSingle = fixmul(diff32, diff32);
435						  }
436					  }
437				  }
438			  }
439			  dist = L_add(dist, distSingle);
440		  }
441	  }
442  }
443
444  return dist;
445}
446