blob: 9e4d741870121aab3faec72ac6b7a2baee9846cd
1 | /* ***** BEGIN LICENSE BLOCK ***** |
2 | * Source last modified: $Id: gainctrl.c,v 1.6 2005/04/27 19:20:50 hubbe Exp $ |
3 | * |
4 | * REALNETWORKS CONFIDENTIAL--NOT FOR DISTRIBUTION IN SOURCE CODE FORM |
5 | * Portions Copyright (c) 1995-2002 RealNetworks, Inc. |
6 | * All Rights Reserved. |
7 | * |
8 | * The contents of this file, and the files included with this file, |
9 | * are subject to the current version of the Real Format Source Code |
10 | * Porting and Optimization License, available at |
11 | * https://helixcommunity.org/2005/license/realformatsource (unless |
12 | * RealNetworks otherwise expressly agrees in writing that you are |
13 | * subject to a different license). You may also obtain the license |
14 | * terms directly from RealNetworks. You may not use this file except |
15 | * in compliance with the Real Format Source Code Porting and |
16 | * Optimization License. There are no redistribution rights for the |
17 | * source code of this file. Please see the Real Format Source Code |
18 | * Porting and Optimization License for the rights, obligations and |
19 | * limitations governing use of the contents of the file. |
20 | * |
21 | * RealNetworks is the developer of the Original Code and owns the |
22 | * copyrights in the portions it created. |
23 | * |
24 | * This file, and the files included with this file, is distributed and |
25 | * made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, |
26 | * EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL |
27 | * SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF |
28 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT |
29 | * OR NON-INFRINGEMENT. |
30 | * |
31 | * Technology Compatibility Kit Test Suite(s) Location: |
32 | * https://rarvcode-tck.helixcommunity.org |
33 | * |
34 | * Contributor(s): |
35 | * |
36 | * ***** END LICENSE BLOCK ***** */ |
37 | |
38 | /************************************************************************************** |
39 | * Fixed-point RealAudio 8 decoder |
40 | * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) |
41 | * October 2003 |
42 | * |
43 | * gainctrl.c - time-domain gain control processing |
44 | * |
45 | * Discussion of interpolating gain control window: |
46 | * gain ranges from -7 to 4 so window ranges from 2^-7 to 2^4 |
47 | * If gain0 != gain1, we start at 2^gain0 and increase logarithmically |
48 | * to a final value of gain1 |
49 | **************************************************************************************/ |
50 | |
51 | #include "coder.h" |
52 | #include "assembly.h" |
53 | |
54 | #define MAX_NPSAMPS (1024 / NPARTS) |
55 | #define MAX_LOGNPSAMPS 7 /* log2(MAX_NPSAMPS) */ |
56 | #define FRAC_MASK (MAX_NPSAMPS - 1) |
57 | |
58 | static const int npsampsTab[NUM_MLT_SIZES] = {256 / NPARTS, 512 / NPARTS, 1024 / NPARTS}; |
59 | static const int nplog2Tab[NUM_MLT_SIZES] = {5, 6, 7}; |
60 | |
61 | /* 2^(x/128) - format = Q30 */ |
62 | static const int POW2NTAB[128] = { |
63 | 0x40000000, 0x4058f6a8, 0x40b268fa, 0x410c57a2, 0x4166c34c, 0x41c1aca7, 0x421d1462, 0x4278fb2b, |
64 | 0x42d561b4, 0x433248ae, 0x438fb0cb, 0x43ed9ac0, 0x444c0740, 0x44aaf702, 0x450a6abb, 0x456a6323, |
65 | 0x45cae0f2, 0x462be4e2, 0x468d6fae, 0x46ef8210, 0x47521cc6, 0x47b5408c, 0x4818ee22, 0x487d2646, |
66 | 0x48e1e9ba, 0x4947393f, 0x49ad1598, 0x4a137f88, 0x4a7a77d4, 0x4ae1ff43, 0x4b4a169c, 0x4bb2bea5, |
67 | 0x4c1bf829, 0x4c85c3f1, 0x4cf022ca, 0x4d5b157e, 0x4dc69cdd, 0x4e32b9b4, 0x4e9f6cd4, 0x4f0cb70c, |
68 | 0x4f7a9930, 0x4fe91413, 0x50582888, 0x50c7d765, 0x51382182, 0x51a907b4, 0x521a8ad7, 0x528cabc3, |
69 | 0x52ff6b55, 0x5372ca68, 0x53e6c9da, 0x545b6a8b, 0x54d0ad5a, 0x55469329, 0x55bd1cdb, 0x56344b52, |
70 | 0x56ac1f75, 0x57249a29, 0x579dbc57, 0x581786e6, 0x5891fac1, 0x590d18d3, 0x5988e209, 0x5a055751, |
71 | 0x5a82799a, 0x5b0049d4, 0x5b7ec8f2, 0x5bfdf7e5, 0x5c7dd7a4, 0x5cfe6923, 0x5d7fad59, 0x5e01a53f, |
72 | 0x5e8451d0, 0x5f07b405, 0x5f8bccdb, 0x60109d51, 0x60962665, 0x611c6919, 0x61a3666d, 0x622b1f66, |
73 | 0x62b39509, 0x633cc85b, 0x63c6ba64, 0x64516c2e, 0x64dcdec3, 0x6569132f, 0x65f60a7f, 0x6683c5c3, |
74 | 0x6712460b, 0x67a18c68, 0x683199ed, 0x68c26fb1, 0x69540ec9, 0x69e6784d, 0x6a79ad56, 0x6b0daeff, |
75 | 0x6ba27e65, 0x6c381ca6, 0x6cce8ae1, 0x6d65ca38, 0x6dfddbcc, 0x6e96c0c3, 0x6f307a41, 0x6fcb096f, |
76 | 0x70666f76, 0x7102ad80, 0x719fc4b9, 0x723db650, 0x72dc8374, 0x737c2d55, 0x741cb528, 0x74be1c20, |
77 | 0x75606374, 0x76038c5b, 0x76a7980f, 0x774c87cc, 0x77f25cce, 0x78991854, 0x7940bb9e, 0x79e947ef, |
78 | 0x7a92be8b, 0x7b3d20b6, 0x7be86fba, 0x7c94acde, 0x7d41d96e, 0x7deff6b6, 0x7e9f0606, 0x7f4f08ae, |
79 | }; |
80 | |
81 | /************************************************************************************** |
82 | * Function: DecodeGainInfo |
83 | * |
84 | * Description: decode the gain window parameters for each frame |
85 | * |
86 | * Inputs: pointer to initialized Gecko2Info struct |
87 | * pointer to uninitialized GAINC struct |
88 | * number of bits remaining in bitstream for this frame |
89 | * |
90 | * Outputs: GAINC struct filled in with number and location of attacks, and gains |
91 | * |
92 | * Return: number of bits remaining in bitstream, -1 if out-of-bits |
93 | **************************************************************************************/ |
94 | int DecodeGainInfo(Gecko2Info *gi, GAINC *gainc, int availbits) |
95 | { |
96 | int i, nbits, code; |
97 | BitStreamInfo *bsi = &(gi->bsi); |
98 | |
99 | /* unpack nattacks */ |
100 | nbits = 0; |
101 | do { |
102 | code = GetBits(bsi, 1, 1); /* count bits until zero reached */ |
103 | nbits++; |
104 | } while (code); |
105 | gainc->nats = nbits - 1; /* nats = number of ones */ |
106 | availbits -= nbits; |
107 | |
108 | if (availbits < 0) { |
109 | return -1; |
110 | } |
111 | |
112 | ASSERT(gainc->nats <= MAXNATS); |
113 | |
114 | /* unpack any location/gain pairs */ |
115 | if (gainc->nats > 0) { |
116 | for (i = 0; i < gainc->nats; i++) { |
117 | /* location */ |
118 | gainc->loc[i] = GetBits(bsi, LOCBITS, 1); |
119 | availbits -= LOCBITS; |
120 | |
121 | /* gain code */ |
122 | code = GetBits(bsi, 1, 1); |
123 | availbits--; |
124 | |
125 | if (!code) { |
126 | gainc->gain[i] = -1; |
127 | } else { |
128 | code = GetBits(bsi, GAINBITS, 1); |
129 | availbits -= GAINBITS; |
130 | gainc->gain[i] = CODE2GAIN(code); |
131 | } |
132 | } |
133 | } |
134 | gainc->maxExGain = 0; |
135 | |
136 | if (availbits < 0) { |
137 | return -1; |
138 | } |
139 | |
140 | return availbits; |
141 | } |
142 | |
143 | /************************************************************************************** |
144 | * Function: CopyGainInfo |
145 | * |
146 | * Description: copy contents of one GAINC struct into another one |
147 | * |
148 | * Inputs: pointer to initialized GAINC struct (source) |
149 | * pointer to uninitialized GAINC struct (destination) |
150 | * |
151 | * Outputs: gaincDest which is identical to gaincSource |
152 | * |
153 | * Return: none |
154 | * |
155 | * Notes: this prevents compiler from generating a memcpy for gainc0 = gainc1 |
156 | * (we want to avoid a CRT lib call, for portability of asm) |
157 | **************************************************************************************/ |
158 | void CopyGainInfo(GAINC *gaincDest, GAINC *gaincSource) |
159 | { |
160 | int nBytes = sizeof(GAINC); |
161 | unsigned char *d = (unsigned char *)gaincDest; |
162 | unsigned char *s = (unsigned char *)gaincSource; |
163 | |
164 | for (; nBytes != 0; nBytes--) { |
165 | *d++ = *s++; |
166 | } |
167 | |
168 | } |
169 | |
170 | /************************************************************************************** |
171 | * Function: CalcGainChanges |
172 | * |
173 | * Description: reconstruct segmented gain window |
174 | * |
175 | * Inputs: pointer to uninitialized exgain array |
176 | * pointer to old (overlap) and current gain info structs |
177 | * |
178 | * Outputs: exgain[0, ... 2*NPARTS] with expanded gains at each switch point |
179 | * |
180 | * Return: none |
181 | * |
182 | * Notes: each frame is divided into NPARTS segments, with |
183 | * npsamps = nSamples / NPARTS samples in each one |
184 | * the gain window can only change at these boundaries |
185 | * if exgain[i] != exgain[i-1] the gain is interpolated logarithmically |
186 | * between the two points (buf[(i-1)*npsamps to buf[i*npsamps]) |
187 | **************************************************************************************/ |
188 | static void CalcGainChanges(short *exgain, GAINC *gainc0, GAINC *gainc1) |
189 | { |
190 | short i, nats, maxGain, offset; |
191 | |
192 | /* second half - expand gains, working backwards */ |
193 | exgain[NPARTS + NPARTS] = 0; /* always finish at 1.0 */ |
194 | nats = gainc1->nats; /* gain changes left */ |
195 | for (i = NPARTS - 1; i >= 0; i--) { |
196 | if (nats && (i == gainc1->loc[nats - 1])) { /* at gain change */ |
197 | exgain[i + NPARTS] = gainc1->gain[--nats]; /* use it */ |
198 | } else { |
199 | exgain[i + NPARTS] = exgain[i + NPARTS + 1]; /* repeat last gain */ |
200 | } |
201 | } |
202 | |
203 | /* pull any discontinuity through first half by offsetting all |
204 | * gains with starting gain of second half |
205 | */ |
206 | offset = exgain[NPARTS]; |
207 | |
208 | /* first half - expand gains, working backwards */ |
209 | nats = gainc0->nats; /* gain changes left */ |
210 | for (i = NPARTS - 1; i >= 0; i--) { |
211 | if (nats && (i == gainc0->loc[nats - 1])) { /* at gain change */ |
212 | exgain[i] = gainc0->gain[--nats] + offset; /* use it */ |
213 | } else { |
214 | exgain[i] = exgain[i + 1]; /* repeat last gain */ |
215 | } |
216 | } |
217 | |
218 | /* find max gain for each half (input and overlap) */ |
219 | maxGain = 0; |
220 | for (i = 0; i <= NPARTS; i++) { |
221 | if (exgain[i] > maxGain) { |
222 | maxGain = exgain[i]; |
223 | } |
224 | } |
225 | gainc0->maxExGain = maxGain; |
226 | |
227 | maxGain = 0; |
228 | for (i = NPARTS; i <= 2 * NPARTS; i++) { |
229 | if (exgain[i] > maxGain) { |
230 | maxGain = exgain[i]; |
231 | } |
232 | } |
233 | gainc1->maxExGain = maxGain; |
234 | |
235 | return; |
236 | } |
237 | |
238 | /************************************************************************************** |
239 | * Function: InterpolatePCM |
240 | * |
241 | * Description: apply gain window to first half of current frame, and overlap-add |
242 | * with second half of previous frame, to produce PCM output |
243 | * |
244 | * Inputs: table index (for transform size) |
245 | * pointer to initialized exgain array (NPARTS+1 gain values) |
246 | * first half of IMLT output for current frame (buf), |
247 | * synthesis window has not yet been applied |
248 | * overlap from previous frame (buf + MAXNMLT), synthesis and gain |
249 | * windows were already applied |
250 | * max exgain for first half of current frame |
251 | * buffer for output PCM |
252 | * number of channels |
253 | * number of fraction bits present in current and overlap data |
254 | * |
255 | * Outputs: nSamples samples of 16-bit PCM output |
256 | * |
257 | * Return: none |
258 | * |
259 | * Notes: this processes one channel at a time, but skips every other sample in |
260 | * the output buffer (pcm) for stereo interleaving |
261 | **************************************************************************************/ |
262 | static void InterpolatePCM(int tabidx, short *exgain, int *buf, int *overlap, short maxGain, short *pcm, int nChans, int fbitsPCM, int fbitsOver) |
263 | { |
264 | int in, npsamps, part; |
265 | int shiftLo, shiftHi, currGainLo, currGainHi, gainDiffLo, gainDiffHi; |
266 | int gainLo0, gainLo1, gainHi0, gainHi1, w0, w1, f0, f1, oc; |
267 | int *over0, *over1, shift[2], rndMask; |
268 | short *pcm0, *pcm1; |
269 | const int *wnd; |
270 | |
271 | shift[0] = 0; |
272 | shift[1] = 0; |
273 | rndMask = 0; |
274 | if (fbitsPCM > fbitsOver) { |
275 | shift[0] = MIN(fbitsPCM - fbitsOver, 31); |
276 | fbitsPCM = fbitsOver; |
277 | } else if (fbitsPCM < fbitsOver) { |
278 | shift[1] = MIN(fbitsOver - fbitsPCM, 31); |
279 | } |
280 | |
281 | if (fbitsPCM > 0) { |
282 | rndMask = (1 << (fbitsPCM - 1)); |
283 | } |
284 | ASSERT(fbitsPCM >= 0); |
285 | |
286 | npsamps = npsampsTab[tabidx]; |
287 | over0 = overlap;//buf + MAXNMLT; |
288 | over1 = over0 + NPARTS * npsamps - 1; |
289 | buf += (nmltTab[tabidx] >> 1) - 1; |
290 | |
291 | wnd = window + windowOffset[tabidx]; |
292 | pcm0 = pcm; |
293 | pcm1 = pcm + (NPARTS * npsamps - 1) * nChans; |
294 | |
295 | gainLo1 = exgain[0]; |
296 | gainHi0 = exgain[NPARTS]; |
297 | |
298 | for (part = 0; part < NPARTS / 2; part++) { |
299 | npsamps = npsampsTab[tabidx]; |
300 | |
301 | gainLo0 = gainLo1; |
302 | gainLo1 = exgain[part + 1]; |
303 | gainHi1 = gainHi0; |
304 | gainHi0 = exgain[NPARTS - part - 1]; |
305 | |
306 | currGainHi = gainHi1 << MAX_LOGNPSAMPS; |
307 | gainDiffHi = (gainHi0 - gainHi1) << (MAX_LOGNPSAMPS - nplog2Tab[tabidx]); |
308 | currGainHi += gainDiffHi; |
309 | |
310 | currGainLo = gainLo0 << MAX_LOGNPSAMPS; |
311 | gainDiffLo = (gainLo1 - gainLo0) << (MAX_LOGNPSAMPS - nplog2Tab[tabidx]); |
312 | |
313 | /* interpolate the gain window: in = in * 2^(gain0) * 2^((gain1 - gain0)*i/npsamps) */ |
314 | if (gainDiffLo || gainDiffHi) { |
315 | /* slow path - interpolated section of gain window */ |
316 | for (; npsamps != 0; npsamps--) { |
317 | in = *buf--; |
318 | w0 = *wnd++; |
319 | w1 = *wnd++; |
320 | |
321 | shiftLo = maxGain - (currGainLo >> MAX_LOGNPSAMPS) + shift[0]; |
322 | oc = *over0++; |
323 | f0 = MULSHIFT32(w0, in); |
324 | f0 = MULSHIFT32(POW2NTAB[currGainLo & FRAC_MASK], f0) << 2; |
325 | *pcm0 = CLIPTOSHORT(((f0 >> shiftLo) + (oc >> shift[1]) + rndMask) >> fbitsPCM); |
326 | pcm0 += nChans; |
327 | currGainLo += gainDiffLo; |
328 | |
329 | shiftHi = maxGain - (currGainHi >> MAX_LOGNPSAMPS) + shift[0]; |
330 | oc = *over1--; |
331 | f1 = MULSHIFT32(w1, in); |
332 | f1 = MULSHIFT32(POW2NTAB[currGainHi & FRAC_MASK], f1) << 2; |
333 | *pcm1 = CLIPTOSHORT(((f1 >> shiftHi) + (oc >> shift[1]) + rndMask) >> fbitsPCM); |
334 | pcm1 -= nChans; |
335 | currGainHi += gainDiffHi; |
336 | } |
337 | } else { |
338 | /* fast path - constant section of gain window */ |
339 | shiftLo = maxGain - gainLo0 + shift[0]; |
340 | shiftHi = maxGain - gainHi1 + shift[0]; |
341 | for (; npsamps != 0; npsamps--) { |
342 | in = *buf--; |
343 | w0 = *wnd++; |
344 | w1 = *wnd++; |
345 | |
346 | oc = *over0++; |
347 | f0 = MULSHIFT32(w0, in); |
348 | *pcm0 = CLIPTOSHORT(((f0 >> shiftLo) + (oc >> shift[1]) + rndMask) >> fbitsPCM); |
349 | pcm0 += nChans; |
350 | |
351 | oc = *over1--; |
352 | f1 = MULSHIFT32(w1, in); |
353 | *pcm1 = CLIPTOSHORT(((f1 >> shiftHi) + (oc >> shift[1]) + rndMask) >> fbitsPCM); |
354 | pcm1 -= nChans; |
355 | } |
356 | } |
357 | } |
358 | } |
359 | |
360 | /************************************************************************************** |
361 | * Function: InterpolateOverlap |
362 | * |
363 | * Description: apply gain window to second half of current frame, and save for |
364 | * overlap-add next frame |
365 | * |
366 | * Inputs: table index (for transform size) |
367 | * pointer to initialized exgain array (NPARTS+1 gain values) |
368 | * second half of IMLT output for current frame (buf + nmlt/2), |
369 | * synthesis window has not yet been applied |
370 | * max exgain for second half of current frame |
371 | * |
372 | * Outputs: nSamples samples of gain windowed data for overlap |
373 | * (stored at buf + MAXNMLT) |
374 | * |
375 | * Return: none |
376 | **************************************************************************************/ |
377 | static void InterpolateOverlap(int tabidx, short *exgain, int *buf, int *overlap, short maxGain) |
378 | { |
379 | int in, npsamps, part; |
380 | int shiftLo, shiftHi, currGainLo, currGainHi, gainDiffLo, gainDiffHi; |
381 | int gainLo0, gainLo1, gainHi0, gainHi1, w0, w1; |
382 | int *over0, *over1; |
383 | const int *wnd; |
384 | |
385 | npsamps = npsampsTab[tabidx]; |
386 | over0 = overlap;//buf + MAXNMLT; |
387 | over1 = over0 + NPARTS * npsamps - 1; |
388 | buf += (nmltTab[tabidx] >> 1); |
389 | wnd = window + windowOffset[tabidx]; |
390 | |
391 | gainLo1 = exgain[0]; |
392 | gainHi0 = exgain[NPARTS]; |
393 | |
394 | for (part = 0; part < NPARTS / 2; part++) { |
395 | npsamps = npsampsTab[tabidx]; |
396 | |
397 | gainLo0 = gainLo1; |
398 | gainLo1 = exgain[part + 1]; |
399 | gainHi1 = gainHi0; |
400 | gainHi0 = exgain[NPARTS - part - 1]; |
401 | |
402 | currGainHi = gainHi1 << MAX_LOGNPSAMPS; |
403 | gainDiffHi = (gainHi0 - gainHi1) << (MAX_LOGNPSAMPS - nplog2Tab[tabidx]); |
404 | currGainHi += gainDiffHi; |
405 | |
406 | currGainLo = gainLo0 << MAX_LOGNPSAMPS; |
407 | gainDiffLo = (gainLo1 - gainLo0) << (MAX_LOGNPSAMPS - nplog2Tab[tabidx]); |
408 | |
409 | /* interpolate the gain window: in = in * 2^(gain0) * 2^((gain1 - gain0)*i/npsamps) */ |
410 | if (gainDiffLo || gainDiffHi) { |
411 | /* slow path - interpolated section of gain window */ |
412 | for (; npsamps != 0; npsamps--) { |
413 | in = *buf++; |
414 | w0 = *wnd++; |
415 | w1 = *wnd++; |
416 | |
417 | shiftLo = maxGain - (currGainLo >> MAX_LOGNPSAMPS); |
418 | w1 = MULSHIFT32(w1, in) >> shiftLo; |
419 | *over0++ = MULSHIFT32(POW2NTAB[currGainLo & FRAC_MASK], w1) << 2; |
420 | currGainLo += gainDiffLo; |
421 | |
422 | shiftHi = maxGain - (currGainHi >> MAX_LOGNPSAMPS); |
423 | w0 = -MULSHIFT32(w0, in) >> shiftHi; |
424 | *over1-- = MULSHIFT32(POW2NTAB[currGainHi & FRAC_MASK], w0) << 2; |
425 | currGainHi += gainDiffHi; |
426 | } |
427 | } else { |
428 | /* fast path - constant section of gain window */ |
429 | shiftLo = maxGain - gainLo0; |
430 | shiftHi = maxGain - gainHi1; |
431 | for (; npsamps != 0; npsamps--) { |
432 | in = *buf++; |
433 | w0 = *wnd++; |
434 | w1 = *wnd++; |
435 | |
436 | *over0++ = MULSHIFT32(w1, in) >> shiftLo; |
437 | *over1-- = -MULSHIFT32(w0, in) >> shiftHi; |
438 | } |
439 | } |
440 | } |
441 | } |
442 | |
443 | /* default fraction bits, not counting any extras from dequantizer */ |
444 | #define FBITS_OUT_IMLT (FBITS_OUT_DQ - FBITS_LOST_IMLT) |
445 | |
446 | /************************************************************************************** |
447 | * Function: DecWindowWithAttacks |
448 | * |
449 | * Description: apply synthesis window, perform gain windowing of current frame, |
450 | * do overlap-add, and produce one frame of decoded PCM |
451 | * (general case - either gain window has attacks or the default Q format |
452 | * is not being used) |
453 | * |
454 | * Inputs: table index (for transform size) |
455 | * input buffer (output of IMLT, before synthesis window) |
456 | * buffer for output PCM |
457 | * number of channels |
458 | * gain control structs for overlap and current frames |
459 | * number of extra integer bits present in current and overlap data |
460 | * (relative to the default format of FBITS_OUT_IMLT) |
461 | * |
462 | * Outputs: nSamples samples of 16-bit PCM output |
463 | * |
464 | * Return: none |
465 | * |
466 | * Notes: this processes one channel at a time, but skips every other sample in |
467 | * the output buffer (pcm) for stereo interleaving |
468 | **************************************************************************************/ |
469 | void DecWindowWithAttacks(int tabidx, int *buf, int *overlap, short *pcm, int nChans, GAINC *gainc0, GAINC *gainc1, short xbits[2]) |
470 | { |
471 | int i, s, fbitsPCM, fbitsOver; |
472 | short exgain[2 * NPARTS + 1]; |
473 | |
474 | fbitsOver = FBITS_OUT_IMLT - xbits[0] - gainc0->maxExGain; |
475 | CalcGainChanges(exgain, gainc0, gainc1); |
476 | fbitsPCM = FBITS_OUT_IMLT - xbits[1] - gainc0->maxExGain; |
477 | |
478 | /* this is EXTREMELY unlikely (gain window so high that we would have negative fraction bits) |
479 | * so just do << and clip whole frame to 0 fraction bits |
480 | * can think of this as artifically adding fraction bits, or just doing gain window |
481 | * in 2 stages (first pass = window by constant power of 2, second pass = window |
482 | * by original gain window / constant power of 2) |
483 | * whole purpose is so Interpolate functions can be hard-coded to >> only (fast) |
484 | */ |
485 | s = 0; |
486 | if (fbitsOver < 0 || fbitsPCM < 0) { |
487 | s = MAX(-fbitsOver, -fbitsPCM); |
488 | for (i = 0; i < npsampsTab[tabidx]*NPARTS; i++) { |
489 | CLIP_2N_SHIFT(buf[i], s); |
490 | } |
491 | for (i = 0; i < npsampsTab[tabidx]*NPARTS; i++) { |
492 | CLIP_2N_SHIFT(overlap[i], s); |
493 | } |
494 | //for (i = MAXNSAMP; i < MAXNSAMP + npsampsTab[tabidx]*NPARTS; i++) |
495 | // CLIP_2N_SHIFT(buf[i], s); |
496 | fbitsOver += s; |
497 | fbitsPCM += s; |
498 | } |
499 | |
500 | InterpolatePCM(tabidx, exgain, buf, overlap, gainc0->maxExGain, pcm, nChans, fbitsPCM, fbitsOver); |
501 | InterpolateOverlap(tabidx, exgain + NPARTS, buf, overlap, gainc1->maxExGain); |
502 | |
503 | /* undo extreme gain window scaling */ |
504 | if (s) { |
505 | for (i = 0; i < npsampsTab[tabidx]*NPARTS; i++) { |
506 | buf[i] >>= s; |
507 | } |
508 | for (i = 0; i < npsampsTab[tabidx]*NPARTS; i++) { |
509 | overlap[i] >>= s; |
510 | } |
511 | //for (i = MAXNSAMP; i < MAXNSAMP + npsampsTab[tabidx]*NPARTS; i++) |
512 | // buf[i] >>= s; |
513 | } |
514 | |
515 | return; |
516 | } |
517 | |
518 | /************************************************************************************** |
519 | * Function: DecWindowNoAttacks |
520 | * |
521 | * Description: apply synthesis window, perform gain windowing of current frame, |
522 | * do overlap-add, and produce one frame of decoded PCM |
523 | * (fast case - no gain window attacks and the data is in the default |
524 | * Q format with FBITS_OUT_IMLT fraction bits in input) |
525 | * |
526 | * Inputs: table index (for transform size) |
527 | * input buffer (output of IMLT, before synthesis window) |
528 | * pcm buffer |
529 | * number of channels |
530 | * |
531 | * Outputs: nSamples samples of 16-bit PCM output |
532 | * |
533 | * Return: none |
534 | * |
535 | * Notes: this processes one channel at a time, but skips every other sample in |
536 | * the output buffer (pcm) for stereo interleaving |
537 | * this should fit in registers on ARM - make sure compiler does this |
538 | * correctly! |
539 | **************************************************************************************/ |
540 | void DecWindowNoAttacks(int tabidx, int *buf0, int *overlap, short *pcm0, int nChans) |
541 | { |
542 | int nmlt, nmltHalf; |
543 | int in, oc, w0, w1, f0, f1; |
544 | int *buf1, *over0, *over1; |
545 | short *pcm1; |
546 | const int *wnd; |
547 | |
548 | nmlt = nmltTab[tabidx]; |
549 | nmltHalf = nmlt >> 1; |
550 | |
551 | over0 = overlap;//buf0 + MAXNMLT; |
552 | over1 = over0 + nmlt - 1; |
553 | |
554 | buf0 += nmltHalf; |
555 | buf1 = buf0 - 1; |
556 | wnd = window + windowOffset[tabidx]; |
557 | pcm1 = pcm0 + (nmlt - 1) * nChans; |
558 | |
559 | for (; nmltHalf != 0; nmltHalf--) { |
560 | /* load window coefficients */ |
561 | w0 = *wnd++; |
562 | w1 = *wnd++; |
563 | |
564 | /* apply window to generate first N samples */ |
565 | in = *buf1--; |
566 | f0 = MULSHIFT32(w0, in); |
567 | f1 = MULSHIFT32(w1, in); |
568 | |
569 | /* overlap-add with second N samples from last frame */ |
570 | oc = *over0; |
571 | *pcm0 = CLIPTOSHORT((f0 + oc + (1 << (FBITS_OUT_IMLT - 1))) >> FBITS_OUT_IMLT); |
572 | pcm0 += nChans; |
573 | oc = *over1; |
574 | *pcm1 = CLIPTOSHORT((f1 + oc + (1 << (FBITS_OUT_IMLT - 1))) >> FBITS_OUT_IMLT); |
575 | pcm1 -= nChans; |
576 | |
577 | /* apply window to generate second nmlt samples, save for overlap with next frame */ |
578 | in = *buf0++; |
579 | *over0++ = MULSHIFT32(w1, in); |
580 | *over1-- = -MULSHIFT32(w0, in); |
581 | } |
582 | |
583 | return; |
584 | } |
585 |