• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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