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.h"
36 : #include "ivas_prot_rend.h"
37 : #include "ivas_cnst.h"
38 : #ifdef DEBUGGING
39 : #include "debug.h"
40 : #endif
41 : #include "math.h"
42 : #include "ivas_rom_rend.h"
43 : #include <assert.h>
44 : #include "wmc_auto.h"
45 :
46 :
47 : /* The reverberator structure implemented here is described in detail in:
48 : * Vilkamo, J., Neugebauer, B., & Plogsties, J. (2012). Sparse frequency-domain reverberator.
49 : * Journal of the Audio Engineering Society, 59(12), 936-943. */
50 :
51 : /*-------------------------------------------------------------------------
52 : * Local constants
53 : *------------------------------------------------------------------------*/
54 :
55 : #define BIN_REND_RANDOM_SEED 1 /* random seed for generating reverb decorrelators */
56 :
57 : #define CLDFB_SLOTS_PER_SECOND 800 /* Used for initializing reverb */
58 :
59 : #define REV_TIME_THRESHOLD ( 0.2f )
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 ( 0.40f ) /* flat section (==1) length of FFT filter window, in proportion to overlap */
64 : #define FFT_FILTER_WND_TRANS_REGION ( 0.15f ) /* transition (1->0) length of FFT filter window, in proportion to overlap */
65 : #define REF_LF_MIN ( 100.0f )
66 : #define REF_LF_MAX ( 250.0f )
67 : #define REF_HF_MIN ( 5000.0f )
68 : #define REF_HF_MAX ( 7950.0f )
69 : #define LF_BIAS ( 0.5f )
70 :
71 : #define DEFAULT_SRC_DIST ( 1.5f ) /* default source distance [m] for reverb dmx factor computing */
72 :
73 : #define IVAS_REVERB_FFT_SIZE_48K ( 512 )
74 : #define IVAS_REVERB_FFT_SIZE_32K ( 512 )
75 : #define IVAS_REVERB_FFT_SIZE_16K ( 256 )
76 : #define IVAS_REVERB_FFT_N_SUBBLOCKS_48K ( 1 )
77 : #define IVAS_REVERB_FFT_N_SUBBLOCKS_32K ( 1 )
78 : #define IVAS_REVERB_FFT_N_SUBBLOCKS_16K ( 1 )
79 :
80 : #define MAX_NR_OUTPUTS ( 2 )
81 :
82 : static const int16_t init_loop_delay[IVAS_REV_MAX_NR_BRANCHES] = { 37, 31, 29, 23, 19, 17, 13, 11 };
83 : static const int16_t default_loop_delay_48k[IVAS_REV_MAX_NR_BRANCHES] = { 2309, 1861, 1523, 1259, 1069, 919, 809, 719 };
84 : static const int16_t default_loop_delay_32k[IVAS_REV_MAX_NR_BRANCHES] = { 1531, 1237, 1013, 839, 709, 613, 541, 479 };
85 : static const int16_t default_loop_delay_16k[IVAS_REV_MAX_NR_BRANCHES] = { 769, 619, 509, 421, 353, 307, 269, 239 };
86 :
87 : /*------------------------------------------------------------------------------------------*
88 : * Local Struct definition
89 : *------------------------------------------------------------------------------------------*/
90 :
91 : typedef struct ivas_reverb_params_t
92 : {
93 : int16_t pre_delay; /* Delay of the FDC reverb, first peak after pre_delay samples. Note that */
94 : /* there may be non-zero samples earlier due to the filters being */
95 : /* linear-phase. */
96 : int16_t nr_loops; /* Number of feedback loops (= L) */
97 : int16_t pLoop_delays[IVAS_REV_MAX_NR_BRANCHES]; /* Delay for each feedback loop in samples. */
98 : float pLoop_feedback_matrix[IVAS_REV_MAX_NR_BRANCHES * IVAS_REV_MAX_NR_BRANCHES]; /* Feedback [L][L] matrix that mixes the signals of the loops. */
99 : int16_t nr_outputs; /* Nr of signals extracted from the loops (= S). */
100 : /* Currently this is fixed to 2. */
101 : float pLoop_extract_matrix[MAX_NR_OUTPUTS * IVAS_REV_MAX_NR_BRANCHES]; /* Mix [S][L] matrix from feedback loops to outputs. */
102 : /* In Matlab: [S x L] - Currently S=2, later may be more than 2 for speaker playback. */
103 : int16_t t60_filter_order; /* Filter order (length of vector) */
104 : float pT60_filter_coeff[MAX_NR_OUTPUTS * IVAS_REV_MAX_NR_BRANCHES * IVAS_REV_MAX_IIR_FILTER_LENGTH]; /* Filters [][] in feedback loops, controlling T60. */
105 : /* In Matlab: IIR: [(2 * L) x (<order> + 1)] (odd: b-vector, even: a-vector) */
106 : /* In Matlab: FIR: [L x <order>] */
107 : float *pFc; /* Center frequencies for FFT filter design */
108 : float *pRt60; /* RT60 values at these frequencies */
109 : float *pDsr; /* DSR values at these frequencies */
110 : const float *pHrtf_avg_pwr_response_l_const; /* The HRTF set's average left ear power response */
111 : const float *pHrtf_avg_pwr_response_r_const; /* The HRTF set's average right ear power response */
112 : const float *pHrtf_inter_aural_coherence_const; /* The HRTF set's inter-aural coherence for diffuse sound */
113 :
114 : int16_t do_corr_filter; /* Flag indicating whether correlation filters should be used. */
115 : /* Correlation only supported and needed for binaural playback (i.e. */
116 : /* when nr_outputs != 2 correlation filtering is never supported). */
117 : } ivas_reverb_params_t;
118 :
119 :
120 : /*------------------------------------------------------------------------------------------*
121 : * Static functions declarations
122 : *------------------------------------------------------------------------------------------*/
123 :
124 : static ivas_error calc_jot_t60_coeffs( float *pH_dB, const uint16_t nrFrequencies, float *pFrequencies, float *pCoeffA, float *pCoeffB, const float fNyquist );
125 :
126 :
127 : /*-------------------------------------------------------------------------
128 : * binRend_rand()
129 : *
130 : *
131 : *------------------------------------------------------------------------*/
132 :
133 138060625 : static uint16_t binRend_rand(
134 : REVERB_STRUCT_HANDLE hReverb /* i/o: binaural reverb handle */
135 : )
136 : {
137 138060625 : hReverb->binRend_RandNext = hReverb->binRend_RandNext * 1103515245 + 12345;
138 :
139 138060625 : return (uint16_t) ( hReverb->binRend_RandNext / 65536 ) % 32768;
140 : }
141 :
142 :
143 : /*-------------------------------------------------------------------------
144 : * ivas_binaural_reverb_setPreDelay()
145 : *
146 : *
147 : *------------------------------------------------------------------------*/
148 :
149 19636 : static void ivas_binaural_reverb_setPreDelay(
150 : REVERB_STRUCT_HANDLE hReverb, /* i/o: binaural reverb handle */
151 : const int16_t delaySamples /* i : reverb pre-delay in CLDFB slots */
152 : )
153 : {
154 19636 : if ( delaySamples < 1 )
155 : {
156 0 : hReverb->preDelayBufferLength = 1;
157 :
158 0 : return;
159 : }
160 :
161 19636 : if ( delaySamples > IVAS_REVERB_PREDELAY_MAX )
162 : {
163 15 : hReverb->preDelayBufferLength = IVAS_REVERB_PREDELAY_MAX;
164 :
165 15 : return;
166 : }
167 :
168 19621 : hReverb->preDelayBufferLength = delaySamples;
169 :
170 19621 : return;
171 : }
172 :
173 :
174 : /*-------------------------------------------------------------------------
175 : * ivas_binaural_reverb_setReverbTimes()
176 : *
177 : *
178 : *------------------------------------------------------------------------*/
179 :
180 19636 : static void ivas_binaural_reverb_setReverbTimes(
181 : REVERB_STRUCT_HANDLE hReverb, /* i/o: binaural reverb handle */
182 : const int32_t output_Fs, /* i : sampling_rate */
183 : const float *revTimes, /* i : reverberation times T60 for each CLDFB bin in seconds */
184 : const float *revEnes /* i : spectrum for reverberated sound at each CLDFB bin */
185 : )
186 : {
187 : int16_t bin, ch, tap, sample;
188 : float binCenterFreq, diffuseFieldICC, tmpVal, attenuationFactorPerSample;
189 : float intendedEnergy, actualizedEnergy, energyBuildup, currentEnergy, attenuationFactorPerSampleSq;
190 :
191 19636 : hReverb->binRend_RandNext = (uint16_t) BIN_REND_RANDOM_SEED;
192 19636 : hReverb->highestBinauralCoherenceBin = 0;
193 798966 : for ( bin = 0; bin < hReverb->numBins; bin++ )
194 : {
195 : /* Determine the diffuse field binaural coherence */
196 779330 : binCenterFreq = ( (float) bin + 0.5f ) / ( (float) hReverb->numBins ) * ( (float) output_Fs ) / 2.0f;
197 779330 : if ( bin == 0 )
198 : {
199 19636 : diffuseFieldICC = 1.0f;
200 : }
201 759694 : else if ( binCenterFreq < 2700.0f )
202 : {
203 115463 : diffuseFieldICC = sinf( EVS_PI * binCenterFreq / 550.0f + 1e-20f ) / ( EVS_PI * binCenterFreq / 550.0f + 1e-20f ) * ( 1.0f - binCenterFreq / 2700.0f );
204 115463 : hReverb->highestBinauralCoherenceBin = bin;
205 : }
206 : else
207 : {
208 644231 : diffuseFieldICC = 0.0f;
209 : }
210 :
211 : /* Mixing gains to generate a diffuse-binaural sound based on incoherent sound */
212 779330 : tmpVal = ( 1.0f - sqrtf( 1.0f - powf( diffuseFieldICC, 2.0 ) ) ) / 2.0f;
213 779330 : if ( diffuseFieldICC > 0 )
214 : {
215 76191 : hReverb->binauralCoherenceCrossmixGains[bin] = sqrtf( fabsf( tmpVal ) );
216 : }
217 : else
218 : {
219 703139 : hReverb->binauralCoherenceCrossmixGains[bin] = -sqrtf( fabsf( tmpVal ) );
220 : }
221 779330 : hReverb->binauralCoherenceDirectGains[bin] = sqrtf( 1.0f - fabsf( tmpVal ) );
222 :
223 : /* Determine attenuation factor that generates the appropriate energy decay according to reverberation time */
224 779330 : attenuationFactorPerSample = powf( 10.0f, -3.0f * ( 1.0f / ( (float) CLDFB_SLOTS_PER_SECOND * revTimes[bin] ) ) );
225 779330 : hReverb->loopAttenuationFactor[bin] = powf( attenuationFactorPerSample, hReverb->loopBufLength[bin] );
226 779330 : attenuationFactorPerSampleSq = attenuationFactorPerSample * attenuationFactorPerSample;
227 :
228 : /* Design sparse decorrelation filters. The decorrelation filters, due to random procedures involved,
229 : * may affect the spectrum of the output. The spectral effect is therefore monitored and compensated for. */
230 779330 : intendedEnergy = 0.0f;
231 779330 : actualizedEnergy = 0.0f;
232 :
233 2337990 : for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
234 : {
235 1558660 : energyBuildup = 0.0f;
236 1558660 : currentEnergy = 1.0f;
237 1558660 : tap = 0;
238 :
239 101462464 : for ( sample = 0; sample < hReverb->loopBufLength[bin]; sample++ )
240 : {
241 99903804 : intendedEnergy += currentEnergy;
242 :
243 : /* The randomization at the energy build up affects where the sparse taps are located */
244 99903804 : energyBuildup += currentEnergy + 0.1f * ( (float) binRend_rand( hReverb ) / PCM16_TO_FLT_FAC - 0.5f );
245 :
246 99903804 : if ( energyBuildup >= 1.0f ) /* A new filter tap is added at this condition */
247 : {
248 : /* Four efficient phase operations: n*pi/2, n=0,1,2,3 */
249 38156821 : hReverb->tapPhaseShiftType[bin][ch][tap] = (int16_t) ( binRend_rand( hReverb ) % 4 );
250 : /* Set the tapPointer to point to the determined sample at the loop buffer */
251 38156821 : hReverb->tapPointersReal[bin][ch][tap] = &( hReverb->loopBufReal[bin][sample] );
252 38156821 : hReverb->tapPointersImag[bin][ch][tap] = &( hReverb->loopBufImag[bin][sample] );
253 38156821 : energyBuildup -= 1.0f; /* A tap is added, thus remove its energy from the buildup */
254 38156821 : tap++;
255 38156821 : actualizedEnergy += 1.0f;
256 : }
257 99903804 : currentEnergy *= attenuationFactorPerSampleSq;
258 : }
259 : /* In some configurations with small T60s it is possible the number of taps randomizes to zero.
260 : Ensure at least 1 filter tap. */
261 1558660 : if ( tap == 0 )
262 : {
263 0 : hReverb->tapPhaseShiftType[bin][ch][0] = (int16_t) ( binRend_rand( hReverb ) % 4 );
264 0 : hReverb->tapPointersReal[bin][ch][0] = &( hReverb->loopBufReal[bin][0] );
265 0 : hReverb->tapPointersImag[bin][ch][0] = &( hReverb->loopBufImag[bin][0] );
266 0 : tap = 1;
267 0 : actualizedEnergy = 1;
268 : }
269 :
270 1558660 : hReverb->taps[bin][ch] = tap; /* Number of taps determined at the above random procedure */
271 : }
272 :
273 : /* The decorrelator design and IIR attenuation rate affects the energy of reverb, which is compensated here */
274 779330 : hReverb->reverbEqGains[bin] = sqrtf( revEnes[bin] ); /* Determined reverb spectrum */
275 779330 : hReverb->reverbEqGains[bin] *= sqrtf( intendedEnergy / actualizedEnergy ); /* Correction of random effects at the decorrelator design */
276 779330 : hReverb->reverbEqGains[bin] *= sqrtf( 0.5f * ( 1.0f - attenuationFactorPerSampleSq ) ); /* Correction of IIR decay rate */
277 : }
278 :
279 19636 : return;
280 : }
281 :
282 :
283 : /*-----------------------------------------------------------------------------------------*
284 : * Function compute_feedback_matrix()
285 : *
286 : * Compute the N x N matrix for the mixing the N feedback loop outputs into the N inputs again
287 : *-----------------------------------------------------------------------------------------*/
288 :
289 6607 : static ivas_error compute_feedback_matrix(
290 : float *pFeedbackMatrix,
291 : const int16_t n )
292 : {
293 : float u, v;
294 : int16_t i, j, x;
295 :
296 6607 : if ( n == 6 )
297 : {
298 : /* special case (there is no 6 x 6 Hadamard matrix in set R) */
299 0 : u = -1.0f / 3;
300 0 : v = 1.0f + u;
301 0 : for ( i = 0; i < n; i++ )
302 : {
303 0 : for ( j = 0; j < n; j++ )
304 : {
305 0 : if ( i == j )
306 : {
307 0 : pFeedbackMatrix[i * n + j] = v;
308 : }
309 : else
310 : {
311 0 : pFeedbackMatrix[i * n + j] = u;
312 : }
313 : }
314 : }
315 : }
316 : else
317 : {
318 6607 : if ( !( n == 4 || n == 8 || n == 16 ) )
319 : {
320 0 : return IVAS_ERR_INTERNAL; /* n must be 4, 6, 8 or 16, else ERROR */
321 : }
322 :
323 6607 : u = inv_sqrt( n );
324 :
325 6607 : if ( n == 4 )
326 : {
327 0 : u = -u;
328 : }
329 :
330 6607 : pFeedbackMatrix[0] = u;
331 26428 : for ( x = 1; x < n; x += x )
332 : {
333 66070 : for ( i = 0; i < x; i++ )
334 : {
335 184996 : for ( j = 0; j < x; j++ )
336 : {
337 138747 : pFeedbackMatrix[( i + x ) * n + j] = pFeedbackMatrix[i * n + j];
338 138747 : pFeedbackMatrix[i * n + j + x] = pFeedbackMatrix[i * n + j];
339 138747 : pFeedbackMatrix[( i + x ) * n + j + x] = -pFeedbackMatrix[i * n + j];
340 : }
341 : }
342 : }
343 :
344 6607 : if ( n == 4 )
345 : {
346 : /* special case */
347 0 : for ( j = 12; j < 16; j++ )
348 : {
349 0 : pFeedbackMatrix[j] = -pFeedbackMatrix[j];
350 : }
351 : }
352 : }
353 :
354 6607 : return IVAS_ERR_OK;
355 : }
356 :
357 :
358 : /*-----------------------------------------------------------------------------------------*
359 : * Function compute_2_out_extract_matrix()
360 : *
361 : * Compute the N x 2 matrix for mixing the N Jot feedback loops to 2 outputs
362 : *-----------------------------------------------------------------------------------------*/
363 :
364 6607 : static void compute_2_out_extract_matrix(
365 : float *pExtractMatrix,
366 : const int16_t n )
367 : {
368 : float ff;
369 : int16_t i;
370 :
371 6607 : ff = 1.0;
372 59463 : for ( i = 0; i < n; i++ )
373 : {
374 52856 : pExtractMatrix[i] = 1.0;
375 52856 : pExtractMatrix[i + n] = ff;
376 52856 : ff = -ff;
377 : }
378 :
379 6607 : return;
380 : }
381 :
382 :
383 : /*-----------------------------------------------------------------------------------------*
384 : * Function set_base_config()
385 : *
386 : * Set all jot reverb parameters that are independent of the input reverb configuration
387 : *-----------------------------------------------------------------------------------------*/
388 :
389 6607 : static ivas_error set_base_config(
390 : ivas_reverb_params_t *pParams,
391 : const int32_t output_Fs )
392 : {
393 : ivas_error error;
394 : int16_t loop_idx;
395 6607 : const int16_t *selected_loop_delay = NULL;
396 :
397 6607 : if ( pParams == NULL )
398 : {
399 0 : return IVAS_ERR_INTERNAL;
400 : }
401 :
402 6607 : pParams->pre_delay = 0;
403 6607 : pParams->nr_outputs = BINAURAL_CHANNELS;
404 6607 : pParams->nr_loops = IVAS_REV_MAX_NR_BRANCHES;
405 :
406 : /* set loop delays to default */
407 6607 : if ( output_Fs == 48000 )
408 : {
409 2016 : selected_loop_delay = default_loop_delay_48k;
410 : }
411 4591 : else if ( output_Fs == 32000 )
412 : {
413 2214 : selected_loop_delay = default_loop_delay_32k;
414 : }
415 2377 : else if ( output_Fs == 16000 )
416 : {
417 2377 : selected_loop_delay = default_loop_delay_16k;
418 : }
419 :
420 59463 : for ( loop_idx = 0; loop_idx < pParams->nr_loops; loop_idx++ )
421 : {
422 52856 : pParams->pLoop_delays[loop_idx] = selected_loop_delay[loop_idx];
423 : }
424 :
425 : /* set feedback and output matrices */
426 6607 : if ( ( error = compute_feedback_matrix( pParams->pLoop_feedback_matrix, pParams->nr_loops ) ) != IVAS_ERR_OK )
427 : {
428 0 : return error;
429 : }
430 :
431 6607 : compute_2_out_extract_matrix( pParams->pLoop_extract_matrix, pParams->nr_loops );
432 :
433 : /* pre-set the various filters; they will be set later based on reverb configuration */
434 6607 : pParams->t60_filter_order = 1; /* set to 1 in base config. */
435 :
436 6607 : if ( pParams->nr_outputs == 2 )
437 : {
438 6607 : pParams->do_corr_filter = 1;
439 : }
440 : else
441 : {
442 0 : pParams->do_corr_filter = 0;
443 : }
444 :
445 6607 : return IVAS_ERR_OK;
446 : }
447 :
448 :
449 : /*-----------------------------------------------------------------------------------------*
450 : * Function calc_dmx_gain()
451 : *
452 : * Computes the downmix gain
453 : *-----------------------------------------------------------------------------------------*/
454 :
455 5804 : static float calc_dmx_gain( void )
456 : {
457 5804 : const float dist = DEFAULT_SRC_DIST;
458 5804 : return sqrtf( 4.0f * EVS_PI * dist * dist / 0.001f );
459 : }
460 :
461 :
462 : /*-----------------------------------------------------------------------------------------*
463 : * Function calc_predelay()
464 : *
465 : * Calculate the predelay, taking shortest jot loop delay into account
466 : *-----------------------------------------------------------------------------------------*/
467 :
468 6607 : static void calc_predelay(
469 : ivas_reverb_params_t *pParams,
470 : float acoustic_predelay_sec,
471 : const int32_t output_Fs )
472 : {
473 : int16_t predelay, fbdelay, output_frame;
474 :
475 6607 : predelay = (int16_t) roundf( acoustic_predelay_sec * (float) output_Fs );
476 6607 : output_frame = (int16_t) ( output_Fs / FRAMES_PER_SEC );
477 6607 : fbdelay = pParams->pLoop_delays[pParams->nr_loops - 1];
478 6607 : predelay -= fbdelay;
479 :
480 6607 : if ( predelay < 0 )
481 : {
482 0 : predelay = 0;
483 : }
484 :
485 6607 : if ( output_frame < predelay )
486 : {
487 0 : predelay = output_frame;
488 : }
489 :
490 6607 : pParams->pre_delay = predelay;
491 :
492 6607 : return;
493 : }
494 :
495 :
496 : /*-----------------------------------------------------------------------------------------*
497 : * Function compute_t60_coeffs()
498 : *
499 : * Calculate Jot reverb's T60 filter coefficients
500 : *-----------------------------------------------------------------------------------------*/
501 :
502 6607 : static ivas_error compute_t60_coeffs(
503 : ivas_reverb_params_t *pParams,
504 : const int16_t nr_fc_fft_filter,
505 : const int32_t output_Fs )
506 : {
507 : int16_t bin_idx, loop_idx, tf_T60_len, len;
508 : float loop_delay_sec, freq_Nyquist, inv_hfs;
509 : float target_gains_db[RV_LENGTH_NR_FC];
510 : float norm_f[RV_LENGTH_NR_FC];
511 : float *pCoeffs_a, *pCoeffs_b;
512 : float *targetT60, *freqT60;
513 : ivas_error error;
514 :
515 6607 : targetT60 = pParams->pRt60;
516 6607 : freqT60 = pParams->pFc;
517 :
518 6607 : error = IVAS_ERR_OK;
519 6607 : tf_T60_len = nr_fc_fft_filter;
520 6607 : len = pParams->t60_filter_order + 1;
521 6607 : freq_Nyquist = 0.5f * (float) output_Fs;
522 :
523 : /* normalize pFrequencies: 0 .. 1/2 output_Fs --> 0.0 .. 1.0 */
524 6607 : inv_hfs = 1.0f / freq_Nyquist;
525 1400350 : for ( bin_idx = 0; bin_idx < tf_T60_len; bin_idx++ )
526 : {
527 1393743 : norm_f[bin_idx] = freqT60[bin_idx] * inv_hfs;
528 : }
529 :
530 59463 : for ( loop_idx = 0; loop_idx < pParams->nr_loops; loop_idx++ )
531 : {
532 52856 : loop_delay_sec = (float) pParams->pLoop_delays[loop_idx] / (float) output_Fs;
533 11202800 : for ( bin_idx = 0; bin_idx < tf_T60_len; bin_idx++ )
534 : {
535 11149944 : target_gains_db[bin_idx] = -60.0f * loop_delay_sec / targetT60[bin_idx];
536 11149944 : target_gains_db[bin_idx] = max( target_gains_db[bin_idx], -120.0f );
537 : }
538 :
539 52856 : pCoeffs_a = &pParams->pT60_filter_coeff[2 * len * loop_idx + len];
540 52856 : pCoeffs_b = &pParams->pT60_filter_coeff[2 * len * loop_idx];
541 52856 : if ( ( error = calc_jot_t60_coeffs( target_gains_db, tf_T60_len, norm_f, pCoeffs_a, pCoeffs_b, freq_Nyquist ) ) != IVAS_ERR_OK )
542 : {
543 0 : return error;
544 : }
545 : }
546 :
547 6607 : len = ( pParams->t60_filter_order + 1 ) >> 1; /* == floor( (order+1) / 2) */
548 59463 : for ( loop_idx = 0; loop_idx < pParams->nr_loops; loop_idx++ )
549 : {
550 52856 : pParams->pLoop_delays[loop_idx] -= len;
551 : }
552 :
553 6607 : return error;
554 : }
555 :
556 :
557 : /*-----------------------------------------------------------------------------------------*
558 : * Function calc_low_shelf_first_order_filter()
559 : *
560 : * Calculate 1st order low shelf filter
561 : *-----------------------------------------------------------------------------------------*/
562 :
563 52856 : static void calc_low_shelf_first_order_filter(
564 : float *pNum,
565 : float *pDen,
566 : const float f0,
567 : const float lin_gain_lf,
568 : const float lin_gain_hf )
569 : {
570 : float w0, gain;
571 :
572 52856 : w0 = tanf( EVS_PI * f0 / 2.0f );
573 52856 : gain = lin_gain_lf / lin_gain_hf;
574 :
575 52856 : if ( gain < 1.0f )
576 : {
577 0 : pNum[0] = 1 + w0 * gain;
578 0 : pNum[1] = w0 * gain - 1;
579 0 : pDen[0] = 1 + w0;
580 0 : pDen[1] = w0 - 1;
581 : }
582 : else
583 : {
584 52856 : pNum[0] = 1 + w0;
585 52856 : pNum[1] = w0 - 1;
586 52856 : pDen[0] = 1 + w0 / gain;
587 52856 : pDen[1] = w0 / gain - 1;
588 : }
589 :
590 : /* Normalize and adjust gain to match target amplitudes */
591 52856 : pNum[0] = ( pNum[0] / pDen[0] ) * lin_gain_hf;
592 52856 : pNum[1] = ( pNum[1] / pDen[0] ) * lin_gain_hf;
593 52856 : pDen[1] = pDen[1] / pDen[0];
594 52856 : pDen[0] = 1.0f;
595 :
596 52856 : return;
597 : }
598 :
599 :
600 : /*-----------------------------------------------------------------------------------------*
601 : * Function calc_jot_t60_coeffs()
602 : *
603 : * Calculate Jot reverb's T60 filters
604 : *-----------------------------------------------------------------------------------------*/
605 :
606 52856 : static ivas_error calc_jot_t60_coeffs(
607 : float *pH_dB,
608 : const uint16_t nrFrequencies,
609 : float *pFrequencies,
610 : float *pCoeffA,
611 : float *pCoeffB,
612 : const float fNyquist )
613 : {
614 52856 : const float ref_lf_min_norm = REF_LF_MIN / fNyquist;
615 52856 : const float ref_lf_max_norm = REF_LF_MAX / fNyquist;
616 52856 : const float ref_hf_min_norm = REF_HF_MIN / fNyquist;
617 52856 : const float ref_hf_max_norm = REF_HF_MAX / fNyquist;
618 : int16_t f_idx, minidx;
619 : float f0, tmp, minval, lf_target_gain_dB, hf_target_gain_dB, mid_crossing_gain_dB;
620 : uint16_t n_points_lf, n_points_hf;
621 : float lin_gain_lf, lin_gain_hf;
622 :
623 52856 : minidx = nrFrequencies - 1;
624 52856 : minval = 1e+20f;
625 52856 : lf_target_gain_dB = 0.0f;
626 52856 : hf_target_gain_dB = 0.0f;
627 52856 : n_points_lf = 0;
628 52856 : n_points_hf = 0;
629 :
630 11202800 : for ( f_idx = 0; f_idx < nrFrequencies; f_idx++ )
631 : {
632 11149944 : if ( ( pFrequencies[f_idx] >= ref_lf_min_norm ) && ( pFrequencies[f_idx] <= ref_lf_max_norm ) )
633 : {
634 126312 : lf_target_gain_dB += pH_dB[f_idx];
635 126312 : n_points_lf++;
636 : }
637 11149944 : if ( ( pFrequencies[f_idx] >= ref_hf_min_norm ) && ( pFrequencies[f_idx] <= ref_hf_max_norm ) )
638 : {
639 2262912 : hf_target_gain_dB += pH_dB[f_idx];
640 2262912 : n_points_hf++;
641 : }
642 : }
643 :
644 52856 : if ( ( n_points_lf == 0 ) || ( n_points_hf == 0 ) )
645 : {
646 0 : return IVAS_ERR_INTERNAL;
647 : }
648 :
649 52856 : lf_target_gain_dB = lf_target_gain_dB / (float) n_points_lf;
650 52856 : hf_target_gain_dB = hf_target_gain_dB / (float) n_points_hf;
651 52856 : mid_crossing_gain_dB = hf_target_gain_dB + LF_BIAS * ( lf_target_gain_dB - hf_target_gain_dB );
652 :
653 11097088 : for ( f_idx = 1; f_idx < nrFrequencies - 1; f_idx++ )
654 : {
655 11044232 : tmp = fabsf( pH_dB[f_idx] - mid_crossing_gain_dB );
656 11044232 : if ( tmp < minval )
657 : {
658 953216 : minval = tmp;
659 953216 : minidx = f_idx;
660 : }
661 : }
662 :
663 52856 : f0 = pFrequencies[minidx];
664 52856 : lin_gain_lf = powf( 10.0f, lf_target_gain_dB * 0.05f );
665 52856 : lin_gain_hf = powf( 10.0f, hf_target_gain_dB * 0.05f );
666 :
667 : /* call low-pass iir shelf */
668 52856 : calc_low_shelf_first_order_filter( pCoeffB, pCoeffA, f0, lin_gain_lf, lin_gain_hf );
669 :
670 52856 : return IVAS_ERR_OK;
671 : }
672 :
673 :
674 : /*-----------------------------------------------------------------------------------------*
675 : * Function initialize_reverb_filters()
676 : *
677 : * Set the number of branches (feedback loops) and Initializes the memory structure (pointers to data)
678 : *-----------------------------------------------------------------------------------------*/
679 :
680 5804 : static ivas_error initialize_reverb_filters(
681 : REVERB_HANDLE hReverb )
682 : {
683 : ivas_error error;
684 :
685 : /* init correlation and coloration filters */
686 5804 : if ( ( error = ivas_reverb_t2f_f2t_init( &hReverb->fft_filter_ols, hReverb->fft_size, hReverb->fft_subblock_size ) ) != IVAS_ERR_OK )
687 : {
688 0 : return error;
689 : }
690 :
691 5804 : if ( ( error = ivas_reverb_fft_filter_init( &hReverb->fft_filter_correl_0, hReverb->fft_size ) ) != IVAS_ERR_OK )
692 : {
693 0 : return error;
694 : }
695 :
696 5804 : if ( ( error = ivas_reverb_fft_filter_init( &hReverb->fft_filter_correl_1, hReverb->fft_size ) ) != IVAS_ERR_OK )
697 : {
698 0 : return error;
699 : }
700 :
701 5804 : if ( ( error = ivas_reverb_fft_filter_init( &hReverb->fft_filter_color_0, hReverb->fft_size ) ) != IVAS_ERR_OK )
702 : {
703 0 : return error;
704 : }
705 :
706 5804 : if ( ( error = ivas_reverb_fft_filter_init( &hReverb->fft_filter_color_1, hReverb->fft_size ) ) != IVAS_ERR_OK )
707 : {
708 0 : return error;
709 : }
710 :
711 5804 : return IVAS_ERR_OK;
712 : }
713 :
714 :
715 : /*-----------------------------------------------------------------------------------------*
716 : * Function set_t60_filter()
717 : *
718 : * Sets t60 number of taps and coefficients A and B
719 : *-----------------------------------------------------------------------------------------*/
720 :
721 52856 : static ivas_error set_t60_filter(
722 : REVERB_HANDLE hReverb,
723 : const uint16_t branch,
724 : const uint16_t nr_taps,
725 : const float coefA[],
726 : const float coefB[] )
727 : {
728 52856 : if ( branch >= hReverb->nr_of_branches )
729 : {
730 0 : return IVAS_ERR_INTERNAL;
731 : }
732 :
733 52856 : if ( nr_taps > IVAS_REV_MAX_IIR_FILTER_LENGTH )
734 : {
735 0 : return IVAS_ERR_INTERNAL;
736 : }
737 :
738 52856 : ivas_reverb_iir_filt_set( &( hReverb->t60[branch] ), nr_taps, coefA, coefB );
739 :
740 52856 : return IVAS_ERR_OK;
741 : }
742 :
743 :
744 : /*-----------------------------------------------------------------------------------------*
745 : * Function set_feedback_delay()
746 : *
747 : * Sets Delay of feedback branch in number of samples
748 : *-----------------------------------------------------------------------------------------*/
749 :
750 46432 : static ivas_error set_feedback_delay(
751 : REVERB_HANDLE hReverb,
752 : const uint16_t branch,
753 : const int16_t fb_delay )
754 : {
755 46432 : if ( branch >= hReverb->nr_of_branches )
756 : {
757 0 : return IVAS_ERR_INTERNAL;
758 : }
759 :
760 46432 : hReverb->delay_line[branch].Delay = fb_delay;
761 :
762 46432 : return IVAS_ERR_OK;
763 : }
764 :
765 :
766 : /*-----------------------------------------------------------------------------------------*
767 : * Function set_feedback_gain()
768 : *
769 : * Sets nr_of_branches feedback gain values in feedback matrix
770 : *-----------------------------------------------------------------------------------------*/
771 :
772 46432 : static ivas_error set_feedback_gain(
773 : REVERB_HANDLE hReverb,
774 : const uint16_t branch,
775 : const float *pGain )
776 : {
777 : uint16_t gain_idx;
778 46432 : if ( branch >= hReverb->nr_of_branches )
779 : {
780 0 : return IVAS_ERR_INTERNAL;
781 : }
782 :
783 417888 : for ( gain_idx = 0; gain_idx < hReverb->nr_of_branches; gain_idx++ )
784 : {
785 371456 : hReverb->gain_matrix[branch][gain_idx] = pGain[gain_idx];
786 : }
787 :
788 46432 : return IVAS_ERR_OK;
789 : }
790 :
791 :
792 : /*-----------------------------------------------------------------------------------------*
793 : * Function set_correl_fft_filter()
794 : *
795 : * Sets correlation filter complex gains
796 : *-----------------------------------------------------------------------------------------*/
797 :
798 13214 : static ivas_error set_correl_fft_filter(
799 : REVERB_HANDLE hReverb,
800 : const uint16_t channel,
801 : rv_fftwf_type_complex *pSpectrum )
802 : {
803 13214 : if ( channel > 1 )
804 : {
805 0 : return IVAS_ERR_INTERNAL;
806 : }
807 :
808 13214 : if ( channel == 0 )
809 : {
810 6607 : ivas_reverb_fft_filter_ConvertFFTWF_2_FFTR( pSpectrum, hReverb->fft_filter_correl_0.fft_spectrum, hReverb->fft_filter_correl_0.fft_size );
811 : }
812 : else
813 : {
814 6607 : ivas_reverb_fft_filter_ConvertFFTWF_2_FFTR( pSpectrum, hReverb->fft_filter_correl_1.fft_spectrum, hReverb->fft_filter_correl_1.fft_size );
815 : }
816 :
817 13214 : return IVAS_ERR_OK;
818 : }
819 :
820 :
821 : /*-----------------------------------------------------------------------------------------*
822 : * Function set_color_fft_filter()
823 : *
824 : * Sets coloration filter complex gains
825 : *-----------------------------------------------------------------------------------------*/
826 :
827 13214 : static ivas_error set_color_fft_filter(
828 : REVERB_HANDLE hReverb,
829 : const uint16_t channel,
830 : rv_fftwf_type_complex *pSpectrum )
831 : {
832 13214 : if ( channel > 1 )
833 : {
834 0 : return IVAS_ERR_INTERNAL;
835 : }
836 :
837 13214 : if ( channel == 0 )
838 : {
839 6607 : ivas_reverb_fft_filter_ConvertFFTWF_2_FFTR( pSpectrum, hReverb->fft_filter_color_0.fft_spectrum, hReverb->fft_filter_color_0.fft_size );
840 : }
841 : else
842 : {
843 6607 : ivas_reverb_fft_filter_ConvertFFTWF_2_FFTR( pSpectrum, hReverb->fft_filter_color_1.fft_spectrum, hReverb->fft_filter_color_1.fft_size );
844 : }
845 :
846 13214 : return IVAS_ERR_OK;
847 : }
848 :
849 :
850 : /*-----------------------------------------------------------------------------------------*
851 : * Function set_mixer_level()
852 : *
853 : * Sets Mixer level: to mix 2 output channels from 8 feedback branches
854 : *-----------------------------------------------------------------------------------------*/
855 :
856 11608 : static ivas_error set_mixer_level(
857 : REVERB_HANDLE hReverb,
858 : const uint16_t channel,
859 : const float level[] )
860 : {
861 : uint16_t branch_idx;
862 11608 : if ( channel >= BINAURAL_CHANNELS )
863 : {
864 0 : return IVAS_ERR_INTERNAL;
865 : }
866 :
867 104472 : for ( branch_idx = 0; branch_idx < hReverb->nr_of_branches; branch_idx++ )
868 : {
869 92864 : hReverb->mixer[channel][branch_idx] = level[branch_idx];
870 : }
871 :
872 11608 : return IVAS_ERR_OK;
873 : }
874 :
875 :
876 : /*-----------------------------------------------------------------------------------------*
877 : * Function clear_buffers()
878 : *
879 : * Clears buffers of delay lines and filters
880 : *-----------------------------------------------------------------------------------------*/
881 :
882 5804 : static void clear_buffers(
883 : REVERB_HANDLE hReverb )
884 : {
885 : int16_t branch_idx;
886 : ivas_rev_iir_filter_t *iirFilter;
887 : ivas_rev_delay_line_t *delay_line;
888 :
889 52236 : for ( branch_idx = 0; branch_idx < IVAS_REV_MAX_NR_BRANCHES; branch_idx++ )
890 : {
891 46432 : delay_line = &( hReverb->delay_line[branch_idx] );
892 46432 : set_f( delay_line->pBuffer, 0, delay_line->MaxDelay );
893 46432 : delay_line->BufferPos = 0;
894 :
895 46432 : iirFilter = &( hReverb->t60[branch_idx] );
896 46432 : set_f( iirFilter->pBuffer, 0, iirFilter->MaxTaps );
897 : }
898 :
899 5804 : ivas_reverb_t2f_f2t_ClearHistory( &hReverb->fft_filter_ols );
900 :
901 5804 : return;
902 : }
903 :
904 :
905 : /*-----------------------------------------------------------------------------------------*
906 : * Function set_fft_and_datablock_sizes()
907 : *
908 : * Sets frame size and fft-filter related sizes
909 : *-----------------------------------------------------------------------------------------*/
910 :
911 6607 : static void set_fft_and_datablock_sizes(
912 : REVERB_HANDLE hReverb,
913 : const int16_t subframe_len )
914 : {
915 6607 : hReverb->full_block_size = subframe_len;
916 6607 : if ( subframe_len == L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES )
917 : {
918 2016 : hReverb->fft_size = IVAS_REVERB_FFT_SIZE_48K;
919 2016 : hReverb->num_fft_subblocks = IVAS_REVERB_FFT_N_SUBBLOCKS_48K;
920 : }
921 4591 : else if ( subframe_len == L_FRAME32k / MAX_PARAM_SPATIAL_SUBFRAMES )
922 : {
923 2214 : hReverb->fft_size = IVAS_REVERB_FFT_SIZE_32K;
924 2214 : hReverb->num_fft_subblocks = IVAS_REVERB_FFT_N_SUBBLOCKS_32K;
925 : }
926 2377 : else if ( subframe_len == L_FRAME16k / MAX_PARAM_SPATIAL_SUBFRAMES )
927 : {
928 2377 : hReverb->fft_size = IVAS_REVERB_FFT_SIZE_16K;
929 2377 : hReverb->num_fft_subblocks = IVAS_REVERB_FFT_N_SUBBLOCKS_16K;
930 : }
931 : else
932 : {
933 0 : assert( 0 ); /* unsupported block size */
934 : }
935 :
936 6607 : hReverb->fft_subblock_size = subframe_len / hReverb->num_fft_subblocks;
937 :
938 6607 : return;
939 : }
940 :
941 :
942 : /*-----------------------------------------------------------------------------------------*
943 : * Function set_reverb_acoustic_data()
944 : *
945 : * Sets reverb acoustic data (room acoustics and HRTF), interpolating it to the filter grid
946 : *-----------------------------------------------------------------------------------------*/
947 :
948 6607 : static void set_reverb_acoustic_data(
949 : ivas_reverb_params_t *pParams,
950 : IVAS_ROOM_ACOUSTICS_CONFIG_DATA *pRoomAcoustics,
951 : const int16_t nr_fc_input,
952 : const int16_t nr_fc_fft_filter )
953 : {
954 : int16_t bin_idx;
955 : float ln_1e6_inverted, delay_diff, exp_argument;
956 : /* interpolate input table data for T60 and DSR to the FFT filter grid */
957 6607 : ivas_reverb_interpolate_acoustic_data( nr_fc_input, pRoomAcoustics->pFc_input, pRoomAcoustics->pAcoustic_rt60, pRoomAcoustics->pAcoustic_dsr,
958 6607 : nr_fc_fft_filter, pParams->pFc, pParams->pRt60, pParams->pDsr );
959 :
960 : /* adjust DSR for the delay difference */
961 6607 : delay_diff = pRoomAcoustics->inputPreDelay - pRoomAcoustics->acousticPreDelay;
962 6607 : ln_1e6_inverted = 1.0f / logf( 1e06f );
963 1400350 : for ( bin_idx = 0; bin_idx < nr_fc_fft_filter; bin_idx++ )
964 : {
965 1393743 : exp_argument = delay_diff / ( pParams->pRt60[bin_idx] * ln_1e6_inverted );
966 : /* Limit exponent to approx +/-100 dB in case of incoherent value of delay_diff, to prevent overflow */
967 1393743 : exp_argument = min( exp_argument, 23.0f );
968 1393743 : exp_argument = max( exp_argument, -23.0f );
969 1393743 : pParams->pDsr[bin_idx] *= expf( exp_argument );
970 : }
971 :
972 6607 : return;
973 : }
974 :
975 :
976 : /*-----------------------------------------------------------------------------------------*
977 : * Function setup_FDN_branches()
978 : *
979 : * Sets up feedback delay network system
980 : *-----------------------------------------------------------------------------------------*/
981 :
982 5804 : static ivas_error setup_FDN_branches(
983 : REVERB_HANDLE hReverb,
984 : ivas_reverb_params_t *pParams )
985 : {
986 : int16_t nr_coefs, branch_idx, channel_idx;
987 : ivas_error error;
988 5804 : error = IVAS_ERR_OK;
989 :
990 : /* initialize feedback branches */
991 52236 : for ( branch_idx = 0; branch_idx < IVAS_REV_MAX_NR_BRANCHES; branch_idx++ )
992 : {
993 46432 : ivas_rev_delay_line_init( &( hReverb->delay_line[branch_idx] ), hReverb->loop_delay_buffer[branch_idx], init_loop_delay[branch_idx], pParams->pLoop_delays[branch_idx] );
994 46432 : ivas_reverb_iir_filt_init( &( hReverb->t60[branch_idx] ), IVAS_REV_MAX_IIR_FILTER_LENGTH );
995 46432 : hReverb->mixer[0][branch_idx] = 0.0f;
996 46432 : hReverb->mixer[1][branch_idx] = 0.0f;
997 : }
998 5804 : clear_buffers( hReverb );
999 5804 : nr_coefs = pParams->t60_filter_order + 1;
1000 :
1001 5804 : if ( IVAS_REV_MAX_IIR_FILTER_LENGTH < nr_coefs )
1002 : {
1003 0 : return IVAS_ERR_INTERNAL;
1004 : }
1005 : else
1006 : {
1007 52236 : for ( branch_idx = 0; branch_idx < pParams->nr_loops; branch_idx++ )
1008 : {
1009 46432 : if ( ( error = set_feedback_delay( hReverb, branch_idx, pParams->pLoop_delays[branch_idx] ) ) != IVAS_ERR_OK )
1010 : {
1011 0 : return error;
1012 : }
1013 :
1014 46432 : if ( ( error = set_feedback_gain( hReverb, branch_idx, &( pParams->pLoop_feedback_matrix[branch_idx * pParams->nr_loops] ) ) ) != IVAS_ERR_OK )
1015 : {
1016 0 : return error;
1017 : }
1018 : }
1019 : }
1020 :
1021 17412 : for ( channel_idx = 0; channel_idx < pParams->nr_outputs; channel_idx++ )
1022 : {
1023 11608 : if ( ( error = set_mixer_level( hReverb, channel_idx, &( pParams->pLoop_extract_matrix[channel_idx * pParams->nr_loops] ) ) ) != IVAS_ERR_OK )
1024 : {
1025 0 : return error;
1026 : }
1027 : }
1028 :
1029 5804 : return error;
1030 : }
1031 :
1032 :
1033 : /*-------------------------------------------------------------------------
1034 : * ivas_reverb_open()
1035 : *
1036 : * Allocate and initialize FDN reverberation handle
1037 : *------------------------------------------------------------------------*/
1038 :
1039 6607 : ivas_error ivas_reverb_open(
1040 : REVERB_HANDLE *hReverb, /* i/o: Reverberator handle */
1041 : const HRTFS_STATISTICS_HANDLE hHrtfStatistics, /* i : HRTF statistics handle */
1042 : RENDER_CONFIG_HANDLE hRenderConfig, /* i : Renderer configuration handle */
1043 : const int32_t output_Fs /* i : output sampling rate */
1044 : )
1045 : {
1046 : ivas_error error;
1047 6607 : REVERB_HANDLE pState = *hReverb;
1048 : int16_t nr_coefs, branch_idx;
1049 : float *pCoef_a, *pCoef_b;
1050 : int16_t bin_idx, subframe_len, output_frame, predelay_bf_len, loop_idx;
1051 : ivas_reverb_params_t params;
1052 : rv_fftwf_type_complex pFft_wf_filter_ch0[RV_LENGTH_NR_FC];
1053 : rv_fftwf_type_complex pFft_wf_filter_ch1[RV_LENGTH_NR_FC];
1054 : float pColor_target_l[RV_LENGTH_NR_FC];
1055 : float pColor_target_r[RV_LENGTH_NR_FC];
1056 : float pTime_window[RV_FILTER_MAX_FFT_SIZE];
1057 : float freq_step;
1058 : int16_t fft_hist_size, transition_start, transition_length;
1059 : int16_t nr_fc_input, nr_fc_fft_filter;
1060 :
1061 6607 : output_frame = (int16_t) ( output_Fs / FRAMES_PER_SEC );
1062 6607 : subframe_len = output_frame / MAX_PARAM_SPATIAL_SUBFRAMES;
1063 6607 : predelay_bf_len = output_frame;
1064 6607 : nr_fc_input = hRenderConfig->roomAcoustics.nBands;
1065 :
1066 6607 : if ( *hReverb == NULL )
1067 : {
1068 : /* Allocate main reverb. handle */
1069 5804 : if ( ( pState = (REVERB_HANDLE) malloc( sizeof( REVERB_DATA ) ) ) == NULL )
1070 : {
1071 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for FDN Reverberator " );
1072 : }
1073 : }
1074 :
1075 6607 : if ( ( error = set_base_config( ¶ms, output_Fs ) ) != IVAS_ERR_OK )
1076 : {
1077 0 : return error;
1078 : }
1079 :
1080 6607 : if ( *hReverb == NULL )
1081 : {
1082 : /* Allocate memory for feedback delay lines */
1083 52236 : for ( loop_idx = 0; loop_idx < IVAS_REV_MAX_NR_BRANCHES; loop_idx++ )
1084 : {
1085 46432 : if ( ( pState->loop_delay_buffer[loop_idx] = (float *) malloc( params.pLoop_delays[loop_idx] * sizeof( float ) ) ) == NULL )
1086 : {
1087 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for FDN Reverberator" );
1088 : }
1089 : }
1090 :
1091 : /* Allocate memory for the pre-delay delay line */
1092 5804 : if ( ( pState->pPredelay_buffer = (float *) malloc( output_frame * sizeof( float ) ) ) == NULL )
1093 : {
1094 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for FDN Reverberator" );
1095 : }
1096 : }
1097 :
1098 6607 : pState->nr_of_branches = IVAS_REV_MAX_NR_BRANCHES;
1099 6607 : set_fft_and_datablock_sizes( pState, subframe_len );
1100 :
1101 6607 : nr_fc_fft_filter = ( pState->fft_size >> 1 ) + 1;
1102 :
1103 : /* === 'Control logic': compute the reverb processing parameters from the === */
1104 : /* === room, source and listener acoustic information provided in the reverb config === */
1105 : /* Setting up shared temporary buffers for fc, RT60, DSR, etc. */
1106 6607 : params.pRt60 = &pFft_wf_filter_ch1[0][0];
1107 6607 : params.pDsr = params.pRt60 + nr_fc_fft_filter;
1108 6607 : params.pFc = &pState->fft_filter_color_0.fft_spectrum[0];
1109 :
1110 : /* Note: these temp buffers can only be used before the final step of the FFT filter design : */
1111 : /* before calls to ivas_reverb_calc_correl_filters(...) or to ivas_reverb_calc_color_filters(...) */
1112 :
1113 : /* set the uniform frequency grid for FFT filtering */
1114 6607 : freq_step = 0.5f * output_Fs / ( nr_fc_fft_filter - 1 );
1115 1400350 : for ( bin_idx = 0; bin_idx < nr_fc_fft_filter; bin_idx++ )
1116 : {
1117 1393743 : params.pFc[bin_idx] = freq_step * bin_idx;
1118 : }
1119 :
1120 6607 : set_reverb_acoustic_data( ¶ms, &hRenderConfig->roomAcoustics, nr_fc_input, nr_fc_fft_filter );
1121 6607 : params.pHrtf_avg_pwr_response_l_const = hHrtfStatistics->average_energy_l;
1122 6607 : params.pHrtf_avg_pwr_response_r_const = hHrtfStatistics->average_energy_r;
1123 6607 : params.pHrtf_inter_aural_coherence_const = hHrtfStatistics->inter_aural_coherence;
1124 :
1125 : /* set reverb acoustic configuration based on renderer config */
1126 : #ifdef DEBUGGING
1127 : pState->pConfig.renderer_type_override = hRenderConfig->renderer_type_override;
1128 : #endif
1129 6607 : pState->pConfig.roomAcoustics.nBands = hRenderConfig->roomAcoustics.nBands;
1130 :
1131 6607 : if ( hRenderConfig->roomAcoustics.use_er == 1 )
1132 : {
1133 46 : pState->pConfig.roomAcoustics.use_er = hRenderConfig->roomAcoustics.use_er;
1134 46 : pState->pConfig.roomAcoustics.lowComplexity = hRenderConfig->roomAcoustics.lowComplexity;
1135 : }
1136 :
1137 : /* set up input downmix */
1138 6607 : if ( *hReverb == NULL )
1139 : {
1140 5804 : pState->dmx_gain = calc_dmx_gain();
1141 : }
1142 :
1143 : /* set up predelay - must be after set_base_config() and before compute_t60_coeffs() */
1144 6607 : calc_predelay( ¶ms, hRenderConfig->roomAcoustics.acousticPreDelay, output_Fs );
1145 :
1146 : /* set up jot reverb 60 filters - must be set up after set_reverb_acoustic_data() */
1147 6607 : if ( ( error = compute_t60_coeffs( ¶ms, nr_fc_fft_filter, output_Fs ) ) != IVAS_ERR_OK )
1148 : {
1149 0 : return error;
1150 : }
1151 :
1152 : /* Compute target levels (gains) for the coloration filters */
1153 6607 : ivas_reverb_calc_color_levels( output_Fs, nr_fc_fft_filter, params.nr_loops, params.pFc, params.pDsr, params.pHrtf_avg_pwr_response_l_const, params.pHrtf_avg_pwr_response_r_const,
1154 : params.pLoop_delays, params.pT60_filter_coeff, pColor_target_l, pColor_target_r );
1155 :
1156 : /* Defining appropriate windowing parameters for FFT filters to prevent aliasing */
1157 6607 : fft_hist_size = pState->fft_size - pState->fft_subblock_size;
1158 :
1159 6607 : transition_start = (int16_t) roundf( FFT_FILTER_WND_FLAT_REGION * fft_hist_size );
1160 6607 : transition_length = (int16_t) roundf( FFT_FILTER_WND_TRANS_REGION * fft_hist_size );
1161 :
1162 : /* Compute the window used for FFT filters */
1163 6607 : ivas_reverb_define_window_fft( pTime_window, transition_start, transition_length, nr_fc_fft_filter );
1164 :
1165 : /* === Copy parameters from ivas_reverb_params_t into DSP blocks === */
1166 : /* === to be used for subsequent audio signal processing === */
1167 6607 : if ( *hReverb == NULL )
1168 : {
1169 5804 : pState->do_corr_filter = params.do_corr_filter;
1170 :
1171 : /* clear & init jot reverb fft filters */
1172 5804 : if ( ( error = initialize_reverb_filters( pState ) ) != IVAS_ERR_OK )
1173 : {
1174 0 : return error;
1175 : }
1176 : }
1177 :
1178 6607 : if ( pState->do_corr_filter )
1179 : {
1180 : /* Computing correlation filters on the basis of target IA coherence */
1181 6607 : ivas_reverb_calc_correl_filters( params.pHrtf_inter_aural_coherence_const, pTime_window, pState->fft_size, 0.0f, pFft_wf_filter_ch0, pFft_wf_filter_ch1 );
1182 :
1183 : /* Copying the computed FFT correlation filters to the fft_filter components */
1184 6607 : if ( ( error = set_correl_fft_filter( pState, 0, pFft_wf_filter_ch0 ) ) != IVAS_ERR_OK )
1185 : {
1186 0 : return error;
1187 : }
1188 :
1189 6607 : if ( ( error = set_correl_fft_filter( pState, 1, pFft_wf_filter_ch1 ) ) != IVAS_ERR_OK )
1190 : {
1191 0 : return error;
1192 : }
1193 : }
1194 :
1195 : /* Computing coloration filters on the basis of target responses */
1196 6607 : ivas_reverb_calc_color_filters( pColor_target_l, pColor_target_r, pTime_window, pState->fft_size, 0.0f, pFft_wf_filter_ch0, pFft_wf_filter_ch1 );
1197 :
1198 : /* Copying the computed FFT colorations filters to the fft_filter components */
1199 6607 : if ( ( error = set_color_fft_filter( pState, 0, pFft_wf_filter_ch0 ) ) != IVAS_ERR_OK )
1200 : {
1201 0 : return error;
1202 : }
1203 :
1204 6607 : if ( ( error = set_color_fft_filter( pState, 1, pFft_wf_filter_ch1 ) ) != IVAS_ERR_OK )
1205 : {
1206 0 : return error;
1207 : }
1208 :
1209 6607 : if ( *hReverb == NULL )
1210 : {
1211 : /* init predelay */
1212 5804 : ivas_rev_delay_line_init( &( pState->predelay_line ), pState->pPredelay_buffer, params.pre_delay, predelay_bf_len );
1213 :
1214 : /* set up feedback delay network */
1215 5804 : if ( ( error = setup_FDN_branches( pState, ¶ms ) ) != IVAS_ERR_OK )
1216 : {
1217 0 : return error;
1218 : }
1219 : }
1220 : else
1221 : {
1222 803 : pState->predelay_line.Delay = params.pre_delay;
1223 : }
1224 :
1225 6607 : nr_coefs = params.t60_filter_order + 1;
1226 :
1227 59463 : for ( branch_idx = 0; branch_idx < params.nr_loops; branch_idx++ )
1228 : {
1229 52856 : pCoef_a = ¶ms.pT60_filter_coeff[2 * nr_coefs * branch_idx + nr_coefs];
1230 52856 : pCoef_b = ¶ms.pT60_filter_coeff[2 * nr_coefs * branch_idx];
1231 :
1232 52856 : if ( ( error = set_t60_filter( pState, branch_idx, nr_coefs, pCoef_a, pCoef_b ) ) != IVAS_ERR_OK )
1233 : {
1234 0 : return error;
1235 : }
1236 : }
1237 :
1238 6607 : *hReverb = pState;
1239 :
1240 6607 : return IVAS_ERR_OK;
1241 : }
1242 :
1243 :
1244 : /*-------------------------------------------------------------------------
1245 : * ivas_reverb_close()
1246 : *
1247 : * Deallocate Crend reverberation handle
1248 : *------------------------------------------------------------------------*/
1249 :
1250 136696 : void ivas_reverb_close(
1251 : REVERB_HANDLE *hReverb_in /* i/o: Reverberator handle */
1252 : )
1253 : {
1254 : REVERB_HANDLE hReverb;
1255 : int16_t loop_idx;
1256 :
1257 136696 : hReverb = *hReverb_in;
1258 :
1259 136696 : if ( hReverb_in == NULL || *hReverb_in == NULL )
1260 : {
1261 130892 : return;
1262 : }
1263 :
1264 52236 : for ( loop_idx = 0; loop_idx < IVAS_REV_MAX_NR_BRANCHES; loop_idx++ )
1265 : {
1266 46432 : if ( hReverb->loop_delay_buffer[loop_idx] != NULL )
1267 : {
1268 46432 : free( hReverb->loop_delay_buffer[loop_idx] );
1269 46432 : hReverb->loop_delay_buffer[loop_idx] = NULL;
1270 : }
1271 : }
1272 :
1273 5804 : free( hReverb->pPredelay_buffer );
1274 5804 : hReverb->pPredelay_buffer = NULL;
1275 :
1276 5804 : free( *hReverb_in );
1277 5804 : *hReverb_in = NULL;
1278 :
1279 5804 : return;
1280 : }
1281 :
1282 :
1283 : /*-----------------------------------------------------------------------------------------*
1284 : * Function post_fft_filter()
1285 : *
1286 : *
1287 : *-----------------------------------------------------------------------------------------*/
1288 :
1289 7814825 : static void post_fft_filter(
1290 : REVERB_HANDLE hReverb,
1291 : float *p0,
1292 : float *p1,
1293 : float *pBuffer_0,
1294 : float *pBuffer_1 )
1295 : {
1296 7814825 : if ( hReverb->do_corr_filter )
1297 : {
1298 7814825 : ivas_reverb_t2f_f2t_in( &hReverb->fft_filter_ols, p0, p1, pBuffer_0, pBuffer_1 );
1299 7814825 : ivas_reverb_fft_filter_ComplexMul( &hReverb->fft_filter_correl_0, pBuffer_0 );
1300 7814825 : ivas_reverb_fft_filter_ComplexMul( &hReverb->fft_filter_correl_1, pBuffer_1 );
1301 7814825 : ivas_reverb_fft_filter_CrossMix( pBuffer_0, pBuffer_1, hReverb->fft_filter_correl_0.fft_size );
1302 : }
1303 : else
1304 : {
1305 0 : ivas_reverb_t2f_f2t_in( &hReverb->fft_filter_ols, p0, p1, pBuffer_0, pBuffer_1 );
1306 : }
1307 :
1308 7814825 : ivas_reverb_fft_filter_ComplexMul( &hReverb->fft_filter_color_0, pBuffer_0 );
1309 7814825 : ivas_reverb_fft_filter_ComplexMul( &hReverb->fft_filter_color_1, pBuffer_1 );
1310 7814825 : ivas_reverb_t2f_f2t_out( &hReverb->fft_filter_ols, pBuffer_0, pBuffer_1, p0, p1 );
1311 :
1312 7814825 : return;
1313 : }
1314 :
1315 :
1316 : /*-----------------------------------------------------------------------------------------*
1317 : * Function reverb_block()
1318 : *
1319 : * Input a block (mono) and calculate the 2 output blocks.
1320 : *-----------------------------------------------------------------------------------------*/
1321 :
1322 7814825 : static void reverb_block(
1323 : REVERB_HANDLE hReverb,
1324 : float *pInput,
1325 : float *pOut0,
1326 : float *pOut1 )
1327 :
1328 : {
1329 7814825 : uint16_t nr_branches = hReverb->nr_of_branches;
1330 7814825 : uint16_t bsize = hReverb->full_block_size;
1331 7814825 : uint16_t inner_bsize = INNER_BLK_SIZE;
1332 : uint16_t i, j, k, ns, branch_idx, blk_idx, start_sample_idx;
1333 :
1334 : float *pFFT_buf[2], FFT_buf_1[RV_FILTER_MAX_FFT_SIZE], FFT_buf_2[RV_FILTER_MAX_FFT_SIZE];
1335 : float pFeedback_input[INNER_BLK_SIZE];
1336 : float pTemp[INNER_BLK_SIZE];
1337 : float *ppOutput[IVAS_REV_MAX_NR_BRANCHES];
1338 : float Output[IVAS_REV_MAX_NR_BRANCHES][INNER_BLK_SIZE];
1339 :
1340 7814825 : pFFT_buf[0] = &FFT_buf_1[0];
1341 7814825 : pFFT_buf[1] = &FFT_buf_2[0];
1342 :
1343 70333425 : for ( branch_idx = 0; branch_idx < nr_branches; branch_idx++ )
1344 : {
1345 62518600 : ppOutput[branch_idx] = (float *) Output + branch_idx * inner_bsize;
1346 : }
1347 :
1348 24017221 : for ( k = 0; k < bsize; k += inner_bsize )
1349 : {
1350 16202396 : float *pO0 = &pOut0[k];
1351 16202396 : float *pO1 = &pOut1[k];
1352 1312394076 : for ( i = 0; i < inner_bsize; i++ )
1353 : {
1354 1296191680 : pO0[i] = 0.0f;
1355 1296191680 : pO1[i] = 0.0f;
1356 : }
1357 :
1358 : /* feedback network: */
1359 145821564 : for ( i = 0; i < nr_branches; i++ )
1360 : {
1361 129619168 : float *pOutput_i = &ppOutput[i][0];
1362 129619168 : float mixer_0_i = hReverb->mixer[0][i];
1363 129619168 : float mixer_1_i = hReverb->mixer[1][i];
1364 :
1365 : /* output and feedback are same, get sample from delay line ... */
1366 129619168 : ivas_rev_delay_line_get_sample_blk( &( hReverb->delay_line[i] ), inner_bsize, pTemp );
1367 129619168 : ivas_reverb_iir_filt_2taps_feed_blk( &( hReverb->t60[i] ), inner_bsize, pTemp, ppOutput[i] );
1368 10499152608 : for ( ns = 0; ns < inner_bsize; ns++ )
1369 : {
1370 10369533440 : pO0[ns] += pOutput_i[ns] * mixer_0_i; /* mixer ch 0 */
1371 10369533440 : pO1[ns] += pOutput_i[ns] * mixer_1_i; /* mixer ch 1 */
1372 : }
1373 : }
1374 :
1375 145821564 : for ( i = 0; i < nr_branches; i++ )
1376 : {
1377 129619168 : float *pIn = &pInput[k];
1378 :
1379 10499152608 : for ( ns = 0; ns < inner_bsize; ns++ )
1380 : {
1381 10369533440 : pFeedback_input[ns] = pIn[ns];
1382 : }
1383 :
1384 1166572512 : for ( j = 0; j < nr_branches; j++ )
1385 : {
1386 1036953344 : float gain_matrix_j_i = hReverb->gain_matrix[j][i];
1387 1036953344 : float *pOutput = &ppOutput[j][0];
1388 83993220864 : for ( ns = 0; ns < inner_bsize; ns++ )
1389 : {
1390 82956267520 : pFeedback_input[ns] += gain_matrix_j_i * pOutput[ns];
1391 : }
1392 : }
1393 :
1394 129619168 : ivas_rev_delay_line_feed_sample_blk( &( hReverb->delay_line[i] ), inner_bsize, pFeedback_input );
1395 : }
1396 : }
1397 :
1398 : /* Applying FFT filter to each sub-frame */
1399 15629650 : for ( blk_idx = 0; blk_idx < hReverb->num_fft_subblocks; blk_idx++ )
1400 : {
1401 7814825 : start_sample_idx = blk_idx * hReverb->fft_subblock_size;
1402 7814825 : post_fft_filter( hReverb, pOut0 + start_sample_idx, pOut1 + start_sample_idx, pFFT_buf[0], pFFT_buf[1] );
1403 : }
1404 :
1405 7814825 : return;
1406 : }
1407 :
1408 :
1409 : /*-----------------------------------------------------------------------------------------*
1410 : * Function downmix_input_block()
1411 : *
1412 : * Downmix input to mono, taking also DSR gain into account
1413 : *-----------------------------------------------------------------------------------------*/
1414 :
1415 7814825 : static ivas_error downmix_input_block(
1416 : const REVERB_HANDLE hReverb,
1417 : float *pcm_in[],
1418 : const AUDIO_CONFIG input_audio_config,
1419 : float *pPcm_out,
1420 : const int16_t input_offset )
1421 : {
1422 : int16_t i, s, nchan_transport;
1423 7814825 : float dmx_gain = hReverb->dmx_gain;
1424 :
1425 7814825 : switch ( input_audio_config )
1426 : {
1427 5988575 : case IVAS_AUDIO_CONFIG_STEREO:
1428 : case IVAS_AUDIO_CONFIG_5_1:
1429 : case IVAS_AUDIO_CONFIG_7_1:
1430 : case IVAS_AUDIO_CONFIG_5_1_2:
1431 : case IVAS_AUDIO_CONFIG_5_1_4:
1432 : case IVAS_AUDIO_CONFIG_7_1_4:
1433 : case IVAS_AUDIO_CONFIG_ISM1:
1434 : case IVAS_AUDIO_CONFIG_ISM2:
1435 : case IVAS_AUDIO_CONFIG_ISM3:
1436 : case IVAS_AUDIO_CONFIG_ISM4:
1437 : {
1438 5988575 : nchan_transport = audioCfg2channels( input_audio_config );
1439 1000888255 : for ( s = 0; s < hReverb->full_block_size; s++ )
1440 : {
1441 994899680 : float temp = pcm_in[0][input_offset + s];
1442 2480019840 : for ( i = 1; i < nchan_transport; i++ )
1443 : {
1444 1485120160 : temp += pcm_in[i][input_offset + s];
1445 : }
1446 994899680 : pPcm_out[s] = dmx_gain * temp;
1447 : }
1448 5988575 : break;
1449 : }
1450 1826250 : case IVAS_AUDIO_CONFIG_MONO: /* ~'ZOA_1' */
1451 : case IVAS_AUDIO_CONFIG_FOA:
1452 : case IVAS_AUDIO_CONFIG_HOA2:
1453 : case IVAS_AUDIO_CONFIG_HOA3:
1454 : {
1455 303118250 : for ( s = 0; s < hReverb->full_block_size; s++ )
1456 : {
1457 301292000 : pPcm_out[s] = dmx_gain * pcm_in[0][input_offset + s];
1458 : }
1459 1826250 : break;
1460 : }
1461 0 : default:
1462 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unsupported input format for reverb" );
1463 : break;
1464 : }
1465 :
1466 7814825 : return IVAS_ERR_OK;
1467 : }
1468 :
1469 :
1470 : /*-----------------------------------------------------------------------------------------*
1471 : * Function predelay_block()
1472 : *
1473 : * Perform a predelay
1474 : *-----------------------------------------------------------------------------------------*/
1475 :
1476 7814825 : static void predelay_block(
1477 : const REVERB_HANDLE hReverb,
1478 : float *pInput,
1479 : float *pOutput )
1480 : {
1481 : uint16_t i, idx, n_samples, blk_size;
1482 7814825 : uint16_t max_blk_size = (uint16_t) hReverb->predelay_line.Delay;
1483 :
1484 7814825 : if ( max_blk_size < 2 )
1485 : {
1486 0 : if ( max_blk_size == 0 ) /* zero-length delay line: just copy the data from input to output */
1487 : {
1488 0 : for ( i = 0; i < hReverb->full_block_size; i++ )
1489 : {
1490 0 : pOutput[i] = pInput[i];
1491 : }
1492 : }
1493 : else /* 1-sample length delay line: feed the data sample-by-sample */
1494 : {
1495 0 : for ( i = 0; i < hReverb->full_block_size; i++ )
1496 : {
1497 0 : pOutput[i] = ivas_rev_delay_line_get_sample( &( hReverb->predelay_line ) );
1498 0 : ivas_rev_delay_line_feed_sample( &( hReverb->predelay_line ), pInput[i] );
1499 : }
1500 : }
1501 : }
1502 : else /* multiple-sample length delay line: use block processing */
1503 : {
1504 7814825 : idx = 0;
1505 7814825 : n_samples = hReverb->full_block_size;
1506 46758806 : while ( n_samples > 0 )
1507 : {
1508 38943981 : blk_size = n_samples;
1509 38943981 : if ( blk_size > max_blk_size )
1510 : {
1511 31129156 : blk_size = max_blk_size;
1512 : }
1513 38943981 : ivas_rev_delay_line_get_sample_blk( &( hReverb->predelay_line ), blk_size, &pOutput[idx] );
1514 38943981 : ivas_rev_delay_line_feed_sample_blk( &( hReverb->predelay_line ), blk_size, &pInput[idx] );
1515 38943981 : idx += blk_size;
1516 38943981 : n_samples -= blk_size;
1517 : }
1518 : }
1519 :
1520 7814825 : return;
1521 : }
1522 :
1523 :
1524 : /*-----------------------------------------------------------------------------------------*
1525 : * Function mix_output_block()
1526 : *
1527 : * mix one block of *pInL and *pInR samples into *pOutL and *pOutL respectively
1528 : *-----------------------------------------------------------------------------------------*/
1529 :
1530 2151812 : static void mix_output_block(
1531 : const REVERB_HANDLE hReverb,
1532 : const float *pInL,
1533 : const float *pInR,
1534 : float *pOutL,
1535 : float *pOutR )
1536 : {
1537 : uint16_t i;
1538 :
1539 370472452 : for ( i = 0; i < hReverb->full_block_size; i++ )
1540 : {
1541 368320640 : pOutL[i] += pInL[i];
1542 368320640 : pOutR[i] += pInR[i];
1543 : }
1544 :
1545 2151812 : return;
1546 : }
1547 :
1548 :
1549 : /*-----------------------------------------------------------------------------------------*
1550 : * ivas_reverb_process()
1551 : *
1552 : * Process the input PCM audio into output PCM audio, applying reverb
1553 : *-----------------------------------------------------------------------------------------*/
1554 :
1555 7814825 : ivas_error ivas_reverb_process(
1556 : const REVERB_HANDLE hReverb, /* i : Reverberator handle */
1557 : const AUDIO_CONFIG input_audio_config, /* i : reverb. input audio configuration */
1558 : const int16_t mix_signals, /* i : add reverb to output signal */
1559 : float *pcm_in[], /* i : the PCM audio to apply reverb on */
1560 : float *pcm_out[], /* o : the PCM audio with reverb applied */
1561 : const int16_t i_ts /* i : subframe index */
1562 : )
1563 : {
1564 : float tmp0[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES], tmp1[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES], tmp2[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES];
1565 : ivas_error error;
1566 :
1567 7814825 : if ( ( error = downmix_input_block( hReverb, pcm_in, input_audio_config, tmp1, i_ts * hReverb->full_block_size ) ) != IVAS_ERR_OK )
1568 : {
1569 0 : return error;
1570 : }
1571 :
1572 7814825 : predelay_block( hReverb, tmp1, tmp0 );
1573 :
1574 7814825 : reverb_block( hReverb, tmp0, tmp1, tmp2 );
1575 :
1576 7814825 : if ( mix_signals )
1577 : {
1578 2151812 : mix_output_block( hReverb, tmp1, tmp2, &pcm_out[0][i_ts * hReverb->full_block_size], &pcm_out[1][i_ts * hReverb->full_block_size] );
1579 : }
1580 : else
1581 : {
1582 5663013 : mvr2r( tmp1, &pcm_out[0][i_ts * hReverb->full_block_size], hReverb->full_block_size );
1583 5663013 : mvr2r( tmp2, &pcm_out[1][i_ts * hReverb->full_block_size], hReverb->full_block_size );
1584 : }
1585 :
1586 7814825 : return IVAS_ERR_OK;
1587 : }
1588 :
1589 :
1590 : /*-------------------------------------------------------------------------
1591 : * ivas_binaural_reverb_processSubFrame()
1592 : *
1593 : * Compute the reverberation - room effect
1594 : *------------------------------------------------------------------------*/
1595 :
1596 5898338 : void ivas_binaural_reverb_processSubframe(
1597 : REVERB_STRUCT_HANDLE hReverb, /* i/o: binaural reverb handle */
1598 : const int16_t numInChannels, /* i : num inputs to be processed */
1599 : const int16_t numSlots, /* i : number of slots to be processed */
1600 : float inReal[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], /* i : input CLDFB data real, Comment: This change swaps two first dimensions as first dimension is not constant. */
1601 : float inImag[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], /* i : input CLDFB data imag */
1602 : float outReal[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], /* o : output CLDFB data real */
1603 : float outImag[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX] /* o : output CLDFB data imag */
1604 : )
1605 : {
1606 : /* Declare the required variables */
1607 : int16_t idx, bin, ch, sample, invertSampleIndex, tapIdx, *phaseShiftTypePr;
1608 : float **tapRealPr, **tapImagPr;
1609 5898338 : push_wmops( "binaural_reverb" );
1610 :
1611 : /* 1) Rotate the data in the loop buffer of the reverberator.
1612 : * Notice that the audio at the loop buffers is at time-inverted order
1613 : * for convolution purposes later on. */
1614 262348658 : for ( bin = 0; bin < hReverb->numBins; bin++ )
1615 : {
1616 : /* Move the data forwards by blockSize (i.e. by the frame size of 16 CLDFB slots) */
1617 256450320 : mvr2r( hReverb->loopBufReal[bin], hReverb->loopBufReal[bin] + numSlots, hReverb->loopBufLength[bin] );
1618 256450320 : mvr2r( hReverb->loopBufImag[bin], hReverb->loopBufImag[bin] + numSlots, hReverb->loopBufLength[bin] );
1619 :
1620 : /* Add the data from the end of the loop to the beginning, with an attenuation factor
1621 : * according to RT60. This procedure generates an IIR decaying response. The response
1622 : * is decorrelated later on. */
1623 256450320 : v_multc( hReverb->loopBufReal[bin] + hReverb->loopBufLength[bin], hReverb->loopAttenuationFactor[bin], hReverb->loopBufReal[bin], numSlots );
1624 256450320 : v_multc( hReverb->loopBufImag[bin] + hReverb->loopBufLength[bin], hReverb->loopAttenuationFactor[bin], hReverb->loopBufImag[bin], numSlots );
1625 : }
1626 :
1627 : /* 2) Apply the determined pre-delay to the input audio, and add the delayed audio to the loop. */
1628 5898338 : idx = hReverb->preDelayBufferIndex;
1629 29423736 : for ( sample = 0; sample < numSlots; sample++ )
1630 : {
1631 23525398 : invertSampleIndex = numSlots - sample - 1;
1632 :
1633 1045947578 : for ( bin = 0; bin < hReverb->numBins; bin++ )
1634 : {
1635 : /* Add from pre-delay buffer a sample to the loop buffer, in a time-inverted order.
1636 : * Also apply the spectral gains determined for the reverberation */
1637 1022422180 : hReverb->loopBufReal[bin][invertSampleIndex] += hReverb->preDelayBufferReal[idx][bin] * hReverb->reverbEqGains[bin];
1638 1022422180 : hReverb->loopBufImag[bin][invertSampleIndex] += hReverb->preDelayBufferImag[idx][bin] * hReverb->reverbEqGains[bin];
1639 1022422180 : hReverb->preDelayBufferReal[idx][bin] = 0.0f;
1640 1022422180 : hReverb->preDelayBufferImag[idx][bin] = 0.0f;
1641 : }
1642 :
1643 : /* Add every second input channel as is to the pre-delay buffer, and every second input channel with
1644 : * 90 degrees phase shift to reduce energy imbalances between coherent and incoherent sounds */
1645 73762942 : for ( ch = 0; ch < numInChannels; ch++ )
1646 : {
1647 50237544 : if ( ch % 2 )
1648 : {
1649 24472726 : v_add( hReverb->preDelayBufferReal[idx], inReal[ch][sample], hReverb->preDelayBufferReal[idx], hReverb->numBins );
1650 24472726 : v_add( hReverb->preDelayBufferImag[idx], inImag[ch][sample], hReverb->preDelayBufferImag[idx], hReverb->numBins );
1651 : }
1652 : else
1653 : {
1654 25764818 : v_sub( hReverb->preDelayBufferReal[idx], inImag[ch][sample], hReverb->preDelayBufferReal[idx], hReverb->numBins );
1655 25764818 : v_add( hReverb->preDelayBufferImag[idx], inReal[ch][sample], hReverb->preDelayBufferImag[idx], hReverb->numBins );
1656 : }
1657 : }
1658 23525398 : idx = ( idx + 1 ) % hReverb->preDelayBufferLength;
1659 : }
1660 5898338 : hReverb->preDelayBufferIndex = idx;
1661 :
1662 : /* 3) Perform the filtering/decorrelating, using complex and sparse FIR filtering */
1663 262348658 : for ( bin = 0; bin < hReverb->numBins; bin++ )
1664 : {
1665 769350960 : for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
1666 : {
1667 : /* These tap pointers have been determined to point to the loop buffer at sparse locations */
1668 512900640 : tapRealPr = hReverb->tapPointersReal[bin][ch];
1669 512900640 : tapImagPr = hReverb->tapPointersImag[bin][ch];
1670 :
1671 512900640 : phaseShiftTypePr = hReverb->tapPhaseShiftType[bin][ch];
1672 :
1673 : /* Flush output */
1674 512900640 : set_f( hReverb->outputBufferReal[bin][ch], 0.0f, numSlots );
1675 512900640 : set_f( hReverb->outputBufferImag[bin][ch], 0.0f, numSlots );
1676 :
1677 : /* Add from temporally decaying sparse tap locations the audio to the output. */
1678 12598750713 : for ( tapIdx = 0; tapIdx < hReverb->taps[bin][ch]; tapIdx++ )
1679 : {
1680 12085850073 : switch ( phaseShiftTypePr[tapIdx] )
1681 : {
1682 2966834646 : case 0: /* 0 degrees phase */
1683 2966834646 : v_add( hReverb->outputBufferReal[bin][ch], tapRealPr[tapIdx], hReverb->outputBufferReal[bin][ch], numSlots );
1684 2966834646 : v_add( hReverb->outputBufferImag[bin][ch], tapImagPr[tapIdx], hReverb->outputBufferImag[bin][ch], numSlots );
1685 2966834646 : break;
1686 3170059513 : case 1: /* 90 degrees phase */
1687 3170059513 : v_sub( hReverb->outputBufferReal[bin][ch], tapImagPr[tapIdx], hReverb->outputBufferReal[bin][ch], numSlots );
1688 3170059513 : v_add( hReverb->outputBufferImag[bin][ch], tapRealPr[tapIdx], hReverb->outputBufferImag[bin][ch], numSlots );
1689 3170059513 : break;
1690 3027722915 : case 2: /* 180 degrees phase */
1691 3027722915 : v_sub( hReverb->outputBufferReal[bin][ch], tapRealPr[tapIdx], hReverb->outputBufferReal[bin][ch], numSlots );
1692 3027722915 : v_sub( hReverb->outputBufferImag[bin][ch], tapImagPr[tapIdx], hReverb->outputBufferImag[bin][ch], numSlots );
1693 3027722915 : break;
1694 2921232999 : default: /* 270 degrees phase */
1695 2921232999 : v_add( hReverb->outputBufferReal[bin][ch], tapImagPr[tapIdx], hReverb->outputBufferReal[bin][ch], numSlots );
1696 2921232999 : v_sub( hReverb->outputBufferImag[bin][ch], tapRealPr[tapIdx], hReverb->outputBufferImag[bin][ch], numSlots );
1697 2921232999 : break;
1698 : }
1699 : }
1700 : }
1701 :
1702 : /* Generate diffuse field binaural coherence by mixing the incoherent reverberated channels with pre-defined gains */
1703 256450320 : if ( bin <= hReverb->highestBinauralCoherenceBin )
1704 : {
1705 40378708 : if ( hReverb->useBinauralCoherence )
1706 : {
1707 201421064 : for ( sample = 0; sample < numSlots; sample++ )
1708 : {
1709 : float leftRe, rightRe, leftIm, rightIm;
1710 :
1711 161042356 : leftRe = hReverb->binauralCoherenceDirectGains[bin] * hReverb->outputBufferReal[bin][0][sample] + hReverb->binauralCoherenceCrossmixGains[bin] * hReverb->outputBufferReal[bin][1][sample];
1712 161042356 : rightRe = hReverb->binauralCoherenceDirectGains[bin] * hReverb->outputBufferReal[bin][1][sample] + hReverb->binauralCoherenceCrossmixGains[bin] * hReverb->outputBufferReal[bin][0][sample];
1713 161042356 : leftIm = hReverb->binauralCoherenceDirectGains[bin] * hReverb->outputBufferImag[bin][0][sample] + hReverb->binauralCoherenceCrossmixGains[bin] * hReverb->outputBufferImag[bin][1][sample];
1714 161042356 : rightIm = hReverb->binauralCoherenceDirectGains[bin] * hReverb->outputBufferImag[bin][1][sample] + hReverb->binauralCoherenceCrossmixGains[bin] * hReverb->outputBufferImag[bin][0][sample];
1715 :
1716 161042356 : hReverb->outputBufferReal[bin][0][sample] = leftRe;
1717 161042356 : hReverb->outputBufferReal[bin][1][sample] = rightRe;
1718 161042356 : hReverb->outputBufferImag[bin][0][sample] = leftIm;
1719 161042356 : hReverb->outputBufferImag[bin][1][sample] = rightIm;
1720 : }
1721 : }
1722 : }
1723 : }
1724 :
1725 : /* 4) Write data to output */
1726 17695014 : for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
1727 : {
1728 58847472 : for ( sample = 0; sample < numSlots; sample++ )
1729 : {
1730 : /* Audio was in the temporally inverted order for convolution, re-invert audio to output */
1731 47050796 : invertSampleIndex = numSlots - sample - 1;
1732 :
1733 2091895156 : for ( bin = 0; bin < hReverb->numBins; bin++ )
1734 : {
1735 2044844360 : outReal[ch][sample][bin] = hReverb->outputBufferReal[bin][ch][invertSampleIndex];
1736 2044844360 : outImag[ch][sample][bin] = hReverb->outputBufferImag[bin][ch][invertSampleIndex];
1737 : }
1738 825254196 : for ( ; bin < CLDFB_NO_CHANNELS_MAX; bin++ )
1739 : {
1740 778203400 : outReal[ch][sample][bin] = 0.0f;
1741 778203400 : outImag[ch][sample][bin] = 0.0f;
1742 : }
1743 : }
1744 : }
1745 :
1746 5898338 : pop_wmops();
1747 5898338 : return;
1748 : }
1749 :
1750 :
1751 : /*-------------------------------------------------------------------------
1752 : * ivas_binaural_reverb_open()
1753 : *
1754 : * Allocate and initialize binaural room reverberator handle
1755 : *------------------------------------------------------------------------*/
1756 :
1757 19636 : static ivas_error ivas_binaural_reverb_open(
1758 : REVERB_STRUCT_HANDLE *hReverbPr, /* i/o: binaural reverb handle */
1759 : const int16_t numBins, /* i : number of CLDFB bins */
1760 : const int16_t numCldfbSlotsPerFrame, /* i : number of CLDFB slots per frame */
1761 : const int32_t sampling_rate, /* i : sampling rate */
1762 : const float *revTimes, /* i : reverberation times T60 for each CLDFB bin in seconds */
1763 : const float *revEnes, /* i : spectrum for reverberated sound at each CLDFB bin */
1764 : const int16_t preDelay /* i : reverb pre-delay in CLDFB slots */
1765 : )
1766 : {
1767 : int16_t bin, chIdx, k, len;
1768 : REVERB_STRUCT_HANDLE hReverb;
1769 :
1770 19636 : if ( ( *hReverbPr = (REVERB_STRUCT_HANDLE) malloc( sizeof( REVERB_STRUCT ) ) ) == NULL )
1771 : {
1772 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1773 : }
1774 :
1775 19636 : hReverb = *hReverbPr;
1776 :
1777 19636 : hReverb->useBinauralCoherence = 1;
1778 19636 : hReverb->preDelayBufferLength = 1;
1779 19636 : hReverb->preDelayBufferIndex = 0;
1780 :
1781 19636 : hReverb->numBins = numBins;
1782 19636 : hReverb->blockSize = numCldfbSlotsPerFrame;
1783 :
1784 431992 : for ( k = 0; k < IVAS_REVERB_PREDELAY_MAX + 1; k++ )
1785 : {
1786 412356 : set_f( hReverb->preDelayBufferReal[k], 0.0f, hReverb->numBins );
1787 412356 : set_f( hReverb->preDelayBufferImag[k], 0.0f, hReverb->numBins );
1788 : }
1789 :
1790 798966 : for ( bin = 0; bin < hReverb->numBins; bin++ )
1791 : {
1792 : /* Loop Buffer */
1793 779330 : hReverb->loopBufLengthMax[bin] = (int16_t) ( 500 / ( 1 + bin ) + ( CLDFB_NO_CHANNELS_MAX - bin ) );
1794 :
1795 779330 : len = hReverb->loopBufLengthMax[bin] + hReverb->blockSize;
1796 779330 : if ( ( hReverb->loopBufReal[bin] = (float *) malloc( len * sizeof( float ) ) ) == NULL )
1797 : {
1798 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1799 : }
1800 :
1801 779330 : if ( ( hReverb->loopBufImag[bin] = (float *) malloc( len * sizeof( float ) ) ) == NULL )
1802 : {
1803 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1804 : }
1805 :
1806 779330 : set_f( hReverb->loopBufReal[bin], 0.0f, len );
1807 779330 : set_f( hReverb->loopBufImag[bin], 0.0f, len );
1808 :
1809 : /* Determine loop buffer length. The following formula is manually tuned to generate sufficiently long
1810 : * but not excessively long loops to generate reverberation. */
1811 : /* Note: the resulted length is very sensitive to the precision of the constants below (e.g. 1.45 vs. 1.45f) */
1812 779330 : hReverb->loopBufLength[bin] = (int16_t) ( 1.45 * (int16_t) ( revTimes[bin] * 150.0 ) + 1 );
1813 779330 : hReverb->loopBufLength[bin] = min( hReverb->loopBufLength[bin], hReverb->loopBufLengthMax[bin] );
1814 :
1815 : /* Sparse Filter Tap Locations */
1816 2337990 : for ( chIdx = 0; chIdx < BINAURAL_CHANNELS; chIdx++ )
1817 : {
1818 1558660 : len = hReverb->loopBufLength[bin];
1819 :
1820 1558660 : if ( ( hReverb->tapPhaseShiftType[bin][chIdx] = (int16_t *) malloc( len * sizeof( int16_t ) ) ) == NULL )
1821 : {
1822 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1823 : }
1824 1558660 : set_s( hReverb->tapPhaseShiftType[bin][chIdx], 0, len );
1825 :
1826 1558660 : if ( ( hReverb->tapPointersReal[bin][chIdx] = (float **) malloc( len * sizeof( float * ) ) ) == NULL )
1827 : {
1828 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1829 : }
1830 :
1831 1558660 : if ( ( hReverb->tapPointersImag[bin][chIdx] = (float **) malloc( len * sizeof( float * ) ) ) == NULL )
1832 : {
1833 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1834 : }
1835 :
1836 1558660 : len = hReverb->blockSize;
1837 1558660 : if ( ( hReverb->outputBufferReal[bin][chIdx] = (float *) malloc( len * sizeof( float ) ) ) == NULL )
1838 : {
1839 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1840 : }
1841 :
1842 1558660 : if ( ( hReverb->outputBufferImag[bin][chIdx] = (float *) malloc( len * sizeof( float ) ) ) == NULL )
1843 : {
1844 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1845 : }
1846 :
1847 1558660 : set_f( hReverb->outputBufferReal[bin][chIdx], 0.0f, len );
1848 1558660 : set_f( hReverb->outputBufferImag[bin][chIdx], 0.0f, len );
1849 : }
1850 : }
1851 :
1852 19636 : ivas_binaural_reverb_setReverbTimes( hReverb, sampling_rate, revTimes, revEnes );
1853 :
1854 19636 : ivas_binaural_reverb_setPreDelay( hReverb, preDelay );
1855 :
1856 19636 : return IVAS_ERR_OK;
1857 : }
1858 :
1859 :
1860 : /*-------------------------------------------------------------------------
1861 : * ivas_binaural_reverb_init()
1862 : *
1863 : * Initialize binaural room reverberator handle for FastConv renderer
1864 : *------------------------------------------------------------------------*/
1865 :
1866 19636 : ivas_error ivas_binaural_reverb_init(
1867 : REVERB_STRUCT_HANDLE *hReverbPr, /* i/o: binaural reverb handle */
1868 : const HRTFS_STATISTICS_HANDLE hHrtfStatistics, /* i : HRTF statistics handle */
1869 : const int16_t numBins, /* i : number of CLDFB bins */
1870 : const int16_t numCldfbSlotsPerFrame, /* i : number of CLDFB slots per frame */
1871 : const IVAS_ROOM_ACOUSTICS_CONFIG_DATA *roomAcoustics, /* i/o: room acoustics parameters */
1872 : const int32_t sampling_rate, /* i : sampling rate */
1873 : const float *defaultTimes, /* i : default reverberation times */
1874 : const float *defaultEne, /* i : default reverberation energies */
1875 : float *earlyEne /* i/o: Early part energies to be modified */
1876 : )
1877 : {
1878 : ivas_error error;
1879 : int16_t preDelay, bin;
1880 : float revTimes[CLDFB_NO_CHANNELS_MAX];
1881 : float revEne[CLDFB_NO_CHANNELS_MAX];
1882 :
1883 19636 : if ( roomAcoustics != NULL )
1884 : {
1885 9647 : if ( ( error = ivas_reverb_prepare_cldfb_params( roomAcoustics, hHrtfStatistics, sampling_rate, revTimes, revEne ) ) != IVAS_ERR_OK )
1886 : {
1887 0 : return error;
1888 : }
1889 :
1890 : /* Convert preDelay from seconds to CLDFB slots as needed by binaural reverb */
1891 9647 : preDelay = (int16_t) roundf( roomAcoustics->acousticPreDelay * CLDFB_SLOTS_PER_SECOND );
1892 : }
1893 : else
1894 : {
1895 : #ifdef FIX_1995_REVERB_INIT
1896 424949 : for ( bin = 0; bin < numBins; bin++ )
1897 : #else
1898 : for ( bin = 0; bin < CLDFB_NO_CHANNELS_MAX; bin++ )
1899 : #endif
1900 : {
1901 414960 : revTimes[bin] = defaultTimes[bin];
1902 414960 : revEne[bin] = defaultEne[bin];
1903 : }
1904 9989 : preDelay = 10;
1905 : }
1906 :
1907 : #ifdef FIX_1995_REVERB_INIT
1908 798966 : for ( bin = 0; bin < numBins; bin++ )
1909 : #else
1910 : for ( bin = 0; bin < CLDFB_NO_CHANNELS_MAX; bin++ )
1911 : #endif
1912 : {
1913 : /* Adjust the room effect parameters when the reverberation time is less than a threshold value, to avoid
1914 : spectral artefacts with the synthetic reverberator. */
1915 779330 : if ( revTimes[bin] < REV_TIME_THRESHOLD )
1916 : {
1917 : float adjustedEarlyEne, adjustedLateEne, adjustedRevTime;
1918 : float revTimeModifier, energyModifier;
1919 :
1920 : /* Adjust reverberation times, higher towards a threshold */
1921 147108 : revTimeModifier = fmaxf( 0.0f, 1.0f - ( revTimes[bin] / REV_TIME_THRESHOLD ) );
1922 147108 : adjustedRevTime = ( 1.0f - revTimeModifier ) * revTimes[bin];
1923 147108 : adjustedRevTime += revTimeModifier * ( revTimes[bin] + REV_TIME_THRESHOLD ) * 0.5f;
1924 147108 : energyModifier = ( adjustedRevTime - revTimes[bin] ) / adjustedRevTime;
1925 :
1926 : /* Adjust early and late energies, by moving late energy to early energy */
1927 147108 : if ( earlyEne != NULL )
1928 : {
1929 124723 : adjustedEarlyEne = earlyEne[bin] + revEne[bin] * energyModifier;
1930 124723 : earlyEne[bin] = adjustedEarlyEne; /* Store already here */
1931 : }
1932 :
1933 147108 : adjustedLateEne = revEne[bin] * ( 1.0f - energyModifier );
1934 :
1935 : /* Store adjusted room effect parameters to be used in reverb processing */
1936 147108 : revTimes[bin] = adjustedRevTime;
1937 147108 : revEne[bin] = adjustedLateEne;
1938 : }
1939 : }
1940 :
1941 19636 : error = ivas_binaural_reverb_open( hReverbPr, numBins, numCldfbSlotsPerFrame, sampling_rate, revTimes, revEne, preDelay );
1942 :
1943 19636 : return error;
1944 : }
1945 :
1946 :
1947 : /*-------------------------------------------------------------------------
1948 : * ivas_binaural_reverb_close()
1949 : *
1950 : * Close binaural room reverberator handle
1951 : *------------------------------------------------------------------------*/
1952 :
1953 19636 : void ivas_binaural_reverb_close(
1954 : REVERB_STRUCT_HANDLE *hReverb /* i/o: binaural reverb handle */
1955 : )
1956 : {
1957 : int16_t bin, chIdx;
1958 :
1959 19636 : if ( hReverb == NULL || *hReverb == NULL )
1960 : {
1961 0 : return;
1962 : }
1963 :
1964 798966 : for ( bin = 0; bin < ( *hReverb )->numBins; bin++ )
1965 : {
1966 2337990 : for ( chIdx = 0; chIdx < BINAURAL_CHANNELS; chIdx++ )
1967 : {
1968 1558660 : free( ( *hReverb )->tapPhaseShiftType[bin][chIdx] );
1969 1558660 : free( ( *hReverb )->tapPointersReal[bin][chIdx] );
1970 1558660 : free( ( *hReverb )->tapPointersImag[bin][chIdx] );
1971 1558660 : free( ( *hReverb )->outputBufferReal[bin][chIdx] );
1972 1558660 : free( ( *hReverb )->outputBufferImag[bin][chIdx] );
1973 : }
1974 779330 : free( ( *hReverb )->loopBufReal[bin] );
1975 779330 : free( ( *hReverb )->loopBufImag[bin] );
1976 : }
1977 :
1978 19636 : free( ( *hReverb ) );
1979 19636 : ( *hReverb ) = NULL;
1980 :
1981 19636 : return;
1982 : }
|