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