xref: /btstack/3rd-party/bluedroid/decoder/srce/synthesis-sbc.c (revision df25739fc3ea5a0a90f0f5925e6461d653697d2e)
1*df25739fSMilanka Ringwald /******************************************************************************
2*df25739fSMilanka Ringwald  *
3*df25739fSMilanka Ringwald  *  Copyright (C) 2014 The Android Open Source Project
4*df25739fSMilanka Ringwald  *  Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved.
5*df25739fSMilanka Ringwald  *
6*df25739fSMilanka Ringwald  *  Licensed under the Apache License, Version 2.0 (the "License");
7*df25739fSMilanka Ringwald  *  you may not use this file except in compliance with the License.
8*df25739fSMilanka Ringwald  *  You may obtain a copy of the License at:
9*df25739fSMilanka Ringwald  *
10*df25739fSMilanka Ringwald  *  http://www.apache.org/licenses/LICENSE-2.0
11*df25739fSMilanka Ringwald  *
12*df25739fSMilanka Ringwald  *  Unless required by applicable law or agreed to in writing, software
13*df25739fSMilanka Ringwald  *  distributed under the License is distributed on an "AS IS" BASIS,
14*df25739fSMilanka Ringwald  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15*df25739fSMilanka Ringwald  *  See the License for the specific language governing permissions and
16*df25739fSMilanka Ringwald  *  limitations under the License.
17*df25739fSMilanka Ringwald  *
18*df25739fSMilanka Ringwald  ******************************************************************************/
19*df25739fSMilanka Ringwald 
20*df25739fSMilanka Ringwald /**********************************************************************************
21*df25739fSMilanka Ringwald   $Revision: #1 $
22*df25739fSMilanka Ringwald ***********************************************************************************/
23*df25739fSMilanka Ringwald 
24*df25739fSMilanka Ringwald /** @file
25*df25739fSMilanka Ringwald 
26*df25739fSMilanka Ringwald This file, along with synthesis-generated.c, contains the synthesis
27*df25739fSMilanka Ringwald filterbank routines. The operations performed correspond to the
28*df25739fSMilanka Ringwald operations described in A2DP Appendix B, Figure 12.3. Several
29*df25739fSMilanka Ringwald mathematical optimizations are performed, particularly for the
30*df25739fSMilanka Ringwald 8-subband case.
31*df25739fSMilanka Ringwald 
32*df25739fSMilanka Ringwald One important optimization is to note that the "matrixing" operation
33*df25739fSMilanka Ringwald can be decomposed into the product of a type II discrete cosine kernel
34*df25739fSMilanka Ringwald and another, sparse matrix.
35*df25739fSMilanka Ringwald 
36*df25739fSMilanka Ringwald According to Fig 12.3, in the 8-subband case,
37*df25739fSMilanka Ringwald @code
38*df25739fSMilanka Ringwald     N[k][i] = cos((i+0.5)*(k+4)*pi/8), k = 0..15 and i = 0..7
39*df25739fSMilanka Ringwald @endcode
40*df25739fSMilanka Ringwald 
41*df25739fSMilanka Ringwald N can be factored as R * C2, where C2 is an 8-point type II discrete
42*df25739fSMilanka Ringwald cosine kernel given by
43*df25739fSMilanka Ringwald @code
44*df25739fSMilanka Ringwald     C2[k][i] = cos((i+0.5)*k*pi/8)), k = 0..7 and i = 0..7
45*df25739fSMilanka Ringwald @endcode
46*df25739fSMilanka Ringwald 
47*df25739fSMilanka Ringwald R turns out to be a sparse 16x8 matrix with the following non-zero
48*df25739fSMilanka Ringwald entries:
49*df25739fSMilanka Ringwald @code
50*df25739fSMilanka Ringwald     R[k][k+4]        =  1,   k = 0..3
51*df25739fSMilanka Ringwald     R[k][abs(12-k)]  = -1,   k = 5..15
52*df25739fSMilanka Ringwald @endcode
53*df25739fSMilanka Ringwald 
54*df25739fSMilanka Ringwald The spec describes computing V[0..15] as N * R.
55*df25739fSMilanka Ringwald @code
56*df25739fSMilanka Ringwald     V[0..15] = N * R = (R * C2) * R = R * (C2 * R)
57*df25739fSMilanka Ringwald @endcode
58*df25739fSMilanka Ringwald 
59*df25739fSMilanka Ringwald C2 * R corresponds to computing the discrete cosine transform of R, so
60*df25739fSMilanka Ringwald V[0..15] can be computed by taking the DCT of R followed by assignment
61*df25739fSMilanka Ringwald and selective negation of the DCT result into V.
62*df25739fSMilanka Ringwald 
63*df25739fSMilanka Ringwald         Although this was derived empirically using GNU Octave, it is
64*df25739fSMilanka Ringwald         formally demonstrated in, e.g., Liu, Chi-Min and Lee,
65*df25739fSMilanka Ringwald         Wen-Chieh. "A Unified Fast Algorithm for Cosine Modulated
66*df25739fSMilanka Ringwald         Filter Banks in Current Audio Coding Standards." Journal of
67*df25739fSMilanka Ringwald         the AES 47 (December 1999): 1061.
68*df25739fSMilanka Ringwald 
69*df25739fSMilanka Ringwald Given the shift operation performed prior to computing V[0..15], it is
70*df25739fSMilanka Ringwald clear that V[0..159] represents a rolling history of the 10 most
71*df25739fSMilanka Ringwald recent groups of blocks input to the synthesis operation. Interpreting
72*df25739fSMilanka Ringwald the matrix N in light of its factorization into C2 and R, R's
73*df25739fSMilanka Ringwald sparseness has implications for interpreting the values in V. In
74*df25739fSMilanka Ringwald particular, there is considerable redundancy in the values stored in
75*df25739fSMilanka Ringwald V. Furthermore, since R[4][0..7] are all zeros, one out of every 16
76*df25739fSMilanka Ringwald values in V will be zero regardless of the input data. Within each
77*df25739fSMilanka Ringwald block of 16 values in V, fully half of them are redundant or
78*df25739fSMilanka Ringwald irrelevant:
79*df25739fSMilanka Ringwald 
80*df25739fSMilanka Ringwald @code
81*df25739fSMilanka Ringwald     V[ 0] =  DCT[4]
82*df25739fSMilanka Ringwald     V[ 1] =  DCT[5]
83*df25739fSMilanka Ringwald     V[ 2] =  DCT[6]
84*df25739fSMilanka Ringwald     V[ 3] =  DCT[7]
85*df25739fSMilanka Ringwald     V[ 4] = 0
86*df25739fSMilanka Ringwald     V[ 5] = -DCT[7] = -V[3] (redundant)
87*df25739fSMilanka Ringwald     V[ 6] = -DCT[6] = -V[2] (redundant)
88*df25739fSMilanka Ringwald     V[ 7] = -DCT[5] = -V[1] (redundant)
89*df25739fSMilanka Ringwald     V[ 8] = -DCT[4] = -V[0] (redundant)
90*df25739fSMilanka Ringwald     V[ 9] = -DCT[3]
91*df25739fSMilanka Ringwald     V[10] = -DCT[2]
92*df25739fSMilanka Ringwald     V[11] = -DCT[1]
93*df25739fSMilanka Ringwald     V[12] = -DCT[0]
94*df25739fSMilanka Ringwald     V[13] = -DCT[1] = V[11] (redundant)
95*df25739fSMilanka Ringwald     V[14] = -DCT[2] = V[10] (redundant)
96*df25739fSMilanka Ringwald     V[15] = -DCT[3] = V[ 9] (redundant)
97*df25739fSMilanka Ringwald @endcode
98*df25739fSMilanka Ringwald 
99*df25739fSMilanka Ringwald Since the elements of V beyond 15 were originally computed the same
100*df25739fSMilanka Ringwald way during a previous run, what holds true for V[x] also holds true
101*df25739fSMilanka Ringwald for V[x+16]. Thus, so long as care is taken to maintain the mapping,
102*df25739fSMilanka Ringwald we need only actually store the unique values, which correspond to the
103*df25739fSMilanka Ringwald output of the DCT, in some cases inverted. In fact, instead of storing
104*df25739fSMilanka Ringwald V[0..159], we could store DCT[0..79] which would contain a history of
105*df25739fSMilanka Ringwald DCT results. More on this in a bit.
106*df25739fSMilanka Ringwald 
107*df25739fSMilanka Ringwald Going back to figure 12.3 in the spec, it should be clear that the
108*df25739fSMilanka Ringwald vector U need not actually be explicitly constructed, but that with
109*df25739fSMilanka Ringwald suitable indexing into V during the window operation, the same end can
110*df25739fSMilanka Ringwald be accomplished. In the same spirit of the pseudocode shown in the
111*df25739fSMilanka Ringwald figure, the following is the construction of W without using U:
112*df25739fSMilanka Ringwald 
113*df25739fSMilanka Ringwald @code
114*df25739fSMilanka Ringwald     for i=0 to 79 do
115*df25739fSMilanka Ringwald         W[i] = D[i]*VSIGN(i)*V[remap_V(i)] where remap_V(i) = 32*(int(i/16)) + (i % 16) + (i % 16 >= 8 ? 16 : 0)
116*df25739fSMilanka Ringwald                                              and VSIGN(i) maps i%16 into {1, 1, 1, 1, 0, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1 }
117*df25739fSMilanka Ringwald                                              These values correspond to the
118*df25739fSMilanka Ringwald                                              signs of the redundant values as
119*df25739fSMilanka Ringwald                                              shown in the explanation three
120*df25739fSMilanka Ringwald                                              paragraphs above.
121*df25739fSMilanka Ringwald @endcode
122*df25739fSMilanka Ringwald 
123*df25739fSMilanka Ringwald We saw above how V[4..8,13..15] (and by extension
124*df25739fSMilanka Ringwald V[(4..8,13..15)+16*n]) can be defined in terms of other elements
125*df25739fSMilanka Ringwald within the subblock of V. V[0..3,9..12] correspond to DCT elements.
126*df25739fSMilanka Ringwald 
127*df25739fSMilanka Ringwald @code
128*df25739fSMilanka Ringwald     for i=0 to 79 do
129*df25739fSMilanka Ringwald         W[i] = D[i]*DSIGN(i)*DCT[remap_DCT(i)]
130*df25739fSMilanka Ringwald @endcode
131*df25739fSMilanka Ringwald 
132*df25739fSMilanka Ringwald The DCT is calculated using the Arai-Agui-Nakajima factorization,
133*df25739fSMilanka Ringwald which saves some computation by producing output that needs to be
134*df25739fSMilanka Ringwald multiplied by scaling factors before being used.
135*df25739fSMilanka Ringwald 
136*df25739fSMilanka Ringwald @code
137*df25739fSMilanka Ringwald     for i=0 to 79 do
138*df25739fSMilanka Ringwald         W[i] = D[i]*SCALE[i%8]*AAN_DCT[remap_DCT(i)]
139*df25739fSMilanka Ringwald @endcode
140*df25739fSMilanka Ringwald 
141*df25739fSMilanka Ringwald D can be premultiplied with the DCT scaling factors to yield
142*df25739fSMilanka Ringwald 
143*df25739fSMilanka Ringwald @code
144*df25739fSMilanka Ringwald     for i=0 to 79 do
145*df25739fSMilanka Ringwald         W[i] = DSCALED[i]*AAN_DCT[remap_DCT(i)] where DSCALED[i] = D[i]*SCALE[i%8]
146*df25739fSMilanka Ringwald @endcode
147*df25739fSMilanka Ringwald 
148*df25739fSMilanka Ringwald The output samples X[0..7] are defined as sums of W:
149*df25739fSMilanka Ringwald 
150*df25739fSMilanka Ringwald @code
151*df25739fSMilanka Ringwald         X[j] = sum{i=0..9}(W[j+8*i])
152*df25739fSMilanka Ringwald @endcode
153*df25739fSMilanka Ringwald 
154*df25739fSMilanka Ringwald @ingroup codec_internal
155*df25739fSMilanka Ringwald */
156*df25739fSMilanka Ringwald 
157*df25739fSMilanka Ringwald /**
158*df25739fSMilanka Ringwald @addtogroup codec_internal
159*df25739fSMilanka Ringwald @{
160*df25739fSMilanka Ringwald */
161*df25739fSMilanka Ringwald 
162*df25739fSMilanka Ringwald #include "oi_codec_sbc_private.h"
163*df25739fSMilanka Ringwald 
164*df25739fSMilanka Ringwald const OI_INT32 dec_window_4[21] = {
165*df25739fSMilanka Ringwald            0,        /* +0.00000000E+00 */
166*df25739fSMilanka Ringwald           97,        /* +5.36548976E-04 */
167*df25739fSMilanka Ringwald          270,        /* +1.49188357E-03 */
168*df25739fSMilanka Ringwald          495,        /* +2.73370904E-03 */
169*df25739fSMilanka Ringwald          694,        /* +3.83720193E-03 */
170*df25739fSMilanka Ringwald          704,        /* +3.89205149E-03 */
171*df25739fSMilanka Ringwald          338,        /* +1.86581691E-03 */
172*df25739fSMilanka Ringwald         -554,        /* -3.06012286E-03 */
173*df25739fSMilanka Ringwald         1974,        /* +1.09137620E-02 */
174*df25739fSMilanka Ringwald         3697,        /* +2.04385087E-02 */
175*df25739fSMilanka Ringwald         5224,        /* +2.88757392E-02 */
176*df25739fSMilanka Ringwald         5824,        /* +3.21939290E-02 */
177*df25739fSMilanka Ringwald         4681,        /* +2.58767811E-02 */
178*df25739fSMilanka Ringwald         1109,        /* +6.13245186E-03 */
179*df25739fSMilanka Ringwald        -5214,        /* -2.88217274E-02 */
180*df25739fSMilanka Ringwald       -14047,        /* -7.76463494E-02 */
181*df25739fSMilanka Ringwald        24529,        /* +1.35593274E-01 */
182*df25739fSMilanka Ringwald        35274,        /* +1.94987841E-01 */
183*df25739fSMilanka Ringwald        44618,        /* +2.46636662E-01 */
184*df25739fSMilanka Ringwald        50984,        /* +2.81828203E-01 */
185*df25739fSMilanka Ringwald        53243,        /* +2.94315332E-01 */
186*df25739fSMilanka Ringwald };
187*df25739fSMilanka Ringwald 
188*df25739fSMilanka Ringwald #define DCTII_4_K06_FIX ( 11585)/* S1.14      11585   0.707107*/
189*df25739fSMilanka Ringwald 
190*df25739fSMilanka Ringwald #define DCTII_4_K08_FIX ( 21407)/* S1.14      21407   1.306563*/
191*df25739fSMilanka Ringwald 
192*df25739fSMilanka Ringwald #define DCTII_4_K09_FIX (-15137)/* S1.14     -15137  -0.923880*/
193*df25739fSMilanka Ringwald 
194*df25739fSMilanka Ringwald #define DCTII_4_K10_FIX ( -8867)/* S1.14      -8867  -0.541196*/
195*df25739fSMilanka Ringwald 
196*df25739fSMilanka Ringwald /** Scales x by y bits to the right, adding a rounding factor.
197*df25739fSMilanka Ringwald  */
198*df25739fSMilanka Ringwald #ifndef SCALE
199*df25739fSMilanka Ringwald #define SCALE(x, y) (((x) + (1 <<((y)-1))) >> (y))
200*df25739fSMilanka Ringwald #endif
201*df25739fSMilanka Ringwald 
202*df25739fSMilanka Ringwald #ifndef CLIP_INT16
203*df25739fSMilanka Ringwald #define CLIP_INT16(x) do { if (x > OI_INT16_MAX) { x = OI_INT16_MAX; } else if (x < OI_INT16_MIN) { x = OI_INT16_MIN; } } while (0)
204*df25739fSMilanka Ringwald #endif
205*df25739fSMilanka Ringwald 
206*df25739fSMilanka Ringwald /**
207*df25739fSMilanka Ringwald  * Default C language implementation of a 16x32->32 multiply. This function may
208*df25739fSMilanka Ringwald  * be replaced by a platform-specific version for speed.
209*df25739fSMilanka Ringwald  *
210*df25739fSMilanka Ringwald  * @param u A signed 16-bit multiplicand
211*df25739fSMilanka Ringwald  * @param v A signed 32-bit multiplier
212*df25739fSMilanka Ringwald 
213*df25739fSMilanka Ringwald  * @return  A signed 32-bit value corresponding to the 32 most significant bits
214*df25739fSMilanka Ringwald  * of the 48-bit product of u and v.
215*df25739fSMilanka Ringwald  */
216*df25739fSMilanka Ringwald INLINE OI_INT32 default_mul_16s_32s_hi(OI_INT16 u, OI_INT32 v)
217*df25739fSMilanka Ringwald {
218*df25739fSMilanka Ringwald     OI_UINT16 v0;
219*df25739fSMilanka Ringwald     OI_INT16 v1;
220*df25739fSMilanka Ringwald 
221*df25739fSMilanka Ringwald     OI_INT32 w,x;
222*df25739fSMilanka Ringwald 
223*df25739fSMilanka Ringwald     v0 = (OI_UINT16)(v & 0xffff);
224*df25739fSMilanka Ringwald     v1 = (OI_INT16) (v >> 16);
225*df25739fSMilanka Ringwald 
226*df25739fSMilanka Ringwald     w = v1 * u;
227*df25739fSMilanka Ringwald     x = u * v0;
228*df25739fSMilanka Ringwald 
229*df25739fSMilanka Ringwald     return w + (x >> 16);
230*df25739fSMilanka Ringwald }
231*df25739fSMilanka Ringwald 
232*df25739fSMilanka Ringwald #define MUL_16S_32S_HI(_x, _y) default_mul_16s_32s_hi(_x, _y)
233*df25739fSMilanka Ringwald 
234*df25739fSMilanka Ringwald #define LONG_MULT_DCT(K, sample) (MUL_16S_32S_HI(K, sample)<<2)
235*df25739fSMilanka Ringwald 
236*df25739fSMilanka Ringwald PRIVATE void SynthWindow80_generated(OI_INT16 *pcm, SBC_BUFFER_T const * RESTRICT buffer, OI_UINT strideShift);
237*df25739fSMilanka Ringwald PRIVATE void SynthWindow112_generated(OI_INT16 *pcm, SBC_BUFFER_T const * RESTRICT buffer, OI_UINT strideShift);
238*df25739fSMilanka Ringwald PRIVATE void dct2_8(SBC_BUFFER_T * RESTRICT out, OI_INT32 const * RESTRICT x);
239*df25739fSMilanka Ringwald 
240*df25739fSMilanka Ringwald typedef void (*SYNTH_FRAME)(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_INT16 *pcm, OI_UINT blkstart, OI_UINT blkcount);
241*df25739fSMilanka Ringwald 
242*df25739fSMilanka Ringwald #ifndef COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS
243*df25739fSMilanka Ringwald #define COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(dest, src) do { shift_buffer(dest, src, 72); } while (0)
244*df25739fSMilanka Ringwald #endif
245*df25739fSMilanka Ringwald 
246*df25739fSMilanka Ringwald #ifndef DCT2_8
247*df25739fSMilanka Ringwald #define DCT2_8(dst, src) dct2_8(dst, src)
248*df25739fSMilanka Ringwald #endif
249*df25739fSMilanka Ringwald 
250*df25739fSMilanka Ringwald #ifndef SYNTH80
251*df25739fSMilanka Ringwald #define SYNTH80 SynthWindow80_generated
252*df25739fSMilanka Ringwald #endif
253*df25739fSMilanka Ringwald 
254*df25739fSMilanka Ringwald #ifndef SYNTH112
255*df25739fSMilanka Ringwald #define SYNTH112 SynthWindow112_generated
256*df25739fSMilanka Ringwald #endif
257*df25739fSMilanka Ringwald 
258*df25739fSMilanka Ringwald PRIVATE void OI_SBC_SynthFrame_80(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_INT16 *pcm, OI_UINT blkstart, OI_UINT blkcount)
259*df25739fSMilanka Ringwald {
260*df25739fSMilanka Ringwald     OI_UINT blk;
261*df25739fSMilanka Ringwald     OI_UINT ch;
262*df25739fSMilanka Ringwald     OI_UINT nrof_channels = context->common.frameInfo.nrof_channels;
263*df25739fSMilanka Ringwald     OI_UINT pcmStrideShift = context->common.pcmStride == 1 ? 0 : 1;
264*df25739fSMilanka Ringwald     OI_UINT offset = context->common.filterBufferOffset;
265*df25739fSMilanka Ringwald     OI_INT32 *s = context->common.subdata + 8 * nrof_channels * blkstart;
266*df25739fSMilanka Ringwald     OI_UINT blkstop = blkstart + blkcount;
267*df25739fSMilanka Ringwald 
268*df25739fSMilanka Ringwald     for (blk = blkstart; blk < blkstop; blk++) {
269*df25739fSMilanka Ringwald         if (offset == 0) {
270*df25739fSMilanka Ringwald             COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(context->common.filterBuffer[0] + context->common.filterBufferLen - 72, context->common.filterBuffer[0]);
271*df25739fSMilanka Ringwald             if (nrof_channels == 2) {
272*df25739fSMilanka Ringwald                 COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(context->common.filterBuffer[1] + context->common.filterBufferLen - 72, context->common.filterBuffer[1]);
273*df25739fSMilanka Ringwald             }
274*df25739fSMilanka Ringwald             offset = context->common.filterBufferLen - 80;
275*df25739fSMilanka Ringwald         } else {
276*df25739fSMilanka Ringwald             offset -= 1*8;
277*df25739fSMilanka Ringwald         }
278*df25739fSMilanka Ringwald 
279*df25739fSMilanka Ringwald         for (ch = 0; ch < nrof_channels; ch++) {
280*df25739fSMilanka Ringwald             DCT2_8(context->common.filterBuffer[ch] + offset, s);
281*df25739fSMilanka Ringwald             SYNTH80(pcm + ch, context->common.filterBuffer[ch] + offset, pcmStrideShift);
282*df25739fSMilanka Ringwald             s += 8;
283*df25739fSMilanka Ringwald         }
284*df25739fSMilanka Ringwald         pcm += (8 << pcmStrideShift);
285*df25739fSMilanka Ringwald     }
286*df25739fSMilanka Ringwald     context->common.filterBufferOffset = offset;
287*df25739fSMilanka Ringwald }
288*df25739fSMilanka Ringwald 
289*df25739fSMilanka Ringwald PRIVATE void OI_SBC_SynthFrame_4SB(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_INT16 *pcm, OI_UINT blkstart, OI_UINT blkcount)
290*df25739fSMilanka Ringwald {
291*df25739fSMilanka Ringwald     OI_UINT blk;
292*df25739fSMilanka Ringwald     OI_UINT ch;
293*df25739fSMilanka Ringwald     OI_UINT nrof_channels = context->common.frameInfo.nrof_channels;
294*df25739fSMilanka Ringwald     OI_UINT pcmStrideShift = context->common.pcmStride == 1 ? 0 : 1;
295*df25739fSMilanka Ringwald     OI_UINT offset = context->common.filterBufferOffset;
296*df25739fSMilanka Ringwald     OI_INT32 *s = context->common.subdata + 8 * nrof_channels * blkstart;
297*df25739fSMilanka Ringwald     OI_UINT blkstop = blkstart + blkcount;
298*df25739fSMilanka Ringwald 
299*df25739fSMilanka Ringwald     for (blk = blkstart; blk < blkstop; blk++) {
300*df25739fSMilanka Ringwald         if (offset == 0) {
301*df25739fSMilanka Ringwald             COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(context->common.filterBuffer[0] + context->common.filterBufferLen - 72,context->common.filterBuffer[0]);
302*df25739fSMilanka Ringwald             if (nrof_channels == 2) {
303*df25739fSMilanka Ringwald                 COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(context->common.filterBuffer[1] + context->common.filterBufferLen - 72,context->common.filterBuffer[1]);
304*df25739fSMilanka Ringwald             }
305*df25739fSMilanka Ringwald             offset =context->common.filterBufferLen - 80;
306*df25739fSMilanka Ringwald         } else {
307*df25739fSMilanka Ringwald             offset -= 8;
308*df25739fSMilanka Ringwald         }
309*df25739fSMilanka Ringwald         for (ch = 0; ch < nrof_channels; ch++) {
310*df25739fSMilanka Ringwald             cosineModulateSynth4(context->common.filterBuffer[ch] + offset, s);
311*df25739fSMilanka Ringwald             SynthWindow40_int32_int32_symmetry_with_sum(pcm + ch,
312*df25739fSMilanka Ringwald                                                         context->common.filterBuffer[ch] + offset,
313*df25739fSMilanka Ringwald                                                         pcmStrideShift);
314*df25739fSMilanka Ringwald             s += 4;
315*df25739fSMilanka Ringwald         }
316*df25739fSMilanka Ringwald         pcm += (4 << pcmStrideShift);
317*df25739fSMilanka Ringwald     }
318*df25739fSMilanka Ringwald     context->common.filterBufferOffset = offset;
319*df25739fSMilanka Ringwald }
320*df25739fSMilanka Ringwald 
321*df25739fSMilanka Ringwald #ifdef SBC_ENHANCED
322*df25739fSMilanka Ringwald 
323*df25739fSMilanka Ringwald PRIVATE void OI_SBC_SynthFrame_Enhanced(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_INT16 *pcm, OI_UINT blkstart, OI_UINT blkcount)
324*df25739fSMilanka Ringwald {
325*df25739fSMilanka Ringwald     OI_UINT blk;
326*df25739fSMilanka Ringwald     OI_UINT ch;
327*df25739fSMilanka Ringwald     OI_UINT nrof_channels = context->common.frameInfo.nrof_channels;
328*df25739fSMilanka Ringwald     OI_UINT pcmStrideShift = context->common.pcmStride == 1 ? 0 : 1;
329*df25739fSMilanka Ringwald     OI_UINT offset = context->common.filterBufferOffset;
330*df25739fSMilanka Ringwald     OI_INT32 *s = context->common.subdata + 8 * nrof_channels * blkstart;
331*df25739fSMilanka Ringwald     OI_UINT blkstop = blkstart + blkcount;
332*df25739fSMilanka Ringwald 
333*df25739fSMilanka Ringwald     for (blk = blkstart; blk < blkstop; blk++) {
334*df25739fSMilanka Ringwald         if (offset == 0) {
335*df25739fSMilanka Ringwald             COPY_BACKWARD_32BIT_ALIGNED_104_HALFWORDS(context->common.filterBuffer[0] +context->common.filterBufferLen - 104, context->common.filterBuffer[0]);
336*df25739fSMilanka Ringwald             if (nrof_channels == 2) {
337*df25739fSMilanka Ringwald                 COPY_BACKWARD_32BIT_ALIGNED_104_HALFWORDS(context->common.filterBuffer[1] + context->common.filterBufferLen - 104, context->common.filterBuffer[1]);
338*df25739fSMilanka Ringwald             }
339*df25739fSMilanka Ringwald             offset = context->common.filterBufferLen - 112;
340*df25739fSMilanka Ringwald         } else {
341*df25739fSMilanka Ringwald             offset -= 8;
342*df25739fSMilanka Ringwald         }
343*df25739fSMilanka Ringwald         for (ch = 0; ch < nrof_channels; ++ch) {
344*df25739fSMilanka Ringwald             DCT2_8(context->common.filterBuffer[ch] + offset, s);
345*df25739fSMilanka Ringwald             SYNTH112(pcm + ch, context->common.filterBuffer[ch] + offset, pcmStrideShift);
346*df25739fSMilanka Ringwald             s += 8;
347*df25739fSMilanka Ringwald         }
348*df25739fSMilanka Ringwald         pcm += (8 << pcmStrideShift);
349*df25739fSMilanka Ringwald     }
350*df25739fSMilanka Ringwald     context->common.filterBufferOffset = offset;
351*df25739fSMilanka Ringwald }
352*df25739fSMilanka Ringwald 
353*df25739fSMilanka Ringwald static const SYNTH_FRAME SynthFrameEnhanced[] = {
354*df25739fSMilanka Ringwald     NULL,                       /* invalid */
355*df25739fSMilanka Ringwald     OI_SBC_SynthFrame_Enhanced, /* mono */
356*df25739fSMilanka Ringwald     OI_SBC_SynthFrame_Enhanced  /* stereo */
357*df25739fSMilanka Ringwald };
358*df25739fSMilanka Ringwald 
359*df25739fSMilanka Ringwald #endif
360*df25739fSMilanka Ringwald 
361*df25739fSMilanka Ringwald static const SYNTH_FRAME SynthFrame8SB[] = {
362*df25739fSMilanka Ringwald     NULL,             /* invalid */
363*df25739fSMilanka Ringwald     OI_SBC_SynthFrame_80, /* mono */
364*df25739fSMilanka Ringwald     OI_SBC_SynthFrame_80  /* stereo */
365*df25739fSMilanka Ringwald };
366*df25739fSMilanka Ringwald 
367*df25739fSMilanka Ringwald 
368*df25739fSMilanka Ringwald static const SYNTH_FRAME SynthFrame4SB[] = {
369*df25739fSMilanka Ringwald     NULL,                  /* invalid */
370*df25739fSMilanka Ringwald     OI_SBC_SynthFrame_4SB, /* mono */
371*df25739fSMilanka Ringwald     OI_SBC_SynthFrame_4SB  /* stereo */
372*df25739fSMilanka Ringwald };
373*df25739fSMilanka Ringwald 
374*df25739fSMilanka Ringwald PRIVATE void OI_SBC_SynthFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_INT16 *pcm, OI_UINT start_block, OI_UINT nrof_blocks)
375*df25739fSMilanka Ringwald {
376*df25739fSMilanka Ringwald     OI_UINT nrof_subbands = context->common.frameInfo.nrof_subbands;
377*df25739fSMilanka Ringwald     OI_UINT nrof_channels = context->common.frameInfo.nrof_channels;
378*df25739fSMilanka Ringwald 
379*df25739fSMilanka Ringwald     OI_ASSERT(nrof_subbands == 4 || nrof_subbands == 8);
380*df25739fSMilanka Ringwald     if (nrof_subbands == 4) {
381*df25739fSMilanka Ringwald         SynthFrame4SB[nrof_channels](context, pcm, start_block, nrof_blocks);
382*df25739fSMilanka Ringwald #ifdef SBC_ENHANCED
383*df25739fSMilanka Ringwald     } else if (context->common.frameInfo.enhanced) {
384*df25739fSMilanka Ringwald         SynthFrameEnhanced[nrof_channels](context, pcm, start_block, nrof_blocks);
385*df25739fSMilanka Ringwald #endif /* SBC_ENHANCED */
386*df25739fSMilanka Ringwald         } else {
387*df25739fSMilanka Ringwald         SynthFrame8SB[nrof_channels](context, pcm, start_block, nrof_blocks);
388*df25739fSMilanka Ringwald     }
389*df25739fSMilanka Ringwald }
390*df25739fSMilanka Ringwald 
391*df25739fSMilanka Ringwald 
392*df25739fSMilanka Ringwald void SynthWindow40_int32_int32_symmetry_with_sum(OI_INT16 *pcm, SBC_BUFFER_T buffer[80], OI_UINT strideShift)
393*df25739fSMilanka Ringwald {
394*df25739fSMilanka Ringwald     OI_INT32 pa;
395*df25739fSMilanka Ringwald     OI_INT32 pb;
396*df25739fSMilanka Ringwald 
397*df25739fSMilanka Ringwald     /* These values should be zero, since out[2] of the 4-band cosine modulation
398*df25739fSMilanka Ringwald      * is always zero. */
399*df25739fSMilanka Ringwald     OI_ASSERT(buffer[ 2] == 0);
400*df25739fSMilanka Ringwald     OI_ASSERT(buffer[10] == 0);
401*df25739fSMilanka Ringwald     OI_ASSERT(buffer[18] == 0);
402*df25739fSMilanka Ringwald     OI_ASSERT(buffer[26] == 0);
403*df25739fSMilanka Ringwald     OI_ASSERT(buffer[34] == 0);
404*df25739fSMilanka Ringwald     OI_ASSERT(buffer[42] == 0);
405*df25739fSMilanka Ringwald     OI_ASSERT(buffer[50] == 0);
406*df25739fSMilanka Ringwald     OI_ASSERT(buffer[58] == 0);
407*df25739fSMilanka Ringwald     OI_ASSERT(buffer[66] == 0);
408*df25739fSMilanka Ringwald     OI_ASSERT(buffer[74] == 0);
409*df25739fSMilanka Ringwald 
410*df25739fSMilanka Ringwald 
411*df25739fSMilanka Ringwald     pa  = dec_window_4[ 4] * (buffer[12] + buffer[76]);
412*df25739fSMilanka Ringwald     pa += dec_window_4[ 8] * (buffer[16] - buffer[64]);
413*df25739fSMilanka Ringwald     pa += dec_window_4[12] * (buffer[28] + buffer[60]);
414*df25739fSMilanka Ringwald     pa += dec_window_4[16] * (buffer[32] - buffer[48]);
415*df25739fSMilanka Ringwald     pa += dec_window_4[20] *  buffer[44];
416*df25739fSMilanka Ringwald     pa = SCALE(-pa, 15);
417*df25739fSMilanka Ringwald     CLIP_INT16(pa);
418*df25739fSMilanka Ringwald     pcm[0 << strideShift] = (OI_INT16)pa;
419*df25739fSMilanka Ringwald 
420*df25739fSMilanka Ringwald 
421*df25739fSMilanka Ringwald     pa  = dec_window_4[ 1] * buffer[ 1]; pb  = dec_window_4[ 1] * buffer[79];
422*df25739fSMilanka Ringwald     pb += dec_window_4[ 3] * buffer[ 3]; pa += dec_window_4[ 3] * buffer[77];
423*df25739fSMilanka Ringwald     pa += dec_window_4[ 5] * buffer[13]; pb += dec_window_4[ 5] * buffer[67];
424*df25739fSMilanka Ringwald     pb += dec_window_4[ 7] * buffer[15]; pa += dec_window_4[ 7] * buffer[65];
425*df25739fSMilanka Ringwald     pa += dec_window_4[ 9] * buffer[17]; pb += dec_window_4[ 9] * buffer[63];
426*df25739fSMilanka Ringwald     pb += dec_window_4[11] * buffer[19]; pa += dec_window_4[11] * buffer[61];
427*df25739fSMilanka Ringwald     pa += dec_window_4[13] * buffer[29]; pb += dec_window_4[13] * buffer[51];
428*df25739fSMilanka Ringwald     pb += dec_window_4[15] * buffer[31]; pa += dec_window_4[15] * buffer[49];
429*df25739fSMilanka Ringwald     pa += dec_window_4[17] * buffer[33]; pb += dec_window_4[17] * buffer[47];
430*df25739fSMilanka Ringwald     pb += dec_window_4[19] * buffer[35]; pa += dec_window_4[19] * buffer[45];
431*df25739fSMilanka Ringwald     pa = SCALE(-pa, 15);
432*df25739fSMilanka Ringwald     CLIP_INT16(pa);
433*df25739fSMilanka Ringwald     pcm[1 << strideShift] = (OI_INT16)(pa);
434*df25739fSMilanka Ringwald     pb = SCALE(-pb, 15);
435*df25739fSMilanka Ringwald     CLIP_INT16(pb);
436*df25739fSMilanka Ringwald     pcm[3 << strideShift] = (OI_INT16)(pb);
437*df25739fSMilanka Ringwald 
438*df25739fSMilanka Ringwald 
439*df25739fSMilanka Ringwald     pa  = dec_window_4[2] * (/*buffer[ 2] + */ buffer[78]);  /* buffer[ 2] is always zero */
440*df25739fSMilanka Ringwald     pa += dec_window_4[6] * (buffer[14] /* + buffer[66]*/);  /* buffer[66] is always zero */
441*df25739fSMilanka Ringwald     pa += dec_window_4[10] * (/*buffer[18] + */ buffer[62]);  /* buffer[18] is always zero */
442*df25739fSMilanka Ringwald     pa += dec_window_4[14] * (buffer[30] /* + buffer[50]*/);  /* buffer[50] is always zero */
443*df25739fSMilanka Ringwald     pa += dec_window_4[18] * (/*buffer[34] + */ buffer[46]);  /* buffer[34] is always zero */
444*df25739fSMilanka Ringwald     pa = SCALE(-pa, 15);
445*df25739fSMilanka Ringwald     CLIP_INT16(pa);
446*df25739fSMilanka Ringwald     pcm[2 << strideShift] = (OI_INT16)(pa);
447*df25739fSMilanka Ringwald }
448*df25739fSMilanka Ringwald 
449*df25739fSMilanka Ringwald 
450*df25739fSMilanka Ringwald /**
451*df25739fSMilanka Ringwald   This routine implements the cosine modulation matrix for 4-subband
452*df25739fSMilanka Ringwald   synthesis. This is called "matrixing" in the SBC specification. This
453*df25739fSMilanka Ringwald   matrix, M4,  can be factored into an 8-point Type II Discrete Cosine
454*df25739fSMilanka Ringwald   Transform, DCTII_4 and a matrix S4, given here:
455*df25739fSMilanka Ringwald 
456*df25739fSMilanka Ringwald   @code
457*df25739fSMilanka Ringwald         __               __
458*df25739fSMilanka Ringwald        |   0   0   1   0   |
459*df25739fSMilanka Ringwald        |   0   0   0   1   |
460*df25739fSMilanka Ringwald        |   0   0   0   0   |
461*df25739fSMilanka Ringwald        |   0   0   0  -1   |
462*df25739fSMilanka Ringwald   S4 = |   0   0  -1   0   |
463*df25739fSMilanka Ringwald        |   0  -1   0   0   |
464*df25739fSMilanka Ringwald        |  -1   0   0   0   |
465*df25739fSMilanka Ringwald        |__ 0  -1   0   0 __|
466*df25739fSMilanka Ringwald 
467*df25739fSMilanka Ringwald   M4 * in = S4 * (DCTII_4 * in)
468*df25739fSMilanka Ringwald   @endcode
469*df25739fSMilanka Ringwald 
470*df25739fSMilanka Ringwald   (DCTII_4 * in) is computed using a Fast Cosine Transform. The algorithm
471*df25739fSMilanka Ringwald   here is based on an implementation computed by the SPIRAL computer
472*df25739fSMilanka Ringwald   algebra system, manually converted to fixed-point arithmetic. S4 can be
473*df25739fSMilanka Ringwald   implemented using only assignment and negation.
474*df25739fSMilanka Ringwald   */
475*df25739fSMilanka Ringwald PRIVATE void cosineModulateSynth4(SBC_BUFFER_T * RESTRICT out, OI_INT32 const * RESTRICT in)
476*df25739fSMilanka Ringwald {
477*df25739fSMilanka Ringwald     OI_INT32 f0, f1, f2, f3, f4, f7, f8, f9, f10;
478*df25739fSMilanka Ringwald     OI_INT32 y0, y1, y2, y3;
479*df25739fSMilanka Ringwald 
480*df25739fSMilanka Ringwald     f0 = (in[0] - in[3]);
481*df25739fSMilanka Ringwald     f1 = (in[0] + in[3]);
482*df25739fSMilanka Ringwald     f2 = (in[1] - in[2]);
483*df25739fSMilanka Ringwald     f3 = (in[1] + in[2]);
484*df25739fSMilanka Ringwald 
485*df25739fSMilanka Ringwald     f4 = f1 - f3;
486*df25739fSMilanka Ringwald 
487*df25739fSMilanka Ringwald     y0 = -SCALE(f1 + f3, DCT_SHIFT);
488*df25739fSMilanka Ringwald     y2 = -SCALE(LONG_MULT_DCT(DCTII_4_K06_FIX, f4), DCT_SHIFT);
489*df25739fSMilanka Ringwald     f7 = f0 + f2;
490*df25739fSMilanka Ringwald     f8 = LONG_MULT_DCT(DCTII_4_K08_FIX, f0);
491*df25739fSMilanka Ringwald     f9 = LONG_MULT_DCT(DCTII_4_K09_FIX, f7);
492*df25739fSMilanka Ringwald     f10 = LONG_MULT_DCT(DCTII_4_K10_FIX, f2);
493*df25739fSMilanka Ringwald     y3 = -SCALE(f8 + f9, DCT_SHIFT);
494*df25739fSMilanka Ringwald     y1 = -SCALE(f10 - f9, DCT_SHIFT);
495*df25739fSMilanka Ringwald 
496*df25739fSMilanka Ringwald     out[0] = (OI_INT16)-y2;
497*df25739fSMilanka Ringwald     out[1] = (OI_INT16)-y3;
498*df25739fSMilanka Ringwald     out[2] = (OI_INT16)0;
499*df25739fSMilanka Ringwald     out[3] = (OI_INT16)y3;
500*df25739fSMilanka Ringwald     out[4] = (OI_INT16)y2;
501*df25739fSMilanka Ringwald     out[5] = (OI_INT16)y1;
502*df25739fSMilanka Ringwald     out[6] = (OI_INT16)y0;
503*df25739fSMilanka Ringwald     out[7] = (OI_INT16)y1;
504*df25739fSMilanka Ringwald }
505*df25739fSMilanka Ringwald 
506*df25739fSMilanka Ringwald 
507*df25739fSMilanka Ringwald 
508*df25739fSMilanka Ringwald /**
509*df25739fSMilanka Ringwald @}
510*df25739fSMilanka Ringwald */
511