Line data Source code
1 : /*====================================================================================
2 : EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0
3 : ====================================================================================*/
4 :
5 : /*This BASOP port is up to date with trunk rev. 36554*/
6 :
7 : #include <assert.h>
8 : #include <stdint.h>
9 : #include "options.h"
10 : #include "cnst.h"
11 : #include "prot_fx.h"
12 : #include "basop32.h"
13 : #include "basop_util.h"
14 : /*-------------------------------------------------------------------------
15 : *
16 : * Perform resynchronisation of the last glottal pulse in voiced lost frame
17 : *
18 : *------------------------------------------------------------------------*/
19 :
20 :
21 : /** Get the location of the minimum energy in the given signal.
22 : * @returns Index of the position of the minimum energy, that is the position i where filter(x[i-filterLength/2],...,x[i+(filterLength-filterLength/2)-1]) is at maximum.
23 : */
24 2494 : static Word16 GetMinimumPosition_fx(
25 : Word16 const *x, /* Input signal. Qx*/
26 : Word16 length, /* The length of the input signal. Q0*/
27 : Word16 filterLength /* the length of the filter length used for the energy calculation. Q0*/
28 : )
29 : {
30 : Word16 iMinEnergyPos, center, i;
31 : Word16 cnt, tmp_e, tmp16;
32 : Word32 energy, energy_old, tmptest;
33 :
34 2494 : filterLength = s_min( filterLength, length ); /*Q0*/
35 2494 : center = shr( filterLength, 1 ); /*Q0*/
36 2494 : iMinEnergyPos = center; /*Q0*/
37 2494 : move16();
38 :
39 2494 : IF( filterLength > 0 )
40 : {
41 1812 : center = add( center, 1 );
42 1812 : energy = L_deposit_l( 0 );
43 1812 : energy_old = L_deposit_l( 0 );
44 :
45 1812 : cnt = sub( length, filterLength ); /*Q0*/
46 :
47 1812 : tmp_e = 0;
48 1812 : move16();
49 333538 : FOR( i = 0; i < cnt; i++ )
50 : {
51 331726 : tmp16 = shr( x[i], tmp_e ); /*Qx*/
52 331726 : energy = L_msu_sat( energy_old, tmp16, tmp16 ); /*2Qx+1*/
53 331726 : tmp16 = shr( x[( i + filterLength )], tmp_e ); /*Qx*/
54 : BASOP_SATURATE_WARNING_OFF_EVS /*Saturation will be handled*/
55 331726 : energy = L_mac_sat( energy, tmp16, tmp16 ); /*2Qx+1*/
56 : BASOP_SATURATE_WARNING_ON_EVS
57 :
58 : /*if (energy == MAXVAL_WORD32)*/
59 : BASOP_SATURATE_WARNING_OFF_EVS /*saturates if energy < 0*/
60 331726 : tmptest = L_sub_sat( energy, MAXVAL_WORD32 );
61 : /*Q31*/
62 : BASOP_SATURATE_WARNING_ON_EVS
63 331726 : IF( tmptest == 0 )
64 : {
65 0 : tmp_e = add( tmp_e, 1 );
66 0 : energy = L_shr( energy_old, 2 );
67 0 : tmp16 = shr( x[i], tmp_e ); /*Qx-1*/
68 0 : energy = L_msu( energy, tmp16, tmp16 ); /*2Qx-1*/
69 0 : tmp16 = shr( x[( i - filterLength )], tmp_e );
70 0 : energy = L_mac( energy, tmp16, tmp16 ); /*2Qx-1*/
71 : }
72 :
73 331726 : IF( energy < 0 )
74 : {
75 11952 : iMinEnergyPos = add( i, center ); /*Q0*/
76 11952 : tmp_e = 0;
77 11952 : move16();
78 11952 : energy = 0;
79 11952 : move16();
80 : }
81 331726 : energy_old = L_add( energy, 0 );
82 : }
83 : }
84 :
85 2494 : return iMinEnergyPos; /*Q0*/
86 : }
87 :
88 : /*!
89 : * \brief FindMaxPeak - Get the location of the maximum peak in the given signal.
90 : *
91 : * \returns Index of the position of the maximum peak, that is the position i where abs(x[i]) has it's maximum.
92 : */
93 :
94 1260 : static Word16 FindMaxPeak_fx(
95 : Word16 /*float*/ const *x, /*<!i : Input signal. Q15*/
96 : Word16 /*int*/ length /*<!i : The length of the input signal.*/
97 : )
98 : {
99 : Word16 iMax, i;
100 :
101 1260 : iMax = 0;
102 1260 : move16();
103 295754 : FOR( i = 1; i < length; i++ )
104 : {
105 294494 : if ( GT_16( abs_s( x[i] ), abs_s( x[iMax] ) ) )
106 : {
107 6832 : iMax = i; /*Q0*/
108 6832 : move16();
109 : }
110 : }
111 :
112 1260 : return iMax; /*Q0*/
113 : }
114 :
115 791 : static void AddSamples_fx(
116 : Word16 const *const old_exc, /*Qx*/
117 : Word16 *const new_exc, /*Qx*/
118 : Word16 const L_frame, /*Q0*/
119 : Word16 const n_samples_to_add, /*Q0*/
120 : Word16 const min_pos[], /*Q0*/
121 : Word16 const points_by_pos[], /*Q0*/
122 : Word16 const nb_min /*Q0*/
123 : )
124 : {
125 : Word16 *pt_dest;
126 : Word16 const *pt_src;
127 : Word16 last_min_pos, i, j;
128 : Word16 ftmp;
129 :
130 791 : pt_dest = new_exc; /*Qx*/
131 791 : pt_src = old_exc; /*Qx*/
132 791 : last_min_pos = 0;
133 791 : move16();
134 :
135 4346 : FOR( i = 0; i < nb_min; i++ )
136 : {
137 : /* Copy section */
138 526146 : FOR( j = min_pos[i] - last_min_pos; j > 0; j-- )
139 : {
140 522591 : *pt_dest++ = *pt_src++; /*Qx*/
141 522591 : move16();
142 : }
143 : /* Add some samples */
144 3555 : ftmp = negate( mult( *pt_src, 1638 /*.05f Q15*/ ) ); /*Qx*/
145 :
146 8467 : FOR( j = 0; j < points_by_pos[i]; j++ )
147 : {
148 4912 : *pt_dest++ = ftmp; /*Qx*/
149 4912 : move16();
150 4912 : ftmp = negate( ftmp ); /*Qx*/
151 : }
152 : /* Prepare for the next loop iteration */
153 3555 : last_min_pos = min_pos[i]; /*Q0*/
154 3555 : move16();
155 : }
156 : /* Copy remaining length */
157 50248 : FOR( j = sub( L_frame, add( n_samples_to_add, last_min_pos ) ); j > 0; j-- )
158 : {
159 49457 : *pt_dest++ = *pt_src++; /*Qx*/
160 49457 : move16();
161 : }
162 791 : }
163 :
164 469 : static void RemoveSamples_fx(
165 : Word16 /*float*/ const *const old_exc, /*i : Qx */
166 : Word16 /*float*/ *const new_exc, /*o : Qx */
167 : Word16 /*int*/ const L_frame, /*i : Q0 */
168 : Word16 /*int*/ const n_samples_to_add, /*i : Q0 */
169 : Word16 /*int*/ const min_pos[], /*i : Q0 */
170 : Word16 /*int*/ const points_by_pos[], /*i : Q0 */
171 : Word16 /*int*/ const nb_min /*i : Q0*/
172 : )
173 : {
174 : Word16 /*float*/ *pt_dest;
175 : Word16 /*float*/ const *pt_src;
176 : Word16 /*int*/ last_min_pos, i, j;
177 :
178 :
179 469 : pt_dest = new_exc + L_frame; /*Qx*/
180 469 : last_min_pos = sub( L_frame, n_samples_to_add ); /*Q0*/
181 :
182 2813 : FOR( i = sub( nb_min, 1 ); i >= 0; i-- )
183 : {
184 : /* Compute len to copy */
185 : /* Copy section, removing some samples */
186 2344 : pt_src = old_exc + last_min_pos; /*Qx*/
187 :
188 322248 : FOR( j = sub( last_min_pos, add( min_pos[i], points_by_pos[i] ) ); j > 0; j-- )
189 : {
190 319904 : *--pt_dest = *--pt_src; /*Qx*/
191 319904 : move16();
192 : }
193 : /* Prepare for the next loop iteration */
194 2344 : last_min_pos = min_pos[i]; /*Q0*/
195 2344 : move16();
196 : }
197 : /* Copy remaining length */
198 469 : pt_src = old_exc + last_min_pos; /*Qx*/
199 :
200 20661 : FOR( j = last_min_pos; j > 0; j-- )
201 : {
202 20192 : *--pt_dest = *--pt_src; /*Qx*/
203 20192 : move16();
204 : }
205 469 : }
206 :
207 : /** Resynchronize glotal pulse positions of the signal in src_exc and store it in dst_exc.
208 : * src_exc holds on call the harmonic part of the signal with the constant pitch, constructed by repeating the last pitch cycle of length pitchStart.
209 : * dst_exc holds on return the harmonic part of the signal with the pitch changing from pitchStart to pitchEnd.
210 : * src_exc and dst_exc can overlap, but src_exc < dst_exc must be fullfiled.
211 : */
212 : /*This BASOP port is up to date with trunk rev 8779(svnext2)*/
213 1260 : void PulseResynchronization_fx(
214 : Word16 /*float*/ const *const src_exc, /*<!i : Input excitation buffer Q15*/
215 : Word16 /*float*/ *const dst_exc, /*<!o : Output excitation buffer Q15*/
216 : Word16 /*int*/ const nFrameLength, /*<!i : Length of the frame, that is the length of the valid data in the excitation buffer on return. Q0 */
217 : Word16 /*int*/ const nSubframes, /*<!i : Number of subframes in the excitation buffer. nFrameLength must be divisible by nSubframes Q0 */
218 : Word32 /*float*/ const pitchStart, /*<!i : Pitch at the end of the last frame Q16*/
219 : Word32 /*float*/ const pitchEnd /*<!i : Pitch at the end of the current frame Q16*/
220 : )
221 : {
222 : Word16 /*int*/ T0, i, k;
223 : Word16 /*float*/ perCycleDeltaDelta, cycleDelta, freqStart, fractionalLeft;
224 : Word16 /*int*/ roundedPitchStart, nSamplesDelta, nSamplesDeltaRemain, iMinPos1, iMinPos[NB_PULSES_MAX + 1], iDeltaSamples[NB_PULSES_MAX + 1], maxDeltaSamples, roundedCycleDelta;
225 : Word16 tmp16, tmp16_a, freqStart_e /*exponent of freqStart*/, tmp_e, samplesDelta_e, perCycleDeltaDelta_e, cycleDelta_e, tmp2_e, tmp3_e;
226 : Word32 /* pitchDelta, */ tmp32, tmp32_a, tmp32_b, samplesDelta, absPitchDiff, cycleDelta32;
227 :
228 :
229 1260 : test();
230 1260 : test();
231 1260 : test();
232 1260 : test();
233 1260 : test();
234 1260 : test();
235 1260 : IF( ( LT_32( L_deposit_h( nFrameLength ), pitchStart ) ) || ( pitchStart <= 0 ) || ( pitchEnd <= 0 ) || ( LT_16( nSubframes, 1 ) ) || ( GT_16( nSubframes, 5 ) ) || ( LE_32( Mpy_32_16_1( pitchEnd, add( nSubframes, 1 ) ), Mpy_32_16_1( pitchStart, sub( nSubframes, 1 ) ) ) ) || ( src_exc - dst_exc >= 0 ) )
236 : {
237 : /* This is error handling and recovery that should never occur. */
238 0 : test();
239 0 : IF( src_exc != dst_exc && LE_16( nFrameLength, 1200 ) )
240 : {
241 0 : Copy( src_exc, dst_exc, nFrameLength ); /*Q15*/
242 : }
243 0 : return;
244 : }
245 :
246 1260 : roundedPitchStart = round_fx( pitchStart ); /*Q0*/
247 :
248 : /* freqStart = 1.0f/roundedPitchStart; */
249 1260 : freqStart_e = 15;
250 1260 : move16();
251 1260 : freqStart = Inv16( roundedPitchStart, &freqStart_e ); /*Q15,freqStart_e*/
252 :
253 : /* Calculate number of samples to be removed (if negative) or added (if positive) */
254 : /*samplesDelta = 0.5f*pitchDelta*nFrameLength*(nSubframes+1)*freqStart;*/
255 : /* pitchDelta*freqStart = ((pitchEnd - pitchStart)/roundedPitchStart)/nSubframes */
256 1260 : tmp16 = shl( roundedPitchStart, 2 ); /*Q0*/
257 1260 : if ( EQ_16( nSubframes, 5 ) )
258 : {
259 651 : tmp16 = add( tmp16, roundedPitchStart ); /*Q0*/ /*tmp16=roundedPitchStart*nSubframes*/
260 : }
261 1260 : tmp_e = norm_s( tmp16 );
262 1260 : tmp16 = shl( tmp16, tmp_e ); /*Q0,-tmp_e*/ /*tmp16=roundedPitchStart*nSubframes*/
263 1260 : tmp_e = sub( 15, tmp_e );
264 1260 : tmp16 = Inv16( tmp16, &tmp_e ); /*Q15,tmp_e*/ /*tmp16=1.0/(roundedPitchStart*nSubframes)*/
265 1260 : tmp32 = L_sub( pitchEnd, pitchStart ); /*Q16*/
266 1260 : tmp2_e = norm_l( tmp32 );
267 1260 : tmp32 = L_shl( tmp32, tmp2_e ); /*Q16,-tmp2_e*/
268 1260 : tmp32 = Mpy_32_16_1( tmp32, tmp16 ); /*Q16,tmp_e-tmp2_e*/ /*tmp32=pitchDelta*freqStart*/
269 1260 : tmp_e = sub( tmp_e, tmp2_e ); /* sum up all the scalings for tmp32 */
270 :
271 1260 : tmp16 = imult1616( nFrameLength, add( nSubframes, 1 ) ); /*Q0*/ /*tmp16=nFrameLength*(nSubframes+1)*/
272 1260 : tmp2_e = norm_s( tmp16 );
273 1260 : tmp16 = shl( tmp16, tmp2_e ); /*Q0+tmp2_e*/
274 :
275 1260 : tmp32 = Mpy_32_16_1( tmp32, tmp16 ); /*Q1 scaling (tmp_e-tmp2_e-1), -1 because of 0.5f*/ /*tmp32=0.5f*pitchDelta*nFrameLength*(nSubframes+1)*freqStart*/
276 1260 : tmp_e = sub( sub( tmp_e, tmp2_e ), 1 ); /* sum up all the scalings for tmp32 */
277 1260 : tmp_e = add( tmp_e, 31 - 1 ); /* tmp32 is now regarded as Q31 with scaling tmp_e */
278 :
279 : /*samplesDelta -= nFrameLength*(1.0f-pitchStart*freqStart);*/
280 1260 : tmp2_e = norm_l( pitchStart );
281 1260 : tmp32_a = L_shl( pitchStart, tmp2_e ); /*Q16+tmp2_e*/
282 1260 : tmp32_a = Mpy_32_16_1( tmp32_a /*Q16,-tmp2_e*/, freqStart /*Q15,freqStart_e*/ ); /*Q16, scaling (freqStart_e-tmp2_e)*/ /*tmp32_a=pitchStart*freqStart*/
283 1260 : tmp16 = norm_l( tmp32_a );
284 1260 : tmp32_a = L_shl( tmp32_a, tmp16 );
285 1260 : tmp2_e = sub( sub( freqStart_e, tmp16 ), tmp2_e ); /* sum up all scalings for tmp32_a */
286 1260 : tmp2_e = add( tmp2_e, 31 - 16 ); /* tmp32_a is now regarded as Q31 with scaling tmp2_e */
287 :
288 1260 : tmp3_e = tmp2_e;
289 1260 : move16();
290 1260 : tmp32_a = L_negate( tmp32_a );
291 1260 : tmp32_a = L_add( L_shl_sat( 1, sub( 31, tmp3_e ) ), tmp32_a ); /*Q31,tmp3_e*/ /*tmp32_a= 1.0f-pitchStart*freqStart*/
292 1260 : tmp2_e = norm_s( nFrameLength );
293 1260 : tmp16_a = shl( nFrameLength, tmp2_e ); /*Q0+tmp2_e*/
294 1260 : tmp32_a = Mpy_32_16_1( tmp32_a /*Q31,tmp3_e*/, tmp16_a /*Q0,-tmp2_e*/ ); /*Q16,tmp3_e-tmp2_e*/ /*tmp32_a= nFrameLength*(1.0f-pitchStart*freqStart)*/
295 1260 : tmp2_e = add( sub( tmp3_e, tmp2_e ), 15 );
296 1260 : samplesDelta = BASOP_Util_Add_Mant32Exp( tmp32, tmp_e, L_negate( tmp32_a ), tmp2_e, &samplesDelta_e ); /*Q31,samplesDelta_e*/
297 :
298 : /* To have enough samples in the buffer of length nFrameLength*(nSubframes+1)/nSubframes, pitchEnd/pitchEnd must be bigger than (nSubframes-1)/(nSubframes+1)=1-2/(nSubframes+1) */
299 : /* Thus nSubframes must be bigger than 1 */
300 1260 : nSamplesDelta = round_fx( L_shl( samplesDelta, sub( samplesDelta_e, 31 - 16 ) ) ); /*Q0*/
301 1260 : nSamplesDeltaRemain = abs_s( nSamplesDelta );
302 : /* Find the location of the glottal pulse */
303 1260 : T0 = FindMaxPeak_fx( src_exc, roundedPitchStart ); /*Q0*/
304 : /* Get the index of the last pulse in the resynchronized frame */
305 : /*k = (int)ceil((nFrameLength-nSamplesDelta-T0)*freqStart - 1);*/
306 1260 : tmp32 = BASOP_Util_Add_Mant32Exp( L_mult( sub( nFrameLength, add( nSamplesDelta, T0 ) ), freqStart ) /*Q16*/, add( freqStart_e, 31 - 16 ), (Word32) 0x80000000 /*-1.f Q31*/, 0, &tmp_e );
307 1260 : tmp32 = L_shl( tmp32, sub( tmp_e, 31 - 16 ) ) /*Q16*/;
308 1260 : tmp32 = L_add( tmp32, 65536l /*1.f Q16*/ );
309 1260 : k = extract_h( tmp32 );
310 1260 : test();
311 1260 : IF( ( k >= 0 ) && LE_16( add( k, 1 ), NB_PULSES_MAX ) )
312 : {
313 1260 : absPitchDiff = L_abs( L_sub( L_deposit_h( roundedPitchStart ), pitchEnd ) ); /*Q16*/
314 :
315 : /* Calculate the delta of the samples to be added/removed between consecutive cycles */
316 : /*perCycleDeltaDelta = (absPitchDiff*(nFrameLength-samplesDelta) - (float)fabs(samplesDelta)*roundedPitchStart)
317 : / ((k+1)*(T0+0.5f*k*roundedPitchStart));*/
318 1260 : tmp32 = L_sub( L_deposit_h( nFrameLength ), L_shl( samplesDelta, sub( samplesDelta_e, 31 - 16 ) ) ); /*Q16*/
319 1260 : tmp_e = 15; /*tmp32 = Q31,tmp_e*/
320 1260 : move16();
321 1260 : tmp2_e = norm_l( tmp32 );
322 1260 : tmp32 = L_shl( tmp32, tmp2_e );
323 1260 : tmp_e = sub( tmp_e, tmp2_e ); /*tmp32 = Q31,tmp_e*/
324 1260 : tmp2_e = norm_l( absPitchDiff );
325 1260 : tmp32_b = L_shl( absPitchDiff, tmp2_e ); /*Q16+tmp2_e*/
326 1260 : tmp_e = sub( tmp_e, tmp2_e );
327 1260 : tmp32 = Mpy_32_16_1( tmp32_b, round_fx( tmp32 ) ); /*Q16,tmp_e*/ /*tmp32 = absPitchDiff*(nFrameLength-samplesDelta)*/
328 1260 : tmp32_a = Mpy_32_16_1( L_abs( samplesDelta ) /*Q31,samplesDelta_e*/, roundedPitchStart /*Q0*/ ); /*Q16,samplesDelta_e*/ /*tmp32_a=fabs(samplesDelta)*roundedPitchStart*/
329 1260 : tmp32 = BASOP_Util_Add_Mant32Exp( tmp32, add( tmp_e, 31 - 16 ), L_negate( tmp32_a ), add( samplesDelta_e, 31 - 16 ), &tmp_e ); /*Q31,tmp_e*/ /*tmp32=absPitchDiff*(nFrameLength-samplesDelta)-fabs(samplesDelta)*roundedPitchStart*/
330 1260 : tmp16 = imult1616( add( k, 1 ), add( shl( T0, 1 ), imult1616( k, roundedPitchStart ) ) ); /*Q0,-1*/ /*tmp16=(k+1)*(T0+0.5f*k*roundedPitchStart)*/
331 1260 : perCycleDeltaDelta = BASOP_Util_Divide3216_Scale( tmp32 /*Q31,tmp_e*/, tmp16 /*Q0,-1*/, &perCycleDeltaDelta_e ); /*Q15,perCycleDeltaDelta_e*/
332 1260 : perCycleDeltaDelta_e = add( perCycleDeltaDelta_e, sub( tmp_e, -1 + 15 ) );
333 1260 : tmp_e = norm_s( perCycleDeltaDelta );
334 1260 : perCycleDeltaDelta_e = sub( perCycleDeltaDelta_e, tmp_e );
335 1260 : perCycleDeltaDelta = shl( perCycleDeltaDelta, tmp_e ); /*Q15,perCycleDeltaDelta_e*/
336 :
337 :
338 : /* Calculate the integer number of samples to be added/removed in each pitch cycle */
339 : /*cycleDelta = max(0, (absPitchDiff-(k+1)*perCycleDeltaDelta)*T0*freqStart); */
340 1260 : tmp_e = norm_s( add( k, 1 ) );
341 1260 : tmp32 = L_mult( perCycleDeltaDelta /*Q15,perCycleDeltaDelta_e*/, shl( add( k, 1 ), tmp_e ) /*Q0, tmp_e*/ ) /*Q0+16, perCycleDeltaDelta_e-tmp_e*/;
342 1260 : tmp32 = BASOP_Util_Add_Mant32Exp( absPitchDiff /*Q16*/, 31 - 16, L_negate( tmp32 ), add( sub( perCycleDeltaDelta_e, tmp_e ), 31 - 16 ), &tmp_e ); /*Q31,tmp_e*/
343 1260 : tmp32 = Mpy_32_16_1( tmp32, T0 /*Q0*/ ); /*Q16,tmp_e*/
344 1260 : tmp32 = Mpy_32_16_1( tmp32 /*Q16,tmp_e*/, freqStart /*Q15,freqStart_e*/ ) /*Q16, tmp_e+(freqStart_e)*/;
345 1260 : tmp32 = L_max( 0, tmp32 );
346 1260 : cycleDelta_e = add( tmp_e, freqStart_e );
347 1260 : tmp32_a = L_shl( tmp32, cycleDelta_e );
348 1260 : roundedCycleDelta = extract_h( L_abs( tmp32_a ) );
349 1260 : if ( tmp32 < 0 )
350 : {
351 0 : roundedCycleDelta = negate( roundedCycleDelta );
352 : }
353 1260 : fractionalLeft = lshr( extract_l( tmp32_a ), 1 ); /*Q15*/
354 1260 : tmp_e = sub( 15, norm_l( tmp32 ) );
355 1260 : cycleDelta_e = add( cycleDelta_e, tmp_e );
356 1260 : tmp32 = L_shr( tmp32, sub( tmp_e, 15 ) ); /*Q31 frac, cycleDelta_e*/
357 1260 : cycleDelta = round_fx_sat( tmp32 ); /*Q15, cycleDelta_e*/
358 1260 : if ( cycleDelta == 0 )
359 : {
360 103 : cycleDelta_e = 0;
361 103 : move16();
362 : }
363 :
364 : /*roundedCycleDelta = (int)(cycleDelta); */ /*done above*/
365 1260 : iDeltaSamples[0] = roundedCycleDelta; /*Q0*/
366 1260 : move16();
367 : /*fractionalLeft = cycleDelta-roundedCycleDelta;*/ /*done above*/
368 1260 : nSamplesDeltaRemain = sub( nSamplesDeltaRemain, roundedCycleDelta ); /*Q0*/
369 :
370 1260 : tmp_e = s_max( 2, k );
371 1260 : tmp_e = norm_s( tmp_e ); /*maximum norming factor for following loop*/
372 :
373 :
374 4639 : FOR( i = 1; i <= k; i++ )
375 : {
376 : /*cycleDelta = (absPitchDiff-(k+1-i)*perCycleDeltaDelta) + fractionalLeft; */
377 3379 : tmp32 = L_mult( perCycleDeltaDelta /*Q15,perCycleDeltaDelta_e*/, shl( sub( add( k, 1 ), i ), tmp_e ) /*Q0, tmp_e*/ ) /*Q0+16, perCycleDeltaDelta_e-tmp_e*/; /*calcultion of base for first iteration*/
378 3379 : tmp32 = L_shl( tmp32, sub( perCycleDeltaDelta_e, tmp_e ) ); /*Q16*/
379 3379 : tmp32_a = L_sub( absPitchDiff, tmp32 );
380 3379 : tmp32_b = L_lshl( L_deposit_l( fractionalLeft /*Q15*/ ), 1 ) /*Q16*/;
381 3379 : cycleDelta32 = L_add( tmp32_a, tmp32_b ); /*Q16*/
382 3379 : cycleDelta32 = L_max( 0, cycleDelta32 );
383 :
384 : /* Make sure that the number of samples increases */
385 3379 : IF( GT_32( L_deposit_h( roundedCycleDelta ), cycleDelta32 ) )
386 : {
387 210 : iDeltaSamples[i] = roundedCycleDelta; /*Q0*/
388 210 : move16();
389 210 : roundedCycleDelta = extract_h( cycleDelta32 ); /* cycleDelta32 should never be < 0 here Q0*/
390 210 : iDeltaSamples[i - 1] = roundedCycleDelta; /*Q0*/
391 210 : move16();
392 : }
393 : ELSE
394 : {
395 3169 : roundedCycleDelta = extract_h( cycleDelta32 ); /* cycleDelta32 should never be < 0 here Q0*/
396 3169 : iDeltaSamples[i] = roundedCycleDelta; /*Q0*/
397 3169 : move16();
398 : }
399 : /*fractionalLeft = cycleDelta-roundedCycleDelta = cycleDelta-(int)cycleDelta;*/
400 3379 : fractionalLeft = lshr( extract_l( cycleDelta32 ), 1 ); /*Q15*/ /* cycleDelta32 should never be < 0 here */
401 3379 : nSamplesDeltaRemain = sub( nSamplesDeltaRemain, roundedCycleDelta );
402 : }
403 1260 : iDeltaSamples[( k + 1 )] = s_max( 0, nSamplesDeltaRemain );
404 1260 : move16();
405 1260 : maxDeltaSamples = s_max( iDeltaSamples[k], iDeltaSamples[( k + 1 )] ); /*Q0*/
406 :
407 : /* Find the location of the minimum energy between the first two pulses */
408 :
409 : /*iMinPos1 = T0+GetMinimumPosition_fx(src_exc+T0, min(roundedPitchStart, (nSubframes+1)*nFrameLength/nSubframes-T0), maxDeltaSamples);*/
410 1260 : BASOP_Util_Divide_MantExp( add( nSubframes, 1 ), 15, nSubframes, 15, &tmp16, &tmp_e );
411 1260 : tmp32 = L_mult( nFrameLength /*Q0*/, tmp16 /*Q15,tmp_e*/ ); /*Q16,tmp_e*/
412 1260 : tmp16 = round_fx( L_shl( tmp32, tmp_e ) ); /*Q0*/
413 1260 : tmp16 = sub( tmp16, T0 ); /*Q0*/
414 1260 : tmp16 = s_min( roundedPitchStart, tmp16 );
415 :
416 1260 : iMinPos1 = GetMinimumPosition_fx(
417 1260 : src_exc + T0, /*Qx*/
418 : tmp16, /*Q0*/
419 : maxDeltaSamples /*Q0*/
420 : );
421 1260 : iMinPos1 = add( iMinPos1, T0 );
422 :
423 :
424 1260 : IF( nSamplesDelta < 0 )
425 : {
426 : /* Find the location of the minimum energy before the first pulse */
427 :
428 469 : IF( GT_16( iMinPos1, add( roundedPitchStart, shr( iDeltaSamples[0], 1 ) ) ) )
429 : {
430 258 : iMinPos[0] = sub( iMinPos1, sub( roundedPitchStart, shr( iDeltaSamples[0], 1 ) ) ); /*Q0*/
431 258 : move16();
432 : }
433 : ELSE
434 : {
435 211 : iMinPos[0] = sub( GetMinimumPosition_fx( src_exc, T0, iDeltaSamples[0] ), shr( iDeltaSamples[0], 1 ) ); /*Q0*/
436 211 : move16();
437 : }
438 :
439 : /* Find the location of the minimum energy between the pulses */
440 1875 : FOR( i = 1; i <= k; i++ )
441 : {
442 1406 : iMinPos[i] = add( iMinPos1, sub( imult1616( sub( i, 1 ), roundedPitchStart ), shr( iDeltaSamples[i], 1 ) ) ); /*Q0*/
443 1406 : move16();
444 : }
445 : /* Find the location of the minimum energy after the last pulse */
446 :
447 469 : IF( LT_16( add( iMinPos1, add( imult1616( k, roundedPitchStart ), sub( iDeltaSamples[( k + 1 )], shr( iDeltaSamples[( k + 1 )], 1 ) ) ) ), sub( nFrameLength, nSamplesDelta ) ) )
448 : {
449 225 : iMinPos[( k + 1 )] = add( iMinPos1, sub( imult1616( k, roundedPitchStart ), shr( iDeltaSamples[( k + 1 )], 1 ) ) ); /*Q0*/
450 225 : move16();
451 : }
452 : ELSE
453 : {
454 : /*iMinPos[k+1] = T0+k*roundedPitchStart
455 : + GetMinimumPosition_fx(src_exc+T0+k*roundedPitchStart, nFrameLength-nSamplesDelta-(T0+k*roundedPitchStart), iDeltaSamples[k+1])
456 : - iDeltaSamples[k+1]/2; */
457 244 : tmp16 = GetMinimumPosition_fx( src_exc + add( T0, imult1616( k, roundedPitchStart ) ), sub( nFrameLength, add( nSamplesDelta, add( T0, imult1616( k, roundedPitchStart ) ) ) ), iDeltaSamples[( k + 1 )] ); /*Q0*/
458 244 : tmp16 = add( add( T0, imult1616( k, roundedPitchStart ) ), tmp16 );
459 244 : tmp16 = sub( tmp16, shr( iDeltaSamples[( k + 1 )], 1 ) );
460 244 : iMinPos[( k + 1 )] = tmp16;
461 244 : move16();
462 : }
463 :
464 469 : IF( GT_16( add( iMinPos[( k + 1 )], iDeltaSamples[( k + 1 )] ), sub( nFrameLength, nSamplesDelta ) ) )
465 : {
466 1 : iDeltaSamples[k] = add( iDeltaSamples[k], add( iMinPos[( k + 1 )], sub( iDeltaSamples[( k + 1 )], sub( nFrameLength, nSamplesDelta ) ) ) ); /*Q0*/
467 1 : move16();
468 1 : iDeltaSamples[( k + 1 )] = sub( nFrameLength, add( nSamplesDelta, iMinPos[( k + 1 )] ) ); /*Q0*/
469 1 : move16();
470 : }
471 :
472 : /* Remove samples at the given positions */
473 469 : RemoveSamples_fx( src_exc, dst_exc, nFrameLength, nSamplesDelta, iMinPos, iDeltaSamples, add( k, 2 ) );
474 : }
475 : ELSE
476 : {
477 : /* Find the location of the minimum energy before the first pulse */
478 791 : IF( GT_16( iMinPos1, roundedPitchStart ) )
479 : {
480 391 : iMinPos[0] = sub( iMinPos1, roundedPitchStart ); /*Q0*/
481 391 : move16();
482 : }
483 : ELSE
484 : {
485 400 : iMinPos[0] = GetMinimumPosition_fx( src_exc, T0, iDeltaSamples[0] ); /*Q0*/
486 400 : move16();
487 : }
488 : /* Find the location of the minimum energy between the pulses */
489 :
490 2764 : FOR( i = 1; i <= k; i++ )
491 : {
492 1973 : iMinPos[i] = iMinPos1; /*Q0*/
493 1973 : move16();
494 1973 : iMinPos1 = add( iMinPos1, roundedPitchStart ); /*Q0*/
495 : }
496 :
497 : /* Find the location of the minimum energy after the last pulse */
498 791 : IF( LT_16( iMinPos1, sub( nFrameLength, nSamplesDelta ) ) )
499 : {
500 412 : iMinPos[( k + 1 )] = iMinPos1;
501 412 : move16();
502 : }
503 : ELSE
504 : {
505 :
506 379 : tmp16 = GetMinimumPosition_fx( src_exc + add( T0, imult1616( k, roundedPitchStart ) ), sub( nFrameLength, add( nSamplesDelta, add( T0, imult1616( k, roundedPitchStart ) ) ) ), iDeltaSamples[( k + 1 )] ); /*Q0*/
507 379 : tmp16 = add( add( tmp16, T0 ), imult1616( k, roundedPitchStart ) );
508 379 : iMinPos[( k + 1 )] = tmp16; /*Q0*/
509 379 : move16();
510 : }
511 :
512 791 : IF( GT_16( add( iMinPos[( k + 1 )], iDeltaSamples[( k + 1 )] ), sub( nFrameLength, nSamplesDelta ) ) )
513 : {
514 4 : iDeltaSamples[k] = add( iDeltaSamples[k], add( iMinPos[( k + 1 )], sub( iDeltaSamples[( k + 1 )], sub( nFrameLength, nSamplesDelta ) ) ) ); /*Q0*/
515 4 : move16();
516 4 : iDeltaSamples[( k + 1 )] = sub( sub( nFrameLength, nSamplesDelta ), iMinPos[( k + 1 )] ); /*Q0*/
517 4 : move16();
518 : }
519 : /* Add samples at the given positions */
520 791 : AddSamples_fx( src_exc, dst_exc, nFrameLength, nSamplesDelta, iMinPos, iDeltaSamples, add( k, 2 ) );
521 : }
522 : }
523 : }
|