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 176227065 : static uint16_t binRend_rand(
134 : REVERB_STRUCT_HANDLE hReverb /* i/o: binaural reverb handle */
135 : )
136 : {
137 176227065 : hReverb->binRend_RandNext = hReverb->binRend_RandNext * 1103515245 + 12345;
138 :
139 176227065 : return (uint16_t) ( hReverb->binRend_RandNext / 65536 ) % 32768;
140 : }
141 :
142 :
143 : /*-------------------------------------------------------------------------
144 : * ivas_binaural_reverb_setPreDelay()
145 : *
146 : *
147 : *------------------------------------------------------------------------*/
148 :
149 32899 : 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 32899 : if ( delaySamples < 1 )
155 : {
156 0 : hReverb->preDelayBufferLength = 1;
157 :
158 0 : return;
159 : }
160 :
161 32899 : if ( delaySamples > IVAS_REVERB_PREDELAY_MAX )
162 : {
163 25 : hReverb->preDelayBufferLength = IVAS_REVERB_PREDELAY_MAX;
164 :
165 25 : return;
166 : }
167 :
168 32874 : hReverb->preDelayBufferLength = delaySamples;
169 :
170 32874 : return;
171 : }
172 :
173 :
174 : /*-------------------------------------------------------------------------
175 : * ivas_binaural_reverb_setReverbTimes()
176 : *
177 : *
178 : *------------------------------------------------------------------------*/
179 :
180 32899 : 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 32899 : hReverb->binRend_RandNext = (uint16_t) BIN_REND_RANDOM_SEED;
192 32899 : hReverb->highestBinauralCoherenceBin = 0;
193 1362609 : for ( bin = 0; bin < hReverb->numBins; bin++ )
194 : {
195 : /* Determine the diffuse field binaural coherence */
196 1329710 : binCenterFreq = ( (float) bin + 0.5f ) / ( (float) hReverb->numBins ) * ( (float) output_Fs ) / 2.0f;
197 1329710 : if ( bin == 0 )
198 : {
199 32899 : diffuseFieldICC = 1.0f;
200 : }
201 1296811 : else if ( binCenterFreq < 2700.0f )
202 : {
203 193595 : diffuseFieldICC = sinf( EVS_PI * binCenterFreq / 550.0f + 1e-20f ) / ( EVS_PI * binCenterFreq / 550.0f + 1e-20f ) * ( 1.0f - binCenterFreq / 2700.0f );
204 193595 : hReverb->highestBinauralCoherenceBin = bin;
205 : }
206 : else
207 : {
208 1103216 : diffuseFieldICC = 0.0f;
209 : }
210 :
211 : /* Mixing gains to generate a diffuse-binaural sound based on incoherent sound */
212 1329710 : tmpVal = ( 1.0f - sqrtf( 1.0f - powf( diffuseFieldICC, 2.0 ) ) ) / 2.0f;
213 1329710 : if ( diffuseFieldICC > 0 )
214 : {
215 127797 : hReverb->binauralCoherenceCrossmixGains[bin] = sqrtf( fabsf( tmpVal ) );
216 : }
217 : else
218 : {
219 1201913 : hReverb->binauralCoherenceCrossmixGains[bin] = -sqrtf( fabsf( tmpVal ) );
220 : }
221 1329710 : hReverb->binauralCoherenceDirectGains[bin] = sqrtf( 1.0f - fabsf( tmpVal ) );
222 :
223 : /* Determine attenuation factor that generates the appropriate energy decay according to reverberation time */
224 1329710 : attenuationFactorPerSample = powf( 10.0f, -3.0f * ( 1.0f / ( (float) CLDFB_SLOTS_PER_SECOND * revTimes[bin] ) ) );
225 1329710 : hReverb->loopAttenuationFactor[bin] = powf( attenuationFactorPerSample, hReverb->loopBufLength[bin] );
226 1329710 : 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 1329710 : intendedEnergy = 0.0f;
231 1329710 : actualizedEnergy = 0.0f;
232 :
233 3989130 : for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
234 : {
235 2659420 : energyBuildup = 0.0f;
236 2659420 : currentEnergy = 1.0f;
237 2659420 : tap = 0;
238 :
239 138893508 : for ( sample = 0; sample < hReverb->loopBufLength[bin]; sample++ )
240 : {
241 136234088 : intendedEnergy += currentEnergy;
242 :
243 : /* The randomization at the energy build up affects where the sparse taps are located */
244 136234088 : energyBuildup += currentEnergy + 0.1f * ( (float) binRend_rand( hReverb ) / PCM16_TO_FLT_FAC - 0.5f );
245 :
246 136234088 : 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 39992977 : 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 39992977 : hReverb->tapPointersReal[bin][ch][tap] = &( hReverb->loopBufReal[bin][sample] );
252 39992977 : hReverb->tapPointersImag[bin][ch][tap] = &( hReverb->loopBufImag[bin][sample] );
253 39992977 : energyBuildup -= 1.0f; /* A tap is added, thus remove its energy from the buildup */
254 39992977 : tap++;
255 39992977 : actualizedEnergy += 1.0f;
256 : }
257 136234088 : 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 2659420 : 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 2659420 : 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 1329710 : hReverb->reverbEqGains[bin] = sqrtf( revEnes[bin] ); /* Determined reverb spectrum */
275 1329710 : hReverb->reverbEqGains[bin] *= sqrtf( intendedEnergy / actualizedEnergy ); /* Correction of random effects at the decorrelator design */
276 1329710 : hReverb->reverbEqGains[bin] *= sqrtf( 0.5f * ( 1.0f - attenuationFactorPerSampleSq ) ); /* Correction of IIR decay rate */
277 : }
278 :
279 32899 : 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 52608 : 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 52608 : 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 52608 : 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 52608 : u = inv_sqrt( n );
324 :
325 52608 : if ( n == 4 )
326 : {
327 0 : u = -u;
328 : }
329 :
330 52608 : pFeedbackMatrix[0] = u;
331 210432 : for ( x = 1; x < n; x += x )
332 : {
333 526080 : for ( i = 0; i < x; i++ )
334 : {
335 1473024 : for ( j = 0; j < x; j++ )
336 : {
337 1104768 : pFeedbackMatrix[( i + x ) * n + j] = pFeedbackMatrix[i * n + j];
338 1104768 : pFeedbackMatrix[i * n + j + x] = pFeedbackMatrix[i * n + j];
339 1104768 : pFeedbackMatrix[( i + x ) * n + j + x] = -pFeedbackMatrix[i * n + j];
340 : }
341 : }
342 : }
343 :
344 52608 : 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 52608 : 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 52608 : 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 52608 : ff = 1.0;
372 473472 : for ( i = 0; i < n; i++ )
373 : {
374 420864 : pExtractMatrix[i] = 1.0;
375 420864 : pExtractMatrix[i + n] = ff;
376 420864 : ff = -ff;
377 : }
378 :
379 52608 : 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 52608 : 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 52608 : const int16_t *selected_loop_delay = NULL;
396 :
397 52608 : if ( pParams == NULL )
398 : {
399 0 : return IVAS_ERR_INTERNAL;
400 : }
401 :
402 52608 : pParams->pre_delay = 0;
403 52608 : pParams->nr_outputs = BINAURAL_CHANNELS;
404 52608 : pParams->nr_loops = IVAS_REV_MAX_NR_BRANCHES;
405 :
406 : /* set loop delays to default */
407 52608 : if ( output_Fs == 48000 )
408 : {
409 17215 : selected_loop_delay = default_loop_delay_48k;
410 : }
411 35393 : else if ( output_Fs == 32000 )
412 : {
413 17534 : selected_loop_delay = default_loop_delay_32k;
414 : }
415 17859 : else if ( output_Fs == 16000 )
416 : {
417 17859 : selected_loop_delay = default_loop_delay_16k;
418 : }
419 :
420 473472 : for ( loop_idx = 0; loop_idx < pParams->nr_loops; loop_idx++ )
421 : {
422 420864 : pParams->pLoop_delays[loop_idx] = selected_loop_delay[loop_idx];
423 : }
424 :
425 : /* set feedback and output matrices */
426 52608 : if ( ( error = compute_feedback_matrix( pParams->pLoop_feedback_matrix, pParams->nr_loops ) ) != IVAS_ERR_OK )
427 : {
428 0 : return error;
429 : }
430 :
431 52608 : 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 52608 : pParams->t60_filter_order = 1; /* set to 1 in base config. */
435 :
436 52608 : if ( pParams->nr_outputs == 2 )
437 : {
438 52608 : pParams->do_corr_filter = 1;
439 : }
440 : else
441 : {
442 0 : pParams->do_corr_filter = 0;
443 : }
444 :
445 52608 : return IVAS_ERR_OK;
446 : }
447 :
448 :
449 : /*-----------------------------------------------------------------------------------------*
450 : * Function calc_dmx_gain()
451 : *
452 : * Computes the downmix gain
453 : *-----------------------------------------------------------------------------------------*/
454 :
455 12692 : static float calc_dmx_gain( void )
456 : {
457 12692 : const float dist = DEFAULT_SRC_DIST;
458 12692 : 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 52608 : 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 52608 : predelay = (int16_t) roundf( acoustic_predelay_sec * (float) output_Fs );
476 52608 : output_frame = (int16_t) ( output_Fs / FRAMES_PER_SEC );
477 52608 : fbdelay = pParams->pLoop_delays[pParams->nr_loops - 1];
478 52608 : predelay -= fbdelay;
479 :
480 52608 : if ( predelay < 0 )
481 : {
482 5432 : predelay = 0;
483 : }
484 :
485 52608 : if ( output_frame < predelay )
486 : {
487 0 : predelay = output_frame;
488 : }
489 :
490 52608 : pParams->pre_delay = predelay;
491 :
492 52608 : return;
493 : }
494 :
495 :
496 : /*-----------------------------------------------------------------------------------------*
497 : * Function compute_t60_coeffs()
498 : *
499 : * Calculate Jot reverb's T60 filter coefficients
500 : *-----------------------------------------------------------------------------------------*/
501 :
502 52608 : 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 52608 : targetT60 = pParams->pRt60;
516 52608 : freqT60 = pParams->pFc;
517 :
518 52608 : error = IVAS_ERR_OK;
519 52608 : tf_T60_len = nr_fc_fft_filter;
520 52608 : len = pParams->t60_filter_order + 1;
521 52608 : freq_Nyquist = 0.5f * (float) output_Fs;
522 :
523 : /* normalize pFrequencies: 0 .. 1/2 output_Fs --> 0.0 .. 1.0 */
524 52608 : inv_hfs = 1.0f / freq_Nyquist;
525 11286912 : for ( bin_idx = 0; bin_idx < tf_T60_len; bin_idx++ )
526 : {
527 11234304 : norm_f[bin_idx] = freqT60[bin_idx] * inv_hfs;
528 : }
529 :
530 473472 : for ( loop_idx = 0; loop_idx < pParams->nr_loops; loop_idx++ )
531 : {
532 420864 : loop_delay_sec = (float) pParams->pLoop_delays[loop_idx] / (float) output_Fs;
533 90295296 : for ( bin_idx = 0; bin_idx < tf_T60_len; bin_idx++ )
534 : {
535 89874432 : target_gains_db[bin_idx] = -60.0f * loop_delay_sec / targetT60[bin_idx];
536 89874432 : target_gains_db[bin_idx] = max( target_gains_db[bin_idx], -120.0f );
537 : }
538 :
539 420864 : pCoeffs_a = &pParams->pT60_filter_coeff[2 * len * loop_idx + len];
540 420864 : pCoeffs_b = &pParams->pT60_filter_coeff[2 * len * loop_idx];
541 420864 : 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 52608 : len = ( pParams->t60_filter_order + 1 ) >> 1; /* == floor( (order+1) / 2) */
548 473472 : for ( loop_idx = 0; loop_idx < pParams->nr_loops; loop_idx++ )
549 : {
550 420864 : pParams->pLoop_delays[loop_idx] -= len;
551 : }
552 :
553 52608 : 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 420864 : 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 420864 : w0 = tanf( EVS_PI * f0 / 2.0f );
573 420864 : gain = lin_gain_lf / lin_gain_hf;
574 :
575 420864 : 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 420864 : pNum[0] = 1 + w0;
585 420864 : pNum[1] = w0 - 1;
586 420864 : pDen[0] = 1 + w0 / gain;
587 420864 : pDen[1] = w0 / gain - 1;
588 : }
589 :
590 : /* Normalize and adjust gain to match target amplitudes */
591 420864 : pNum[0] = ( pNum[0] / pDen[0] ) * lin_gain_hf;
592 420864 : pNum[1] = ( pNum[1] / pDen[0] ) * lin_gain_hf;
593 420864 : pDen[1] = pDen[1] / pDen[0];
594 420864 : pDen[0] = 1.0f;
595 :
596 420864 : return;
597 : }
598 :
599 :
600 : /*-----------------------------------------------------------------------------------------*
601 : * Function calc_jot_t60_coeffs()
602 : *
603 : * Calculate Jot reverb's T60 filters
604 : *-----------------------------------------------------------------------------------------*/
605 :
606 420864 : 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 420864 : const float ref_lf_min_norm = REF_LF_MIN / fNyquist;
615 420864 : const float ref_lf_max_norm = REF_LF_MAX / fNyquist;
616 420864 : const float ref_hf_min_norm = REF_HF_MIN / fNyquist;
617 420864 : 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 420864 : minidx = nrFrequencies - 1;
624 420864 : minval = 1e+20f;
625 420864 : lf_target_gain_dB = 0.0f;
626 420864 : hf_target_gain_dB = 0.0f;
627 420864 : n_points_lf = 0;
628 420864 : n_points_hf = 0;
629 :
630 90295296 : for ( f_idx = 0; f_idx < nrFrequencies; f_idx++ )
631 : {
632 89874432 : if ( ( pFrequencies[f_idx] >= ref_lf_min_norm ) && ( pFrequencies[f_idx] <= ref_lf_max_norm ) )
633 : {
634 987152 : lf_target_gain_dB += pH_dB[f_idx];
635 987152 : n_points_lf++;
636 : }
637 89874432 : if ( ( pFrequencies[f_idx] >= ref_hf_min_norm ) && ( pFrequencies[f_idx] <= ref_hf_max_norm ) )
638 : {
639 17860232 : hf_target_gain_dB += pH_dB[f_idx];
640 17860232 : n_points_hf++;
641 : }
642 : }
643 :
644 420864 : if ( ( n_points_lf == 0 ) || ( n_points_hf == 0 ) )
645 : {
646 0 : return IVAS_ERR_INTERNAL;
647 : }
648 :
649 420864 : lf_target_gain_dB = lf_target_gain_dB / (float) n_points_lf;
650 420864 : hf_target_gain_dB = hf_target_gain_dB / (float) n_points_hf;
651 420864 : mid_crossing_gain_dB = hf_target_gain_dB + LF_BIAS * ( lf_target_gain_dB - hf_target_gain_dB );
652 :
653 89453568 : for ( f_idx = 1; f_idx < nrFrequencies - 1; f_idx++ )
654 : {
655 89032704 : tmp = fabsf( pH_dB[f_idx] - mid_crossing_gain_dB );
656 89032704 : if ( tmp < minval )
657 : {
658 5724352 : minval = tmp;
659 5724352 : minidx = f_idx;
660 : }
661 : }
662 :
663 420864 : f0 = pFrequencies[minidx];
664 420864 : lin_gain_lf = powf( 10.0f, lf_target_gain_dB * 0.05f );
665 420864 : lin_gain_hf = powf( 10.0f, hf_target_gain_dB * 0.05f );
666 :
667 : /* call low-pass iir shelf */
668 420864 : calc_low_shelf_first_order_filter( pCoeffB, pCoeffA, f0, lin_gain_lf, lin_gain_hf );
669 :
670 420864 : 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 12692 : static ivas_error initialize_reverb_filters(
681 : REVERB_HANDLE hReverb )
682 : {
683 : ivas_error error;
684 :
685 : /* init correlation and coloration filters */
686 12692 : 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 12692 : 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 12692 : 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 12692 : 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 12692 : 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 12692 : 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 420864 : 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 420864 : if ( branch >= hReverb->nr_of_branches )
729 : {
730 0 : return IVAS_ERR_INTERNAL;
731 : }
732 :
733 420864 : if ( nr_taps > IVAS_REV_MAX_IIR_FILTER_LENGTH )
734 : {
735 0 : return IVAS_ERR_INTERNAL;
736 : }
737 :
738 420864 : ivas_reverb_iir_filt_set( &( hReverb->t60[branch] ), nr_taps, coefA, coefB );
739 :
740 420864 : 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 101536 : static ivas_error set_feedback_delay(
751 : REVERB_HANDLE hReverb,
752 : const uint16_t branch,
753 : const int16_t fb_delay )
754 : {
755 101536 : if ( branch >= hReverb->nr_of_branches )
756 : {
757 0 : return IVAS_ERR_INTERNAL;
758 : }
759 :
760 101536 : hReverb->delay_line[branch].Delay = fb_delay;
761 :
762 101536 : 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 101536 : 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 101536 : if ( branch >= hReverb->nr_of_branches )
779 : {
780 0 : return IVAS_ERR_INTERNAL;
781 : }
782 :
783 913824 : for ( gain_idx = 0; gain_idx < hReverb->nr_of_branches; gain_idx++ )
784 : {
785 812288 : hReverb->gain_matrix[branch][gain_idx] = pGain[gain_idx];
786 : }
787 :
788 101536 : return IVAS_ERR_OK;
789 : }
790 :
791 :
792 : /*-----------------------------------------------------------------------------------------*
793 : * Function set_correl_fft_filter()
794 : *
795 : * Sets correlation filter complex gains
796 : *-----------------------------------------------------------------------------------------*/
797 :
798 105216 : static ivas_error set_correl_fft_filter(
799 : REVERB_HANDLE hReverb,
800 : const uint16_t channel,
801 : rv_fftwf_type_complex *pSpectrum )
802 : {
803 105216 : if ( channel > 1 )
804 : {
805 0 : return IVAS_ERR_INTERNAL;
806 : }
807 :
808 105216 : if ( channel == 0 )
809 : {
810 52608 : 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 52608 : 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 105216 : return IVAS_ERR_OK;
818 : }
819 :
820 :
821 : /*-----------------------------------------------------------------------------------------*
822 : * Function set_color_fft_filter()
823 : *
824 : * Sets coloration filter complex gains
825 : *-----------------------------------------------------------------------------------------*/
826 :
827 105216 : static ivas_error set_color_fft_filter(
828 : REVERB_HANDLE hReverb,
829 : const uint16_t channel,
830 : rv_fftwf_type_complex *pSpectrum )
831 : {
832 105216 : if ( channel > 1 )
833 : {
834 0 : return IVAS_ERR_INTERNAL;
835 : }
836 :
837 105216 : if ( channel == 0 )
838 : {
839 52608 : 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 52608 : 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 105216 : 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 25384 : 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 25384 : if ( channel >= BINAURAL_CHANNELS )
863 : {
864 0 : return IVAS_ERR_INTERNAL;
865 : }
866 :
867 228456 : for ( branch_idx = 0; branch_idx < hReverb->nr_of_branches; branch_idx++ )
868 : {
869 203072 : hReverb->mixer[channel][branch_idx] = level[branch_idx];
870 : }
871 :
872 25384 : return IVAS_ERR_OK;
873 : }
874 :
875 :
876 : /*-----------------------------------------------------------------------------------------*
877 : * Function clear_buffers()
878 : *
879 : * Clears buffers of delay lines and filters
880 : *-----------------------------------------------------------------------------------------*/
881 :
882 12692 : 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 114228 : for ( branch_idx = 0; branch_idx < IVAS_REV_MAX_NR_BRANCHES; branch_idx++ )
890 : {
891 101536 : delay_line = &( hReverb->delay_line[branch_idx] );
892 101536 : set_f( delay_line->pBuffer, 0, delay_line->MaxDelay );
893 101536 : delay_line->BufferPos = 0;
894 :
895 101536 : iirFilter = &( hReverb->t60[branch_idx] );
896 101536 : set_f( iirFilter->pBuffer, 0, iirFilter->MaxTaps );
897 : }
898 :
899 12692 : ivas_reverb_t2f_f2t_ClearHistory( &hReverb->fft_filter_ols );
900 :
901 12692 : 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 52608 : static void set_fft_and_datablock_sizes(
912 : REVERB_HANDLE hReverb,
913 : const int16_t subframe_len )
914 : {
915 52608 : hReverb->full_block_size = subframe_len;
916 52608 : if ( subframe_len == L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES )
917 : {
918 17215 : hReverb->fft_size = IVAS_REVERB_FFT_SIZE_48K;
919 17215 : hReverb->num_fft_subblocks = IVAS_REVERB_FFT_N_SUBBLOCKS_48K;
920 : }
921 35393 : else if ( subframe_len == L_FRAME32k / MAX_PARAM_SPATIAL_SUBFRAMES )
922 : {
923 17534 : hReverb->fft_size = IVAS_REVERB_FFT_SIZE_32K;
924 17534 : hReverb->num_fft_subblocks = IVAS_REVERB_FFT_N_SUBBLOCKS_32K;
925 : }
926 17859 : else if ( subframe_len == L_FRAME16k / MAX_PARAM_SPATIAL_SUBFRAMES )
927 : {
928 17859 : hReverb->fft_size = IVAS_REVERB_FFT_SIZE_16K;
929 17859 : hReverb->num_fft_subblocks = IVAS_REVERB_FFT_N_SUBBLOCKS_16K;
930 : }
931 : else
932 : {
933 0 : assert( 0 ); /* unsupported block size */
934 : }
935 :
936 52608 : hReverb->fft_subblock_size = subframe_len / hReverb->num_fft_subblocks;
937 :
938 52608 : 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 52608 : 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 52608 : ivas_reverb_interpolate_acoustic_data( nr_fc_input, pRoomAcoustics->pFc_input, pRoomAcoustics->pAcoustic_rt60, pRoomAcoustics->pAcoustic_dsr,
958 52608 : nr_fc_fft_filter, pParams->pFc, pParams->pRt60, pParams->pDsr );
959 :
960 : /* adjust DSR for the delay difference */
961 52608 : delay_diff = pRoomAcoustics->inputPreDelay - pRoomAcoustics->acousticPreDelay;
962 52608 : ln_1e6_inverted = 1.0f / logf( 1e06f );
963 11286912 : for ( bin_idx = 0; bin_idx < nr_fc_fft_filter; bin_idx++ )
964 : {
965 11234304 : 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 11234304 : exp_argument = min( exp_argument, 23.0f );
968 11234304 : exp_argument = max( exp_argument, -23.0f );
969 11234304 : pParams->pDsr[bin_idx] *= expf( exp_argument );
970 : }
971 :
972 52608 : return;
973 : }
974 :
975 :
976 : /*-----------------------------------------------------------------------------------------*
977 : * Function setup_FDN_branches()
978 : *
979 : * Sets up feedback delay network system
980 : *-----------------------------------------------------------------------------------------*/
981 :
982 12692 : 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 12692 : error = IVAS_ERR_OK;
989 :
990 : /* initialize feedback branches */
991 114228 : for ( branch_idx = 0; branch_idx < IVAS_REV_MAX_NR_BRANCHES; branch_idx++ )
992 : {
993 101536 : 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 101536 : ivas_reverb_iir_filt_init( &( hReverb->t60[branch_idx] ), IVAS_REV_MAX_IIR_FILTER_LENGTH );
995 101536 : hReverb->mixer[0][branch_idx] = 0.0f;
996 101536 : hReverb->mixer[1][branch_idx] = 0.0f;
997 : }
998 12692 : clear_buffers( hReverb );
999 12692 : nr_coefs = pParams->t60_filter_order + 1;
1000 :
1001 12692 : if ( IVAS_REV_MAX_IIR_FILTER_LENGTH < nr_coefs )
1002 : {
1003 0 : return IVAS_ERR_INTERNAL;
1004 : }
1005 : else
1006 : {
1007 114228 : for ( branch_idx = 0; branch_idx < pParams->nr_loops; branch_idx++ )
1008 : {
1009 101536 : if ( ( error = set_feedback_delay( hReverb, branch_idx, pParams->pLoop_delays[branch_idx] ) ) != IVAS_ERR_OK )
1010 : {
1011 0 : return error;
1012 : }
1013 :
1014 101536 : 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 38076 : for ( channel_idx = 0; channel_idx < pParams->nr_outputs; channel_idx++ )
1022 : {
1023 25384 : 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 12692 : return error;
1030 : }
1031 :
1032 :
1033 : /*-------------------------------------------------------------------------
1034 : * ivas_reverb_open()
1035 : *
1036 : * Allocate and initialize FDN reverberation handle
1037 : *------------------------------------------------------------------------*/
1038 :
1039 52608 : 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 52608 : 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 52608 : output_frame = (int16_t) ( output_Fs / FRAMES_PER_SEC );
1062 52608 : subframe_len = output_frame / MAX_PARAM_SPATIAL_SUBFRAMES;
1063 52608 : predelay_bf_len = output_frame;
1064 52608 : nr_fc_input = hRenderConfig->roomAcoustics.nBands;
1065 :
1066 52608 : if ( *hReverb == NULL )
1067 : {
1068 : /* Allocate main reverb. handle */
1069 12692 : 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 52608 : if ( ( error = set_base_config( ¶ms, output_Fs ) ) != IVAS_ERR_OK )
1076 : {
1077 0 : return error;
1078 : }
1079 :
1080 52608 : if ( *hReverb == NULL )
1081 : {
1082 : /* Allocate memory for feedback delay lines */
1083 114228 : for ( loop_idx = 0; loop_idx < IVAS_REV_MAX_NR_BRANCHES; loop_idx++ )
1084 : {
1085 101536 : 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 12692 : 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 52608 : pState->nr_of_branches = IVAS_REV_MAX_NR_BRANCHES;
1099 52608 : set_fft_and_datablock_sizes( pState, subframe_len );
1100 :
1101 52608 : 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 52608 : params.pRt60 = &pFft_wf_filter_ch1[0][0];
1107 52608 : params.pDsr = params.pRt60 + nr_fc_fft_filter;
1108 52608 : 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 52608 : freq_step = 0.5f * output_Fs / ( nr_fc_fft_filter - 1 );
1115 11286912 : for ( bin_idx = 0; bin_idx < nr_fc_fft_filter; bin_idx++ )
1116 : {
1117 11234304 : params.pFc[bin_idx] = freq_step * bin_idx;
1118 : }
1119 :
1120 52608 : set_reverb_acoustic_data( ¶ms, &hRenderConfig->roomAcoustics, nr_fc_input, nr_fc_fft_filter );
1121 52608 : params.pHrtf_avg_pwr_response_l_const = hHrtfStatistics->average_energy_l;
1122 52608 : params.pHrtf_avg_pwr_response_r_const = hHrtfStatistics->average_energy_r;
1123 52608 : params.pHrtf_inter_aural_coherence_const = hHrtfStatistics->inter_aural_coherence;
1124 :
1125 : /* set reverb acoustic configuration based on renderer config */
1126 52608 : pState->pConfig.roomAcoustics.nBands = hRenderConfig->roomAcoustics.nBands;
1127 :
1128 52608 : if ( hRenderConfig->roomAcoustics.use_er == 1 )
1129 : {
1130 26030 : pState->pConfig.roomAcoustics.use_er = hRenderConfig->roomAcoustics.use_er;
1131 26030 : pState->pConfig.roomAcoustics.lowComplexity = hRenderConfig->roomAcoustics.lowComplexity;
1132 : }
1133 :
1134 : /* set up input downmix */
1135 52608 : if ( *hReverb == NULL )
1136 : {
1137 12692 : pState->dmx_gain = calc_dmx_gain();
1138 : }
1139 :
1140 : /* set up predelay - must be after set_base_config() and before compute_t60_coeffs() */
1141 52608 : calc_predelay( ¶ms, hRenderConfig->roomAcoustics.acousticPreDelay, output_Fs );
1142 :
1143 : /* set up jot reverb 60 filters - must be set up after set_reverb_acoustic_data() */
1144 52608 : if ( ( error = compute_t60_coeffs( ¶ms, nr_fc_fft_filter, output_Fs ) ) != IVAS_ERR_OK )
1145 : {
1146 0 : return error;
1147 : }
1148 :
1149 : /* Compute target levels (gains) for the coloration filters */
1150 52608 : 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,
1151 : params.pLoop_delays, params.pT60_filter_coeff, pColor_target_l, pColor_target_r );
1152 :
1153 : /* Defining appropriate windowing parameters for FFT filters to prevent aliasing */
1154 52608 : fft_hist_size = pState->fft_size - pState->fft_subblock_size;
1155 :
1156 52608 : transition_start = (int16_t) roundf( FFT_FILTER_WND_FLAT_REGION * fft_hist_size );
1157 52608 : transition_length = (int16_t) roundf( FFT_FILTER_WND_TRANS_REGION * fft_hist_size );
1158 :
1159 : /* Compute the window used for FFT filters */
1160 52608 : ivas_reverb_define_window_fft( pTime_window, transition_start, transition_length, nr_fc_fft_filter );
1161 :
1162 : /* === Copy parameters from ivas_reverb_params_t into DSP blocks === */
1163 : /* === to be used for subsequent audio signal processing === */
1164 52608 : if ( *hReverb == NULL )
1165 : {
1166 12692 : pState->do_corr_filter = params.do_corr_filter;
1167 :
1168 : /* clear & init jot reverb fft filters */
1169 12692 : if ( ( error = initialize_reverb_filters( pState ) ) != IVAS_ERR_OK )
1170 : {
1171 0 : return error;
1172 : }
1173 : }
1174 :
1175 52608 : if ( pState->do_corr_filter )
1176 : {
1177 : /* Computing correlation filters on the basis of target IA coherence */
1178 52608 : 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 );
1179 :
1180 : /* Copying the computed FFT correlation filters to the fft_filter components */
1181 52608 : if ( ( error = set_correl_fft_filter( pState, 0, pFft_wf_filter_ch0 ) ) != IVAS_ERR_OK )
1182 : {
1183 0 : return error;
1184 : }
1185 :
1186 52608 : if ( ( error = set_correl_fft_filter( pState, 1, pFft_wf_filter_ch1 ) ) != IVAS_ERR_OK )
1187 : {
1188 0 : return error;
1189 : }
1190 : }
1191 :
1192 : /* Computing coloration filters on the basis of target responses */
1193 52608 : 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 );
1194 :
1195 : /* Copying the computed FFT colorations filters to the fft_filter components */
1196 52608 : if ( ( error = set_color_fft_filter( pState, 0, pFft_wf_filter_ch0 ) ) != IVAS_ERR_OK )
1197 : {
1198 0 : return error;
1199 : }
1200 :
1201 52608 : if ( ( error = set_color_fft_filter( pState, 1, pFft_wf_filter_ch1 ) ) != IVAS_ERR_OK )
1202 : {
1203 0 : return error;
1204 : }
1205 :
1206 52608 : if ( *hReverb == NULL )
1207 : {
1208 : /* init predelay */
1209 12692 : ivas_rev_delay_line_init( &( pState->predelay_line ), pState->pPredelay_buffer, params.pre_delay, predelay_bf_len );
1210 :
1211 : /* set up feedback delay network */
1212 12692 : if ( ( error = setup_FDN_branches( pState, ¶ms ) ) != IVAS_ERR_OK )
1213 : {
1214 0 : return error;
1215 : }
1216 : }
1217 : else
1218 : {
1219 39916 : pState->predelay_line.Delay = params.pre_delay;
1220 : }
1221 :
1222 52608 : nr_coefs = params.t60_filter_order + 1;
1223 :
1224 473472 : for ( branch_idx = 0; branch_idx < params.nr_loops; branch_idx++ )
1225 : {
1226 420864 : pCoef_a = ¶ms.pT60_filter_coeff[2 * nr_coefs * branch_idx + nr_coefs];
1227 420864 : pCoef_b = ¶ms.pT60_filter_coeff[2 * nr_coefs * branch_idx];
1228 :
1229 420864 : if ( ( error = set_t60_filter( pState, branch_idx, nr_coefs, pCoef_a, pCoef_b ) ) != IVAS_ERR_OK )
1230 : {
1231 0 : return error;
1232 : }
1233 : }
1234 :
1235 52608 : *hReverb = pState;
1236 :
1237 52608 : return IVAS_ERR_OK;
1238 : }
1239 :
1240 :
1241 : /*-------------------------------------------------------------------------
1242 : * ivas_reverb_close()
1243 : *
1244 : * Deallocate Crend reverberation handle
1245 : *------------------------------------------------------------------------*/
1246 :
1247 193614 : void ivas_reverb_close(
1248 : REVERB_HANDLE *hReverb_in /* i/o: Reverberator handle */
1249 : )
1250 : {
1251 : REVERB_HANDLE hReverb;
1252 : int16_t loop_idx;
1253 :
1254 193614 : hReverb = *hReverb_in;
1255 :
1256 193614 : if ( hReverb_in == NULL || *hReverb_in == NULL )
1257 : {
1258 180922 : return;
1259 : }
1260 :
1261 114228 : for ( loop_idx = 0; loop_idx < IVAS_REV_MAX_NR_BRANCHES; loop_idx++ )
1262 : {
1263 101536 : if ( hReverb->loop_delay_buffer[loop_idx] != NULL )
1264 : {
1265 101536 : free( hReverb->loop_delay_buffer[loop_idx] );
1266 101536 : hReverb->loop_delay_buffer[loop_idx] = NULL;
1267 : }
1268 : }
1269 :
1270 12692 : free( hReverb->pPredelay_buffer );
1271 12692 : hReverb->pPredelay_buffer = NULL;
1272 :
1273 12692 : free( *hReverb_in );
1274 12692 : *hReverb_in = NULL;
1275 :
1276 12692 : return;
1277 : }
1278 :
1279 :
1280 : /*-----------------------------------------------------------------------------------------*
1281 : * Function post_fft_filter()
1282 : *
1283 : *
1284 : *-----------------------------------------------------------------------------------------*/
1285 :
1286 87962834 : static void post_fft_filter(
1287 : REVERB_HANDLE hReverb,
1288 : float *p0,
1289 : float *p1,
1290 : float *pBuffer_0,
1291 : float *pBuffer_1 )
1292 : {
1293 87962834 : if ( hReverb->do_corr_filter )
1294 : {
1295 87962834 : ivas_reverb_t2f_f2t_in( &hReverb->fft_filter_ols, p0, p1, pBuffer_0, pBuffer_1 );
1296 87962834 : ivas_reverb_fft_filter_ComplexMul( &hReverb->fft_filter_correl_0, pBuffer_0 );
1297 87962834 : ivas_reverb_fft_filter_ComplexMul( &hReverb->fft_filter_correl_1, pBuffer_1 );
1298 87962834 : ivas_reverb_fft_filter_CrossMix( pBuffer_0, pBuffer_1, hReverb->fft_filter_correl_0.fft_size );
1299 : }
1300 : else
1301 : {
1302 0 : ivas_reverb_t2f_f2t_in( &hReverb->fft_filter_ols, p0, p1, pBuffer_0, pBuffer_1 );
1303 : }
1304 :
1305 87962834 : ivas_reverb_fft_filter_ComplexMul( &hReverb->fft_filter_color_0, pBuffer_0 );
1306 87962834 : ivas_reverb_fft_filter_ComplexMul( &hReverb->fft_filter_color_1, pBuffer_1 );
1307 87962834 : ivas_reverb_t2f_f2t_out( &hReverb->fft_filter_ols, pBuffer_0, pBuffer_1, p0, p1 );
1308 :
1309 87962834 : return;
1310 : }
1311 :
1312 :
1313 : /*-----------------------------------------------------------------------------------------*
1314 : * Function reverb_block()
1315 : *
1316 : * Input a block (mono) and calculate the 2 output blocks.
1317 : *-----------------------------------------------------------------------------------------*/
1318 :
1319 87962834 : static void reverb_block(
1320 : REVERB_HANDLE hReverb,
1321 : float *pInput,
1322 : float *pOut0,
1323 : float *pOut1 )
1324 :
1325 : {
1326 87962834 : uint16_t nr_branches = hReverb->nr_of_branches;
1327 87962834 : uint16_t bsize = hReverb->full_block_size;
1328 87962834 : uint16_t inner_bsize = INNER_BLK_SIZE;
1329 : uint16_t i, j, k, ns, branch_idx, blk_idx, start_sample_idx;
1330 :
1331 : float *pFFT_buf[2], FFT_buf_1[RV_FILTER_MAX_FFT_SIZE], FFT_buf_2[RV_FILTER_MAX_FFT_SIZE];
1332 : float pFeedback_input[INNER_BLK_SIZE];
1333 : float pTemp[INNER_BLK_SIZE];
1334 : float *ppOutput[IVAS_REV_MAX_NR_BRANCHES];
1335 : float Output[IVAS_REV_MAX_NR_BRANCHES][INNER_BLK_SIZE];
1336 :
1337 87962834 : pFFT_buf[0] = &FFT_buf_1[0];
1338 87962834 : pFFT_buf[1] = &FFT_buf_2[0];
1339 :
1340 791665506 : for ( branch_idx = 0; branch_idx < nr_branches; branch_idx++ )
1341 : {
1342 703702672 : ppOutput[branch_idx] = (float *) Output + branch_idx * inner_bsize;
1343 : }
1344 :
1345 268094773 : for ( k = 0; k < bsize; k += inner_bsize )
1346 : {
1347 180131939 : float *pO0 = &pOut0[k];
1348 180131939 : float *pO1 = &pOut1[k];
1349 14590687059 : for ( i = 0; i < inner_bsize; i++ )
1350 : {
1351 14410555120 : pO0[i] = 0.0f;
1352 14410555120 : pO1[i] = 0.0f;
1353 : }
1354 :
1355 : /* feedback network: */
1356 1621187451 : for ( i = 0; i < nr_branches; i++ )
1357 : {
1358 1441055512 : float *pOutput_i = &ppOutput[i][0];
1359 1441055512 : float mixer_0_i = hReverb->mixer[0][i];
1360 1441055512 : float mixer_1_i = hReverb->mixer[1][i];
1361 :
1362 : /* output and feedback are same, get sample from delay line ... */
1363 1441055512 : ivas_rev_delay_line_get_sample_blk( &( hReverb->delay_line[i] ), inner_bsize, pTemp );
1364 1441055512 : ivas_reverb_iir_filt_2taps_feed_blk( &( hReverb->t60[i] ), inner_bsize, pTemp, ppOutput[i] );
1365 >11672*10^7 : for ( ns = 0; ns < inner_bsize; ns++ )
1366 : {
1367 >11528*10^7 : pO0[ns] += pOutput_i[ns] * mixer_0_i; /* mixer ch 0 */
1368 >11528*10^7 : pO1[ns] += pOutput_i[ns] * mixer_1_i; /* mixer ch 1 */
1369 : }
1370 : }
1371 :
1372 1621187451 : for ( i = 0; i < nr_branches; i++ )
1373 : {
1374 1441055512 : float *pIn = &pInput[k];
1375 :
1376 >11672*10^7 : for ( ns = 0; ns < inner_bsize; ns++ )
1377 : {
1378 >11528*10^7 : pFeedback_input[ns] = pIn[ns];
1379 : }
1380 :
1381 12969499608 : for ( j = 0; j < nr_branches; j++ )
1382 : {
1383 11528444096 : float gain_matrix_j_i = hReverb->gain_matrix[j][i];
1384 11528444096 : float *pOutput = &ppOutput[j][0];
1385 >93380*10^7 : for ( ns = 0; ns < inner_bsize; ns++ )
1386 : {
1387 >92227*10^7 : pFeedback_input[ns] += gain_matrix_j_i * pOutput[ns];
1388 : }
1389 : }
1390 :
1391 1441055512 : ivas_rev_delay_line_feed_sample_blk( &( hReverb->delay_line[i] ), inner_bsize, pFeedback_input );
1392 : }
1393 : }
1394 :
1395 : /* Applying FFT filter to each sub-frame */
1396 175925668 : for ( blk_idx = 0; blk_idx < hReverb->num_fft_subblocks; blk_idx++ )
1397 : {
1398 87962834 : start_sample_idx = blk_idx * hReverb->fft_subblock_size;
1399 87962834 : post_fft_filter( hReverb, pOut0 + start_sample_idx, pOut1 + start_sample_idx, pFFT_buf[0], pFFT_buf[1] );
1400 : }
1401 :
1402 87962834 : return;
1403 : }
1404 :
1405 :
1406 : /*-----------------------------------------------------------------------------------------*
1407 : * Function downmix_input_block()
1408 : *
1409 : * Downmix input to mono, taking also DSR gain into account
1410 : *-----------------------------------------------------------------------------------------*/
1411 :
1412 87962834 : static ivas_error downmix_input_block(
1413 : const REVERB_HANDLE hReverb,
1414 : float *pcm_in[],
1415 : const AUDIO_CONFIG input_audio_config,
1416 : float *pPcm_out,
1417 : const int16_t input_offset )
1418 : {
1419 : int16_t i, s, nchan_transport;
1420 87962834 : float dmx_gain = hReverb->dmx_gain;
1421 :
1422 87962834 : switch ( input_audio_config )
1423 : {
1424 69661313 : case IVAS_AUDIO_CONFIG_STEREO:
1425 : case IVAS_AUDIO_CONFIG_5_1:
1426 : case IVAS_AUDIO_CONFIG_7_1:
1427 : case IVAS_AUDIO_CONFIG_5_1_2:
1428 : case IVAS_AUDIO_CONFIG_5_1_4:
1429 : case IVAS_AUDIO_CONFIG_7_1_4:
1430 : case IVAS_AUDIO_CONFIG_ISM1:
1431 : case IVAS_AUDIO_CONFIG_ISM2:
1432 : case IVAS_AUDIO_CONFIG_ISM3:
1433 : case IVAS_AUDIO_CONFIG_ISM4:
1434 : {
1435 69661313 : nchan_transport = audioCfg2channels( input_audio_config );
1436 11416654913 : for ( s = 0; s < hReverb->full_block_size; s++ )
1437 : {
1438 11346993600 : float temp = pcm_in[0][input_offset + s];
1439 23429713120 : for ( i = 1; i < nchan_transport; i++ )
1440 : {
1441 12082719520 : temp += pcm_in[i][input_offset + s];
1442 : }
1443 11346993600 : pPcm_out[s] = dmx_gain * temp;
1444 : }
1445 69661313 : break;
1446 : }
1447 18301521 : case IVAS_AUDIO_CONFIG_MONO: /* ~'ZOA_1' */
1448 : case IVAS_AUDIO_CONFIG_FOA:
1449 : case IVAS_AUDIO_CONFIG_HOA2:
1450 : case IVAS_AUDIO_CONFIG_HOA3:
1451 : {
1452 3081863041 : for ( s = 0; s < hReverb->full_block_size; s++ )
1453 : {
1454 3063561520 : pPcm_out[s] = dmx_gain * pcm_in[0][input_offset + s];
1455 : }
1456 18301521 : break;
1457 : }
1458 0 : default:
1459 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unsupported input format for reverb" );
1460 : break;
1461 : }
1462 :
1463 87962834 : return IVAS_ERR_OK;
1464 : }
1465 :
1466 :
1467 : /*-----------------------------------------------------------------------------------------*
1468 : * Function predelay_block()
1469 : *
1470 : * Perform a predelay
1471 : *-----------------------------------------------------------------------------------------*/
1472 :
1473 87962834 : static void predelay_block(
1474 : const REVERB_HANDLE hReverb,
1475 : float *pInput,
1476 : float *pOutput )
1477 : {
1478 : uint16_t i, idx, n_samples, blk_size;
1479 87962834 : uint16_t max_blk_size = (uint16_t) hReverb->predelay_line.Delay;
1480 :
1481 87962834 : if ( max_blk_size < 2 )
1482 : {
1483 939323 : if ( max_blk_size == 0 ) /* zero-length delay line: just copy the data from input to output */
1484 : {
1485 185452683 : for ( i = 0; i < hReverb->full_block_size; i++ )
1486 : {
1487 184513360 : pOutput[i] = pInput[i];
1488 : }
1489 : }
1490 : else /* 1-sample length delay line: feed the data sample-by-sample */
1491 : {
1492 0 : for ( i = 0; i < hReverb->full_block_size; i++ )
1493 : {
1494 0 : pOutput[i] = ivas_rev_delay_line_get_sample( &( hReverb->predelay_line ) );
1495 0 : ivas_rev_delay_line_feed_sample( &( hReverb->predelay_line ), pInput[i] );
1496 : }
1497 : }
1498 : }
1499 : else /* multiple-sample length delay line: use block processing */
1500 : {
1501 87023511 : idx = 0;
1502 87023511 : n_samples = hReverb->full_block_size;
1503 521750634 : while ( n_samples > 0 )
1504 : {
1505 434727123 : blk_size = n_samples;
1506 434727123 : if ( blk_size > max_blk_size )
1507 : {
1508 347703612 : blk_size = max_blk_size;
1509 : }
1510 434727123 : ivas_rev_delay_line_get_sample_blk( &( hReverb->predelay_line ), blk_size, &pOutput[idx] );
1511 434727123 : ivas_rev_delay_line_feed_sample_blk( &( hReverb->predelay_line ), blk_size, &pInput[idx] );
1512 434727123 : idx += blk_size;
1513 434727123 : n_samples -= blk_size;
1514 : }
1515 : }
1516 :
1517 87962834 : return;
1518 : }
1519 :
1520 :
1521 : /*-----------------------------------------------------------------------------------------*
1522 : * Function mix_output_block()
1523 : *
1524 : * mix one block of *pInL and *pInR samples into *pOutL and *pOutL respectively
1525 : *-----------------------------------------------------------------------------------------*/
1526 :
1527 25144598 : static void mix_output_block(
1528 : const REVERB_HANDLE hReverb,
1529 : const float *pInL,
1530 : const float *pInR,
1531 : float *pOutL,
1532 : float *pOutR )
1533 : {
1534 : uint16_t i;
1535 :
1536 4247705558 : for ( i = 0; i < hReverb->full_block_size; i++ )
1537 : {
1538 4222560960 : pOutL[i] += pInL[i];
1539 4222560960 : pOutR[i] += pInR[i];
1540 : }
1541 :
1542 25144598 : return;
1543 : }
1544 :
1545 :
1546 : /*-----------------------------------------------------------------------------------------*
1547 : * ivas_reverb_process()
1548 : *
1549 : * Process the input PCM audio into output PCM audio, applying reverb
1550 : *-----------------------------------------------------------------------------------------*/
1551 :
1552 87962834 : ivas_error ivas_reverb_process(
1553 : const REVERB_HANDLE hReverb, /* i : Reverberator handle */
1554 : const AUDIO_CONFIG input_audio_config, /* i : reverb. input audio configuration */
1555 : const int16_t mix_signals, /* i : add reverb to output signal */
1556 : float *pcm_in[], /* i : the PCM audio to apply reverb on */
1557 : float *pcm_out[], /* o : the PCM audio with reverb applied */
1558 : const int16_t i_ts /* i : subframe index */
1559 : )
1560 : {
1561 : float tmp0[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES], tmp1[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES], tmp2[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES];
1562 : ivas_error error;
1563 :
1564 87962834 : if ( ( error = downmix_input_block( hReverb, pcm_in, input_audio_config, tmp1, i_ts * hReverb->full_block_size ) ) != IVAS_ERR_OK )
1565 : {
1566 0 : return error;
1567 : }
1568 :
1569 87962834 : predelay_block( hReverb, tmp1, tmp0 );
1570 :
1571 87962834 : reverb_block( hReverb, tmp0, tmp1, tmp2 );
1572 :
1573 87962834 : if ( mix_signals )
1574 : {
1575 25144598 : mix_output_block( hReverb, tmp1, tmp2, &pcm_out[0][i_ts * hReverb->full_block_size], &pcm_out[1][i_ts * hReverb->full_block_size] );
1576 : }
1577 : else
1578 : {
1579 62818236 : mvr2r( tmp1, &pcm_out[0][i_ts * hReverb->full_block_size], hReverb->full_block_size );
1580 62818236 : mvr2r( tmp2, &pcm_out[1][i_ts * hReverb->full_block_size], hReverb->full_block_size );
1581 : }
1582 :
1583 87962834 : return IVAS_ERR_OK;
1584 : }
1585 :
1586 :
1587 : /*-------------------------------------------------------------------------
1588 : * ivas_binaural_reverb_processSubFrame()
1589 : *
1590 : * Compute the reverberation - room effect
1591 : *------------------------------------------------------------------------*/
1592 :
1593 21747994 : void ivas_binaural_reverb_processSubframe(
1594 : REVERB_STRUCT_HANDLE hReverb, /* i/o: binaural reverb handle */
1595 : const int16_t numInChannels, /* i : num inputs to be processed */
1596 : const int16_t numSlots, /* i : number of slots to be processed */
1597 : 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. */
1598 : float inImag[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], /* i : input CLDFB data imag */
1599 : float outReal[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], /* o : output CLDFB data real */
1600 : float outImag[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX] /* o : output CLDFB data imag */
1601 : )
1602 : {
1603 : /* Declare the required variables */
1604 : int16_t idx, bin, ch, sample, invertSampleIndex, tapIdx, *phaseShiftTypePr;
1605 : float **tapRealPr, **tapImagPr;
1606 21747994 : push_wmops( "binaural_reverb" );
1607 :
1608 : /* 1) Rotate the data in the loop buffer of the reverberator.
1609 : * Notice that the audio at the loop buffers is at time-inverted order
1610 : * for convolution purposes later on. */
1611 959171864 : for ( bin = 0; bin < hReverb->numBins; bin++ )
1612 : {
1613 : /* Move the data forwards by blockSize (i.e. by the frame size of 16 CLDFB slots) */
1614 937423870 : mvr2r( hReverb->loopBufReal[bin], hReverb->loopBufReal[bin] + numSlots, hReverb->loopBufLength[bin] );
1615 937423870 : mvr2r( hReverb->loopBufImag[bin], hReverb->loopBufImag[bin] + numSlots, hReverb->loopBufLength[bin] );
1616 :
1617 : /* Add the data from the end of the loop to the beginning, with an attenuation factor
1618 : * according to RT60. This procedure generates an IIR decaying response. The response
1619 : * is decorrelated later on. */
1620 937423870 : v_multc( hReverb->loopBufReal[bin] + hReverb->loopBufLength[bin], hReverb->loopAttenuationFactor[bin], hReverb->loopBufReal[bin], numSlots );
1621 937423870 : v_multc( hReverb->loopBufImag[bin] + hReverb->loopBufLength[bin], hReverb->loopAttenuationFactor[bin], hReverb->loopBufImag[bin], numSlots );
1622 : }
1623 :
1624 : /* 2) Apply the determined pre-delay to the input audio, and add the delayed audio to the loop. */
1625 21747994 : idx = hReverb->preDelayBufferIndex;
1626 108551903 : for ( sample = 0; sample < numSlots; sample++ )
1627 : {
1628 86803909 : invertSampleIndex = numSlots - sample - 1;
1629 :
1630 3827231689 : for ( bin = 0; bin < hReverb->numBins; bin++ )
1631 : {
1632 : /* Add from pre-delay buffer a sample to the loop buffer, in a time-inverted order.
1633 : * Also apply the spectral gains determined for the reverberation */
1634 3740427780 : hReverb->loopBufReal[bin][invertSampleIndex] += hReverb->preDelayBufferReal[idx][bin] * hReverb->reverbEqGains[bin];
1635 3740427780 : hReverb->loopBufImag[bin][invertSampleIndex] += hReverb->preDelayBufferImag[idx][bin] * hReverb->reverbEqGains[bin];
1636 3740427780 : hReverb->preDelayBufferReal[idx][bin] = 0.0f;
1637 3740427780 : hReverb->preDelayBufferImag[idx][bin] = 0.0f;
1638 : }
1639 :
1640 : /* Add every second input channel as is to the pre-delay buffer, and every second input channel with
1641 : * 90 degrees phase shift to reduce energy imbalances between coherent and incoherent sounds */
1642 265326099 : for ( ch = 0; ch < numInChannels; ch++ )
1643 : {
1644 178522190 : if ( ch % 2 )
1645 : {
1646 88116997 : v_add( hReverb->preDelayBufferReal[idx], inReal[ch][sample], hReverb->preDelayBufferReal[idx], hReverb->numBins );
1647 88116997 : v_add( hReverb->preDelayBufferImag[idx], inImag[ch][sample], hReverb->preDelayBufferImag[idx], hReverb->numBins );
1648 : }
1649 : else
1650 : {
1651 90405193 : v_sub( hReverb->preDelayBufferReal[idx], inImag[ch][sample], hReverb->preDelayBufferReal[idx], hReverb->numBins );
1652 90405193 : v_add( hReverb->preDelayBufferImag[idx], inReal[ch][sample], hReverb->preDelayBufferImag[idx], hReverb->numBins );
1653 : }
1654 : }
1655 86803909 : idx = ( idx + 1 ) % hReverb->preDelayBufferLength;
1656 : }
1657 21747994 : hReverb->preDelayBufferIndex = idx;
1658 :
1659 : /* 3) Perform the filtering/decorrelating, using complex and sparse FIR filtering */
1660 959171864 : for ( bin = 0; bin < hReverb->numBins; bin++ )
1661 : {
1662 2812271610 : for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
1663 : {
1664 : /* These tap pointers have been determined to point to the loop buffer at sparse locations */
1665 1874847740 : tapRealPr = hReverb->tapPointersReal[bin][ch];
1666 1874847740 : tapImagPr = hReverb->tapPointersImag[bin][ch];
1667 :
1668 1874847740 : phaseShiftTypePr = hReverb->tapPhaseShiftType[bin][ch];
1669 :
1670 : /* Flush output */
1671 1874847740 : set_f( hReverb->outputBufferReal[bin][ch], 0.0f, numSlots );
1672 1874847740 : set_f( hReverb->outputBufferImag[bin][ch], 0.0f, numSlots );
1673 :
1674 : /* Add from temporally decaying sparse tap locations the audio to the output. */
1675 41746244548 : for ( tapIdx = 0; tapIdx < hReverb->taps[bin][ch]; tapIdx++ )
1676 : {
1677 39871396808 : switch ( phaseShiftTypePr[tapIdx] )
1678 : {
1679 9750652268 : case 0: /* 0 degrees phase */
1680 9750652268 : v_add( hReverb->outputBufferReal[bin][ch], tapRealPr[tapIdx], hReverb->outputBufferReal[bin][ch], numSlots );
1681 9750652268 : v_add( hReverb->outputBufferImag[bin][ch], tapImagPr[tapIdx], hReverb->outputBufferImag[bin][ch], numSlots );
1682 9750652268 : break;
1683 10451484932 : case 1: /* 90 degrees phase */
1684 10451484932 : v_sub( hReverb->outputBufferReal[bin][ch], tapImagPr[tapIdx], hReverb->outputBufferReal[bin][ch], numSlots );
1685 10451484932 : v_add( hReverb->outputBufferImag[bin][ch], tapRealPr[tapIdx], hReverb->outputBufferImag[bin][ch], numSlots );
1686 10451484932 : break;
1687 10030681420 : case 2: /* 180 degrees phase */
1688 10030681420 : v_sub( hReverb->outputBufferReal[bin][ch], tapRealPr[tapIdx], hReverb->outputBufferReal[bin][ch], numSlots );
1689 10030681420 : v_sub( hReverb->outputBufferImag[bin][ch], tapImagPr[tapIdx], hReverb->outputBufferImag[bin][ch], numSlots );
1690 10030681420 : break;
1691 9638578188 : default: /* 270 degrees phase */
1692 9638578188 : v_add( hReverb->outputBufferReal[bin][ch], tapImagPr[tapIdx], hReverb->outputBufferReal[bin][ch], numSlots );
1693 9638578188 : v_sub( hReverb->outputBufferImag[bin][ch], tapRealPr[tapIdx], hReverb->outputBufferImag[bin][ch], numSlots );
1694 9638578188 : break;
1695 : }
1696 : }
1697 : }
1698 :
1699 : /* Generate diffuse field binaural coherence by mixing the incoherent reverberated channels with pre-defined gains */
1700 937423870 : if ( bin <= hReverb->highestBinauralCoherenceBin )
1701 : {
1702 150316343 : if ( hReverb->useBinauralCoherence )
1703 : {
1704 750272452 : for ( sample = 0; sample < numSlots; sample++ )
1705 : {
1706 : float leftRe, rightRe, leftIm, rightIm;
1707 :
1708 599956109 : leftRe = hReverb->binauralCoherenceDirectGains[bin] * hReverb->outputBufferReal[bin][0][sample] + hReverb->binauralCoherenceCrossmixGains[bin] * hReverb->outputBufferReal[bin][1][sample];
1709 599956109 : rightRe = hReverb->binauralCoherenceDirectGains[bin] * hReverb->outputBufferReal[bin][1][sample] + hReverb->binauralCoherenceCrossmixGains[bin] * hReverb->outputBufferReal[bin][0][sample];
1710 599956109 : leftIm = hReverb->binauralCoherenceDirectGains[bin] * hReverb->outputBufferImag[bin][0][sample] + hReverb->binauralCoherenceCrossmixGains[bin] * hReverb->outputBufferImag[bin][1][sample];
1711 599956109 : rightIm = hReverb->binauralCoherenceDirectGains[bin] * hReverb->outputBufferImag[bin][1][sample] + hReverb->binauralCoherenceCrossmixGains[bin] * hReverb->outputBufferImag[bin][0][sample];
1712 :
1713 599956109 : hReverb->outputBufferReal[bin][0][sample] = leftRe;
1714 599956109 : hReverb->outputBufferReal[bin][1][sample] = rightRe;
1715 599956109 : hReverb->outputBufferImag[bin][0][sample] = leftIm;
1716 599956109 : hReverb->outputBufferImag[bin][1][sample] = rightIm;
1717 : }
1718 : }
1719 : }
1720 : }
1721 :
1722 : /* 4) Write data to output */
1723 65243982 : for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
1724 : {
1725 217103806 : for ( sample = 0; sample < numSlots; sample++ )
1726 : {
1727 : /* Audio was in the temporally inverted order for convolution, re-invert audio to output */
1728 173607818 : invertSampleIndex = numSlots - sample - 1;
1729 :
1730 7654463378 : for ( bin = 0; bin < hReverb->numBins; bin++ )
1731 : {
1732 7480855560 : outReal[ch][sample][bin] = hReverb->outputBufferReal[bin][ch][invertSampleIndex];
1733 7480855560 : outImag[ch][sample][bin] = hReverb->outputBufferImag[bin][ch][invertSampleIndex];
1734 : }
1735 3109221338 : for ( ; bin < CLDFB_NO_CHANNELS_MAX; bin++ )
1736 : {
1737 2935613520 : outReal[ch][sample][bin] = 0.0f;
1738 2935613520 : outImag[ch][sample][bin] = 0.0f;
1739 : }
1740 : }
1741 : }
1742 :
1743 21747994 : pop_wmops();
1744 21747994 : return;
1745 : }
1746 :
1747 :
1748 : /*-------------------------------------------------------------------------
1749 : * ivas_binaural_reverb_open()
1750 : *
1751 : * Allocate and initialize binaural room reverberator handle
1752 : *------------------------------------------------------------------------*/
1753 :
1754 32899 : static ivas_error ivas_binaural_reverb_open(
1755 : REVERB_STRUCT_HANDLE *hReverbPr, /* i/o: binaural reverb handle */
1756 : const int16_t numBins, /* i : number of CLDFB bins */
1757 : const int16_t numCldfbSlotsPerFrame, /* i : number of CLDFB slots per frame */
1758 : const int32_t sampling_rate, /* i : sampling rate */
1759 : const float *revTimes, /* i : reverberation times T60 for each CLDFB bin in seconds */
1760 : const float *revEnes, /* i : spectrum for reverberated sound at each CLDFB bin */
1761 : const int16_t preDelay /* i : reverb pre-delay in CLDFB slots */
1762 : )
1763 : {
1764 : int16_t bin, chIdx, k, len;
1765 : REVERB_STRUCT_HANDLE hReverb;
1766 :
1767 32899 : if ( ( *hReverbPr = (REVERB_STRUCT_HANDLE) malloc( sizeof( REVERB_STRUCT ) ) ) == NULL )
1768 : {
1769 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1770 : }
1771 :
1772 32899 : hReverb = *hReverbPr;
1773 :
1774 32899 : hReverb->useBinauralCoherence = 1;
1775 32899 : hReverb->preDelayBufferLength = 1;
1776 32899 : hReverb->preDelayBufferIndex = 0;
1777 :
1778 32899 : hReverb->numBins = numBins;
1779 32899 : hReverb->blockSize = numCldfbSlotsPerFrame;
1780 :
1781 723778 : for ( k = 0; k < IVAS_REVERB_PREDELAY_MAX + 1; k++ )
1782 : {
1783 690879 : set_f( hReverb->preDelayBufferReal[k], 0.0f, hReverb->numBins );
1784 690879 : set_f( hReverb->preDelayBufferImag[k], 0.0f, hReverb->numBins );
1785 : }
1786 :
1787 1362609 : for ( bin = 0; bin < hReverb->numBins; bin++ )
1788 : {
1789 : /* Loop Buffer */
1790 1329710 : hReverb->loopBufLengthMax[bin] = (int16_t) ( 500 / ( 1 + bin ) + ( CLDFB_NO_CHANNELS_MAX - bin ) );
1791 :
1792 1329710 : len = hReverb->loopBufLengthMax[bin] + hReverb->blockSize;
1793 1329710 : if ( ( hReverb->loopBufReal[bin] = (float *) malloc( len * sizeof( float ) ) ) == NULL )
1794 : {
1795 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1796 : }
1797 :
1798 1329710 : if ( ( hReverb->loopBufImag[bin] = (float *) malloc( len * sizeof( float ) ) ) == NULL )
1799 : {
1800 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1801 : }
1802 :
1803 1329710 : set_f( hReverb->loopBufReal[bin], 0.0f, len );
1804 1329710 : set_f( hReverb->loopBufImag[bin], 0.0f, len );
1805 :
1806 : /* Determine loop buffer length. The following formula is manually tuned to generate sufficiently long
1807 : * but not excessively long loops to generate reverberation. */
1808 : /* Note: the resulted length is very sensitive to the precision of the constants below (e.g. 1.45 vs. 1.45f) */
1809 1329710 : hReverb->loopBufLength[bin] = (int16_t) ( 1.45 * (int16_t) ( revTimes[bin] * 150.0 ) + 1 );
1810 1329710 : hReverb->loopBufLength[bin] = min( hReverb->loopBufLength[bin], hReverb->loopBufLengthMax[bin] );
1811 :
1812 : /* Sparse Filter Tap Locations */
1813 3989130 : for ( chIdx = 0; chIdx < BINAURAL_CHANNELS; chIdx++ )
1814 : {
1815 2659420 : len = hReverb->loopBufLength[bin];
1816 :
1817 2659420 : if ( ( hReverb->tapPhaseShiftType[bin][chIdx] = (int16_t *) malloc( len * sizeof( int16_t ) ) ) == NULL )
1818 : {
1819 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1820 : }
1821 2659420 : set_s( hReverb->tapPhaseShiftType[bin][chIdx], 0, len );
1822 :
1823 2659420 : if ( ( hReverb->tapPointersReal[bin][chIdx] = (float **) malloc( len * sizeof( float * ) ) ) == NULL )
1824 : {
1825 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1826 : }
1827 :
1828 2659420 : if ( ( hReverb->tapPointersImag[bin][chIdx] = (float **) malloc( len * sizeof( float * ) ) ) == NULL )
1829 : {
1830 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1831 : }
1832 :
1833 2659420 : len = hReverb->blockSize;
1834 2659420 : if ( ( hReverb->outputBufferReal[bin][chIdx] = (float *) malloc( len * sizeof( float ) ) ) == NULL )
1835 : {
1836 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1837 : }
1838 :
1839 2659420 : if ( ( hReverb->outputBufferImag[bin][chIdx] = (float *) malloc( len * sizeof( float ) ) ) == NULL )
1840 : {
1841 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
1842 : }
1843 :
1844 2659420 : set_f( hReverb->outputBufferReal[bin][chIdx], 0.0f, len );
1845 2659420 : set_f( hReverb->outputBufferImag[bin][chIdx], 0.0f, len );
1846 : }
1847 : }
1848 :
1849 32899 : ivas_binaural_reverb_setReverbTimes( hReverb, sampling_rate, revTimes, revEnes );
1850 :
1851 32899 : ivas_binaural_reverb_setPreDelay( hReverb, preDelay );
1852 :
1853 32899 : return IVAS_ERR_OK;
1854 : }
1855 :
1856 :
1857 : /*-------------------------------------------------------------------------
1858 : * ivas_binaural_reverb_init()
1859 : *
1860 : * Initialize binaural room reverberator handle for FastConv renderer
1861 : *------------------------------------------------------------------------*/
1862 :
1863 32899 : ivas_error ivas_binaural_reverb_init(
1864 : REVERB_STRUCT_HANDLE *hReverbPr, /* i/o: binaural reverb handle */
1865 : const HRTFS_STATISTICS_HANDLE hHrtfStatistics, /* i : HRTF statistics handle */
1866 : const int16_t numBins, /* i : number of CLDFB bins */
1867 : const int16_t numCldfbSlotsPerFrame, /* i : number of CLDFB slots per frame */
1868 : const IVAS_ROOM_ACOUSTICS_CONFIG_DATA *roomAcoustics, /* i/o: room acoustics parameters */
1869 : const int32_t sampling_rate, /* i : sampling rate */
1870 : const float *defaultTimes, /* i : default reverberation times */
1871 : const float *defaultEne, /* i : default reverberation energies */
1872 : float *earlyEne /* i/o: Early part energies to be modified */
1873 : )
1874 : {
1875 : ivas_error error;
1876 : int16_t preDelay, bin;
1877 : float revTimes[CLDFB_NO_CHANNELS_MAX];
1878 : float revEne[CLDFB_NO_CHANNELS_MAX];
1879 :
1880 32899 : if ( roomAcoustics != NULL )
1881 : {
1882 18206 : if ( ( error = ivas_reverb_prepare_cldfb_params( roomAcoustics, hHrtfStatistics, sampling_rate, revTimes, revEne ) ) != IVAS_ERR_OK )
1883 : {
1884 0 : return error;
1885 : }
1886 :
1887 : /* Convert preDelay from seconds to CLDFB slots as needed by binaural reverb */
1888 18206 : preDelay = (int16_t) roundf( roomAcoustics->acousticPreDelay * CLDFB_SLOTS_PER_SECOND );
1889 : }
1890 : else
1891 : {
1892 654253 : for ( bin = 0; bin < numBins; bin++ )
1893 : {
1894 639560 : revTimes[bin] = defaultTimes[bin];
1895 639560 : revEne[bin] = defaultEne[bin];
1896 : }
1897 14693 : preDelay = 10;
1898 : }
1899 :
1900 1362609 : for ( bin = 0; bin < numBins; bin++ )
1901 : {
1902 : /* Adjust the room effect parameters when the reverberation time is less than a threshold value, to avoid
1903 : spectral artefacts with the synthetic reverberator. */
1904 1329710 : if ( revTimes[bin] < REV_TIME_THRESHOLD )
1905 : {
1906 : float adjustedEarlyEne, adjustedLateEne, adjustedRevTime;
1907 : float revTimeModifier, energyModifier;
1908 :
1909 : /* Adjust reverberation times, higher towards a threshold */
1910 422674 : revTimeModifier = fmaxf( 0.0f, 1.0f - ( revTimes[bin] / REV_TIME_THRESHOLD ) );
1911 422674 : adjustedRevTime = ( 1.0f - revTimeModifier ) * revTimes[bin];
1912 422674 : adjustedRevTime += revTimeModifier * ( revTimes[bin] + REV_TIME_THRESHOLD ) * 0.5f;
1913 422674 : energyModifier = ( adjustedRevTime - revTimes[bin] ) / adjustedRevTime;
1914 :
1915 : /* Adjust early and late energies, by moving late energy to early energy */
1916 422674 : if ( earlyEne != NULL )
1917 : {
1918 326554 : adjustedEarlyEne = earlyEne[bin] + revEne[bin] * energyModifier;
1919 326554 : earlyEne[bin] = adjustedEarlyEne; /* Store already here */
1920 : }
1921 :
1922 422674 : adjustedLateEne = revEne[bin] * ( 1.0f - energyModifier );
1923 :
1924 : /* Store adjusted room effect parameters to be used in reverb processing */
1925 422674 : revTimes[bin] = adjustedRevTime;
1926 422674 : revEne[bin] = adjustedLateEne;
1927 : }
1928 : }
1929 :
1930 32899 : error = ivas_binaural_reverb_open( hReverbPr, numBins, numCldfbSlotsPerFrame, sampling_rate, revTimes, revEne, preDelay );
1931 :
1932 32899 : return error;
1933 : }
1934 :
1935 :
1936 : /*-------------------------------------------------------------------------
1937 : * ivas_binaural_reverb_close()
1938 : *
1939 : * Close binaural room reverberator handle
1940 : *------------------------------------------------------------------------*/
1941 :
1942 32899 : void ivas_binaural_reverb_close(
1943 : REVERB_STRUCT_HANDLE *hReverb /* i/o: binaural reverb handle */
1944 : )
1945 : {
1946 : int16_t bin, chIdx;
1947 :
1948 32899 : if ( hReverb == NULL || *hReverb == NULL )
1949 : {
1950 0 : return;
1951 : }
1952 :
1953 1362609 : for ( bin = 0; bin < ( *hReverb )->numBins; bin++ )
1954 : {
1955 3989130 : for ( chIdx = 0; chIdx < BINAURAL_CHANNELS; chIdx++ )
1956 : {
1957 2659420 : free( ( *hReverb )->tapPhaseShiftType[bin][chIdx] );
1958 2659420 : free( ( *hReverb )->tapPointersReal[bin][chIdx] );
1959 2659420 : free( ( *hReverb )->tapPointersImag[bin][chIdx] );
1960 2659420 : free( ( *hReverb )->outputBufferReal[bin][chIdx] );
1961 2659420 : free( ( *hReverb )->outputBufferImag[bin][chIdx] );
1962 : }
1963 1329710 : free( ( *hReverb )->loopBufReal[bin] );
1964 1329710 : free( ( *hReverb )->loopBufImag[bin] );
1965 : }
1966 :
1967 32899 : free( ( *hReverb ) );
1968 32899 : ( *hReverb ) = NULL;
1969 :
1970 32899 : return;
1971 : }
|