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 : #include <stdint.h>
34 : #include "options.h"
35 : #include "prot_fx.h"
36 : #include "ivas_prot_rend_fx.h"
37 : #include "ivas_cnst.h"
38 : #include "math.h"
39 : #include "ivas_rom_rend.h"
40 : #include <assert.h>
41 : #include "wmc_auto.h"
42 : #include "debug.h"
43 : #define float_to_fix( n, factor ) ( round( n * ( 1 << factor ) ) )
44 : #define float_to_fixQ31( n ) ( round( n * 0x7fffffff ) )
45 : #define fix_to_float( n, factor ) ( (float) n / ( 1 << factor ) )
46 :
47 1626 : static Word16 wrap_rad_fixed(
48 : Word32 angle /* Q13 */ )
49 : {
50 1626 : Word32 L_tmp = angle;
51 1626 : move32();
52 :
53 : /* Wrap azimuth value */
54 4065 : WHILE( GT_32( L_tmp, EVS_PI_FX ) )
55 : {
56 2439 : L_tmp = L_sub( L_tmp, EVS_2PI_FX );
57 : }
58 1626 : WHILE( LE_32( L_tmp, -EVS_PI_FX ) )
59 : {
60 0 : L_tmp = L_add( L_tmp, EVS_2PI_FX );
61 : }
62 :
63 1626 : return extract_l( L_tmp );
64 : }
65 :
66 : /* The reverberator structure implemented here is described in detail in:
67 : * Vilkamo, J., Neugebauer, B., & Plogsties, J. (2012). Sparse frequency-domain reverberator.
68 : * Journal of the Audio Engineering Society, 59(12), 936-943. */
69 :
70 : /*-------------------------------------------------------------------------
71 : * Local constants
72 : *------------------------------------------------------------------------*/
73 :
74 : #define BIN_REND_RANDOM_SEED 1 /* random seed for generating reverb decorrelators */
75 :
76 : #define CLDFB_SLOTS_PER_SECOND 800 /* Used for initializing reverb */
77 :
78 : #define INNER_BLK_SIZE 80 /* size of data blocks used for more efficient delay line and IIR filter processing */
79 : /* should be a divisor of the frame length at any sampling rate and an even number*/
80 : #define FFT_FILTER_WND_FLAT_REGION ( 0.40f ) /* flat section (==1) length of FFT filter window, in proportion to overlap */
81 : #define FFT_FILTER_WND_TRANS_REGION ( 0.15f ) /* transition (1->0) length of FFT filter window, in proportion to overlap */
82 : #define FFT_FILTER_WND_FLAT_REGION_FX ( 26214 ) /*Q16 flat section (==1) length of FFT filter window, in proportion to overlap */
83 : #define FFT_FILTER_WND_TRANS_REGION_FX ( 9830 ) /*Q16 transition (1->0) length of FFT filter window, in proportion to overlap */
84 : #define REF_LF_MIN ( 100.0f )
85 : #define REF_LF_MAX ( 250.0f )
86 : #define REF_HF_MIN ( 5000.0f )
87 : #define REF_HF_MAX ( 7950.0f )
88 :
89 : #define REF_LF_MIN_FX ( 100 )
90 : #define REF_LF_MAX_FX ( 250 )
91 : #define REF_HF_MIN_FX ( 5000 )
92 : #define REF_HF_MAX_FX ( 7950 )
93 : #define LF_BIAS ( 0.5f )
94 :
95 : #define DEFAULT_SRC_DIST ( 1.5f ) /* default source distance [m] for reverb dmx factor computing */
96 : #define DMX_GAIN ( 1410542208 )
97 : #define IVAS_REVERB_FFT_SIZE_48K ( 512 )
98 : #define IVAS_REVERB_FFT_SIZE_32K ( 512 )
99 : #define IVAS_REVERB_FFT_SIZE_16K ( 256 )
100 : #define IVAS_REVERB_FFT_N_SUBBLOCKS_48K ( 1 )
101 : #define IVAS_REVERB_FFT_N_SUBBLOCKS_32K ( 1 )
102 : #define IVAS_REVERB_FFT_N_SUBBLOCKS_16K ( 1 )
103 :
104 : #define MAX_NR_OUTPUTS ( 2 )
105 :
106 : const Word16 init_loop_delay[IVAS_REV_MAX_NR_BRANCHES] = { 37, 31, 29, 23, 19, 17, 13, 11 };
107 : const Word16 default_loop_delay_48k[IVAS_REV_MAX_NR_BRANCHES] = { 2309, 1861, 1523, 1259, 1069, 919, 809, 719 };
108 : const Word16 default_loop_delay_32k[IVAS_REV_MAX_NR_BRANCHES] = { 1531, 1237, 1013, 839, 709, 613, 541, 479 };
109 : const Word16 default_loop_delay_16k[IVAS_REV_MAX_NR_BRANCHES] = { 769, 619, 509, 421, 353, 307, 269, 239 };
110 :
111 : /*------------------------------------------------------------------------------------------*
112 : * Local Struct definition
113 : *------------------------------------------------------------------------------------------*/
114 : typedef struct ivas_reverb_params_t
115 : {
116 : Word16 pre_delay; /* Delay of the FDC reverb, first peak after pre_delay samples. Note that */
117 : /* there may be non-zero samples earlier due to the filters being */
118 : /* linear-phase. */
119 : Word16 nr_loops; /* Number of feedback loops (= L) */
120 : Word16 pLoop_delays[IVAS_REV_MAX_NR_BRANCHES]; /* Delay for each feedback loop in samples. */ /* Feedback [L][L] matrix that mixes the signals of the loops. */
121 : Word32 pLoop_feedback_matrix_fx[IVAS_REV_MAX_NR_BRANCHES * IVAS_REV_MAX_NR_BRANCHES]; /* Feedback [L][L] matrix that mixes the signals of the loops. */
122 : Word16 nr_outputs; /* Nr of signals extracted from the loops (= S). */
123 : /* Currently this is fixed to 2. */ /* Mix [S][L] matrix from feedback loops to outputs. */
124 : Word16 pLoop_extract_matrix_fx[MAX_NR_OUTPUTS * IVAS_REV_MAX_NR_BRANCHES]; /* Mix [S][L] matrix from feedback loops to outputs. */ /* In Matlab: [S x L] - Currently S=2, later may be more than 2 for speaker playback. */
125 : Word16 t60_filter_order; /* Filter order (length of vector) */
126 : // float pT60_filter_coeff[MAX_NR_OUTPUTS * IVAS_REV_MAX_NR_BRANCHES * IVAS_REV_MAX_IIR_FILTER_LENGTH]; /* Filters [][] in feedback loops, controlling T60. */
127 : Word16 pT60_filter_coeff_fx[MAX_NR_OUTPUTS * IVAS_REV_MAX_NR_BRANCHES * IVAS_REV_MAX_IIR_FILTER_LENGTH];
128 : /* In Matlab: IIR: [(2 * L) x (<order> + 1)] (odd: b-vector, even: a-vector) */
129 : /* In Matlab: FIR: [L x <order>] */
130 : // float *pFc; /* Center frequencies for FFT filter design */
131 : // float *pRt60; /* RT60 values at these frequencies */
132 : // float *pDsr; /* DSR values at these frequencies */
133 : Word32 *pFc_fx; /* Center frequencies for FFT filter design */
134 : Word32 *pRt60_fx; /* RT60 values at these frequencies */
135 : Word16 *pRt60_e; /* exponents for RT60 values at these frequencies */
136 : Word32 *pDsr_fx; /* DSR values at these frequencies */
137 : Word16 *pDsr_e; /* DSR values at these frequencies */
138 : // float *pHrtf_avg_pwr_response_l; /* The HRTF set's average left ear power response */
139 : // float *pHrtf_avg_pwr_response_r; /* The HRTF set's average right ear power response */
140 : // float *pHrtf_inter_aural_coherence; /* The HRTF set's inter-aural coherence for diffuse sound */
141 : // const float *pHrtf_avg_pwr_response_l_const; /* The HRTF set's average left ear power response */
142 : // const float *pHrtf_avg_pwr_response_r_const; /* The HRTF set's average right ear power response */
143 : // const float *pHrtf_inter_aural_coherence_const; /* The HRTF set's inter-aural coherence for diffuse sound */
144 :
145 : Word32 *pHrtf_avg_pwr_response_l_fx; /* The HRTF set's average left ear power response */
146 : Word32 *pHrtf_avg_pwr_response_r_fx; /* The HRTF set's average right ear power response */
147 : Word32 *pHrtf_inter_aural_coherence_fx; /* The HRTF set's inter-aural coherence for diffuse sound */
148 : const Word32 *pHrtf_avg_pwr_response_l_const_fx; /* The HRTF set's average left ear power response */
149 : const Word32 *pHrtf_avg_pwr_response_r_const_fx; /* The HRTF set's average right ear power response */
150 : const Word32 *pHrtf_inter_aural_coherence_const_fx; /* The HRTF set's inter-aural coherence for diffuse sound */
151 : Word16 do_corr_filter; /* Flag indicating whether correlation filters should be used. */
152 : /* Correlation only supported and needed for binaural playback (i.e. */
153 : /* when nr_outputs != 2 correlation filtering is never supported). */
154 : } ivas_reverb_params_t;
155 :
156 : /*------------------------------------------------------------------------------------------*
157 : * Static functions declarations
158 : *------------------------------------------------------------------------------------------*/
159 :
160 : static ivas_error calc_jot_t60_coeffs_fx( Word16 *pH_dB_fx, Word16 pH_dB_exp, const UWord16 nrFrequencies, Word16 *pFrequencies_fx, Word16 *pCoeffA_fx, Word16 *pCoeffB_fx, const Word16 fNyquist_fx );
161 :
162 : /*-------------------------------------------------------------------------
163 : * binRend_rand()
164 : *
165 : *
166 : *------------------------------------------------------------------------*/
167 :
168 1516034 : static UWord16 binRend_rand(
169 : REVERB_STRUCT_HANDLE hReverb /* i/o: binaural reverb handle */
170 : )
171 : {
172 1516034 : hReverb->binRend_RandNext = hReverb->binRend_RandNext * 1103515245 + 12345;
173 :
174 1516034 : return (UWord16) ( hReverb->binRend_RandNext / 65536 ) % 32768;
175 : }
176 :
177 :
178 : /*-------------------------------------------------------------------------
179 : * ivas_binaural_reverb_setPreDelay()
180 : *
181 : *
182 : *------------------------------------------------------------------------*/
183 :
184 271 : static void ivas_binaural_reverb_setPreDelay_fx(
185 : REVERB_STRUCT_HANDLE hReverb, /* i/o: binaural reverb handle */
186 : const Word16 delaySamples /* i : reverb pre-delay in CLDFB slots */
187 : )
188 : {
189 271 : IF( LT_16( delaySamples, 1 ) )
190 : {
191 0 : hReverb->preDelayBufferLength = 1;
192 0 : move16();
193 :
194 0 : return;
195 : }
196 :
197 271 : IF( GT_16( delaySamples, REVERB_PREDELAY_MAX ) )
198 : {
199 0 : hReverb->preDelayBufferLength = REVERB_PREDELAY_MAX;
200 0 : move16();
201 :
202 0 : return;
203 : }
204 :
205 271 : hReverb->preDelayBufferLength = delaySamples;
206 271 : move16();
207 :
208 271 : return;
209 : }
210 :
211 :
212 : /*-------------------------------------------------------------------------
213 : * ivas_binaural_reverb_setReverbTimes()
214 : *
215 : *
216 : *------------------------------------------------------------------------*/
217 :
218 :
219 271 : static void ivas_binaural_reverb_setReverbTimes_fx(
220 : REVERB_STRUCT_HANDLE hReverb, /* i/o: binaural reverb handle */
221 : const Word32 output_Fs, /* i : sampling_rate */
222 : const Word32 *revTimes_fx, /*Q31 i : reverberation times T60 for each CLDFB bin in seconds */
223 : const Word32 *revEnes_fx /*Q31 i : spectrum for reverberated sound at each CLDFB bin */
224 : )
225 : {
226 : Word16 bin, ch, tap, sample;
227 :
228 : Word32 binCenterFreq_fx, diffuseFieldICC_fx, tmpVal_fx, attenuationFactorPerSample_fx, L_tmp;
229 : Word32 intendedEnergy_fx, actualizedEnergy_fx, energyBuildup_fx, currentEnergy_fx, attenuationFactorPerSampleSq_fx;
230 : Word16 tmp, tmp_exp, scale, tmpVal_exp, attenuationFactorPerSample_exp, attenuationFactorPerSampleSq_exp, energyBuildup_exp, currentEnergy_exp, intendedEnergy_exp, actualizedEnergy_exp;
231 : Word16 sine_inp, norm, div_exp1, div1, sine, binCenterFreq_exp;
232 271 : Word16 reverb_exp = 0;
233 271 : move16();
234 :
235 271 : hReverb->binRend_RandNext = (UWord16) BIN_REND_RANDOM_SEED;
236 271 : move16();
237 271 : hReverb->highestBinauralCoherenceBin = 0;
238 271 : move16();
239 :
240 12371 : FOR( bin = 0; bin < hReverb->numBins; bin++ )
241 : {
242 : /* Determine the diffuse field binaural coherence */
243 : Word16 exp;
244 12100 : tmp_exp = BASOP_Util_Add_MantExp( bin, 15, 1, 14, &tmp );
245 12100 : tmp = BASOP_Util_Divide3232_Scale( L_deposit_h( tmp ), L_deposit_h( hReverb->numBins ), &exp );
246 12100 : exp = add( exp, sub( tmp_exp, 15 ) );
247 12100 : L_tmp = Mpy_32_16_1( output_Fs, tmp ); /*- exp */
248 12100 : binCenterFreq_exp = add( 31, exp );
249 12100 : binCenterFreq_fx = L_shr( L_tmp, 1 ); // divide by 2
250 12100 : IF( bin == 0 )
251 : {
252 271 : diffuseFieldICC_fx = ONE_IN_Q31;
253 271 : move32();
254 : }
255 11829 : ELSE IF( EQ_16( BASOP_Util_Cmp_Mant32Exp( binCenterFreq_fx, binCenterFreq_exp, 2700, 31 ), -1 ) )
256 : {
257 : /* binCenterFreq / 550.0f */
258 1626 : L_tmp = Mpy_32_32( binCenterFreq_fx, 3904516 /* 1 / 550 in Q31 */ );
259 1626 : norm = norm_l( L_tmp );
260 1626 : tmp = extract_h( L_shl( L_tmp, norm ) );
261 1626 : tmp = add( mult( EVS_PI_FX, tmp ), EPSILLON_FX ); // to avoid divide by 0 issue
262 1626 : tmp_exp = sub( add( binCenterFreq_exp, 2 ), norm );
263 :
264 1626 : sine_inp = wrap_rad_fixed( L_shl( tmp, sub( tmp_exp, 2 ) ) ); // Q13
265 :
266 1626 : sine = getSinWord16( sine_inp ); // Q15
267 1626 : div1 = BASOP_Util_Divide1616_Scale( sine, tmp, &scale );
268 1626 : div_exp1 = add( scale, sub( 0, tmp_exp ) );
269 1626 : div1 = shl( div1, div_exp1 ); /* Q15 */
270 :
271 : /* binCenterFreq / 2700.0f */
272 1626 : L_tmp = Mpy_32_32( binCenterFreq_fx, 795364 /* 1 / 2700 in Q31 */ );
273 1626 : norm = norm_l( L_tmp );
274 1626 : L_tmp = L_shl( L_tmp, norm ); /* Q31 */
275 :
276 : /* ( 1.0f - binCenterFreq / 2700.0f ) */
277 1626 : L_tmp = L_sub( ONE_IN_Q31, L_tmp ); /* Q31 */
278 :
279 1626 : diffuseFieldICC_fx = Mpy_32_16_1( L_tmp, div1 ); /* Q31 */
280 :
281 1626 : hReverb->highestBinauralCoherenceBin = bin;
282 1626 : move16();
283 : }
284 : ELSE
285 : {
286 :
287 10203 : diffuseFieldICC_fx = 0;
288 10203 : move32();
289 : }
290 :
291 : /* Mixing gains to generate a diffuse-binaural sound based on incoherent sound */
292 : /* tmpVal = ( 1.0f - sqrtf( 1.0f - powf( diffuseFieldICC, 2.0 ) ) ) / 2.0f; */
293 12100 : L_tmp = Mpy_32_32( diffuseFieldICC_fx, diffuseFieldICC_fx ); // square
294 12100 : L_tmp = L_sub( ONE_IN_Q31, L_tmp );
295 12100 : scale = 0;
296 12100 : L_tmp = Sqrt32( L_tmp, &scale );
297 12100 : L_tmp = L_shl( L_tmp, scale ); /* Q31 */
298 12100 : tmpVal_fx = L_shr( L_sub( ONE_IN_Q31, L_tmp ), 1 );
299 12100 : tmpVal_exp = 0;
300 12100 : move16();
301 :
302 12100 : IF( diffuseFieldICC_fx > 0 )
303 : {
304 813 : exp = tmpVal_exp;
305 813 : move16();
306 813 : L_tmp = Sqrt32( L_abs( tmpVal_fx ), &exp );
307 813 : hReverb->binauralCoherenceCrossmixGains_fx[bin] = L_shl( L_tmp, exp ); // Q31
308 : }
309 : ELSE
310 : {
311 11287 : exp = tmpVal_exp;
312 11287 : move16();
313 11287 : L_tmp = Sqrt32( L_abs( tmpVal_fx ), &exp );
314 11287 : hReverb->binauralCoherenceCrossmixGains_fx[bin] = L_negate( L_shl( L_tmp, exp ) ); // Q31
315 : }
316 :
317 : /* hReverb->binauralCoherenceDirectGains[bin] = sqrtf( 1.0f - fabsf( tmpVal ) ); */
318 12100 : exp = tmpVal_exp;
319 12100 : move16();
320 12100 : L_tmp = L_sub( ONE_IN_Q31, L_abs( tmpVal_fx ) );
321 12100 : L_tmp = Sqrt32( L_abs( L_tmp ), &exp );
322 12100 : hReverb->binauralCoherenceDirectGains_fx[bin] = L_shl( L_tmp, exp ); // making as Q31
323 :
324 : /* Determine attenuation factor that generates the appropriate energy decay according to reverberation time */
325 12100 : L_tmp = Mpy_32_32( 1677721600, revTimes_fx[bin] ); // e10 --> 800 * 2^21, + e0
326 12100 : tmp = BASOP_Util_Divide3232_Scale( 1073741824, L_tmp, &scale );
327 12100 : scale = add( scale, sub( 1, 10 ) );
328 12100 : L_tmp = Mpy_32_16_1( -1610612736, tmp ); // * -3
329 12100 : scale = add( 2, scale );
330 12100 : L_tmp = Mpy_32_32( 1783446563, L_tmp ); // scale + 2
331 12100 : attenuationFactorPerSample_fx = BASOP_util_Pow2( L_tmp, add( scale, 2 ), &attenuationFactorPerSample_exp );
332 :
333 : Word32 tmp_mul;
334 12100 : scale = norm_l( hReverb->loopBufLength[bin] );
335 12100 : tmp_mul = L_shl( hReverb->loopBufLength[bin], scale );
336 12100 : L_tmp = BASOP_Util_Log2( attenuationFactorPerSample_fx ); // Q25
337 12100 : L_tmp = L_add( L_tmp, L_shl( (Word32) attenuationFactorPerSample_exp, 25 ) ); // Q25
338 12100 : L_tmp = Mpy_32_32( L_tmp, tmp_mul );
339 12100 : L_tmp = BASOP_util_Pow2( L_tmp, sub( 6 + 31, scale ), &exp );
340 12100 : hReverb->loopAttenuationFactor_fx[bin] = L_shl( L_tmp, exp ); // making as Q31
341 :
342 12100 : attenuationFactorPerSampleSq_fx = Mpy_32_32( attenuationFactorPerSample_fx, attenuationFactorPerSample_fx );
343 12100 : attenuationFactorPerSampleSq_exp = attenuationFactorPerSample_exp + attenuationFactorPerSample_exp;
344 :
345 : /* Design sparse decorrelation filters. The decorrelation filters, due to random procedures involved,
346 : * may affect the spectrum of the output. The spectral effect is therefore monitored and compensated for. */
347 :
348 12100 : intendedEnergy_fx = 0;
349 12100 : move32();
350 12100 : intendedEnergy_exp = 0;
351 12100 : move16();
352 12100 : actualizedEnergy_fx = 0;
353 12100 : move32();
354 12100 : actualizedEnergy_exp = 0;
355 12100 : move16();
356 :
357 36300 : FOR( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
358 : {
359 :
360 24200 : energyBuildup_fx = 0;
361 24200 : move32();
362 24200 : energyBuildup_exp = 0;
363 24200 : move16();
364 24200 : currentEnergy_fx = ONE_IN_Q30;
365 24200 : move32();
366 24200 : currentEnergy_exp = 1;
367 24200 : move16();
368 :
369 24200 : tap = 0;
370 24200 : move16();
371 :
372 1218720 : FOR( sample = 0; sample < hReverb->loopBufLength[bin]; sample++ )
373 : {
374 1194520 : intendedEnergy_fx = BASOP_Util_Add_Mant32Exp( intendedEnergy_fx, intendedEnergy_exp, currentEnergy_fx, currentEnergy_exp, &intendedEnergy_exp );
375 : /* The randomization at the energy build up affects where the sparse taps are located */
376 :
377 1194520 : UWord16 ret_binRend = binRend_rand( hReverb );
378 :
379 1194520 : tmp = BASOP_Util_Divide3232_Scale( ret_binRend, PCM16_TO_FLT_FAC_FX, &tmp_exp );
380 1194520 : L_tmp = BASOP_Util_Add_Mant32Exp( L_deposit_h( tmp ), tmp_exp, L_negate( 1073741824 ), 0, &exp );
381 1194520 : L_tmp = Mpy_32_32( L_tmp, 214748364 ); // exp + 0
382 1194520 : L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, exp, currentEnergy_fx, currentEnergy_exp, &exp );
383 1194520 : energyBuildup_fx = BASOP_Util_Add_Mant32Exp( energyBuildup_fx, energyBuildup_exp, L_tmp, exp, &energyBuildup_exp );
384 1194520 : IF( energyBuildup_fx >= 0 ) /* A new filter tap is added at this condition */
385 : {
386 1194024 : IF( ( BASOP_Util_Cmp_Mant32Exp( energyBuildup_fx, energyBuildup_exp, 1, 31 ) > 0 ) )
387 : {
388 : /* Four efficient phase operations: n*pi/2, n=0,1,2,3 */
389 321514 : hReverb->tapPhaseShiftType[bin][ch][tap] = (Word16) ( binRend_rand( hReverb ) % 4 );
390 321514 : move16();
391 : /* Set the tapPointer to point to the determined sample at the loop buffer */
392 :
393 321514 : hReverb->tapPointersReal_fx[bin][ch][tap] = &( hReverb->loopBufReal_fx[bin][sample] );
394 321514 : hReverb->tapPointersImag_fx[bin][ch][tap] = &( hReverb->loopBufImag_fx[bin][sample] );
395 :
396 321514 : energyBuildup_fx = BASOP_Util_Add_Mant32Exp( energyBuildup_fx, energyBuildup_exp, L_negate( 1073741824 ), 1, &energyBuildup_exp ); /* A tap is added, thus remove its energy from the buildup */
397 :
398 321514 : tap = add( tap, 1 );
399 :
400 321514 : actualizedEnergy_fx = BASOP_Util_Add_Mant32Exp( actualizedEnergy_fx, actualizedEnergy_exp, 1073741824, 1, &actualizedEnergy_exp );
401 : }
402 : }
403 :
404 1194520 : currentEnergy_fx = BASOP_Util_Add_Mant32Exp( currentEnergy_fx, currentEnergy_exp, 0, 0, ¤tEnergy_exp );
405 1194520 : currentEnergy_fx = Mpy_32_32( currentEnergy_fx, attenuationFactorPerSampleSq_fx );
406 1194520 : currentEnergy_exp = currentEnergy_exp + attenuationFactorPerSampleSq_exp;
407 : }
408 24200 : hReverb->taps[bin][ch] = tap; /* Number of taps determined at the above random procedure */
409 24200 : move16();
410 : }
411 :
412 : /* The decorrelator design and IIR attenuation rate affects the energy of reverb, which is compensated here */
413 12100 : reverb_exp = 0;
414 12100 : move16();
415 12100 : hReverb->reverbEqGains_fx[bin] = Sqrt32( revEnes_fx[bin], &reverb_exp ); /* Determined reverb spectrum */
416 12100 : move32();
417 12100 : hReverb->reverbEqGains_fx[bin] = BASOP_Util_Add_Mant32Exp( hReverb->reverbEqGains_fx[bin], reverb_exp, 0, 0, &reverb_exp );
418 12100 : move32();
419 :
420 12100 : tmp = BASOP_Util_Divide3232_Scale( intendedEnergy_fx, actualizedEnergy_fx, &tmp_exp );
421 12100 : tmp_exp = add( tmp_exp, sub( intendedEnergy_exp, actualizedEnergy_exp ) );
422 12100 : hReverb->reverbEqGains_fx[bin] = BASOP_Util_Add_Mant32Exp( hReverb->reverbEqGains_fx[bin], reverb_exp, 0, 0, &reverb_exp );
423 12100 : move32();
424 12100 : L_tmp = Sqrt32( L_deposit_h( tmp ), &tmp_exp );
425 12100 : hReverb->reverbEqGains_fx[bin] = Mpy_32_32( hReverb->reverbEqGains_fx[bin], L_tmp );
426 12100 : move32();
427 12100 : reverb_exp = add( reverb_exp, tmp_exp );
428 :
429 12100 : L_tmp = BASOP_Util_Add_Mant32Exp( 1073741824, 1, L_negate( attenuationFactorPerSampleSq_fx ), attenuationFactorPerSampleSq_exp, &tmp_exp );
430 12100 : L_tmp = Mpy_32_32( L_tmp, 1073741824 ); // tmp_exp + 1
431 12100 : tmp_exp = add( tmp_exp, 0 );
432 12100 : L_tmp = Sqrt32( L_tmp, &tmp_exp );
433 12100 : hReverb->reverbEqGains_fx[bin] = Mpy_32_32( L_tmp, hReverb->reverbEqGains_fx[bin] );
434 12100 : move32();
435 12100 : reverb_exp = add( reverb_exp, tmp_exp );
436 12100 : hReverb->reverbEqGains_fx[bin] = L_shl( hReverb->reverbEqGains_fx[bin], reverb_exp ); // making as Q31
437 12100 : move32();
438 : }
439 271 : return;
440 : }
441 :
442 : /*-----------------------------------------------------------------------------------------*
443 : * Function compute_feedback_matrix()
444 : *
445 : * Compute the N x N matrix for the mixing the N feedback loop outputs into the N inputs again
446 : *-----------------------------------------------------------------------------------------*/
447 :
448 159 : static ivas_error compute_feedback_matrix_fx(
449 : Word32 *pFeedbackMatrix, // Q31
450 : const Word16 n )
451 : {
452 : Word32 u;
453 : Word16 i, j, x;
454 :
455 159 : u = MATRIX_CONSTANT; // Q31
456 159 : move32();
457 :
458 159 : pFeedbackMatrix[0] = u;
459 159 : move32();
460 636 : FOR( x = 1; x < n; x += x )
461 : {
462 1590 : FOR( i = 0; i < x; i++ )
463 : {
464 4452 : FOR( j = 0; j < x; j++ )
465 : {
466 3339 : pFeedbackMatrix[add( i_mult( add( i, x ), n ), j )] = pFeedbackMatrix[add( i_mult( i, n ), j )];
467 3339 : move32();
468 3339 : pFeedbackMatrix[i_mult( i, n ) + j + x] = pFeedbackMatrix[add( i_mult( i, n ), j )];
469 3339 : move32();
470 3339 : pFeedbackMatrix[add( add( i_mult( add( i, x ), n ), j ), x )] = L_negate( pFeedbackMatrix[add( i_mult( i, n ), j )] );
471 3339 : move32();
472 : }
473 : }
474 : }
475 :
476 :
477 159 : return IVAS_ERR_OK;
478 : }
479 :
480 :
481 : /*-----------------------------------------------------------------------------------------*
482 : * Function compute_2_out_extract_matrix()
483 : *
484 : * Compute the N x 2 matrix for mixing the N Jot feedback loops to 2 outputs
485 : *-----------------------------------------------------------------------------------------*/
486 :
487 159 : static void compute_2_out_extract_matrix_fx(
488 : Word16 *pExtractMatrix,
489 : const Word16 n )
490 : {
491 : Word16 ff;
492 : Word16 i;
493 :
494 159 : ff = 1;
495 159 : move16();
496 :
497 1431 : FOR( i = 0; i < n; i++ )
498 : {
499 1272 : pExtractMatrix[i] = 1;
500 1272 : move16();
501 1272 : pExtractMatrix[add( i, n )] = ff;
502 1272 : move16();
503 1272 : ff = negate( ff );
504 : }
505 :
506 159 : return;
507 : }
508 : /*-----------------------------------------------------------------------------------------*
509 : * Function set_base_config()
510 : *
511 : * Set all jot reverb parameters that are independent of the input reverb configuration
512 : *-----------------------------------------------------------------------------------------*/
513 :
514 159 : static ivas_error set_base_config_fx(
515 : ivas_reverb_params_t *pParams,
516 : const Word32 output_Fs )
517 : {
518 : ivas_error error;
519 : Word16 loop_idx;
520 159 : const Word16 *selected_loop_delay = NULL;
521 :
522 159 : IF( pParams == NULL )
523 : {
524 0 : return IVAS_ERR_INTERNAL;
525 : }
526 :
527 159 : pParams->pre_delay = 0;
528 159 : move16();
529 159 : pParams->nr_outputs = BINAURAL_CHANNELS;
530 159 : move16();
531 159 : pParams->nr_loops = IVAS_REV_MAX_NR_BRANCHES;
532 159 : move16();
533 :
534 : /* set loop delays to default */
535 159 : IF( EQ_32( output_Fs, 48000 ) )
536 : {
537 98 : selected_loop_delay = default_loop_delay_48k; // Q0
538 : }
539 61 : ELSE IF( EQ_32( output_Fs, 32000 ) )
540 : {
541 0 : selected_loop_delay = default_loop_delay_32k; // Q0
542 : }
543 61 : ELSE IF( EQ_32( output_Fs, 16000 ) )
544 : {
545 61 : selected_loop_delay = default_loop_delay_16k; // Q0
546 : }
547 :
548 1431 : FOR( loop_idx = 0; loop_idx < pParams->nr_loops; loop_idx++ )
549 : {
550 1272 : pParams->pLoop_delays[loop_idx] = selected_loop_delay[loop_idx];
551 1272 : move16();
552 : }
553 :
554 : /* set feedback and output matrices */
555 159 : IF( NE_32( ( error = compute_feedback_matrix_fx( pParams->pLoop_feedback_matrix_fx, pParams->nr_loops ) ), IVAS_ERR_OK ) )
556 : {
557 0 : return error;
558 : }
559 :
560 159 : compute_2_out_extract_matrix_fx( pParams->pLoop_extract_matrix_fx, pParams->nr_loops );
561 : /* pre-set the various filters; they will be set later based on reverb configuration */
562 159 : pParams->t60_filter_order = 1; /* set to 1 in base config. */
563 159 : move16();
564 :
565 159 : IF( EQ_16( pParams->nr_outputs, 2 ) )
566 : {
567 159 : pParams->do_corr_filter = 1;
568 159 : move16();
569 : }
570 : ELSE
571 : {
572 0 : pParams->do_corr_filter = 0;
573 0 : move16();
574 : }
575 :
576 159 : return IVAS_ERR_OK;
577 : }
578 :
579 : /*-----------------------------------------------------------------------------------------*
580 : * Function calc_dmx_gain()
581 : *
582 : * Computes the downmix gain
583 : *-----------------------------------------------------------------------------------------*/
584 159 : static Word32 calc_dmx_gain_fx( void )
585 : {
586 159 : const Word32 gain = DMX_GAIN; // Q25
587 159 : move32();
588 159 : return gain;
589 : }
590 : /*-----------------------------------------------------------------------------------------*
591 : * Function calc_predelay()
592 : *
593 : * Calculate the predelay, taking shortest jot loop delay into account
594 : *-----------------------------------------------------------------------------------------*/
595 :
596 159 : static void calc_predelay_fx(
597 : ivas_reverb_params_t *pParams,
598 : Word32 acoustic_predelay_sec,
599 : const Word32 output_Fs )
600 : {
601 : Word16 predelay, fbdelay, output_frame;
602 159 : predelay = round_fx( L_shl( Mult_32_32( L_shl( output_Fs, 15 ), acoustic_predelay_sec ), 5 ) );
603 159 : output_frame = extract_l( Mult_32_16( output_Fs, INV_FRAME_PER_SEC_Q15 ) );
604 159 : fbdelay = pParams->pLoop_delays[sub( pParams->nr_loops, 1 )];
605 159 : move16();
606 159 : predelay = sub( predelay, fbdelay );
607 :
608 159 : if ( predelay < 0 )
609 : {
610 0 : predelay = 0;
611 0 : move16();
612 : }
613 :
614 159 : if ( LT_16( output_frame, predelay ) )
615 : {
616 0 : predelay = output_frame; // Q0
617 0 : move16();
618 : }
619 :
620 159 : pParams->pre_delay = predelay; // Q0
621 159 : move16();
622 159 : move16();
623 159 : move16();
624 159 : return;
625 : }
626 :
627 : /*-----------------------------------------------------------------------------------------*
628 : * Function compute_t60_coeffs()
629 : *
630 : * Calculate Jot reverb's T60 filter coefficients
631 : *-----------------------------------------------------------------------------------------*/
632 159 : static ivas_error compute_t60_coeffs_fx(
633 : ivas_reverb_params_t *pParams,
634 : const Word16 nr_fc_fft_filter, /*Q0*/
635 : const Word32 output_Fs )
636 : {
637 : Word16 bin_idx, loop_idx, tf_T60_len, len;
638 : ivas_error error;
639 :
640 : Word16 loop_delay_sec_fx, norm_f_e, tmp;
641 159 : Word32 freq_Nyquist_fx = L_shr( output_Fs, 1 );
642 : Word16 target_gains_db_fx[RV_LENGTH_NR_FC];
643 : Word16 norm_f_fx[RV_LENGTH_NR_FC];
644 : Word32 *targetT60_fx, *pFc_fx;
645 : Word16 *pCoeffs_a_fx, *pCoeffs_b_fx, *targetT60_e;
646 : Word16 target_gains_db_exp[RV_LENGTH_NR_FC];
647 159 : error = IVAS_ERR_OK;
648 159 : move32();
649 159 : tf_T60_len = nr_fc_fft_filter;
650 159 : move16();
651 159 : len = add( pParams->t60_filter_order, 1 );
652 :
653 159 : pFc_fx = pParams->pFc_fx;
654 159 : targetT60_fx = pParams->pRt60_fx;
655 159 : targetT60_e = pParams->pRt60_e;
656 159 : move16();
657 :
658 33214 : FOR( bin_idx = 0; bin_idx < tf_T60_len; bin_idx++ )
659 : {
660 33055 : norm_f_fx[bin_idx] = BASOP_Util_Divide3232_Scale( pFc_fx[bin_idx], freq_Nyquist_fx, &norm_f_e );
661 33055 : move16();
662 33055 : norm_f_e = add( norm_f_e, sub( 17, 31 ) );
663 33055 : norm_f_fx[bin_idx] = shl( norm_f_fx[bin_idx], sub( norm_f_e, 1 ) ); // making Q14
664 33055 : move16();
665 : }
666 :
667 1431 : FOR( loop_idx = 0; loop_idx < pParams->nr_loops; loop_idx++ )
668 : {
669 :
670 : Word16 loop_delay_sec_fx_exp;
671 1272 : loop_delay_sec_fx = BASOP_Util_Divide3232_Scale( pParams->pLoop_delays[loop_idx], output_Fs, &loop_delay_sec_fx_exp );
672 :
673 265712 : FOR( bin_idx = 0; bin_idx < tf_T60_len; bin_idx++ )
674 : {
675 264440 : tmp = BASOP_Util_Divide3232_Scale( L_deposit_h( loop_delay_sec_fx ), targetT60_fx[bin_idx], &target_gains_db_exp[bin_idx] );
676 264440 : target_gains_db_exp[bin_idx] = add( target_gains_db_exp[bin_idx], sub( loop_delay_sec_fx_exp, targetT60_e[bin_idx] ) );
677 264440 : move16();
678 264440 : target_gains_db_fx[bin_idx] = mult( -30720, tmp ); // -60 in Q9 -> -30720
679 264440 : move16();
680 264440 : target_gains_db_exp[bin_idx] = add( target_gains_db_exp[bin_idx], 6 ); // Q9 -> e6
681 264440 : move16();
682 :
683 264440 : tmp = BASOP_Util_Cmp_Mant32Exp( L_deposit_h( target_gains_db_fx[bin_idx] ), target_gains_db_exp[bin_idx], -2013265920, 7 );
684 264440 : IF( tmp < 0 )
685 : {
686 0 : target_gains_db_fx[bin_idx] = -30720; // -60 in Q9 -> -30720
687 0 : move16();
688 0 : target_gains_db_exp[bin_idx] = 7;
689 0 : move16();
690 : }
691 : }
692 :
693 1272 : pCoeffs_a_fx = &pParams->pT60_filter_coeff_fx[add( shl( i_mult( len, loop_idx ), 1 ), len )]; // Q14
694 1272 : pCoeffs_b_fx = &pParams->pT60_filter_coeff_fx[shl( i_mult( len, loop_idx ), 1 )]; // Q14
695 :
696 1272 : Word16 val = target_gains_db_exp[0];
697 1272 : move16();
698 :
699 264440 : FOR( Word16 i = 1; i < nr_fc_fft_filter; i++ )
700 : {
701 263168 : val = s_max( val, target_gains_db_exp[i] );
702 : }
703 :
704 265712 : FOR( Word16 i = 0; i < nr_fc_fft_filter; i++ )
705 : {
706 264440 : target_gains_db_fx[i] = shr( target_gains_db_fx[i], sub( val, target_gains_db_exp[i] ) );
707 264440 : move16();
708 : }
709 :
710 1272 : IF( NE_32( ( error = calc_jot_t60_coeffs_fx( target_gains_db_fx, val, tf_T60_len, norm_f_fx, pCoeffs_a_fx, pCoeffs_b_fx, extract_l( freq_Nyquist_fx ) ) ), IVAS_ERR_OK ) )
711 : {
712 0 : return error;
713 : }
714 : }
715 :
716 159 : len = shr( ( add( pParams->t60_filter_order, 1 ) ), 1 ); // Q0// /* == floor( (order+1) / 2) */
717 1431 : FOR( loop_idx = 0; loop_idx < pParams->nr_loops; loop_idx++ )
718 : {
719 1272 : pParams->pLoop_delays[loop_idx] = sub( pParams->pLoop_delays[loop_idx], len ); // Q0
720 1272 : move16();
721 : }
722 159 : return error;
723 : }
724 :
725 :
726 : /*-----------------------------------------------------------------------------------------*
727 : * Function calc_low_shelf_first_order_filter()
728 : *
729 : * Calculate 1st order low shelf filter
730 : *-----------------------------------------------------------------------------------------*/
731 :
732 :
733 1272 : static void calc_low_shelf_first_order_filter_fx(
734 : Word16 *pNum, /* Q14 */
735 : Word16 *pDen, /* Q14 */
736 : const Word16 f0,
737 : const Word16 lin_gain_lf,
738 : const Word16 lin_gain_hf )
739 : {
740 : Word16 sine_val, shift;
741 : Word16 cos_val, tmp, tan_val, tan_exp, gain_exp, exp, norm_num0, norm_num1, norm_den0, norm_den1;
742 : Word32 L_tmp;
743 :
744 1272 : tmp = mult( EVS_PI_BY_2_FX, f0 );
745 1272 : sine_val = getSinWord16( shl( tmp, 1 ) ); // Q15
746 :
747 1272 : tmp = mult( EVS_PI_BY_2_FX, f0 );
748 1272 : cos_val = getCosWord16( shl( tmp, 1 ) ); // Q14
749 :
750 1272 : tan_val = BASOP_Util_Divide1616_Scale( sine_val, cos_val, &tan_exp );
751 1272 : tan_exp = add( tan_exp, sub( 0, 1 ) );
752 :
753 : Word16 gain_fx;
754 1272 : gain_fx = BASOP_Util_Divide1616_Scale( lin_gain_lf, lin_gain_hf, &gain_exp );
755 :
756 1272 : IF( LT_16( gain_fx, 16384 ) )
757 : {
758 :
759 3 : tmp = mult( tan_val, gain_fx );
760 3 : norm_num0 = add( tan_exp, gain_exp );
761 3 : L_tmp = L_add( L_shl( 1, sub( 15, norm_num0 ) ), tmp );
762 3 : shift = norm_l( L_tmp );
763 3 : L_tmp = L_shl( L_tmp, shift );
764 3 : tmp = extract_h( L_tmp );
765 3 : pNum[0] = tmp;
766 3 : move16();
767 3 : norm_num0 = sub( norm_num0, sub( shift, 16 ) );
768 :
769 3 : tmp = mult( tan_val, gain_fx );
770 3 : norm_num1 = add( tan_exp, gain_exp );
771 3 : L_tmp = L_sub( tmp, L_shl( 1, sub( 15, norm_num1 ) ) );
772 3 : shift = norm_l( L_tmp );
773 3 : L_tmp = L_shl( L_tmp, shift );
774 3 : tmp = extract_h( L_tmp );
775 3 : pNum[1] = tmp;
776 3 : move16();
777 3 : norm_num1 = sub( norm_num1, sub( shift, 16 ) );
778 :
779 3 : L_tmp = L_add( L_shl( 1, sub( 15, tan_exp ) ), tan_val );
780 3 : shift = norm_l( L_tmp );
781 3 : L_tmp = L_shl( L_tmp, shift );
782 3 : tmp = extract_h( L_tmp );
783 3 : pDen[0] = tmp;
784 3 : move16();
785 3 : norm_den0 = sub( tan_exp, sub( shift, 16 ) );
786 :
787 3 : L_tmp = L_sub( tan_val, L_shl( 1, sub( 15, tan_exp ) ) );
788 3 : shift = norm_l( L_tmp );
789 3 : L_tmp = L_shl( L_tmp, shift );
790 3 : tmp = extract_h( L_tmp );
791 3 : pDen[1] = tmp;
792 3 : move16();
793 3 : norm_den1 = sub( tan_exp, sub( shift, 16 ) );
794 : }
795 : ELSE
796 : {
797 1269 : L_tmp = L_add( L_shl( 1, ( sub( 15, tan_exp ) ) ), tan_val );
798 1269 : shift = norm_l( L_tmp );
799 1269 : L_tmp = L_shl( L_tmp, shift );
800 1269 : tmp = extract_h( L_tmp );
801 1269 : pNum[0] = tmp;
802 1269 : move16();
803 1269 : norm_num0 = sub( tan_exp, sub( shift, 16 ) );
804 :
805 1269 : L_tmp = L_sub( tan_val, L_shl( 1, ( sub( 15, tan_exp ) ) ) );
806 1269 : shift = norm_l( L_tmp );
807 1269 : L_tmp = L_shl( L_tmp, shift );
808 1269 : tmp = extract_h( L_tmp );
809 1269 : pNum[1] = tmp;
810 1269 : move16();
811 1269 : norm_num1 = sub( tan_exp, sub( shift, 16 ) );
812 :
813 1269 : tmp = BASOP_Util_Divide1616_Scale( tan_val, gain_fx, &exp );
814 1269 : exp = add( exp, sub( tan_exp, gain_exp ) );
815 1269 : L_tmp = L_add( L_shl( 1, sub( 15, exp ) ), tmp );
816 1269 : shift = norm_l( L_tmp );
817 1269 : L_tmp = L_shl( L_tmp, shift );
818 1269 : tmp = extract_h( L_tmp );
819 1269 : pDen[0] = tmp;
820 1269 : move16();
821 1269 : norm_den0 = sub( exp, sub( shift, 16 ) );
822 :
823 1269 : tmp = BASOP_Util_Divide1616_Scale( tan_val, gain_fx, &exp );
824 1269 : exp = add( exp, sub( tan_exp, gain_exp ) );
825 1269 : L_tmp = L_sub( tmp, 1 * L_shl( 1, sub( 15, exp ) ) );
826 1269 : shift = norm_l( L_tmp );
827 1269 : L_tmp = L_shl( L_tmp, shift );
828 1269 : tmp = extract_h( L_tmp );
829 1269 : pDen[1] = tmp;
830 1269 : move16();
831 1269 : norm_den1 = sub( exp, sub( shift, 16 ) );
832 : }
833 :
834 : /* Normalize and adjust gain to match target amplitudes */
835 1272 : pNum[0] = mult( BASOP_Util_Divide1616_Scale( pNum[0], pDen[0], &exp ), lin_gain_hf );
836 1272 : move16();
837 1272 : norm_num0 = add( exp, sub( norm_num0, norm_den0 ) );
838 :
839 1272 : pNum[1] = mult( BASOP_Util_Divide1616_Scale( pNum[1], pDen[0], &exp ), lin_gain_hf );
840 1272 : move16();
841 1272 : norm_num1 = add( exp, sub( norm_num1, norm_den0 ) );
842 :
843 1272 : pDen[1] = BASOP_Util_Divide1616_Scale( pDen[1], pDen[0], &exp );
844 1272 : move16();
845 1272 : norm_den1 = add( exp, sub( norm_den1, norm_den0 ) );
846 :
847 1272 : pNum[0] = shr( pNum[0], sub( 1, norm_num0 ) ); // Q14
848 1272 : move16();
849 1272 : pNum[1] = shr( pNum[1], sub( 1, norm_num1 ) ); // Q14
850 1272 : move16();
851 1272 : pDen[1] = shr( pDen[1], sub( 1, norm_den1 ) ); // Q14
852 1272 : move16();
853 1272 : pDen[0] = shl( 1, 14 ); // Q14
854 1272 : move16();
855 1272 : return;
856 : }
857 :
858 :
859 : /*-----------------------------------------------------------------------------------------*
860 : * Function calc_jot_t60_coeffs()
861 : *
862 : * Calculate Jot reverb's T60 filters
863 : *-----------------------------------------------------------------------------------------*/
864 :
865 :
866 1272 : static ivas_error calc_jot_t60_coeffs_fx(
867 : Word16 *pH_dB_fx,
868 : Word16 pH_dB_exp,
869 : const UWord16 nrFrequencies,
870 : Word16 *pFrequencies_fx,
871 : Word16 *pCoeffA_fx, /* Q14 */
872 : Word16 *pCoeffB_fx, /* Q14 */
873 : const Word16 fNyquist_fx )
874 : {
875 : Word16 scale1, scale2, scale3, scale4;
876 1272 : Word16 ref_lf_min_norm_fx = BASOP_Util_Divide1616_Scale( REF_LF_MIN_FX, fNyquist_fx, &scale1 );
877 1272 : Word16 ref_lf_max_norm_fx = BASOP_Util_Divide1616_Scale( REF_LF_MAX_FX, fNyquist_fx, &scale2 );
878 1272 : Word16 ref_hf_min_norm_fx = BASOP_Util_Divide1616_Scale( REF_HF_MIN_FX, fNyquist_fx, &scale3 );
879 1272 : Word16 ref_hf_max_norm_fx = BASOP_Util_Divide1616_Scale( REF_HF_MAX_FX, fNyquist_fx, &scale4 );
880 :
881 1272 : ref_lf_min_norm_fx = shl( ref_lf_min_norm_fx, sub( scale1, 1 ) ); // Q14
882 1272 : ref_lf_max_norm_fx = shl( ref_lf_max_norm_fx, sub( scale2, 1 ) ); // Q14
883 1272 : ref_hf_min_norm_fx = shl( ref_hf_min_norm_fx, sub( scale3, 1 ) ); // Q14
884 1272 : ref_hf_max_norm_fx = shl( ref_hf_max_norm_fx, sub( scale4, 1 ) ); // Q14
885 :
886 : Word32 L_tmp;
887 : Word16 f0_fx, tmp_fx, lf_target_gain_dB_fx, hf_target_gain_dB_fx, mid_crossing_gain_dB_fx;
888 : Word16 lin_gain_lf_fx, lin_gain_hf_fx, shift, expl, exph;
889 1272 : Word16 f_idx, e = pH_dB_exp;
890 1272 : move16();
891 : UWord16 n_points_lf, n_points_hf;
892 :
893 1272 : lf_target_gain_dB_fx = 0;
894 1272 : move16();
895 1272 : hf_target_gain_dB_fx = 0;
896 1272 : move16();
897 1272 : Word32 minval_fx = 1455191552;
898 1272 : move32();
899 1272 : Word16 minval_e = 67, exp;
900 1272 : move16();
901 :
902 1272 : Word32 L_tmpl = 0, L_tmph = 0;
903 1272 : move32();
904 1272 : move32();
905 1272 : n_points_lf = 0;
906 1272 : move16();
907 1272 : n_points_hf = 0;
908 1272 : move16();
909 1272 : Word16 minidx_fx = sub( nrFrequencies, 1 );
910 :
911 265712 : FOR( f_idx = 0; f_idx < nrFrequencies; f_idx++ )
912 : {
913 264440 : test();
914 264440 : IF( GE_16( pFrequencies_fx[f_idx], ref_lf_min_norm_fx ) && LE_16( pFrequencies_fx[f_idx], ref_lf_max_norm_fx ) )
915 : {
916 2248 : L_tmpl = L_add( L_tmpl, pH_dB_fx[f_idx] );
917 2248 : n_points_lf = add( n_points_lf, 1 );
918 : }
919 264440 : test();
920 264440 : IF( GE_16( pFrequencies_fx[f_idx], ref_hf_min_norm_fx ) && LE_16( pFrequencies_fx[f_idx], ref_hf_max_norm_fx ) )
921 : {
922 47728 : L_tmph = L_add( L_tmph, pH_dB_fx[f_idx] );
923 47728 : n_points_hf = add( n_points_hf, 1 );
924 : }
925 : }
926 1272 : shift = norm_l( L_tmpl );
927 1272 : L_tmpl = L_shl( L_tmpl, shift );
928 1272 : tmp_fx = extract_h( L_tmpl );
929 1272 : expl = sub( e, sub( shift, 16 ) );
930 1272 : lf_target_gain_dB_fx = tmp_fx;
931 1272 : move16();
932 :
933 1272 : shift = norm_l( L_tmph );
934 1272 : L_tmph = L_shl( L_tmph, shift );
935 1272 : tmp_fx = extract_h( L_tmph );
936 1272 : exph = sub( e, sub( shift, 16 ) );
937 1272 : hf_target_gain_dB_fx = tmp_fx;
938 1272 : move16();
939 :
940 1272 : test();
941 1272 : IF( ( n_points_lf == 0 ) || ( n_points_hf == 0 ) )
942 : {
943 0 : return IVAS_ERR_INTERNAL;
944 : }
945 :
946 1272 : lf_target_gain_dB_fx = BASOP_Util_Divide1616_Scale( lf_target_gain_dB_fx, n_points_lf, &e );
947 1272 : expl = add( e, sub( expl, 15 ) );
948 :
949 1272 : hf_target_gain_dB_fx = BASOP_Util_Divide1616_Scale( hf_target_gain_dB_fx, n_points_hf, &e );
950 1272 : exph = add( e, sub( exph, 15 ) );
951 :
952 1272 : e = BASOP_Util_Add_MantExp( lf_target_gain_dB_fx, expl, negate( hf_target_gain_dB_fx ), exph, &tmp_fx );
953 1272 : exp = BASOP_Util_Add_MantExp( hf_target_gain_dB_fx, exph, tmp_fx, e - 1, &mid_crossing_gain_dB_fx );
954 :
955 263168 : FOR( f_idx = 1; f_idx < nrFrequencies - 1; f_idx++ )
956 : {
957 : Word16 tmp1;
958 261896 : e = BASOP_Util_Add_MantExp( pH_dB_fx[f_idx], pH_dB_exp, negate( mid_crossing_gain_dB_fx ), exp, &tmp_fx );
959 261896 : tmp1 = abs_s( tmp_fx );
960 :
961 261896 : tmp_fx = BASOP_Util_Cmp_Mant32Exp( L_deposit_h( tmp1 ), e, minval_fx, minval_e );
962 :
963 261896 : IF( EQ_16( tmp_fx, -1 ) )
964 : {
965 21184 : minval_fx = L_deposit_h( tmp1 );
966 21184 : minval_e = e;
967 21184 : move16();
968 21184 : minidx_fx = f_idx;
969 21184 : move16();
970 : }
971 : }
972 :
973 1272 : f0_fx = pFrequencies_fx[minidx_fx];
974 1272 : move16();
975 :
976 1272 : tmp_fx = mult( lf_target_gain_dB_fx, 5443 ); // expl
977 1272 : L_tmp = BASOP_util_Pow2( L_deposit_h( tmp_fx ), expl, &e );
978 1272 : lin_gain_lf_fx = extract_l( L_shr( L_tmp, sub( 16, e ) ) );
979 :
980 1272 : tmp_fx = mult( hf_target_gain_dB_fx, 5443 ); // exph
981 1272 : L_tmp = BASOP_util_Pow2( L_deposit_h( tmp_fx ), exph, &e );
982 1272 : lin_gain_hf_fx = extract_l( L_shr( L_tmp, sub( 16, e ) ) );
983 :
984 : /* call low-pass iir shelf */
985 1272 : calc_low_shelf_first_order_filter_fx( pCoeffB_fx, pCoeffA_fx, f0_fx, lin_gain_lf_fx, lin_gain_hf_fx );
986 1272 : return IVAS_ERR_OK;
987 : }
988 :
989 : /*-----------------------------------------------------------------------------------------*
990 : * Function initialize_reverb_filters()
991 : *
992 : * Set the number of branches (feedback loops) and Initializes the memory structure (pointers to data)
993 : *-----------------------------------------------------------------------------------------*/
994 159 : static ivas_error initialize_reverb_filters_fx(
995 : REVERB_HANDLE hReverb )
996 : {
997 : ivas_error error;
998 :
999 159 : error = IVAS_ERR_OK;
1000 :
1001 : /* init correlation and coloration filters */
1002 159 : IF( NE_32( ( error = ivas_reverb_t2f_f2t_init( &hReverb->fft_filter_ols, hReverb->fft_size, hReverb->fft_subblock_size ) ), IVAS_ERR_OK ) )
1003 : {
1004 0 : return error;
1005 : }
1006 :
1007 159 : IF( NE_32( ( error = ivas_reverb_fft_filter_init( &hReverb->fft_filter_correl_0, hReverb->fft_size ) ), IVAS_ERR_OK ) )
1008 : {
1009 0 : return error;
1010 : }
1011 :
1012 159 : IF( NE_32( ( error = ivas_reverb_fft_filter_init( &hReverb->fft_filter_correl_1, hReverb->fft_size ) ), IVAS_ERR_OK ) )
1013 : {
1014 0 : return error;
1015 : }
1016 :
1017 159 : IF( NE_32( ( error = ivas_reverb_fft_filter_init( &hReverb->fft_filter_color_0, hReverb->fft_size ) ), IVAS_ERR_OK ) )
1018 : {
1019 0 : return error;
1020 : }
1021 :
1022 159 : IF( NE_32( ( error = ivas_reverb_fft_filter_init( &hReverb->fft_filter_color_1, hReverb->fft_size ) ), IVAS_ERR_OK ) )
1023 : {
1024 0 : return error;
1025 : }
1026 :
1027 159 : return error;
1028 : }
1029 :
1030 : /*-----------------------------------------------------------------------------------------*
1031 : * Function set_t60_filter()
1032 : *
1033 : * Sets t60 number of taps and coefficients A and B
1034 : *-----------------------------------------------------------------------------------------*/
1035 :
1036 1272 : static ivas_error set_t60_filter(
1037 : REVERB_HANDLE hReverb,
1038 : const UWord16 branch,
1039 : const UWord16 nr_taps,
1040 : const Word16 coefA[], /*Q14*/
1041 : const Word16 coefB[] /*Q14*/ )
1042 : {
1043 1272 : IF( GE_32( branch, hReverb->nr_of_branches ) )
1044 : {
1045 0 : return IVAS_ERR_INTERNAL;
1046 : }
1047 :
1048 1272 : IF( GT_32( nr_taps, IVAS_REV_MAX_IIR_FILTER_LENGTH ) )
1049 : {
1050 0 : return IVAS_ERR_INTERNAL;
1051 : }
1052 :
1053 1272 : ivas_reverb_iir_filt_set( &( hReverb->t60[branch] ), nr_taps, coefA, coefB );
1054 :
1055 1272 : return IVAS_ERR_OK;
1056 : }
1057 :
1058 : /*-----------------------------------------------------------------------------------------*
1059 : * Function set_feedback_delay()
1060 : *
1061 : * Sets Delay of feedback branch in number of samples
1062 : *-----------------------------------------------------------------------------------------*/
1063 :
1064 1272 : static ivas_error set_feedback_delay_fx(
1065 : REVERB_HANDLE hReverb,
1066 : const UWord16 branch,
1067 : const Word16 fb_delay /*Q0*/ )
1068 : {
1069 1272 : IF( GE_32( branch, hReverb->nr_of_branches ) )
1070 : {
1071 0 : return IVAS_ERR_INTERNAL;
1072 : }
1073 :
1074 1272 : hReverb->delay_line[branch].Delay = fb_delay;
1075 1272 : move16();
1076 :
1077 1272 : return IVAS_ERR_OK;
1078 : }
1079 : /*-----------------------------------------------------------------------------------------*
1080 : * Function set_feedback_gain()
1081 : *
1082 : * Sets nr_of_branches feedback gain values in feedback matrix
1083 : *-----------------------------------------------------------------------------------------*/
1084 :
1085 1272 : static ivas_error set_feedback_gain_fx(
1086 : REVERB_HANDLE hReverb,
1087 : const UWord16 branch,
1088 : const Word32 *pGain /*Q31*/ )
1089 : {
1090 : UWord16 gain_idx;
1091 1272 : IF( GE_32( branch, hReverb->nr_of_branches ) )
1092 : {
1093 0 : return IVAS_ERR_INTERNAL;
1094 : }
1095 :
1096 11448 : FOR( gain_idx = 0; gain_idx < hReverb->nr_of_branches; gain_idx++ )
1097 : {
1098 10176 : hReverb->gain_matrix_fx[branch][gain_idx] = pGain[gain_idx]; // Q31
1099 10176 : move32();
1100 : }
1101 :
1102 1272 : return IVAS_ERR_OK;
1103 : }
1104 : /*-----------------------------------------------------------------------------------------*
1105 : * Function set_correl_fft_filter()
1106 : *
1107 : * Sets correlation filter complex gains
1108 : *-----------------------------------------------------------------------------------------*/
1109 :
1110 318 : static ivas_error set_correl_fft_filter_fx(
1111 : REVERB_HANDLE hReverb,
1112 : const UWord16 channel,
1113 : rv_fftwf_type_complex_fx *pSpectrum )
1114 : {
1115 318 : IF( GT_32( channel, 1 ) )
1116 : {
1117 0 : return IVAS_ERR_INTERNAL;
1118 : }
1119 :
1120 318 : IF( EQ_32( channel, 0 ) )
1121 : {
1122 159 : ivas_reverb_fft_filter_ConvertFFTWF_2_FFTR_fx( pSpectrum, hReverb->fft_filter_correl_0.fft_spectrum_fx, hReverb->fft_filter_correl_0.fft_size );
1123 : }
1124 : ELSE
1125 : {
1126 159 : ivas_reverb_fft_filter_ConvertFFTWF_2_FFTR_fx( pSpectrum, hReverb->fft_filter_correl_1.fft_spectrum_fx, hReverb->fft_filter_correl_1.fft_size );
1127 : }
1128 :
1129 318 : return IVAS_ERR_OK;
1130 : }
1131 :
1132 :
1133 : /*-----------------------------------------------------------------------------------------*
1134 : * Function set_color_fft_filter()
1135 : *
1136 : * Sets coloration filter complex gains
1137 : *-----------------------------------------------------------------------------------------*/
1138 :
1139 318 : static ivas_error set_color_fft_filter_fx(
1140 : REVERB_HANDLE hReverb,
1141 : const UWord16 channel,
1142 : rv_fftwf_type_complex_fx *pSpectrum )
1143 : {
1144 318 : IF( GT_32( channel, 1 ) )
1145 : {
1146 0 : return IVAS_ERR_INTERNAL;
1147 : }
1148 :
1149 318 : IF( EQ_32( channel, 0 ) )
1150 : {
1151 159 : ivas_reverb_fft_filter_ConvertFFTWF_2_FFTR_fx( pSpectrum, hReverb->fft_filter_color_0.fft_spectrum_fx, hReverb->fft_filter_color_0.fft_size );
1152 : }
1153 : ELSE
1154 : {
1155 159 : ivas_reverb_fft_filter_ConvertFFTWF_2_FFTR_fx( pSpectrum, hReverb->fft_filter_color_1.fft_spectrum_fx, hReverb->fft_filter_color_1.fft_size );
1156 : }
1157 :
1158 318 : return IVAS_ERR_OK;
1159 : }
1160 :
1161 :
1162 : /*-----------------------------------------------------------------------------------------*
1163 : * Function set_mixer_level_fx()
1164 : *
1165 : * Sets Mixer level: to mix 2 output channels from 8 feedback branches
1166 : *-----------------------------------------------------------------------------------------*/
1167 :
1168 318 : static ivas_error set_mixer_level_fx(
1169 : REVERB_HANDLE hReverb,
1170 : const UWord16 channel,
1171 : const Word16 level[] /*Q0*/ )
1172 : {
1173 : UWord16 branch_idx;
1174 318 : IF( GE_32( channel, BINAURAL_CHANNELS ) )
1175 : {
1176 0 : return IVAS_ERR_INTERNAL;
1177 : }
1178 :
1179 2862 : FOR( branch_idx = 0; branch_idx < hReverb->nr_of_branches; branch_idx++ )
1180 : {
1181 2544 : hReverb->mixer_fx[channel][branch_idx] = level[branch_idx]; /*Q0*/
1182 2544 : move16();
1183 : }
1184 :
1185 318 : return IVAS_ERR_OK;
1186 : }
1187 : /*-----------------------------------------------------------------------------------------*
1188 : * Function clear_buffers_fx()
1189 : *
1190 : * Clears buffers of delay lines and filters
1191 : *-----------------------------------------------------------------------------------------*/
1192 :
1193 159 : static void clear_buffers_fx(
1194 : REVERB_HANDLE hReverb )
1195 : {
1196 : Word16 branch_idx;
1197 : ivas_rev_iir_filter_t *iirFilter;
1198 : ivas_rev_delay_line_t *delay_line;
1199 :
1200 1431 : FOR( branch_idx = 0; branch_idx < IVAS_REV_MAX_NR_BRANCHES; branch_idx++ )
1201 : {
1202 1272 : delay_line = &( hReverb->delay_line[branch_idx] );
1203 1272 : set32_fx( delay_line->pBuffer_fx, 0, delay_line->MaxDelay );
1204 1272 : delay_line->BufferPos = 0;
1205 1272 : move16();
1206 :
1207 1272 : iirFilter = &( hReverb->t60[branch_idx] );
1208 1272 : set32_fx( iirFilter->pBuffer_fx, 0, iirFilter->MaxTaps );
1209 : }
1210 :
1211 159 : ivas_reverb_t2f_f2t_ClearHistory( &hReverb->fft_filter_ols );
1212 :
1213 159 : return;
1214 : }
1215 :
1216 : /*-----------------------------------------------------------------------------------------*
1217 : * Function set_fft_and_datablock_sizes_fx()
1218 : *
1219 : * Sets frame size and fft-filter related sizes
1220 : *-----------------------------------------------------------------------------------------*/
1221 :
1222 159 : static void set_fft_and_datablock_sizes_fx(
1223 : REVERB_HANDLE hReverb,
1224 : const Word16 subframe_len )
1225 : {
1226 159 : hReverb->full_block_size = subframe_len;
1227 159 : IF( EQ_16( subframe_len, 240 /*L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES*/ ) )
1228 : {
1229 98 : hReverb->fft_size = IVAS_REVERB_FFT_SIZE_48K;
1230 98 : move16();
1231 98 : hReverb->num_fft_subblocks = IVAS_REVERB_FFT_N_SUBBLOCKS_48K;
1232 98 : move16();
1233 : }
1234 61 : ELSE IF( EQ_16( subframe_len, 160 /*L_FRAME32k / MAX_PARAM_SPATIAL_SUBFRAMES*/ ) )
1235 : {
1236 0 : hReverb->fft_size = IVAS_REVERB_FFT_SIZE_32K;
1237 0 : move16();
1238 0 : hReverb->num_fft_subblocks = IVAS_REVERB_FFT_N_SUBBLOCKS_32K;
1239 0 : move16();
1240 : }
1241 61 : ELSE IF( EQ_16( subframe_len, 80 /*L_FRAME16k / MAX_PARAM_SPATIAL_SUBFRAMES*/ ) )
1242 : {
1243 61 : hReverb->fft_size = IVAS_REVERB_FFT_SIZE_16K;
1244 61 : move16();
1245 61 : hReverb->num_fft_subblocks = IVAS_REVERB_FFT_N_SUBBLOCKS_16K;
1246 61 : move16();
1247 : }
1248 : ELSE
1249 : {
1250 0 : assert( 0 ); /* unsupported block size */
1251 : }
1252 :
1253 159 : hReverb->fft_subblock_size = (UWord16) idiv1616( subframe_len, hReverb->num_fft_subblocks );
1254 159 : move16();
1255 :
1256 159 : return;
1257 : }
1258 :
1259 : /*-----------------------------------------------------------------------------------------*
1260 : * Function set_reverb_acoustic_data()
1261 : *
1262 : * Sets reverb acoustic data (room acoustics and HRTF), interpolating it to the filter grid
1263 : *-----------------------------------------------------------------------------------------*/
1264 :
1265 159 : static void set_reverb_acoustic_data_fx(
1266 : ivas_reverb_params_t *pParams,
1267 : const AUDIO_CONFIG input_audio_config,
1268 : const HRTFS_HANDLE hHrtf,
1269 : IVAS_ROOM_ACOUSTICS_CONFIG_DATA *pRoomAcoustics,
1270 : const Word16 subframe_len,
1271 : const Word16 nr_fc_input,
1272 : const Word16 nr_fc_fft_filter )
1273 : {
1274 : Word16 nr_out_ch, hrtf_idx, offset, iter_idx, bin_idx;
1275 : Word32 *pHrtf_set_l_re_fx[MAX_INTERN_CHANNELS];
1276 : Word32 *pHrtf_set_l_im_fx[MAX_INTERN_CHANNELS];
1277 : Word32 *pHrtf_set_r_re_fx[MAX_INTERN_CHANNELS];
1278 : Word32 *pHrtf_set_r_im_fx[MAX_INTERN_CHANNELS];
1279 : Word32 ln_1e6_inverted_fx, delay_diff_fx, L_tmp;
1280 : Word16 exp_argument_fx, tmp, tmp_flag, exp_argument_e;
1281 : Word16 pow_exp;
1282 :
1283 159 : Word32 *pFc_input_fx = pRoomAcoustics->pFc_input_fx;
1284 159 : Word32 *pAcoustic_rt60_fx = pRoomAcoustics->pAcoustic_rt60_fx;
1285 159 : Word32 *pAcoustic_dsr_fx = pRoomAcoustics->pAcoustic_dsr_fx;
1286 :
1287 159 : Word32 *pFc_fx = pParams->pFc_fx;
1288 159 : Word32 *pRt60_fx = pParams->pRt60_fx;
1289 159 : Word16 *pRt60_e = pParams->pRt60_e;
1290 159 : Word32 *pDsr_fx = pParams->pDsr_fx;
1291 159 : Word16 *pDsr_e = pParams->pDsr_e;
1292 :
1293 : /* use crend hrtf filters */
1294 159 : IF( hHrtf != NULL )
1295 : {
1296 : /* Compute HRTF set properties: average left/right energies, IA coherence */
1297 : /* First, find the offset of the frequency-domain data for the 1st frame and assign HRTF pointers */
1298 330 : FOR( nr_out_ch = 0; nr_out_ch < BINAURAL_CHANNELS; nr_out_ch++ )
1299 : {
1300 1792 : FOR( hrtf_idx = 0; hrtf_idx < hHrtf->max_num_ir; hrtf_idx++ )
1301 : {
1302 1572 : offset = 0;
1303 1572 : move16();
1304 1572 : FOR( iter_idx = 0; iter_idx < hHrtf->num_iterations[hrtf_idx][nr_out_ch] - 1; iter_idx++ )
1305 : {
1306 0 : offset = add( offset, hHrtf->pIndex_frequency_max[hrtf_idx][nr_out_ch][iter_idx] );
1307 : }
1308 :
1309 1572 : IF( EQ_16( nr_out_ch, 0 ) )
1310 : {
1311 786 : pHrtf_set_l_re_fx[hrtf_idx] = &hHrtf->pOut_to_bin_re_fx[hrtf_idx][0][offset];
1312 786 : pHrtf_set_l_im_fx[hrtf_idx] = &hHrtf->pOut_to_bin_im_fx[hrtf_idx][0][offset];
1313 : }
1314 : ELSE
1315 : {
1316 786 : pHrtf_set_r_re_fx[hrtf_idx] = &hHrtf->pOut_to_bin_re_fx[hrtf_idx][1][offset];
1317 786 : pHrtf_set_r_im_fx[hrtf_idx] = &hHrtf->pOut_to_bin_im_fx[hrtf_idx][1][offset];
1318 : }
1319 : }
1320 : }
1321 :
1322 : /* Compute HRTF set properties using frequency-domain HRTF data */
1323 110 : Word32 *pHrtf_avg_pwr_response_l_fx = pParams->pHrtf_avg_pwr_response_l_fx;
1324 110 : Word32 *pHrtf_avg_pwr_response_r_fx = pParams->pHrtf_avg_pwr_response_r_fx;
1325 110 : Word32 *pHrtf_inter_aural_coherence_fx = pParams->pHrtf_inter_aural_coherence_fx;
1326 110 : ivas_reverb_get_hrtf_set_properties_fx( pHrtf_set_l_re_fx, pHrtf_set_l_im_fx, pHrtf_set_r_re_fx, pHrtf_set_r_im_fx, input_audio_config, hHrtf->max_num_ir, subframe_len,
1327 : nr_fc_fft_filter, pHrtf_avg_pwr_response_l_fx, pHrtf_avg_pwr_response_r_fx, pHrtf_inter_aural_coherence_fx );
1328 :
1329 110 : pParams->pHrtf_avg_pwr_response_l_const_fx = (const Word32 *) pParams->pHrtf_avg_pwr_response_l_fx;
1330 110 : pParams->pHrtf_avg_pwr_response_r_const_fx = (const Word32 *) pParams->pHrtf_avg_pwr_response_r_fx;
1331 110 : pParams->pHrtf_inter_aural_coherence_const_fx = (const Word32 *) pParams->pHrtf_inter_aural_coherence_fx;
1332 : }
1333 :
1334 : /* interpolate input table data for T60 and DSR to the FFT filter grid */
1335 159 : ivas_reverb_interpolate_acoustic_data_fx( nr_fc_input, pFc_input_fx, pAcoustic_rt60_fx, pAcoustic_dsr_fx,
1336 : nr_fc_fft_filter, pFc_fx, pRt60_fx, pDsr_fx, pRt60_e, pDsr_e );
1337 :
1338 : /* adjust DSR for the delay difference */
1339 :
1340 159 : delay_diff_fx = L_sub( pRoomAcoustics->inputPreDelay_fx, pRoomAcoustics->acousticPreDelay_fx );
1341 :
1342 159 : ln_1e6_inverted_fx = 155440049; // Q31 /* 1.0f / logf( 1e06f ) */
1343 159 : move32();
1344 :
1345 33214 : FOR( bin_idx = 0; bin_idx < nr_fc_fft_filter; bin_idx++ )
1346 : {
1347 33055 : L_tmp = Mpy_32_32( pRt60_fx[bin_idx], ln_1e6_inverted_fx ); // exp = pRt60_e[bin_idx] + 0
1348 33055 : exp_argument_fx = BASOP_Util_Divide3232_Scale( delay_diff_fx, L_tmp, &exp_argument_e );
1349 33055 : exp_argument_e = add( exp_argument_e, sub( 4, pRt60_e[bin_idx] ) ); // Q27 -> e4
1350 : /* Limit exponent to approx +/-100 dB in case of incoherent value of delay_diff, to prevent overflow */
1351 :
1352 : // 23 in Q26
1353 33055 : tmp_flag = BASOP_Util_Cmp_Mant32Exp( L_deposit_h( exp_argument_fx ), exp_argument_e, 1543503872, 5 );
1354 33055 : IF( tmp_flag > 0 )
1355 : {
1356 0 : exp_argument_fx = 23552;
1357 0 : move16();
1358 0 : exp_argument_e = 5;
1359 0 : move16();
1360 : }
1361 :
1362 33055 : tmp_flag = BASOP_Util_Cmp_Mant32Exp( L_deposit_h( exp_argument_fx ), exp_argument_e, 0, 31 );
1363 33055 : IF( tmp_flag < 0 )
1364 : {
1365 0 : tmp_flag = BASOP_Util_Cmp_Mant32Exp( L_deposit_h( negate( exp_argument_fx ) ), exp_argument_e, 1543503872, 5 );
1366 0 : IF( tmp_flag < 0 )
1367 : {
1368 0 : exp_argument_fx = -23552;
1369 0 : move16();
1370 0 : exp_argument_e = 5;
1371 0 : move16();
1372 : }
1373 : }
1374 :
1375 : Word16 tmp_exp;
1376 : /* expf(exp_argument) -> pow(2, log2(e) * exp_argument) */
1377 33055 : tmp = mult( 23637, exp_argument_fx ); // exp_argument_e + 1
1378 33055 : tmp_exp = add( exp_argument_e, 1 );
1379 33055 : L_tmp = BASOP_util_Pow2( L_deposit_h( tmp ), tmp_exp, &pow_exp );
1380 33055 : L_tmp = Mpy_32_32( L_tmp, pDsr_fx[bin_idx] );
1381 33055 : tmp_exp = add( pow_exp, pDsr_e[bin_idx] );
1382 :
1383 33055 : pDsr_fx[bin_idx] = L_tmp;
1384 33055 : move32();
1385 33055 : pDsr_e[bin_idx] = tmp_exp;
1386 33055 : move16();
1387 : }
1388 159 : return;
1389 : }
1390 :
1391 :
1392 : /*-----------------------------------------------------------------------------------------*
1393 : * Function setup_FDN_branches_fx()
1394 : *
1395 : * Sets up feedback delay network system
1396 : *-----------------------------------------------------------------------------------------*/
1397 :
1398 159 : static ivas_error setup_FDN_branches_fx(
1399 : REVERB_HANDLE hReverb,
1400 : ivas_reverb_params_t *pParams )
1401 : {
1402 : Word16 nr_coefs, branch_idx, channel_idx;
1403 : ivas_error error;
1404 : Word16 *pCoef_a, *pCoef_b;
1405 159 : error = IVAS_ERR_OK;
1406 :
1407 : /* initialize feedback branches */
1408 1431 : FOR( branch_idx = 0; branch_idx < IVAS_REV_MAX_NR_BRANCHES; branch_idx++ )
1409 : {
1410 1272 : ivas_rev_delay_line_init( &( hReverb->delay_line[branch_idx] ), hReverb->loop_delay_buffer_fx[branch_idx], init_loop_delay[branch_idx], pParams->pLoop_delays[branch_idx] );
1411 1272 : ivas_reverb_iir_filt_init( &( hReverb->t60[branch_idx] ), IVAS_REV_MAX_IIR_FILTER_LENGTH );
1412 1272 : hReverb->mixer_fx[0][branch_idx] = 0;
1413 1272 : move16();
1414 1272 : hReverb->mixer_fx[1][branch_idx] = 0;
1415 1272 : move16();
1416 : }
1417 159 : clear_buffers_fx( hReverb );
1418 159 : nr_coefs = add( pParams->t60_filter_order, 1 );
1419 :
1420 159 : IF( LT_16( IVAS_REV_MAX_IIR_FILTER_LENGTH, nr_coefs ) )
1421 : {
1422 0 : return IVAS_ERR_INTERNAL;
1423 : }
1424 : ELSE
1425 : {
1426 1431 : FOR( branch_idx = 0; branch_idx < pParams->nr_loops; branch_idx++ )
1427 : {
1428 1272 : pCoef_b = &pParams->pT60_filter_coeff_fx[shl( i_mult( nr_coefs, branch_idx ), 1 )]; /*Q14*/
1429 1272 : pCoef_a = &pParams->pT60_filter_coeff_fx[add( shl( i_mult( nr_coefs, branch_idx ), 1 ), nr_coefs )]; /*Q14*/
1430 :
1431 1272 : IF( NE_32( ( error = set_t60_filter( hReverb, branch_idx, nr_coefs, pCoef_a, pCoef_b ) ), IVAS_ERR_OK ) )
1432 : {
1433 0 : return error;
1434 : }
1435 :
1436 1272 : IF( NE_32( ( error = set_feedback_delay_fx( hReverb, branch_idx, pParams->pLoop_delays[branch_idx] ) ), IVAS_ERR_OK ) )
1437 : {
1438 0 : return error;
1439 : }
1440 1272 : IF( NE_32( ( error = set_feedback_gain_fx( hReverb, branch_idx, &( pParams->pLoop_feedback_matrix_fx[i_mult( branch_idx, pParams->nr_loops )] ) ) ), IVAS_ERR_OK ) )
1441 : {
1442 0 : return error;
1443 : }
1444 : }
1445 : }
1446 :
1447 477 : FOR( channel_idx = 0; channel_idx < pParams->nr_outputs; channel_idx++ )
1448 : {
1449 318 : IF( NE_32( ( error = set_mixer_level_fx( hReverb, channel_idx, &( pParams->pLoop_extract_matrix_fx[i_mult( channel_idx, pParams->nr_loops )] ) ) ), IVAS_ERR_OK ) )
1450 : {
1451 0 : return error;
1452 : }
1453 : }
1454 :
1455 159 : return error;
1456 : }
1457 : /*-------------------------------------------------------------------------
1458 : * ivas_reverb_open_fx()
1459 : *
1460 : * Allocate and initialize Crend reverberation handle
1461 : *------------------------------------------------------------------------*/
1462 :
1463 159 : ivas_error ivas_reverb_open_fx(
1464 : REVERB_HANDLE *hReverb, /* i/o: Reverberator handle */
1465 : const AUDIO_CONFIG input_audio_config, /* i : reverb. input audio configuration */
1466 : const HRTFS_HANDLE hHrtf, /* i : HRTF handle */
1467 : const Word32 *lr_energy_and_iac_fx[], /* i : precomuputed lr energies and iac */
1468 : RENDER_CONFIG_HANDLE hRenderConfig, /* i : Renderer configuration handle */
1469 : const Word32 output_Fs /* i : output sampling rate */
1470 : )
1471 : {
1472 : ivas_error error;
1473 159 : REVERB_HANDLE pState = NULL;
1474 : Word16 bin_idx, subframe_len, output_frame, predelay_bf_len, loop_idx, i;
1475 : ivas_reverb_params_t params;
1476 : Word32 pColor_target_l_fx[RV_LENGTH_NR_FC];
1477 : Word32 pColor_target_r_fx[RV_LENGTH_NR_FC];
1478 : Word32 pTime_window_fx[RV_FILTER_MAX_FFT_SIZE];
1479 : Word32 freq_step_fx;
1480 : Word16 fft_hist_size, transition_start, transition_length;
1481 : Word16 nr_fc_input, nr_fc_fft_filter;
1482 : rv_fftwf_type_complex_fx pFft_wf_filter_ch0_fx[RV_LENGTH_NR_FC];
1483 : rv_fftwf_type_complex_fx pFft_wf_filter_ch1_fx[RV_LENGTH_NR_FC];
1484 :
1485 159 : error = IVAS_ERR_OK;
1486 159 : output_frame = extract_l( Mult_32_16( output_Fs, INV_FRAME_PER_SEC_Q15 ) );
1487 159 : subframe_len = shr( output_frame, 2 ); /*output_frame / MAX_PARAM_SPATIAL_SUBFRAMES*/
1488 159 : predelay_bf_len = output_frame;
1489 159 : move16();
1490 159 : nr_fc_input = hRenderConfig->roomAcoustics.nBands;
1491 :
1492 : /* Allocate main reverb. handle */
1493 159 : IF( ( pState = (REVERB_HANDLE) malloc( sizeof( REVERB_DATA ) ) ) == NULL )
1494 : {
1495 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Crend Reverberator " );
1496 : }
1497 :
1498 159 : IF( NE_32( ( error = set_base_config_fx( ¶ms, output_Fs ) ), IVAS_ERR_OK ) )
1499 : {
1500 0 : return error;
1501 : }
1502 :
1503 : /* Allocate memory for feedback delay lines */
1504 1431 : FOR( loop_idx = 0; loop_idx < IVAS_REV_MAX_NR_BRANCHES; loop_idx++ )
1505 : {
1506 1272 : IF( ( pState->loop_delay_buffer_fx[loop_idx] = (Word32 *) malloc( params.pLoop_delays[loop_idx] * sizeof( Word32 ) ) ) == NULL )
1507 : {
1508 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for CREND Reverberator" );
1509 : }
1510 : }
1511 :
1512 : /* Allocate memory for the pre-delay delay line */
1513 159 : IF( ( pState->pPredelay_buffer_fx = (Word32 *) malloc( output_frame * sizeof( Word32 ) ) ) == NULL )
1514 : {
1515 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for CREND Reverberator" );
1516 : }
1517 :
1518 159 : pState->nr_of_branches = IVAS_REV_MAX_NR_BRANCHES;
1519 159 : move16();
1520 159 : set_fft_and_datablock_sizes_fx( pState, subframe_len );
1521 159 : nr_fc_fft_filter = add( extract_l( L_shr( pState->fft_size, 1 ) ), 1 );
1522 :
1523 : /* === 'Control logic': compute the reverb processing parameters from the === */
1524 : /* === room, source and listener acoustic information provided in the reverb config === */
1525 : /* Setting up shared temporary buffers for fc, RT60, DSR, etc. */
1526 159 : params.pHrtf_avg_pwr_response_l_fx = &pFft_wf_filter_ch0_fx[0][0];
1527 159 : params.pHrtf_avg_pwr_response_r_fx = params.pHrtf_avg_pwr_response_l_fx + nr_fc_fft_filter;
1528 159 : params.pRt60_fx = &pFft_wf_filter_ch1_fx[0][0];
1529 159 : params.pDsr_fx = params.pRt60_fx + nr_fc_fft_filter;
1530 159 : params.pFc_fx = &pState->fft_filter_color_0.fft_spectrum_fx[0];
1531 159 : params.pHrtf_inter_aural_coherence_fx = &pState->fft_filter_color_1.fft_spectrum_fx[0];
1532 159 : set32_fx( pState->fft_filter_color_1.fft_spectrum_fx, 0, RV_FILTER_MAX_FFT_SIZE );
1533 : /* Note: these temp buffers can only be used before the final step of the FFT filter design : */
1534 : /* before calls to ivas_reverb_calc_correl_filters(...) or to ivas_reverb_calc_color_filters(...) */
1535 :
1536 : /* set the uniform frequency grid for FFT filtering */
1537 159 : freq_step_fx = L_mult0( extract_l( L_shr( output_Fs, 2 ) ), div_s( 1, ( nr_fc_fft_filter - 1 ) ) ); /*Q14:0.5f * output_Fs / ( nr_fc_fft_filter - 1 )*/
1538 33214 : FOR( bin_idx = 0; bin_idx < nr_fc_fft_filter; bin_idx++ )
1539 : {
1540 33055 : params.pFc_fx[bin_idx] = W_extract_l( W_mult0_32_32( freq_step_fx, bin_idx ) ); /*Q14*/
1541 : }
1542 :
1543 159 : test();
1544 159 : IF( hHrtf == NULL && lr_energy_and_iac_fx != NULL )
1545 : {
1546 49 : params.pHrtf_avg_pwr_response_l_const_fx = lr_energy_and_iac_fx[0];
1547 49 : params.pHrtf_avg_pwr_response_r_const_fx = lr_energy_and_iac_fx[1];
1548 49 : params.pHrtf_inter_aural_coherence_const_fx = lr_energy_and_iac_fx[2];
1549 : }
1550 : /* set up reverb acoustic data on the basis of HRTF data and renderer config */
1551 159 : Scale_sig32( params.pFc_fx, nr_fc_fft_filter, 2 );
1552 159 : Word16 *pRt60_e = (Word16 *) malloc( sizeof( Word16 ) * nr_fc_fft_filter );
1553 159 : Word16 *pDsr_e = (Word16 *) malloc( sizeof( Word16 ) * nr_fc_fft_filter );
1554 :
1555 159 : params.pRt60_e = pRt60_e;
1556 159 : params.pDsr_e = pDsr_e;
1557 :
1558 159 : set_reverb_acoustic_data_fx( ¶ms, input_audio_config, hHrtf, &hRenderConfig->roomAcoustics, subframe_len, nr_fc_input, nr_fc_fft_filter );
1559 159 : Scale_sig32( params.pFc_fx, nr_fc_fft_filter, -2 );
1560 33214 : FOR( i = 0; i < nr_fc_fft_filter; i++ )
1561 : {
1562 33055 : params.pRt60_fx[i] = L_abs( params.pRt60_fx[i] );
1563 33055 : move32();
1564 33055 : params.pDsr_fx[i] = L_abs( params.pDsr_fx[i] );
1565 33055 : move32();
1566 : }
1567 :
1568 : /* set reverb acoustic configuration based on renderer config */
1569 159 : pState->pConfig.roomAcoustics.override = hRenderConfig->roomAcoustics.override;
1570 159 : move16();
1571 159 : pState->pConfig.roomAcoustics.nBands = hRenderConfig->roomAcoustics.nBands;
1572 159 : move16();
1573 :
1574 159 : IF( EQ_16( hRenderConfig->roomAcoustics.use_er, 1 ) )
1575 : {
1576 3 : pState->pConfig.roomAcoustics.use_er = hRenderConfig->roomAcoustics.use_er;
1577 3 : move16();
1578 3 : pState->pConfig.roomAcoustics.lowComplexity = hRenderConfig->roomAcoustics.lowComplexity;
1579 3 : move32();
1580 : }
1581 :
1582 : /* set up input downmix */
1583 159 : pState->dmx_gain_fx = calc_dmx_gain_fx();
1584 :
1585 : /* set up predelay - must be after set_base_config() and before compute_t60_coeffs() */
1586 159 : calc_predelay_fx( ¶ms, hRenderConfig->roomAcoustics.acousticPreDelay_fx, output_Fs );
1587 :
1588 : /* set up jot reverb 60 filters - must be set up after set_reverb_acoustic_data() */
1589 :
1590 159 : IF( NE_32( ( error = compute_t60_coeffs_fx( ¶ms, nr_fc_fft_filter, output_Fs ) ), IVAS_ERR_OK ) )
1591 : {
1592 0 : return error;
1593 : }
1594 : /* Compute target levels (gains) for the coloration filters */
1595 159 : Word32 *pHrtf_avg_pwr_response_l_const = (Word32 *) malloc( nr_fc_fft_filter * sizeof( Word32 * ) );
1596 159 : Word32 *pHrtf_avg_pwr_response_r_const = (Word32 *) malloc( nr_fc_fft_filter * sizeof( Word32 * ) );
1597 159 : Word16 lenT60_filter_coeff = add( params.t60_filter_order, 1 );
1598 159 : lenT60_filter_coeff = add( i_mult( shl( lenT60_filter_coeff, 1 ), sub( params.nr_loops, 1 ) ), add( lenT60_filter_coeff, 2 ) );
1599 159 : Word32 *pT60_filter_coeff = (Word32 *) malloc( ( lenT60_filter_coeff ) * sizeof( Word32 * ) );
1600 :
1601 :
1602 33214 : FOR( i = 0; i < nr_fc_fft_filter; i++ )
1603 : {
1604 33055 : params.pDsr_fx[i] = L_shl( params.pDsr_fx[i], params.pDsr_e[i] );
1605 33055 : move32();
1606 33055 : pHrtf_avg_pwr_response_l_const[i] = L_shl( params.pHrtf_avg_pwr_response_l_const_fx[i], 5 ); /*Q23+5*/
1607 33055 : move32();
1608 33055 : pHrtf_avg_pwr_response_r_const[i] = L_shl( params.pHrtf_avg_pwr_response_r_const_fx[i], 5 ); /*Q23+5*/
1609 33055 : move32();
1610 : }
1611 5247 : FOR( i = 0; i < lenT60_filter_coeff; i++ )
1612 : {
1613 5088 : pT60_filter_coeff[i] = L_shl_sat( params.pT60_filter_coeff_fx[i], 17 );
1614 5088 : move32();
1615 : }
1616 159 : ivas_reverb_calc_color_levels_fx( output_Fs, nr_fc_fft_filter, params.nr_loops, params.pFc_fx, params.pDsr_fx, pHrtf_avg_pwr_response_l_const, pHrtf_avg_pwr_response_r_const,
1617 : params.pLoop_delays, pT60_filter_coeff, pColor_target_l_fx, pColor_target_r_fx );
1618 :
1619 159 : free( pHrtf_avg_pwr_response_l_const );
1620 159 : free( pHrtf_avg_pwr_response_r_const );
1621 159 : free( pT60_filter_coeff );
1622 :
1623 : /* Defining appropriate windowing parameters for FFT filters to prevent aliasing */
1624 159 : fft_hist_size = sub( pState->fft_size, pState->fft_subblock_size );
1625 :
1626 159 : transition_start = round_fx( L_mult0( FFT_FILTER_WND_FLAT_REGION_FX, fft_hist_size ) );
1627 159 : transition_length = round_fx( L_mult0( FFT_FILTER_WND_TRANS_REGION_FX, fft_hist_size ) );
1628 :
1629 : /* Compute the window used for FFT filters */
1630 159 : ivas_reverb_define_window_fft_fx( pTime_window_fx, transition_start, transition_length, nr_fc_fft_filter );
1631 : /* === Now, copy parameters from ivas_reverb_params_t into DSP blocks === */
1632 : /* === to be used for subsequent audio signal processing === */
1633 :
1634 159 : pState->do_corr_filter = params.do_corr_filter;
1635 159 : move16();
1636 :
1637 : /* clear & init jot reverb fft filters */
1638 159 : IF( NE_32( ( error = initialize_reverb_filters_fx( pState ) ), IVAS_ERR_OK ) )
1639 : {
1640 0 : return error;
1641 : }
1642 159 : Word16 q_pFft_wf_filter_ch0_fx = 23, q_pFft_wf_filter_ch1_fx = 23;
1643 159 : move16();
1644 159 : move16();
1645 159 : IF( pState->do_corr_filter )
1646 : {
1647 : /* Computing correlation filters on the basis of target IA coherence */
1648 65951 : FOR( i = 0; i < shl( sub( nr_fc_fft_filter, 1 ), 1 ); i++ )
1649 : {
1650 65792 : pTime_window_fx[i] = L_shr( pTime_window_fx[i], 1 ); /*Scaling signal down to 30*/
1651 65792 : move32();
1652 : }
1653 :
1654 159 : Word32 *pHrtf_inter_aural_coherence_const = (Word32 *) malloc( nr_fc_fft_filter * sizeof( Word32 ) );
1655 33214 : FOR( i = 0; i < nr_fc_fft_filter; i++ )
1656 : {
1657 33055 : pHrtf_inter_aural_coherence_const[i] = L_shl( params.pHrtf_inter_aural_coherence_const_fx[i], 3 ); /*Scaling up to Q30*/
1658 33055 : move32();
1659 : }
1660 159 : ivas_reverb_calc_correl_filters_fx( pHrtf_inter_aural_coherence_const, pTime_window_fx, pState->fft_size, pFft_wf_filter_ch0_fx, pFft_wf_filter_ch1_fx, &q_pFft_wf_filter_ch0_fx, &q_pFft_wf_filter_ch1_fx );
1661 :
1662 159 : free( pHrtf_inter_aural_coherence_const );
1663 :
1664 33214 : FOR( i = 0; i < nr_fc_fft_filter; i++ )
1665 : {
1666 33055 : pFft_wf_filter_ch0_fx[i][0] = L_shl( pFft_wf_filter_ch0_fx[i][0], sub( 31, q_pFft_wf_filter_ch0_fx ) );
1667 33055 : move32();
1668 33055 : pFft_wf_filter_ch0_fx[i][1] = L_shl( pFft_wf_filter_ch0_fx[i][1], sub( 31, q_pFft_wf_filter_ch0_fx ) );
1669 33055 : move32();
1670 : }
1671 33214 : FOR( i = 0; i < nr_fc_fft_filter; i++ )
1672 : {
1673 33055 : pFft_wf_filter_ch1_fx[i][0] = L_shl( pFft_wf_filter_ch1_fx[i][0], sub( 31, q_pFft_wf_filter_ch1_fx ) );
1674 33055 : move32();
1675 33055 : pFft_wf_filter_ch1_fx[i][1] = L_shl( pFft_wf_filter_ch1_fx[i][1], sub( 31, q_pFft_wf_filter_ch1_fx ) );
1676 33055 : move32();
1677 : }
1678 : /* Copying the computed FFT correlation filters to the fft_filter components */
1679 159 : IF( NE_32( ( error = set_correl_fft_filter_fx( pState, 0, pFft_wf_filter_ch0_fx ) ), IVAS_ERR_OK ) )
1680 : {
1681 0 : return error;
1682 : }
1683 :
1684 159 : IF( NE_32( ( error = set_correl_fft_filter_fx( pState, 1, pFft_wf_filter_ch1_fx ) ), IVAS_ERR_OK ) )
1685 : {
1686 0 : return error;
1687 : }
1688 : }
1689 :
1690 : /* Computing coloration filters on the basis of target responses */
1691 :
1692 159 : ivas_reverb_calc_color_filters_fx( pColor_target_l_fx, pColor_target_r_fx, pTime_window_fx, pState->fft_size, pFft_wf_filter_ch0_fx, pFft_wf_filter_ch1_fx, &q_pFft_wf_filter_ch0_fx, &q_pFft_wf_filter_ch1_fx );
1693 33214 : FOR( i = 0; i < nr_fc_fft_filter; i++ )
1694 : {
1695 33055 : pFft_wf_filter_ch0_fx[i][0] = L_shl( pFft_wf_filter_ch0_fx[i][0], sub( 31, q_pFft_wf_filter_ch0_fx ) );
1696 33055 : move32();
1697 33055 : pFft_wf_filter_ch0_fx[i][1] = L_shl( pFft_wf_filter_ch0_fx[i][1], sub( 31, q_pFft_wf_filter_ch0_fx ) );
1698 33055 : move32();
1699 : }
1700 33214 : FOR( i = 0; i < nr_fc_fft_filter; i++ )
1701 : {
1702 33055 : pFft_wf_filter_ch1_fx[i][0] = L_shl( pFft_wf_filter_ch1_fx[i][0], sub( 31, q_pFft_wf_filter_ch1_fx ) );
1703 33055 : move32();
1704 33055 : pFft_wf_filter_ch1_fx[i][1] = L_shl( pFft_wf_filter_ch1_fx[i][1], sub( 31, q_pFft_wf_filter_ch1_fx ) );
1705 33055 : move32();
1706 : }
1707 :
1708 159 : Scale_sig32( params.pHrtf_inter_aural_coherence_fx, nr_fc_fft_filter, 4 ); /*Scaling ( *hReverb )->fft_filter_color_0.fft_spectrum_fx to Q31*/
1709 159 : Scale_sig32( params.pFc_fx, nr_fc_fft_filter, 17 ); /*Scaling ( *hReverb )->fft_filter_color_1.fft_spectrum_fx to Q31*/
1710 :
1711 : /* Copying the computed FFT colorations filters to the fft_filter components */
1712 159 : IF( NE_32( ( error = set_color_fft_filter_fx( pState, 0, pFft_wf_filter_ch0_fx ) ), IVAS_ERR_OK ) )
1713 : {
1714 0 : return error;
1715 : }
1716 :
1717 159 : IF( NE_32( ( error = set_color_fft_filter_fx( pState, 1, pFft_wf_filter_ch1_fx ) ), IVAS_ERR_OK ) )
1718 : {
1719 0 : return error;
1720 : }
1721 :
1722 : /* init predelay */
1723 159 : ivas_rev_delay_line_init( &( pState->predelay_line ), pState->pPredelay_buffer_fx, params.pre_delay, predelay_bf_len );
1724 :
1725 : /* set up feedback delay network */
1726 159 : IF( NE_32( ( error = setup_FDN_branches_fx( pState, ¶ms ) ), IVAS_ERR_OK ) )
1727 : {
1728 0 : return error;
1729 : }
1730 159 : free( pDsr_e );
1731 159 : free( pRt60_e );
1732 159 : *hReverb = pState;
1733 :
1734 159 : return error;
1735 : }
1736 : /*-------------------------------------------------------------------------
1737 : * ivas_reverb_close()
1738 : *
1739 : * Deallocate Crend reverberation handle
1740 : *------------------------------------------------------------------------*/
1741 :
1742 4431 : void ivas_reverb_close(
1743 : REVERB_HANDLE *hReverb_in /* i/o: Reverberator handle */
1744 : )
1745 : {
1746 : REVERB_HANDLE hReverb;
1747 : Word16 loop_idx;
1748 :
1749 4431 : hReverb = *hReverb_in;
1750 :
1751 4431 : test();
1752 4431 : IF( hReverb_in == NULL || *hReverb_in == NULL )
1753 : {
1754 4272 : return;
1755 : }
1756 :
1757 1431 : FOR( loop_idx = 0; loop_idx < IVAS_REV_MAX_NR_BRANCHES; loop_idx++ )
1758 : {
1759 1272 : IF( hReverb->loop_delay_buffer_fx[loop_idx] != NULL )
1760 : {
1761 1272 : free( hReverb->loop_delay_buffer_fx[loop_idx] );
1762 1272 : hReverb->loop_delay_buffer_fx[loop_idx] = NULL;
1763 : }
1764 : }
1765 :
1766 159 : free( hReverb->pPredelay_buffer_fx );
1767 159 : hReverb->pPredelay_buffer_fx = NULL;
1768 :
1769 159 : free( *hReverb_in );
1770 159 : *hReverb_in = NULL;
1771 :
1772 159 : return;
1773 : }
1774 : /*-----------------------------------------------------------------------------------------*
1775 : * Function post_fft_filter()
1776 : *
1777 : *
1778 : *-----------------------------------------------------------------------------------------*/
1779 :
1780 353080 : static void post_fft_filter_fx(
1781 : REVERB_HANDLE hReverb,
1782 : Word32 *input_L_fx,
1783 : Word32 *input_R_fx,
1784 : Word32 *buffer_L_fx,
1785 : Word32 *buffer_R_fx )
1786 : {
1787 :
1788 353080 : IF( hReverb->do_corr_filter )
1789 : {
1790 353080 : ivas_reverb_t2f_f2t_in_fx( &hReverb->fft_filter_ols, input_L_fx, input_R_fx, buffer_L_fx, buffer_R_fx );
1791 353080 : ivas_reverb_fft_filter_ComplexMul_fx( &hReverb->fft_filter_correl_0, buffer_L_fx );
1792 353080 : ivas_reverb_fft_filter_ComplexMul_fx( &hReverb->fft_filter_correl_1, buffer_R_fx );
1793 353080 : ivas_reverb_fft_filter_CrossMix_fx( buffer_L_fx, buffer_R_fx, hReverb->fft_filter_correl_0.fft_size );
1794 : }
1795 : ELSE
1796 : {
1797 0 : ivas_reverb_t2f_f2t_in_fx( &hReverb->fft_filter_ols, input_L_fx, input_R_fx, buffer_L_fx, buffer_R_fx );
1798 : }
1799 353080 : ivas_reverb_fft_filter_ComplexMul_fx( &hReverb->fft_filter_color_0, buffer_L_fx );
1800 353080 : ivas_reverb_fft_filter_ComplexMul_fx( &hReverb->fft_filter_color_1, buffer_R_fx );
1801 353080 : ivas_reverb_t2f_f2t_out_fx( &hReverb->fft_filter_ols, buffer_L_fx, buffer_R_fx, input_L_fx, input_R_fx );
1802 :
1803 353080 : return;
1804 : }
1805 : /*-----------------------------------------------------------------------------------------*
1806 : * Function reverb_block()
1807 : *
1808 : * Input a block (mono) and calculate the 2 output blocks.
1809 : *-----------------------------------------------------------------------------------------*/
1810 :
1811 353080 : static void reverb_block_fx(
1812 : REVERB_HANDLE hReverb,
1813 : Word32 *pInput_fx, /*Q11*/
1814 : Word32 *pOut0_fx,
1815 : Word32 *pOut1_fx )
1816 :
1817 : {
1818 353080 : UWord16 nr_branches = hReverb->nr_of_branches;
1819 353080 : UWord16 bsize = hReverb->full_block_size;
1820 353080 : UWord16 inner_bsize = INNER_BLK_SIZE;
1821 : UWord16 i, j, k, ns, branch_idx, blk_idx, start_sample_idx;
1822 : Word32 *pFFT_buf[2], FFT_buf_1[RV_FILTER_MAX_FFT_SIZE], FFT_buf_2[RV_FILTER_MAX_FFT_SIZE];
1823 : Word32 pFeedback_input_fx[INNER_BLK_SIZE];
1824 : Word32 pTemp_fx[INNER_BLK_SIZE];
1825 : Word32 *ppOutput_fx[IVAS_REV_MAX_NR_BRANCHES];
1826 : Word32 Output_fx[IVAS_REV_MAX_NR_BRANCHES][INNER_BLK_SIZE];
1827 353080 : move16();
1828 353080 : move16();
1829 353080 : move16();
1830 :
1831 353080 : pFFT_buf[0] = &FFT_buf_1[0];
1832 353080 : pFFT_buf[1] = &FFT_buf_2[0];
1833 :
1834 3177720 : FOR( branch_idx = 0; branch_idx < nr_branches; branch_idx++ )
1835 : {
1836 2824640 : ppOutput_fx[branch_idx] = (Word32 *) Output_fx + i_mult( branch_idx, inner_bsize );
1837 : }
1838 :
1839 1400640 : FOR( k = 0; k < bsize; k += inner_bsize )
1840 : {
1841 1047560 : Word32 *pO0 = &pOut0_fx[k];
1842 1047560 : Word32 *pO1 = &pOut1_fx[k];
1843 84852360 : FOR( i = 0; i < inner_bsize; i++ )
1844 : {
1845 83804800 : pO0[i] = 0;
1846 83804800 : move16();
1847 83804800 : pO1[i] = 0;
1848 83804800 : move16();
1849 : }
1850 :
1851 : /* feedback network: */
1852 9428040 : FOR( i = 0; i < nr_branches; i++ )
1853 : {
1854 8380480 : Word32 *pOutput_i_fx = &ppOutput_fx[i][0];
1855 8380480 : Word16 mixer_0_i = hReverb->mixer_fx[0][i];
1856 8380480 : move16();
1857 8380480 : Word16 mixer_1_i = hReverb->mixer_fx[1][i];
1858 8380480 : move16();
1859 : /* output and feedback are same, get sample from delay line ... */
1860 8380480 : ivas_rev_delay_line_get_sample_blk_fx( &( hReverb->delay_line[i] ), inner_bsize, pTemp_fx );
1861 8380480 : ivas_reverb_iir_filt_2taps_feed_blk_fx( &( hReverb->t60[i] ), inner_bsize, pTemp_fx, ppOutput_fx[i] );
1862 678818880 : FOR( ns = 0; ns < inner_bsize; ns++ )
1863 : {
1864 670438400 : pO0[ns] = L_add_sat( imult3216( pOutput_i_fx[ns], mixer_0_i ), pO0[ns] ); /* mixer ch 0 */
1865 670438400 : move32();
1866 670438400 : pO1[ns] = L_add_sat( imult3216( pOutput_i_fx[ns], mixer_1_i ), pO1[ns] ); /* mixer ch 1 */
1867 670438400 : move32();
1868 : }
1869 : }
1870 :
1871 9428040 : FOR( i = 0; i < nr_branches; i++ )
1872 : {
1873 8380480 : Word32 *pIn = &pInput_fx[k];
1874 :
1875 678818880 : FOR( ns = 0; ns < inner_bsize; ns++ )
1876 : {
1877 670438400 : pFeedback_input_fx[ns] = L_shr( pIn[ns], 3 ); // to make the Qfactor similar to pOutput
1878 670438400 : move32();
1879 : }
1880 :
1881 75424320 : FOR( j = 0; j < nr_branches; j++ )
1882 : {
1883 67043840 : Word32 gain_matrix_j_i = hReverb->gain_matrix_fx[j][i]; // Q31
1884 67043840 : move32();
1885 67043840 : Word32 *pOutput = &ppOutput_fx[j][0];
1886 5430551040 : FOR( ns = 0; ns < inner_bsize; ns++ )
1887 : {
1888 5363507200 : pFeedback_input_fx[ns] = ( L_add( Mpy_32_32( gain_matrix_j_i, pOutput[ns] ), pFeedback_input_fx[ns] ) );
1889 5363507200 : move32();
1890 : }
1891 : }
1892 :
1893 8380480 : ivas_rev_delay_line_feed_sample_blk_fx( &( hReverb->delay_line[i] ), inner_bsize, pFeedback_input_fx );
1894 : }
1895 : }
1896 :
1897 : Word16 r_shift;
1898 353080 : r_shift = add( find_guarded_bits_fx( hReverb->fft_filter_ols.fft_size ), 1 );
1899 : // Applying guard bits for the DoRTFT inside the post_fft_filter function
1900 84157880 : FOR( k = 0; k < hReverb->fft_filter_ols.block_size; k++ )
1901 : {
1902 83804800 : pOut0_fx[k] = (Word32) L_shr( pOut0_fx[k], ( r_shift ) );
1903 83804800 : move32();
1904 83804800 : pOut1_fx[k] = (Word32) L_shr( pOut1_fx[k], ( r_shift ) );
1905 83804800 : move32();
1906 : }
1907 : /* Applying FFT filter to each sub-frame */
1908 706160 : FOR( blk_idx = 0; blk_idx < hReverb->num_fft_subblocks; blk_idx++ )
1909 : {
1910 353080 : start_sample_idx = imult1616( blk_idx, hReverb->fft_subblock_size );
1911 353080 : post_fft_filter_fx( hReverb, pOut0_fx + start_sample_idx, pOut1_fx + start_sample_idx, pFFT_buf[0], pFFT_buf[1] );
1912 : }
1913 :
1914 84157880 : FOR( k = 0; k < hReverb->fft_filter_ols.block_size; k++ )
1915 : {
1916 83804800 : pOut0_fx[k] = (Word32) L_shl( pOut0_fx[k], 1 );
1917 83804800 : move32();
1918 83804800 : pOut1_fx[k] = (Word32) L_shl( pOut1_fx[k], 1 );
1919 83804800 : move32();
1920 : }
1921 :
1922 353080 : return;
1923 : }
1924 : /*-----------------------------------------------------------------------------------------*
1925 : * Function downmix_input_block()
1926 : *
1927 : * Downmix input to mono, taking also DSR gain into account
1928 : *-----------------------------------------------------------------------------------------*/
1929 :
1930 353080 : static ivas_error downmix_input_block_fx(
1931 : const REVERB_HANDLE hReverb,
1932 : Word32 *pcm_in[], /* i Q11 : the input PCM audio */
1933 : const AUDIO_CONFIG input_audio_config,
1934 : Word32 *pPcm_out, /* o Q11 : the output PCM audio */
1935 : const Word16 input_offset )
1936 : {
1937 : Word16 i, s, nchan_transport;
1938 353080 : Word32 dmx_gain_fx = hReverb->dmx_gain_fx;
1939 353080 : move32();
1940 353080 : SWITCH( input_audio_config )
1941 : {
1942 353080 : case IVAS_AUDIO_CONFIG_STEREO:
1943 : case IVAS_AUDIO_CONFIG_5_1:
1944 : case IVAS_AUDIO_CONFIG_7_1:
1945 : case IVAS_AUDIO_CONFIG_5_1_2:
1946 : case IVAS_AUDIO_CONFIG_5_1_4:
1947 : case IVAS_AUDIO_CONFIG_7_1_4:
1948 : case IVAS_AUDIO_CONFIG_ISM1:
1949 : case IVAS_AUDIO_CONFIG_ISM2:
1950 : case IVAS_AUDIO_CONFIG_ISM3:
1951 : case IVAS_AUDIO_CONFIG_ISM4:
1952 : {
1953 353080 : nchan_transport = audioCfg2channels( input_audio_config );
1954 84157880 : FOR( s = 0; s < hReverb->full_block_size; s++ )
1955 : {
1956 83804800 : Word32 temp = pcm_in[0][add( input_offset, s )];
1957 83804800 : move32();
1958 325862400 : FOR( i = 1; i < nchan_transport; i++ )
1959 : {
1960 242057600 : temp = L_add( temp, pcm_in[i][add( input_offset, s )] );
1961 : }
1962 83804800 : pPcm_out[s] = W_extract_h( W_shl( W_mult0_32_32( dmx_gain_fx, temp ), 9 ) ); // ( Q23 + Q11 + Q9 ) - 32 = Q11
1963 83804800 : move32();
1964 : }
1965 353080 : BREAK;
1966 : }
1967 0 : case IVAS_AUDIO_CONFIG_MONO: /* ~'ZOA_1' */
1968 : case IVAS_AUDIO_CONFIG_FOA:
1969 : case IVAS_AUDIO_CONFIG_HOA2:
1970 : case IVAS_AUDIO_CONFIG_HOA3:
1971 : {
1972 0 : FOR( s = 0; s < hReverb->full_block_size; s++ )
1973 : {
1974 0 : pPcm_out[s] = Mpy_32_32( dmx_gain_fx, L_shl_sat( pcm_in[0][input_offset + s], 8 ) ); //(Q23 + Q11 + Q8) - 31 = Q11
1975 0 : move32();
1976 : }
1977 0 : BREAK;
1978 : }
1979 0 : default:
1980 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unsupported input format for reverb" );
1981 : }
1982 :
1983 353080 : return IVAS_ERR_OK;
1984 : }
1985 : /*-----------------------------------------------------------------------------------------*
1986 : * Function predelay_block()
1987 : *
1988 : * Perform a predelay
1989 : *-----------------------------------------------------------------------------------------*/
1990 :
1991 353080 : static void predelay_block_fx(
1992 : const REVERB_HANDLE hReverb,
1993 : Word32 *pInput, /*Q11*/
1994 : Word32 *pOutput /*Q11*/ )
1995 : {
1996 : UWord16 i, idx, n_samples, blk_size;
1997 353080 : UWord16 max_blk_size = (UWord16) hReverb->predelay_line.Delay;
1998 353080 : IF( LT_32( max_blk_size, 2 ) )
1999 : {
2000 0 : IF( max_blk_size == 0 ) /* zero-length delay line: just copy the data from input to output */
2001 : {
2002 0 : FOR( i = 0; i < hReverb->full_block_size; i++ )
2003 : {
2004 0 : pOutput[i] = pInput[i]; // Q11
2005 0 : move32();
2006 : }
2007 : }
2008 : ELSE /* 1-sample length delay line: feed the data sample-by-sample */
2009 : {
2010 0 : FOR( i = 0; i < hReverb->full_block_size; i++ )
2011 : {
2012 0 : pOutput[i] = ivas_rev_delay_line_get_sample_fx( &( hReverb->predelay_line ) ); // Q11
2013 0 : move32();
2014 0 : ivas_rev_delay_line_feed_sample_fx( &( hReverb->predelay_line ), pInput[i] );
2015 : }
2016 : }
2017 : }
2018 : ELSE /* multiple-sample length delay line: use block processing */
2019 : {
2020 353080 : idx = 0;
2021 353080 : move16();
2022 353080 : n_samples = hReverb->full_block_size;
2023 2118480 : WHILE( n_samples > 0 )
2024 : {
2025 1765400 : blk_size = n_samples;
2026 1765400 : move16();
2027 1765400 : if ( GT_16( blk_size, max_blk_size ) )
2028 : {
2029 1412320 : blk_size = max_blk_size;
2030 1412320 : move16();
2031 : }
2032 1765400 : ivas_rev_delay_line_get_sample_blk_fx( &( hReverb->predelay_line ), blk_size, &pOutput[idx] );
2033 1765400 : ivas_rev_delay_line_feed_sample_blk_fx( &( hReverb->predelay_line ), blk_size, &pInput[idx] );
2034 1765400 : idx = (UWord16) UL_addNsD( idx, blk_size );
2035 1765400 : move16();
2036 1765400 : n_samples = (UWord16) UL_subNsD( n_samples, blk_size );
2037 1765400 : move16();
2038 : }
2039 : }
2040 :
2041 353080 : return;
2042 : }
2043 : /*-----------------------------------------------------------------------------------------*
2044 : * Function mix_output_block()
2045 : *
2046 : * mix one block of *pInL and *pInR samples into *pOutL and *pOutL respectively
2047 : *-----------------------------------------------------------------------------------------*/
2048 :
2049 99880 : static void mix_output_block_fx(
2050 : const REVERB_HANDLE hReverb,
2051 : const Word32 *pInL,
2052 : const Word32 *pInR,
2053 : Word32 *pOutL,
2054 : Word32 *pOutR )
2055 : {
2056 : UWord16 i;
2057 :
2058 23136680 : FOR( i = 0; i < hReverb->full_block_size; i++ )
2059 : {
2060 23036800 : pOutL[i] = L_add( pInL[i], ( L_shr( pOutL[i], 2 ) ) );
2061 23036800 : move32();
2062 23036800 : pOutR[i] = L_add( pInR[i], ( L_shr( pOutR[i], 2 ) ) );
2063 23036800 : move32();
2064 : }
2065 :
2066 99880 : return;
2067 : }
2068 : /*-----------------------------------------------------------------------------------------*
2069 : * ivas_reverb_process()
2070 : *
2071 : * Process the input PCM audio into output PCM audio, applying reverb
2072 : *-----------------------------------------------------------------------------------------*/
2073 :
2074 353080 : ivas_error ivas_reverb_process_fx(
2075 : const REVERB_HANDLE hReverb, /* i : Reverberator handle */
2076 : const AUDIO_CONFIG input_audio_config, /* i : reverb. input audio configuration */
2077 : const Word16 mix_signals, /* i : add reverb to output signal */
2078 : Word32 *pcm_in_fx[], /* i Q11 : the PCM audio to apply reverb on */
2079 : Word32 *pcm_out_fx[], /* o Q11 : the PCM audio with reverb applied */
2080 : const Word16 i_ts /* i : subframe index */
2081 : )
2082 : {
2083 : Word32 tmp0_fx[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES], tmp1_fx[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES], tmp2_fx[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES];
2084 : ivas_error error;
2085 :
2086 353080 : IF( NE_32( ( error = downmix_input_block_fx( hReverb, pcm_in_fx, input_audio_config, tmp1_fx, i_ts * hReverb->full_block_size ) ), IVAS_ERR_OK ) )
2087 : {
2088 0 : return error;
2089 : }
2090 :
2091 353080 : predelay_block_fx( hReverb, tmp1_fx, tmp0_fx );
2092 :
2093 353080 : reverb_block_fx( hReverb, tmp0_fx, tmp1_fx, tmp2_fx );
2094 :
2095 353080 : IF( mix_signals )
2096 : {
2097 99880 : mix_output_block_fx( hReverb, tmp1_fx, tmp2_fx, &pcm_out_fx[0][i_ts * hReverb->full_block_size], &pcm_out_fx[1][i_ts * hReverb->full_block_size] );
2098 : }
2099 : ELSE
2100 : {
2101 253200 : MVR2R_WORD32( tmp1_fx, &pcm_out_fx[0][i_mult( i_ts, hReverb->full_block_size )], hReverb->full_block_size );
2102 253200 : MVR2R_WORD32( tmp2_fx, &pcm_out_fx[1][i_mult( i_ts, hReverb->full_block_size )], hReverb->full_block_size );
2103 : }
2104 :
2105 353080 : return IVAS_ERR_OK;
2106 : }
2107 :
2108 : /*-------------------------------------------------------------------------
2109 : * ivas_binaural_reverb_processSubFrame()
2110 : *
2111 : * Compute the reverberation - room effect
2112 : *------------------------------------------------------------------------*/
2113 :
2114 :
2115 : /*-------------------------------------------------------------------------
2116 : * ivas_binaural_reverb_processSubFrame_fx()
2117 : *
2118 : * Compute the reverberation - room effect
2119 : *------------------------------------------------------------------------*/
2120 :
2121 112972 : void ivas_binaural_reverb_processSubframe_fx(
2122 : REVERB_STRUCT_HANDLE hReverb, /* i/o: binaural reverb handle */
2123 : const Word16 numInChannels, /* i : num inputs to be processed */
2124 : const Word16 numSlots, /* i : number of slots to be processed */
2125 : Word32 inReal[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], /* i (Q_in) : input CLDFB data real, Comment: This change swaps two first dimensions as first dimension is not constant. */
2126 : Word32 inImag[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], /* i (Q_in) : input CLDFB data imag */
2127 : Word32 outReal[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], /* o (Q_in) : output CLDFB data real */
2128 : Word32 outImag[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX] /* o (Q_in) : output CLDFB data imag */
2129 : )
2130 : {
2131 : /* Declare the required variables */
2132 : Word16 idx, bin, ch, sample, invertSampleIndex, tapIdx, *phaseShiftTypePr;
2133 : Word32 **tapRealPr_fx, **tapImagPr_fx;
2134 112972 : push_wmops( "binaural_reverb" );
2135 :
2136 : /* 1) Rotate the data in the loop buffer of the reverberator.
2137 : * Notice that the audio at the loop buffers is at time-inverted order
2138 : * for convolution purposes later on. */
2139 5361772 : FOR( bin = 0; bin < hReverb->numBins; bin++ )
2140 : {
2141 : /* Move the data forwards by blockSize (i.e. by the frame size of 16 CLDFB slots) */
2142 5248800 : Copy32( hReverb->loopBufReal_fx[bin], hReverb->loopBufReal_fx[bin] + numSlots, hReverb->loopBufLength[bin] );
2143 5248800 : Copy32( hReverb->loopBufImag_fx[bin], hReverb->loopBufImag_fx[bin] + numSlots, hReverb->loopBufLength[bin] );
2144 :
2145 : /* Add the data from the end of the loop to the beginning, with an attenuation factor
2146 : * according to RT60. This procedure generates an IIR decaying response. The response
2147 : * is decorrelated later on. */
2148 5248800 : v_multc_fixed( hReverb->loopBufReal_fx[bin] + hReverb->loopBufLength[bin], hReverb->loopAttenuationFactor_fx[bin], hReverb->loopBufReal_fx[bin], numSlots );
2149 5248800 : v_multc_fixed( hReverb->loopBufImag_fx[bin] + hReverb->loopBufLength[bin], hReverb->loopAttenuationFactor_fx[bin], hReverb->loopBufImag_fx[bin], numSlots );
2150 : }
2151 :
2152 : /* 2) Apply the determined pre-delay to the input audio, and add the delayed audio to the loop. */
2153 112972 : idx = hReverb->preDelayBufferIndex;
2154 562594 : FOR( sample = 0; sample < numSlots; sample++ )
2155 : {
2156 449622 : invertSampleIndex = sub( sub( numSlots, sample ), 1 );
2157 :
2158 21314822 : FOR( bin = 0; bin < hReverb->numBins; bin++ )
2159 : {
2160 : /* Add from pre-delay buffer a sample to the loop buffer, in a time-inverted order.
2161 : * Also apply the spectral gains determined for the reverberation */
2162 20865200 : Word32 temp_1 = Mpy_32_32( hReverb->preDelayBufferReal_fx[idx][bin], hReverb->reverbEqGains_fx[bin] ); /*Q_in*/
2163 20865200 : Word32 temp_2 = Mpy_32_32( hReverb->preDelayBufferImag_fx[idx][bin], hReverb->reverbEqGains_fx[bin] ); /*Q_in*/
2164 20865200 : hReverb->loopBufReal_fx[bin][invertSampleIndex] = L_add( hReverb->loopBufReal_fx[bin][invertSampleIndex], temp_1 ); /*Q_in*/
2165 20865200 : move32();
2166 20865200 : hReverb->loopBufImag_fx[bin][invertSampleIndex] = L_add( hReverb->loopBufImag_fx[bin][invertSampleIndex], temp_2 ); /*Q_in*/
2167 20865200 : move32();
2168 20865200 : hReverb->preDelayBufferReal_fx[idx][bin] = 0;
2169 20865200 : move32();
2170 20865200 : hReverb->preDelayBufferImag_fx[idx][bin] = 0;
2171 20865200 : move32();
2172 : }
2173 :
2174 : /* Add every second input channel as is to the pre-delay buffer, and every second input channel with
2175 : * 90 degrees phase shift to reduce energy imbalances between coherent and incoherent sounds */
2176 1370663 : FOR( ch = 0; ch < numInChannels; ch++ )
2177 : {
2178 921041 : IF( s_and( ch, 1 ) )
2179 : {
2180 : #ifdef VEC_ARITH_OPT_v1
2181 455702 : v_add_fixed_no_hdrm( hReverb->preDelayBufferReal_fx[idx], inReal[ch][sample], hReverb->preDelayBufferReal_fx[idx], hReverb->numBins );
2182 455702 : v_add_fixed_no_hdrm( hReverb->preDelayBufferImag_fx[idx], inImag[ch][sample], hReverb->preDelayBufferImag_fx[idx], hReverb->numBins );
2183 : #else /* VEC_ARITH_OPT_v1 */
2184 : v_add_fixed( hReverb->preDelayBufferReal_fx[idx], inReal[ch][sample], hReverb->preDelayBufferReal_fx[idx], hReverb->numBins, 0 );
2185 : v_add_fixed( hReverb->preDelayBufferImag_fx[idx], inImag[ch][sample], hReverb->preDelayBufferImag_fx[idx], hReverb->numBins, 0 );
2186 : #endif /* VEC_ARITH_OPT_v1 */
2187 : }
2188 : ELSE
2189 : {
2190 : #ifdef VEC_ARITH_OPT_v1
2191 465339 : v_sub_fixed_no_hdrm( hReverb->preDelayBufferReal_fx[idx], inImag[ch][sample], hReverb->preDelayBufferReal_fx[idx], hReverb->numBins );
2192 465339 : v_add_fixed_no_hdrm( hReverb->preDelayBufferImag_fx[idx], inReal[ch][sample], hReverb->preDelayBufferImag_fx[idx], hReverb->numBins );
2193 : #else /* VEC_ARITH_OPT_v1 */
2194 : v_sub_fixed( hReverb->preDelayBufferReal_fx[idx], inImag[ch][sample], hReverb->preDelayBufferReal_fx[idx], hReverb->numBins, 0 );
2195 : v_add_fixed( hReverb->preDelayBufferImag_fx[idx], inReal[ch][sample], hReverb->preDelayBufferImag_fx[idx], hReverb->numBins, 0 );
2196 : #endif /* VEC_ARITH_OPT_v1 */
2197 : }
2198 : }
2199 449622 : idx = add( idx, 1 ) % hReverb->preDelayBufferLength;
2200 449622 : move16();
2201 : }
2202 112972 : hReverb->preDelayBufferIndex = idx;
2203 112972 : move16();
2204 :
2205 : /* 3) Perform the filtering/decorrelating, using complex and sparse FIR filtering */
2206 5361772 : FOR( bin = 0; bin < hReverb->numBins; bin++ )
2207 : {
2208 15746400 : FOR( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
2209 : {
2210 : /* These tap pointers have been determined to point to the loop buffer at sparse locations */
2211 10497600 : tapRealPr_fx = hReverb->tapPointersReal_fx[bin][ch];
2212 10497600 : tapImagPr_fx = hReverb->tapPointersImag_fx[bin][ch];
2213 :
2214 10497600 : phaseShiftTypePr = hReverb->tapPhaseShiftType[bin][ch];
2215 :
2216 : /* Flush output */
2217 10497600 : set32_fx( hReverb->outputBufferReal_fx[bin][ch], 0, numSlots );
2218 10497600 : set32_fx( hReverb->outputBufferImag_fx[bin][ch], 0, numSlots );
2219 :
2220 : /* Add from temporally decaying sparse tap locations the audio to the output. */
2221 148955684 : FOR( tapIdx = 0; tapIdx < hReverb->taps[bin][ch]; tapIdx++ )
2222 : {
2223 138458084 : SWITCH( phaseShiftTypePr[tapIdx] )
2224 : {
2225 32232560 : case 0: /* 0 degrees phase */
2226 : #ifdef VEC_ARITH_OPT_v1
2227 32232560 : v_add_fixed_no_hdrm( hReverb->outputBufferReal_fx[bin][ch], tapRealPr_fx[tapIdx], hReverb->outputBufferReal_fx[bin][ch], numSlots );
2228 32232560 : v_add_fixed_no_hdrm( hReverb->outputBufferImag_fx[bin][ch], tapImagPr_fx[tapIdx], hReverb->outputBufferImag_fx[bin][ch], numSlots );
2229 : #else /* VEC_ARITH_OPT_v1 */
2230 : v_add_fixed( hReverb->outputBufferReal_fx[bin][ch], tapRealPr_fx[tapIdx], hReverb->outputBufferReal_fx[bin][ch], numSlots, 0 );
2231 : v_add_fixed( hReverb->outputBufferImag_fx[bin][ch], tapImagPr_fx[tapIdx], hReverb->outputBufferImag_fx[bin][ch], numSlots, 0 );
2232 : #endif /* VEC_ARITH_OPT_v1 */
2233 32232560 : BREAK;
2234 38307988 : case 1: /* 90 degrees phase */
2235 : #ifdef VEC_ARITH_OPT_v1
2236 38307988 : v_sub_fixed_no_hdrm( hReverb->outputBufferReal_fx[bin][ch], tapImagPr_fx[tapIdx], hReverb->outputBufferReal_fx[bin][ch], numSlots );
2237 38307988 : v_add_fixed_no_hdrm( hReverb->outputBufferImag_fx[bin][ch], tapRealPr_fx[tapIdx], hReverb->outputBufferImag_fx[bin][ch], numSlots );
2238 : #else /* VEC_ARITH_OPT_v1 */
2239 : v_sub_fixed( hReverb->outputBufferReal_fx[bin][ch], tapImagPr_fx[tapIdx], hReverb->outputBufferReal_fx[bin][ch], numSlots, 0 );
2240 : v_add_fixed( hReverb->outputBufferImag_fx[bin][ch], tapRealPr_fx[tapIdx], hReverb->outputBufferImag_fx[bin][ch], numSlots, 0 );
2241 : #endif /* VEC_ARITH_OPT_v1 */
2242 38307988 : BREAK;
2243 34487496 : case 2: /* 180 degrees phase */
2244 : #ifdef VEC_ARITH_OPT_v1
2245 34487496 : v_sub_fixed_no_hdrm( hReverb->outputBufferReal_fx[bin][ch], tapRealPr_fx[tapIdx], hReverb->outputBufferReal_fx[bin][ch], numSlots );
2246 34487496 : v_sub_fixed_no_hdrm( hReverb->outputBufferImag_fx[bin][ch], tapImagPr_fx[tapIdx], hReverb->outputBufferImag_fx[bin][ch], numSlots );
2247 : #else /* VEC_ARITH_OPT_v1 */
2248 : v_sub_fixed( hReverb->outputBufferReal_fx[bin][ch], tapRealPr_fx[tapIdx], hReverb->outputBufferReal_fx[bin][ch], numSlots, 0 );
2249 : v_sub_fixed( hReverb->outputBufferImag_fx[bin][ch], tapImagPr_fx[tapIdx], hReverb->outputBufferImag_fx[bin][ch], numSlots, 0 );
2250 : #endif /* VEC_ARITH_OPT_v1 */
2251 34487496 : BREAK;
2252 33430040 : default: /* 270 degrees phase */
2253 : #ifdef VEC_ARITH_OPT_v1
2254 33430040 : v_add_fixed_no_hdrm( hReverb->outputBufferReal_fx[bin][ch], tapImagPr_fx[tapIdx], hReverb->outputBufferReal_fx[bin][ch], numSlots );
2255 33430040 : v_sub_fixed_no_hdrm( hReverb->outputBufferImag_fx[bin][ch], tapRealPr_fx[tapIdx], hReverb->outputBufferImag_fx[bin][ch], numSlots );
2256 : #else /* VEC_ARITH_OPT_v1 */
2257 : v_add_fixed( hReverb->outputBufferReal_fx[bin][ch], tapImagPr_fx[tapIdx], hReverb->outputBufferReal_fx[bin][ch], numSlots, 0 );
2258 : v_sub_fixed( hReverb->outputBufferImag_fx[bin][ch], tapRealPr_fx[tapIdx], hReverb->outputBufferImag_fx[bin][ch], numSlots, 0 );
2259 : #endif /* VEC_ARITH_OPT_v1 */
2260 33430040 : BREAK;
2261 : }
2262 : }
2263 : }
2264 :
2265 : /* Generate diffuse field binaural coherence by mixing the incoherent reverberated channels with pre-defined gains */
2266 5248800 : IF( LE_16( bin, hReverb->highestBinauralCoherenceBin ) )
2267 : {
2268 790804 : IF( hReverb->useBinauralCoherence )
2269 : {
2270 3938158 : FOR( sample = 0; sample < numSlots; sample++ )
2271 : {
2272 : Word32 leftRe_fx, rightRe_fx, leftIm_fx, rightIm_fx;
2273 :
2274 3147354 : leftRe_fx = L_add( Mpy_32_32( hReverb->binauralCoherenceDirectGains_fx[bin], hReverb->outputBufferReal_fx[bin][0][sample] ),
2275 3147354 : Mpy_32_32( hReverb->binauralCoherenceCrossmixGains_fx[bin], hReverb->outputBufferReal_fx[bin][1][sample] ) ); // Q_in
2276 3147354 : rightRe_fx = L_add( Mpy_32_32( hReverb->binauralCoherenceDirectGains_fx[bin], hReverb->outputBufferReal_fx[bin][1][sample] ),
2277 3147354 : Mpy_32_32( hReverb->binauralCoherenceCrossmixGains_fx[bin], hReverb->outputBufferReal_fx[bin][0][sample] ) ); // Q_in
2278 3147354 : leftIm_fx = L_add( Mpy_32_32( hReverb->binauralCoherenceDirectGains_fx[bin], hReverb->outputBufferImag_fx[bin][0][sample] ),
2279 3147354 : Mpy_32_32( hReverb->binauralCoherenceCrossmixGains_fx[bin], hReverb->outputBufferImag_fx[bin][1][sample] ) ); // Q_in
2280 3147354 : rightIm_fx = L_add( Mpy_32_32( hReverb->binauralCoherenceDirectGains_fx[bin], hReverb->outputBufferImag_fx[bin][1][sample] ),
2281 3147354 : Mpy_32_32( hReverb->binauralCoherenceCrossmixGains_fx[bin], hReverb->outputBufferImag_fx[bin][0][sample] ) ); // Q_in
2282 :
2283 3147354 : hReverb->outputBufferReal_fx[bin][0][sample] = leftRe_fx; // Q_in
2284 3147354 : move32();
2285 3147354 : hReverb->outputBufferReal_fx[bin][1][sample] = rightRe_fx; // Q_in
2286 3147354 : move32();
2287 3147354 : hReverb->outputBufferImag_fx[bin][0][sample] = leftIm_fx; // Q_in
2288 3147354 : move32();
2289 3147354 : hReverb->outputBufferImag_fx[bin][1][sample] = rightIm_fx; // Q_in
2290 3147354 : move32();
2291 : }
2292 : }
2293 : }
2294 : }
2295 :
2296 : /* 4) Write data to output */
2297 338916 : FOR( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
2298 : {
2299 1125188 : FOR( sample = 0; sample < numSlots; sample++ )
2300 : {
2301 : /* Audio was in the temporally inverted order for convolution, re-invert audio to output */
2302 899244 : invertSampleIndex = sub( sub( numSlots, sample ), 1 );
2303 :
2304 42629644 : FOR( bin = 0; bin < hReverb->numBins; bin++ )
2305 : {
2306 41730400 : outReal[ch][sample][bin] = hReverb->outputBufferReal_fx[bin][ch][invertSampleIndex]; // Q_in
2307 41730400 : move32();
2308 41730400 : outImag[ch][sample][bin] = hReverb->outputBufferImag_fx[bin][ch][invertSampleIndex]; // Q_in
2309 41730400 : move32();
2310 : }
2311 13123484 : FOR( ; bin < CLDFB_NO_CHANNELS_MAX; bin++ )
2312 : {
2313 12224240 : outReal[ch][sample][bin] = 0;
2314 12224240 : move32();
2315 12224240 : outImag[ch][sample][bin] = 0;
2316 12224240 : move32();
2317 : }
2318 : }
2319 : }
2320 :
2321 112972 : pop_wmops();
2322 112972 : return;
2323 : }
2324 :
2325 : /*-------------------------------------------------------------------------
2326 : * ivas_binaural_reverb_open()
2327 : *
2328 : * Allocate and initialize binaural room reverberator handle
2329 : *------------------------------------------------------------------------*/
2330 271 : static ivas_error ivas_binaural_reverb_open_fx(
2331 : REVERB_STRUCT_HANDLE *hReverbPr, /* i/o: binaural reverb handle */
2332 : const Word16 numBins, /* i : Q0 number of CLDFB bins */
2333 : const Word16 numCldfbSlotsPerFrame, /* i : Q0 number of CLDFB slots per frame */
2334 : const Word32 sampling_rate, /* i : Q0 sampling rate */
2335 : const Word32 *revTimes_fx, /* i : Q31 reverberation times T60 for each CLDFB bin in seconds */
2336 : const Word32 *revEnes_fx, /* i : Q31 spectrum for reverberated sound at each CLDFB bin */
2337 : const Word16 preDelay /* i : Q0 reverb pre-delay in CLDFB slots */
2338 : )
2339 : {
2340 : Word16 bin, chIdx, k, len, scale, tmp;
2341 : REVERB_STRUCT_HANDLE hReverb;
2342 :
2343 271 : IF( ( *hReverbPr = (REVERB_STRUCT_HANDLE) malloc( sizeof( REVERB_STRUCT ) ) ) == NULL )
2344 : {
2345 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
2346 : }
2347 :
2348 271 : hReverb = *hReverbPr;
2349 :
2350 271 : hReverb->useBinauralCoherence = 1;
2351 271 : move16();
2352 271 : hReverb->preDelayBufferLength = 1;
2353 271 : move16();
2354 271 : hReverb->preDelayBufferIndex = 0;
2355 271 : move16();
2356 :
2357 271 : hReverb->numBins = numBins;
2358 271 : move16();
2359 271 : hReverb->blockSize = numCldfbSlotsPerFrame;
2360 271 : move16();
2361 :
2362 5962 : FOR( k = 0; k < REVERB_PREDELAY_MAX + 1; k++ )
2363 : {
2364 5691 : set32_fx( hReverb->preDelayBufferReal_fx[k], 0, hReverb->numBins );
2365 5691 : set32_fx( hReverb->preDelayBufferImag_fx[k], 0, hReverb->numBins );
2366 : }
2367 :
2368 12371 : FOR( bin = 0; bin < hReverb->numBins; bin++ )
2369 : {
2370 : /* Loop Buffer */
2371 :
2372 12100 : tmp = BASOP_Util_Divide1616_Scale( 500, add( bin, 1 ), &scale );
2373 12100 : tmp = shr( tmp, sub( 15, scale ) );
2374 12100 : hReverb->loopBufLengthMax[bin] = add( tmp, sub( CLDFB_NO_CHANNELS_MAX, bin ) );
2375 : // hReverb->loopBufLengthMax[bin] = (Word16) ( 500 / ( 1 + bin ) + ( CLDFB_NO_CHANNELS_MAX - bin ) );
2376 :
2377 12100 : len = add( hReverb->loopBufLengthMax[bin], hReverb->blockSize );
2378 :
2379 12100 : IF( ( hReverb->loopBufReal_fx[bin] = (Word32 *) malloc( len * sizeof( Word32 ) ) ) == NULL )
2380 : {
2381 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
2382 : }
2383 :
2384 12100 : if ( ( hReverb->loopBufImag_fx[bin] = (Word32 *) malloc( len * sizeof( Word32 ) ) ) == NULL )
2385 : {
2386 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
2387 : }
2388 12100 : set32_fx( hReverb->loopBufReal_fx[bin], 0, len );
2389 12100 : set32_fx( hReverb->loopBufImag_fx[bin], 0, len );
2390 :
2391 : /* Determine loop buffer length. The following formula is manually tuned to generate sufficiently long
2392 : * but not excessively long loops to generate reverberation. */
2393 : /* Note: the resulted length is very sensitive to the precision of the constants below (e.g. 1.45 vs. 1.45f) */
2394 : // hReverb->loopBufLength[bin] = (int16_t) ( 1.45 * (int16_t) ( revTimes[bin] * 150.0 ) + 1 );
2395 12100 : Word32 L_tmp_BufLength = L_shl( L_shr( Mpy_32_32( revTimes_fx[bin], 1258291200 /*150.0 in Q23*/ ), 23 ), 23 );
2396 12100 : L_tmp_BufLength = L_add( Mpy_32_32( 1556925645 /*1.45 in Q30*/, L_tmp_BufLength ), ONE_IN_Q22 );
2397 12100 : hReverb->loopBufLength[bin] = (Word16) L_shr( L_tmp_BufLength, 22 ); /*Q0*/
2398 12100 : move16();
2399 12100 : hReverb->loopBufLength[bin] = s_min( hReverb->loopBufLength[bin], hReverb->loopBufLengthMax[bin] );
2400 :
2401 : /* Sparse Filter Tap Locations */
2402 36300 : FOR( chIdx = 0; chIdx < BINAURAL_CHANNELS; chIdx++ )
2403 : {
2404 24200 : len = hReverb->loopBufLength[bin];
2405 24200 : move16();
2406 :
2407 24200 : IF( ( hReverb->tapPhaseShiftType[bin][chIdx] = (Word16 *) malloc( len * sizeof( Word16 ) ) ) == NULL )
2408 : {
2409 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
2410 : }
2411 24200 : set16_fx( hReverb->tapPhaseShiftType[bin][chIdx], 0, len );
2412 :
2413 24200 : IF( ( hReverb->tapPointersReal_fx[bin][chIdx] = (Word32 **) malloc( len * sizeof( Word32 * ) ) ) == NULL )
2414 : {
2415 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
2416 : }
2417 :
2418 24200 : IF( ( hReverb->tapPointersImag_fx[bin][chIdx] = (Word32 **) malloc( len * sizeof( Word32 * ) ) ) == NULL )
2419 : {
2420 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
2421 : }
2422 :
2423 24200 : len = hReverb->blockSize;
2424 24200 : move16();
2425 24200 : IF( ( hReverb->outputBufferReal_fx[bin][chIdx] = (Word32 *) malloc( len * sizeof( Word32 ) ) ) == NULL )
2426 : {
2427 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
2428 : }
2429 :
2430 24200 : IF( ( hReverb->outputBufferImag_fx[bin][chIdx] = (Word32 *) malloc( len * sizeof( Word32 ) ) ) == NULL )
2431 : {
2432 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
2433 : }
2434 24200 : set32_fx( hReverb->outputBufferReal_fx[bin][chIdx], 0, len );
2435 24200 : set32_fx( hReverb->outputBufferImag_fx[bin][chIdx], 0, len );
2436 : }
2437 : }
2438 :
2439 271 : ivas_binaural_reverb_setReverbTimes_fx( hReverb, sampling_rate, revTimes_fx, revEnes_fx );
2440 :
2441 : /*free(revTimes_fx);
2442 : free(revEnes_fx);*/
2443 :
2444 271 : ivas_binaural_reverb_setPreDelay_fx( hReverb, preDelay );
2445 :
2446 271 : return IVAS_ERR_OK;
2447 : }
2448 :
2449 : /*-------------------------------------------------------------------------
2450 : * ivas_binaural_reverb_open_fastconv()
2451 : *
2452 : * Allocate and initialize binaural room reverberator handle for FastConv
2453 : *------------------------------------------------------------------------*/
2454 0 : ivas_error ivas_binaural_reverb_open_fastconv_fx(
2455 : REVERB_STRUCT_HANDLE *hReverbPr, /* i/o: binaural reverb handle */
2456 : const Word16 numBins, /* i : number of CLDFB bins */
2457 : const Word16 numCldfbSlotsPerFrame, /* i : number of CLDFB slots per frame */
2458 : IVAS_ROOM_ACOUSTICS_CONFIG_DATA *roomAcoustics, /* i/o: room acoustics parameters */
2459 : const AUDIO_CONFIG internal_config, /* i : internal audio config for FastConv */
2460 : const Word32 sampling_rate, /* i : sampling rate */
2461 : const HRTFS_FASTCONV_HANDLE hHrtfFastConv /* i : FastConv HRTF handle */
2462 : )
2463 : {
2464 : ivas_error error;
2465 : const Word32 *revTimes;
2466 : const Word32 *revEne;
2467 : Word32 t60[CLDFB_NO_CHANNELS_MAX];
2468 : Word32 ene[CLDFB_NO_CHANNELS_MAX];
2469 : Word16 preDelay;
2470 :
2471 0 : error = IVAS_ERR_OK;
2472 :
2473 0 : IF( ( roomAcoustics != NULL ) && roomAcoustics->override )
2474 0 : {
2475 : /* THIS PART IS YET TO BE CONVERTED AS REVERB_UTILS.C IS NOT INVOKED IN GPROF */
2476 : float t60_flt[CLDFB_NO_CHANNELS_MAX];
2477 : float ene_flt[CLDFB_NO_CHANNELS_MAX];
2478 0 : revTimes = t60;
2479 0 : revEne = ene;
2480 0 : if ( NE_32( ( error = ivas_reverb_prepare_cldfb_params( roomAcoustics,
2481 : hHrtfFastConv,
2482 : internal_config,
2483 : false,
2484 : sampling_rate, t60_flt, ene_flt ) ),
2485 : IVAS_ERR_OK ) )
2486 : {
2487 0 : return error;
2488 : }
2489 0 : preDelay = (Word16) roundf( 48000.0f * roomAcoustics->acousticPreDelay / CLDFB_NO_CHANNELS_MAX );
2490 0 : floatToFixed_arrL( t60_flt, t60, Q31, CLDFB_NO_CHANNELS_MAX );
2491 0 : floatToFixed_arrL( ene_flt, ene, Q31, CLDFB_NO_CHANNELS_MAX );
2492 : }
2493 : ELSE
2494 : {
2495 0 : revTimes = hHrtfFastConv->fastconvReverberationTimes_fx; /*Q31*/
2496 0 : revEne = hHrtfFastConv->fastconvReverberationEneCorrections_fx; /*Q31*/
2497 0 : preDelay = 10;
2498 0 : move16();
2499 : }
2500 :
2501 0 : error = ivas_binaural_reverb_open_fx( hReverbPr, numBins, numCldfbSlotsPerFrame, sampling_rate, revTimes, revEne, preDelay );
2502 :
2503 0 : return error;
2504 : }
2505 :
2506 : /*-------------------------------------------------------------------------
2507 : * ivas_binaural_reverb_open_parambin()
2508 : *
2509 : * Allocate and initialize binaural room reverberator handle for ParamBin
2510 : *------------------------------------------------------------------------*/
2511 271 : ivas_error ivas_binaural_reverb_open_parambin(
2512 : REVERB_STRUCT_HANDLE *hReverbPr, /* i/o: binaural reverb handle */
2513 : const Word16 numBins, /* i : number of CLDFB bins Q0 */
2514 : const Word16 numCldfbSlotsPerFrame, /* i : number of CLDFB slots per frame Q0 */
2515 : IVAS_ROOM_ACOUSTICS_CONFIG_DATA *roomAcoustics, /* i/o: room acoustics parameters */
2516 : const Word32 sampling_rate, /* i : sampling rate Q0 */
2517 : const HRTFS_PARAMBIN_HANDLE hHrtfParambin /* i : Parametric binauralizer HRTF handle */
2518 : )
2519 : {
2520 : ivas_error error;
2521 : const Word32 *revTimes;
2522 : const Word32 *revEne;
2523 : Word32 t60[CLDFB_NO_CHANNELS_MAX];
2524 : Word32 ene[CLDFB_NO_CHANNELS_MAX];
2525 : Word16 preDelay;
2526 :
2527 271 : error = IVAS_ERR_OK;
2528 :
2529 271 : IF( ( roomAcoustics != NULL ) && roomAcoustics->override )
2530 : {
2531 0 : revTimes = t60;
2532 0 : revEne = ene;
2533 0 : preDelay = (Word16) L_shr_r( Mpy_32_32( 1677721600 /*800 in Q21*/, roomAcoustics->acousticPreDelay_fx /*Q27*/ ), Q17 ); /*Q0*/
2534 0 : move16();
2535 : }
2536 : ELSE
2537 : {
2538 271 : revTimes = hHrtfParambin->parametricReverberationTimes_fx; /*Q31*/
2539 271 : revEne = hHrtfParambin->parametricReverberationEneCorrections_fx; /*Q31*/
2540 271 : preDelay = 10;
2541 271 : move16();
2542 : }
2543 :
2544 271 : error = ivas_binaural_reverb_open_fx( hReverbPr, numBins, numCldfbSlotsPerFrame, sampling_rate, revTimes, revEne, preDelay );
2545 :
2546 271 : return error;
2547 : }
2548 :
2549 : /*-------------------------------------------------------------------------
2550 : * ivas_binaural_reverb_close()
2551 : *
2552 : * Close binaural room reverberator handle
2553 : *------------------------------------------------------------------------*/
2554 :
2555 271 : void ivas_binaural_reverb_close_fx(
2556 : REVERB_STRUCT_HANDLE *hReverb /* i/o: binaural reverb handle */
2557 : )
2558 : {
2559 : Word16 bin, chIdx;
2560 :
2561 271 : test();
2562 271 : IF( hReverb == NULL || *hReverb == NULL )
2563 : {
2564 0 : return;
2565 : }
2566 :
2567 12371 : FOR( bin = 0; bin < ( *hReverb )->numBins; bin++ )
2568 : {
2569 36300 : FOR( chIdx = 0; chIdx < BINAURAL_CHANNELS; chIdx++ )
2570 : {
2571 24200 : free( ( *hReverb )->tapPhaseShiftType[bin][chIdx] );
2572 24200 : free( ( *hReverb )->tapPointersReal_fx[bin][chIdx] );
2573 24200 : free( ( *hReverb )->tapPointersImag_fx[bin][chIdx] );
2574 24200 : free( ( *hReverb )->outputBufferReal_fx[bin][chIdx] );
2575 24200 : free( ( *hReverb )->outputBufferImag_fx[bin][chIdx] );
2576 : }
2577 12100 : free( ( *hReverb )->loopBufReal_fx[bin] );
2578 12100 : free( ( *hReverb )->loopBufImag_fx[bin] );
2579 : }
2580 :
2581 271 : free( ( *hReverb ) );
2582 271 : ( *hReverb ) = NULL;
2583 :
2584 271 : return;
2585 : }
|