Line data Source code
1 : /******************************************************************************************************
2 :
3 : (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
4 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
5 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
6 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
7 : contributors to this repository. All Rights Reserved.
8 :
9 : This software is protected by copyright law and by international treaties.
10 : The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
11 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
12 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
13 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
14 : contributors to this repository retain full ownership rights in their respective contributions in
15 : the software. This notice grants no license of any kind, including but not limited to patent
16 : license, nor is any license granted by implication, estoppel or otherwise.
17 :
18 : Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
19 : contributions.
20 :
21 : This software is provided "AS IS", without any express or implied warranties. The software is in the
22 : development stage. It is intended exclusively for experts who have experience with such software and
23 : solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
24 : and fitness for a particular purpose are hereby disclaimed and excluded.
25 :
26 : Any dispute, controversy or claim arising under or in relation to providing this software shall be
27 : submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
28 : accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
29 : the United Nations Convention on Contracts on the International Sales of Goods.
30 :
31 : *******************************************************************************************************/
32 :
33 : /*====================================================================================
34 : EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0
35 : ====================================================================================*/
36 :
37 : /*! @file jbm_pcmdsp_apa.c Adaptive Playout for Audio (apa). */
38 :
39 : /* system headers */
40 : #include <assert.h>
41 : #include <math.h>
42 : #include <stdlib.h>
43 : #include <stdio.h>
44 : #include <stdint.h>
45 : #include <string.h>
46 : #include "options.h"
47 : #include "prot_fx.h"
48 : #include "wmc_auto.h"
49 : /* local headers */
50 : #include "jbm_pcmdsp_apa.h"
51 : #include "jbm_pcmdsp_similarityestimation.h"
52 : #include "jbm_pcmdsp_window.h"
53 : #include "cnst.h"
54 : #include "rom_dec.h"
55 :
56 :
57 : #define INV_100_Q15 328
58 : #define INV_400_Q15 82
59 : #define INV_80_Q15 410
60 :
61 :
62 : /*---------------------------------------------------------------------*
63 : * Local state structure
64 : *---------------------------------------------------------------------*/
65 :
66 : /* maximum number of segments/iterations in extend_frm() */
67 : #define MAXN 10
68 :
69 : /* definition of state struct */
70 : struct apa_state_t
71 : {
72 : Word16 signalScaleForCorrelation;
73 : Word16 frmInScaled[6 * 2 * 48000 / 50 * 2];
74 :
75 : /* output buffer */
76 : bool evs_compat_mode;
77 :
78 : Word16 *buf_out_fx;
79 : Word16 Q_buf_out; /* stores the scaling of buf_out_fx */
80 : #ifdef FIX1998_APA_EXEC_SCALING
81 : Word16 Q_a_out_init_old; /* stores initially determined max. scaling of data in buf_out_fx, before beeing adjusted to previous frame scaling */
82 : #endif
83 : UWord16 buf_out_capacity;
84 : UWord16 l_buf_out;
85 :
86 : /* Hann window */
87 : const Word16 *win_fx;
88 : // const Word16 *win_fx;
89 : UWord16 l_halfwin;
90 :
91 : Word16 win_incrementor;
92 :
93 : /* sampling rate [Hz] */
94 : UWord16 rate;
95 :
96 : /* length of a segment [samples] */
97 : UWord16 l_seg;
98 :
99 : /* length of a frame [samples] */
100 : UWord16 l_frm;
101 :
102 : /* total number of processed input samples since apa_reset() */
103 : UWord32 l_in_total;
104 :
105 : /* time resolution in samples of the IVAS renderer*/
106 : UWord16 l_ts;
107 :
108 : /* samples already available in the renderer buffer */
109 : UWord16 l_r_buf;
110 :
111 : /* sum of inserted/removed samples since last apa_set_scale() */
112 : Word32 diffSinceSetScale;
113 : /* number of input frames since last apa_set_scale() */
114 : UWord32 nFramesSinceSetScale;
115 :
116 : /* current and previous scaling ratio [%] */
117 : UWord16 scale;
118 :
119 : /* minimum pitch length [samples] */
120 : UWord16 p_min;
121 :
122 : /* search length [samples] */
123 : UWord16 l_search;
124 :
125 : UWord16 wss; /* waveform subsampling per channel */
126 : UWord16 css; /* correlation subsampling per channel */
127 :
128 : Word32 targetQuality_fx; /* Q16 */
129 : UWord16 qualityred; /* quality reduction threshold */
130 : UWord16 qualityrise; /* quality rising for adaptive quality thresholds */
131 :
132 : UWord16 last_pitch; /* last pitch/sync position */
133 : UWord16 bad_frame_count; /* # frames before quality threshold is lowered */
134 : UWord16 good_frame_count; /* # scaled frames */
135 :
136 : UWord16 num_channels; /* number of input/output channels */
137 : };
138 :
139 :
140 : /*---------------------------------------------------------------------*
141 : * Local function prototypes
142 : *---------------------------------------------------------------------*/
143 :
144 : Word16 apa_corrEnergy2dB_fx( Word32 energy, Word16 energyExp, Word16 corr_len );
145 :
146 : Word16 apa_getQualityIncreaseForLowEnergy_fx( Word16 energydB );
147 :
148 : static Word8 logarithmic_search_fx( const apa_state_t *ps, const Word16 *signal, Word16 s_start, Word16 inlen, Word16 offset, Word16 fixed_pos, Word16 corr_len, Word16 wss, Word16 css, Word16 *synchpos );
149 :
150 : static Word16 find_synch_fx( apa_state_t *ps, const Word16 *in, Word16 l_in, Word16 s_start, Word16 s_len, Word16 fixed_pos, Word16 corr_len, Word16 offset, Word16 *energydBQ8, Word32 *qualityQ16, Word16 *synch_pos );
151 :
152 : static bool copy_frm_fx( apa_state_t *ps, const Word16 frm_in[], Word16 frm_out[], UWord16 *l_frm_out );
153 :
154 : static bool shrink_frm_fx( apa_state_t *ps, const Word16 frm_in[], UWord16 maxScaling, Word16 frm_out[], UWord16 *l_frm_out );
155 :
156 : static bool shrink_frm_ivas_fx( apa_state_t *ps, const Word16 frm_in[], UWord16 maxScaling, Word16 frm_out[], Word16 Q_frm_in, UWord16 *l_frm_out );
157 :
158 : static bool extend_frm_fx( apa_state_t *ps, const Word16 frm_in[], Word16 frm_out[], UWord16 *l_frm_out );
159 :
160 : static bool extend_frm_ivas_fx( apa_state_t *ps, const Word16 frm_in[], Word16 frm_out[], Word16 Q_frm_in, UWord16 *l_frm_out );
161 :
162 : /*---------------------------------------------------------------------*
163 : * Public functions
164 : *---------------------------------------------------------------------*/
165 :
166 : /* Allocates memory for state struct and initializes elements. */
167 28 : ivas_error apa_init(
168 : apa_state_t **pps,
169 : const Word32 num_channels )
170 : {
171 28 : apa_state_t *ps = NULL;
172 :
173 : /* make sure pointer is valid */
174 28 : IF( !pps )
175 : {
176 0 : return 1;
177 : }
178 :
179 : /* allocate state struct */
180 28 : IF( ( ps = (apa_state_t *) malloc( sizeof( apa_state_t ) ) ) == NULL )
181 : {
182 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JBM\n" ) );
183 : }
184 :
185 28 : ps->num_channels = (UWord16) num_channels;
186 28 : move16();
187 28 : ps->buf_out_capacity = (UWord16) L_mult0( APA_BUF_PER_CHANNEL, (Word16) num_channels );
188 28 : move16();
189 :
190 28 : IF( ( ps->buf_out_fx = malloc( sizeof( Word16 ) * ps->buf_out_capacity ) ) == NULL )
191 : {
192 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for JBM\n" ) );
193 : }
194 28 : memset( ps->buf_out_fx, 0, ( sizeof( Word16 ) * ps->buf_out_capacity ) );
195 28 : ps->Q_buf_out = Q15;
196 : #ifdef FIX1998_APA_EXEC_SCALING
197 28 : ps->Q_a_out_init_old = Q15;
198 28 : move16();
199 : #endif
200 28 : move16();
201 :
202 28 : ps->evs_compat_mode = false;
203 28 : move16();
204 :
205 28 : apa_reset( ps );
206 28 : *pps = ps;
207 :
208 28 : return IVAS_ERR_OK;
209 : }
210 :
211 :
212 : /* Sets state variables to initial value. */
213 56 : void apa_reset(
214 : apa_state_t *ps )
215 : {
216 : /* init state struct */
217 56 : ps->signalScaleForCorrelation = 0;
218 56 : move16();
219 56 : ps->l_buf_out = 0;
220 56 : move16();
221 56 : ps->l_halfwin = 0;
222 56 : move16();
223 56 : ps->rate = 0;
224 56 : move16();
225 56 : ps->l_seg = 0;
226 56 : move16();
227 56 : ps->l_frm = 0;
228 56 : move16();
229 56 : ps->l_in_total = 0;
230 56 : move32();
231 56 : ps->diffSinceSetScale = 0;
232 56 : move32();
233 56 : ps->nFramesSinceSetScale = 0;
234 56 : move32();
235 56 : ps->scale = 100;
236 56 : move16();
237 56 : ps->p_min = 0;
238 56 : move16();
239 56 : ps->l_search = 0;
240 56 : move16();
241 56 : ps->wss = 1;
242 56 : move16();
243 56 : ps->css = 1;
244 56 : move16();
245 56 : ps->targetQuality_fx = 0;
246 56 : move32();
247 :
248 56 : ps->qualityred = 0;
249 56 : move16();
250 56 : ps->qualityrise = 0;
251 56 : move16();
252 56 : ps->last_pitch = 0;
253 56 : move16();
254 56 : ps->bad_frame_count = 0;
255 56 : move16();
256 56 : ps->good_frame_count = 0;
257 56 : move16();
258 :
259 56 : ps->l_ts = 1;
260 56 : move16();
261 56 : ps->l_r_buf = 0;
262 56 : move16();
263 56 : return;
264 : }
265 :
266 941 : UWord8 apa_reconfigure(
267 : apa_state_t *ps,
268 : UWord16 num_channels,
269 : UWord16 l_ts )
270 : {
271 :
272 : /* realloc buffer */
273 941 : ps->num_channels = (UWord16) num_channels;
274 941 : move16();
275 941 : ps->buf_out_capacity = (UWord16) L_mult0( APA_BUF_PER_CHANNEL, (Word16) num_channels );
276 941 : move16();
277 :
278 941 : free( ps->buf_out_fx );
279 941 : ps->buf_out_fx = (Word16 *) malloc( sizeof( Word16 ) * ps->buf_out_capacity );
280 941 : memset( ps->buf_out_fx, 0, ( sizeof( Word16 ) * ps->buf_out_capacity ) );
281 941 : ps->Q_buf_out = Q15;
282 : #ifdef FIX1998_APA_EXEC_SCALING
283 941 : ps->Q_a_out_init_old = Q15;
284 941 : move16();
285 : #endif
286 941 : move16();
287 941 : IF( !ps->buf_out_fx )
288 : {
289 0 : return 2;
290 : }
291 :
292 941 : ps->l_buf_out = 0;
293 941 : ps->l_in_total = 0;
294 941 : move16();
295 941 : move32();
296 941 : ps->l_ts = (UWord16) imult3216( l_ts, ps->num_channels );
297 941 : move16();
298 :
299 : /* set everything else dependent on the number of channels */
300 : /* set segment size */
301 : /* in the order of a pitch, set to 160 samples at 16 kHz */
302 : /* used for windowing and as the correlation length, i.e., */
303 : /* the size of the template segment. */
304 941 : ps->l_seg = (UWord16) imult3216( Mult_32_16( ps->rate, INV_100_Q15 ), (Word16) ps->num_channels ); // Q0
305 941 : move16();
306 :
307 : /* set frame size */
308 : /* set to 320 samples at 16 kHz */
309 941 : ps->l_frm = (UWord16) imult3216( Mult_32_16( ps->rate, INV_FRAME_PER_SEC_Q15 ), (Word16) ps->num_channels ); // Q0
310 941 : move16();
311 :
312 : /* set minimum pitch */
313 : /* set to 40 samples at 16 kHz */
314 : /* (defines min change in number of samples, i.e., abs(l_in-l_out) >= p_min) */
315 941 : ps->p_min = (UWord16) imult3216( Mult_32_16( ps->rate, INV_400_Q15 ), (Word16) ps->num_channels ); // Q0
316 941 : move16();
317 :
318 : /* set search length */
319 : /* must cover one pitch, set to 200 samples at 16 kHz */
320 : /* (the resulting maximum pitch is then p_min+l_search = 240 samples at 16 kHz) */
321 941 : ps->l_search = (UWord16) imult3216( Mult_32_16( ps->rate, INV_80_Q15 ), (Word16) ps->num_channels ); // Q0
322 941 : move16();
323 :
324 941 : return 0;
325 : }
326 :
327 : /* Sets the audio configuration. */
328 28 : bool apa_set_rate(
329 : apa_state_t *ps,
330 : const Word32 output_Fs )
331 : {
332 : /* make sure pointer is valid */
333 28 : IF( ps == NULL )
334 : {
335 0 : return 1;
336 : }
337 :
338 : /* check range */
339 28 : test();
340 28 : IF( ( LT_32( output_Fs, APA_MIN_RATE ) ) || ( GT_32( output_Fs, APA_MAX_RATE ) ) )
341 : {
342 0 : return 1;
343 : }
344 :
345 : /* reset state struct */
346 28 : apa_reset( ps );
347 :
348 : /* copy rate to state struct */
349 28 : ps->rate = (UWord16) output_Fs;
350 28 : move16();
351 :
352 28 : IF( GT_32( ps->num_channels, APA_MAX_NUM_CHANNELS ) )
353 : {
354 0 : return 1;
355 : }
356 :
357 : /*
358 : * several other parameters depend on the sampling rate
359 : * and are set below. Some "magic numbers" are used here
360 : * which are based on typical values of a "pitch" in
361 : * human voice. The pitch length is the period of the
362 : * base frequency and is usually assumed to be 40-240
363 : * samples at 16 kHz.
364 : */
365 :
366 : /* set segment size */
367 : /* in the order of a pitch, set to 160 samples at 16 kHz */
368 : /* used for windowing and as the correlation length, i.e., */
369 : /* the size of the template segment. */
370 28 : ps->l_seg = (UWord16) imult3216( Mult_32_16( ps->rate, INV_100_Q15 ), ps->num_channels ); // Q0
371 28 : move16();
372 :
373 : /* init Hann window */
374 : /* Note: l_win < APA_BUF_PER_CHANNEL is required */
375 : /* Length of Hann window should be independent of
376 : * number of channels - same window applied to all channels */
377 28 : ps->l_halfwin = (UWord16) Mult_32_16( ps->rate, INV_100_Q15 ); // Q0
378 28 : move16();
379 :
380 : /* set frame size */
381 : /* set to 320 samples at 16 kHz */
382 28 : ps->l_frm = (UWord16) imult3216( ( Mult_32_16( ps->rate, INV_FRAME_PER_SEC_Q15 ) ), ps->num_channels ); // Q0
383 28 : move16();
384 :
385 : /* set minimum pitch */
386 : /* set to 40 samples at 16 kHz */
387 : /* (defines min change in number of samples, i.e., abs(l_in-l_out) >= p_min) */
388 28 : ps->p_min = (UWord16) imult3216( ( Mult_32_16( ps->rate, INV_400_Q15 ) ), ps->num_channels ); // Q0
389 28 : move16();
390 :
391 : /* set search length */
392 : /* must cover one pitch, set to 200 samples at 16 kHz */
393 : /* (the resulting maximum pitch is then p_min+l_search = 240 samples at 16 kHz) */
394 28 : ps->l_search = (UWord16) imult3216( Mult_32_16( ps->rate, INV_80_Q15 ), ps->num_channels ); // Q0
395 28 : move16();
396 :
397 28 : ps->win_fx = pcmdsp_window_hann_640;
398 28 : ps->l_halfwin = 320;
399 28 : move16();
400 28 : ps->win_incrementor = 1;
401 28 : move16();
402 28 : IF( EQ_32( ps->rate, 48000 ) )
403 : {
404 16 : ps->win_fx = pcmdsp_window_hann_960;
405 16 : ps->l_halfwin = 480;
406 16 : move16();
407 : }
408 28 : IF( EQ_32( ps->rate, 24000 ) )
409 : {
410 0 : ps->win_fx = pcmdsp_window_hann_960;
411 0 : ps->l_halfwin = 480;
412 0 : move16();
413 0 : ps->win_incrementor = 2;
414 0 : move16();
415 : }
416 : /* sample rates 8k, 16k & 32k use a Hann window of length of 640,
417 : * where 8k and 16k subsample */
418 28 : if ( EQ_32( ps->rate, 16000 ) )
419 : {
420 3 : ps->win_incrementor = 2;
421 3 : move16();
422 : }
423 28 : if ( EQ_32( ps->rate, 8000 ) )
424 : {
425 0 : ps->win_incrementor = 4;
426 0 : move16();
427 : }
428 :
429 : /* set minimum pitch */
430 : /* set to 40 samples at 16 kHz */
431 : /* (defines min change in number of samples, i.e., abs(l_in-l_out) >= p_min) */
432 : /* before basop port was originally: ps->p_min = (ps->rate * ps->num_channels) / 400;
433 : * but for simplicity can be taken as l_seg / 4 */
434 28 : ps->signalScaleForCorrelation = getSignalScaleForCorrelation( ps->rate );
435 28 : move16();
436 28 : return 0;
437 : }
438 :
439 : /* Set scaling. */
440 19551 : bool apa_set_scale_fx(
441 : apa_state_t *ps,
442 : UWord16 scale )
443 : {
444 : /* make sure pointer is valid */
445 19551 : IF( ps == NULL )
446 : {
447 0 : return 1;
448 : }
449 :
450 : /* check range */
451 19551 : test();
452 19551 : IF( ( LT_32( (Word32) scale, APA_MIN_SCALE ) ) || GT_32( (Word32) scale, APA_MAX_SCALE ) )
453 : {
454 0 : return 1;
455 : }
456 :
457 : /* do nothing if same scale is set multiple times */
458 : /* (otherwise scale control is confused) */
459 19551 : IF( EQ_32( (Word32) ps->scale, (Word32) scale ) )
460 : {
461 19460 : return 0;
462 : }
463 :
464 : /* copy to state struct */
465 91 : ps->scale = scale;
466 91 : move16();
467 :
468 : /* reset scaling statistics */
469 91 : ps->diffSinceSetScale = 0;
470 91 : move32();
471 91 : ps->nFramesSinceSetScale = 0;
472 91 : move32();
473 :
474 91 : return 0;
475 : }
476 :
477 28 : bool apa_set_renderer_granularity(
478 : apa_state_t *ps,
479 : UWord16 l_ts )
480 : {
481 : /* make sure pointer is valid */
482 28 : IF( ps == NULL )
483 : {
484 0 : return 1;
485 : }
486 :
487 :
488 : /* copy to state struct */
489 28 : ps->l_ts = (UWord16) imult3216( l_ts, (Word16) ps->num_channels );
490 28 : move16();
491 28 : return 0;
492 : }
493 :
494 19551 : bool apa_set_renderer_residual_samples(
495 : apa_state_t *ps,
496 : UWord16 l_r_buf )
497 : {
498 : /* make sure pointer is valid */
499 19551 : IF( ps == NULL )
500 : {
501 0 : return 1;
502 : }
503 :
504 :
505 : /* copy to state struct */
506 19551 : ps->l_r_buf = (UWord16) imult3216( l_r_buf, (Word16) ps->num_channels );
507 19551 : move16();
508 19551 : return 0;
509 : }
510 :
511 :
512 0 : bool apa_set_evs_compat_mode(
513 : apa_state_t *ps,
514 : bool mode )
515 : {
516 : /* make sure pointer is valid */
517 0 : IF( ps == NULL )
518 : {
519 0 : return 1;
520 : }
521 :
522 0 : ps->evs_compat_mode = mode;
523 0 : move16();
524 :
525 0 : return 0;
526 : }
527 :
528 :
529 : /*
530 : ********************************************************************************
531 : *
532 : * Function : apa_set_quality
533 : * Tables : <none>
534 : * Compile Defines : <none>
535 : * Return : 0 on success, 1 on failure
536 : * Information : Set quality thresholds.
537 : *
538 : * quality is lower limit for minimum quality
539 : * Range is [-2;2] - where positive values allow
540 : * only pasting with same phase information
541 : * Negative values would yield cross phased pasting
542 : *
543 : * qualityred allows dynamic lowering of lower quality
544 : * bound - this gives better results for rhythmic signals
545 : * Range is [0;20], meaning 0.1 lowering*qualityred
546 : *
547 : * undocumented: qualityrise (same as qualityred - other
548 : * direction)
549 : *
550 : ********************************************************************************
551 : */
552 28 : bool apa_set_quality(
553 : apa_state_t *ps,
554 : Word32 quality, // Q16
555 : UWord16 qualityred,
556 : UWord16 qualityrise )
557 : {
558 28 : assert( ps != NULL );
559 28 : assert( -131072 /*-2.0f in Q16*/ <= quality && quality <= 203161 /*3.1f in Q16*/ );
560 28 : assert( qualityred > 0 && qualityred <= 20 );
561 28 : assert( qualityrise > 0 && qualityrise <= 20 );
562 :
563 28 : ps->targetQuality_fx = quality;
564 28 : move32();
565 28 : ps->qualityred = qualityred;
566 28 : move16();
567 28 : ps->qualityrise = qualityrise;
568 28 : move16();
569 28 : ps->bad_frame_count = 0;
570 28 : move16();
571 28 : ps->good_frame_count = 0;
572 28 : move16();
573 :
574 28 : return 0;
575 : }
576 :
577 : /*
578 : ********************************************************************************
579 : *
580 : * Function : apa_set_complexity_options
581 : * Tables : <none>
582 : * Compile Defines : <none>
583 : * Return : 0 on success, 1 on failure
584 : * Information : Set complexity options
585 : * Waveform subsampling computes the correlation function
586 : * for certain positions only
587 : * Correlation function subsampling computes the maxima
588 : * for certain positions only
589 : *
590 : ********************************************************************************
591 : */
592 28 : bool apa_set_complexity_options(
593 : apa_state_t *ps,
594 : UWord16 wss,
595 : UWord16 css )
596 : {
597 : /* make sure pointer is valid */
598 28 : IF( ps == NULL )
599 : {
600 0 : return 1;
601 : }
602 :
603 28 : test();
604 28 : IF( wss == 0 || GT_32( wss, 1000 ) )
605 : {
606 0 : return 1;
607 : }
608 :
609 28 : test();
610 28 : IF( css == 0 || GT_32( css, 1000 ) )
611 : {
612 0 : return 1;
613 : }
614 :
615 28 : ps->wss = wss;
616 28 : move16();
617 28 : ps->css = css;
618 28 : move16();
619 :
620 28 : return 0;
621 : }
622 :
623 :
624 : /*
625 : ********************************************************************************
626 : *
627 : * Function : apa_exit
628 : * Tables : <none>
629 : * Compile Defines : <none>
630 : * Return : 0 on success, 1 on failure
631 : * Information : The memory used for storing the state is freed.
632 : * The state struct pointer is set to NULL.
633 : *
634 : ********************************************************************************
635 : */
636 614 : bool apa_exit(
637 : apa_state_t **pps )
638 : {
639 : /* ignore NULL pointer input */
640 614 : IF( *pps == NULL )
641 : {
642 586 : return 0;
643 : }
644 :
645 : /* deallocate state struct members */
646 28 : free( ( *pps )->buf_out_fx );
647 :
648 : /* deallocate state struct */
649 28 : free( *pps );
650 :
651 : /* set pointer to NULL */
652 28 : *pps = NULL;
653 :
654 28 : return 0;
655 : }
656 :
657 : /*
658 : ********************************************************************************
659 : *
660 : * Function : apa_exec
661 : * Tables : <none>
662 : * Compile Defines : <none>
663 : * Return : 0 on success, 1 on failure
664 : * Information : Execute adaptive playout for audio, i.e., audio scaling.
665 : * Will take l_in input samples from a_in[] and
666 : * try to extend/shrink the amount of samples according
667 : * to the last scaling set by using apa_set_scale().
668 : * The actual amount of samples after scaling may vary
669 : * and is given in l_out. The scaled audio samples
670 : * are contained in a_out[]. Note that the scaling is
671 : * achieved only in average. The input buffer must be
672 : * filled with 20ms audio. The output buffer must be
673 : * allocated externally and must be at least of size
674 : * APA_BUF.
675 : * Scaling can only be performed when a sampling rate
676 : * is specified using apa_set_rate(). Otherwise,
677 : * an error is returned.
678 : *
679 : * The amount of scaling is achieved by controlling the
680 : * frequency of scaling. Note that the exact amount of
681 : * scaling is signal dependent and is an integer
682 : * multiple of a pitch. Hence, when we want to achieve
683 : * a scaling of e.g. 110% then the APA module will typically
684 : * forward several frames without any modification and
685 : * then scale one frame by a higher amount, e.g. 143%.
686 : *
687 : ********************************************************************************
688 : */
689 0 : UWord8 apa_exec_fx(
690 : apa_state_t *ps, /* i/o: state struct */
691 : const Word16 a_in[], /* i : input samples Q0 */
692 : UWord16 l_in, /* i : number of input samples */
693 : UWord16 maxScaling, /* i : allowed number of inserted/removed samples */
694 : Word16 a_out[], /* o : output samples Q0*/
695 : UWord16 *l_out /* o : number of output samples */
696 : )
697 : {
698 : UWord16 i;
699 : Word16 frm_in[APA_BUF]; /* TODO(mcjbm): this buffer could be smaller - always allocates space for 16 channels */
700 : UWord16 l_frm_out;
701 : Word16 l_rem;
702 : Word32 dl_scaled, dl_copied, l_frm_out_target;
703 : Word32 expScaling, actScaling;
704 : UWord32 statsResetThreshold, statsResetShift;
705 :
706 0 : statsResetThreshold = 1637;
707 0 : move32();
708 0 : statsResetShift = 2;
709 0 : move32();
710 :
711 : /* Convert max_scaling from "per channel" to total */
712 0 : maxScaling = (UWord16) imult3216( maxScaling, ps->num_channels );
713 :
714 : /* make sure no invalid output is used */
715 0 : *l_out = 0;
716 0 : move16();
717 0 : l_frm_out = 0;
718 0 : move16();
719 :
720 : /* make sure pointer is valid */
721 0 : IF( ps == NULL )
722 : {
723 0 : return 1;
724 : }
725 : /* check available rate */
726 0 : IF( ps->rate == 0 )
727 : {
728 0 : return 2;
729 : }
730 : /* check size of input */
731 0 : IF( NE_32( l_in, ps->l_frm ) )
732 : {
733 0 : return 3;
734 : }
735 :
736 : /* get target length */
737 0 : test();
738 0 : test();
739 0 : IF( EQ_16( ps->l_frm, 480 ) || EQ_16( ps->l_frm, 960 ) || EQ_16( ps->l_frm, 1920 ) )
740 : {
741 : /* decomposite ps->l_frm into 15<<i, e.g. 480=15<<5 */
742 0 : i = sub( 15 - 4, norm_s( ps->l_frm ) );
743 : /* this only works for 20ms framing */
744 0 : assert( ps->l_frm == shl( shr( ps->l_frm, i ), i ) );
745 : // assert( i_mult2( sub( ps->scale, 100 ), add( ps->nFramesSinceSetScale, 1 ) ) == ( ps->scale - 100 ) * ( ps->nFramesSinceSetScale + 1 ) );
746 0 : expScaling = L_shr_r( L_mult0( i_mult2( sub( ps->scale, 100 ), add( (Word16) ps->nFramesSinceSetScale, 1 ) ), 19661 /*15*(1<<2)/100.0 Q15*/ ), sub( 15 + 2, i ) );
747 : }
748 : ELSE
749 : {
750 : /* decomposite ps->l_frm into 5<<i, e.g. 320=5<<6 */
751 0 : i = sub( 15 - 3, norm_s( ps->l_frm ) );
752 : /* this only works for 20ms framing */
753 0 : assert( ps->l_frm == shl( shr( ps->l_frm, i ), i ) );
754 : // assert( i_mult2( sub( ps->scale, 100 ), add( ps->nFramesSinceSetScale, 1 ) ) == ( ps->scale - 100 ) * ( ps->nFramesSinceSetScale + 1 ) );
755 0 : expScaling = L_shr_r( L_mult0( i_mult2( sub( ps->scale, 100 ), add( (Word16) ps->nFramesSinceSetScale, 1 ) ), 13107 /*5*(1<<3)/100.0 Q15*/ ), sub( 15 + 3, i ) );
756 : }
757 0 : actScaling = L_sub( ps->diffSinceSetScale, ps->l_frm );
758 0 : l_frm_out_target = L_sub( expScaling, actScaling );
759 :
760 : /* Wait until we have l_frm outputs samples */
761 : /* (required to search for correlation in the past). */
762 : /* If we don't have enough samples, simply copy input to output */
763 0 : IF( LT_32( ps->l_buf_out, ps->l_frm ) )
764 : {
765 0 : FOR( i = 0; i < ps->l_frm; i++ )
766 : {
767 0 : a_out[i] = a_in[i];
768 0 : move16();
769 : }
770 0 : l_frm_out = ps->l_frm;
771 0 : move16();
772 : }
773 : ELSE
774 : {
775 0 : Word16 *buf_out_ptr = &( ps->buf_out_fx[ps->l_buf_out - ps->l_frm] );
776 0 : Word16 *frm_in_ptr = &( frm_in[ps->l_frm] );
777 :
778 : /* fill input frame */
779 : /* 1st input frame: previous output samples */
780 0 : FOR( i = 0; i < ps->l_frm; i++ )
781 : {
782 0 : frm_in[i] = buf_out_ptr[i];
783 0 : move16();
784 : }
785 : /* 2nd input frame: new input samples */
786 0 : FOR( i = 0; i < ps->l_frm; i++ )
787 : {
788 0 : frm_in_ptr[i] = a_in[i];
789 0 : move16();
790 : }
791 : /* no scaling */
792 0 : IF( EQ_32( ps->scale, 100 ) )
793 : {
794 0 : copy_frm_fx( ps, frm_in, a_out, &l_frm_out );
795 : }
796 : /* shrink */
797 0 : ELSE IF( LT_32( ps->scale, 100 ) )
798 : {
799 0 : shrink_frm_fx( ps, frm_in, maxScaling, a_out, &l_frm_out );
800 : }
801 : /* extend */
802 : ELSE
803 : {
804 0 : extend_frm_fx( ps, frm_in, a_out, &l_frm_out );
805 : }
806 : /* control the amount/frequency of scaling */
807 0 : IF( NE_32( l_frm_out, ps->l_frm ) )
808 : {
809 0 : test();
810 0 : IF( maxScaling != 0 &&
811 : GT_32( abs_s( extract_l( L_sub( ps->l_frm, l_frm_out ) ) ), maxScaling ) )
812 : {
813 : /* maxScaling exceeded -> discard scaled frame */
814 0 : copy_frm_fx( ps, frm_in, a_out, &l_frm_out );
815 : }
816 0 : ELSE IF( GT_32( L_abs( l_frm_out_target ), ps->l_frm ) ) /* ignore small difference */
817 : {
818 0 : dl_copied = L_sub( l_frm_out_target, ps->l_frm );
819 0 : dl_scaled = L_sub( l_frm_out_target, l_frm_out );
820 : /* discard scaled frame if copied frame is closer to target length */
821 0 : IF( LT_32( L_abs( dl_copied ), L_abs( dl_scaled ) ) )
822 : {
823 0 : copy_frm_fx( ps, frm_in, a_out, &l_frm_out );
824 : }
825 : }
826 : }
827 : }
828 :
829 : /* copy output to internal buffer */
830 : /* avoid buffer overflow: */
831 : /* discard old samples; always keep at least most recent l_frm samples */
832 0 : IF( GT_32( L_add( ps->l_buf_out, l_frm_out ), ps->buf_out_capacity ) )
833 : {
834 0 : Word16 *buf_out_ptr1 = ps->buf_out_fx;
835 : Word16 *buf_out_ptr2;
836 :
837 0 : l_rem = extract_l( L_sub( ps->l_frm, l_frm_out ) );
838 0 : if ( l_rem < 0 )
839 : {
840 0 : l_rem = 0;
841 0 : move16();
842 : }
843 0 : buf_out_ptr2 = &( ps->buf_out_fx[ps->l_buf_out - l_rem] );
844 0 : FOR( i = 0; i < l_rem; i++ )
845 : {
846 0 : buf_out_ptr1[i] = buf_out_ptr2[i];
847 0 : move16();
848 : }
849 0 : ps->l_buf_out = l_rem;
850 0 : move16();
851 : }
852 : /* append new output samples */
853 0 : IF( GT_32( L_add( ps->l_buf_out, l_frm_out ), ps->buf_out_capacity ) )
854 : {
855 0 : return 5;
856 : }
857 : {
858 0 : Word16 *buf_out_ptr = &( ps->buf_out_fx[ps->l_buf_out] );
859 0 : FOR( i = 0; i < l_frm_out; i++ )
860 : {
861 0 : buf_out_ptr[i] = a_out[i];
862 0 : move16();
863 : }
864 : }
865 0 : ps->l_buf_out = (UWord16) L_add( ps->l_buf_out, l_frm_out );
866 0 : move16();
867 :
868 0 : *l_out = l_frm_out;
869 0 : move16();
870 : /* update time */
871 0 : ps->l_in_total = UL_addNsD( ps->l_in_total, ps->l_frm );
872 0 : move32();
873 :
874 0 : test();
875 0 : IF( LT_32( L_abs( ps->diffSinceSetScale ), L_sub( 0x7FFFFF, L_sub( l_frm_out, ps->l_frm ) ) ) &&
876 : LT_64( ps->nFramesSinceSetScale, statsResetThreshold ) )
877 : {
878 0 : ps->diffSinceSetScale = L_add( ps->diffSinceSetScale, L_sub( l_frm_out, ps->l_frm ) );
879 0 : move32();
880 0 : ps->nFramesSinceSetScale = UL_addNsD( ps->nFramesSinceSetScale, 1 );
881 0 : move32();
882 : }
883 : ELSE /* scale statistics down to avoid overflow */
884 : {
885 0 : ps->diffSinceSetScale = L_shr( ps->diffSinceSetScale, (Word16) statsResetShift );
886 0 : move32();
887 0 : ps->nFramesSinceSetScale = UL_lshr( ps->nFramesSinceSetScale, (Word16) statsResetShift );
888 0 : move32();
889 : }
890 :
891 0 : return 0;
892 : }
893 :
894 19551 : UWord8 apa_exec_ivas_fx(
895 : apa_state_t *ps, /* i/o: state struct */
896 : const Word32 a_in[], /* i : input samples Q(-1) */
897 : UWord16 l_in, /* i : number of input samples */
898 : UWord16 maxScaling, /* i : allowed number of inserted/removed samples */
899 : Word32 a_out[], /* o : output samples Q(-1) */
900 : UWord16 *l_out /* o : number of output samples */
901 : )
902 : {
903 : UWord16 i;
904 : Word16 frm_in[APA_BUF]; /* TODO(mcjbm): this buffer could be smaller - always allocates space for 16 channels */
905 : UWord16 l_frm_out;
906 : Word16 l_rem;
907 : Word32 dl_scaled, dl_copied, l_frm_out_target;
908 : Word32 expScaling, actScaling;
909 : UWord32 statsResetThreshold, statsResetShift;
910 : Word16 Q_a_out;
911 : #ifdef FIX1998_APA_EXEC_SCALING
912 : Word16 Q_a_out_init_old;
913 : #endif
914 :
915 19551 : Q_a_out = add( getScaleFactor32_copy( a_in, L_mult0( ps->num_channels, APA_BUF_PER_CHANNEL ) ), Q11 - Q16 - Q1 );
916 : #ifdef FIX1998_APA_EXEC_SCALING
917 19551 : Q_a_out_init_old = Q_a_out; /* store the possible scaling of a_in, to be re-used in the next frame */
918 19551 : move16();
919 : #endif
920 19551 : statsResetThreshold = 1637;
921 19551 : move32();
922 19551 : statsResetShift = 2;
923 19551 : move32();
924 :
925 : /* Convert max_scaling from "per channel" to total */
926 19551 : maxScaling = (UWord16) imult3216( maxScaling, ps->num_channels );
927 :
928 : /* make sure no invalid output is used */
929 19551 : *l_out = 0;
930 19551 : move16();
931 19551 : l_frm_out = 0;
932 19551 : move16();
933 :
934 : /* make sure pointer is valid */
935 19551 : IF( ps == NULL )
936 : {
937 0 : return 1;
938 : }
939 : /* check available rate */
940 19551 : IF( ps->rate == 0 )
941 : {
942 0 : return 2;
943 : }
944 : /* check size of input */
945 19551 : IF( NE_32( l_in, ps->l_frm ) )
946 : {
947 0 : return 3;
948 : }
949 :
950 : /* get target length */
951 19551 : IF( GT_32( ps->scale, 100 ) )
952 : {
953 : // expScaling = (int32_t) ( ( ps->l_frm * ( ps->scale - 100.0f ) / 100.0f ) * ( ps->nFramesSinceSetScale + 1 ) + 0.5f );
954 436 : expScaling = W_extract_l( W_shr( W_add( W_mult_32_32( Mpy_32_16_1( imult3216( ps->l_frm, sub( ps->scale, 100 ) ), 328 /* 1 / 100.0f in Q15 */ ), UL_addNsD( ps->nFramesSinceSetScale, 1 ) ), 1 ), 1 ) );
955 : }
956 19115 : ELSE IF( LT_32( ps->scale, 100 ) )
957 : {
958 141 : expScaling = L_negate( W_extract_l( W_shr( W_abs( W_sub( W_mult_32_32( Mpy_32_16_1( imult3216( ps->l_frm, sub( ps->scale, 100 ) ), 328 /* 1 / 100.0f in Q15 */ ), UL_addNsD( ps->nFramesSinceSetScale, 1 ) ), 1 ) ), 1 ) ) );
959 : }
960 : ELSE
961 : {
962 18974 : expScaling = 0;
963 18974 : move32();
964 : }
965 19551 : actScaling = L_sub( ps->diffSinceSetScale, ps->l_frm );
966 19551 : l_frm_out_target = L_sub( expScaling, actScaling );
967 :
968 : /* Wait until we have l_frm outputs samples */
969 : /* (required to search for correlation in the past). */
970 : /* If we don't have enough samples, simply copy input to output */
971 19551 : IF( LT_32( ps->l_buf_out, ps->l_frm ) )
972 : {
973 2296329 : FOR( i = 0; i < ps->l_frm; i++ )
974 : {
975 2295360 : a_out[i] = a_in[i];
976 2295360 : move32();
977 : }
978 969 : l_frm_out = ps->l_frm;
979 969 : move16();
980 : }
981 : ELSE
982 : {
983 : Word16 a_tmp[APA_BUF];
984 18582 : Word16 *buf_out_ptr = &( ps->buf_out_fx[ps->l_buf_out - ps->l_frm] );
985 :
986 : #ifdef FIX1998_APA_EXEC_SCALING
987 : /*
988 : don't compare against actual scaling in ps->Q_buf_out, but possible scaling in ps->Q_a_out_init_old; otherwise we are constantly reducing the scaling over time, leading to precision issues
989 : alternative approach: determine scaling of ps->buf_out_fx, but this is costly due to the sheer amount of samples stored there...
990 : */
991 18582 : Q_a_out = s_min( Q_a_out, ps->Q_a_out_init_old );
992 : #else
993 : Q_a_out = s_min( Q_a_out, ps->Q_buf_out );
994 : #endif
995 18582 : Scale_sig( ps->buf_out_fx, ps->buf_out_capacity, sub( Q_a_out, ps->Q_buf_out ) ); // Q_buf_out -> Q_a_out
996 18582 : IF( EQ_32( ps->scale, 100 ) )
997 : {
998 118293950 : FOR( i = 0; i < ps->num_channels * APA_BUF_PER_CHANNEL; i++ )
999 : {
1000 118275840 : a_out[i] = a_in[i]; // Q11
1001 118275840 : move32();
1002 : }
1003 18110 : l_frm_out = ps->l_frm;
1004 18110 : move16();
1005 : }
1006 : ELSE
1007 : {
1008 472 : Word16 *frm_in_ptr = &( frm_in[ps->l_frm] );
1009 :
1010 3151192 : FOR( i = 0; i < ps->num_channels * APA_BUF_PER_CHANNEL; i++ )
1011 : {
1012 3150720 : a_tmp[i] = extract_h( L_shl( a_in[i], add( Q_a_out, Q5 ) ) ); // Q_a_out
1013 3150720 : move16();
1014 : }
1015 : /* fill input frame */
1016 : /* 1st input frame: previous output samples */
1017 791832 : FOR( i = 0; i < ps->l_frm; i++ )
1018 : {
1019 791360 : frm_in[i] = buf_out_ptr[i];
1020 791360 : move16();
1021 : }
1022 : /* 2nd input frame: new input samples */
1023 791832 : FOR( i = 0; i < ps->l_frm; i++ )
1024 : {
1025 791360 : frm_in_ptr[i] = a_tmp[i];
1026 791360 : move16();
1027 : }
1028 : /* shrink */
1029 472 : IF( LT_32( ps->scale, 100 ) )
1030 : {
1031 139 : shrink_frm_ivas_fx( ps, frm_in, maxScaling, a_tmp, Q_a_out, &l_frm_out );
1032 : }
1033 : /* extend */
1034 : ELSE
1035 : {
1036 333 : extend_frm_ivas_fx( ps, frm_in, a_tmp, Q_a_out, &l_frm_out );
1037 : }
1038 : /* control the amount/frequency of scaling */
1039 472 : IF( NE_32( l_frm_out, ps->l_frm ) )
1040 : {
1041 86 : test();
1042 86 : IF( ( maxScaling != 0 ) &&
1043 : GT_32( abs_s( extract_l( L_sub( ps->l_frm, l_frm_out ) ) ), maxScaling ) )
1044 : {
1045 : /* maxScaling exceeded -> discard scaled frame */
1046 40 : copy_frm_fx( ps, frm_in, a_tmp, &l_frm_out );
1047 : }
1048 46 : ELSE IF( GT_32( L_abs( l_frm_out_target ), ps->l_frm ) ) /* ignore small difference */
1049 : {
1050 41 : dl_copied = L_sub( l_frm_out_target, ps->l_frm );
1051 41 : dl_scaled = L_sub( l_frm_out_target, l_frm_out );
1052 : /* discard scaled frame if copied frame is closer to target length */
1053 41 : IF( LT_32( L_abs( dl_copied ), L_abs( dl_scaled ) ) )
1054 : {
1055 0 : copy_frm_fx( ps, frm_in, a_tmp, &l_frm_out );
1056 : }
1057 : }
1058 : }
1059 :
1060 3151192 : FOR( i = 0; i < ps->num_channels * APA_BUF_PER_CHANNEL; i++ )
1061 : {
1062 3150720 : a_out[i] = L_shl( a_tmp[i], sub( Q11, Q_a_out ) ); // Q0 -> Q11
1063 3150720 : move32();
1064 : }
1065 : }
1066 : }
1067 :
1068 : /* copy output to internal buffer */
1069 : /* avoid buffer overflow: */
1070 : /* discard old samples; always keep at least most recent l_frm samples */
1071 19551 : IF( GT_32( L_add( ps->l_buf_out, l_frm_out ), ps->buf_out_capacity ) )
1072 : {
1073 4763 : Word16 *buf_out_ptr1 = ps->buf_out_fx;
1074 : Word16 *buf_out_ptr2;
1075 :
1076 4763 : l_rem = extract_l( L_sub( ps->l_frm, l_frm_out ) );
1077 4763 : if ( l_rem < 0 )
1078 : {
1079 21 : l_rem = 0;
1080 21 : move16();
1081 : }
1082 4763 : buf_out_ptr2 = &( ps->buf_out_fx[ps->l_buf_out - l_rem] );
1083 5339 : FOR( i = 0; i < l_rem; i++ )
1084 : {
1085 576 : buf_out_ptr1[i] = buf_out_ptr2[i];
1086 576 : move16();
1087 : }
1088 4763 : ps->l_buf_out = l_rem;
1089 4763 : move16();
1090 : }
1091 : /* append new output samples */
1092 19551 : IF( GT_32( L_add( ps->l_buf_out, l_frm_out ), ps->buf_out_capacity ) )
1093 : {
1094 0 : return 5;
1095 : }
1096 : {
1097 19551 : Word16 *buf_out_ptr = &( ps->buf_out_fx[ps->l_buf_out] );
1098 35850720 : FOR( i = 0; i < l_frm_out; i++ )
1099 : {
1100 35831169 : buf_out_ptr[i] = extract_h( L_shl( a_out[i], add( Q_a_out, Q16 - Q11 ) ) ); // Q_a_out
1101 35831169 : move16();
1102 : }
1103 19551 : ps->Q_buf_out = Q_a_out;
1104 19551 : move16();
1105 : }
1106 19551 : ps->l_buf_out = (UWord16) L_add( ps->l_buf_out, l_frm_out );
1107 19551 : move16();
1108 : #ifdef FIX1998_APA_EXEC_SCALING
1109 19551 : ps->Q_a_out_init_old = Q_a_out_init_old;
1110 19551 : move16();
1111 : #endif
1112 :
1113 19551 : *l_out = l_frm_out;
1114 19551 : move16();
1115 : /* update time */
1116 19551 : ps->l_in_total = UL_addNsD( ps->l_in_total, ps->l_frm );
1117 19551 : move32();
1118 :
1119 :
1120 19551 : test();
1121 19551 : IF( LT_32( L_abs( ps->diffSinceSetScale ), L_sub( 0x7FFFFF, L_sub( l_frm_out, ps->l_frm ) ) ) &&
1122 : LT_64( ps->nFramesSinceSetScale, statsResetThreshold ) )
1123 : {
1124 19551 : ps->diffSinceSetScale = L_add( ps->diffSinceSetScale, L_sub( l_frm_out, ps->l_frm ) );
1125 19551 : move32();
1126 19551 : ps->nFramesSinceSetScale = UL_addNsD( ps->nFramesSinceSetScale, 1 );
1127 19551 : move32();
1128 : }
1129 : ELSE /* scale statistics down to avoid overflow */
1130 : {
1131 0 : ps->diffSinceSetScale = L_shr( ps->diffSinceSetScale, (Word16) statsResetShift );
1132 0 : move32();
1133 0 : ps->nFramesSinceSetScale = UL_lshr( ps->nFramesSinceSetScale, (Word16) statsResetShift );
1134 0 : move32();
1135 : }
1136 :
1137 19551 : return 0;
1138 : }
1139 :
1140 :
1141 : /*---------------------------------------------------------------------*
1142 : * Local functions
1143 : *---------------------------------------------------------------------*/
1144 :
1145 : /*
1146 : ********************************************************************************
1147 : *
1148 : * Function : get_scaling_quality
1149 : * Tables : <none>
1150 : * Compile Defines : <none>
1151 : * Return : 0 on success, 1 on failure
1152 : * Information : Uses pitch, half pitch, three halves and double pitch
1153 : * to evaluate the quality of the scaled frame by checking
1154 : * periodicity.
1155 : * Silence can be detected as additional feature. This must
1156 : * be set in global struct apa_state.
1157 : *
1158 : * If search length is very narrow then use fewer points
1159 : * to evaluate periodicity and silence.
1160 : *
1161 : * Computationally not very efficient by using normalized
1162 : * cross-correlation: Using sqrt() for energy calculation
1163 : * adds complexity.
1164 : *
1165 : * 03-AUG-04 S.Doehla initial version
1166 : *
1167 : ********************************************************************************
1168 : */
1169 472 : static void get_scaling_quality_fx( const apa_state_t *ps,
1170 : const Word16 *signal,
1171 : Word16 s_len,
1172 : Word16 offset,
1173 : Word16 corr_len,
1174 : Word16 pitch,
1175 : Word16 *energydBQ8, // Q8
1176 : Word32 *qualityQ16 // Q16
1177 : )
1178 : {
1179 : Word32 energy, maxEnergy;
1180 : Word32 qualityOfMaxEnergy; /* we measure the quality for all channels and select the one with highest energy */
1181 : Word16 half_pitch_cn;
1182 : Word16 pitch_cn;
1183 : Word16 three_halves_pitch_cn;
1184 : Word16 double_pitch_cn;
1185 : Word32 pitch_energy;
1186 : Word32 half_pitch_energy;
1187 : Word32 three_halves_pitch_energy;
1188 : Word32 double_pitch_energy;
1189 : Word16 i;
1190 :
1191 :
1192 472 : maxEnergy = 0;
1193 472 : qualityOfMaxEnergy = 0;
1194 472 : move32();
1195 472 : move32();
1196 :
1197 1566 : FOR( i = 0; i < ps->num_channels; i++ )
1198 : {
1199 1094 : offset = 0;
1200 1094 : move16();
1201 :
1202 1094 : pitch_cn = normalized_cross_correlation_self_fx( signal, add( pitch, offset ), offset, corr_len,
1203 1094 : shl( ps->num_channels, 1 ), &pitch_energy );
1204 1094 : IF( pitch_cn > 0 )
1205 : {
1206 : /* calculate correlation for double pitch */
1207 766 : IF( LE_16( add( add( shl( pitch, 1 ), offset ), corr_len ), s_len ) )
1208 : {
1209 635 : double_pitch_cn = normalized_cross_correlation_self_fx( signal, add( shl( pitch, 1 ), offset ),
1210 635 : offset, corr_len, shl( ps->num_channels, 1 ), &double_pitch_energy );
1211 : }
1212 : ELSE
1213 : {
1214 131 : double_pitch_cn = pitch_cn;
1215 131 : move16();
1216 131 : double_pitch_energy = L_add( pitch_energy, 0 );
1217 : }
1218 : /* calculate correlation for three/half pitch */
1219 766 : IF( LE_16( add( add( shr( i_mult2( pitch, 3 ), 1 ), offset ), corr_len ), s_len ) )
1220 : {
1221 669 : three_halves_pitch_cn = normalized_cross_correlation_self_fx( signal, add( shr( i_mult2( pitch, 3 ), 1 ), offset ), offset, corr_len, shl( ps->num_channels, 1 ), &three_halves_pitch_energy );
1222 : }
1223 : ELSE
1224 : {
1225 97 : three_halves_pitch_cn = pitch_cn;
1226 97 : move16();
1227 97 : three_halves_pitch_energy = L_add( pitch_energy, 0 );
1228 : }
1229 : /* calculate correlation for half pitch */
1230 766 : IF( LE_16( add( add( shr( pitch, 1 ), offset ), corr_len ), s_len ) )
1231 : {
1232 766 : half_pitch_cn = normalized_cross_correlation_self_fx( signal, add( shr( pitch, 1 ), offset ),
1233 766 : offset, corr_len, shl( ps->num_channels, 1 ), &half_pitch_energy );
1234 : }
1235 : ELSE
1236 : {
1237 0 : half_pitch_cn = pitch_cn;
1238 0 : move16();
1239 0 : half_pitch_energy = L_add( pitch_energy, 0 );
1240 : }
1241 :
1242 : /* combine correlation results: Q15.16 */
1243 766 : *qualityQ16 = L_shr( L_mac0( L_mult0( half_pitch_cn, three_halves_pitch_cn ),
1244 : pitch_cn, double_pitch_cn ),
1245 : 14 );
1246 766 : move32();
1247 : BASOP_SATURATE_WARNING_OFF_EVS
1248 766 : energy = L_add( L_add( L_add( pitch_energy, half_pitch_energy ), three_halves_pitch_energy ), double_pitch_energy );
1249 : BASOP_SATURATE_WARNING_ON_EVS
1250 : }
1251 : ELSE
1252 : {
1253 328 : *qualityQ16 = L_shl( L_deposit_l( pitch_cn ), 1 ); /* value is negative, thus pass it */
1254 328 : move32();
1255 328 : energy = L_add( pitch_energy, 0 );
1256 : }
1257 :
1258 : /* update the quality by the quality of the signal with the highest energy */
1259 1094 : IF( GT_32( energy, maxEnergy ) )
1260 : {
1261 699 : qualityOfMaxEnergy = L_add( *qualityQ16, 0 );
1262 699 : maxEnergy = L_add( energy, 0 );
1263 : }
1264 :
1265 : /* go to next channel */
1266 1094 : ++signal;
1267 : }
1268 472 : *qualityQ16 = qualityOfMaxEnergy;
1269 472 : move32();
1270 :
1271 : /* increase calculated quality of signals with low energy */
1272 472 : *energydBQ8 = apa_corrEnergy2dB_fx( maxEnergy, shl( ps->signalScaleForCorrelation, 1 ), corr_len );
1273 472 : *qualityQ16 = L_add( *qualityQ16, L_shl( L_deposit_l( apa_getQualityIncreaseForLowEnergy_fx( *energydBQ8 ) ), 8 ) );
1274 472 : move16();
1275 472 : move32();
1276 472 : }
1277 :
1278 : /* Converts the correlation energy to dB. */
1279 472 : Word16 apa_corrEnergy2dB_fx( Word32 energy, Word16 energyExp, Word16 corr_len )
1280 : {
1281 :
1282 : Word16 result, tmpScale;
1283 :
1284 : /* normalise before dividing */
1285 472 : tmpScale = norm_l( energy );
1286 472 : energy = L_shl( energy, tmpScale );
1287 472 : energyExp = sub( energyExp, tmpScale );
1288 :
1289 : /* divide energy by corr_len */
1290 472 : result = BASOP_Util_Divide3216_Scale( energy, corr_len, &tmpScale );
1291 472 : energyExp = add( energyExp, tmpScale );
1292 :
1293 472 : result = BASOP_Util_lin2dB( L_deposit_l( result ), energyExp, 1 );
1294 472 : return result;
1295 : }
1296 :
1297 : /* Increases the calculated quality of signals with low energy. */
1298 472 : Word16 apa_getQualityIncreaseForLowEnergy_fx( Word16 energydBQ8 )
1299 : {
1300 : Word16 qualIncreaseMinEnergy, qualIncreaseMaxEnergy, qualIncForLowEnergy; /* Q8 */
1301 :
1302 472 : qualIncreaseMinEnergy = -65 * ( 1 << 8 ); // Q8
1303 472 : move16();
1304 472 : qualIncreaseMaxEnergy = -40 * ( 1 << 8 ); // Q8
1305 472 : move16();
1306 472 : qualIncForLowEnergy = 0;
1307 472 : move16();
1308 :
1309 : /* increase calculated quality of signals with low energy */
1310 472 : IF( LT_16( energydBQ8, qualIncreaseMaxEnergy ) )
1311 : {
1312 124 : qualIncForLowEnergy = energydBQ8;
1313 124 : move16();
1314 124 : if ( LT_16( qualIncForLowEnergy, qualIncreaseMinEnergy ) )
1315 : {
1316 0 : qualIncForLowEnergy = qualIncreaseMinEnergy;
1317 0 : move16();
1318 : }
1319 124 : if ( GT_16( qualIncForLowEnergy, qualIncreaseMaxEnergy ) )
1320 : {
1321 0 : qualIncForLowEnergy = qualIncreaseMaxEnergy;
1322 0 : move16();
1323 : }
1324 : /* -50: (-50 - -40) / (-65 - -40) * 20
1325 : * = -10 / -25 * 20
1326 : */
1327 124 : qualIncForLowEnergy = divide1616( sub( qualIncForLowEnergy, qualIncreaseMaxEnergy ),
1328 124 : sub( qualIncreaseMinEnergy, qualIncreaseMaxEnergy ) );
1329 : /* apply factor 2 and scale back to Q8 */
1330 124 : assert( qualIncForLowEnergy >= 0 );
1331 124 : qualIncForLowEnergy = shr( qualIncForLowEnergy, 7 - 1 );
1332 124 : assert( qualIncForLowEnergy >= 0 && qualIncForLowEnergy <= ( 2 << 8 ) );
1333 : }
1334 472 : return qualIncForLowEnergy;
1335 : }
1336 :
1337 :
1338 : /*
1339 : ********************************************************************************
1340 : *
1341 : * Function : logarithmic_search
1342 : * Tables : <none>
1343 : * Compile Defines : <none>
1344 : * Return : 0 on success, 1 on failure
1345 : * Information : Search for best match of a template segment using
1346 : * hierarchical search method:
1347 : * Parameter css is used for sampling every css'd correlation
1348 : * value. The area around the best match so far is used for
1349 : * further correlation value with half css-value until css=1.
1350 : * Search area length is always half previous search length.
1351 : * Parameter wss is passed to the correlation computation
1352 : * If the search area passes the boundaries, the search
1353 : * window is reduced so that it's entirely inside the
1354 : * boundaries.
1355 : *
1356 : ********************************************************************************
1357 : */
1358 472 : static Word8 logarithmic_search_fx( const apa_state_t *ps,
1359 : const Word16 *signal,
1360 : Word16 s_start,
1361 : Word16 inlen,
1362 : Word16 offset,
1363 : Word16 fixed_pos,
1364 : Word16 corr_len,
1365 : Word16 wss,
1366 : Word16 css,
1367 : Word16 *synchpos )
1368 : {
1369 : Word16 i;
1370 : Word32 coeff;
1371 : Word32 coeff_max;
1372 : Word16 s_start_old, s_len_old;
1373 :
1374 : DO
1375 : {
1376 472 : coeff_max = 0x80000000; /* will always be overwritten with result of first correlation */
1377 472 : move32();
1378 :
1379 83752 : FOR( i = s_start; i < s_start + inlen; i += css * ps->num_channels )
1380 : {
1381 83280 : test();
1382 83280 : IF( EQ_16( wss, 1 ) && EQ_16( ps->num_channels, 1 ) )
1383 : {
1384 0 : coeff = cross_correlation_self_fx( signal, add( i, offset ), add( fixed_pos, offset ), corr_len );
1385 : }
1386 : ELSE
1387 : {
1388 83280 : coeff = cross_correlation_subsampled_self_fx( signal, add( i, offset ), add( fixed_pos, offset ),
1389 83280 : corr_len, i_mult2( wss, ps->num_channels ) );
1390 : }
1391 :
1392 : /* update max corr */
1393 83280 : IF( LT_16( ps->scale, 100 ) )
1394 : {
1395 : /* shrinking: prefer greater synchpos for equal coeff */
1396 : BASOP_SATURATE_WARNING_OFF_EVS;
1397 16680 : IF( GE_32( coeff, coeff_max ) )
1398 : {
1399 1773 : coeff_max = L_add( coeff, 0 );
1400 1773 : *synchpos = i;
1401 1773 : move16();
1402 : }
1403 : BASOP_SATURATE_WARNING_ON_EVS;
1404 : }
1405 : ELSE
1406 : {
1407 : /* extending: prefer smaller synchpos for equal coeff */
1408 : BASOP_SATURATE_WARNING_OFF_EVS;
1409 66600 : IF( GT_32( coeff, coeff_max ) )
1410 : {
1411 6772 : coeff_max = L_add( coeff, 0 );
1412 6772 : *synchpos = i;
1413 6772 : move16();
1414 : }
1415 : BASOP_SATURATE_WARNING_ON_EVS;
1416 : }
1417 : }
1418 : /* backup old search range */
1419 472 : s_start_old = s_start;
1420 472 : move16();
1421 472 : s_len_old = inlen;
1422 472 : move16();
1423 :
1424 472 : css = shr( css, 1 );
1425 472 : inlen = shr( inlen, 1 );
1426 472 : s_start_old = s_start;
1427 472 : move16();
1428 472 : s_start = sub( *synchpos, shr( inlen, 1 ) );
1429 :
1430 472 : if ( LT_16( s_start, s_start_old ) )
1431 : {
1432 142 : s_start = s_start_old;
1433 142 : move16();
1434 : }
1435 :
1436 472 : IF( GT_16( add( s_start, inlen ), add( s_start_old, s_len_old ) ) )
1437 : {
1438 121 : inlen = add( sub( s_start_old, s_start ), s_len_old );
1439 : }
1440 : }
1441 472 : WHILE( ( css > 2 ) );
1442 472 : return 0;
1443 : }
1444 :
1445 : /*
1446 : ********************************************************************************
1447 : *
1448 : * Function : find_synch
1449 : * Tables : <none>
1450 : * Compile Defines : <none>
1451 : * Return : 0 on success, 1 on failure
1452 : * Information : Find the best match of an template segment within
1453 : * a search region by similarity measures.
1454 : *
1455 : * Typical example:
1456 : *
1457 : * 0 10 20 30 40 50 60
1458 : * in[] = abcdefghijk_abcdefghijk_abcdefghijk_abcdEFGHIJk_abcdefghijk_a
1459 : * l_in = 61
1460 : * offset = 30 |
1461 : * s_start = -20 <-------------------|
1462 : * s_len = 15 <-------------> |
1463 : * search range: *************** |
1464 : * fixed_pos = 10 |--------->
1465 : * corr_len = 6 | <---->
1466 : * template segment: | ******
1467 : * synch_pos: -14 <-------------|
1468 : *
1469 : * All positions are given relative to offset. The
1470 : * search region starts at offset+s_start and ends
1471 : * at offset+s_start+s_len. The template segment
1472 : * starts at offset+fixed_pos and ends at
1473 : * offset+fixed_pos+corr_len. For correlation, the
1474 : * template segment (EFGHIJ) is matched against the
1475 : * segment in the search region, e.g., against (k_abcd)
1476 : * in the first search position. The search position
1477 : * with the best match (-14: EFGHIJ <-> efghij) is
1478 : * returned.
1479 : *
1480 : * 19-JUN-03 N.Faerber initial version
1481 : * 23-APR-04 S.Doehla added subsampling
1482 : *
1483 : ********************************************************************************
1484 : */
1485 472 : static Word16 find_synch_fx( apa_state_t *ps,
1486 : const Word16 *in,
1487 : Word16 l_in,
1488 : Word16 s_start,
1489 : Word16 s_len,
1490 : Word16 fixed_pos,
1491 : Word16 corr_len,
1492 : Word16 offset,
1493 : Word16 *energydBQ8, // Q8
1494 : Word32 *qualityQ16, // Q16
1495 : Word16 *synch_pos )
1496 : {
1497 472 : assert( ( corr_len - 1 + s_start + s_len - 1 + offset ) < l_in );
1498 472 : assert( ( corr_len - 1 + fixed_pos + offset ) < l_in );
1499 :
1500 : /* pass last pitch to search function as prediction value */
1501 472 : *synch_pos = ps->last_pitch;
1502 472 : move16();
1503 472 : logarithmic_search_fx( ps,
1504 : in,
1505 : s_start,
1506 : s_len,
1507 : offset,
1508 : fixed_pos,
1509 : corr_len,
1510 472 : ps->wss,
1511 : // i_mult2( ps->css, ps->num_channels ),
1512 472 : ps->css,
1513 : synch_pos );
1514 : /* assert synch_pos is cleanly divisible by number of channels */
1515 472 : assert( *synch_pos % ps->num_channels == 0 );
1516 :
1517 472 : *qualityQ16 = 0;
1518 472 : move32();
1519 472 : get_scaling_quality_fx( ps, in, l_in, offset, corr_len,
1520 472 : abs_s( sub( *synch_pos, fixed_pos ) ), energydBQ8, qualityQ16 );
1521 472 : ps->last_pitch = *synch_pos;
1522 472 : move16();
1523 472 : return 0;
1524 : }
1525 :
1526 :
1527 : /*
1528 : ********************************************************************************
1529 : *
1530 : * Function : copy_frm
1531 : * Tables : <none>
1532 : * Compile Defines : <none>
1533 : * Return : 0 on success, 1 on failure
1534 : * Information : Copy an audio.
1535 : *
1536 : * The frame size is fixed to ps->l_frm. The input data
1537 : * is stored in frm_in[], where the first ps->l_frm samples
1538 : * shall include the previous output frame and the second
1539 : * ps->l_frm samples shall contain the current input frame.
1540 : * The output frame is stored in frm_out[] and contains
1541 : * l_frm_out = ps->l_frm.
1542 : *
1543 : * The first ps->l_frm input samples are not used by
1544 : * this function and are only provided for a consistent
1545 : * function call with shrink_frm() and extend_frm().
1546 : *
1547 : ********************************************************************************
1548 : */
1549 40 : static bool copy_frm_fx(
1550 : apa_state_t *ps,
1551 : const Word16 frm_in_fx[], // Qx
1552 : Word16 frm_out_fx[], // Qx
1553 : UWord16 *l_frm_out )
1554 : {
1555 : UWord16 i;
1556 :
1557 : /* only 2nd input frame is used */
1558 40 : frm_in_fx += ps->l_frm;
1559 :
1560 : /* copy frame */
1561 25640 : FOR( i = 0; i < ps->l_frm; i++ )
1562 : {
1563 25600 : frm_out_fx[i] = frm_in_fx[i];
1564 25600 : move16();
1565 : }
1566 :
1567 : /* set output length */
1568 40 : *l_frm_out = ps->l_frm;
1569 40 : move16();
1570 :
1571 40 : return 0;
1572 : }
1573 :
1574 : /*
1575 : ********************************************************************************
1576 : *
1577 : * Function : shrink_frm
1578 : * Tables : <none>
1579 : * Compile Defines : <none>
1580 : * Return : 0 on success, 1 on failure
1581 : * Information : Shrink the length of an audio frame using the WSOLA
1582 : * algorithm.
1583 : *
1584 : * The frame size is fixed to ps->l_frm. The input data
1585 : * is stored in frm_in[], where the first ps->l_frm samples
1586 : * shall include the previous output frame and the second
1587 : * ps->l_frm samples shall contain the current input frame.
1588 : * The output frame is stored in frm_out[] and contains
1589 : * l_frm_out samples. The amount of shrinking is signal
1590 : * dependent.
1591 : *
1592 : * The first ps->l_frm input samples are not used by
1593 : * this function and are only provided for a consistent
1594 : * function call with extend_frm().
1595 : *
1596 : ********************************************************************************
1597 : */
1598 0 : static bool shrink_frm_fx(
1599 : apa_state_t *ps,
1600 : const Word16 frm_in_fx[], // Qx
1601 : UWord16 maxScaling,
1602 : Word16 frm_out_fx[], // Qx
1603 : UWord16 *l_frm_out )
1604 : {
1605 0 : bool findSynchResult = 0;
1606 : Word16 xtract, l_rem, s_start, s_end;
1607 : UWord16 i;
1608 : UWord16 over;
1609 0 : Word16 energy_fx = 0;
1610 0 : Word32 quality_fx = 0;
1611 : UWord16 l_frm;
1612 : UWord16 l_seg;
1613 0 : move16();
1614 0 : move32();
1615 :
1616 0 : l_frm = ps->l_frm;
1617 0 : move16();
1618 0 : l_seg = ps->l_seg;
1619 0 : move16();
1620 :
1621 : /* only 2nd input frame is used */
1622 0 : frm_in_fx += l_frm;
1623 :
1624 : /* set search range */
1625 : // s_start = ( ps->p_min / ps->num_channels ) * ps->num_channels;
1626 : Word16 tmp, tmp_e;
1627 0 : tmp = BASOP_Util_Divide3232_Scale( ps->p_min, ps->num_channels, &tmp_e );
1628 0 : tmp = shr( tmp, sub( 15, tmp_e ) );
1629 0 : s_start = i_mult( tmp, extract_l( ps->num_channels ) );
1630 0 : s_end = add( s_start, extract_l( ps->l_search ) );
1631 0 : IF( GE_32( L_add( s_end, l_seg ), l_frm ) )
1632 : {
1633 0 : s_end = extract_l( L_sub( l_frm, l_seg ) );
1634 : }
1635 :
1636 : /* calculate overlap position */
1637 0 : IF( isSilence_fx( frm_in_fx, l_seg, 10 ) )
1638 : {
1639 : /* maximum scaling */
1640 0 : energy_fx = -65 * ( 1 << 8 ); // Q8
1641 0 : move16();
1642 0 : quality_fx = 5 << Q16; // Q16
1643 0 : move32();
1644 0 : IF( ps->evs_compat_mode == false )
1645 : {
1646 :
1647 0 : xtract = maxScaling;
1648 0 : move16();
1649 : /* take samples already in the renderer buf into account */
1650 0 : xtract = add( xtract, extract_l( ps->l_r_buf ) );
1651 : /* snap to renderer time slot borders */
1652 0 : xtract = sub( xtract, extract_l( L_sub( ps->l_ts, ( L_add( L_sub( l_frm, xtract ), ps->l_r_buf ) ) % ps->l_ts ) ) );
1653 0 : WHILE( xtract < 0 )
1654 : {
1655 0 : xtract = add( xtract, extract_l( ps->l_ts ) );
1656 : }
1657 0 : WHILE( GT_32( xtract, sub( s_end, extract_l( ps->num_channels ) ) ) )
1658 : {
1659 : /* exceeded the possible shrinking, go back one renderer ts*/
1660 0 : xtract = sub( xtract, extract_l( ps->l_ts ) );
1661 : }
1662 : }
1663 0 : ELSE IF( maxScaling != 0U && GT_16( s_end, add( extract_l( maxScaling ), 1 ) ) )
1664 : {
1665 0 : xtract = maxScaling;
1666 0 : move16();
1667 : }
1668 : ELSE
1669 : {
1670 : /* set to last valid element (i.e. element[len - 1] but note for stereo last element is last pair of samples) */
1671 0 : xtract = sub( s_end, extract_l( ps->num_channels ) );
1672 : }
1673 : }
1674 : ELSE
1675 : {
1676 : /* find synch */
1677 0 : scaleSignal16( frm_in_fx, ps->frmInScaled, l_frm, ps->signalScaleForCorrelation );
1678 0 : findSynchResult = find_synch_fx( ps, ps->frmInScaled, l_frm, s_start, (UWord16) ( sub( s_end, s_start ) ), 0, l_seg, 0, &energy_fx, &quality_fx, &xtract );
1679 : }
1680 :
1681 : /* assert synch_pos is cleanly divisible by number of channels */
1682 0 : assert( xtract % ps->num_channels == 0 );
1683 :
1684 : /* set frame overlappable - reset if necessary */
1685 0 : over = 1;
1686 0 : move16();
1687 :
1688 : /* test whether frame has sufficient quality */
1689 0 : IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
1690 : L_mult0( ps->bad_frame_count, 6554 ) ),
1691 : L_mult0( ps->good_frame_count, 13107 ) ) ) )
1692 : {
1693 : /* not sufficient */
1694 0 : over = 0;
1695 0 : move16();
1696 0 : IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
1697 : {
1698 0 : ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
1699 0 : move16();
1700 : }
1701 0 : IF( GT_32( ps->good_frame_count, 0 ) )
1702 : {
1703 0 : ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
1704 0 : move16();
1705 : }
1706 : }
1707 : ELSE
1708 : {
1709 : /* sufficient quality */
1710 0 : IF( GT_32( ps->bad_frame_count, 0 ) )
1711 : {
1712 0 : ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
1713 0 : move16();
1714 : }
1715 0 : IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
1716 : {
1717 0 : ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
1718 0 : move16();
1719 : }
1720 : }
1721 :
1722 : /* Calculate output data */
1723 0 : test();
1724 0 : IF( over && xtract )
1725 : {
1726 0 : IF( findSynchResult == 1 )
1727 : {
1728 0 : return 1;
1729 : }
1730 0 : IF( ps->evs_compat_mode == true )
1731 : {
1732 : // overlapAddEvs_fx( frm_in_fx, frm_in_fx + xtract, frm_out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx );
1733 0 : overlapAdd( frm_in_fx, frm_in_fx + xtract, frm_out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
1734 : }
1735 : ELSE
1736 : {
1737 0 : overlapAdd( frm_in_fx, frm_in_fx + xtract, frm_out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
1738 : }
1739 : }
1740 : ELSE
1741 : {
1742 0 : xtract = 0;
1743 0 : move16();
1744 0 : FOR( i = 0; i < l_seg; i++ )
1745 : {
1746 0 : frm_out_fx[i] = frm_in_fx[i];
1747 0 : move16();
1748 : }
1749 : }
1750 :
1751 : /* append remaining samples */
1752 0 : l_rem = extract_l( L_sub( L_sub( l_frm, xtract ), l_seg ) );
1753 0 : FOR( i = 0; i < l_rem; i++ )
1754 : {
1755 0 : frm_out_fx[l_seg + i] = frm_in_fx[l_frm - l_rem + i];
1756 0 : move16();
1757 : }
1758 :
1759 : /* set output length */
1760 0 : *l_frm_out = u_extract_l( UL_addNsD( l_seg, l_rem ) );
1761 0 : move16();
1762 :
1763 0 : return 0;
1764 : }
1765 :
1766 139 : static bool shrink_frm_ivas_fx(
1767 : apa_state_t *ps,
1768 : const Word16 frm_in_fx[], // Qx
1769 : UWord16 maxScaling,
1770 : Word16 frm_out_fx[], // Qx
1771 : Word16 Q_frm_in,
1772 : UWord16 *l_frm_out )
1773 : {
1774 139 : bool findSynchResult = 0;
1775 139 : move16();
1776 : Word16 xtract, l_rem, s_start, s_end;
1777 : UWord16 i;
1778 : UWord16 over;
1779 139 : Word16 energy_fx = 0;
1780 139 : Word32 quality_fx = 0;
1781 : UWord16 l_frm;
1782 : UWord16 l_seg;
1783 139 : move16();
1784 139 : move32();
1785 :
1786 139 : l_frm = ps->l_frm;
1787 139 : move16();
1788 139 : l_seg = ps->l_seg;
1789 139 : move16();
1790 :
1791 : /* only 2nd input frame is used */
1792 139 : frm_in_fx += l_frm;
1793 :
1794 : /* set search range */
1795 : // s_start = ( ps->p_min / ps->num_channels ) * ps->num_channels;
1796 : Word16 tmp, tmp_e;
1797 139 : tmp = BASOP_Util_Divide3232_Scale( ps->p_min, ps->num_channels, &tmp_e );
1798 139 : tmp = shr( tmp, sub( 15, tmp_e ) );
1799 139 : s_start = i_mult( tmp, extract_l( ps->num_channels ) );
1800 139 : s_end = add( s_start, extract_l( ps->l_search ) );
1801 139 : IF( GE_32( L_add( s_end, l_seg ), l_frm ) )
1802 : {
1803 139 : s_end = extract_l( L_sub( l_frm, l_seg ) );
1804 : }
1805 :
1806 : /* calculate overlap position */
1807 139 : IF( isSilence_ivas_fx( frm_in_fx, Q_frm_in, l_seg, 10 ) )
1808 : {
1809 : /* maximum scaling */
1810 0 : energy_fx = -65 * ( 1 << 8 ); // Q8
1811 0 : move16();
1812 0 : quality_fx = 5 << Q16; // Q16
1813 0 : move32();
1814 0 : IF( ps->evs_compat_mode == false )
1815 : {
1816 :
1817 0 : xtract = maxScaling;
1818 0 : move16();
1819 : /* take samples already in the renderer buf into account */
1820 0 : xtract = add( xtract, extract_l( ps->l_r_buf ) );
1821 : /* snap to renderer time slot borders */
1822 0 : xtract = sub( xtract, extract_l( L_sub( ps->l_ts, ( L_add( L_sub( l_frm, xtract ), ps->l_r_buf ) ) % ps->l_ts ) ) );
1823 0 : WHILE( xtract < 0 )
1824 : {
1825 0 : xtract = add( xtract, extract_l( ps->l_ts ) );
1826 : }
1827 0 : WHILE( GT_32( xtract, sub( s_end, extract_l( ps->num_channels ) ) ) )
1828 : {
1829 : /* exceeded the possible shrinking, go back one renderer ts*/
1830 0 : xtract = sub( xtract, extract_l( ps->l_ts ) );
1831 : }
1832 : }
1833 0 : ELSE IF( maxScaling != 0U && GT_16( s_end, add( extract_l( maxScaling ), 1 ) ) )
1834 : {
1835 0 : xtract = maxScaling;
1836 0 : move16();
1837 : }
1838 : ELSE
1839 : {
1840 : /* set to last valid element (i.e. element[len - 1] but note for stereo last element is last pair of samples) */
1841 0 : xtract = sub( s_end, extract_l( ps->num_channels ) );
1842 : }
1843 : }
1844 : ELSE
1845 : {
1846 : /* find synch */
1847 139 : scaleSignal16( frm_in_fx, ps->frmInScaled, l_frm, ps->signalScaleForCorrelation );
1848 139 : ps->signalScaleForCorrelation = sub( ps->signalScaleForCorrelation, Q_frm_in );
1849 139 : move16();
1850 139 : findSynchResult = find_synch_fx( ps, ps->frmInScaled, l_frm, s_start, (UWord16) ( sub( s_end, s_start ) ), 0, l_seg, 0, &energy_fx, &quality_fx, &xtract );
1851 139 : ps->signalScaleForCorrelation = add( ps->signalScaleForCorrelation, Q_frm_in );
1852 139 : move16();
1853 : }
1854 :
1855 : /* assert synch_pos is cleanly divisible by number of channels */
1856 139 : assert( xtract % ps->num_channels == 0 );
1857 :
1858 : /* set frame overlappable - reset if necessary */
1859 139 : over = 1;
1860 139 : move16();
1861 :
1862 : /* test whether frame has sufficient quality */
1863 139 : IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
1864 : L_mult0( ps->bad_frame_count, 6554 /*0.1 (Q16)*/ ) ),
1865 : L_mult0( ps->good_frame_count, 13107 /*0.2 (Q16)*/ ) ) ) )
1866 : {
1867 : /* not sufficient */
1868 94 : over = 0;
1869 94 : move16();
1870 94 : IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
1871 : {
1872 50 : ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
1873 50 : move16();
1874 : }
1875 94 : IF( GT_32( ps->good_frame_count, 0 ) )
1876 : {
1877 46 : ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
1878 46 : move16();
1879 : }
1880 : }
1881 : ELSE
1882 : {
1883 : /* sufficient quality */
1884 45 : IF( ps->bad_frame_count > 0 )
1885 : {
1886 44 : ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
1887 44 : move16();
1888 : }
1889 45 : IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
1890 : {
1891 45 : ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
1892 45 : move16();
1893 : }
1894 : }
1895 :
1896 : /* Calculate output data */
1897 139 : test();
1898 139 : IF( over && xtract )
1899 : {
1900 45 : IF( findSynchResult == 1 )
1901 : {
1902 0 : return 1;
1903 : }
1904 45 : IF( EQ_16( ps->evs_compat_mode, true ) )
1905 : {
1906 : // overlapAddEvs_fx( frm_in_fx, frm_in_fx + xtract, frm_out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx );
1907 0 : overlapAdd( frm_in_fx, frm_in_fx + xtract, frm_out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
1908 : }
1909 : ELSE
1910 : {
1911 45 : overlapAdd( frm_in_fx, frm_in_fx + xtract, frm_out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
1912 : }
1913 : }
1914 : ELSE
1915 : {
1916 94 : xtract = 0;
1917 94 : move16();
1918 40414 : FOR( i = 0; i < l_seg; i++ )
1919 : {
1920 40320 : frm_out_fx[i] = frm_in_fx[i];
1921 40320 : move16();
1922 : }
1923 : }
1924 :
1925 : /* append remaining samples */
1926 139 : l_rem = extract_l( L_sub( L_sub( l_frm, xtract ), l_seg ) );
1927 47447 : FOR( i = 0; i < l_rem; i++ )
1928 : {
1929 47308 : frm_out_fx[l_seg + i] = frm_in_fx[l_frm - l_rem + i];
1930 47308 : move16();
1931 : }
1932 :
1933 : /* set output length */
1934 139 : *l_frm_out = u_extract_l( UL_addNsD( l_seg, l_rem ) );
1935 139 : move16();
1936 :
1937 139 : return 0;
1938 : }
1939 :
1940 : /*
1941 : ********************************************************************************
1942 : *
1943 : * Function : extend_frm
1944 : * Tables : <none>
1945 : * Compile Defines : <none>
1946 : * Return : 0 on success, 1 on failure
1947 : * Information : Extend the length of an audio frame using the WSOLA
1948 : * algorithm.
1949 : *
1950 : * The frame size is fixed to ps->l_frm. The input data
1951 : * is stored in frm_in[], where the first ps->l_frm samples
1952 : * shall include the previous output frame and the second
1953 : * ps->l_frm samples shall contain the current input frame.
1954 : * The output frame is stored in frm_out[] and contains
1955 : * l_frm_out samples. The amount of extension is signal
1956 : * dependent.
1957 : *
1958 : ********************************************************************************
1959 : */
1960 0 : static bool extend_frm_fx(
1961 : apa_state_t *ps,
1962 : const Word16 frm_in_fx[], // Qx
1963 : Word16 frm_out_fx[], // Qx
1964 : UWord16 *l_frm_out )
1965 : {
1966 0 : bool findSynchResult = 0;
1967 : UWord16 l_frm_out_target;
1968 : UWord16 n, i;
1969 : Word16 N;
1970 : Word16 s[MAXN + 2], s_max, s_min;
1971 : Word16 xtract[MAXN + 2], sync_start, s_end;
1972 : UWord16 over[MAXN + 2];
1973 : Word16 l_rem;
1974 0 : Word16 s_start = 0;
1975 0 : move16();
1976 : Word16 energy_fx;
1977 0 : Word32 quality_fx = 0;
1978 0 : move32();
1979 : UWord16 l_frm, l_seg;
1980 : const Word16 *fadeOut_fx, *fadeIn_fx;
1981 : Word16 *out_fx;
1982 :
1983 0 : l_frm = ps->l_frm;
1984 0 : l_seg = ps->l_seg;
1985 0 : move16();
1986 0 : move16();
1987 : /* number of segments/iterations */
1988 0 : l_frm_out_target = (UWord16) ( L_add( l_frm, L_shr( l_frm, 1 ) ) );
1989 : //(l_frm_out_target/l_seg -1 )
1990 : Word16 tmp, tmp_e;
1991 0 : tmp = BASOP_Util_Divide3232_Scale( l_frm_out_target, l_seg, &tmp_e );
1992 0 : tmp = shr( tmp, sub( 15, tmp_e ) );
1993 0 : N = sub( ( tmp ), 1 );
1994 0 : if ( LT_16( N, 1 ) )
1995 : {
1996 0 : N = 1;
1997 0 : move16();
1998 : }
1999 0 : IF( GT_16( N, MAXN ) )
2000 : {
2001 0 : return 1;
2002 : }
2003 : /* calculate equally spaced search regions */
2004 : /* s[n] are given relative to 2nd frame and point to the start of */
2005 : /* the search region. The first segment (n=1) will not be moved. */
2006 : /* Hence, the iterations will start with n=2. */
2007 0 : s_min = extract_l( L_negate( L_add( ps->l_search, ps->p_min ) ) );
2008 : /* (make sure not to exceed array dimension) */
2009 0 : IF( L_add( l_frm, s_min ) < 0 )
2010 : {
2011 0 : s_min = extract_l( L_negate( l_frm ) );
2012 : }
2013 0 : s_max = extract_l( L_sub( L_sub( l_frm, L_shl( l_seg, 1 ) ), ps->l_search ) );
2014 0 : if ( s_max < s_min )
2015 : {
2016 0 : N = 1;
2017 0 : move16();
2018 : }
2019 : /* for just one segment start at s_min */
2020 0 : if ( N == 1 )
2021 : {
2022 0 : s[2] = s_min;
2023 0 : move16();
2024 : }
2025 : /* else, spread linear in between s_min and s_max */
2026 : /* (including s_min and s_max) */
2027 : ELSE
2028 : {
2029 0 : FOR( n = 2; n <= ( N + 1 ); n++ )
2030 : {
2031 : // s[n] = s_min + ( ( s_max - s_min ) * ( n - 2 ) ) / ( N - 1 );
2032 : Word16 tmp2, tmp2_e;
2033 0 : tmp2 = sub( s_max, s_min );
2034 0 : tmp2 = i_mult( tmp2, extract_l( L_sub( n, 2 ) ) );
2035 0 : tmp2 = BASOP_Util_Divide1616_Scale( tmp2, sub( N, 1 ), &tmp2_e );
2036 0 : tmp2 = shr( tmp2, sub( 15, tmp2_e ) );
2037 0 : s[n] = add( s_min, tmp2 );
2038 0 : move16();
2039 : }
2040 : }
2041 :
2042 : /*
2043 : * Planning Phase
2044 : */
2045 :
2046 0 : xtract[1] = extract_l( L_negate( l_seg ) ); /* make sync_start=0 in 1st iteration */
2047 0 : move16();
2048 0 : n = 2;
2049 0 : move16();
2050 : /* define synch segment (to be correlated with search region) */
2051 0 : sync_start = extract_l( L_add( xtract[n - 1], l_seg ) );
2052 0 : over[n] = 1; /* will be reset if overlap is not required */
2053 0 : move16();
2054 : /* check end of search region: should be at least p_min */
2055 : /* samples on the left of synch_start */
2056 0 : IF( LT_32( L_add( s[n], ps->l_search ), L_sub( sync_start, ( ps->p_min ) ) ) )
2057 : {
2058 0 : s_start = s[n];
2059 0 : move16();
2060 0 : s_end = extract_l( L_add( s_start, ps->l_search ) );
2061 : }
2062 : ELSE
2063 : {
2064 : /* shrink search region to enforce minimum shift */
2065 0 : s_end = extract_l( L_sub( sync_start, ( ps->p_min ) ) );
2066 0 : IF( LT_16( extract_l( L_add( s[n], ps->l_search ) ), sync_start ) )
2067 : {
2068 0 : s_start = s[n]; /* just do it with normal start position */
2069 0 : move16();
2070 : }
2071 0 : ELSE IF( EQ_32( n, L_add( N, 1 ) ) ) /* move search region left for last segment */
2072 : {
2073 0 : s_start = extract_l( L_sub( s_end, L_sub( ps->l_search, ps->p_min ) ) );
2074 : }
2075 : ELSE
2076 : {
2077 0 : over[n] = 0; /* don't search/overlap (just copy down) */
2078 0 : move16();
2079 : }
2080 : }
2081 :
2082 0 : IF( over[n] )
2083 : {
2084 : /* calculate overlap position */
2085 0 : IF( isSilence_fx( frm_in_fx, l_seg, 10 ) )
2086 : {
2087 : /* maximum scaling */
2088 0 : energy_fx = -65 * ( 1 << 8 ); // Q8
2089 0 : move16();
2090 0 : quality_fx = 5 << 16; // Q16
2091 0 : move32();
2092 0 : xtract[n] = extract_l( L_add( s_start, ps->num_channels ) );
2093 0 : move16();
2094 0 : IF( ps->evs_compat_mode == false )
2095 : {
2096 : /* take renderer buffer samples into accout */
2097 0 : xtract[n] = extract_l( L_add( xtract[n], ps->l_r_buf ) );
2098 : /* snap to next renderer time slot border to resynchronize */
2099 : // xtract[n] -= ( ( N - 1 ) * l_seg - xtract[n] + ps->l_r_buf ) % ps->l_ts;
2100 : Word16 tmp3;
2101 0 : tmp3 = extract_l( L_add( L_sub( W_extract_l( W_mult0_32_32( L_sub( N, 1 ), l_seg ) ), xtract[n] ), ps->l_r_buf ) );
2102 0 : xtract[n] = sub( xtract[n], tmp3 % ps->l_ts );
2103 0 : move16();
2104 0 : move16();
2105 : }
2106 : }
2107 : ELSE
2108 : {
2109 : Word16 *frmInScaled;
2110 0 : frmInScaled = ps->frmInScaled;
2111 0 : assert( sizeof( ps->frmInScaled ) / sizeof( ps->frmInScaled[0] ) >= 2 * (size_t) l_frm );
2112 0 : scaleSignal16( frm_in_fx, frmInScaled, shl( l_frm, 1 ), ps->signalScaleForCorrelation );
2113 0 : findSynchResult = find_synch_fx( ps, frmInScaled, extract_l( L_shl( l_frm, 1 ) ), s_start, sub( s_end, s_start ), sync_start, l_seg, l_frm, &energy_fx, &quality_fx, &xtract[n] );
2114 : }
2115 : /* assert synch_pos is cleanly divisible by number of channels */
2116 0 : assert( xtract[n] % ps->num_channels == 0 );
2117 :
2118 : /* test for sufficient quality */
2119 0 : IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
2120 : L_mult0( ps->bad_frame_count, 6554 /*.1f in Q16*/ ) ),
2121 : L_mult0( ps->good_frame_count, 13107 /*.1f in Q16*/ ) ) ) )
2122 : {
2123 : /* not sufficient */
2124 0 : over[n] = 0;
2125 0 : move16();
2126 0 : xtract[n] = sync_start;
2127 0 : move16();
2128 0 : IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
2129 : {
2130 0 : ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
2131 0 : move16();
2132 : }
2133 0 : IF( GT_32( ps->good_frame_count, 0 ) )
2134 : {
2135 0 : ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
2136 0 : move16();
2137 : }
2138 : }
2139 : ELSE
2140 : {
2141 : /* sufficient quality */
2142 0 : IF( GT_32( ps->bad_frame_count, 0 ) )
2143 : {
2144 0 : ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
2145 0 : move16();
2146 : }
2147 0 : IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
2148 : {
2149 0 : ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
2150 0 : move16();
2151 : }
2152 : }
2153 0 : IF( findSynchResult )
2154 : {
2155 0 : return 1;
2156 : }
2157 : }
2158 : ELSE
2159 : {
2160 0 : xtract[n] = sync_start;
2161 0 : move16();
2162 : }
2163 :
2164 :
2165 : /* Calculate output data */
2166 0 : FOR( n = 2; n <= N; n++ )
2167 : {
2168 0 : test();
2169 0 : IF( over[n] && NE_16( extract_l( L_add( xtract[n - 1], l_seg ) ), xtract[n] ) )
2170 : {
2171 : /* mix 2nd half of previous segment with 1st half of current segment */
2172 0 : fadeOut_fx = frm_in_fx + l_frm + xtract[n - 1] + l_seg;
2173 0 : fadeIn_fx = frm_in_fx + l_frm + xtract[n];
2174 0 : out_fx = frm_out_fx + ( n - 2 ) * l_seg;
2175 0 : IF( ps->evs_compat_mode == true )
2176 : {
2177 : // overlapAddEvs_fx( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx );
2178 0 : overlapAdd( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
2179 : }
2180 : ELSE
2181 : {
2182 0 : overlapAdd( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
2183 : }
2184 : }
2185 : ELSE
2186 : {
2187 : /* just copy down 1st half of current segment (= 2nd half of previous segment) */
2188 : Word16 *frm_out_ptr;
2189 : const Word16 *frm_in_ptr;
2190 0 : frm_out_ptr = &( frm_out_fx[( n - 2 ) * l_seg] );
2191 0 : frm_in_ptr = &( frm_in_fx[l_frm + xtract[n]] );
2192 0 : FOR( i = 0; i < l_seg; i++ )
2193 : {
2194 0 : frm_out_ptr[i] = frm_in_ptr[i];
2195 0 : move16();
2196 : }
2197 : }
2198 : }
2199 :
2200 : /* append remaining samples */
2201 0 : l_rem = l_frm - ( xtract[N] + l_seg );
2202 0 : FOR( i = 0; i < l_rem; i++ )
2203 : {
2204 0 : frm_out_fx[( N - 1 ) * l_seg + i] = frm_in_fx[2 * l_frm - l_rem + i];
2205 0 : move16();
2206 : }
2207 :
2208 : /* set output length */
2209 0 : *l_frm_out = (UWord16) ( W_mult0_32_32( L_sub( N, 1 ), L_add( l_seg, l_rem ) ) );
2210 0 : move16();
2211 0 : return 0;
2212 : }
2213 :
2214 :
2215 333 : static bool extend_frm_ivas_fx(
2216 : apa_state_t *ps,
2217 : const Word16 frm_in_fx[], // Qx
2218 : Word16 frm_out_fx[], // Qx
2219 : Word16 Q_frm_in,
2220 : UWord16 *l_frm_out )
2221 : {
2222 333 : bool findSynchResult = 0;
2223 333 : move16();
2224 : UWord16 l_frm_out_target;
2225 : UWord16 n, i;
2226 : Word16 N;
2227 : Word16 s[MAXN + 2], s_max, s_min;
2228 : Word16 xtract[MAXN + 2], sync_start, s_end;
2229 : UWord16 over[MAXN + 2];
2230 : Word16 l_rem;
2231 333 : Word16 s_start = 0;
2232 333 : move16();
2233 : Word16 energy_fx;
2234 333 : Word32 quality_fx = 0;
2235 333 : move32();
2236 : UWord16 l_frm, l_seg;
2237 : const Word16 *fadeOut_fx, *fadeIn_fx;
2238 : Word16 *out_fx;
2239 :
2240 333 : l_frm = ps->l_frm;
2241 333 : l_seg = ps->l_seg;
2242 333 : move16();
2243 333 : move16();
2244 : /* number of segments/iterations */
2245 333 : l_frm_out_target = (UWord16) ( L_add( l_frm, L_shr( l_frm, 1 ) ) );
2246 : //(l_frm_out_target/l_seg -1 )
2247 : Word16 tmp, tmp_e;
2248 333 : tmp = BASOP_Util_Divide3232_Scale( l_frm_out_target, l_seg, &tmp_e );
2249 333 : tmp = shr( tmp, sub( 15, tmp_e ) );
2250 333 : N = sub( ( tmp ), 1 );
2251 333 : if ( LT_16( N, 1 ) )
2252 : {
2253 0 : N = 1;
2254 0 : move16();
2255 : }
2256 333 : IF( GT_16( N, MAXN ) )
2257 : {
2258 0 : return 1;
2259 : }
2260 : /* calculate equally spaced search regions */
2261 : /* s[n] are given relative to 2nd frame and point to the start of */
2262 : /* the search region. The first segment (n=1) will not be moved. */
2263 : /* Hence, the iterations will start with n=2. */
2264 333 : s_min = extract_l( L_negate( L_add( ps->l_search, ps->p_min ) ) );
2265 : /* (make sure not to exceed array dimension) */
2266 333 : IF( L_add( l_frm, s_min ) < 0 )
2267 : {
2268 0 : s_min = extract_l( L_negate( l_frm ) );
2269 : }
2270 333 : s_max = extract_l( L_sub( L_sub( l_frm, L_shl( l_seg, 1 ) ), ps->l_search ) );
2271 333 : if ( s_max < s_min )
2272 : {
2273 0 : N = 1;
2274 0 : move16();
2275 : }
2276 : /* for just one segment start at s_min */
2277 333 : if ( N == 1 )
2278 : {
2279 0 : s[2] = s_min;
2280 0 : move16();
2281 : }
2282 : /* else, spread linear in between s_min and s_max */
2283 : /* (including s_min and s_max) */
2284 : ELSE
2285 : {
2286 999 : FOR( n = 2; n <= ( N + 1 ); n++ )
2287 : {
2288 : // s[n] = s_min + ( ( s_max - s_min ) * ( n - 2 ) ) / ( N - 1 );
2289 : Word16 tmp2, tmp2_e;
2290 666 : tmp2 = sub( s_max, s_min );
2291 666 : tmp2 = i_mult( tmp2, extract_l( L_sub( n, 2 ) ) );
2292 666 : tmp2 = BASOP_Util_Divide1616_Scale( tmp2, sub( N, 1 ), &tmp2_e );
2293 666 : tmp2 = shr( tmp2, sub( 15, tmp2_e ) );
2294 666 : s[n] = add( s_min, tmp2 );
2295 666 : move16();
2296 : }
2297 : }
2298 :
2299 : /*
2300 : * Planning Phase
2301 : */
2302 :
2303 333 : xtract[1] = extract_l( L_negate( l_seg ) ); /* make sync_start=0 in 1st iteration */
2304 333 : move16();
2305 333 : n = 2;
2306 333 : move16();
2307 : /* define synch segment (to be correlated with search region) */
2308 333 : sync_start = extract_l( L_add( xtract[n - 1], l_seg ) );
2309 333 : over[n] = 1; /* will be reset if overlap is not required */
2310 333 : move16();
2311 : /* check end of search region: should be at least p_min */
2312 : /* samples on the left of synch_start */
2313 333 : IF( LT_32( L_add( s[n], ps->l_search ), L_sub( sync_start, ( ps->p_min ) ) ) )
2314 : {
2315 0 : s_start = s[n];
2316 0 : move16();
2317 0 : s_end = extract_l( L_add( s_start, ps->l_search ) );
2318 : }
2319 : ELSE
2320 : {
2321 : /* shrink search region to enforce minimum shift */
2322 333 : s_end = extract_l( L_sub( sync_start, ( ps->p_min ) ) );
2323 333 : IF( LT_16( extract_l( L_add( s[n], ps->l_search ) ), sync_start ) )
2324 : {
2325 333 : s_start = s[n]; /* just do it with normal start position */
2326 333 : move16();
2327 : }
2328 0 : ELSE IF( EQ_32( n, L_add( N, 1 ) ) ) /* move search region left for last segment */
2329 : {
2330 0 : s_start = extract_l( L_sub( s_end, L_sub( ps->l_search, ps->p_min ) ) );
2331 : }
2332 : ELSE
2333 : {
2334 0 : over[n] = 0; /* don't search/overlap (just copy down) */
2335 0 : move16();
2336 : }
2337 : }
2338 :
2339 333 : IF( over[n] )
2340 : {
2341 : /* calculate overlap position */
2342 333 : IF( isSilence_ivas_fx( frm_in_fx, Q_frm_in, l_seg, 10 ) )
2343 : {
2344 : /* maximum scaling */
2345 0 : energy_fx = -65 * ( 1 << 8 ); // Q8
2346 0 : move16();
2347 0 : quality_fx = 5 << 16; // Q16
2348 0 : move32();
2349 0 : xtract[n] = extract_l( L_add( s_start, ps->num_channels ) );
2350 0 : move16();
2351 0 : IF( ps->evs_compat_mode == false )
2352 : {
2353 : /* take renderer buffer samples into accout */
2354 0 : xtract[n] = extract_l( L_add( xtract[n], ps->l_r_buf ) );
2355 : /* snap to next renderer time slot border to resynchronize */
2356 : // xtract[n] -= ( ( N - 1 ) * l_seg - xtract[n] + ps->l_r_buf ) % ps->l_ts;
2357 : Word16 tmp3;
2358 0 : tmp3 = extract_l( L_add( L_sub( W_extract_l( W_mult0_32_32( L_sub( N, 1 ), l_seg ) ), xtract[n] ), ps->l_r_buf ) );
2359 0 : xtract[n] = sub( xtract[n], tmp3 % ps->l_ts );
2360 0 : move16();
2361 0 : move16();
2362 : }
2363 : }
2364 : ELSE
2365 : {
2366 : Word16 *frmInScaled;
2367 333 : frmInScaled = ps->frmInScaled;
2368 333 : assert( sizeof( ps->frmInScaled ) / sizeof( ps->frmInScaled[0] ) >= 2 * (size_t) l_frm );
2369 333 : scaleSignal16( frm_in_fx, frmInScaled, shl( l_frm, 1 ), ps->signalScaleForCorrelation );
2370 333 : ps->signalScaleForCorrelation = sub( ps->signalScaleForCorrelation, Q_frm_in );
2371 333 : findSynchResult = find_synch_fx( ps, frmInScaled, extract_l( L_shl( l_frm, 1 ) ), s_start, sub( s_end, s_start ), sync_start, l_seg, l_frm, &energy_fx, &quality_fx, &xtract[n] );
2372 333 : ps->signalScaleForCorrelation = add( ps->signalScaleForCorrelation, Q_frm_in );
2373 : }
2374 : /* assert synch_pos is cleanly divisible by number of channels */
2375 333 : assert( xtract[n] % ps->num_channels == 0 );
2376 :
2377 : /* test for sufficient quality */
2378 333 : IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
2379 : L_mult0( ps->bad_frame_count, 6554 /*.1f in Q16*/ ) ),
2380 : L_mult0( ps->good_frame_count, 13107 /*.1f in Q16*/ ) ) ) )
2381 : {
2382 : /* not sufficient */
2383 292 : over[n] = 0;
2384 292 : move16();
2385 292 : xtract[n] = sync_start;
2386 292 : move16();
2387 292 : IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
2388 : {
2389 99 : ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
2390 99 : move16();
2391 : }
2392 292 : IF( GT_32( ps->good_frame_count, 0 ) )
2393 : {
2394 17 : ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
2395 17 : move16();
2396 : }
2397 : }
2398 : ELSE
2399 : {
2400 : /* sufficient quality */
2401 41 : IF( GT_32( ps->bad_frame_count, 0 ) )
2402 : {
2403 38 : ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
2404 38 : move16();
2405 : }
2406 41 : IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
2407 : {
2408 41 : ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
2409 41 : move16();
2410 : }
2411 : }
2412 333 : IF( findSynchResult )
2413 : {
2414 0 : return 1;
2415 : }
2416 : }
2417 : ELSE
2418 : {
2419 0 : xtract[n] = sync_start;
2420 0 : move16();
2421 : }
2422 :
2423 :
2424 : /* Calculate output data */
2425 666 : FOR( n = 2; n <= N; n++ )
2426 : {
2427 333 : test();
2428 333 : IF( over[n] && NE_16( extract_l( L_add( xtract[n - 1], l_seg ) ), xtract[n] ) )
2429 : {
2430 : /* mix 2nd half of previous segment with 1st half of current segment */
2431 41 : fadeOut_fx = frm_in_fx + l_frm + xtract[n - 1] + l_seg;
2432 41 : fadeIn_fx = frm_in_fx + l_frm + xtract[n];
2433 41 : out_fx = frm_out_fx + ( n - 2 ) * l_seg;
2434 41 : IF( EQ_16( ps->evs_compat_mode, true ) )
2435 : {
2436 : // overlapAddEvs_fx( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx );
2437 0 : overlapAdd( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
2438 : }
2439 : ELSE
2440 : {
2441 41 : overlapAdd( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin, ps->win_fx, ps->win_incrementor );
2442 : }
2443 : }
2444 : ELSE
2445 : {
2446 : /* just copy down 1st half of current segment (= 2nd half of previous segment) */
2447 : Word16 *frm_out_ptr;
2448 : const Word16 *frm_in_ptr;
2449 292 : frm_out_ptr = &( frm_out_fx[( n - 2 ) * l_seg] );
2450 292 : frm_in_ptr = &( frm_in_fx[l_frm + xtract[n]] );
2451 292292 : FOR( i = 0; i < l_seg; i++ )
2452 : {
2453 292000 : frm_out_ptr[i] = frm_in_ptr[i];
2454 292000 : move16();
2455 : }
2456 : }
2457 : }
2458 :
2459 : /* append remaining samples */
2460 333 : l_rem = l_frm - ( xtract[N] + l_seg );
2461 381768 : FOR( i = 0; i < l_rem; i++ )
2462 : {
2463 381435 : frm_out_fx[( N - 1 ) * l_seg + i] = frm_in_fx[2 * l_frm - l_rem + i];
2464 381435 : move16();
2465 : }
2466 :
2467 : /* set output length */
2468 333 : *l_frm_out = (UWord16) ( W_mult0_32_32( L_sub( N, 1 ), L_add( l_seg, l_rem ) ) );
2469 333 : move16();
2470 333 : return 0;
2471 : }
|