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 81676201 : static uint16_t binRend_rand(
134 : REVERB_STRUCT_HANDLE hReverb /* i/o: binaural reverb handle */
135 : )
136 : {
137 81676201 : hReverb->binRend_RandNext = hReverb->binRend_RandNext * 1103515245 + 12345;
138 :
139 81676201 : return (uint16_t) ( hReverb->binRend_RandNext / 65536 ) % 32768;
140 : }
141 :
142 :
143 : /*-------------------------------------------------------------------------
144 : * ivas_binaural_reverb_setPreDelay()
145 : *
146 : *
147 : *------------------------------------------------------------------------*/
148 :
149 16075 : 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 16075 : if ( delaySamples < 1 )
155 : {
156 0 : hReverb->preDelayBufferLength = 1;
157 :
158 0 : return;
159 : }
160 :
161 16075 : if ( delaySamples > IVAS_REVERB_PREDELAY_MAX )
162 : {
163 12 : hReverb->preDelayBufferLength = IVAS_REVERB_PREDELAY_MAX;
164 :
165 12 : return;
166 : }
167 :
168 16063 : hReverb->preDelayBufferLength = delaySamples;
169 :
170 16063 : return;
171 : }
172 :
173 :
174 : /*-------------------------------------------------------------------------
175 : * ivas_binaural_reverb_setReverbTimes()
176 : *
177 : *
178 : *------------------------------------------------------------------------*/
179 :
180 16075 : 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 16075 : hReverb->binRend_RandNext = (uint16_t) BIN_REND_RANDOM_SEED;
192 16075 : hReverb->highestBinauralCoherenceBin = 0;
193 644595 : for ( bin = 0; bin < hReverb->numBins; bin++ )
194 : {
195 : /* Determine the diffuse field binaural coherence */
196 628520 : binCenterFreq = ( (float) bin + 0.5f ) / ( (float) hReverb->numBins ) * ( (float) output_Fs ) / 2.0f;
197 628520 : if ( bin == 0 )
198 : {
199 16075 : diffuseFieldICC = 1.0f;
200 : }
201 612445 : else if ( binCenterFreq < 2700.0f )
202 : {
203 94772 : diffuseFieldICC = sinf( EVS_PI * binCenterFreq / 550.0f + 1e-20f ) / ( EVS_PI * binCenterFreq / 550.0f + 1e-20f ) * ( 1.0f - binCenterFreq / 2700.0f );
204 94772 : hReverb->highestBinauralCoherenceBin = bin;
205 : }
206 : else
207 : {
208 517673 : diffuseFieldICC = 0.0f;
209 : }
210 :
211 : /* Mixing gains to generate a diffuse-binaural sound based on incoherent sound */
212 628520 : tmpVal = ( 1.0f - sqrtf( 1.0f - powf( diffuseFieldICC, 2.0 ) ) ) / 2.0f;
213 628520 : if ( diffuseFieldICC > 0 )
214 : {
215 62622 : hReverb->binauralCoherenceCrossmixGains[bin] = sqrtf( fabsf( tmpVal ) );
216 : }
217 : else
218 : {
219 565898 : hReverb->binauralCoherenceCrossmixGains[bin] = -sqrtf( fabsf( tmpVal ) );
220 : }
221 628520 : hReverb->binauralCoherenceDirectGains[bin] = sqrtf( 1.0f - fabsf( tmpVal ) );
222 :
223 : /* Determine attenuation factor that generates the appropriate energy decay according to reverberation time */
224 628520 : attenuationFactorPerSample = powf( 10.0f, -3.0f * ( 1.0f / ( (float) CLDFB_SLOTS_PER_SECOND * revTimes[bin] ) ) );
225 628520 : hReverb->loopAttenuationFactor[bin] = powf( attenuationFactorPerSample, hReverb->loopBufLength[bin] );
226 628520 : 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 628520 : intendedEnergy = 0.0f;
231 628520 : actualizedEnergy = 0.0f;
232 :
233 1885560 : for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
234 : {
235 1257040 : energyBuildup = 0.0f;
236 1257040 : currentEnergy = 1.0f;
237 1257040 : tap = 0;
238 :
239 64762584 : for ( sample = 0; sample < hReverb->loopBufLength[bin]; sample++ )
240 : {
241 63505544 : intendedEnergy += currentEnergy;
242 :
243 : /* The randomization at the energy build up affects where the sparse taps are located */
244 63505544 : energyBuildup += currentEnergy + 0.1f * ( (float) binRend_rand( hReverb ) / PCM16_TO_FLT_FAC - 0.5f );
245 :
246 63505544 : 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 18170657 : 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 18170657 : hReverb->tapPointersReal[bin][ch][tap] = &( hReverb->loopBufReal[bin][sample] );
252 18170657 : hReverb->tapPointersImag[bin][ch][tap] = &( hReverb->loopBufImag[bin][sample] );
253 18170657 : energyBuildup -= 1.0f; /* A tap is added, thus remove its energy from the buildup */
254 18170657 : tap++;
255 18170657 : actualizedEnergy += 1.0f;
256 : }
257 63505544 : 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 1257040 : 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 1257040 : 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 628520 : hReverb->reverbEqGains[bin] = sqrtf( revEnes[bin] ); /* Determined reverb spectrum */
275 628520 : hReverb->reverbEqGains[bin] *= sqrtf( intendedEnergy / actualizedEnergy ); /* Correction of random effects at the decorrelator design */
276 628520 : hReverb->reverbEqGains[bin] *= sqrtf( 0.5f * ( 1.0f - attenuationFactorPerSampleSq ) ); /* Correction of IIR decay rate */
277 : }
278 :
279 16075 : 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 12409 : 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 12409 : 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 12409 : 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 12409 : u = inv_sqrt( n );
324 :
325 12409 : if ( n == 4 )
326 : {
327 0 : u = -u;
328 : }
329 :
330 12409 : pFeedbackMatrix[0] = u;
331 49636 : for ( x = 1; x < n; x += x )
332 : {
333 124090 : for ( i = 0; i < x; i++ )
334 : {
335 347452 : for ( j = 0; j < x; j++ )
336 : {
337 260589 : pFeedbackMatrix[( i + x ) * n + j] = pFeedbackMatrix[i * n + j];
338 260589 : pFeedbackMatrix[i * n + j + x] = pFeedbackMatrix[i * n + j];
339 260589 : pFeedbackMatrix[( i + x ) * n + j + x] = -pFeedbackMatrix[i * n + j];
340 : }
341 : }
342 : }
343 :
344 12409 : 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 12409 : 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 12409 : 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 12409 : ff = 1.0;
372 111681 : for ( i = 0; i < n; i++ )
373 : {
374 99272 : pExtractMatrix[i] = 1.0;
375 99272 : pExtractMatrix[i + n] = ff;
376 99272 : ff = -ff;
377 : }
378 :
379 12409 : 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 12409 : 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 12409 : const int16_t *selected_loop_delay = NULL;
396 :
397 12409 : if ( pParams == NULL )
398 : {
399 0 : return IVAS_ERR_INTERNAL;
400 : }
401 :
402 12409 : pParams->pre_delay = 0;
403 12409 : pParams->nr_outputs = BINAURAL_CHANNELS;
404 12409 : pParams->nr_loops = IVAS_REV_MAX_NR_BRANCHES;
405 :
406 : /* set loop delays to default */
407 12409 : if ( output_Fs == 48000 )
408 : {
409 4142 : selected_loop_delay = default_loop_delay_48k;
410 : }
411 8267 : else if ( output_Fs == 32000 )
412 : {
413 4087 : selected_loop_delay = default_loop_delay_32k;
414 : }
415 4180 : else if ( output_Fs == 16000 )
416 : {
417 4180 : selected_loop_delay = default_loop_delay_16k;
418 : }
419 :
420 111681 : for ( loop_idx = 0; loop_idx < pParams->nr_loops; loop_idx++ )
421 : {
422 99272 : pParams->pLoop_delays[loop_idx] = selected_loop_delay[loop_idx];
423 : }
424 :
425 : /* set feedback and output matrices */
426 12409 : if ( ( error = compute_feedback_matrix( pParams->pLoop_feedback_matrix, pParams->nr_loops ) ) != IVAS_ERR_OK )
427 : {
428 0 : return error;
429 : }
430 :
431 12409 : 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 12409 : pParams->t60_filter_order = 1; /* set to 1 in base config. */
435 :
436 12409 : if ( pParams->nr_outputs == 2 )
437 : {
438 12409 : pParams->do_corr_filter = 1;
439 : }
440 : else
441 : {
442 0 : pParams->do_corr_filter = 0;
443 : }
444 :
445 12409 : return IVAS_ERR_OK;
446 : }
447 :
448 :
449 : /*-----------------------------------------------------------------------------------------*
450 : * Function calc_dmx_gain()
451 : *
452 : * Computes the downmix gain
453 : *-----------------------------------------------------------------------------------------*/
454 :
455 8248 : static float calc_dmx_gain( void )
456 : {
457 8248 : const float dist = DEFAULT_SRC_DIST;
458 8248 : 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 12409 : 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 12409 : predelay = (int16_t) roundf( acoustic_predelay_sec * (float) output_Fs );
476 12409 : output_frame = (int16_t) ( output_Fs / FRAMES_PER_SEC );
477 12409 : fbdelay = pParams->pLoop_delays[pParams->nr_loops - 1];
478 12409 : predelay -= fbdelay;
479 :
480 12409 : if ( predelay < 0 )
481 : {
482 2005 : predelay = 0;
483 : }
484 :
485 12409 : if ( output_frame < predelay )
486 : {
487 0 : predelay = output_frame;
488 : }
489 :
490 12409 : pParams->pre_delay = predelay;
491 :
492 12409 : return;
493 : }
494 :
495 :
496 : /*-----------------------------------------------------------------------------------------*
497 : * Function compute_t60_coeffs()
498 : *
499 : * Calculate Jot reverb's T60 filter coefficients
500 : *-----------------------------------------------------------------------------------------*/
501 :
502 12409 : 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 12409 : targetT60 = pParams->pRt60;
516 12409 : freqT60 = pParams->pFc;
517 :
518 12409 : error = IVAS_ERR_OK;
519 12409 : tf_T60_len = nr_fc_fft_filter;
520 12409 : len = pParams->t60_filter_order + 1;
521 12409 : freq_Nyquist = 0.5f * (float) output_Fs;
522 :
523 : /* normalize pFrequencies: 0 .. 1/2 output_Fs --> 0.0 .. 1.0 */
524 12409 : inv_hfs = 1.0f / freq_Nyquist;
525 2666482 : for ( bin_idx = 0; bin_idx < tf_T60_len; bin_idx++ )
526 : {
527 2654073 : norm_f[bin_idx] = freqT60[bin_idx] * inv_hfs;
528 : }
529 :
530 111681 : for ( loop_idx = 0; loop_idx < pParams->nr_loops; loop_idx++ )
531 : {
532 99272 : loop_delay_sec = (float) pParams->pLoop_delays[loop_idx] / (float) output_Fs;
533 21331856 : for ( bin_idx = 0; bin_idx < tf_T60_len; bin_idx++ )
534 : {
535 21232584 : target_gains_db[bin_idx] = -60.0f * loop_delay_sec / targetT60[bin_idx];
536 21232584 : target_gains_db[bin_idx] = max( target_gains_db[bin_idx], -120.0f );
537 : }
538 :
539 99272 : pCoeffs_a = &pParams->pT60_filter_coeff[2 * len * loop_idx + len];
540 99272 : pCoeffs_b = &pParams->pT60_filter_coeff[2 * len * loop_idx];
541 99272 : 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 12409 : len = ( pParams->t60_filter_order + 1 ) >> 1; /* == floor( (order+1) / 2) */
548 111681 : for ( loop_idx = 0; loop_idx < pParams->nr_loops; loop_idx++ )
549 : {
550 99272 : pParams->pLoop_delays[loop_idx] -= len;
551 : }
552 :
553 12409 : 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 99272 : 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 99272 : w0 = tanf( EVS_PI * f0 / 2.0f );
573 99272 : gain = lin_gain_lf / lin_gain_hf;
574 :
575 99272 : 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 99272 : pNum[0] = 1 + w0;
585 99272 : pNum[1] = w0 - 1;
586 99272 : pDen[0] = 1 + w0 / gain;
587 99272 : pDen[1] = w0 / gain - 1;
588 : }
589 :
590 : /* Normalize and adjust gain to match target amplitudes */
591 99272 : pNum[0] = ( pNum[0] / pDen[0] ) * lin_gain_hf;
592 99272 : pNum[1] = ( pNum[1] / pDen[0] ) * lin_gain_hf;
593 99272 : pDen[1] = pDen[1] / pDen[0];
594 99272 : pDen[0] = 1.0f;
595 :
596 99272 : return;
597 : }
598 :
599 :
600 : /*-----------------------------------------------------------------------------------------*
601 : * Function calc_jot_t60_coeffs()
602 : *
603 : * Calculate Jot reverb's T60 filters
604 : *-----------------------------------------------------------------------------------------*/
605 :
606 99272 : 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 99272 : const float ref_lf_min_norm = REF_LF_MIN / fNyquist;
615 99272 : const float ref_lf_max_norm = REF_LF_MAX / fNyquist;
616 99272 : const float ref_hf_min_norm = REF_HF_MIN / fNyquist;
617 99272 : 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 99272 : minidx = nrFrequencies - 1;
624 99272 : minval = 1e+20f;
625 99272 : lf_target_gain_dB = 0.0f;
626 99272 : hf_target_gain_dB = 0.0f;
627 99272 : n_points_lf = 0;
628 99272 : n_points_hf = 0;
629 :
630 21331856 : for ( f_idx = 0; f_idx < nrFrequencies; f_idx++ )
631 : {
632 21232584 : if ( ( pFrequencies[f_idx] >= ref_lf_min_norm ) && ( pFrequencies[f_idx] <= ref_lf_max_norm ) )
633 : {
634 231544 : lf_target_gain_dB += pH_dB[f_idx];
635 231544 : n_points_lf++;
636 : }
637 21232584 : if ( ( pFrequencies[f_idx] >= ref_hf_min_norm ) && ( pFrequencies[f_idx] <= ref_hf_max_norm ) )
638 : {
639 4201744 : hf_target_gain_dB += pH_dB[f_idx];
640 4201744 : n_points_hf++;
641 : }
642 : }
643 :
644 99272 : if ( ( n_points_lf == 0 ) || ( n_points_hf == 0 ) )
645 : {
646 0 : return IVAS_ERR_INTERNAL;
647 : }
648 :
649 99272 : lf_target_gain_dB = lf_target_gain_dB / (float) n_points_lf;
650 99272 : hf_target_gain_dB = hf_target_gain_dB / (float) n_points_hf;
651 99272 : mid_crossing_gain_dB = hf_target_gain_dB + LF_BIAS * ( lf_target_gain_dB - hf_target_gain_dB );
652 :
653 21133312 : for ( f_idx = 1; f_idx < nrFrequencies - 1; f_idx++ )
654 : {
655 21034040 : tmp = fabsf( pH_dB[f_idx] - mid_crossing_gain_dB );
656 21034040 : if ( tmp < minval )
657 : {
658 1511024 : minval = tmp;
659 1511024 : minidx = f_idx;
660 : }
661 : }
662 :
663 99272 : f0 = pFrequencies[minidx];
664 99272 : lin_gain_lf = powf( 10.0f, lf_target_gain_dB * 0.05f );
665 99272 : lin_gain_hf = powf( 10.0f, hf_target_gain_dB * 0.05f );
666 :
667 : /* call low-pass iir shelf */
668 99272 : calc_low_shelf_first_order_filter( pCoeffB, pCoeffA, f0, lin_gain_lf, lin_gain_hf );
669 :
670 99272 : 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 8248 : static ivas_error initialize_reverb_filters(
681 : REVERB_HANDLE hReverb )
682 : {
683 : ivas_error error;
684 :
685 : /* init correlation and coloration filters */
686 8248 : 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 8248 : 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 8248 : 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 8248 : 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 8248 : 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 8248 : 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 99272 : 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 99272 : if ( branch >= hReverb->nr_of_branches )
729 : {
730 0 : return IVAS_ERR_INTERNAL;
731 : }
732 :
733 99272 : if ( nr_taps > IVAS_REV_MAX_IIR_FILTER_LENGTH )
734 : {
735 0 : return IVAS_ERR_INTERNAL;
736 : }
737 :
738 99272 : ivas_reverb_iir_filt_set( &( hReverb->t60[branch] ), nr_taps, coefA, coefB );
739 :
740 99272 : 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 65984 : static ivas_error set_feedback_delay(
751 : REVERB_HANDLE hReverb,
752 : const uint16_t branch,
753 : const int16_t fb_delay )
754 : {
755 65984 : if ( branch >= hReverb->nr_of_branches )
756 : {
757 0 : return IVAS_ERR_INTERNAL;
758 : }
759 :
760 65984 : hReverb->delay_line[branch].Delay = fb_delay;
761 :
762 65984 : 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 65984 : 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 65984 : if ( branch >= hReverb->nr_of_branches )
779 : {
780 0 : return IVAS_ERR_INTERNAL;
781 : }
782 :
783 593856 : for ( gain_idx = 0; gain_idx < hReverb->nr_of_branches; gain_idx++ )
784 : {
785 527872 : hReverb->gain_matrix[branch][gain_idx] = pGain[gain_idx];
786 : }
787 :
788 65984 : return IVAS_ERR_OK;
789 : }
790 :
791 :
792 : /*-----------------------------------------------------------------------------------------*
793 : * Function set_correl_fft_filter()
794 : *
795 : * Sets correlation filter complex gains
796 : *-----------------------------------------------------------------------------------------*/
797 :
798 24818 : static ivas_error set_correl_fft_filter(
799 : REVERB_HANDLE hReverb,
800 : const uint16_t channel,
801 : rv_fftwf_type_complex *pSpectrum )
802 : {
803 24818 : if ( channel > 1 )
804 : {
805 0 : return IVAS_ERR_INTERNAL;
806 : }
807 :
808 24818 : if ( channel == 0 )
809 : {
810 12409 : 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 12409 : 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 24818 : return IVAS_ERR_OK;
818 : }
819 :
820 :
821 : /*-----------------------------------------------------------------------------------------*
822 : * Function set_color_fft_filter()
823 : *
824 : * Sets coloration filter complex gains
825 : *-----------------------------------------------------------------------------------------*/
826 :
827 24818 : static ivas_error set_color_fft_filter(
828 : REVERB_HANDLE hReverb,
829 : const uint16_t channel,
830 : rv_fftwf_type_complex *pSpectrum )
831 : {
832 24818 : if ( channel > 1 )
833 : {
834 0 : return IVAS_ERR_INTERNAL;
835 : }
836 :
837 24818 : if ( channel == 0 )
838 : {
839 12409 : 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 12409 : 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 24818 : 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 16496 : 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 16496 : if ( channel >= BINAURAL_CHANNELS )
863 : {
864 0 : return IVAS_ERR_INTERNAL;
865 : }
866 :
867 148464 : for ( branch_idx = 0; branch_idx < hReverb->nr_of_branches; branch_idx++ )
868 : {
869 131968 : hReverb->mixer[channel][branch_idx] = level[branch_idx];
870 : }
871 :
872 16496 : return IVAS_ERR_OK;
873 : }
874 :
875 :
876 : /*-----------------------------------------------------------------------------------------*
877 : * Function clear_buffers()
878 : *
879 : * Clears buffers of delay lines and filters
880 : *-----------------------------------------------------------------------------------------*/
881 :
882 8248 : 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 74232 : for ( branch_idx = 0; branch_idx < IVAS_REV_MAX_NR_BRANCHES; branch_idx++ )
890 : {
891 65984 : delay_line = &( hReverb->delay_line[branch_idx] );
892 65984 : set_f( delay_line->pBuffer, 0, delay_line->MaxDelay );
893 65984 : delay_line->BufferPos = 0;
894 :
895 65984 : iirFilter = &( hReverb->t60[branch_idx] );
896 65984 : set_f( iirFilter->pBuffer, 0, iirFilter->MaxTaps );
897 : }
898 :
899 8248 : ivas_reverb_t2f_f2t_ClearHistory( &hReverb->fft_filter_ols );
900 :
901 8248 : 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 12409 : static void set_fft_and_datablock_sizes(
912 : REVERB_HANDLE hReverb,
913 : const int16_t subframe_len )
914 : {
915 12409 : hReverb->full_block_size = subframe_len;
916 12409 : if ( subframe_len == L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES )
917 : {
918 4142 : hReverb->fft_size = IVAS_REVERB_FFT_SIZE_48K;
919 4142 : hReverb->num_fft_subblocks = IVAS_REVERB_FFT_N_SUBBLOCKS_48K;
920 : }
921 8267 : else if ( subframe_len == L_FRAME32k / MAX_PARAM_SPATIAL_SUBFRAMES )
922 : {
923 4087 : hReverb->fft_size = IVAS_REVERB_FFT_SIZE_32K;
924 4087 : hReverb->num_fft_subblocks = IVAS_REVERB_FFT_N_SUBBLOCKS_32K;
925 : }
926 4180 : else if ( subframe_len == L_FRAME16k / MAX_PARAM_SPATIAL_SUBFRAMES )
927 : {
928 4180 : hReverb->fft_size = IVAS_REVERB_FFT_SIZE_16K;
929 4180 : hReverb->num_fft_subblocks = IVAS_REVERB_FFT_N_SUBBLOCKS_16K;
930 : }
931 : else
932 : {
933 0 : assert( 0 ); /* unsupported block size */
934 : }
935 :
936 12409 : hReverb->fft_subblock_size = subframe_len / hReverb->num_fft_subblocks;
937 :
938 12409 : 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 12409 : 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 12409 : ivas_reverb_interpolate_acoustic_data( nr_fc_input, pRoomAcoustics->pFc_input, pRoomAcoustics->pAcoustic_rt60, pRoomAcoustics->pAcoustic_dsr,
958 12409 : nr_fc_fft_filter, pParams->pFc, pParams->pRt60, pParams->pDsr );
959 :
960 : /* adjust DSR for the delay difference */
961 12409 : delay_diff = pRoomAcoustics->inputPreDelay - pRoomAcoustics->acousticPreDelay;
962 12409 : ln_1e6_inverted = 1.0f / logf( 1e06f );
963 2666482 : for ( bin_idx = 0; bin_idx < nr_fc_fft_filter; bin_idx++ )
964 : {
965 2654073 : 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 2654073 : exp_argument = min( exp_argument, 23.0f );
968 2654073 : exp_argument = max( exp_argument, -23.0f );
969 2654073 : pParams->pDsr[bin_idx] *= expf( exp_argument );
970 : }
971 :
972 12409 : return;
973 : }
974 :
975 :
976 : /*-----------------------------------------------------------------------------------------*
977 : * Function setup_FDN_branches()
978 : *
979 : * Sets up feedback delay network system
980 : *-----------------------------------------------------------------------------------------*/
981 :
982 8248 : 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 8248 : error = IVAS_ERR_OK;
989 :
990 : /* initialize feedback branches */
991 74232 : for ( branch_idx = 0; branch_idx < IVAS_REV_MAX_NR_BRANCHES; branch_idx++ )
992 : {
993 65984 : 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 65984 : ivas_reverb_iir_filt_init( &( hReverb->t60[branch_idx] ), IVAS_REV_MAX_IIR_FILTER_LENGTH );
995 65984 : hReverb->mixer[0][branch_idx] = 0.0f;
996 65984 : hReverb->mixer[1][branch_idx] = 0.0f;
997 : }
998 8248 : clear_buffers( hReverb );
999 8248 : nr_coefs = pParams->t60_filter_order + 1;
1000 :
1001 8248 : if ( IVAS_REV_MAX_IIR_FILTER_LENGTH < nr_coefs )
1002 : {
1003 0 : return IVAS_ERR_INTERNAL;
1004 : }
1005 : else
1006 : {
1007 74232 : for ( branch_idx = 0; branch_idx < pParams->nr_loops; branch_idx++ )
1008 : {
1009 65984 : if ( ( error = set_feedback_delay( hReverb, branch_idx, pParams->pLoop_delays[branch_idx] ) ) != IVAS_ERR_OK )
1010 : {
1011 0 : return error;
1012 : }
1013 :
1014 65984 : 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 24744 : for ( channel_idx = 0; channel_idx < pParams->nr_outputs; channel_idx++ )
1022 : {
1023 16496 : 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 8248 : return error;
1030 : }
1031 :
1032 :
1033 : /*-------------------------------------------------------------------------
1034 : * ivas_reverb_open()
1035 : *
1036 : * Allocate and initialize FDN reverberation handle
1037 : *------------------------------------------------------------------------*/
1038 :
1039 12409 : 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 12409 : 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 12409 : output_frame = (int16_t) ( output_Fs / FRAMES_PER_SEC );
1062 12409 : subframe_len = output_frame / MAX_PARAM_SPATIAL_SUBFRAMES;
1063 12409 : predelay_bf_len = output_frame;
1064 12409 : nr_fc_input = hRenderConfig->roomAcoustics.nBands;
1065 :
1066 12409 : if ( *hReverb == NULL )
1067 : {
1068 : /* Allocate main reverb. handle */
1069 8248 : 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 12409 : if ( ( error = set_base_config( ¶ms, output_Fs ) ) != IVAS_ERR_OK )
1076 : {
1077 0 : return error;
1078 : }
1079 :
1080 12409 : if ( *hReverb == NULL )
1081 : {
1082 : /* Allocate memory for feedback delay lines */
1083 74232 : for ( loop_idx = 0; loop_idx < IVAS_REV_MAX_NR_BRANCHES; loop_idx++ )
1084 : {
1085 65984 : 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 8248 : 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 12409 : pState->nr_of_branches = IVAS_REV_MAX_NR_BRANCHES;
1099 12409 : set_fft_and_datablock_sizes( pState, subframe_len );
1100 :
1101 12409 : 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 12409 : params.pRt60 = &pFft_wf_filter_ch1[0][0];
1107 12409 : params.pDsr = params.pRt60 + nr_fc_fft_filter;
1108 12409 : 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 12409 : freq_step = 0.5f * output_Fs / ( nr_fc_fft_filter - 1 );
1115 2666482 : for ( bin_idx = 0; bin_idx < nr_fc_fft_filter; bin_idx++ )
1116 : {
1117 2654073 : params.pFc[bin_idx] = freq_step * bin_idx;
1118 : }
1119 :
1120 12409 : set_reverb_acoustic_data( ¶ms, &hRenderConfig->roomAcoustics, nr_fc_input, nr_fc_fft_filter );
1121 12409 : params.pHrtf_avg_pwr_response_l_const = hHrtfStatistics->average_energy_l;
1122 12409 : params.pHrtf_avg_pwr_response_r_const = hHrtfStatistics->average_energy_r;
1123 12409 : params.pHrtf_inter_aural_coherence_const = hHrtfStatistics->inter_aural_coherence;
1124 :
1125 : /* set reverb acoustic configuration based on renderer config */
1126 12409 : pState->pConfig.roomAcoustics.nBands = hRenderConfig->roomAcoustics.nBands;
1127 :
1128 12409 : if ( hRenderConfig->roomAcoustics.use_er == 1 )
1129 : {
1130 3147 : pState->pConfig.roomAcoustics.use_er = hRenderConfig->roomAcoustics.use_er;
1131 3147 : pState->pConfig.roomAcoustics.lowComplexity = hRenderConfig->roomAcoustics.lowComplexity;
1132 : }
1133 :
1134 : /* set up input downmix */
1135 12409 : if ( *hReverb == NULL )
1136 : {
1137 8248 : pState->dmx_gain = calc_dmx_gain();
1138 : }
1139 :
1140 : /* set up predelay - must be after set_base_config() and before compute_t60_coeffs() */
1141 12409 : 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 12409 : 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 12409 : 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 12409 : fft_hist_size = pState->fft_size - pState->fft_subblock_size;
1155 :
1156 12409 : transition_start = (int16_t) roundf( FFT_FILTER_WND_FLAT_REGION * fft_hist_size );
1157 12409 : transition_length = (int16_t) roundf( FFT_FILTER_WND_TRANS_REGION * fft_hist_size );
1158 :
1159 : /* Compute the window used for FFT filters */
1160 12409 : 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 12409 : if ( *hReverb == NULL )
1165 : {
1166 8248 : pState->do_corr_filter = params.do_corr_filter;
1167 :
1168 : /* clear & init jot reverb fft filters */
1169 8248 : if ( ( error = initialize_reverb_filters( pState ) ) != IVAS_ERR_OK )
1170 : {
1171 0 : return error;
1172 : }
1173 : }
1174 :
1175 12409 : if ( pState->do_corr_filter )
1176 : {
1177 : /* Computing correlation filters on the basis of target IA coherence */
1178 12409 : 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 12409 : if ( ( error = set_correl_fft_filter( pState, 0, pFft_wf_filter_ch0 ) ) != IVAS_ERR_OK )
1182 : {
1183 0 : return error;
1184 : }
1185 :
1186 12409 : 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 12409 : 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 12409 : if ( ( error = set_color_fft_filter( pState, 0, pFft_wf_filter_ch0 ) ) != IVAS_ERR_OK )
1197 : {
1198 0 : return error;
1199 : }
1200 :
1201 12409 : if ( ( error = set_color_fft_filter( pState, 1, pFft_wf_filter_ch1 ) ) != IVAS_ERR_OK )
1202 : {
1203 0 : return error;
1204 : }
1205 :
1206 12409 : if ( *hReverb == NULL )
1207 : {
1208 : /* init predelay */
1209 8248 : 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 8248 : if ( ( error = setup_FDN_branches( pState, ¶ms ) ) != IVAS_ERR_OK )
1213 : {
1214 0 : return error;
1215 : }
1216 : }
1217 : else
1218 : {
1219 4161 : pState->predelay_line.Delay = params.pre_delay;
1220 : }
1221 :
1222 12409 : nr_coefs = params.t60_filter_order + 1;
1223 :
1224 111681 : for ( branch_idx = 0; branch_idx < params.nr_loops; branch_idx++ )
1225 : {
1226 99272 : pCoef_a = ¶ms.pT60_filter_coeff[2 * nr_coefs * branch_idx + nr_coefs];
1227 99272 : pCoef_b = ¶ms.pT60_filter_coeff[2 * nr_coefs * branch_idx];
1228 :
1229 99272 : 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 12409 : *hReverb = pState;
1236 :
1237 12409 : return IVAS_ERR_OK;
1238 : }
1239 :
1240 :
1241 : /*-------------------------------------------------------------------------
1242 : * ivas_reverb_close()
1243 : *
1244 : * Deallocate Crend reverberation handle
1245 : *------------------------------------------------------------------------*/
1246 :
1247 150008 : 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 150008 : hReverb = *hReverb_in;
1255 :
1256 150008 : if ( hReverb_in == NULL || *hReverb_in == NULL )
1257 : {
1258 141760 : return;
1259 : }
1260 :
1261 74232 : for ( loop_idx = 0; loop_idx < IVAS_REV_MAX_NR_BRANCHES; loop_idx++ )
1262 : {
1263 65984 : if ( hReverb->loop_delay_buffer[loop_idx] != NULL )
1264 : {
1265 65984 : free( hReverb->loop_delay_buffer[loop_idx] );
1266 65984 : hReverb->loop_delay_buffer[loop_idx] = NULL;
1267 : }
1268 : }
1269 :
1270 8248 : free( hReverb->pPredelay_buffer );
1271 8248 : hReverb->pPredelay_buffer = NULL;
1272 :
1273 8248 : free( *hReverb_in );
1274 8248 : *hReverb_in = NULL;
1275 :
1276 8248 : return;
1277 : }
1278 :
1279 :
1280 : /*-----------------------------------------------------------------------------------------*
1281 : * Function post_fft_filter()
1282 : *
1283 : *
1284 : *-----------------------------------------------------------------------------------------*/
1285 :
1286 9333313 : 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 9333313 : if ( hReverb->do_corr_filter )
1294 : {
1295 9333313 : ivas_reverb_t2f_f2t_in( &hReverb->fft_filter_ols, p0, p1, pBuffer_0, pBuffer_1 );
1296 9333313 : ivas_reverb_fft_filter_ComplexMul( &hReverb->fft_filter_correl_0, pBuffer_0 );
1297 9333313 : ivas_reverb_fft_filter_ComplexMul( &hReverb->fft_filter_correl_1, pBuffer_1 );
1298 9333313 : 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 9333313 : ivas_reverb_fft_filter_ComplexMul( &hReverb->fft_filter_color_0, pBuffer_0 );
1306 9333313 : ivas_reverb_fft_filter_ComplexMul( &hReverb->fft_filter_color_1, pBuffer_1 );
1307 9333313 : ivas_reverb_t2f_f2t_out( &hReverb->fft_filter_ols, pBuffer_0, pBuffer_1, p0, p1 );
1308 :
1309 9333313 : return;
1310 : }
1311 :
1312 :
1313 : /*-----------------------------------------------------------------------------------------*
1314 : * Function reverb_block()
1315 : *
1316 : * Input a block (mono) and calculate the 2 output blocks.
1317 : *-----------------------------------------------------------------------------------------*/
1318 :
1319 9333313 : static void reverb_block(
1320 : REVERB_HANDLE hReverb,
1321 : float *pInput,
1322 : float *pOut0,
1323 : float *pOut1 )
1324 :
1325 : {
1326 9333313 : uint16_t nr_branches = hReverb->nr_of_branches;
1327 9333313 : uint16_t bsize = hReverb->full_block_size;
1328 9333313 : 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 9333313 : pFFT_buf[0] = &FFT_buf_1[0];
1338 9333313 : pFFT_buf[1] = &FFT_buf_2[0];
1339 :
1340 83999817 : for ( branch_idx = 0; branch_idx < nr_branches; branch_idx++ )
1341 : {
1342 74666504 : ppOutput[branch_idx] = (float *) Output + branch_idx * inner_bsize;
1343 : }
1344 :
1345 28100560 : for ( k = 0; k < bsize; k += inner_bsize )
1346 : {
1347 18767247 : float *pO0 = &pOut0[k];
1348 18767247 : float *pO1 = &pOut1[k];
1349 1520147007 : for ( i = 0; i < inner_bsize; i++ )
1350 : {
1351 1501379760 : pO0[i] = 0.0f;
1352 1501379760 : pO1[i] = 0.0f;
1353 : }
1354 :
1355 : /* feedback network: */
1356 168905223 : for ( i = 0; i < nr_branches; i++ )
1357 : {
1358 150137976 : float *pOutput_i = &ppOutput[i][0];
1359 150137976 : float mixer_0_i = hReverb->mixer[0][i];
1360 150137976 : float mixer_1_i = hReverb->mixer[1][i];
1361 :
1362 : /* output and feedback are same, get sample from delay line ... */
1363 150137976 : ivas_rev_delay_line_get_sample_blk( &( hReverb->delay_line[i] ), inner_bsize, pTemp );
1364 150137976 : ivas_reverb_iir_filt_2taps_feed_blk( &( hReverb->t60[i] ), inner_bsize, pTemp, ppOutput[i] );
1365 12161176056 : for ( ns = 0; ns < inner_bsize; ns++ )
1366 : {
1367 12011038080 : pO0[ns] += pOutput_i[ns] * mixer_0_i; /* mixer ch 0 */
1368 12011038080 : pO1[ns] += pOutput_i[ns] * mixer_1_i; /* mixer ch 1 */
1369 : }
1370 : }
1371 :
1372 168905223 : for ( i = 0; i < nr_branches; i++ )
1373 : {
1374 150137976 : float *pIn = &pInput[k];
1375 :
1376 12161176056 : for ( ns = 0; ns < inner_bsize; ns++ )
1377 : {
1378 12011038080 : pFeedback_input[ns] = pIn[ns];
1379 : }
1380 :
1381 1351241784 : for ( j = 0; j < nr_branches; j++ )
1382 : {
1383 1201103808 : float gain_matrix_j_i = hReverb->gain_matrix[j][i];
1384 1201103808 : float *pOutput = &ppOutput[j][0];
1385 97289408448 : for ( ns = 0; ns < inner_bsize; ns++ )
1386 : {
1387 96088304640 : pFeedback_input[ns] += gain_matrix_j_i * pOutput[ns];
1388 : }
1389 : }
1390 :
1391 150137976 : 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 18666626 : for ( blk_idx = 0; blk_idx < hReverb->num_fft_subblocks; blk_idx++ )
1397 : {
1398 9333313 : start_sample_idx = blk_idx * hReverb->fft_subblock_size;
1399 9333313 : post_fft_filter( hReverb, pOut0 + start_sample_idx, pOut1 + start_sample_idx, pFFT_buf[0], pFFT_buf[1] );
1400 : }
1401 :
1402 9333313 : 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 9333313 : 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 9333313 : float dmx_gain = hReverb->dmx_gain;
1421 :
1422 9333313 : switch ( input_audio_config )
1423 : {
1424 7118891 : 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 7118891 : nchan_transport = audioCfg2channels( input_audio_config );
1436 1150451051 : for ( s = 0; s < hReverb->full_block_size; s++ )
1437 : {
1438 1143332160 : float temp = pcm_in[0][input_offset + s];
1439 1753238400 : for ( i = 1; i < nchan_transport; i++ )
1440 : {
1441 609906240 : temp += pcm_in[i][input_offset + s];
1442 : }
1443 1143332160 : pPcm_out[s] = dmx_gain * temp;
1444 : }
1445 7118891 : break;
1446 : }
1447 2214422 : 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 360262022 : for ( s = 0; s < hReverb->full_block_size; s++ )
1453 : {
1454 358047600 : pPcm_out[s] = dmx_gain * pcm_in[0][input_offset + s];
1455 : }
1456 2214422 : break;
1457 : }
1458 0 : default:
1459 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unsupported input format for reverb" );
1460 : break;
1461 : }
1462 :
1463 9333313 : return IVAS_ERR_OK;
1464 : }
1465 :
1466 :
1467 : /*-----------------------------------------------------------------------------------------*
1468 : * Function predelay_block()
1469 : *
1470 : * Perform a predelay
1471 : *-----------------------------------------------------------------------------------------*/
1472 :
1473 9333313 : 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 9333313 : uint16_t max_blk_size = (uint16_t) hReverb->predelay_line.Delay;
1480 :
1481 9333313 : if ( max_blk_size < 2 )
1482 : {
1483 359528 : if ( max_blk_size == 0 ) /* zero-length delay line: just copy the data from input to output */
1484 : {
1485 60756728 : for ( i = 0; i < hReverb->full_block_size; i++ )
1486 : {
1487 60397200 : 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 8973785 : idx = 0;
1502 8973785 : n_samples = hReverb->full_block_size;
1503 53842710 : while ( n_samples > 0 )
1504 : {
1505 44868925 : blk_size = n_samples;
1506 44868925 : if ( blk_size > max_blk_size )
1507 : {
1508 35895140 : blk_size = max_blk_size;
1509 : }
1510 44868925 : ivas_rev_delay_line_get_sample_blk( &( hReverb->predelay_line ), blk_size, &pOutput[idx] );
1511 44868925 : ivas_rev_delay_line_feed_sample_blk( &( hReverb->predelay_line ), blk_size, &pInput[idx] );
1512 44868925 : idx += blk_size;
1513 44868925 : n_samples -= blk_size;
1514 : }
1515 : }
1516 :
1517 9333313 : 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 2305047 : 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 373804407 : for ( i = 0; i < hReverb->full_block_size; i++ )
1537 : {
1538 371499360 : pOutL[i] += pInL[i];
1539 371499360 : pOutR[i] += pInR[i];
1540 : }
1541 :
1542 2305047 : 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 9333313 : 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 9333313 : 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 9333313 : predelay_block( hReverb, tmp1, tmp0 );
1570 :
1571 9333313 : reverb_block( hReverb, tmp0, tmp1, tmp2 );
1572 :
1573 9333313 : if ( mix_signals )
1574 : {
1575 2305047 : 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 7028266 : mvr2r( tmp1, &pcm_out[0][i_ts * hReverb->full_block_size], hReverb->full_block_size );
1580 7028266 : mvr2r( tmp2, &pcm_out[1][i_ts * hReverb->full_block_size], hReverb->full_block_size );
1581 : }
1582 :
1583 9333313 : return IVAS_ERR_OK;
1584 : }
1585 :
1586 :
1587 : /*-------------------------------------------------------------------------
1588 : * ivas_binaural_reverb_processSubFrame()
1589 : *
1590 : * Compute the reverberation - room effect
1591 : *------------------------------------------------------------------------*/
1592 :
1593 3786680 : 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 3786680 : 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 159625390 : 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 155838710 : mvr2r( hReverb->loopBufReal[bin], hReverb->loopBufReal[bin] + numSlots, hReverb->loopBufLength[bin] );
1615 155838710 : 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 155838710 : v_multc( hReverb->loopBufReal[bin] + hReverb->loopBufLength[bin], hReverb->loopAttenuationFactor[bin], hReverb->loopBufReal[bin], numSlots );
1621 155838710 : 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 3786680 : idx = hReverb->preDelayBufferIndex;
1626 18925030 : for ( sample = 0; sample < numSlots; sample++ )
1627 : {
1628 15138350 : invertSampleIndex = numSlots - sample - 1;
1629 :
1630 638037850 : 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 622899500 : hReverb->loopBufReal[bin][invertSampleIndex] += hReverb->preDelayBufferReal[idx][bin] * hReverb->reverbEqGains[bin];
1635 622899500 : hReverb->loopBufImag[bin][invertSampleIndex] += hReverb->preDelayBufferImag[idx][bin] * hReverb->reverbEqGains[bin];
1636 622899500 : hReverb->preDelayBufferReal[idx][bin] = 0.0f;
1637 622899500 : 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 48200490 : for ( ch = 0; ch < numInChannels; ch++ )
1643 : {
1644 33062140 : if ( ch % 2 )
1645 : {
1646 15995438 : v_add( hReverb->preDelayBufferReal[idx], inReal[ch][sample], hReverb->preDelayBufferReal[idx], hReverb->numBins );
1647 15995438 : v_add( hReverb->preDelayBufferImag[idx], inImag[ch][sample], hReverb->preDelayBufferImag[idx], hReverb->numBins );
1648 : }
1649 : else
1650 : {
1651 17066702 : v_sub( hReverb->preDelayBufferReal[idx], inImag[ch][sample], hReverb->preDelayBufferReal[idx], hReverb->numBins );
1652 17066702 : v_add( hReverb->preDelayBufferImag[idx], inReal[ch][sample], hReverb->preDelayBufferImag[idx], hReverb->numBins );
1653 : }
1654 : }
1655 15138350 : idx = ( idx + 1 ) % hReverb->preDelayBufferLength;
1656 : }
1657 3786680 : hReverb->preDelayBufferIndex = idx;
1658 :
1659 : /* 3) Perform the filtering/decorrelating, using complex and sparse FIR filtering */
1660 159625390 : for ( bin = 0; bin < hReverb->numBins; bin++ )
1661 : {
1662 467516130 : 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 311677420 : tapRealPr = hReverb->tapPointersReal[bin][ch];
1666 311677420 : tapImagPr = hReverb->tapPointersImag[bin][ch];
1667 :
1668 311677420 : phaseShiftTypePr = hReverb->tapPhaseShiftType[bin][ch];
1669 :
1670 : /* Flush output */
1671 311677420 : set_f( hReverb->outputBufferReal[bin][ch], 0.0f, numSlots );
1672 311677420 : set_f( hReverb->outputBufferImag[bin][ch], 0.0f, numSlots );
1673 :
1674 : /* Add from temporally decaying sparse tap locations the audio to the output. */
1675 5403554372 : for ( tapIdx = 0; tapIdx < hReverb->taps[bin][ch]; tapIdx++ )
1676 : {
1677 5091876952 : switch ( phaseShiftTypePr[tapIdx] )
1678 : {
1679 1228097810 : case 0: /* 0 degrees phase */
1680 1228097810 : v_add( hReverb->outputBufferReal[bin][ch], tapRealPr[tapIdx], hReverb->outputBufferReal[bin][ch], numSlots );
1681 1228097810 : v_add( hReverb->outputBufferImag[bin][ch], tapImagPr[tapIdx], hReverb->outputBufferImag[bin][ch], numSlots );
1682 1228097810 : break;
1683 1350403720 : case 1: /* 90 degrees phase */
1684 1350403720 : v_sub( hReverb->outputBufferReal[bin][ch], tapImagPr[tapIdx], hReverb->outputBufferReal[bin][ch], numSlots );
1685 1350403720 : v_add( hReverb->outputBufferImag[bin][ch], tapRealPr[tapIdx], hReverb->outputBufferImag[bin][ch], numSlots );
1686 1350403720 : break;
1687 1274621675 : case 2: /* 180 degrees phase */
1688 1274621675 : v_sub( hReverb->outputBufferReal[bin][ch], tapRealPr[tapIdx], hReverb->outputBufferReal[bin][ch], numSlots );
1689 1274621675 : v_sub( hReverb->outputBufferImag[bin][ch], tapImagPr[tapIdx], hReverb->outputBufferImag[bin][ch], numSlots );
1690 1274621675 : break;
1691 1238753747 : default: /* 270 degrees phase */
1692 1238753747 : v_add( hReverb->outputBufferReal[bin][ch], tapImagPr[tapIdx], hReverb->outputBufferReal[bin][ch], numSlots );
1693 1238753747 : v_sub( hReverb->outputBufferImag[bin][ch], tapRealPr[tapIdx], hReverb->outputBufferImag[bin][ch], numSlots );
1694 1238753747 : break;
1695 : }
1696 : }
1697 : }
1698 :
1699 : /* Generate diffuse field binaural coherence by mixing the incoherent reverberated channels with pre-defined gains */
1700 155838710 : if ( bin <= hReverb->highestBinauralCoherenceBin )
1701 : {
1702 26075431 : if ( hReverb->useBinauralCoherence )
1703 : {
1704 130320005 : for ( sample = 0; sample < numSlots; sample++ )
1705 : {
1706 : float leftRe, rightRe, leftIm, rightIm;
1707 :
1708 104244574 : leftRe = hReverb->binauralCoherenceDirectGains[bin] * hReverb->outputBufferReal[bin][0][sample] + hReverb->binauralCoherenceCrossmixGains[bin] * hReverb->outputBufferReal[bin][1][sample];
1709 104244574 : rightRe = hReverb->binauralCoherenceDirectGains[bin] * hReverb->outputBufferReal[bin][1][sample] + hReverb->binauralCoherenceCrossmixGains[bin] * hReverb->outputBufferReal[bin][0][sample];
1710 104244574 : leftIm = hReverb->binauralCoherenceDirectGains[bin] * hReverb->outputBufferImag[bin][0][sample] + hReverb->binauralCoherenceCrossmixGains[bin] * hReverb->outputBufferImag[bin][1][sample];
1711 104244574 : rightIm = hReverb->binauralCoherenceDirectGains[bin] * hReverb->outputBufferImag[bin][1][sample] + hReverb->binauralCoherenceCrossmixGains[bin] * hReverb->outputBufferImag[bin][0][sample];
1712 :
1713 104244574 : hReverb->outputBufferReal[bin][0][sample] = leftRe;
1714 104244574 : hReverb->outputBufferReal[bin][1][sample] = rightRe;
1715 104244574 : hReverb->outputBufferImag[bin][0][sample] = leftIm;
1716 104244574 : hReverb->outputBufferImag[bin][1][sample] = rightIm;
1717 : }
1718 : }
1719 : }
1720 : }
1721 :
1722 : /* 4) Write data to output */
1723 11360040 : for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
1724 : {
1725 37850060 : for ( sample = 0; sample < numSlots; sample++ )
1726 : {
1727 : /* Audio was in the temporally inverted order for convolution, re-invert audio to output */
1728 30276700 : invertSampleIndex = numSlots - sample - 1;
1729 :
1730 1276075700 : for ( bin = 0; bin < hReverb->numBins; bin++ )
1731 : {
1732 1245799000 : outReal[ch][sample][bin] = hReverb->outputBufferReal[bin][ch][invertSampleIndex];
1733 1245799000 : outImag[ch][sample][bin] = hReverb->outputBufferImag[bin][ch][invertSampleIndex];
1734 : }
1735 601079700 : for ( ; bin < CLDFB_NO_CHANNELS_MAX; bin++ )
1736 : {
1737 570803000 : outReal[ch][sample][bin] = 0.0f;
1738 570803000 : outImag[ch][sample][bin] = 0.0f;
1739 : }
1740 : }
1741 : }
1742 :
1743 3786680 : pop_wmops();
1744 3786680 : return;
1745 : }
1746 :
1747 :
1748 : /*-------------------------------------------------------------------------
1749 : * ivas_binaural_reverb_open()
1750 : *
1751 : * Allocate and initialize binaural room reverberator handle
1752 : *------------------------------------------------------------------------*/
1753 :
1754 16075 : 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 16075 : 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 16075 : hReverb = *hReverbPr;
1773 :
1774 16075 : hReverb->useBinauralCoherence = 1;
1775 16075 : hReverb->preDelayBufferLength = 1;
1776 16075 : hReverb->preDelayBufferIndex = 0;
1777 :
1778 16075 : hReverb->numBins = numBins;
1779 16075 : hReverb->blockSize = numCldfbSlotsPerFrame;
1780 :
1781 353650 : for ( k = 0; k < IVAS_REVERB_PREDELAY_MAX + 1; k++ )
1782 : {
1783 337575 : set_f( hReverb->preDelayBufferReal[k], 0.0f, hReverb->numBins );
1784 337575 : set_f( hReverb->preDelayBufferImag[k], 0.0f, hReverb->numBins );
1785 : }
1786 :
1787 644595 : for ( bin = 0; bin < hReverb->numBins; bin++ )
1788 : {
1789 : /* Loop Buffer */
1790 628520 : hReverb->loopBufLengthMax[bin] = (int16_t) ( 500 / ( 1 + bin ) + ( CLDFB_NO_CHANNELS_MAX - bin ) );
1791 :
1792 628520 : len = hReverb->loopBufLengthMax[bin] + hReverb->blockSize;
1793 628520 : 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 628520 : 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 628520 : set_f( hReverb->loopBufReal[bin], 0.0f, len );
1804 628520 : 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 628520 : hReverb->loopBufLength[bin] = (int16_t) ( 1.45 * (int16_t) ( revTimes[bin] * 150.0 ) + 1 );
1810 628520 : hReverb->loopBufLength[bin] = min( hReverb->loopBufLength[bin], hReverb->loopBufLengthMax[bin] );
1811 :
1812 : /* Sparse Filter Tap Locations */
1813 1885560 : for ( chIdx = 0; chIdx < BINAURAL_CHANNELS; chIdx++ )
1814 : {
1815 1257040 : len = hReverb->loopBufLength[bin];
1816 :
1817 1257040 : 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 1257040 : set_s( hReverb->tapPhaseShiftType[bin][chIdx], 0, len );
1822 :
1823 1257040 : 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 1257040 : 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 1257040 : len = hReverb->blockSize;
1834 1257040 : 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 1257040 : 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 1257040 : set_f( hReverb->outputBufferReal[bin][chIdx], 0.0f, len );
1845 1257040 : set_f( hReverb->outputBufferImag[bin][chIdx], 0.0f, len );
1846 : }
1847 : }
1848 :
1849 16075 : ivas_binaural_reverb_setReverbTimes( hReverb, sampling_rate, revTimes, revEnes );
1850 :
1851 16075 : ivas_binaural_reverb_setPreDelay( hReverb, preDelay );
1852 :
1853 16075 : 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 16075 : 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 16075 : if ( roomAcoustics != NULL )
1881 : {
1882 8198 : 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 8198 : preDelay = (int16_t) roundf( roomAcoustics->acousticPreDelay * CLDFB_SLOTS_PER_SECOND );
1889 : }
1890 : else
1891 : {
1892 321947 : for ( bin = 0; bin < numBins; bin++ )
1893 : {
1894 314070 : revTimes[bin] = defaultTimes[bin];
1895 314070 : revEne[bin] = defaultEne[bin];
1896 : }
1897 7877 : preDelay = 10;
1898 : }
1899 :
1900 644595 : 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 628520 : 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 225932 : revTimeModifier = fmaxf( 0.0f, 1.0f - ( revTimes[bin] / REV_TIME_THRESHOLD ) );
1911 225932 : adjustedRevTime = ( 1.0f - revTimeModifier ) * revTimes[bin];
1912 225932 : adjustedRevTime += revTimeModifier * ( revTimes[bin] + REV_TIME_THRESHOLD ) * 0.5f;
1913 225932 : energyModifier = ( adjustedRevTime - revTimes[bin] ) / adjustedRevTime;
1914 :
1915 : /* Adjust early and late energies, by moving late energy to early energy */
1916 225932 : if ( earlyEne != NULL )
1917 : {
1918 175151 : adjustedEarlyEne = earlyEne[bin] + revEne[bin] * energyModifier;
1919 175151 : earlyEne[bin] = adjustedEarlyEne; /* Store already here */
1920 : }
1921 :
1922 225932 : adjustedLateEne = revEne[bin] * ( 1.0f - energyModifier );
1923 :
1924 : /* Store adjusted room effect parameters to be used in reverb processing */
1925 225932 : revTimes[bin] = adjustedRevTime;
1926 225932 : revEne[bin] = adjustedLateEne;
1927 : }
1928 : }
1929 :
1930 16075 : error = ivas_binaural_reverb_open( hReverbPr, numBins, numCldfbSlotsPerFrame, sampling_rate, revTimes, revEne, preDelay );
1931 :
1932 16075 : return error;
1933 : }
1934 :
1935 :
1936 : /*-------------------------------------------------------------------------
1937 : * ivas_binaural_reverb_close()
1938 : *
1939 : * Close binaural room reverberator handle
1940 : *------------------------------------------------------------------------*/
1941 :
1942 16075 : void ivas_binaural_reverb_close(
1943 : REVERB_STRUCT_HANDLE *hReverb /* i/o: binaural reverb handle */
1944 : )
1945 : {
1946 : int16_t bin, chIdx;
1947 :
1948 16075 : if ( hReverb == NULL || *hReverb == NULL )
1949 : {
1950 0 : return;
1951 : }
1952 :
1953 644595 : for ( bin = 0; bin < ( *hReverb )->numBins; bin++ )
1954 : {
1955 1885560 : for ( chIdx = 0; chIdx < BINAURAL_CHANNELS; chIdx++ )
1956 : {
1957 1257040 : free( ( *hReverb )->tapPhaseShiftType[bin][chIdx] );
1958 1257040 : free( ( *hReverb )->tapPointersReal[bin][chIdx] );
1959 1257040 : free( ( *hReverb )->tapPointersImag[bin][chIdx] );
1960 1257040 : free( ( *hReverb )->outputBufferReal[bin][chIdx] );
1961 1257040 : free( ( *hReverb )->outputBufferImag[bin][chIdx] );
1962 : }
1963 628520 : free( ( *hReverb )->loopBufReal[bin] );
1964 628520 : free( ( *hReverb )->loopBufImag[bin] );
1965 : }
1966 :
1967 16075 : free( ( *hReverb ) );
1968 16075 : ( *hReverb ) = NULL;
1969 :
1970 16075 : return;
1971 : }
|