summaryrefslogtreecommitdiff
path: root/apps/codecs/libfaad/mdct.c
blob: 158ea222050f3999b17fae66c3b334817812cabb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
/*
** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
** Copyright (C) 2003-2004 M. Bakker, Ahead Software AG, http://www.nero.com
**  
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
** 
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software 
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
** Any non-GPL usage of this software or parts of this software is strictly
** forbidden.
**
** Commercial non-GPL licensing of this software is possible.
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
**
** $Id$
**/

/*
 * Fast (I)MDCT Implementation using (I)FFT ((Inverse) Fast Fourier Transform)
 * and consists of three steps: pre-(I)FFT complex multiplication, complex
 * (I)FFT, post-(I)FFT complex multiplication,
 * 
 * As described in:
 *  P. Duhamel, Y. Mahieux, and J.P. Petit, "A Fast Algorithm for the
 *  Implementation of Filter Banks Based on 'Time Domain Aliasing
 *  Cancellation’," IEEE Proc. on ICASSP‘91, 1991, pp. 2209-2212.
 *
 *
 * As of April 6th 2002 completely rewritten.
 * This (I)MDCT can now be used for any data size n, where n is divisible by 8.
 *
 */

#include "common.h"
#include "structs.h"

#include <stdlib.h>
#ifdef _WIN32_WCE
#define assert(x)
#else
#include <assert.h>
#endif

#include "cfft.h"
#include "mdct.h"
#include "mdct_tab.h"


mdct_info *faad_mdct_init(uint16_t N)
{
    mdct_info *mdct = (mdct_info*)faad_malloc(sizeof(mdct_info));

    //assert(N % 8 == 0);

    mdct->N = N;

    /* NOTE: For "small framelengths" in FIXED_POINT the coefficients need to be
     * scaled by sqrt("(nearest power of 2) > N" / N) */

    /* RE(mdct->sincos[k]) = scale*(real_t)(cos(2.0*M_PI*(k+1./8.) / (real_t)N));
     * IM(mdct->sincos[k]) = scale*(real_t)(sin(2.0*M_PI*(k+1./8.) / (real_t)N)); */
    /* scale is 1 for fixed point, sqrt(N) for floating point */
    switch (N)
    {
    case 2048: mdct->sincos = (complex_t*)mdct_tab_2048; break;
    case 256:  mdct->sincos = (complex_t*)mdct_tab_256;  break;
#ifdef LD_DEC
    case 1024: mdct->sincos = (complex_t*)mdct_tab_1024; break;
#endif
#ifdef ALLOW_SMALL_FRAMELENGTH
    case 1920: mdct->sincos = (complex_t*)mdct_tab_1920; break;
    case 240:  mdct->sincos = (complex_t*)mdct_tab_240;  break;
#ifdef LD_DEC
    case 960:  mdct->sincos = (complex_t*)mdct_tab_960;  break;
#endif
#endif
#ifdef SSR_DEC
    case 512:  mdct->sincos = (complex_t*)mdct_tab_512;  break;
    case 64:   mdct->sincos = (complex_t*)mdct_tab_64;   break;
#endif
    }

    /* initialise fft */
    mdct->cfft = cffti(N/4);

#ifdef PROFILE
    mdct->cycles = 0;
    mdct->fft_cycles = 0;
#endif

    return mdct;
}

void faad_mdct_end(mdct_info *mdct)
{
    if (mdct != NULL)
    {
#ifdef PROFILE
        printf("MDCT[%.4d]:         %I64d cycles\n", mdct->N, mdct->cycles);
        printf("CFFT[%.4d]:         %I64d cycles\n", mdct->N/4, mdct->fft_cycles);
#endif

        cfftu(mdct->cfft);

        faad_free(mdct);
    }
}

void faad_imdct(mdct_info *mdct, real_t *X_in, real_t *X_out)
{
    uint16_t k;

    complex_t x;
#ifdef ALLOW_SMALL_FRAMELENGTH
#ifdef FIXED_POINT
    real_t scale = 0, b_scale = 0;
#endif
#endif
    ALIGN static complex_t Z1[512];
    complex_t *sincos = mdct->sincos;

    uint16_t N  = mdct->N;
    uint16_t N2 = N >> 1;
    uint16_t N4 = N >> 2;
    uint16_t N8 = N >> 3;

#ifdef PROFILE
    int64_t count1, count2 = faad_get_ts();
#endif

#ifdef ALLOW_SMALL_FRAMELENGTH
#ifdef FIXED_POINT
    /* detect non-power of 2 */
    if (N & (N-1))
    {
        /* adjust scale for non-power of 2 MDCT */
        /* 2048/1920 */
        b_scale = 1;
        scale = COEF_CONST(1.0666666666666667);
    }
#endif
#endif

    /* pre-IFFT complex multiplication */
    for (k = 0; k < N4; k++)
    {
        ComplexMult(&IM(Z1[k]), &RE(Z1[k]),
            X_in[2*k], X_in[N2 - 1 - 2*k], RE(sincos[k]), IM(sincos[k]));
    }

#ifdef PROFILE
    count1 = faad_get_ts();
#endif

    /* complex IFFT, any non-scaling FFT can be used here */
    cfftb(mdct->cfft, Z1);

#ifdef PROFILE
    count1 = faad_get_ts() - count1;
#endif

    /* post-IFFT complex multiplication */
    for (k = 0; k < N4; k++)
    {
        RE(x) = RE(Z1[k]);
        IM(x) = IM(Z1[k]);
        ComplexMult(&IM(Z1[k]), &RE(Z1[k]),
            IM(x), RE(x), RE(sincos[k]), IM(sincos[k]));

#ifdef ALLOW_SMALL_FRAMELENGTH
#ifdef FIXED_POINT
        /* non-power of 2 MDCT scaling */
        if (b_scale)
        {
            RE(Z1[k]) = MUL_C(RE(Z1[k]), scale);
            IM(Z1[k]) = MUL_C(IM(Z1[k]), scale);
        }
#endif
#endif
    }

    /* reordering */
    for (k = 0; k < N8; k+=2)
    {
        X_out[              2*k] =  IM(Z1[N8 +     k]);
        X_out[          2 + 2*k] =  IM(Z1[N8 + 1 + k]);

        X_out[          1 + 2*k] = -RE(Z1[N8 - 1 - k]);
        X_out[          3 + 2*k] = -RE(Z1[N8 - 2 - k]);

        X_out[N4 +          2*k] =  RE(Z1[         k]);
        X_out[N4 +    + 2 + 2*k] =  RE(Z1[     1 + k]);

        X_out[N4 +      1 + 2*k] = -IM(Z1[N4 - 1 - k]);
        X_out[N4 +      3 + 2*k] = -IM(Z1[N4 - 2 - k]);

        X_out[N2 +          2*k] =  RE(Z1[N8 +     k]);
        X_out[N2 +    + 2 + 2*k] =  RE(Z1[N8 + 1 + k]);

        X_out[N2 +      1 + 2*k] = -IM(Z1[N8 - 1 - k]);
        X_out[N2 +      3 + 2*k] = -IM(Z1[N8 - 2 - k]);

        X_out[N2 + N4 +     2*k] = -IM(Z1[         k]);
        X_out[N2 + N4 + 2 + 2*k] = -IM(Z1[     1 + k]);

        X_out[N2 + N4 + 1 + 2*k] =  RE(Z1[N4 - 1 - k]);
        X_out[N2 + N4 + 3 + 2*k] =  RE(Z1[N4 - 2 - k]);
    }

#ifdef PROFILE
    count2 = faad_get_ts() - count2;
    mdct->fft_cycles += count1;
    mdct->cycles += (count2 - count1);
#endif
}

#ifdef LTP_DEC
void faad_mdct(mdct_info *mdct, real_t *X_in, real_t *X_out)
{
    uint16_t k;

    complex_t x;
    ALIGN static complex_t Z1[512];
    complex_t *sincos = mdct->sincos;

    uint16_t N  = mdct->N;
    uint16_t N2 = N >> 1;
    uint16_t N4 = N >> 2;
    uint16_t N8 = N >> 3;

#ifndef FIXED_POINT
	real_t scale = REAL_CONST(N);
#else
	real_t scale = REAL_CONST(4.0/N);
#endif

#ifdef ALLOW_SMALL_FRAMELENGTH
#ifdef FIXED_POINT
    /* detect non-power of 2 */
    if (N & (N-1))
    {
        /* adjust scale for non-power of 2 MDCT */
        /* *= sqrt(2048/1920) */
        scale = MUL_C(scale, COEF_CONST(1.0327955589886444));
    }
#endif
#endif

    /* pre-FFT complex multiplication */
    for (k = 0; k < N8; k++)
    {
        uint16_t n = k << 1;
        RE(x) = X_in[N - N4 - 1 - n] + X_in[N - N4 +     n];
        IM(x) = X_in[    N4 +     n] - X_in[    N4 - 1 - n];

        ComplexMult(&RE(Z1[k]), &IM(Z1[k]),
            RE(x), IM(x), RE(sincos[k]), IM(sincos[k]));

        RE(Z1[k]) = MUL_R(RE(Z1[k]), scale);
        IM(Z1[k]) = MUL_R(IM(Z1[k]), scale);

        RE(x) =  X_in[N2 - 1 - n] - X_in[        n];
        IM(x) =  X_in[N2 +     n] + X_in[N - 1 - n];

        ComplexMult(&RE(Z1[k + N8]), &IM(Z1[k + N8]),
            RE(x), IM(x), RE(sincos[k + N8]), IM(sincos[k + N8]));

        RE(Z1[k + N8]) = MUL_R(RE(Z1[k + N8]), scale);
        IM(Z1[k + N8]) = MUL_R(IM(Z1[k + N8]), scale);
    }

    /* complex FFT, any non-scaling FFT can be used here  */
    cfftf(mdct->cfft, Z1);

    /* post-FFT complex multiplication */
    for (k = 0; k < N4; k++)
    {
        uint16_t n = k << 1;
        ComplexMult(&RE(x), &IM(x),
            RE(Z1[k]), IM(Z1[k]), RE(sincos[k]), IM(sincos[k]));

        X_out[         n] = -RE(x);
        X_out[N2 - 1 - n] =  IM(x);
        X_out[N2 +     n] = -IM(x);
        X_out[N  - 1 - n] =  RE(x);
    }
}
#endif
16_16(g[0],pitch_control),C[0])); sum = ADD32(sum,MULT16_16(MULT16_16_16(g[1],pitch_control),C[1])); sum = ADD32(sum,MULT16_16(MULT16_16_16(g[2],pitch_control),C[2])); sum = SUB32(sum,MULT16_16(MULT16_16_16(g[0],g[1]),C[3])); sum = SUB32(sum,MULT16_16(MULT16_16_16(g[2],g[1]),C[4])); sum = SUB32(sum,MULT16_16(MULT16_16_16(g[2],g[0]),C[5])); sum = SUB32(sum,MULT16_16(MULT16_16_16(g[0],g[0]),C[6])); sum = SUB32(sum,MULT16_16(MULT16_16_16(g[1],g[1]),C[7])); sum = SUB32(sum,MULT16_16(MULT16_16_16(g[2],g[2]),C[8])); return sum; } #endif #ifndef OVERRIDE_OPEN_LOOP_NBEST_PITCH void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *pitch, spx_word16_t *gain, int N, char *stack) { int i,j,k; VARDECL(spx_word32_t *best_score); VARDECL(spx_word32_t *best_ener); spx_word32_t e0; VARDECL(spx_word32_t *corr); #ifdef FIXED_POINT /* In fixed-point, we need only one (temporary) array of 32-bit values and two (corr16, ener16) arrays for (normalized) 16-bit values */ VARDECL(spx_word16_t *corr16); VARDECL(spx_word16_t *ener16); spx_word32_t *energy; int cshift=0, eshift=0; int scaledown = 0; ALLOC(corr16, end-start+1, spx_word16_t); ALLOC(ener16, end-start+1, spx_word16_t); ALLOC(corr, end-start+1, spx_word32_t); energy = corr; #else /* In floating-point, we need to float arrays and no normalized copies */ VARDECL(spx_word32_t *energy); spx_word16_t *corr16; spx_word16_t *ener16; ALLOC(energy, end-start+2, spx_word32_t); ALLOC(corr, end-start+1, spx_word32_t); corr16 = corr; ener16 = energy; #endif ALLOC(best_score, N, spx_word32_t); ALLOC(best_ener, N, spx_word32_t); for (i=0;i<N;i++) { best_score[i]=-1; best_ener[i]=0; pitch[i]=start; } #ifdef FIXED_POINT for (i=-end;i<len;i++) { if (ABS16(sw[i])>16383) { scaledown=1; break; } } /* If the weighted input is close to saturation, then we scale it down */ if (scaledown) { for (i=-end;i<len;i++) { sw[i]=SHR16(sw[i],1); } } #endif energy[0]=inner_prod(sw-start, sw-start, len); e0=inner_prod(sw, sw, len); for (i=start;i<end;i++) { /* Update energy for next pitch*/ energy[i-start+1] = SUB32(ADD32(energy[i-start],SHR32(MULT16_16(sw[-i-1],sw[-i-1]),6)), SHR32(MULT16_16(sw[-i+len-1],sw[-i+len-1]),6)); if (energy[i-start+1] < 0) energy[i-start+1] = 0; } #ifdef FIXED_POINT eshift = normalize16(energy, ener16, 32766, end-start+1); #endif /* In fixed-point, this actually overrites the energy array (aliased to corr) */ pitch_xcorr(sw, sw-end, corr, len, end-start+1, stack); #ifdef FIXED_POINT /* Normalize to 180 so we can square it and it still fits in 16 bits */ cshift = normalize16(corr, corr16, 180, end-start+1); /* If we scaled weighted input down, we need to scale it up again (OK, so we've just lost the LSB, who cares?) */ if (scaledown) { for (i=-end;i<len;i++) { sw[i]=SHL16(sw[i],1); } } #endif /* Search for the best pitch prediction gain */ for (i=start;i<=end;i++) { spx_word16_t tmp = MULT16_16_16(corr16[i-start],corr16[i-start]); /* Instead of dividing the tmp by the energy, we multiply on the other side */ if (MULT16_16(tmp,best_ener[N-1])>MULT16_16(best_score[N-1],ADD16(1,ener16[i-start]))) { /* We can safely put it last and then check */ best_score[N-1]=tmp; best_ener[N-1]=ener16[i-start]+1; pitch[N-1]=i; /* Check if it comes in front of others */ for (j=0;j<N-1;j++) { if (MULT16_16(tmp,best_ener[j])>MULT16_16(best_score[j],ADD16(1,ener16[i-start]))) { for (k=N-1;k>j;k--) { best_score[k]=best_score[k-1]; best_ener[k]=best_ener[k-1]; pitch[k]=pitch[k-1]; } best_score[j]=tmp; best_ener[j]=ener16[i-start]+1; pitch[j]=i; break; } } } } /* Compute open-loop gain if necessary */ if (gain) { for (j=0;j<N;j++) { spx_word16_t g; i=pitch[j]; g = DIV32(SHL32(EXTEND32(corr16[i-start]),cshift), 10+SHR32(MULT16_16(spx_sqrt(e0),spx_sqrt(SHL32(EXTEND32(ener16[i-start]),eshift))),6)); /* FIXME: g = max(g,corr/energy) */ if (g<0) g = 0; gain[j]=g; } } } #endif #ifndef OVERRIDE_PITCH_GAIN_SEARCH_3TAP_VQ static int pitch_gain_search_3tap_vq( const signed char *gain_cdbk, int gain_cdbk_size, spx_word16_t *C16, spx_word16_t max_gain ) { const signed char *ptr=gain_cdbk; int best_cdbk=0; spx_word32_t best_sum=-VERY_LARGE32; spx_word32_t sum=0; spx_word16_t g[3]; spx_word16_t pitch_control=64; spx_word16_t gain_sum; int i; for (i=0;i<gain_cdbk_size;i++) { ptr = gain_cdbk+4*i; g[0]=ADD16((spx_word16_t)ptr[0],32); g[1]=ADD16((spx_word16_t)ptr[1],32); g[2]=ADD16((spx_word16_t)ptr[2],32); gain_sum = (spx_word16_t)ptr[3]; sum = compute_pitch_error(C16, g, pitch_control); if (sum>best_sum && gain_sum<=max_gain) { best_sum=sum; best_cdbk=i; } } return best_cdbk; } #endif /** Finds the best quantized 3-tap pitch predictor by analysis by synthesis */ static spx_word32_t pitch_gain_search_3tap( const spx_word16_t target[], /* Target vector */ const spx_coef_t ak[], /* LPCs for this subframe */ const spx_coef_t awk1[], /* Weighted LPCs #1 for this subframe */ const spx_coef_t awk2[], /* Weighted LPCs #2 for this subframe */ spx_sig_t exc[], /* Excitation */ const signed char *gain_cdbk, int gain_cdbk_size, int pitch, /* Pitch value */ int p, /* Number of LPC coeffs */ int nsf, /* Number of samples in subframe */ SpeexBits *bits, char *stack, const spx_word16_t *exc2, const spx_word16_t *r, spx_word16_t *new_target, int *cdbk_index, int plc_tuning, spx_word32_t cumul_gain, int scaledown ) { int i,j; VARDECL(spx_word16_t *tmp1); VARDECL(spx_word16_t *e); spx_word16_t *x[3]; spx_word32_t corr[3]; spx_word32_t A[3][3]; spx_word16_t gain[3]; spx_word32_t err; spx_word16_t max_gain=128; int best_cdbk=0; ALLOC(tmp1, 3*nsf, spx_word16_t); ALLOC(e, nsf, spx_word16_t); if (cumul_gain > 262144) max_gain = 31; x[0]=tmp1; x[1]=tmp1+nsf; x[2]=tmp1+2*nsf; for (j=0;j<nsf;j++) new_target[j] = target[j]; { VARDECL(spx_mem_t *mm); int pp=pitch-1; ALLOC(mm, p, spx_mem_t); for (j=0;j<nsf;j++) { if (j-pp<0) e[j]=exc2[j-pp]; else if (j-pp-pitch<0) e[j]=exc2[j-pp-pitch]; else e[j]=0; } #ifdef FIXED_POINT /* Scale target and excitation down if needed (avoiding overflow) */ if (scaledown) { for (j=0;j<nsf;j++) e[j] = SHR16(e[j],1); for (j=0;j<nsf;j++) new_target[j] = SHR16(new_target[j],1); } #endif for (j=0;j<p;j++) mm[j] = 0; iir_mem16(e, ak, e, nsf, p, mm, stack); for (j=0;j<p;j++) mm[j] = 0; filter_mem16(e, awk1, awk2, e, nsf, p, mm, stack); for (j=0;j<nsf;j++) x[2][j] = e[j]; } for (i=1;i>=0;i--) { spx_word16_t e0=exc2[-pitch-1+i]; #ifdef FIXED_POINT /* Scale excitation down if needed (avoiding overflow) */ if (scaledown) e0 = SHR16(e0,1); #endif x[i][0]=MULT16_16_Q14(r[0], e0); for (j=0;j<nsf-1;j++) x[i][j+1]=ADD32(x[i+1][j],MULT16_16_P14(r[j+1], e0)); } for (i=0;i<3;i++) corr[i]=inner_prod(x[i],new_target,nsf); for (i=0;i<3;i++) for (j=0;j<=i;j++) A[i][j]=A[j][i]=inner_prod(x[i],x[j],nsf); { spx_word32_t C[9]; #ifdef FIXED_POINT spx_word16_t C16[9]; #else spx_word16_t *C16=C; #endif C[0]=corr[2]; C[1]=corr[1]; C[2]=corr[0]; C[3]=A[1][2]; C[4]=A[0][1]; C[5]=A[0][2]; C[6]=A[2][2]; C[7]=A[1][1]; C[8]=A[0][0]; /*plc_tuning *= 2;*/ if (plc_tuning<2) plc_tuning=2; if (plc_tuning>30) plc_tuning=30; #ifdef FIXED_POINT C[0] = SHL32(C[0],1); C[1] = SHL32(C[1],1); C[2] = SHL32(C[2],1); C[3] = SHL32(C[3],1); C[4] = SHL32(C[4],1); C[5] = SHL32(C[5],1); C[6] = MAC16_32_Q15(C[6],MULT16_16_16(plc_tuning,655),C[6]); C[7] = MAC16_32_Q15(C[7],MULT16_16_16(plc_tuning,655),C[7]); C[8] = MAC16_32_Q15(C[8],MULT16_16_16(plc_tuning,655),C[8]); normalize16(C, C16, 32767, 9); #else C[6]*=.5*(1+.02*plc_tuning); C[7]*=.5*(1+.02*plc_tuning); C[8]*=.5*(1+.02*plc_tuning); #endif best_cdbk = pitch_gain_search_3tap_vq(gain_cdbk, gain_cdbk_size, C16, max_gain); #ifdef FIXED_POINT gain[0] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4]); gain[1] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4+1]); gain[2] = ADD16(32,(spx_word16_t)gain_cdbk[best_cdbk*4+2]); /*printf ("%d %d %d %d\n",gain[0],gain[1],gain[2], best_cdbk);*/ #else gain[0] = 0.015625*gain_cdbk[best_cdbk*4] + .5; gain[1] = 0.015625*gain_cdbk[best_cdbk*4+1]+ .5; gain[2] = 0.015625*gain_cdbk[best_cdbk*4+2]+ .5; #endif *cdbk_index=best_cdbk; } SPEEX_MEMSET(exc, 0, nsf); for (i=0;i<3;i++) { int j; int tmp1, tmp3; int pp=pitch+1-i; tmp1=nsf; if (tmp1>pp) tmp1=pp; for (j=0;j<tmp1;j++) exc[j]=MAC16_16(exc[j],SHL16(gain[2-i],7),exc2[j-pp]); tmp3=nsf; if (tmp3>pp+pitch) tmp3=pp+pitch; for (j=tmp1;j<tmp3;j++) exc[j]=MAC16_16(exc[j],SHL16(gain[2-i],7),exc2[j-pp-pitch]); } for (i=0;i<nsf;i++) { spx_word32_t tmp = ADD32(ADD32(MULT16_16(gain[0],x[2][i]),MULT16_16(gain[1],x[1][i])), MULT16_16(gain[2],x[0][i])); new_target[i] = SUB16(new_target[i], EXTRACT16(PSHR32(tmp,6))); } err = inner_prod(new_target, new_target, nsf); return err; } /** Finds the best quantized 3-tap pitch predictor by analysis by synthesis */ int pitch_search_3tap( spx_word16_t target[], /* Target vector */ spx_word16_t *sw, spx_coef_t ak[], /* LPCs for this subframe */ spx_coef_t awk1[], /* Weighted LPCs #1 for this subframe */ spx_coef_t awk2[], /* Weighted LPCs #2 for this subframe */ spx_sig_t exc[], /* Excitation */ const void *par, int start, /* Smallest pitch value allowed */ int end, /* Largest pitch value allowed */ spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ int p, /* Number of LPC coeffs */ int nsf, /* Number of samples in subframe */ SpeexBits *bits, char *stack, spx_word16_t *exc2, spx_word16_t *r, int complexity, int cdbk_offset, int plc_tuning, spx_word32_t *cumul_gain ) { int i; int cdbk_index, pitch=0, best_gain_index=0; VARDECL(spx_sig_t *best_exc); VARDECL(spx_word16_t *new_target); VARDECL(spx_word16_t *best_target); int best_pitch=0; spx_word32_t err, best_err=-1; int N; const ltp_params *params; const signed char *gain_cdbk; int gain_cdbk_size; int scaledown=0; VARDECL(int *nbest); params = (const ltp_params*) par; gain_cdbk_size = 1<<params->gain_bits; gain_cdbk = params->gain_cdbk + 4*gain_cdbk_size*cdbk_offset; N=complexity; if (N>10) N=10; if (N<1) N=1; ALLOC(nbest, N, int); params = (const ltp_params*) par; if (end<start) { speex_bits_pack(bits, 0, params->pitch_bits); speex_bits_pack(bits, 0, params->gain_bits); SPEEX_MEMSET(exc, 0, nsf); return start; } #ifdef FIXED_POINT /* Check if we need to scale everything down in the pitch search to avoid overflows */ for (i=0;i<nsf;i++) { if (ABS16(target[i])>16383) { scaledown=1; break; } } for (i=-end;i<nsf;i++) { if (ABS16(exc2[i])>16383) { scaledown=1; break; } } #endif if (N>end-start+1) N=end-start+1; if (end != start) open_loop_nbest_pitch(sw, start, end, nsf, nbest, NULL, N, stack); else nbest[0] = start; ALLOC(best_exc, nsf, spx_sig_t); ALLOC(new_target, nsf, spx_word16_t); ALLOC(best_target, nsf, spx_word16_t); for (i=0;i<N;i++) { pitch=nbest[i]; SPEEX_MEMSET(exc, 0, nsf); err=pitch_gain_search_3tap(target, ak, awk1, awk2, exc, gain_cdbk, gain_cdbk_size, pitch, p, nsf, bits, stack, exc2, r, new_target, &cdbk_index, plc_tuning, *cumul_gain, scaledown); if (err<best_err || best_err<0) { SPEEX_COPY(best_exc, exc, nsf); SPEEX_COPY(best_target, new_target, nsf); best_err=err; best_pitch=pitch; best_gain_index=cdbk_index; } } /*printf ("pitch: %d %d\n", best_pitch, best_gain_index);*/ speex_bits_pack(bits, best_pitch-start, params->pitch_bits); speex_bits_pack(bits, best_gain_index, params->gain_bits); #ifdef FIXED_POINT *cumul_gain = MULT16_32_Q13(SHL16(params->gain_cdbk[4*best_gain_index+3],8), MAX32(1024,*cumul_gain)); #else *cumul_gain = 0.03125*MAX32(1024,*cumul_gain)*params->gain_cdbk[4*best_gain_index+3]; #endif /*printf ("%f\n", cumul_gain);*/ /*printf ("encode pitch: %d %d\n", best_pitch, best_gain_index);*/ SPEEX_COPY(exc, best_exc, nsf); SPEEX_COPY(target, best_target, nsf); #ifdef FIXED_POINT /* Scale target back up if needed */ if (scaledown) { for (i=0;i<nsf;i++) target[i]=SHL16(target[i],1); } #endif return pitch; } #endif /* SPEEX_DISABLE_ENCODER */ void pitch_unquant_3tap( spx_word16_t exc[], /* Input excitation */ spx_word32_t exc_out[], /* Output excitation */ int start, /* Smallest pitch value allowed */ int end, /* Largest pitch value allowed */ spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ const void *par, int nsf, /* Number of samples in subframe */ int *pitch_val, spx_word16_t *gain_val, SpeexBits *bits, char *stack, int count_lost, int subframe_offset, spx_word16_t last_pitch_gain, int cdbk_offset ) { int i; int pitch; int gain_index; spx_word16_t gain[3]; const signed char *gain_cdbk; int gain_cdbk_size; const ltp_params *params; params = (const ltp_params*) par; gain_cdbk_size = 1<<params->gain_bits; gain_cdbk = params->gain_cdbk + 4*gain_cdbk_size*cdbk_offset; pitch = speex_bits_unpack_unsigned(bits, params->pitch_bits); pitch += start; gain_index = speex_bits_unpack_unsigned(bits, params->gain_bits); /*printf ("decode pitch: %d %d\n", pitch, gain_index);*/ #ifdef FIXED_POINT gain[0] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4]); gain[1] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4+1]); gain[2] = ADD16(32,(spx_word16_t)gain_cdbk[gain_index*4+2]); #else gain[0] = 0.015625*gain_cdbk[gain_index*4]+.5; gain[1] = 0.015625*gain_cdbk[gain_index*4+1]+.5; gain[2] = 0.015625*gain_cdbk[gain_index*4+2]+.5; #endif if (count_lost && pitch > subframe_offset) { spx_word16_t gain_sum; if (1) { #ifdef FIXED_POINT spx_word16_t tmp = count_lost < 4 ? last_pitch_gain : SHR16(last_pitch_gain,1); if (tmp>62) tmp=62; #else spx_word16_t tmp = count_lost < 4 ? last_pitch_gain : 0.5 * last_pitch_gain; if (tmp>.95) tmp=.95; #endif gain_sum = gain_3tap_to_1tap(gain); if (gain_sum > tmp) { spx_word16_t fact = DIV32_16(SHL32(EXTEND32(tmp),14),gain_sum); for (i=0;i<3;i++) gain[i]=MULT16_16_Q14(fact,gain[i]); } } } *pitch_val = pitch; gain_val[0]=gain[0]; gain_val[1]=gain[1]; gain_val[2]=gain[2]; gain[0] = SHL16(gain[0],7); gain[1] = SHL16(gain[1],7); gain[2] = SHL16(gain[2],7); SPEEX_MEMSET(exc_out, 0, nsf); for (i=0;i<3;i++) { int j; int tmp1, tmp3; int pp=pitch+1-i; tmp1=nsf; if (tmp1>pp) tmp1=pp; for (j=0;j<tmp1;j++) exc_out[j]=MAC16_16(exc_out[j],gain[2-i],exc[j-pp]); tmp3=nsf; if (tmp3>pp+pitch) tmp3=pp+pitch; for (j=tmp1;j<tmp3;j++) exc_out[j]=MAC16_16(exc_out[j],gain[2-i],exc[j-pp-pitch]); } /*for (i=0;i<nsf;i++) exc[i]=PSHR32(exc32[i],13);*/ } #ifndef SPEEX_DISABLE_ENCODER /** Forced pitch delay and gain */ int forced_pitch_quant( spx_word16_t target[], /* Target vector */ spx_word16_t *sw, spx_coef_t ak[], /* LPCs for this subframe */ spx_coef_t awk1[], /* Weighted LPCs #1 for this subframe */ spx_coef_t awk2[], /* Weighted LPCs #2 for this subframe */ spx_sig_t exc[], /* Excitation */ const void *par, int start, /* Smallest pitch value allowed */ int end, /* Largest pitch value allowed */ spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ int p, /* Number of LPC coeffs */ int nsf, /* Number of samples in subframe */ SpeexBits *bits, char *stack, spx_word16_t *exc2, spx_word16_t *r, int complexity, int cdbk_offset, int plc_tuning, spx_word32_t *cumul_gain ) { int i; VARDECL(spx_word16_t *res); ALLOC(res, nsf, spx_word16_t); #ifdef FIXED_POINT if (pitch_coef>63) pitch_coef=63; #else if (pitch_coef>.99) pitch_coef=.99; #endif for (i=0;i<nsf&&i<start;i++) { exc[i]=MULT16_16(SHL16(pitch_coef, 7),exc2[i-start]); } for (;i<nsf;i++) { exc[i]=MULT16_32_Q15(SHL16(pitch_coef, 9),exc[i-start]); } for (i=0;i<nsf;i++) res[i] = EXTRACT16(PSHR32(exc[i], SIG_SHIFT-1)); syn_percep_zero16(res, ak, awk1, awk2, res, nsf, p, stack); for (i=0;i<nsf;i++) target[i]=EXTRACT16(SATURATE(SUB32(EXTEND32(target[i]),EXTEND32(res[i])),32700)); return start; } #endif /* SPEEX_DISABLE_ENCODER */ /** Unquantize forced pitch delay and gain */ void forced_pitch_unquant( spx_word16_t exc[], /* Input excitation */ spx_word32_t exc_out[], /* Output excitation */ int start, /* Smallest pitch value allowed */ int end, /* Largest pitch value allowed */ spx_word16_t pitch_coef, /* Voicing (pitch) coefficient */ const void *par, int nsf, /* Number of samples in subframe */ int *pitch_val, spx_word16_t *gain_val, SpeexBits *bits, char *stack, int count_lost, int subframe_offset, spx_word16_t last_pitch_gain, int cdbk_offset ) { int i; #ifdef FIXED_POINT if (pitch_coef>63) pitch_coef=63; #else if (pitch_coef>.99) pitch_coef=.99; #endif for (i=0;i<nsf;i++) { exc_out[i]=MULT16_16(exc[i-start],SHL16(pitch_coef,7)); exc[i] = EXTRACT16(PSHR32(exc_out[i],13)); } *pitch_val = start; gain_val[0]=gain_val[2]=0; gain_val[1] = pitch_coef; }