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