1 /**
2 * Copyright (C) 2022 The Android Open Source Project
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 *
18 * Subband processing consists of:
19 * inverse quantisation (defined in a separate file),
20 * predictor coefficient update (Pole and Zero Coeff update),
21 * predictor filtering.
22 *
23 *----------------------------------------------------------------------------*/
24
25 #ifndef SUBBANDFUNCTIONSCOMMON_H
26 #define SUBBANDFUNCTIONSCOMMON_H
27
28 enum reg64_reg { reg64_H = 1, reg64_L = 0 };
29
30 void processSubband_HD(const int32_t qCode, const int32_t ditherVal, Subband_data* SubbandDataPt,
31 IQuantiser_data* iqDataPt);
32 void processSubband_HDLL(const int32_t qCode, const int32_t ditherVal, Subband_data* SubbandDataPt,
33 IQuantiser_data* iqDataPt);
34 void processSubband_HDHL(const int32_t qCode, const int32_t ditherVal, Subband_data* SubbandDataPt,
35 IQuantiser_data* iqDataPt);
36
37 /* Function to carry out inverse quantisation for a subband */
invertQuantisation(const int32_t qCode,const int32_t ditherVal,IQuantiser_data * iqdata_pt)38 XBT_INLINE_ void invertQuantisation(const int32_t qCode, const int32_t ditherVal,
39 IQuantiser_data* iqdata_pt) {
40 int32_t invQ;
41 int32_t index;
42 int32_t acc;
43 reg64_t tmp_r64;
44 int64_t tmp_acc;
45 int32_t tmp_accL;
46 int32_t tmp_accH;
47 uint32_t tmp_round0;
48 uint32_t tmp_round1;
49 unsigned u16t;
50 /* log delta leak value (Q23) */
51 const uint32_t logDeltaLeakVal = 0x7F6CL;
52
53 /* Turn the quantised code back into an index into the threshold table. This
54 * involves bitwise inversion of the code (if -ve) and adding 1 (phantom
55 * element at table base). Then set invQ to be +/- the threshold value,
56 * depending on the code sign. */
57 index = qCode;
58 if (qCode < 0) {
59 index = (~index);
60 }
61 index = index + 1;
62 invQ = iqdata_pt->thresholdTablePtr_sl1[index];
63 if (qCode < 0) {
64 invQ = -invQ;
65 }
66
67 /* Load invQ into the accumulator. Add the product of the dither value times
68 * the indexed dither table value. Then get the result back from the
69 * accumulator as an updated invQ. */
70 tmp_r64.s64 = ((int64_t)ditherVal * iqdata_pt->ditherTablePtr_sf1[index]);
71 tmp_r64.s32.h += invQ >> 1;
72
73 acc = tmp_r64.s32.h;
74
75 tmp_round1 = tmp_r64.s32.h & 0x00000001L;
76 if (tmp_r64.u32.l >= 0x80000000) {
77 acc++;
78 }
79 if (tmp_round1 == 0 && tmp_r64.s32.l == (int32_t)0x80000000L) {
80 acc--;
81 }
82 acc = ssat24(acc);
83
84 invQ = acc;
85
86 /* Scale invQ by the current delta value. Left-shift the result (in the
87 * accumulator) by 4 positions for the delta scaling. Get the updated invQ
88 * back from the accumulator. */
89 u16t = iqdata_pt->logDelta;
90 tmp_acc = ((int64_t)invQ * iqdata_pt->delta);
91 tmp_accL = u16t * logDeltaLeakVal;
92 tmp_accH = iqdata_pt->incrTablePtr[index];
93 acc = (int32_t)(tmp_acc >> (23 - deltaScale));
94 invQ = ssat24(acc);
95
96 /* Now update the value of logDelta. Load the accumulator with the index
97 * value of the logDelta increment table. Add the product of the current
98 * logDelta scaled by a leaky coefficient (16310 in Q14). Get the value back
99 * from the accumulator. */
100 tmp_accH += tmp_accL >> (32 - 17);
101
102 acc = tmp_accH;
103
104 tmp_r64.u32.l = ((uint32_t)tmp_accL << 17);
105 tmp_r64.s32.h = tmp_accH;
106
107 tmp_round0 = tmp_r64.u32.l;
108 tmp_round1 = (int32_t)(tmp_r64.u64 >> 1);
109 if (tmp_round0 >= 0x80000000L) {
110 acc++;
111 }
112 if (tmp_round1 == 0x40000000L) {
113 acc--;
114 }
115
116 /* Limit the updated logDelta between 0 and its subband-specific maximum. */
117 if (acc < 0) {
118 acc = 0;
119 }
120 if (acc > iqdata_pt->maxLogDelta) {
121 acc = iqdata_pt->maxLogDelta;
122 }
123
124 iqdata_pt->logDelta = (uint16_t)acc;
125
126 /* The updated value of delta is the logTable output (indexed by 5 bits from
127 * the updated logDelta) shifted by a value involving the logDelta minimum
128 * and the updated logDelta itself. */
129 iqdata_pt->delta = iqdata_pt->iquantTableLogPtr[(acc >> 3) & 0x1f] >>
130 (22 - 25 - iqdata_pt->minLogDelta - (acc >> 8));
131
132 iqdata_pt->invQ = invQ;
133 }
134
invertQuantisationHL(const int32_t qCode,const int32_t ditherVal,IQuantiser_data * iqdata_pt)135 XBT_INLINE_ void invertQuantisationHL(const int32_t qCode, const int32_t ditherVal,
136 IQuantiser_data* iqdata_pt) {
137 int32_t invQ;
138 int32_t index;
139 int32_t acc;
140 reg64_t tmp_r64;
141 int64_t tmp_acc;
142 int32_t tmp_accL;
143 int32_t tmp_accH;
144 uint32_t tmp_round0;
145 uint32_t tmp_round1;
146 unsigned u16t;
147 /* log delta leak value (Q23) */
148 const uint32_t logDeltaLeakVal = 0x7F6CL;
149
150 /* Turn the quantised code back into an index into the threshold table. This
151 * involves bitwise inversion of the code (if -ve) and adding 1 (phantom
152 * element at table base). Then set invQ to be +/- the threshold value,
153 * depending on the code sign. */
154 index = qCode;
155 if (qCode < 0) {
156 index = (~index);
157 }
158 index = index + 1;
159 invQ = iqdata_pt->thresholdTablePtr_sl1[index];
160 if (qCode < 0) {
161 invQ = -invQ;
162 }
163
164 /* Load invQ into the accumulator. Add the product of the dither value times
165 * the indexed dither table value. Then get the result back from the
166 * accumulator as an updated invQ. */
167 tmp_r64.s64 = ((int64_t)ditherVal * iqdata_pt->ditherTablePtr_sf1[index]);
168 tmp_r64.s32.h += invQ >> 1;
169
170 acc = tmp_r64.s32.h;
171
172 tmp_round1 = tmp_r64.s32.h & 0x00000001L;
173 if (tmp_r64.u32.l >= 0x80000000) {
174 acc++;
175 }
176 if (tmp_round1 == 0 && tmp_r64.u32.l == 0x80000000L) {
177 acc--;
178 }
179 acc = ssat24(acc);
180
181 invQ = acc;
182
183 /* Scale invQ by the current delta value. Left-shift the result (in the
184 * accumulator) by 4 positions for the delta scaling. Get the updated invQ
185 * back from the accumulator. */
186 u16t = iqdata_pt->logDelta;
187 tmp_acc = ((int64_t)invQ * iqdata_pt->delta);
188 tmp_accL = u16t * logDeltaLeakVal;
189 tmp_accH = iqdata_pt->incrTablePtr[index];
190 acc = (int32_t)(tmp_acc >> (23 - deltaScale));
191 invQ = ssat24(acc);
192
193 /* Now update the value of logDelta. Load the accumulator with the index
194 * value of the logDelta increment table. Add the product of the current
195 * logDelta scaled by a leaky coefficient (16310 in Q14). Get the value back
196 * from the accumulator. */
197 tmp_accH += tmp_accL >> (32 - 17);
198
199 acc = tmp_accH;
200
201 tmp_r64.u32.l = ((uint32_t)tmp_accL << 17);
202 tmp_r64.s32.h = tmp_accH;
203
204 tmp_round0 = tmp_r64.u32.l;
205 tmp_round1 = (int32_t)(tmp_r64.u64 >> 1);
206 if (tmp_round0 >= 0x80000000L) {
207 acc++;
208 }
209 if (tmp_round1 == 0x40000000L) {
210 acc--;
211 }
212
213 /* Limit the updated logDelta between 0 and its subband-specific maximum. */
214 if (acc < 0) {
215 acc = 0;
216 }
217 if (acc > iqdata_pt->maxLogDelta) {
218 acc = iqdata_pt->maxLogDelta;
219 }
220
221 iqdata_pt->logDelta = (uint16_t)acc;
222
223 /* The updated value of delta is the logTable output (indexed by 5 bits from
224 * the updated logDelta) shifted by a value involving the logDelta minimum
225 * and the updated logDelta itself. */
226 iqdata_pt->delta = iqdata_pt->iquantTableLogPtr[(acc >> 3) & 0x1f] >>
227 (22 - 25 - iqdata_pt->minLogDelta - (acc >> 8));
228
229 iqdata_pt->invQ = invQ;
230 }
231
232 /* Function to carry out prediction ARMA filtering for the current subband
233 * performPredictionFiltering should only be used for HH and LH subband! */
performPredictionFiltering(const int32_t invQ,Subband_data * SubbandDataPt)234 XBT_INLINE_ void performPredictionFiltering(const int32_t invQ, Subband_data* SubbandDataPt) {
235 int32_t poleVal;
236 int32_t acc;
237 int64_t accL;
238 uint32_t pointer;
239 int32_t poleDelayLine;
240 int32_t predVal;
241 int32_t* zeroCoeffPt = SubbandDataPt->m_ZeroCoeffData.m_zeroCoeff;
242 int32_t* poleCoeff = SubbandDataPt->m_PoleCoeffData.m_poleCoeff;
243 int32_t* cbuf_pt;
244 int32_t invQincr_pos;
245 int32_t invQincr_neg;
246 int32_t k;
247 int32_t oldZData;
248 /* Pole coefficient and data indices */
249 enum { a1 = 0, a2 = 1 };
250
251 /* Write the newest pole input sample to the pole delay line.
252 * Ensure the sum of the current dequantised error and the previous
253 * predictor output is saturated if necessary. */
254 poleDelayLine = invQ + SubbandDataPt->m_predData.m_predVal;
255
256 poleDelayLine = ssat24(poleDelayLine);
257
258 /* Pole filter convolution. Shift convolution result 1 place to the left
259 * before retrieving it, since the pole coefficients are Q22 (data is Q23)
260 * and we want a Q23 result */
261 accL = ((int64_t)poleCoeff[a2] * (int64_t)SubbandDataPt->m_predData.m_poleDelayLine[a2]);
262 /* Update the pole delay line for the next pass by writing the new input
263 * sample into the 2nd element */
264 SubbandDataPt->m_predData.m_poleDelayLine[a2] = poleDelayLine;
265 accL += ((int64_t)poleCoeff[a1] * (int64_t)poleDelayLine);
266 poleVal = (int32_t)(accL >> 22);
267 poleVal = ssat24(poleVal);
268
269 /* Create (2^(-7)) * sgn(invQ) in Q22 format. */
270 if (invQ == 0) {
271 invQincr_pos = 0L;
272 } else {
273 invQincr_pos = 0x800000;
274 }
275 if (invQ < 0L) {
276 invQincr_pos = -invQincr_pos;
277 }
278
279 invQincr_neg = 0x0080 - invQincr_pos;
280 invQincr_pos += 0x0080;
281
282 pointer = (SubbandDataPt->m_predData.m_zeroDelayLine.pointer++) + 12;
283 cbuf_pt = &SubbandDataPt->m_predData.m_zeroDelayLine.buffer[pointer];
284 /* partial manual unrolling to improve performance */
285 if (SubbandDataPt->m_predData.m_zeroDelayLine.pointer >= 12) {
286 SubbandDataPt->m_predData.m_zeroDelayLine.pointer = 0;
287 }
288
289 SubbandDataPt->m_predData.m_zeroDelayLine.modulo = invQ;
290
291 /* Iterate over the number of coefficients for this subband */
292 oldZData = invQ;
293 accL = 0;
294 for (k = 0; k < 12; k++) {
295 uint32_t tmp_round0;
296 int32_t coeffValue;
297 int32_t zData0;
298
299 /* ------------------------------------------------------------------*/
300 zData0 = (*(cbuf_pt--));
301 coeffValue = *(zeroCoeffPt + k);
302 if (zData0 < 0L) {
303 acc = invQincr_neg - coeffValue;
304 } else {
305 acc = invQincr_pos - coeffValue;
306 }
307 tmp_round0 = acc;
308 acc = (acc >> 8) + coeffValue;
309 if (((tmp_round0 << 23) ^ 0x80000000) == 0) {
310 acc--;
311 }
312 accL += (int64_t)acc * (int64_t)(oldZData);
313 oldZData = zData0;
314 *(zeroCoeffPt + k) = acc;
315 }
316
317 acc = (int32_t)(accL >> 22);
318 acc = ssat24(acc);
319
320 /* Predictor output is the sum of the pole and zero filter outputs. Ensure
321 * this is saturated, if necessary. */
322 predVal = acc + poleVal;
323 predVal = ssat24(predVal);
324 SubbandDataPt->m_predData.m_zeroVal = acc;
325 SubbandDataPt->m_predData.m_predVal = predVal;
326
327 /* Update the zero filter delay line by writing the new input sample to the
328 * circular buffer. */
329 SubbandDataPt->m_predData.m_zeroDelayLine
330 .buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer] =
331 SubbandDataPt->m_predData.m_zeroDelayLine.modulo;
332 SubbandDataPt->m_predData.m_zeroDelayLine
333 .buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer + 12] =
334 SubbandDataPt->m_predData.m_zeroDelayLine.modulo;
335 }
336
performPredictionFilteringLL(const int32_t invQ,Subband_data * SubbandDataPt)337 XBT_INLINE_ void performPredictionFilteringLL(const int32_t invQ, Subband_data* SubbandDataPt) {
338 int32_t poleVal;
339 int32_t acc;
340 int64_t accL;
341 uint32_t pointer;
342 int32_t poleDelayLine;
343 int32_t predVal;
344 int32_t* zeroCoeffPt = SubbandDataPt->m_ZeroCoeffData.m_zeroCoeff;
345 int32_t* poleCoeff = SubbandDataPt->m_PoleCoeffData.m_poleCoeff;
346 int32_t* cbuf_pt;
347 int32_t invQincr_pos;
348 int32_t invQincr_neg;
349 int32_t k;
350 int32_t oldZData;
351 /* Pole coefficient and data indices */
352 enum { a1 = 0, a2 = 1 };
353
354 /* Write the newest pole input sample to the pole delay line.
355 * Ensure the sum of the current dequantised error and the previous
356 * predictor output is saturated if necessary. */
357 poleDelayLine = invQ + SubbandDataPt->m_predData.m_predVal;
358
359 poleDelayLine = ssat24(poleDelayLine);
360
361 /* Pole filter convolution. Shift convolution result 1 place to the left
362 * before retrieving it, since the pole coefficients are Q22 (data is Q23)
363 * and we want a Q23 result */
364 accL = ((int64_t)poleCoeff[a2] * (int64_t)SubbandDataPt->m_predData.m_poleDelayLine[a2]);
365 /* Update the pole delay line for the next pass by writing the new input
366 * sample into the 2nd element */
367 SubbandDataPt->m_predData.m_poleDelayLine[a2] = poleDelayLine;
368 accL += ((int64_t)poleCoeff[a1] * (int64_t)poleDelayLine);
369 poleVal = (int32_t)(accL >> 22);
370 poleVal = ssat24(poleVal);
371 /* store poleVal to free one register. */
372 SubbandDataPt->m_predData.m_predVal = poleVal;
373
374 /* Create (2^(-7)) * sgn(invQ) in Q22 format. */
375 if (invQ == 0) {
376 invQincr_pos = 0L;
377 } else {
378 invQincr_pos = 0x800000;
379 }
380 if (invQ < 0L) {
381 invQincr_pos = -invQincr_pos;
382 }
383
384 invQincr_neg = 0x0080 - invQincr_pos;
385 invQincr_pos += 0x0080;
386
387 pointer = (SubbandDataPt->m_predData.m_zeroDelayLine.pointer++) + 24;
388 cbuf_pt = &SubbandDataPt->m_predData.m_zeroDelayLine.buffer[pointer];
389 /* partial manual unrolling to improve performance */
390 if (SubbandDataPt->m_predData.m_zeroDelayLine.pointer >= 24) {
391 SubbandDataPt->m_predData.m_zeroDelayLine.pointer = 0;
392 }
393
394 SubbandDataPt->m_predData.m_zeroDelayLine.modulo = invQ;
395
396 /* Iterate over the number of coefficients for this subband */
397 oldZData = invQ;
398 accL = 0;
399 for (k = 0; k < 24; k++) {
400 int32_t zData0;
401 int32_t coeffValue;
402
403 zData0 = (*(cbuf_pt--));
404 coeffValue = *(zeroCoeffPt + k);
405 if (zData0 < 0L) {
406 acc = invQincr_neg - coeffValue;
407 } else {
408 acc = invQincr_pos - coeffValue;
409 }
410 if (((acc << 23) ^ 0x80000000) == 0) {
411 coeffValue--;
412 }
413 acc = (acc >> 8) + coeffValue;
414 accL += (int64_t)acc * (int64_t)(oldZData);
415 oldZData = zData0;
416 *(zeroCoeffPt + k) = acc;
417 }
418
419 acc = (int32_t)(accL >> 22);
420 acc = ssat24(acc);
421
422 /* Predictor output is the sum of the pole and zero filter outputs. Ensure
423 * this is saturated, if necessary.
424 * recover value of PoleVal stored at beginning of routine... */
425 predVal = acc + SubbandDataPt->m_predData.m_predVal;
426 predVal = ssat24(predVal);
427 SubbandDataPt->m_predData.m_zeroVal = acc;
428 SubbandDataPt->m_predData.m_predVal = predVal;
429
430 /* Update the zero filter delay line by writing the new input sample to the
431 * circular buffer. */
432 SubbandDataPt->m_predData.m_zeroDelayLine
433 .buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer] =
434 SubbandDataPt->m_predData.m_zeroDelayLine.modulo;
435 SubbandDataPt->m_predData.m_zeroDelayLine
436 .buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer + 24] =
437 SubbandDataPt->m_predData.m_zeroDelayLine.modulo;
438 }
439
performPredictionFilteringHL(const int32_t invQ,Subband_data * SubbandDataPt)440 XBT_INLINE_ void performPredictionFilteringHL(const int32_t invQ, Subband_data* SubbandDataPt) {
441 int32_t poleVal;
442 int32_t acc;
443 int64_t accL;
444 uint32_t pointer;
445 int32_t poleDelayLine;
446 int32_t predVal;
447 int32_t* zeroCoeffPt = SubbandDataPt->m_ZeroCoeffData.m_zeroCoeff;
448 int32_t* poleCoeff = SubbandDataPt->m_PoleCoeffData.m_poleCoeff;
449 int32_t* cbuf_pt;
450 int32_t invQincr_pos;
451 int32_t invQincr_neg;
452 int32_t k;
453 int32_t oldZData;
454 const int32_t roundCte = 0x80000000;
455 /* Pole coefficient and data indices */
456 enum { a1 = 0, a2 = 1 };
457
458 /* Write the newest pole input sample to the pole delay line.
459 * Ensure the sum of the current dequantised error and the previous
460 * predictor output is saturated if necessary. */
461 poleDelayLine = invQ + SubbandDataPt->m_predData.m_predVal;
462
463 poleDelayLine = ssat24(poleDelayLine);
464
465 /* Pole filter convolution. Shift convolution result 1 place to the left
466 * before retrieving it, since the pole coefficients are Q22 (data is Q23)
467 * and we want a Q23 result */
468 accL = ((int64_t)poleCoeff[a2] * (int64_t)SubbandDataPt->m_predData.m_poleDelayLine[a2]);
469 /* Update the pole delay line for the next pass by writing the new input
470 * sample into the 2nd element */
471 SubbandDataPt->m_predData.m_poleDelayLine[a2] = poleDelayLine;
472 accL += ((int64_t)poleCoeff[a1] * (int64_t)poleDelayLine);
473 poleVal = (int32_t)(accL >> 22);
474 poleVal = ssat24(poleVal);
475
476 /* Create (2^(-7)) * sgn(invQ) in Q22 format. */
477 invQincr_pos = 0L;
478 if (invQ != 0) {
479 invQincr_pos = 0x800000;
480 }
481 if (invQ < 0L) {
482 invQincr_pos = -invQincr_pos;
483 }
484
485 invQincr_neg = 0x0080 - invQincr_pos;
486 invQincr_pos += 0x0080;
487
488 pointer = (SubbandDataPt->m_predData.m_zeroDelayLine.pointer++) + 6;
489 cbuf_pt = &SubbandDataPt->m_predData.m_zeroDelayLine.buffer[pointer];
490 /* partial manual unrolling to improve performance */
491 if (SubbandDataPt->m_predData.m_zeroDelayLine.pointer >= 6) {
492 SubbandDataPt->m_predData.m_zeroDelayLine.pointer = 0;
493 }
494
495 SubbandDataPt->m_predData.m_zeroDelayLine.modulo = invQ;
496
497 /* Iterate over the number of coefficients for this subband */
498 oldZData = invQ;
499 accL = 0;
500
501 for (k = 0; k < 6; k++) {
502 uint32_t tmp_round0;
503 int32_t coeffValue;
504 int32_t zData0;
505
506 /* ------------------------------------------------------------------*/
507 zData0 = (*(cbuf_pt--));
508 coeffValue = *(zeroCoeffPt + k);
509 if (zData0 < 0L) {
510 acc = invQincr_neg - coeffValue;
511 } else {
512 acc = invQincr_pos - coeffValue;
513 }
514 tmp_round0 = acc;
515 acc = (acc >> 8) + coeffValue;
516 if (((tmp_round0 << 23) ^ roundCte) == 0) {
517 acc--;
518 }
519 accL += (int64_t)acc * (int64_t)(oldZData);
520 oldZData = zData0;
521 *(zeroCoeffPt + k) = acc;
522 }
523
524 acc = (int32_t)(accL >> 22);
525 acc = ssat24(acc);
526
527 /* Predictor output is the sum of the pole and zero filter outputs. Ensure
528 * this is saturated, if necessary. */
529 predVal = acc + poleVal;
530 predVal = ssat24(predVal);
531 SubbandDataPt->m_predData.m_zeroVal = acc;
532 SubbandDataPt->m_predData.m_predVal = predVal;
533
534 /* Update the zero filter delay line by writing the new input sample to the
535 * circular buffer. */
536 SubbandDataPt->m_predData.m_zeroDelayLine
537 .buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer] =
538 SubbandDataPt->m_predData.m_zeroDelayLine.modulo;
539 SubbandDataPt->m_predData.m_zeroDelayLine
540 .buffer[SubbandDataPt->m_predData.m_zeroDelayLine.pointer + 6] =
541 SubbandDataPt->m_predData.m_zeroDelayLine.modulo;
542 }
543
544 #endif // SUBBANDFUNCTIONSCOMMON_H
545