• 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  *  This file includes the coefficient tables or the two convolution function
19  *  It also includes the definition of Qmf_storage and the prototype of all
20  *  necessary functions required to implement the QMF filtering.
21  *
22  *----------------------------------------------------------------------------*/
23 
24 #ifndef QMF_H
25 #define QMF_H
26 
27 #include "AptxParameters.h"
28 
29 typedef struct {
30   int32_t QmfL_buf[32];
31   int32_t QmfH_buf[32];
32   int32_t QmfLH_buf[32];
33   int32_t QmfHL_buf[32];
34   int32_t QmfLL_buf[32];
35   int32_t QmfHH_buf[32];
36   int32_t QmfI_pt;
37   int32_t QmfO_pt;
38 } Qmf_storage;
39 
40 /* Outer QMF filter for aptX HD is a symmetrical 32-tap filter (16
41  * different coefficients). The table defined in QmfConv.c */
42 #ifndef _STDQMFOUTERCOEFF
43 static const int32_t Qmf_outerCoeffs[12] = {
44         /* (C(1/30)C(3/28)), C(5/26), C(7/24) */
45         0xFE6302DA,
46         0xFFFFDA75,
47         0x0000AA6A,
48         /*  C(9/22), C(11/20), C(13/18), C(15/16) */
49         0xFFFE273E,
50         0x00041E95,
51         0xFFF710B5,
52         0x002AC12E,
53         /*  C(17/14), C(19/12), (C(21/10)C(23/8)) */
54         0x000AA328,
55         0xFFFD8D1F,
56         0x211E6BDB,
57         /* (C(25/6)C(27/4)), (C(29/2)C(31/0)) */
58         0x0DB7D8C5,
59         0xFC7F02B0,
60 };
61 #else
62 static const int32_t Qmf_outerCoeffs[16] = {
63         730,    -413,    -9611, 43626, -121026, 269973, -585547, 2801966,
64         697128, -160481, 27611, 8478,  -10043,  3511,   688,     -897,
65 };
66 #endif
67 
68 /* Each inner QMF filter for aptX HD is a symmetrical 32-tap filter (16
69  * different coefficients) */
70 static const int32_t Qmf_innerCoeffs[16] = {
71         1033,   -584,    -13592, 61697, -171156, 381799, -828088, 3962579,
72         985888, -226954, 39048,  11990, -14203,  4966,   973,     -1268,
73 };
74 
75 void AsmQmfConvI_HD(const int32_t* p1dl_buffPtr, const int32_t* p2dl_buffPtr,
76                     const int32_t* coeffPtr, int32_t* filterOutputs);
77 void AsmQmfConvO_HD(const int32_t* p1dl_buffPtr, const int32_t* p2dl_buffPtr,
78                     const int32_t* coeffPtr, int32_t* convSumDiff);
79 
QmfAnalysisFilter(const int32_t pcm[4],Qmf_storage * Qmf_St,const int32_t * predVals,int32_t * aqmfOutputs)80 XBT_INLINE_ void QmfAnalysisFilter(const int32_t pcm[4], Qmf_storage* Qmf_St,
81                                    const int32_t* predVals, int32_t* aqmfOutputs) {
82   int32_t convSumDiff[4];
83   int32_t filterOutputs[4];
84 
85   int32_t lc_QmfO_pt = (Qmf_St->QmfO_pt);
86   int32_t lc_QmfI_pt = (Qmf_St->QmfI_pt);
87 
88   /* Run the analysis QMF */
89   /* Symbolic constants to represent the first and second set out outer filter
90    * outputs. */
91   enum { FirstOuterOutputs = 0, SecondOuterOutputs = 1 };
92 
93   /* Load outer filter phase1 and phase2 delay lines with the first 2 PCM
94    * samples. Convolve the filter and get the 2 convolution results. */
95   Qmf_St->QmfL_buf[lc_QmfO_pt + 16] = pcm[FirstPcm];
96   Qmf_St->QmfL_buf[lc_QmfO_pt] = pcm[FirstPcm];
97   Qmf_St->QmfH_buf[lc_QmfO_pt + 16] = pcm[SecondPcm];
98   Qmf_St->QmfH_buf[lc_QmfO_pt++] = pcm[SecondPcm];
99   lc_QmfO_pt &= 0xF;
100 
101   AsmQmfConvO_HD(&Qmf_St->QmfL_buf[lc_QmfO_pt + 15], &Qmf_St->QmfH_buf[lc_QmfO_pt], Qmf_outerCoeffs,
102                  &convSumDiff[0]);
103 
104   /* Load outer filter phase1 and phase2 delay lines with the second 2 PCM
105    * samples. Convolve the filter and get the 2 convolution results. */
106   Qmf_St->QmfL_buf[lc_QmfO_pt + 16] = pcm[ThirdPcm];
107   Qmf_St->QmfL_buf[lc_QmfO_pt] = pcm[ThirdPcm];
108   Qmf_St->QmfH_buf[lc_QmfO_pt + 16] = pcm[FourthPcm];
109   Qmf_St->QmfH_buf[lc_QmfO_pt++] = pcm[FourthPcm];
110   lc_QmfO_pt &= 0xF;
111 
112   AsmQmfConvO_HD(&Qmf_St->QmfL_buf[lc_QmfO_pt + 15], &Qmf_St->QmfH_buf[lc_QmfO_pt], Qmf_outerCoeffs,
113                  &convSumDiff[1]);
114 
115   /* Load the first inner filter phase1 and phase2 delay lines with the 2
116    * convolution sum (low-pass) outer filter outputs. Convolve the filter and
117    * get the 2 convolution results. The first 2 analysis filter outputs are
118    * the sum and difference values for the first inner filter convolutions. */
119   Qmf_St->QmfLL_buf[lc_QmfI_pt + 16] = convSumDiff[0];
120   Qmf_St->QmfLL_buf[lc_QmfI_pt] = convSumDiff[0];
121   Qmf_St->QmfLH_buf[lc_QmfI_pt + 16] = convSumDiff[1];
122   Qmf_St->QmfLH_buf[lc_QmfI_pt] = convSumDiff[1];
123 
124   AsmQmfConvI_HD(&Qmf_St->QmfLL_buf[lc_QmfI_pt + 16], &Qmf_St->QmfLH_buf[lc_QmfI_pt + 1],
125                  &Qmf_innerCoeffs[0], &filterOutputs[LL]);
126 
127   /* Load the second inner filter phase1 and phase2 delay lines with the 2
128    * convolution difference (high-pass) outer filter outputs. Convolve the
129    * filter and get the 2 convolution results. The second 2 analysis filter
130    * outputs are the sum and difference values for the second inner filter
131    * convolutions. */
132   Qmf_St->QmfHL_buf[lc_QmfI_pt + 16] = convSumDiff[2];
133   Qmf_St->QmfHL_buf[lc_QmfI_pt] = convSumDiff[2];
134   Qmf_St->QmfHH_buf[lc_QmfI_pt + 16] = convSumDiff[3];
135   Qmf_St->QmfHH_buf[lc_QmfI_pt++] = convSumDiff[3];
136   lc_QmfI_pt &= 0xF;
137 
138   AsmQmfConvI_HD(&Qmf_St->QmfHL_buf[lc_QmfI_pt + 15], &Qmf_St->QmfHH_buf[lc_QmfI_pt],
139                  &Qmf_innerCoeffs[0], &filterOutputs[HL]);
140 
141   /* Subtracted the previous predicted value from the filter output on a
142    * per-subband basis. Ensure these values are saturated, if necessary.
143    * Manual unrolling */
144   aqmfOutputs[LL] = filterOutputs[LL] - predVals[LL];
145   if (aqmfOutputs[LL] > 8388607) {
146     aqmfOutputs[LL] = 8388607;
147   }
148   if (aqmfOutputs[LL] < -8388608) {
149     aqmfOutputs[LL] = -8388608;
150   }
151 
152   aqmfOutputs[LH] = filterOutputs[LH] - predVals[LH];
153   if (aqmfOutputs[LH] > 8388607) {
154     aqmfOutputs[LH] = 8388607;
155   }
156   if (aqmfOutputs[LH] < -8388608) {
157     aqmfOutputs[LH] = -8388608;
158   }
159 
160   aqmfOutputs[HL] = filterOutputs[HL] - predVals[HL];
161   if (aqmfOutputs[HL] > 8388607) {
162     aqmfOutputs[HL] = 8388607;
163   }
164   if (aqmfOutputs[HL] < -8388608) {
165     aqmfOutputs[HL] = -8388608;
166   }
167 
168   aqmfOutputs[HH] = filterOutputs[HH] - predVals[HH];
169   if (aqmfOutputs[HH] > 8388607) {
170     aqmfOutputs[HH] = 8388607;
171   }
172   if (aqmfOutputs[HH] < -8388608) {
173     aqmfOutputs[HH] = -8388608;
174   }
175 
176   (Qmf_St->QmfO_pt) = lc_QmfO_pt;
177   (Qmf_St->QmfI_pt) = lc_QmfI_pt;
178 }
179 
180 #endif  // QMF_H
181