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 28 : ivas_error apa_init(
165 : apa_state_t **pps,
166 : const Word32 num_channels )
167 : {
168 28 : apa_state_t *ps = NULL;
169 :
170 : /* make sure pointer is valid */
171 28 : IF( !pps )
172 : {
173 0 : return 1;
174 : }
175 :
176 : /* allocate state struct */
177 28 : 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 28 : ps->num_channels = (UWord16) num_channels;
183 28 : move16();
184 28 : ps->buf_out_capacity = (UWord16) L_mult0( APA_BUF_PER_CHANNEL, (Word16) num_channels );
185 28 : move16();
186 :
187 28 : 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 28 : memset( ps->buf_out_fx, 0, ( sizeof( Word16 ) * ps->buf_out_capacity ) );
192 28 : ps->Q_buf_out = Q15;
193 28 : move16();
194 :
195 28 : ps->evs_compat_mode = false;
196 28 : move16();
197 :
198 28 : apa_reset( ps );
199 28 : *pps = ps;
200 :
201 28 : return IVAS_ERR_OK;
202 : }
203 :
204 :
205 : /* Sets state variables to initial value. */
206 56 : void apa_reset(
207 : apa_state_t *ps )
208 : {
209 : /* init state struct */
210 56 : ps->signalScaleForCorrelation = 0;
211 56 : move16();
212 56 : ps->l_buf_out = 0;
213 56 : move16();
214 56 : ps->l_halfwin = 0;
215 56 : move16();
216 56 : ps->rate = 0;
217 56 : move16();
218 56 : ps->l_seg = 0;
219 56 : move16();
220 56 : ps->l_frm = 0;
221 56 : move16();
222 56 : ps->l_in_total = 0;
223 56 : move32();
224 56 : ps->diffSinceSetScale = 0;
225 56 : move32();
226 56 : ps->nFramesSinceSetScale = 0;
227 56 : move32();
228 56 : ps->scale = 100;
229 56 : move16();
230 56 : ps->p_min = 0;
231 56 : move16();
232 56 : ps->l_search = 0;
233 56 : move16();
234 56 : ps->wss = 1;
235 56 : move16();
236 56 : ps->css = 1;
237 56 : move16();
238 56 : ps->targetQuality_fx = 0;
239 56 : move32();
240 :
241 56 : ps->qualityred = 0;
242 56 : move16();
243 56 : ps->qualityrise = 0;
244 56 : move16();
245 56 : ps->last_pitch = 0;
246 56 : move16();
247 56 : ps->bad_frame_count = 0;
248 56 : move16();
249 56 : ps->good_frame_count = 0;
250 56 : move16();
251 :
252 56 : ps->l_ts = 1;
253 56 : move16();
254 56 : ps->l_r_buf = 0;
255 56 : move16();
256 56 : return;
257 : }
258 :
259 941 : UWord8 apa_reconfigure(
260 : apa_state_t *ps,
261 : UWord16 num_channels,
262 : UWord16 l_ts )
263 : {
264 :
265 : /* realloc buffer */
266 941 : ps->num_channels = (UWord16) num_channels;
267 941 : move16();
268 941 : ps->buf_out_capacity = (UWord16) L_mult0( APA_BUF_PER_CHANNEL, (Word16) num_channels );
269 941 : move16();
270 :
271 941 : free( ps->buf_out_fx );
272 941 : ps->buf_out_fx = (Word16 *) malloc( sizeof( Word16 ) * ps->buf_out_capacity );
273 941 : memset( ps->buf_out_fx, 0, ( sizeof( Word16 ) * ps->buf_out_capacity ) );
274 941 : ps->Q_buf_out = Q15;
275 941 : move16();
276 941 : IF( !ps->buf_out_fx )
277 : {
278 0 : return 2;
279 : }
280 :
281 941 : ps->l_buf_out = 0;
282 941 : ps->l_in_total = 0;
283 941 : move16();
284 941 : move32();
285 941 : ps->l_ts = (UWord16) imult3216( l_ts, ps->num_channels );
286 941 : 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 941 : ps->l_seg = (UWord16) imult3216( Mult_32_16( ps->rate, INV_100_Q15 ), (Word16) ps->num_channels ); // Q0
294 941 : move16();
295 :
296 : /* set frame size */
297 : /* set to 320 samples at 16 kHz */
298 941 : ps->l_frm = (UWord16) imult3216( Mult_32_16( ps->rate, INV_FRAME_PER_SEC_Q15 ), (Word16) ps->num_channels ); // Q0
299 941 : 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 941 : ps->p_min = (UWord16) imult3216( Mult_32_16( ps->rate, INV_400_Q15 ), (Word16) ps->num_channels ); // Q0
305 941 : 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 941 : ps->l_search = (UWord16) imult3216( Mult_32_16( ps->rate, INV_80_Q15 ), (Word16) ps->num_channels ); // Q0
311 941 : move16();
312 :
313 941 : return 0;
314 : }
315 :
316 : /* Sets the audio configuration. */
317 28 : bool apa_set_rate(
318 : apa_state_t *ps,
319 : const Word32 output_Fs )
320 : {
321 : /* make sure pointer is valid */
322 28 : IF( ps == NULL )
323 : {
324 0 : return 1;
325 : }
326 :
327 : /* check range */
328 28 : test();
329 28 : 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 28 : apa_reset( ps );
336 :
337 : /* copy rate to state struct */
338 28 : ps->rate = (UWord16) output_Fs;
339 28 : move16();
340 :
341 28 : 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 28 : ps->l_seg = (UWord16) imult3216( Mult_32_16( ps->rate, INV_100_Q15 ), ps->num_channels ); // Q0
360 28 : 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 28 : ps->l_halfwin = (UWord16) Mult_32_16( ps->rate, INV_100_Q15 ); // Q0
367 28 : move16();
368 :
369 : /* set frame size */
370 : /* set to 320 samples at 16 kHz */
371 28 : ps->l_frm = (UWord16) imult3216( ( Mult_32_16( ps->rate, INV_FRAME_PER_SEC_Q15 ) ), ps->num_channels ); // Q0
372 28 : 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 28 : ps->p_min = (UWord16) imult3216( ( Mult_32_16( ps->rate, INV_400_Q15 ) ), ps->num_channels ); // Q0
378 28 : 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 28 : ps->l_search = (UWord16) imult3216( Mult_32_16( ps->rate, INV_80_Q15 ), ps->num_channels ); // Q0
384 28 : move16();
385 :
386 28 : ps->win_fx = pcmdsp_window_hann_640;
387 28 : ps->l_halfwin = 320;
388 28 : move16();
389 28 : ps->win_incrementor = 1;
390 28 : move16();
391 28 : 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 28 : 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 28 : if ( EQ_32( ps->rate, 16000 ) )
408 : {
409 3 : ps->win_incrementor = 2;
410 3 : move16();
411 : }
412 28 : 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 28 : ps->signalScaleForCorrelation = getSignalScaleForCorrelation( ps->rate );
424 28 : move16();
425 28 : return 0;
426 : }
427 :
428 : /* Set scaling. */
429 19553 : bool apa_set_scale_fx(
430 : apa_state_t *ps,
431 : UWord16 scale )
432 : {
433 : /* make sure pointer is valid */
434 19553 : IF( ps == NULL )
435 : {
436 0 : return 1;
437 : }
438 :
439 : /* check range */
440 19553 : test();
441 19553 : 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 19553 : IF( EQ_32( (Word32) ps->scale, (Word32) scale ) )
449 : {
450 19474 : return 0;
451 : }
452 :
453 : /* copy to state struct */
454 79 : ps->scale = scale;
455 79 : move16();
456 :
457 : /* reset scaling statistics */
458 79 : ps->diffSinceSetScale = 0;
459 79 : move32();
460 79 : ps->nFramesSinceSetScale = 0;
461 79 : move32();
462 :
463 79 : return 0;
464 : }
465 :
466 28 : bool apa_set_renderer_granularity(
467 : apa_state_t *ps,
468 : UWord16 l_ts )
469 : {
470 : /* make sure pointer is valid */
471 28 : IF( ps == NULL )
472 : {
473 0 : return 1;
474 : }
475 :
476 :
477 : /* copy to state struct */
478 28 : ps->l_ts = (UWord16) imult3216( l_ts, (Word16) ps->num_channels );
479 28 : move16();
480 28 : return 0;
481 : }
482 :
483 19553 : bool apa_set_renderer_residual_samples(
484 : apa_state_t *ps,
485 : UWord16 l_r_buf )
486 : {
487 : /* make sure pointer is valid */
488 19553 : IF( ps == NULL )
489 : {
490 0 : return 1;
491 : }
492 :
493 :
494 : /* copy to state struct */
495 19553 : ps->l_r_buf = (UWord16) imult3216( l_r_buf, (Word16) ps->num_channels );
496 19553 : move16();
497 19553 : 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 28 : bool apa_set_quality(
542 : apa_state_t *ps,
543 : Word32 quality, // Q16
544 : UWord16 qualityred,
545 : UWord16 qualityrise )
546 : {
547 28 : assert( ps != NULL );
548 28 : assert( -131072 /*-2.0f in Q16*/ <= quality && quality <= 203161 /*3.1f in Q16*/ );
549 28 : assert( qualityred > 0 && qualityred <= 20 );
550 28 : assert( qualityrise > 0 && qualityrise <= 20 );
551 :
552 28 : ps->targetQuality_fx = quality;
553 28 : move32();
554 28 : ps->qualityred = qualityred;
555 28 : move16();
556 28 : ps->qualityrise = qualityrise;
557 28 : move16();
558 28 : ps->bad_frame_count = 0;
559 28 : move16();
560 28 : ps->good_frame_count = 0;
561 28 : move16();
562 :
563 28 : 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 28 : bool apa_set_complexity_options(
582 : apa_state_t *ps,
583 : UWord16 wss,
584 : UWord16 css )
585 : {
586 : /* make sure pointer is valid */
587 28 : IF( ps == NULL )
588 : {
589 0 : return 1;
590 : }
591 :
592 28 : test();
593 28 : IF( wss == 0 || GT_32( wss, 1000 ) )
594 : {
595 0 : return 1;
596 : }
597 :
598 28 : test();
599 28 : IF( css == 0 || GT_32( css, 1000 ) )
600 : {
601 0 : return 1;
602 : }
603 :
604 28 : ps->wss = wss;
605 28 : move16();
606 28 : ps->css = css;
607 28 : move16();
608 :
609 28 : 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 613 : bool apa_exit(
626 : apa_state_t **pps )
627 : {
628 : /* ignore NULL pointer input */
629 613 : IF( *pps == NULL )
630 : {
631 585 : return 0;
632 : }
633 :
634 : /* deallocate state struct members */
635 28 : free( ( *pps )->buf_out_fx );
636 :
637 : /* deallocate state struct */
638 28 : free( *pps );
639 :
640 : /* set pointer to NULL */
641 28 : *pps = NULL;
642 :
643 28 : 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 19553 : 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 19553 : Q_a_out = add( getScaleFactor32_copy( a_in, L_mult0( ps->num_channels, APA_BUF_PER_CHANNEL ) ), Q11 - Q16 - Q1 );
902 19553 : statsResetThreshold = 1637;
903 19553 : move32();
904 19553 : statsResetShift = 2;
905 19553 : move32();
906 :
907 : /* Convert max_scaling from "per channel" to total */
908 19553 : maxScaling = (UWord16) imult3216( maxScaling, ps->num_channels );
909 :
910 : /* make sure no invalid output is used */
911 19553 : *l_out = 0;
912 19553 : move16();
913 19553 : l_frm_out = 0;
914 19553 : move16();
915 :
916 : /* make sure pointer is valid */
917 19553 : IF( ps == NULL )
918 : {
919 0 : return 1;
920 : }
921 : /* check available rate */
922 19553 : IF( ps->rate == 0 )
923 : {
924 0 : return 2;
925 : }
926 : /* check size of input */
927 19553 : IF( NE_32( l_in, ps->l_frm ) )
928 : {
929 0 : return 3;
930 : }
931 :
932 : /* get target length */
933 19553 : 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 486 : 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 19067 : ELSE IF( LT_32( ps->scale, 100 ) )
939 : {
940 109 : 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 18958 : expScaling = 0;
945 18958 : move32();
946 : }
947 19553 : actScaling = L_sub( ps->diffSinceSetScale, ps->l_frm );
948 19553 : 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 19553 : IF( LT_32( ps->l_buf_out, ps->l_frm ) )
954 : {
955 2296329 : FOR( i = 0; i < ps->l_frm; i++ )
956 : {
957 2295360 : a_out[i] = a_in[i];
958 2295360 : move32();
959 : }
960 969 : l_frm_out = ps->l_frm;
961 969 : move16();
962 : }
963 : ELSE
964 : {
965 : Word16 a_tmp[APA_BUF];
966 18584 : Word16 *buf_out_ptr = &( ps->buf_out_fx[ps->l_buf_out - ps->l_frm] );
967 :
968 18584 : Q_a_out = s_min( Q_a_out, ps->Q_buf_out );
969 18584 : Scale_sig( ps->buf_out_fx, ps->buf_out_capacity, sub( Q_a_out, ps->Q_buf_out ) ); // Q_buf_out -> Q_a_out
970 18584 : IF( EQ_32( ps->scale, 100 ) )
971 : {
972 118219090 : FOR( i = 0; i < ps->num_channels * APA_BUF_PER_CHANNEL; i++ )
973 : {
974 118200960 : a_out[i] = a_in[i]; // Q11
975 118200960 : move32();
976 : }
977 18130 : l_frm_out = ps->l_frm;
978 18130 : move16();
979 : }
980 : ELSE
981 : {
982 454 : Word16 *frm_in_ptr = &( frm_in[ps->l_frm] );
983 :
984 3226054 : FOR( i = 0; i < ps->num_channels * APA_BUF_PER_CHANNEL; i++ )
985 : {
986 3225600 : a_tmp[i] = extract_h( L_shl( a_in[i], add( Q_a_out, Q5 ) ) ); // Q_a_out
987 3225600 : move16();
988 : }
989 : /* fill input frame */
990 : /* 1st input frame: previous output samples */
991 915334 : FOR( i = 0; i < ps->l_frm; i++ )
992 : {
993 914880 : frm_in[i] = buf_out_ptr[i];
994 914880 : move16();
995 : }
996 : /* 2nd input frame: new input samples */
997 915334 : FOR( i = 0; i < ps->l_frm; i++ )
998 : {
999 914880 : frm_in_ptr[i] = a_tmp[i];
1000 914880 : move16();
1001 : }
1002 : /* shrink */
1003 454 : IF( LT_32( ps->scale, 100 ) )
1004 : {
1005 103 : shrink_frm_ivas_fx( ps, frm_in, maxScaling, a_tmp, Q_a_out, &l_frm_out );
1006 : }
1007 : /* extend */
1008 : ELSE
1009 : {
1010 351 : extend_frm_ivas_fx( ps, frm_in, a_tmp, Q_a_out, &l_frm_out );
1011 : }
1012 : /* control the amount/frequency of scaling */
1013 454 : IF( NE_32( l_frm_out, ps->l_frm ) )
1014 : {
1015 65 : test();
1016 65 : IF( ( maxScaling != 0 ) &&
1017 : GT_32( abs_s( extract_l( L_sub( ps->l_frm, l_frm_out ) ) ), maxScaling ) )
1018 : {
1019 : /* maxScaling exceeded -> discard scaled frame */
1020 15 : copy_frm_fx( ps, frm_in, a_tmp, &l_frm_out );
1021 : }
1022 50 : ELSE IF( GT_32( L_abs( l_frm_out_target ), ps->l_frm ) ) /* ignore small difference */
1023 : {
1024 42 : dl_copied = L_sub( l_frm_out_target, ps->l_frm );
1025 42 : dl_scaled = L_sub( l_frm_out_target, l_frm_out );
1026 : /* discard scaled frame if copied frame is closer to target length */
1027 42 : IF( LT_32( L_abs( dl_copied ), L_abs( dl_scaled ) ) )
1028 : {
1029 1 : copy_frm_fx( ps, frm_in, a_tmp, &l_frm_out );
1030 : }
1031 : }
1032 : }
1033 :
1034 3226054 : FOR( i = 0; i < ps->num_channels * APA_BUF_PER_CHANNEL; i++ )
1035 : {
1036 3225600 : a_out[i] = L_shl( a_tmp[i], sub( Q11, Q_a_out ) ); // Q0 -> Q11
1037 3225600 : move32();
1038 : }
1039 : }
1040 : }
1041 :
1042 : /* copy output to internal buffer */
1043 : /* avoid buffer overflow: */
1044 : /* discard old samples; always keep at least most recent l_frm samples */
1045 19553 : IF( GT_32( L_add( ps->l_buf_out, l_frm_out ), ps->buf_out_capacity ) )
1046 : {
1047 4765 : Word16 *buf_out_ptr1 = ps->buf_out_fx;
1048 : Word16 *buf_out_ptr2;
1049 :
1050 4765 : l_rem = extract_l( L_sub( ps->l_frm, l_frm_out ) );
1051 4765 : if ( l_rem < 0 )
1052 : {
1053 21 : l_rem = 0;
1054 21 : move16();
1055 : }
1056 4765 : buf_out_ptr2 = &( ps->buf_out_fx[ps->l_buf_out - l_rem] );
1057 5551 : FOR( i = 0; i < l_rem; i++ )
1058 : {
1059 786 : buf_out_ptr1[i] = buf_out_ptr2[i];
1060 786 : move16();
1061 : }
1062 4765 : ps->l_buf_out = l_rem;
1063 4765 : move16();
1064 : }
1065 : /* append new output samples */
1066 19553 : IF( GT_32( L_add( ps->l_buf_out, l_frm_out ), ps->buf_out_capacity ) )
1067 : {
1068 0 : return 5;
1069 : }
1070 : {
1071 19553 : Word16 *buf_out_ptr = &( ps->buf_out_fx[ps->l_buf_out] );
1072 35847328 : FOR( i = 0; i < l_frm_out; i++ )
1073 : {
1074 35827775 : buf_out_ptr[i] = extract_h( L_shl( a_out[i], add( Q_a_out, Q16 - Q11 ) ) ); // Q_a_out
1075 35827775 : move16();
1076 : }
1077 19553 : ps->Q_buf_out = Q_a_out;
1078 19553 : move16();
1079 : }
1080 19553 : ps->l_buf_out = (UWord16) L_add( ps->l_buf_out, l_frm_out );
1081 19553 : move16();
1082 :
1083 19553 : *l_out = l_frm_out;
1084 19553 : move16();
1085 : /* update time */
1086 19553 : ps->l_in_total = UL_addNsD( ps->l_in_total, ps->l_frm );
1087 19553 : move32();
1088 :
1089 19553 : test();
1090 19553 : IF( LT_32( L_abs( ps->diffSinceSetScale ), L_sub( 0x7FFFFF, L_sub( l_frm_out, ps->l_frm ) ) ) &&
1091 : LT_64( ps->nFramesSinceSetScale, statsResetThreshold ) )
1092 : {
1093 19553 : ps->diffSinceSetScale = L_add( ps->diffSinceSetScale, L_sub( l_frm_out, ps->l_frm ) );
1094 19553 : move32();
1095 19553 : ps->nFramesSinceSetScale = UL_addNsD( ps->nFramesSinceSetScale, 1 );
1096 19553 : move32();
1097 : }
1098 : ELSE /* scale statistics down to avoid overflow */
1099 : {
1100 0 : ps->diffSinceSetScale = L_shr( ps->diffSinceSetScale, (Word16) statsResetShift );
1101 0 : move32();
1102 0 : ps->nFramesSinceSetScale = UL_lshr( ps->nFramesSinceSetScale, (Word16) statsResetShift );
1103 0 : move32();
1104 : }
1105 :
1106 19553 : return 0;
1107 : }
1108 :
1109 :
1110 : /*---------------------------------------------------------------------*
1111 : * Local functions
1112 : *---------------------------------------------------------------------*/
1113 :
1114 : /*
1115 : ********************************************************************************
1116 : *
1117 : * Function : get_scaling_quality
1118 : * Tables : <none>
1119 : * Compile Defines : <none>
1120 : * Return : 0 on success, 1 on failure
1121 : * Information : Uses pitch, half pitch, three halves and double pitch
1122 : * to evaluate the quality of the scaled frame by checking
1123 : * periodicity.
1124 : * Silence can be detected as additional feature. This must
1125 : * be set in global struct apa_state.
1126 : *
1127 : * If search length is very narrow then use fewer points
1128 : * to evaluate periodicity and silence.
1129 : *
1130 : * Computationally not very efficient by using normalized
1131 : * cross-correlation: Using sqrt() for energy calculation
1132 : * adds complexity.
1133 : *
1134 : * 03-AUG-04 S.Doehla initial version
1135 : *
1136 : ********************************************************************************
1137 : */
1138 454 : static void get_scaling_quality_fx( const apa_state_t *ps,
1139 : const Word16 *signal,
1140 : Word16 s_len,
1141 : Word16 offset,
1142 : Word16 corr_len,
1143 : Word16 pitch,
1144 : Word16 *energydBQ8, // Q8
1145 : Word32 *qualityQ16 // Q16
1146 : )
1147 : {
1148 : Word32 energy, maxEnergy;
1149 : Word32 qualityOfMaxEnergy; /* we measure the quality for all channels and select the one with highest energy */
1150 : Word16 half_pitch_cn;
1151 : Word16 pitch_cn;
1152 : Word16 three_halves_pitch_cn;
1153 : Word16 double_pitch_cn;
1154 : Word32 pitch_energy;
1155 : Word32 half_pitch_energy;
1156 : Word32 three_halves_pitch_energy;
1157 : Word32 double_pitch_energy;
1158 : Word16 i;
1159 :
1160 :
1161 454 : maxEnergy = 0;
1162 454 : qualityOfMaxEnergy = 0;
1163 454 : move32();
1164 454 : move32();
1165 :
1166 1574 : FOR( i = 0; i < ps->num_channels; i++ )
1167 : {
1168 1120 : offset = 0;
1169 1120 : move16();
1170 :
1171 1120 : pitch_cn = normalized_cross_correlation_self_fx( signal, add( pitch, offset ), offset, corr_len,
1172 1120 : shl( ps->num_channels, 1 ), &pitch_energy );
1173 1120 : IF( pitch_cn > 0 )
1174 : {
1175 : /* calculate correlation for double pitch */
1176 779 : IF( LE_16( add( add( shl( pitch, 1 ), offset ), corr_len ), s_len ) )
1177 : {
1178 659 : double_pitch_cn = normalized_cross_correlation_self_fx( signal, add( shl( pitch, 1 ), offset ),
1179 659 : offset, corr_len, shl( ps->num_channels, 1 ), &double_pitch_energy );
1180 : }
1181 : ELSE
1182 : {
1183 120 : double_pitch_cn = pitch_cn;
1184 120 : move16();
1185 120 : double_pitch_energy = L_add( pitch_energy, 0 );
1186 : }
1187 : /* calculate correlation for three/half pitch */
1188 779 : IF( LE_16( add( add( shr( i_mult2( pitch, 3 ), 1 ), offset ), corr_len ), s_len ) )
1189 : {
1190 693 : 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 );
1191 : }
1192 : ELSE
1193 : {
1194 86 : three_halves_pitch_cn = pitch_cn;
1195 86 : move16();
1196 86 : three_halves_pitch_energy = L_add( pitch_energy, 0 );
1197 : }
1198 : /* calculate correlation for half pitch */
1199 779 : IF( LE_16( add( add( shr( pitch, 1 ), offset ), corr_len ), s_len ) )
1200 : {
1201 779 : half_pitch_cn = normalized_cross_correlation_self_fx( signal, add( shr( pitch, 1 ), offset ),
1202 779 : offset, corr_len, shl( ps->num_channels, 1 ), &half_pitch_energy );
1203 : }
1204 : ELSE
1205 : {
1206 0 : half_pitch_cn = pitch_cn;
1207 0 : move16();
1208 0 : half_pitch_energy = L_add( pitch_energy, 0 );
1209 : }
1210 :
1211 : /* combine correlation results: Q15.16 */
1212 779 : *qualityQ16 = L_shr( L_mac0( L_mult0( half_pitch_cn, three_halves_pitch_cn ),
1213 : pitch_cn, double_pitch_cn ),
1214 : 14 );
1215 779 : move32();
1216 : BASOP_SATURATE_WARNING_OFF_EVS
1217 779 : energy = L_add( L_add( L_add( pitch_energy, half_pitch_energy ), three_halves_pitch_energy ), double_pitch_energy );
1218 : BASOP_SATURATE_WARNING_ON_EVS
1219 : }
1220 : ELSE
1221 : {
1222 341 : *qualityQ16 = L_shl( L_deposit_l( pitch_cn ), 1 ); /* value is negative, thus pass it */
1223 341 : move32();
1224 341 : energy = L_add( pitch_energy, 0 );
1225 : }
1226 :
1227 : /* update the quality by the quality of the signal with the highest energy */
1228 1120 : IF( GT_32( energy, maxEnergy ) )
1229 : {
1230 659 : qualityOfMaxEnergy = L_add( *qualityQ16, 0 );
1231 659 : maxEnergy = L_add( energy, 0 );
1232 : }
1233 :
1234 : /* go to next channel */
1235 1120 : ++signal;
1236 : }
1237 454 : *qualityQ16 = qualityOfMaxEnergy;
1238 454 : move32();
1239 :
1240 : /* increase calculated quality of signals with low energy */
1241 454 : *energydBQ8 = apa_corrEnergy2dB_fx( maxEnergy, shl( ps->signalScaleForCorrelation, 1 ), corr_len );
1242 454 : *qualityQ16 = L_add( *qualityQ16, L_shl( L_deposit_l( apa_getQualityIncreaseForLowEnergy_fx( *energydBQ8 ) ), 8 ) );
1243 454 : move16();
1244 454 : move32();
1245 454 : }
1246 :
1247 : /* Converts the correlation energy to dB. */
1248 454 : Word16 apa_corrEnergy2dB_fx( Word32 energy, Word16 energyExp, Word16 corr_len )
1249 : {
1250 :
1251 : Word16 result, tmpScale;
1252 :
1253 : /* normalise before dividing */
1254 454 : tmpScale = norm_l( energy );
1255 454 : energy = L_shl( energy, tmpScale );
1256 454 : energyExp = sub( energyExp, tmpScale );
1257 :
1258 : /* divide energy by corr_len */
1259 454 : result = BASOP_Util_Divide3216_Scale( energy, corr_len, &tmpScale );
1260 454 : energyExp = add( energyExp, tmpScale );
1261 :
1262 454 : result = BASOP_Util_lin2dB( L_deposit_l( result ), energyExp, 1 );
1263 454 : return result;
1264 : }
1265 :
1266 : /* Increases the calculated quality of signals with low energy. */
1267 454 : Word16 apa_getQualityIncreaseForLowEnergy_fx( Word16 energydBQ8 )
1268 : {
1269 : Word16 qualIncreaseMinEnergy, qualIncreaseMaxEnergy, qualIncForLowEnergy; /* Q8 */
1270 :
1271 454 : qualIncreaseMinEnergy = -65 * ( 1 << 8 ); // Q8
1272 454 : move16();
1273 454 : qualIncreaseMaxEnergy = -40 * ( 1 << 8 ); // Q8
1274 454 : move16();
1275 454 : qualIncForLowEnergy = 0;
1276 454 : move16();
1277 :
1278 : /* increase calculated quality of signals with low energy */
1279 454 : IF( LT_16( energydBQ8, qualIncreaseMaxEnergy ) )
1280 : {
1281 108 : qualIncForLowEnergy = energydBQ8;
1282 108 : move16();
1283 108 : if ( LT_16( qualIncForLowEnergy, qualIncreaseMinEnergy ) )
1284 : {
1285 0 : qualIncForLowEnergy = qualIncreaseMinEnergy;
1286 0 : move16();
1287 : }
1288 108 : if ( GT_16( qualIncForLowEnergy, qualIncreaseMaxEnergy ) )
1289 : {
1290 0 : qualIncForLowEnergy = qualIncreaseMaxEnergy;
1291 0 : move16();
1292 : }
1293 : /* -50: (-50 - -40) / (-65 - -40) * 20
1294 : * = -10 / -25 * 20
1295 : */
1296 108 : qualIncForLowEnergy = divide1616( sub( qualIncForLowEnergy, qualIncreaseMaxEnergy ),
1297 108 : sub( qualIncreaseMinEnergy, qualIncreaseMaxEnergy ) );
1298 : /* apply factor 2 and scale back to Q8 */
1299 108 : assert( qualIncForLowEnergy >= 0 );
1300 108 : qualIncForLowEnergy = shr( qualIncForLowEnergy, 7 - 1 );
1301 108 : assert( qualIncForLowEnergy >= 0 && qualIncForLowEnergy <= ( 2 << 8 ) );
1302 : }
1303 454 : return qualIncForLowEnergy;
1304 : }
1305 :
1306 :
1307 : /*
1308 : ********************************************************************************
1309 : *
1310 : * Function : logarithmic_search
1311 : * Tables : <none>
1312 : * Compile Defines : <none>
1313 : * Return : 0 on success, 1 on failure
1314 : * Information : Search for best match of a template segment using
1315 : * hierarchical search method:
1316 : * Parameter css is used for sampling every css'd correlation
1317 : * value. The area around the best match so far is used for
1318 : * further correlation value with half css-value until css=1.
1319 : * Search area length is always half previous search length.
1320 : * Parameter wss is passed to the correlation computation
1321 : * If the search area passes the boundaries, the search
1322 : * window is reduced so that it's entirely inside the
1323 : * boundaries.
1324 : *
1325 : ********************************************************************************
1326 : */
1327 454 : static Word8 logarithmic_search_fx( const apa_state_t *ps,
1328 : const Word16 *signal,
1329 : Word16 s_start,
1330 : Word16 inlen,
1331 : Word16 offset,
1332 : Word16 fixed_pos,
1333 : Word16 corr_len,
1334 : Word16 wss,
1335 : Word16 css,
1336 : Word16 *synchpos )
1337 : {
1338 : Word16 i;
1339 : Word32 coeff;
1340 : Word32 coeff_max;
1341 : Word16 s_start_old, s_len_old;
1342 :
1343 : DO
1344 : {
1345 454 : coeff_max = 0x80000000; /* will always be overwritten with result of first correlation */
1346 454 : move32();
1347 :
1348 83014 : FOR( i = s_start; i < s_start + inlen; i += css * ps->num_channels )
1349 : {
1350 82560 : test();
1351 82560 : IF( EQ_16( wss, 1 ) && EQ_16( ps->num_channels, 1 ) )
1352 : {
1353 0 : coeff = cross_correlation_self_fx( signal, add( i, offset ), add( fixed_pos, offset ), corr_len );
1354 : }
1355 : ELSE
1356 : {
1357 82560 : coeff = cross_correlation_subsampled_self_fx( signal, add( i, offset ), add( fixed_pos, offset ),
1358 82560 : corr_len, i_mult2( wss, ps->num_channels ) );
1359 : }
1360 :
1361 : /* update max corr */
1362 82560 : IF( LT_16( ps->scale, 100 ) )
1363 : {
1364 : /* shrinking: prefer greater synchpos for equal coeff */
1365 : BASOP_SATURATE_WARNING_OFF_EVS;
1366 12360 : IF( GE_32( coeff, coeff_max ) )
1367 : {
1368 1588 : coeff_max = L_add( coeff, 0 );
1369 1588 : *synchpos = i;
1370 1588 : move16();
1371 : }
1372 : BASOP_SATURATE_WARNING_ON_EVS;
1373 : }
1374 : ELSE
1375 : {
1376 : /* extending: prefer smaller synchpos for equal coeff */
1377 : BASOP_SATURATE_WARNING_OFF_EVS;
1378 70200 : IF( GT_32( coeff, coeff_max ) )
1379 : {
1380 7141 : coeff_max = L_add( coeff, 0 );
1381 7141 : *synchpos = i;
1382 7141 : move16();
1383 : }
1384 : BASOP_SATURATE_WARNING_ON_EVS;
1385 : }
1386 : }
1387 : /* backup old search range */
1388 454 : s_start_old = s_start;
1389 454 : move16();
1390 454 : s_len_old = inlen;
1391 454 : move16();
1392 :
1393 454 : css = shr( css, 1 );
1394 454 : inlen = shr( inlen, 1 );
1395 454 : s_start_old = s_start;
1396 454 : move16();
1397 454 : s_start = sub( *synchpos, shr( inlen, 1 ) );
1398 :
1399 454 : if ( LT_16( s_start, s_start_old ) )
1400 : {
1401 116 : s_start = s_start_old;
1402 116 : move16();
1403 : }
1404 :
1405 454 : IF( GT_16( add( s_start, inlen ), add( s_start_old, s_len_old ) ) )
1406 : {
1407 116 : inlen = add( sub( s_start_old, s_start ), s_len_old );
1408 : }
1409 : }
1410 454 : WHILE( ( css > 2 ) );
1411 454 : return 0;
1412 : }
1413 :
1414 : /*
1415 : ********************************************************************************
1416 : *
1417 : * Function : find_synch
1418 : * Tables : <none>
1419 : * Compile Defines : <none>
1420 : * Return : 0 on success, 1 on failure
1421 : * Information : Find the best match of an template segment within
1422 : * a search region by similarity measures.
1423 : *
1424 : * Typical example:
1425 : *
1426 : * 0 10 20 30 40 50 60
1427 : * in[] = abcdefghijk_abcdefghijk_abcdefghijk_abcdEFGHIJk_abcdefghijk_a
1428 : * l_in = 61
1429 : * offset = 30 |
1430 : * s_start = -20 <-------------------|
1431 : * s_len = 15 <-------------> |
1432 : * search range: *************** |
1433 : * fixed_pos = 10 |--------->
1434 : * corr_len = 6 | <---->
1435 : * template segment: | ******
1436 : * synch_pos: -14 <-------------|
1437 : *
1438 : * All positions are given relative to offset. The
1439 : * search region starts at offset+s_start and ends
1440 : * at offset+s_start+s_len. The template segment
1441 : * starts at offset+fixed_pos and ends at
1442 : * offset+fixed_pos+corr_len. For correlation, the
1443 : * template segment (EFGHIJ) is matched against the
1444 : * segment in the search region, e.g., against (k_abcd)
1445 : * in the first search position. The search position
1446 : * with the best match (-14: EFGHIJ <-> efghij) is
1447 : * returned.
1448 : *
1449 : * 19-JUN-03 N.Faerber initial version
1450 : * 23-APR-04 S.Doehla added subsampling
1451 : *
1452 : ********************************************************************************
1453 : */
1454 454 : static Word16 find_synch_fx( apa_state_t *ps,
1455 : const Word16 *in,
1456 : Word16 l_in,
1457 : Word16 s_start,
1458 : Word16 s_len,
1459 : Word16 fixed_pos,
1460 : Word16 corr_len,
1461 : Word16 offset,
1462 : Word16 *energydBQ8, // Q8
1463 : Word32 *qualityQ16, // Q16
1464 : Word16 *synch_pos )
1465 : {
1466 454 : assert( ( corr_len - 1 + s_start + s_len - 1 + offset ) < l_in );
1467 454 : assert( ( corr_len - 1 + fixed_pos + offset ) < l_in );
1468 :
1469 : /* pass last pitch to search function as prediction value */
1470 454 : *synch_pos = ps->last_pitch;
1471 454 : move16();
1472 454 : logarithmic_search_fx( ps,
1473 : in,
1474 : s_start,
1475 : s_len,
1476 : offset,
1477 : fixed_pos,
1478 : corr_len,
1479 454 : ps->wss,
1480 : // i_mult2( ps->css, ps->num_channels ),
1481 454 : ps->css,
1482 : synch_pos );
1483 : /* assert synch_pos is cleanly divisible by number of channels */
1484 454 : assert( *synch_pos % ps->num_channels == 0 );
1485 :
1486 454 : *qualityQ16 = 0;
1487 454 : move32();
1488 454 : get_scaling_quality_fx( ps, in, l_in, offset, corr_len,
1489 454 : abs_s( sub( *synch_pos, fixed_pos ) ), energydBQ8, qualityQ16 );
1490 454 : ps->last_pitch = *synch_pos;
1491 454 : move16();
1492 454 : return 0;
1493 : }
1494 :
1495 :
1496 : /*
1497 : ********************************************************************************
1498 : *
1499 : * Function : copy_frm
1500 : * Tables : <none>
1501 : * Compile Defines : <none>
1502 : * Return : 0 on success, 1 on failure
1503 : * Information : Copy an audio.
1504 : *
1505 : * The frame size is fixed to ps->l_frm. The input data
1506 : * is stored in frm_in[], where the first ps->l_frm samples
1507 : * shall include the previous output frame and the second
1508 : * ps->l_frm samples shall contain the current input frame.
1509 : * The output frame is stored in frm_out[] and contains
1510 : * l_frm_out = ps->l_frm.
1511 : *
1512 : * The first ps->l_frm input samples are not used by
1513 : * this function and are only provided for a consistent
1514 : * function call with shrink_frm() and extend_frm().
1515 : *
1516 : ********************************************************************************
1517 : */
1518 16 : static bool copy_frm_fx(
1519 : apa_state_t *ps,
1520 : const Word16 frm_in_fx[], // Qx
1521 : Word16 frm_out_fx[], // Qx
1522 : UWord16 *l_frm_out )
1523 : {
1524 : UWord16 i;
1525 :
1526 : /* only 2nd input frame is used */
1527 16 : frm_in_fx += ps->l_frm;
1528 :
1529 : /* copy frame */
1530 20496 : FOR( i = 0; i < ps->l_frm; i++ )
1531 : {
1532 20480 : frm_out_fx[i] = frm_in_fx[i];
1533 20480 : move16();
1534 : }
1535 :
1536 : /* set output length */
1537 16 : *l_frm_out = ps->l_frm;
1538 16 : move16();
1539 :
1540 16 : return 0;
1541 : }
1542 :
1543 : /*
1544 : ********************************************************************************
1545 : *
1546 : * Function : shrink_frm
1547 : * Tables : <none>
1548 : * Compile Defines : <none>
1549 : * Return : 0 on success, 1 on failure
1550 : * Information : Shrink the length of an audio frame using the WSOLA
1551 : * algorithm.
1552 : *
1553 : * The frame size is fixed to ps->l_frm. The input data
1554 : * is stored in frm_in[], where the first ps->l_frm samples
1555 : * shall include the previous output frame and the second
1556 : * ps->l_frm samples shall contain the current input frame.
1557 : * The output frame is stored in frm_out[] and contains
1558 : * l_frm_out samples. The amount of shrinking is signal
1559 : * dependent.
1560 : *
1561 : * The first ps->l_frm input samples are not used by
1562 : * this function and are only provided for a consistent
1563 : * function call with extend_frm().
1564 : *
1565 : ********************************************************************************
1566 : */
1567 0 : static bool shrink_frm_fx(
1568 : apa_state_t *ps,
1569 : const Word16 frm_in_fx[], // Qx
1570 : UWord16 maxScaling,
1571 : Word16 frm_out_fx[], // Qx
1572 : UWord16 *l_frm_out )
1573 : {
1574 0 : bool findSynchResult = 0;
1575 : Word16 xtract, l_rem, s_start, s_end;
1576 : UWord16 i;
1577 : UWord16 over;
1578 0 : Word16 energy_fx = 0;
1579 0 : Word32 quality_fx = 0;
1580 : UWord16 l_frm;
1581 : UWord16 l_seg;
1582 0 : move16();
1583 0 : move32();
1584 :
1585 0 : l_frm = ps->l_frm;
1586 0 : move16();
1587 0 : l_seg = ps->l_seg;
1588 0 : move16();
1589 :
1590 : /* only 2nd input frame is used */
1591 0 : frm_in_fx += l_frm;
1592 :
1593 : /* set search range */
1594 : // s_start = ( ps->p_min / ps->num_channels ) * ps->num_channels;
1595 : Word16 tmp, tmp_e;
1596 0 : tmp = BASOP_Util_Divide3232_Scale( ps->p_min, ps->num_channels, &tmp_e );
1597 0 : tmp = shr( tmp, sub( 15, tmp_e ) );
1598 0 : s_start = i_mult( tmp, extract_l( ps->num_channels ) );
1599 0 : s_end = add( s_start, extract_l( ps->l_search ) );
1600 0 : IF( GE_32( L_add( s_end, l_seg ), l_frm ) )
1601 : {
1602 0 : s_end = extract_l( L_sub( l_frm, l_seg ) );
1603 : }
1604 :
1605 : /* calculate overlap position */
1606 0 : IF( isSilence_fx( frm_in_fx, l_seg, 10 ) )
1607 : {
1608 : /* maximum scaling */
1609 0 : energy_fx = -65 * ( 1 << 8 ); // Q8
1610 0 : move16();
1611 0 : quality_fx = 5 << Q16; // Q16
1612 0 : move32();
1613 0 : IF( ps->evs_compat_mode == false )
1614 : {
1615 :
1616 0 : xtract = maxScaling;
1617 0 : move16();
1618 : /* take samples already in the renderer buf into account */
1619 0 : xtract = add( xtract, extract_l( ps->l_r_buf ) );
1620 : /* snap to renderer time slot borders */
1621 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 ) ) );
1622 0 : WHILE( xtract < 0 )
1623 : {
1624 0 : xtract = add( xtract, extract_l( ps->l_ts ) );
1625 : }
1626 0 : WHILE( GT_32( xtract, sub( s_end, extract_l( ps->num_channels ) ) ) )
1627 : {
1628 : /* exceeded the possible shrinking, go back one renderer ts*/
1629 0 : xtract = sub( xtract, extract_l( ps->l_ts ) );
1630 : }
1631 : }
1632 0 : ELSE IF( maxScaling != 0U && GT_16( s_end, add( extract_l( maxScaling ), 1 ) ) )
1633 : {
1634 0 : xtract = maxScaling;
1635 0 : move16();
1636 : }
1637 : ELSE
1638 : {
1639 : /* set to last valid element (i.e. element[len - 1] but note for stereo last element is last pair of samples) */
1640 0 : xtract = sub( s_end, extract_l( ps->num_channels ) );
1641 : }
1642 : }
1643 : ELSE
1644 : {
1645 : /* find synch */
1646 0 : scaleSignal16( frm_in_fx, ps->frmInScaled, l_frm, ps->signalScaleForCorrelation );
1647 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 );
1648 : }
1649 :
1650 : /* assert synch_pos is cleanly divisible by number of channels */
1651 0 : assert( xtract % ps->num_channels == 0 );
1652 :
1653 : /* set frame overlappable - reset if necessary */
1654 0 : over = 1;
1655 0 : move16();
1656 :
1657 : /* test whether frame has sufficient quality */
1658 0 : IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
1659 : L_mult0( ps->bad_frame_count, 6554 ) ),
1660 : L_mult0( ps->good_frame_count, 13107 ) ) ) )
1661 : {
1662 : /* not sufficient */
1663 0 : over = 0;
1664 0 : move16();
1665 0 : IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
1666 : {
1667 0 : ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
1668 0 : move16();
1669 : }
1670 0 : IF( GT_32( ps->good_frame_count, 0 ) )
1671 : {
1672 0 : ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
1673 0 : move16();
1674 : }
1675 : }
1676 : ELSE
1677 : {
1678 : /* sufficient quality */
1679 0 : IF( GT_32( ps->bad_frame_count, 0 ) )
1680 : {
1681 0 : ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
1682 0 : move16();
1683 : }
1684 0 : IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
1685 : {
1686 0 : ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
1687 0 : move16();
1688 : }
1689 : }
1690 :
1691 : /* Calculate output data */
1692 0 : test();
1693 0 : IF( over && xtract )
1694 : {
1695 0 : IF( findSynchResult == 1 )
1696 : {
1697 0 : return 1;
1698 : }
1699 0 : IF( ps->evs_compat_mode == true )
1700 : {
1701 : // 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 );
1702 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 );
1703 : }
1704 : ELSE
1705 : {
1706 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 );
1707 : }
1708 : }
1709 : ELSE
1710 : {
1711 0 : xtract = 0;
1712 0 : move16();
1713 0 : FOR( i = 0; i < l_seg; i++ )
1714 : {
1715 0 : frm_out_fx[i] = frm_in_fx[i];
1716 0 : move16();
1717 : }
1718 : }
1719 :
1720 : /* append remaining samples */
1721 0 : l_rem = extract_l( L_sub( L_sub( l_frm, xtract ), l_seg ) );
1722 0 : FOR( i = 0; i < l_rem; i++ )
1723 : {
1724 0 : frm_out_fx[l_seg + i] = frm_in_fx[l_frm - l_rem + i];
1725 0 : move16();
1726 : }
1727 :
1728 : /* set output length */
1729 0 : *l_frm_out = u_extract_l( UL_addNsD( l_seg, l_rem ) );
1730 0 : move16();
1731 :
1732 0 : return 0;
1733 : }
1734 :
1735 103 : static bool shrink_frm_ivas_fx(
1736 : apa_state_t *ps,
1737 : const Word16 frm_in_fx[], // Qx
1738 : UWord16 maxScaling,
1739 : Word16 frm_out_fx[], // Qx
1740 : Word16 Q_frm_in,
1741 : UWord16 *l_frm_out )
1742 : {
1743 103 : bool findSynchResult = 0;
1744 103 : move16();
1745 : Word16 xtract, l_rem, s_start, s_end;
1746 : UWord16 i;
1747 : UWord16 over;
1748 103 : Word16 energy_fx = 0;
1749 103 : Word32 quality_fx = 0;
1750 : UWord16 l_frm;
1751 : UWord16 l_seg;
1752 103 : move16();
1753 103 : move32();
1754 :
1755 103 : l_frm = ps->l_frm;
1756 103 : move16();
1757 103 : l_seg = ps->l_seg;
1758 103 : move16();
1759 :
1760 : /* only 2nd input frame is used */
1761 103 : frm_in_fx += l_frm;
1762 :
1763 : /* set search range */
1764 : // s_start = ( ps->p_min / ps->num_channels ) * ps->num_channels;
1765 : Word16 tmp, tmp_e;
1766 103 : tmp = BASOP_Util_Divide3232_Scale( ps->p_min, ps->num_channels, &tmp_e );
1767 103 : tmp = shr( tmp, sub( 15, tmp_e ) );
1768 103 : s_start = i_mult( tmp, extract_l( ps->num_channels ) );
1769 103 : s_end = add( s_start, extract_l( ps->l_search ) );
1770 103 : IF( GE_32( L_add( s_end, l_seg ), l_frm ) )
1771 : {
1772 103 : s_end = extract_l( L_sub( l_frm, l_seg ) );
1773 : }
1774 :
1775 : /* calculate overlap position */
1776 103 : IF( isSilence_ivas_fx( frm_in_fx, Q_frm_in, l_seg, 10 ) )
1777 : {
1778 : /* maximum scaling */
1779 0 : energy_fx = -65 * ( 1 << 8 ); // Q8
1780 0 : move16();
1781 0 : quality_fx = 5 << Q16; // Q16
1782 0 : move32();
1783 0 : IF( ps->evs_compat_mode == false )
1784 : {
1785 :
1786 0 : xtract = maxScaling;
1787 0 : move16();
1788 : /* take samples already in the renderer buf into account */
1789 0 : xtract = add( xtract, extract_l( ps->l_r_buf ) );
1790 : /* snap to renderer time slot borders */
1791 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 ) ) );
1792 0 : WHILE( xtract < 0 )
1793 : {
1794 0 : xtract = add( xtract, extract_l( ps->l_ts ) );
1795 : }
1796 0 : WHILE( GT_32( xtract, sub( s_end, extract_l( ps->num_channels ) ) ) )
1797 : {
1798 : /* exceeded the possible shrinking, go back one renderer ts*/
1799 0 : xtract = sub( xtract, extract_l( ps->l_ts ) );
1800 : }
1801 : }
1802 0 : ELSE IF( maxScaling != 0U && GT_16( s_end, add( extract_l( maxScaling ), 1 ) ) )
1803 : {
1804 0 : xtract = maxScaling;
1805 0 : move16();
1806 : }
1807 : ELSE
1808 : {
1809 : /* set to last valid element (i.e. element[len - 1] but note for stereo last element is last pair of samples) */
1810 0 : xtract = sub( s_end, extract_l( ps->num_channels ) );
1811 : }
1812 : }
1813 : ELSE
1814 : {
1815 : /* find synch */
1816 103 : scaleSignal16( frm_in_fx, ps->frmInScaled, l_frm, ps->signalScaleForCorrelation );
1817 103 : ps->signalScaleForCorrelation = sub( ps->signalScaleForCorrelation, Q_frm_in );
1818 103 : move16();
1819 103 : 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 );
1820 103 : ps->signalScaleForCorrelation = add( ps->signalScaleForCorrelation, Q_frm_in );
1821 103 : move16();
1822 : }
1823 :
1824 : /* assert synch_pos is cleanly divisible by number of channels */
1825 103 : assert( xtract % ps->num_channels == 0 );
1826 :
1827 : /* set frame overlappable - reset if necessary */
1828 103 : over = 1;
1829 103 : move16();
1830 :
1831 : /* test whether frame has sufficient quality */
1832 103 : IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
1833 : L_mult0( ps->bad_frame_count, 6554 /*0.1 (Q16)*/ ) ),
1834 : L_mult0( ps->good_frame_count, 13107 /*0.2 (Q16)*/ ) ) ) )
1835 : {
1836 : /* not sufficient */
1837 79 : over = 0;
1838 79 : move16();
1839 79 : IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
1840 : {
1841 31 : ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
1842 31 : move16();
1843 : }
1844 79 : IF( GT_32( ps->good_frame_count, 0 ) )
1845 : {
1846 25 : ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
1847 25 : move16();
1848 : }
1849 : }
1850 : ELSE
1851 : {
1852 : /* sufficient quality */
1853 24 : IF( ps->bad_frame_count > 0 )
1854 : {
1855 24 : ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
1856 24 : move16();
1857 : }
1858 24 : IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
1859 : {
1860 24 : ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
1861 24 : move16();
1862 : }
1863 : }
1864 :
1865 : /* Calculate output data */
1866 103 : test();
1867 103 : IF( over && xtract )
1868 : {
1869 24 : IF( findSynchResult == 1 )
1870 : {
1871 0 : return 1;
1872 : }
1873 24 : IF( EQ_16( ps->evs_compat_mode, true ) )
1874 : {
1875 : // 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 );
1876 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 );
1877 : }
1878 : ELSE
1879 : {
1880 24 : 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 );
1881 : }
1882 : }
1883 : ELSE
1884 : {
1885 79 : xtract = 0;
1886 79 : move16();
1887 58319 : FOR( i = 0; i < l_seg; i++ )
1888 : {
1889 58240 : frm_out_fx[i] = frm_in_fx[i];
1890 58240 : move16();
1891 : }
1892 : }
1893 :
1894 : /* append remaining samples */
1895 103 : l_rem = extract_l( L_sub( L_sub( l_frm, xtract ), l_seg ) );
1896 65015 : FOR( i = 0; i < l_rem; i++ )
1897 : {
1898 64912 : frm_out_fx[l_seg + i] = frm_in_fx[l_frm - l_rem + i];
1899 64912 : move16();
1900 : }
1901 :
1902 : /* set output length */
1903 103 : *l_frm_out = u_extract_l( UL_addNsD( l_seg, l_rem ) );
1904 103 : move16();
1905 :
1906 103 : return 0;
1907 : }
1908 :
1909 : /*
1910 : ********************************************************************************
1911 : *
1912 : * Function : extend_frm
1913 : * Tables : <none>
1914 : * Compile Defines : <none>
1915 : * Return : 0 on success, 1 on failure
1916 : * Information : Extend the length of an audio frame using the WSOLA
1917 : * algorithm.
1918 : *
1919 : * The frame size is fixed to ps->l_frm. The input data
1920 : * is stored in frm_in[], where the first ps->l_frm samples
1921 : * shall include the previous output frame and the second
1922 : * ps->l_frm samples shall contain the current input frame.
1923 : * The output frame is stored in frm_out[] and contains
1924 : * l_frm_out samples. The amount of extension is signal
1925 : * dependent.
1926 : *
1927 : ********************************************************************************
1928 : */
1929 0 : static bool extend_frm_fx(
1930 : apa_state_t *ps,
1931 : const Word16 frm_in_fx[], // Qx
1932 : Word16 frm_out_fx[], // Qx
1933 : UWord16 *l_frm_out )
1934 : {
1935 0 : bool findSynchResult = 0;
1936 : UWord16 l_frm_out_target;
1937 : UWord16 n, i;
1938 : Word16 N;
1939 : Word16 s[MAXN + 2], s_max, s_min;
1940 : Word16 xtract[MAXN + 2], sync_start, s_end;
1941 : UWord16 over[MAXN + 2];
1942 : Word16 l_rem;
1943 0 : Word16 s_start = 0;
1944 0 : move16();
1945 : Word16 energy_fx;
1946 0 : Word32 quality_fx = 0;
1947 0 : move32();
1948 : UWord16 l_frm, l_seg;
1949 : const Word16 *fadeOut_fx, *fadeIn_fx;
1950 : Word16 *out_fx;
1951 :
1952 0 : l_frm = ps->l_frm;
1953 0 : l_seg = ps->l_seg;
1954 0 : move16();
1955 0 : move16();
1956 : /* number of segments/iterations */
1957 0 : l_frm_out_target = (UWord16) ( L_add( l_frm, L_shr( l_frm, 1 ) ) );
1958 : //(l_frm_out_target/l_seg -1 )
1959 : Word16 tmp, tmp_e;
1960 0 : tmp = BASOP_Util_Divide3232_Scale( l_frm_out_target, l_seg, &tmp_e );
1961 0 : tmp = shr( tmp, sub( 15, tmp_e ) );
1962 0 : N = sub( ( tmp ), 1 );
1963 0 : if ( LT_16( N, 1 ) )
1964 : {
1965 0 : N = 1;
1966 0 : move16();
1967 : }
1968 0 : IF( GT_16( N, MAXN ) )
1969 : {
1970 0 : return 1;
1971 : }
1972 : /* calculate equally spaced search regions */
1973 : /* s[n] are given relative to 2nd frame and point to the start of */
1974 : /* the search region. The first segment (n=1) will not be moved. */
1975 : /* Hence, the iterations will start with n=2. */
1976 0 : s_min = extract_l( L_negate( L_add( ps->l_search, ps->p_min ) ) );
1977 : /* (make sure not to exceed array dimension) */
1978 0 : IF( L_add( l_frm, s_min ) < 0 )
1979 : {
1980 0 : s_min = extract_l( L_negate( l_frm ) );
1981 : }
1982 0 : s_max = extract_l( L_sub( L_sub( l_frm, L_shl( l_seg, 1 ) ), ps->l_search ) );
1983 0 : if ( s_max < s_min )
1984 : {
1985 0 : N = 1;
1986 0 : move16();
1987 : }
1988 : /* for just one segment start at s_min */
1989 0 : if ( N == 1 )
1990 : {
1991 0 : s[2] = s_min;
1992 0 : move16();
1993 : }
1994 : /* else, spread linear in between s_min and s_max */
1995 : /* (including s_min and s_max) */
1996 : ELSE
1997 : {
1998 0 : FOR( n = 2; n <= ( N + 1 ); n++ )
1999 : {
2000 : // s[n] = s_min + ( ( s_max - s_min ) * ( n - 2 ) ) / ( N - 1 );
2001 : Word16 tmp2, tmp2_e;
2002 0 : tmp2 = sub( s_max, s_min );
2003 0 : tmp2 = i_mult( tmp2, extract_l( L_sub( n, 2 ) ) );
2004 0 : tmp2 = BASOP_Util_Divide1616_Scale( tmp2, sub( N, 1 ), &tmp2_e );
2005 0 : tmp2 = shr( tmp2, sub( 15, tmp2_e ) );
2006 0 : s[n] = add( s_min, tmp2 );
2007 0 : move16();
2008 : }
2009 : }
2010 :
2011 : /*
2012 : * Planning Phase
2013 : */
2014 :
2015 0 : xtract[1] = extract_l( L_negate( l_seg ) ); /* make sync_start=0 in 1st iteration */
2016 0 : move16();
2017 0 : n = 2;
2018 0 : move16();
2019 : /* define synch segment (to be correlated with search region) */
2020 0 : sync_start = extract_l( L_add( xtract[n - 1], l_seg ) );
2021 0 : over[n] = 1; /* will be reset if overlap is not required */
2022 0 : move16();
2023 : /* check end of search region: should be at least p_min */
2024 : /* samples on the left of synch_start */
2025 0 : IF( LT_32( L_add( s[n], ps->l_search ), L_sub( sync_start, ( ps->p_min ) ) ) )
2026 : {
2027 0 : s_start = s[n];
2028 0 : move16();
2029 0 : s_end = extract_l( L_add( s_start, ps->l_search ) );
2030 : }
2031 : ELSE
2032 : {
2033 : /* shrink search region to enforce minimum shift */
2034 0 : s_end = extract_l( L_sub( sync_start, ( ps->p_min ) ) );
2035 0 : IF( LT_16( extract_l( L_add( s[n], ps->l_search ) ), sync_start ) )
2036 : {
2037 0 : s_start = s[n]; /* just do it with normal start position */
2038 0 : move16();
2039 : }
2040 0 : ELSE IF( EQ_32( n, L_add( N, 1 ) ) ) /* move search region left for last segment */
2041 : {
2042 0 : s_start = extract_l( L_sub( s_end, L_sub( ps->l_search, ps->p_min ) ) );
2043 : }
2044 : ELSE
2045 : {
2046 0 : over[n] = 0; /* don't search/overlap (just copy down) */
2047 0 : move16();
2048 : }
2049 : }
2050 :
2051 0 : IF( over[n] )
2052 : {
2053 : /* calculate overlap position */
2054 0 : IF( isSilence_fx( frm_in_fx, l_seg, 10 ) )
2055 : {
2056 : /* maximum scaling */
2057 0 : energy_fx = -65 * ( 1 << 8 ); // Q8
2058 0 : move16();
2059 0 : quality_fx = 5 << 16; // Q16
2060 0 : move32();
2061 0 : xtract[n] = extract_l( L_add( s_start, ps->num_channels ) );
2062 0 : move16();
2063 0 : IF( ps->evs_compat_mode == false )
2064 : {
2065 : /* take renderer buffer samples into accout */
2066 0 : xtract[n] = extract_l( L_add( xtract[n], ps->l_r_buf ) );
2067 : /* snap to next renderer time slot border to resynchronize */
2068 : // xtract[n] -= ( ( N - 1 ) * l_seg - xtract[n] + ps->l_r_buf ) % ps->l_ts;
2069 : Word16 tmp3;
2070 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 ) );
2071 0 : xtract[n] = sub( xtract[n], tmp3 % ps->l_ts );
2072 0 : move16();
2073 0 : move16();
2074 : }
2075 : }
2076 : ELSE
2077 : {
2078 : Word16 *frmInScaled;
2079 0 : frmInScaled = ps->frmInScaled;
2080 0 : assert( sizeof( ps->frmInScaled ) / sizeof( ps->frmInScaled[0] ) >= 2 * (size_t) l_frm );
2081 0 : scaleSignal16( frm_in_fx, frmInScaled, shl( l_frm, 1 ), ps->signalScaleForCorrelation );
2082 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] );
2083 : }
2084 : /* assert synch_pos is cleanly divisible by number of channels */
2085 0 : assert( xtract[n] % ps->num_channels == 0 );
2086 :
2087 : /* test for sufficient quality */
2088 0 : IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
2089 : L_mult0( ps->bad_frame_count, 6554 /*.1f in Q16*/ ) ),
2090 : L_mult0( ps->good_frame_count, 13107 /*.1f in Q16*/ ) ) ) )
2091 : {
2092 : /* not sufficient */
2093 0 : over[n] = 0;
2094 0 : move16();
2095 0 : xtract[n] = sync_start;
2096 0 : move16();
2097 0 : IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
2098 : {
2099 0 : ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
2100 0 : move16();
2101 : }
2102 0 : IF( GT_32( ps->good_frame_count, 0 ) )
2103 : {
2104 0 : ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
2105 0 : move16();
2106 : }
2107 : }
2108 : ELSE
2109 : {
2110 : /* sufficient quality */
2111 0 : IF( GT_32( ps->bad_frame_count, 0 ) )
2112 : {
2113 0 : ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
2114 0 : move16();
2115 : }
2116 0 : IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
2117 : {
2118 0 : ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
2119 0 : move16();
2120 : }
2121 : }
2122 0 : IF( findSynchResult )
2123 : {
2124 0 : return 1;
2125 : }
2126 : }
2127 : ELSE
2128 : {
2129 0 : xtract[n] = sync_start;
2130 0 : move16();
2131 : }
2132 :
2133 :
2134 : /* Calculate output data */
2135 0 : FOR( n = 2; n <= N; n++ )
2136 : {
2137 0 : test();
2138 0 : IF( over[n] && NE_16( extract_l( L_add( xtract[n - 1], l_seg ) ), xtract[n] ) )
2139 : {
2140 : /* mix 2nd half of previous segment with 1st half of current segment */
2141 0 : fadeOut_fx = frm_in_fx + l_frm + xtract[n - 1] + l_seg;
2142 0 : fadeIn_fx = frm_in_fx + l_frm + xtract[n];
2143 0 : out_fx = frm_out_fx + ( n - 2 ) * l_seg;
2144 0 : IF( ps->evs_compat_mode == true )
2145 : {
2146 : // overlapAddEvs_fx( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx );
2147 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 );
2148 : }
2149 : ELSE
2150 : {
2151 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 );
2152 : }
2153 : }
2154 : ELSE
2155 : {
2156 : /* just copy down 1st half of current segment (= 2nd half of previous segment) */
2157 : Word16 *frm_out_ptr;
2158 : const Word16 *frm_in_ptr;
2159 0 : frm_out_ptr = &( frm_out_fx[( n - 2 ) * l_seg] );
2160 0 : frm_in_ptr = &( frm_in_fx[l_frm + xtract[n]] );
2161 0 : FOR( i = 0; i < l_seg; i++ )
2162 : {
2163 0 : frm_out_ptr[i] = frm_in_ptr[i];
2164 0 : move16();
2165 : }
2166 : }
2167 : }
2168 :
2169 : /* append remaining samples */
2170 0 : l_rem = l_frm - ( xtract[N] + l_seg );
2171 0 : FOR( i = 0; i < l_rem; i++ )
2172 : {
2173 0 : frm_out_fx[( N - 1 ) * l_seg + i] = frm_in_fx[2 * l_frm - l_rem + i];
2174 0 : move16();
2175 : }
2176 :
2177 : /* set output length */
2178 0 : *l_frm_out = (UWord16) ( W_mult0_32_32( L_sub( N, 1 ), L_add( l_seg, l_rem ) ) );
2179 0 : move16();
2180 0 : return 0;
2181 : }
2182 :
2183 :
2184 351 : static bool extend_frm_ivas_fx(
2185 : apa_state_t *ps,
2186 : const Word16 frm_in_fx[], // Qx
2187 : Word16 frm_out_fx[], // Qx
2188 : Word16 Q_frm_in,
2189 : UWord16 *l_frm_out )
2190 : {
2191 351 : bool findSynchResult = 0;
2192 351 : move16();
2193 : UWord16 l_frm_out_target;
2194 : UWord16 n, i;
2195 : Word16 N;
2196 : Word16 s[MAXN + 2], s_max, s_min;
2197 : Word16 xtract[MAXN + 2], sync_start, s_end;
2198 : UWord16 over[MAXN + 2];
2199 : Word16 l_rem;
2200 351 : Word16 s_start = 0;
2201 351 : move16();
2202 : Word16 energy_fx;
2203 351 : Word32 quality_fx = 0;
2204 351 : move32();
2205 : UWord16 l_frm, l_seg;
2206 : const Word16 *fadeOut_fx, *fadeIn_fx;
2207 : Word16 *out_fx;
2208 :
2209 351 : l_frm = ps->l_frm;
2210 351 : l_seg = ps->l_seg;
2211 351 : move16();
2212 351 : move16();
2213 : /* number of segments/iterations */
2214 351 : l_frm_out_target = (UWord16) ( L_add( l_frm, L_shr( l_frm, 1 ) ) );
2215 : //(l_frm_out_target/l_seg -1 )
2216 : Word16 tmp, tmp_e;
2217 351 : tmp = BASOP_Util_Divide3232_Scale( l_frm_out_target, l_seg, &tmp_e );
2218 351 : tmp = shr( tmp, sub( 15, tmp_e ) );
2219 351 : N = sub( ( tmp ), 1 );
2220 351 : if ( LT_16( N, 1 ) )
2221 : {
2222 0 : N = 1;
2223 0 : move16();
2224 : }
2225 351 : IF( GT_16( N, MAXN ) )
2226 : {
2227 0 : return 1;
2228 : }
2229 : /* calculate equally spaced search regions */
2230 : /* s[n] are given relative to 2nd frame and point to the start of */
2231 : /* the search region. The first segment (n=1) will not be moved. */
2232 : /* Hence, the iterations will start with n=2. */
2233 351 : s_min = extract_l( L_negate( L_add( ps->l_search, ps->p_min ) ) );
2234 : /* (make sure not to exceed array dimension) */
2235 351 : IF( L_add( l_frm, s_min ) < 0 )
2236 : {
2237 0 : s_min = extract_l( L_negate( l_frm ) );
2238 : }
2239 351 : s_max = extract_l( L_sub( L_sub( l_frm, L_shl( l_seg, 1 ) ), ps->l_search ) );
2240 351 : if ( s_max < s_min )
2241 : {
2242 0 : N = 1;
2243 0 : move16();
2244 : }
2245 : /* for just one segment start at s_min */
2246 351 : if ( N == 1 )
2247 : {
2248 0 : s[2] = s_min;
2249 0 : move16();
2250 : }
2251 : /* else, spread linear in between s_min and s_max */
2252 : /* (including s_min and s_max) */
2253 : ELSE
2254 : {
2255 1053 : FOR( n = 2; n <= ( N + 1 ); n++ )
2256 : {
2257 : // s[n] = s_min + ( ( s_max - s_min ) * ( n - 2 ) ) / ( N - 1 );
2258 : Word16 tmp2, tmp2_e;
2259 702 : tmp2 = sub( s_max, s_min );
2260 702 : tmp2 = i_mult( tmp2, extract_l( L_sub( n, 2 ) ) );
2261 702 : tmp2 = BASOP_Util_Divide1616_Scale( tmp2, sub( N, 1 ), &tmp2_e );
2262 702 : tmp2 = shr( tmp2, sub( 15, tmp2_e ) );
2263 702 : s[n] = add( s_min, tmp2 );
2264 702 : move16();
2265 : }
2266 : }
2267 :
2268 : /*
2269 : * Planning Phase
2270 : */
2271 :
2272 351 : xtract[1] = extract_l( L_negate( l_seg ) ); /* make sync_start=0 in 1st iteration */
2273 351 : move16();
2274 351 : n = 2;
2275 351 : move16();
2276 : /* define synch segment (to be correlated with search region) */
2277 351 : sync_start = extract_l( L_add( xtract[n - 1], l_seg ) );
2278 351 : over[n] = 1; /* will be reset if overlap is not required */
2279 351 : move16();
2280 : /* check end of search region: should be at least p_min */
2281 : /* samples on the left of synch_start */
2282 351 : IF( LT_32( L_add( s[n], ps->l_search ), L_sub( sync_start, ( ps->p_min ) ) ) )
2283 : {
2284 0 : s_start = s[n];
2285 0 : move16();
2286 0 : s_end = extract_l( L_add( s_start, ps->l_search ) );
2287 : }
2288 : ELSE
2289 : {
2290 : /* shrink search region to enforce minimum shift */
2291 351 : s_end = extract_l( L_sub( sync_start, ( ps->p_min ) ) );
2292 351 : IF( LT_16( extract_l( L_add( s[n], ps->l_search ) ), sync_start ) )
2293 : {
2294 351 : s_start = s[n]; /* just do it with normal start position */
2295 351 : move16();
2296 : }
2297 0 : ELSE IF( EQ_32( n, L_add( N, 1 ) ) ) /* move search region left for last segment */
2298 : {
2299 0 : s_start = extract_l( L_sub( s_end, L_sub( ps->l_search, ps->p_min ) ) );
2300 : }
2301 : ELSE
2302 : {
2303 0 : over[n] = 0; /* don't search/overlap (just copy down) */
2304 0 : move16();
2305 : }
2306 : }
2307 :
2308 351 : IF( over[n] )
2309 : {
2310 : /* calculate overlap position */
2311 351 : IF( isSilence_ivas_fx( frm_in_fx, Q_frm_in, l_seg, 10 ) )
2312 : {
2313 : /* maximum scaling */
2314 0 : energy_fx = -65 * ( 1 << 8 ); // Q8
2315 0 : move16();
2316 0 : quality_fx = 5 << 16; // Q16
2317 0 : move32();
2318 0 : xtract[n] = extract_l( L_add( s_start, ps->num_channels ) );
2319 0 : move16();
2320 0 : IF( ps->evs_compat_mode == false )
2321 : {
2322 : /* take renderer buffer samples into accout */
2323 0 : xtract[n] = extract_l( L_add( xtract[n], ps->l_r_buf ) );
2324 : /* snap to next renderer time slot border to resynchronize */
2325 : // xtract[n] -= ( ( N - 1 ) * l_seg - xtract[n] + ps->l_r_buf ) % ps->l_ts;
2326 : Word16 tmp3;
2327 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 ) );
2328 0 : xtract[n] = sub( xtract[n], tmp3 % ps->l_ts );
2329 0 : move16();
2330 0 : move16();
2331 : }
2332 : }
2333 : ELSE
2334 : {
2335 : Word16 *frmInScaled;
2336 351 : frmInScaled = ps->frmInScaled;
2337 351 : assert( sizeof( ps->frmInScaled ) / sizeof( ps->frmInScaled[0] ) >= 2 * (size_t) l_frm );
2338 351 : scaleSignal16( frm_in_fx, frmInScaled, shl( l_frm, 1 ), ps->signalScaleForCorrelation );
2339 351 : ps->signalScaleForCorrelation = sub( ps->signalScaleForCorrelation, Q_frm_in );
2340 351 : 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] );
2341 351 : ps->signalScaleForCorrelation = add( ps->signalScaleForCorrelation, Q_frm_in );
2342 : }
2343 : /* assert synch_pos is cleanly divisible by number of channels */
2344 351 : assert( xtract[n] % ps->num_channels == 0 );
2345 :
2346 : /* test for sufficient quality */
2347 351 : IF( LT_32( quality_fx, L_add( L_sub( ps->targetQuality_fx,
2348 : L_mult0( ps->bad_frame_count, 6554 /*.1f in Q16*/ ) ),
2349 : L_mult0( ps->good_frame_count, 13107 /*.1f in Q16*/ ) ) ) )
2350 : {
2351 : /* not sufficient */
2352 310 : over[n] = 0;
2353 310 : move16();
2354 310 : xtract[n] = sync_start;
2355 310 : move16();
2356 310 : IF( LT_32( ps->bad_frame_count, ps->qualityred ) )
2357 : {
2358 97 : ps->bad_frame_count = u_extract_l( UL_addNsD( ps->bad_frame_count, 1 ) );
2359 97 : move16();
2360 : }
2361 310 : IF( GT_32( ps->good_frame_count, 0 ) )
2362 : {
2363 16 : ps->good_frame_count = u_extract_l( UL_subNsD( ps->good_frame_count, 1 ) );
2364 16 : move16();
2365 : }
2366 : }
2367 : ELSE
2368 : {
2369 : /* sufficient quality */
2370 41 : IF( GT_32( ps->bad_frame_count, 0 ) )
2371 : {
2372 40 : ps->bad_frame_count = u_extract_l( UL_subNsD( ps->bad_frame_count, 1 ) );
2373 40 : move16();
2374 : }
2375 41 : IF( LT_32( ps->good_frame_count, ps->qualityrise ) )
2376 : {
2377 41 : ps->good_frame_count = u_extract_l( UL_addNsD( ps->good_frame_count, 1 ) );
2378 41 : move16();
2379 : }
2380 : }
2381 351 : IF( findSynchResult )
2382 : {
2383 0 : return 1;
2384 : }
2385 : }
2386 : ELSE
2387 : {
2388 0 : xtract[n] = sync_start;
2389 0 : move16();
2390 : }
2391 :
2392 :
2393 : /* Calculate output data */
2394 702 : FOR( n = 2; n <= N; n++ )
2395 : {
2396 351 : test();
2397 351 : IF( over[n] && NE_16( extract_l( L_add( xtract[n - 1], l_seg ) ), xtract[n] ) )
2398 : {
2399 : /* mix 2nd half of previous segment with 1st half of current segment */
2400 41 : fadeOut_fx = frm_in_fx + l_frm + xtract[n - 1] + l_seg;
2401 41 : fadeIn_fx = frm_in_fx + l_frm + xtract[n];
2402 41 : out_fx = frm_out_fx + ( n - 2 ) * l_seg;
2403 41 : IF( EQ_16( ps->evs_compat_mode, true ) )
2404 : {
2405 : // overlapAddEvs_fx( fadeOut_fx, fadeIn_fx, out_fx, l_seg, ps->num_channels, ps->win_fx + ps->l_halfwin_fx, ps->win_fx );
2406 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 );
2407 : }
2408 : ELSE
2409 : {
2410 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 );
2411 : }
2412 : }
2413 : ELSE
2414 : {
2415 : /* just copy down 1st half of current segment (= 2nd half of previous segment) */
2416 : Word16 *frm_out_ptr;
2417 : const Word16 *frm_in_ptr;
2418 310 : frm_out_ptr = &( frm_out_fx[( n - 2 ) * l_seg] );
2419 310 : frm_in_ptr = &( frm_in_fx[l_frm + xtract[n]] );
2420 335030 : FOR( i = 0; i < l_seg; i++ )
2421 : {
2422 334720 : frm_out_ptr[i] = frm_in_ptr[i];
2423 334720 : move16();
2424 : }
2425 : }
2426 : }
2427 :
2428 : /* append remaining samples */
2429 351 : l_rem = l_frm - ( xtract[N] + l_seg );
2430 422626 : FOR( i = 0; i < l_rem; i++ )
2431 : {
2432 422275 : frm_out_fx[( N - 1 ) * l_seg + i] = frm_in_fx[2 * l_frm - l_rem + i];
2433 422275 : move16();
2434 : }
2435 :
2436 : /* set output length */
2437 351 : *l_frm_out = (UWord16) ( W_mult0_32_32( L_sub( N, 1 ), L_add( l_seg, l_rem ) ) );
2438 351 : move16();
2439 351 : return 0;
2440 : }
|