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