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,
82 int32_t* aqmfOutputs) {
83 int32_t convSumDiff[4];
84 int32_t filterOutputs[4];
85
86 int32_t lc_QmfO_pt = (Qmf_St->QmfO_pt);
87 int32_t lc_QmfI_pt = (Qmf_St->QmfI_pt);
88
89 /* Run the analysis QMF */
90 /* Symbolic constants to represent the first and second set out outer filter
91 * outputs. */
92 enum { FirstOuterOutputs = 0, SecondOuterOutputs = 1 };
93
94 /* Load outer filter phase1 and phase2 delay lines with the first 2 PCM
95 * samples. Convolve the filter and get the 2 convolution results. */
96 Qmf_St->QmfL_buf[lc_QmfO_pt + 16] = pcm[FirstPcm];
97 Qmf_St->QmfL_buf[lc_QmfO_pt] = pcm[FirstPcm];
98 Qmf_St->QmfH_buf[lc_QmfO_pt + 16] = pcm[SecondPcm];
99 Qmf_St->QmfH_buf[lc_QmfO_pt++] = pcm[SecondPcm];
100 lc_QmfO_pt &= 0xF;
101
102 AsmQmfConvO_HD(&Qmf_St->QmfL_buf[lc_QmfO_pt + 15],
103 &Qmf_St->QmfH_buf[lc_QmfO_pt], Qmf_outerCoeffs,
104 &convSumDiff[0]);
105
106 /* Load outer filter phase1 and phase2 delay lines with the second 2 PCM
107 * samples. Convolve the filter and get the 2 convolution results. */
108 Qmf_St->QmfL_buf[lc_QmfO_pt + 16] = pcm[ThirdPcm];
109 Qmf_St->QmfL_buf[lc_QmfO_pt] = pcm[ThirdPcm];
110 Qmf_St->QmfH_buf[lc_QmfO_pt + 16] = pcm[FourthPcm];
111 Qmf_St->QmfH_buf[lc_QmfO_pt++] = pcm[FourthPcm];
112 lc_QmfO_pt &= 0xF;
113
114 AsmQmfConvO_HD(&Qmf_St->QmfL_buf[lc_QmfO_pt + 15],
115 &Qmf_St->QmfH_buf[lc_QmfO_pt], Qmf_outerCoeffs,
116 &convSumDiff[1]);
117
118 /* Load the first inner filter phase1 and phase2 delay lines with the 2
119 * convolution sum (low-pass) outer filter outputs. Convolve the filter and
120 * get the 2 convolution results. The first 2 analysis filter outputs are
121 * the sum and difference values for the first inner filter convolutions. */
122 Qmf_St->QmfLL_buf[lc_QmfI_pt + 16] = convSumDiff[0];
123 Qmf_St->QmfLL_buf[lc_QmfI_pt] = convSumDiff[0];
124 Qmf_St->QmfLH_buf[lc_QmfI_pt + 16] = convSumDiff[1];
125 Qmf_St->QmfLH_buf[lc_QmfI_pt] = convSumDiff[1];
126
127 AsmQmfConvI_HD(&Qmf_St->QmfLL_buf[lc_QmfI_pt + 16],
128 &Qmf_St->QmfLH_buf[lc_QmfI_pt + 1], &Qmf_innerCoeffs[0],
129 &filterOutputs[LL]);
130
131 /* Load the second inner filter phase1 and phase2 delay lines with the 2
132 * convolution difference (high-pass) outer filter outputs. Convolve the
133 * filter and get the 2 convolution results. The second 2 analysis filter
134 * outputs are the sum and difference values for the second inner filter
135 * convolutions. */
136 Qmf_St->QmfHL_buf[lc_QmfI_pt + 16] = convSumDiff[2];
137 Qmf_St->QmfHL_buf[lc_QmfI_pt] = convSumDiff[2];
138 Qmf_St->QmfHH_buf[lc_QmfI_pt + 16] = convSumDiff[3];
139 Qmf_St->QmfHH_buf[lc_QmfI_pt++] = convSumDiff[3];
140 lc_QmfI_pt &= 0xF;
141
142 AsmQmfConvI_HD(&Qmf_St->QmfHL_buf[lc_QmfI_pt + 15],
143 &Qmf_St->QmfHH_buf[lc_QmfI_pt], &Qmf_innerCoeffs[0],
144 &filterOutputs[HL]);
145
146 /* Subtracted the previous predicted value from the filter output on a
147 * per-subband basis. Ensure these values are saturated, if necessary.
148 * Manual unrolling */
149 aqmfOutputs[LL] = filterOutputs[LL] - predVals[LL];
150 if (aqmfOutputs[LL] > 8388607) {
151 aqmfOutputs[LL] = 8388607;
152 }
153 if (aqmfOutputs[LL] < -8388608) {
154 aqmfOutputs[LL] = -8388608;
155 }
156
157 aqmfOutputs[LH] = filterOutputs[LH] - predVals[LH];
158 if (aqmfOutputs[LH] > 8388607) {
159 aqmfOutputs[LH] = 8388607;
160 }
161 if (aqmfOutputs[LH] < -8388608) {
162 aqmfOutputs[LH] = -8388608;
163 }
164
165 aqmfOutputs[HL] = filterOutputs[HL] - predVals[HL];
166 if (aqmfOutputs[HL] > 8388607) {
167 aqmfOutputs[HL] = 8388607;
168 }
169 if (aqmfOutputs[HL] < -8388608) {
170 aqmfOutputs[HL] = -8388608;
171 }
172
173 aqmfOutputs[HH] = filterOutputs[HH] - predVals[HH];
174 if (aqmfOutputs[HH] > 8388607) {
175 aqmfOutputs[HH] = 8388607;
176 }
177 if (aqmfOutputs[HH] < -8388608) {
178 aqmfOutputs[HH] = -8388608;
179 }
180
181 (Qmf_St->QmfO_pt) = lc_QmfO_pt;
182 (Qmf_St->QmfI_pt) = lc_QmfI_pt;
183 }
184
185 #endif // QMF_H
186