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