summaryrefslogtreecommitdiff
path: root/audio_codec/libraac/pns.c (plain)
blob: 179206cbee78f552d80cffbf919405903e957721
1/* ***** BEGIN LICENSE BLOCK *****
2 * Source last modified: $Id: pns.c,v 1.2 2005/03/10 17:01:56 jrecker Exp $
3 *
4 * Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
5 *
6 * The contents of this file, and the files included with this file,
7 * are subject to the current version of the RealNetworks Public
8 * Source License (the "RPSL") available at
9 * http://www.helixcommunity.org/content/rpsl unless you have licensed
10 * the file under the current version of the RealNetworks Community
11 * Source License (the "RCSL") available at
12 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
13 * will apply. You may also obtain the license terms directly from
14 * RealNetworks. You may not use this file except in compliance with
15 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
16 * to this file, the RCSL. Please see the applicable RPSL or RCSL for
17 * the rights, obligations and limitations governing use of the
18 * contents of the file.
19 *
20 * This file is part of the Helix DNA Technology. RealNetworks is the
21 * developer of the Original Code and owns the copyrights in the
22 * portions it created.
23 *
24 * This file, and the files included with this file, is distributed
25 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
26 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
27 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
28 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
29 * ENJOYMENT OR NON-INFRINGEMENT.
30 *
31 * Technology Compatibility Kit Test Suite(s) Location:
32 * http://www.helixcommunity.org/content/tck
33 *
34 * Contributor(s):
35 *
36 * ***** END LICENSE BLOCK ***** */
37
38/**************************************************************************************
39 * Fixed-point HE-AAC decoder
40 * Jon Recker (jrecker@real.com)
41 * February 2005
42 *
43 * pns.c - perceptual noise substitution
44 **************************************************************************************/
45
46#include "coder.h"
47
48#include "assembly.h"
49
50
51/**************************************************************************************
52 * Function: Get32BitVal
53 *
54 * Description: generate 32-bit unsigned random number
55 *
56 * Inputs: last number calculated (seed, first time through)
57 *
58 * Outputs: new number, saved in *last
59 *
60 * Return: 32-bit number, uniformly distributed between [0, 2^32)
61 *
62 * Notes: uses simple linear congruential generator
63 **************************************************************************************/
64static unsigned int Get32BitVal(unsigned int *last)
65{
66 unsigned int r = *last;
67
68 /* use same coefs as MPEG reference code (classic LCG)
69 * use unsigned multiply to force reliable wraparound behavior in C (mod 2^32)
70 */
71 r = (1664525U * r) + 1013904223U;
72 *last = r;
73
74 return r;
75}
76
77/* pow(2, i/4.0) for i = [0,1,2,3], format = Q30 */
78static const int pow14[4] = {
79 0x40000000, 0x4c1bf829, 0x5a82799a, 0x6ba27e65
80};
81
82#define NUM_ITER_INVSQRT 4
83
84#define X0_COEF_2 0xc0000000 /* Q29: -2.0 */
85#define X0_OFF_2 0x60000000 /* Q29: 3.0 */
86#define Q26_3 0x0c000000 /* Q26: 3.0 */
87
88/**************************************************************************************
89 * Function: InvRootR
90 *
91 * Description: use Newton's method to solve for x = 1/sqrt(r)
92 *
93 * Inputs: r in Q30 format, range = [0.25, 1] (normalize inputs to this range)
94 *
95 * Outputs: none
96 *
97 * Return: x = Q29, range = (1, 2)
98 *
99 * Notes: guaranteed to converge and not overflow for any r in this range
100 *
101 * xn+1 = xn - f(xn)/f'(xn)
102 * f(x) = 1/sqrt(r) - x = 0 (find root)
103 * = 1/x^2 - r
104 * f'(x) = -2/x^3
105 *
106 * so xn+1 = xn/2 * (3 - r*xn^2)
107 *
108 * NUM_ITER_INVSQRT = 3, maxDiff = 1.3747e-02
109 * NUM_ITER_INVSQRT = 4, maxDiff = 3.9832e-04
110 **************************************************************************************/
111static int InvRootR(int r)
112{
113 int i, xn, t;
114
115 /* use linear equation for initial guess
116 * x0 = -2*r + 3 (so x0 always >= correct answer in range [0.25, 1))
117 * xn = Q29 (at every step)
118 */
119 xn = (MULSHIFT32(r, X0_COEF_2) << 2) + X0_OFF_2;
120
121 for (i = 0; i < NUM_ITER_INVSQRT; i++) {
122 t = MULSHIFT32(xn, xn); /* Q26 = Q29*Q29 */
123 t = Q26_3 - (MULSHIFT32(r, t) << 2); /* Q26 = Q26 - (Q31*Q26 << 1) */
124 xn = MULSHIFT32(xn, t) << (6 - 1); /* Q29 = (Q29*Q26 << 6), and -1 for division by 2 */
125 }
126
127 /* clip to range (1.0, 2.0)
128 * (because of rounding, this can converge to xn slightly > 2.0 when r is near 0.25)
129 */
130 if (xn >> 30) {
131 xn = (1 << 30) - 1;
132 }
133
134 return xn;
135}
136
137/**************************************************************************************
138 * Function: ScaleNoiseVector
139 *
140 * Description: apply scaling to vector of noise coefficients for one scalefactor band
141 *
142 * Inputs: unscaled coefficients
143 * number of coefficients in vector (one scalefactor band of coefs)
144 * scalefactor for this band (i.e. noise energy)
145 *
146 * Outputs: nVals coefficients in Q(FBITS_OUT_DQ_OFF)
147 *
148 * Return: guard bit mask (OR of abs value of all noise coefs)
149 **************************************************************************************/
150static int ScaleNoiseVector(int *coef, int nVals, int sf)
151{
152 int i, c, spec, energy, sq, scalef, scalei, invSqrtEnergy, z, gbMask;
153
154 energy = 0;
155 for (i = 0; i < nVals; i++) {
156 spec = coef[i];
157
158 /* max nVals = max SFB width = 96, so energy can gain < 2^7 bits in accumulation */
159 sq = (spec * spec) >> 8; /* spec*spec range = (-2^30, 2^30) */
160 energy += sq;
161 }
162
163 /* unless nVals == 1 (or the number generator is broken...), this should not happen */
164 if (energy == 0) {
165 return 0; /* coef[i] must = 0 for i = [0, nVals-1], so gbMask = 0 */
166 }
167
168 /* pow(2, sf/4) * pow(2, FBITS_OUT_DQ_OFF) */
169 scalef = pow14[sf & 0x3];
170 scalei = (sf >> 2) + FBITS_OUT_DQ_OFF;
171
172 /* energy has implied factor of 2^-8 since we shifted the accumulator
173 * normalize energy to range [0.25, 1.0), calculate 1/sqrt(1), and denormalize
174 * i.e. divide input by 2^(30-z) and convert to Q30
175 * output of 1/sqrt(i) now has extra factor of 2^((30-z)/2)
176 * for energy > 0, z is an even number between 0 and 28
177 * final scaling of invSqrtEnergy:
178 * 2^(15 - z/2) to compensate for implicit 2^(30-z) factor in input
179 * +4 to compensate for implicit 2^-8 factor in input
180 */
181 z = CLZ(energy) - 2; /* energy has at least 2 leading zeros (see acc loop) */
182 z &= 0xfffffffe; /* force even */
183 invSqrtEnergy = InvRootR(energy << z); /* energy << z must be in range [0x10000000, 0x40000000] */
184 scalei -= (15 - z / 2 + 4); /* nInt = 1/sqrt(energy) in Q29 */
185
186 /* normalize for final scaling */
187 z = CLZ(invSqrtEnergy) - 1;
188 invSqrtEnergy <<= z;
189 scalei -= (z - 3 - 2); /* -2 for scalef, z-3 for invSqrtEnergy */
190 scalef = MULSHIFT32(scalef, invSqrtEnergy); /* scalef (input) = Q30, invSqrtEnergy = Q29 * 2^z */
191 gbMask = 0;
192
193 if (scalei < 0) {
194 scalei = -scalei;
195 if (scalei > 31) {
196 scalei = 31;
197 }
198 for (i = 0; i < nVals; i++) {
199 c = MULSHIFT32(coef[i], scalef) >> scalei;
200 gbMask |= FASTABS(c);
201 coef[i] = c;
202 }
203 } else {
204 /* for scalei <= 16, no clipping possible (coef[i] is < 2^15 before scaling)
205 * for scalei > 16, just saturate exponent (rare)
206 * scalef is close to full-scale (since we normalized invSqrtEnergy)
207 * remember, we are just producing noise here
208 */
209 if (scalei > 16) {
210 scalei = 16;
211 }
212 for (i = 0; i < nVals; i++) {
213 c = MULSHIFT32(coef[i] << scalei, scalef);
214 coef[i] = c;
215 gbMask |= FASTABS(c);
216 }
217 }
218
219 return gbMask;
220}
221
222/**************************************************************************************
223 * Function: GenerateNoiseVector
224 *
225 * Description: create vector of noise coefficients for one scalefactor band
226 *
227 * Inputs: seed for number generator
228 * number of coefficients to generate
229 *
230 * Outputs: buffer of nVals coefficients, range = [-2^15, 2^15)
231 * updated seed for number generator
232 *
233 * Return: none
234 **************************************************************************************/
235static void GenerateNoiseVector(int *coef, int *last, int nVals)
236{
237 int i;
238
239 for (i = 0; i < nVals; i++) {
240 coef[i] = ((signed int)Get32BitVal((unsigned int *)last)) >> 16;
241 }
242}
243
244/**************************************************************************************
245 * Function: CopyNoiseVector
246 *
247 * Description: copy vector of noise coefficients for one scalefactor band from L to R
248 *
249 * Inputs: buffer of left coefficients
250 * number of coefficients to copy
251 *
252 * Outputs: buffer of right coefficients
253 *
254 * Return: none
255 **************************************************************************************/
256static void CopyNoiseVector(int *coefL, int *coefR, int nVals)
257{
258 int i;
259
260 for (i = 0; i < nVals; i++) {
261 coefR[i] = coefL[i];
262 }
263}
264
265/**************************************************************************************
266 * Function: PNS
267 *
268 * Description: apply perceptual noise substitution, if enabled (MPEG-4 only)
269 *
270 * Inputs: valid AACDecInfo struct
271 * index of current channel
272 *
273 * Outputs: shaped noise in scalefactor bands where PNS is active
274 * updated minimum guard bit count for this channel
275 *
276 * Return: 0 if successful, -1 if error
277 **************************************************************************************/
278int PNS(AACDecInfo *aacDecInfo, int ch)
279{
280 int gp, sfb, win, width, nSamps, gb, gbMask;
281 int *coef;
282 const short *sfbTab;
283 unsigned char *sfbCodeBook;
284 short *scaleFactors;
285 int msMaskOffset, checkCorr, genNew;
286 unsigned char msMask;
287 unsigned char *msMaskPtr;
288 PSInfoBase *psi;
289 ICSInfo *icsInfo;
290
291 /* validate pointers */
292 if (!aacDecInfo || !aacDecInfo->psInfoBase) {
293 return -1;
294 }
295 psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
296 icsInfo = (ch == 1 && psi->commonWin == 1) ? &(psi->icsInfo[0]) : &(psi->icsInfo[ch]);
297
298 if (!psi->pnsUsed[ch]) {
299 return 0;
300 }
301
302 if (icsInfo->winSequence == 2) {
303 sfbTab = sfBandTabShort + sfBandTabShortOffset[psi->sampRateIdx];
304 nSamps = NSAMPS_SHORT;
305 } else {
306 sfbTab = sfBandTabLong + sfBandTabLongOffset[psi->sampRateIdx];
307 nSamps = NSAMPS_LONG;
308 }
309 coef = psi->coef[ch];
310 sfbCodeBook = psi->sfbCodeBook[ch];
311 scaleFactors = psi->scaleFactors[ch];
312 checkCorr = (aacDecInfo->currBlockID == AAC_ID_CPE && psi->commonWin == 1 ? 1 : 0);
313
314 gbMask = 0;
315 for (gp = 0; gp < icsInfo->numWinGroup; gp++) {
316 for (win = 0; win < icsInfo->winGroupLen[gp]; win++) {
317 msMaskPtr = psi->msMaskBits + ((gp * icsInfo->maxSFB) >> 3);
318 msMaskOffset = ((gp * icsInfo->maxSFB) & 0x07);
319 msMask = (*msMaskPtr++) >> msMaskOffset;
320
321 for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) {
322 width = sfbTab[sfb + 1] - sfbTab[sfb];
323 if (sfbCodeBook[sfb] == 13) {
324 if (ch == 0) {
325 /* generate new vector, copy into ch 1 if it's possible that the channels will be correlated
326 * if ch 1 has PNS enabled for this SFB but it's uncorrelated (i.e. ms_used == 0),
327 * the copied values will be overwritten when we process ch 1
328 */
329 GenerateNoiseVector(coef, &psi->pnsLastVal, width);
330 if (checkCorr && psi->sfbCodeBook[1][gp * icsInfo->maxSFB + sfb] == 13) {
331 CopyNoiseVector(coef, psi->coef[1] + (coef - psi->coef[0]), width);
332 }
333 } else {
334 /* generate new vector if no correlation between channels */
335 genNew = 1;
336 if (checkCorr && psi->sfbCodeBook[0][gp * icsInfo->maxSFB + sfb] == 13) {
337 if ((psi->msMaskPresent == 1 && (msMask & 0x01)) || psi->msMaskPresent == 2) {
338 genNew = 0;
339 }
340 }
341 if (genNew) {
342 GenerateNoiseVector(coef, &psi->pnsLastVal, width);
343 }
344 }
345 gbMask |= ScaleNoiseVector(coef, width, psi->scaleFactors[ch][gp * icsInfo->maxSFB + sfb]);
346 }
347 coef += width;
348
349 /* get next mask bit (should be branchless on ARM) */
350 msMask >>= 1;
351 if (++msMaskOffset == 8) {
352 msMask = *msMaskPtr++;
353 msMaskOffset = 0;
354 }
355 }
356 coef += (nSamps - sfbTab[icsInfo->maxSFB]);
357 }
358 sfbCodeBook += icsInfo->maxSFB;
359 scaleFactors += icsInfo->maxSFB;
360 }
361
362 /* update guard bit count if necessary */
363 gb = CLZ(gbMask) - 1;
364 if (psi->gbCurrent[ch] > gb) {
365 psi->gbCurrent[ch] = gb;
366 }
367
368 return 0;
369}
370