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