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