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 "options.h"
34 : #include <stdint.h>
35 : #include <math.h>
36 : #include "prot.h"
37 : #include "rom_dec.h"
38 : #include "lib_rend.h"
39 : #include "ivas_prot_rend.h"
40 : #include "ivas_stat_rend.h"
41 : #include "ivas_cnst.h"
42 : #include "ivas_prot.h"
43 : #include "ivas_rom_com.h"
44 : #include "wmc_auto.h"
45 : #ifdef DEBUGGING
46 : #include "debug.h"
47 : #endif
48 :
49 :
50 : /*-----------------------------------------------------------------------------------------*
51 : * Local constants/tabels
52 : *-----------------------------------------------------------------------------------------*/
53 :
54 : #define ER_NUM_REF 6
55 :
56 : static uint16_t LC_mixing_5_1[5] = { 0, 1, 2, 0, 1 };
57 :
58 : static uint16_t LC_mixing_7_1[7] = { 0, 1, 2, 3, 4, 3, 4 };
59 :
60 : static uint16_t LC_mixing_5_1_2[7] = { 0, 1, 2, 3, 4, 0, 1 };
61 :
62 : static uint16_t LC_mixing_5_1_4[9] = { 0, 1, 2, 3, 4, 0, 1, 3, 4 };
63 :
64 : static uint16_t LC_mixing_7_1_4[11] = { 0, 1, 2, 3, 4, 3, 4, 0, 1, 3, 4 };
65 :
66 : /*-----------------------------------------------------------------------------------------*
67 : * Function ivas_er_init()
68 : *
69 : * Initializes the reflections data structure according to the requested input config.
70 : *-----------------------------------------------------------------------------------------*/
71 :
72 12 : ivas_error ivas_er_init(
73 : er_struct_t *reflections,
74 : const AUDIO_CONFIG inConfig )
75 : {
76 : ivas_error error;
77 : uint8_t i;
78 :
79 : /* Set to defaults for shoebox */
80 12 : reflections->is_ready = 0;
81 12 : reflections->audio_config = IVAS_AUDIO_CONFIG_INVALID;
82 12 : reflections->is_cartesian = 0;
83 12 : reflections->is_relative = 1;
84 12 : reflections->shoebox_data.n_ref = ER_NUM_REF;
85 12 : reflections->user_origin[0] = 0.0f;
86 12 : reflections->user_origin[1] = 0.0f;
87 12 : reflections->user_origin[2] = ER_LIST_HEIGHT;
88 :
89 : /* Store scene origin if present */
90 48 : for ( i = 0; i < 3; i++ )
91 : {
92 36 : reflections->user_origin[i] = reflections->shoebox_lib.cal.list_orig[i];
93 : }
94 :
95 : /* Init Shoebox */
96 12 : ivas_shoebox_init( &reflections->shoebox_lib, &reflections->shoebox_lib.cal );
97 :
98 : /* Set mode */
99 12 : if ( ( error = ivas_er_set_reflections_mode( reflections, inConfig ) ) != IVAS_ERR_OK )
100 : {
101 0 : return error;
102 : }
103 :
104 : /* Compute the static reflections (first frame) */
105 12 : if ( ( error = ivas_er_compute_reflections( reflections ) ) != IVAS_ERR_OK )
106 : {
107 0 : return error;
108 : }
109 :
110 12 : if ( ( reflections->closest_ch_idx = (uint16_t *) malloc( reflections->n_total_reflections * sizeof( uint16_t ) ) ) == NULL )
111 : {
112 0 : return IVAS_ERR_FAILED_ALLOC;
113 : }
114 12 : set_s( (int16_t *) reflections->closest_ch_idx, 0, reflections->n_total_reflections );
115 :
116 12 : if ( ( error = getAudioConfigNumChannels( reflections->audio_config, &( reflections->nchan_out ) ) ) != IVAS_ERR_OK )
117 : {
118 0 : return error;
119 : }
120 :
121 : /* Initialize Encoder */
122 12 : if ( ( error = ivas_er_encoder_init( reflections ) ) != IVAS_ERR_OK )
123 : {
124 0 : return error;
125 : }
126 :
127 : /* Update flag to indicate that reflection module is ready to process */
128 12 : reflections->is_ready = 1;
129 :
130 12 : return error;
131 : }
132 :
133 :
134 : /*-----------------------------------------------------------------------------------------*
135 : Function ivas_er_set_reflections_mode()
136 :
137 : Function sets the ER source positions based on the audio config
138 : *-----------------------------------------------------------------------------------------*/
139 :
140 12 : ivas_error ivas_er_set_reflections_mode(
141 : er_struct_t *reflections,
142 : const AUDIO_CONFIG inConfig )
143 : {
144 : ivas_error error;
145 : uint16_t ch;
146 12 : error = IVAS_ERR_OK;
147 :
148 12 : if ( reflections->audio_config == inConfig )
149 : {
150 0 : return error;
151 : }
152 :
153 12 : reflections->is_ready = 0;
154 12 : reflections->audio_config = inConfig;
155 :
156 12 : switch ( reflections->audio_config )
157 : {
158 0 : case IVAS_AUDIO_CONFIG_MONO:
159 0 : reflections->shoebox_data.n_sources = 1;
160 0 : reflections->n_LC_sources = 1;
161 0 : reflections->LC_mixing = LC_mixing_5_1;
162 0 : reflections->source_positions[0] = 0;
163 0 : reflections->source_positions[1] = 0;
164 0 : reflections->source_positions[2] = ER_RADIUS;
165 0 : break;
166 0 : case IVAS_AUDIO_CONFIG_STEREO:
167 0 : reflections->shoebox_data.n_sources = 2;
168 0 : reflections->n_LC_sources = 2;
169 0 : reflections->LC_mixing = LC_mixing_5_1;
170 0 : for ( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
171 : {
172 0 : reflections->source_positions[3 * ch] = deg2rad( ls_azimuth_CICP2[ch] );
173 0 : reflections->source_positions[1 + ( 3 * ch )] = deg2rad( ls_elevation_CICP2[ch] );
174 0 : reflections->source_positions[2 + ( 3 * ch )] = ER_RADIUS;
175 : }
176 0 : break;
177 3 : case IVAS_AUDIO_CONFIG_5_1:
178 3 : reflections->shoebox_data.n_sources = 5;
179 3 : reflections->n_LC_sources = 3;
180 3 : reflections->LC_mixing = LC_mixing_5_1;
181 18 : for ( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
182 : {
183 15 : reflections->source_positions[3 * ch] = deg2rad( ls_azimuth_CICP6[ch] );
184 15 : reflections->source_positions[1 + ( 3 * ch )] = deg2rad( ls_elevation_CICP6[ch] );
185 15 : reflections->source_positions[2 + ( 3 * ch )] = ER_RADIUS;
186 : }
187 3 : break;
188 0 : case IVAS_AUDIO_CONFIG_7_1:
189 0 : reflections->shoebox_data.n_sources = 7;
190 0 : reflections->n_LC_sources = 5;
191 0 : reflections->LC_mixing = LC_mixing_7_1;
192 0 : for ( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
193 : {
194 0 : reflections->source_positions[3 * ch] = deg2rad( ls_azimuth_CICP12[ch] );
195 0 : reflections->source_positions[1 + ( 3 * ch )] = deg2rad( ls_elevation_CICP12[ch] );
196 0 : reflections->source_positions[2 + ( 3 * ch )] = ER_RADIUS;
197 : }
198 0 : break;
199 0 : case IVAS_AUDIO_CONFIG_5_1_2:
200 0 : reflections->shoebox_data.n_sources = 7;
201 0 : reflections->n_LC_sources = 5;
202 0 : reflections->LC_mixing = LC_mixing_5_1_2;
203 0 : for ( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
204 : {
205 0 : reflections->source_positions[3 * ch] = deg2rad( ls_azimuth_CICP14[ch] );
206 0 : reflections->source_positions[1 + ( 3 * ch )] = deg2rad( ls_elevation_CICP14[ch] );
207 0 : reflections->source_positions[2 + ( 3 * ch )] = ER_RADIUS;
208 : }
209 0 : break;
210 0 : case IVAS_AUDIO_CONFIG_5_1_4:
211 0 : reflections->shoebox_data.n_sources = 9;
212 0 : reflections->n_LC_sources = 5;
213 0 : reflections->LC_mixing = LC_mixing_5_1_4;
214 0 : for ( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
215 : {
216 0 : reflections->source_positions[3 * ch] = deg2rad( ls_azimuth_CICP16[ch] );
217 0 : reflections->source_positions[1 + ( 3 * ch )] = deg2rad( ls_elevation_CICP16[ch] );
218 0 : reflections->source_positions[2 + ( 3 * ch )] = ER_RADIUS;
219 : }
220 0 : break;
221 9 : case IVAS_AUDIO_CONFIG_7_1_4:
222 9 : reflections->shoebox_data.n_sources = 11;
223 9 : reflections->n_LC_sources = 5;
224 9 : reflections->LC_mixing = LC_mixing_7_1_4;
225 108 : for ( ch = 0; ch < reflections->shoebox_data.n_sources; ch++ )
226 : {
227 99 : reflections->source_positions[3 * ch] = deg2rad( ls_azimuth_CICP19[ch] );
228 99 : reflections->source_positions[1 + ( 3 * ch )] = deg2rad( ls_elevation_CICP19[ch] );
229 99 : reflections->source_positions[2 + ( 3 * ch )] = ER_RADIUS;
230 : }
231 9 : break;
232 0 : case IVAS_AUDIO_CONFIG_HOA3:
233 0 : reflections->use_er = 0;
234 0 : break;
235 0 : case IVAS_AUDIO_CONFIG_HOA2:
236 0 : reflections->use_er = 0;
237 0 : break;
238 0 : case IVAS_AUDIO_CONFIG_FOA:
239 0 : reflections->use_er = 0;
240 0 : break;
241 0 : default:
242 0 : reflections->audio_config = IVAS_AUDIO_CONFIG_INVALID;
243 0 : return IVAS_ERROR( IVAS_ERR_INVALID_ER_PARAM, "Unsupported reflections mode" );
244 : }
245 :
246 12 : return error;
247 : }
248 :
249 :
250 : /*-----------------------------------------------------------------------------------------*
251 : Function ivas_er_encoder_init()
252 :
253 : Function that initializes the er encoder
254 : *-----------------------------------------------------------------------------------------*/
255 :
256 12 : ivas_error ivas_er_encoder_init(
257 : er_struct_t *reflections )
258 : {
259 12 : ivas_error error = IVAS_ERR_OK;
260 : uint16_t i, j, src_idx;
261 12 : uint16_t min_index = 0;
262 : float p_x, p_y, p_z;
263 : float p_x_src, p_y_src, p_z_src;
264 : float tmp;
265 12 : float dist, min_dist = 0;
266 :
267 12 : if ( !reflections )
268 : {
269 0 : return IVAS_ERR_FAILED_ALLOC;
270 : }
271 :
272 12 : if ( getAudioConfigType( reflections->audio_config ) == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
273 : {
274 : /* Compute MC-snap location (closest channel position to reflection direction) */
275 696 : for ( i = 0; i < reflections->n_total_reflections; i++ )
276 : {
277 : /* Compute cartesian points for reflection (from degrees) */
278 684 : p_x = ER_RADIUS * ( cosf( deg2rad( reflections->shoebox_data.el_angle.data[i] ) ) * cosf( deg2rad( reflections->shoebox_data.az_angle.data[i] ) ) );
279 684 : p_y = ER_RADIUS * ( cosf( deg2rad( reflections->shoebox_data.el_angle.data[i] ) ) * sinf( deg2rad( reflections->shoebox_data.az_angle.data[i] ) ) );
280 684 : p_z = ER_RADIUS * ( sinf( deg2rad( reflections->shoebox_data.el_angle.data[i] ) ) );
281 :
282 : /* Calculate the euclidean distance to each point in the config ls setup */
283 8352 : for ( j = 0; j < reflections->nchan_out; j++ )
284 : {
285 : /* Ignore LFE */
286 7668 : if ( j != LFE_CHANNEL )
287 : {
288 6984 : src_idx = ( j > LFE_CHANNEL ) ? j - 1 : j;
289 :
290 6984 : p_x_src = reflections->source_positions[src_idx * 3 + 2] * ( cosf( reflections->source_positions[src_idx * 3 + 1] ) * cosf( reflections->source_positions[src_idx * 3] ) );
291 6984 : p_y_src = reflections->source_positions[src_idx * 3 + 2] * ( cosf( reflections->source_positions[src_idx * 3 + 1] ) * sinf( reflections->source_positions[src_idx * 3] ) );
292 6984 : p_z_src = reflections->source_positions[src_idx * 3 + 2] * sinf( reflections->source_positions[src_idx * 3 + 1] );
293 :
294 6984 : tmp = ( p_x_src - p_x ) * ( p_x_src - p_x );
295 6984 : tmp += ( p_y_src - p_y ) * ( p_y_src - p_y );
296 6984 : tmp += ( p_z_src - p_z ) * ( p_z_src - p_z );
297 6984 : dist = sqrtf( tmp );
298 :
299 : /* Save index of closest channel */
300 6984 : if ( src_idx == 0 )
301 : {
302 684 : min_dist = dist;
303 684 : min_index = j;
304 : }
305 : else
306 : {
307 6300 : if ( dist < min_dist )
308 : {
309 1356 : min_dist = dist;
310 1356 : min_index = j;
311 : }
312 : }
313 : }
314 : }
315 :
316 684 : reflections->closest_ch_idx[i] = (uint16_t) min_index;
317 : }
318 : }
319 :
320 12 : return error;
321 : }
322 :
323 :
324 : /*-----------------------------------------------------------------------------------------*
325 : Function ivas_er_compute_reflections()
326 :
327 : Function computes reflections using the shoebox library and sets up the circular buffers
328 : structure for the early reflections process
329 : *-----------------------------------------------------------------------------------------*/
330 :
331 12 : ivas_error ivas_er_compute_reflections(
332 : er_struct_t *reflections )
333 : {
334 12 : ivas_error error = IVAS_ERR_OK;
335 : uint16_t circ_len, i, j;
336 : float tmp;
337 :
338 12 : reflections->is_ready = 0;
339 :
340 : /* Disabled case */
341 12 : if ( reflections->audio_config == IVAS_AUDIO_CONFIG_INVALID )
342 : {
343 0 : return error;
344 : }
345 :
346 : /* Run shoebox with current reflection parameters */
347 12 : ivas_shoebox_set_scene( &( reflections->shoebox_lib ), &( reflections->shoebox_data ), reflections->shoebox_lib.cal.list_orig,
348 12 : reflections->source_positions, reflections->is_cartesian, reflections->is_relative );
349 :
350 : /* Convert reflection times in seconds to samples and keep track of max */
351 12 : circ_len = 0;
352 126 : for ( i = 0; i < reflections->shoebox_data.n_sources; i++ )
353 : {
354 798 : for ( j = 0; j < reflections->shoebox_data.n_ref; j++ )
355 : {
356 684 : tmp = reflections->shoebox_data.times.data[j + ( i * reflections->shoebox_data.n_ref )];
357 684 : tmp = roundf( tmp * reflections->output_Fs );
358 684 : reflections->shoebox_data.times.data[j + ( i * reflections->shoebox_data.n_ref )] = tmp;
359 684 : circ_len = ( (uint16_t) tmp > circ_len ) ? (uint16_t) tmp : circ_len;
360 : }
361 : }
362 :
363 : /* If max delay is less than max frame size, use max frame size to compute circ buffer length */
364 12 : circ_len = ( circ_len > (uint16_t) reflections->max_frame_size ) ? circ_len : (uint16_t) reflections->max_frame_size;
365 12 : circ_len += (uint16_t) reflections->max_frame_size;
366 :
367 : /* If circ buffers exist and size is the same, reset memory to all zeros */
368 : /* If size is different, reallocate circ buffers */
369 : /* Otherwise allocate new circ buffers */
370 12 : if ( reflections->circ_buffers )
371 : {
372 0 : if ( reflections->circ_len == circ_len )
373 : {
374 : /* circ buffers exist and size is the same */
375 0 : set_f( reflections->circ_buffers, 0.0f, reflections->shoebox_data.n_sources * reflections->circ_len );
376 : }
377 : else
378 : {
379 : /* circ buffers exist but size is different */
380 0 : reflections->circ_len = circ_len;
381 0 : free( reflections->circ_buffers );
382 0 : if ( ( reflections->circ_buffers = (float *) malloc( reflections->shoebox_data.n_sources * reflections->circ_len * sizeof( float ) ) ) == NULL )
383 : {
384 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Early Reflections buffers" );
385 : }
386 0 : set_f( reflections->circ_buffers, 0.0f, reflections->shoebox_data.n_sources * reflections->circ_len );
387 : }
388 : }
389 : else
390 : {
391 : /* circ buffers do not exist */
392 12 : reflections->circ_len = circ_len;
393 12 : if ( ( reflections->circ_buffers = (float *) malloc( reflections->shoebox_data.n_sources * reflections->circ_len * sizeof( float ) ) ) == NULL )
394 : {
395 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Early Reflections buffers" );
396 : }
397 12 : set_f( reflections->circ_buffers, 0.0f, reflections->shoebox_data.n_sources * reflections->circ_len );
398 : }
399 :
400 :
401 : /* Initialize circular buffer insertion point */
402 12 : reflections->circ_insert = reflections->circ_len - (uint16_t) reflections->max_frame_size;
403 :
404 : /* Get total reflections number */
405 12 : reflections->n_total_reflections = reflections->shoebox_data.n_sources * reflections->shoebox_data.n_ref;
406 :
407 : /* Check that reflection buffers were allocated */
408 12 : if ( error != IVAS_ERR_OK )
409 : {
410 0 : return error;
411 : }
412 :
413 12 : return error;
414 : }
415 :
416 :
417 : /*-----------------------------------------------------------------------------------------*
418 : Function ivas_er_process()
419 :
420 : Takes a buffer of N channels, returns a buffer of N*6 channels containing the early
421 : reflections (one per wall). The process is a delay line architecture
422 : *-----------------------------------------------------------------------------------------*/
423 :
424 :
425 17400 : ivas_error ivas_er_process(
426 : er_struct_t *reflections,
427 : const int16_t subframe_size,
428 : const int16_t subframe_idx,
429 : float **io,
430 : const AUDIO_CONFIG inConfig )
431 : {
432 17400 : ivas_error error = IVAS_ERR_OK;
433 : uint16_t i, j, k, subframe_offset;
434 : uint16_t ref_no, ref_delay;
435 : uint16_t n_ref_sources, n_ref;
436 : int16_t samp_idx, in_ch_idx, buf_ch_idx, ref_out_idx;
437 : float ref_gain;
438 : float *buffer_ch;
439 :
440 17400 : if ( !reflections )
441 : {
442 0 : return IVAS_ERR_INIT_ERROR;
443 : }
444 :
445 : /* should not arrive here if reflections are disabled but in case it does just do nothing */
446 17400 : if ( reflections->use_er != 1 )
447 : {
448 0 : return error;
449 : }
450 :
451 : /* Ensure all reflection memory is allocated */
452 17400 : if ( !reflections->circ_buffers || !reflections->is_ready )
453 : {
454 0 : return IVAS_ERR_INIT_ERROR;
455 : }
456 :
457 17400 : subframe_offset = subframe_idx * subframe_size;
458 17400 : n_ref = reflections->shoebox_data.n_ref;
459 :
460 : /* If low complexity ER are requested only compute ER for n_LC_sources */
461 17400 : if ( reflections->lowComplexity )
462 : {
463 13800 : n_ref_sources = reflections->n_LC_sources;
464 : }
465 : else
466 : {
467 3600 : n_ref_sources = reflections->shoebox_data.n_sources;
468 : }
469 :
470 : /* Channel case, copy input into buffers panning for LC mode and skipping LFE */
471 17400 : if ( getAudioConfigType( inConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
472 : {
473 : /* Loop through all input sources filling circular buffers */
474 136800 : for ( i = 0; i < reflections->shoebox_data.n_sources; i++ )
475 : {
476 : /* Pull correct circular buffer depending on complexity mode */
477 119400 : buf_ch_idx = ( reflections->lowComplexity == 1 ) ? reflections->LC_mixing[i] : i;
478 119400 : buffer_ch = &( reflections->circ_buffers[buf_ch_idx * reflections->circ_len] );
479 :
480 : /* Skip LFE from input buffer */
481 119400 : in_ch_idx = ( i >= LFE_CHANNEL ) ? i + 1 : i;
482 119400 : samp_idx = reflections->circ_insert;
483 :
484 : /* If less than number of reflection sources, overwrite buffer */
485 119400 : if ( i == buf_ch_idx )
486 : {
487 20388600 : for ( j = 0; j < subframe_size; j++ )
488 : {
489 20304000 : buffer_ch[samp_idx++] = io[in_ch_idx][j + subframe_offset];
490 20304000 : samp_idx = samp_idx % reflections->circ_len;
491 : }
492 : }
493 : /* Accumulate with buffer for low complexity mixed sources */
494 : else
495 : {
496 8386800 : for ( j = 0; j < subframe_size; j++ )
497 : {
498 8352000 : buffer_ch[samp_idx++] += io[in_ch_idx][j + subframe_offset];
499 8352000 : samp_idx = samp_idx % reflections->circ_len;
500 : }
501 : }
502 : }
503 : }
504 : else
505 : {
506 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
507 : }
508 :
509 : /* Loop through sources retrieve reflections from circ buffers */
510 102000 : for ( i = 0; i < n_ref_sources; i++ )
511 : {
512 : /* Access correct row of input circ buffer */
513 84600 : buffer_ch = &( reflections->circ_buffers[i * reflections->circ_len] );
514 :
515 : /* Loop through reflections */
516 592200 : for ( j = 0; j < n_ref; j++ )
517 : {
518 507600 : ref_no = j + ( i * n_ref );
519 507600 : ref_gain = reflections->shoebox_data.gains.data[ref_no];
520 507600 : ref_delay = (uint16_t) reflections->shoebox_data.times.data[ref_no];
521 507600 : ref_out_idx = reflections->closest_ch_idx[ref_no];
522 :
523 : /* Determine start idx of reflection in circ buffer based on
524 : current insert idx and reflection delay */
525 507600 : samp_idx = (int16_t) reflections->circ_insert - ref_delay;
526 507600 : if ( samp_idx < 0 )
527 : {
528 159609 : samp_idx = (int16_t) reflections->circ_len + samp_idx;
529 : }
530 :
531 : /* Pull reflection from circ buffer and apply gain */
532 122331600 : for ( k = 0; k < subframe_size; k++ )
533 : {
534 121824000 : io[ref_out_idx][k + subframe_offset] += buffer_ch[samp_idx++] * ref_gain;
535 121824000 : samp_idx = samp_idx % reflections->circ_len;
536 : }
537 : }
538 : }
539 :
540 : /* Increment circular buffer start index */
541 17400 : reflections->circ_insert = ( reflections->circ_insert + subframe_size ) % reflections->circ_len;
542 :
543 17400 : return error;
544 : }
|