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 "ivas_stat_rend.h"
34 : #include <stdint.h>
35 : #include "options.h"
36 : #include "prot_fx.h"
37 : #include "ivas_prot_rend_fx.h"
38 : #include <math.h>
39 : #include "ivas_rom_com.h"
40 : #include "wmc_auto.h"
41 : #include "ivas_prot_fx.h"
42 : #include "debug.h"
43 : #include "ivas_rom_com_fx.h"
44 : #define float_to_fixed( n, factor ) ( round( n * ( 1 << factor ) ) )
45 : #define fixed_to_float( n, factor ) ( (float) n / ( 1 << factor ) )
46 :
47 : /*---------------------------------------------------------------------*
48 : * Local function prototypes
49 : *---------------------------------------------------------------------*/
50 :
51 :
52 : static void TDREND_Clear_Update_flags_fx(
53 : BINAURAL_TD_OBJECT_RENDERER_HANDLE hBinRendererTd /* i/o: TD renderer handle */
54 : );
55 :
56 :
57 : static void angles_to_vec_fx(
58 : const Word16 radius, /* i : radius */
59 : const Word32 azimuth, /* i : Azimuth angle */
60 : const Word32 elevation, /* i : Elevation angle */
61 : Word32 *vec /* o : Pos/Dir vector */
62 : );
63 :
64 : /*---------------------------------------------------------------------*
65 : * ivas_td_binaural_open_unwrap()
66 : *
67 : * Call TD open/init function without st_ivas
68 : *---------------------------------------------------------------------*/
69 :
70 513 : ivas_error ivas_td_binaural_open_unwrap_fx(
71 : TDREND_HRFILT_FiltSet_t **hHrtfTD, /* i/o: HR filter model (from file or NULL) */
72 : const Word32 output_Fs, /* i : Output sampling rate */
73 : const Word16 nchan_transport, /* i : Number of channels */
74 : const IVAS_FORMAT ivas_format, /* i : IVAS format (ISM/MC) */
75 : const AUDIO_CONFIG transport_config, /* i : Transport configuration */
76 : const Word16 *directivity, /* i : Directivity pattern (used for ISM) */
77 : const IVAS_OUTPUT_SETUP hTransSetup, /* i : Loudspeaker layout */
78 : BINAURAL_TD_OBJECT_RENDERER_HANDLE *hBinRendererTd, /* o : TD renderer handle */
79 : Word32 *binaural_latency_ns, /* i : Binauralization delay */
80 : Word16 *SrcInd )
81 : {
82 : BINAURAL_TD_OBJECT_RENDERER_HANDLE pBinRendTd;
83 : TDREND_PosType_t PosType;
84 : Word16 nS;
85 : const Word32 *ls_azimuth_fx, *ls_elevation_fx;
86 : Word32 Pos_fx[3]; // Q25
87 : Word32 Dir_fx[3]; // Q30
88 : TDREND_DirAtten_t *DirAtten_p;
89 : Word16 nchan_rend;
90 : ivas_error error;
91 :
92 513 : error = IVAS_ERR_OK;
93 :
94 513 : IF( ( pBinRendTd = malloc( sizeof( BINAURAL_TD_OBJECT_RENDERER ) ) ) == NULL )
95 : {
96 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for TD renderer\n" ) );
97 : }
98 513 : IF( ( pBinRendTd->TdRend_MixSpatSpec_p = malloc( sizeof( TDREND_MixSpatSpec_t ) ) ) == NULL )
99 : {
100 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for TD renderer\n" ) );
101 : }
102 513 : IF( ( pBinRendTd->DirAtten_p = malloc( sizeof( TDREND_DirAtten_t ) ) ) == NULL )
103 : {
104 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for TD renderer\n" ) );
105 : }
106 513 : IF( ( pBinRendTd->Listener_p = malloc( sizeof( TDREND_MIX_Listener_t ) ) ) == NULL )
107 : {
108 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for TD renderer\n" ) );
109 : }
110 :
111 513 : pBinRendTd->NumOfSrcs = 0;
112 513 : pBinRendTd->MaxSrcInd = -1;
113 :
114 513 : move16();
115 513 : move16();
116 : /* Mixer spatial setup */
117 513 : pBinRendTd->TdRend_MixSpatSpec_p->UseCommonDistAttenModel = TRUE;
118 513 : move16();
119 513 : pBinRendTd->TdRend_MixSpatSpec_p->DistAttenModel = 0; /* 0=Turned off, else use TDREND_DIST_ATTEN_MODEL_INV_DIST_CLAMPED */
120 513 : move16();
121 :
122 513 : IF( NE_32( ( error = TDREND_MIX_Init_fx( pBinRendTd, hHrtfTD, pBinRendTd->TdRend_MixSpatSpec_p, output_Fs ) ), IVAS_ERR_OK ) )
123 : {
124 0 : return error;
125 : }
126 :
127 : /* Set the attenuation (or can set MixSpatSpec.DistAttenModel above) */
128 513 : IF( NE_32( ( error = TDREND_MIX_SetDistAttenModel( pBinRendTd, TDREND_DIST_ATTEN_MODEL_INV_DIST_CLAMPED ) ), IVAS_ERR_OK ) )
129 : {
130 0 : return error;
131 : }
132 :
133 : /* Add sources to module and mixer, headphones */
134 513 : PosType = TDREND_POSTYPE_ABSOLUTE; /* or TDREND_POSTYPE_RELATIVE_TO_LISTENER */
135 513 : move16();
136 513 : nchan_rend = nchan_transport;
137 513 : move16();
138 513 : test();
139 513 : if ( EQ_16( ivas_format, MC_FORMAT ) && NE_16( transport_config, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
140 : {
141 20 : nchan_rend = sub( nchan_rend, 1 ); /* Skip LFE channel -- added to the others */
142 : }
143 :
144 1509 : FOR( nS = 0; nS < nchan_rend; nS++ )
145 : {
146 996 : IF( NE_32( ( error = TDREND_MIX_AddSrc_fx( pBinRendTd, &SrcInd[nS], PosType ) ), IVAS_ERR_OK ) )
147 : {
148 0 : return error;
149 : }
150 : }
151 513 : IF( EQ_16( ivas_format, MC_FORMAT ) )
152 : {
153 44 : SWITCH( transport_config )
154 : {
155 11 : case IVAS_AUDIO_CONFIG_5_1:
156 11 : ls_azimuth_fx = ls_azimuth_CICP6_fx; // Q22
157 11 : ls_elevation_fx = ls_elevation_CICP6_fx; // Q22
158 11 : BREAK;
159 9 : case IVAS_AUDIO_CONFIG_7_1:
160 9 : ls_azimuth_fx = ls_azimuth_CICP12_fx; // Q22
161 9 : ls_elevation_fx = ls_elevation_CICP12_fx; // Q22
162 9 : BREAK;
163 0 : case IVAS_AUDIO_CONFIG_5_1_2:
164 0 : ls_azimuth_fx = ls_azimuth_CICP14_fx; // Q22
165 0 : ls_elevation_fx = ls_elevation_CICP14_fx; // Q22
166 0 : BREAK;
167 0 : case IVAS_AUDIO_CONFIG_5_1_4:
168 0 : ls_azimuth_fx = ls_azimuth_CICP16_fx; // Q22
169 0 : ls_elevation_fx = ls_elevation_CICP16_fx; // Q22
170 0 : BREAK;
171 0 : case IVAS_AUDIO_CONFIG_7_1_4:
172 0 : ls_azimuth_fx = ls_azimuth_CICP19_fx; // Q22
173 0 : ls_elevation_fx = ls_elevation_CICP19_fx; // Q22
174 0 : BREAK;
175 24 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
176 24 : ls_azimuth_fx = hTransSetup.ls_azimuth_fx; // Q22
177 24 : ls_elevation_fx = hTransSetup.ls_elevation_fx; // Q22
178 24 : BREAK;
179 0 : default:
180 0 : ls_azimuth_fx = NULL;
181 0 : ls_elevation_fx = NULL;
182 : }
183 :
184 44 : DirAtten_p = pBinRendTd->DirAtten_p;
185 :
186 318 : FOR( nS = 0; nS < nchan_rend; nS++ )
187 : {
188 : /* Set source positions according to loudspeaker layout */
189 274 : angles_to_vec_fx( ONE_IN_Q9, ls_azimuth_fx[nS], ls_elevation_fx[nS], Pos_fx );
190 :
191 274 : Dir_fx[0] = ONE_IN_Q30;
192 274 : move32();
193 274 : Dir_fx[1] = 0;
194 274 : move32();
195 274 : Dir_fx[2] = 0;
196 274 : move32();
197 : /* Source directivity info */
198 274 : DirAtten_p->ConeInnerAngle_fx = DEG_360_IN_Q22;
199 274 : move32();
200 274 : DirAtten_p->ConeOuterAngle_fx = DEG_360_IN_Q22;
201 274 : move32();
202 274 : DirAtten_p->ConeOuterGain_fx = ONE_IN_Q30;
203 274 : move32();
204 :
205 : // TDREND_SRC_SPATIAL_t *SrcSpatial_p = pBinRendTd->Sources[nS]->SrcSpatial_p;
206 274 : IF( NE_32( ( error = TDREND_MIX_SRC_SetPos_fx( pBinRendTd, nS, Pos_fx ) ), IVAS_ERR_OK ) )
207 : {
208 0 : return error;
209 : }
210 274 : IF( NE_32( ( error = TDREND_MIX_SRC_SetDir_fx( pBinRendTd, nS, Dir_fx, Q30 ) ), IVAS_ERR_OK ) )
211 : {
212 0 : return error;
213 : }
214 274 : IF( NE_32( ( error = TDREND_MIX_SRC_SetPlayState( pBinRendTd, nS, TDREND_PLAYSTATUS_PLAYING ) ), IVAS_ERR_OK ) )
215 : {
216 0 : return error;
217 : }
218 : /*TDREND_SRC_SPATIAL_t **/ // SrcSpatial_p = pBinRendTd->Sources[nS]->SrcSpatial_p;
219 274 : IF( NE_32( ( error = TDREND_MIX_SRC_SetDirAtten_fx( pBinRendTd, nS, DirAtten_p ) ), IVAS_ERR_OK ) )
220 : {
221 0 : return error;
222 : }
223 : }
224 : }
225 513 : test();
226 513 : test();
227 513 : IF( EQ_16( ivas_format, ISM_FORMAT ) || EQ_16( ivas_format, MASA_ISM_FORMAT ) || EQ_16( ivas_format, SBA_ISM_FORMAT ) )
228 : {
229 469 : DirAtten_p = pBinRendTd->DirAtten_p;
230 :
231 1191 : FOR( nS = 0; nS < nchan_rend; nS++ )
232 : {
233 722 : IF( NULL == directivity )
234 : {
235 285 : DirAtten_p->ConeInnerAngle_fx = DEG_360_IN_Q22;
236 285 : DirAtten_p->ConeOuterAngle_fx = DEG_360_IN_Q22;
237 285 : DirAtten_p->ConeOuterGain_fx = ONE_IN_Q30;
238 : }
239 : ELSE
240 : {
241 437 : DirAtten_p->ConeInnerAngle_fx = L_deposit_h( directivity[nS * 3] ); // 9Q6 -> 9Q22
242 437 : DirAtten_p->ConeOuterAngle_fx = L_deposit_h( directivity[add( nS * 3, 1 )] ); // 9Q6 -> 9Q22
243 437 : DirAtten_p->ConeOuterGain_fx = L_shr( L_deposit_h( directivity[add( nS * 3, 2 )] ), 1 ); // 0Q15 -> 1Q30
244 : }
245 722 : move32();
246 722 : move32();
247 722 : move32();
248 722 : IF( NE_32( ( error = TDREND_MIX_SRC_SetDirAtten_fx( pBinRendTd, nS, DirAtten_p ) ), IVAS_ERR_OK ) )
249 : {
250 0 : return error;
251 : }
252 : }
253 : }
254 :
255 513 : *hBinRendererTd = pBinRendTd;
256 513 : test();
257 513 : IF( NE_16( ivas_format, MASA_ISM_FORMAT ) && NE_16( ivas_format, SBA_ISM_FORMAT ) )
258 : {
259 429 : *binaural_latency_ns = Mult_32_32( ( *hBinRendererTd )->HrFiltSet_p->latency_s_fx, 1000000000 /* 1000000000.f in Q0 */ );
260 429 : move32();
261 : }
262 :
263 513 : return error;
264 : }
265 :
266 :
267 : /*---------------------------------------------------------------------*
268 : * ivas_td_binaural_close()
269 : *
270 : * Close TD Object binaural renderer
271 : *---------------------------------------------------------------------*/
272 :
273 633 : void ivas_td_binaural_close_fx(
274 : BINAURAL_TD_OBJECT_RENDERER_HANDLE *hBinRendererTd /* i/o: TD binaural object renderer handle */
275 : )
276 : {
277 633 : test();
278 633 : IF( hBinRendererTd == NULL || *hBinRendererTd == NULL )
279 : {
280 120 : return;
281 : }
282 :
283 513 : free( ( *hBinRendererTd )->TdRend_MixSpatSpec_p );
284 513 : free( ( *hBinRendererTd )->DirAtten_p );
285 :
286 513 : TDREND_MIX_Dealloc_fx( *hBinRendererTd );
287 :
288 513 : free( *hBinRendererTd );
289 513 : *hBinRendererTd = NULL;
290 :
291 513 : return;
292 : }
293 :
294 :
295 : /*---------------------------------------------------------------------*
296 : * ivas_td_binaural_renderer_unwrap()
297 : *
298 : * Call ivas_td_binaural_renderer() without st_ivas.
299 : *---------------------------------------------------------------------*/
300 :
301 324504 : ivas_error ivas_td_binaural_renderer_unwrap_fx(
302 : const REVERB_HANDLE hReverb, /* i : Reverberator handle */
303 : const AUDIO_CONFIG transport_config, /* i : Transport configuration */
304 : BINAURAL_TD_OBJECT_RENDERER_HANDLE hBinRendererTd, /* i/o: TD binaural object renderer handle */
305 : const Word16 num_src, /* i : number of sources to render */
306 : const Word16 lfe_idx, /* i : LFE channel index */
307 : const IVAS_FORMAT ivas_format, /* i : IVAS format */
308 : ISM_METADATA_HANDLE *hIsmMetaData, /* i : ISM metadata handle */
309 : COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientaton data handle */
310 : const Word16 ism_md_subframe_update, /* i : Number of subframes to delay ism metadata to sync with audio */
311 : Word32 *output_fx[], /* i/o: SCE channels / Binaural synthesis Q11 */
312 : const Word16 output_frame, /* i : output frame length */
313 : const Word16 num_subframes /* i : number of subframes to render */
314 : )
315 : {
316 : Word16 subframe_length;
317 : Word16 subframe_idx;
318 : ivas_error error;
319 : Word16 c_indx, nS;
320 : Word16 ch;
321 : Word16 *enableCombinedOrientation; /* i : Combined orientation flag */
322 : IVAS_QUATERNION *Quaternions; /* i : Head tracking data per subframe */
323 : IVAS_VECTOR3 *Pos; /* i : Listener position data per subframe */
324 :
325 :
326 : Word32 reverb_signal_fx[BINAURAL_CHANNELS][L_FRAME48k];
327 : Word32 *p_reverb_signal_fx[BINAURAL_CHANNELS];
328 :
329 324504 : enableCombinedOrientation = NULL;
330 324504 : Quaternions = NULL;
331 324504 : Pos = NULL;
332 324504 : IF( hCombinedOrientationData != NULL )
333 : {
334 324504 : enableCombinedOrientation = hCombinedOrientationData->enableCombinedOrientation;
335 324504 : Quaternions = hCombinedOrientationData->Quaternions;
336 324504 : Pos = hCombinedOrientationData->listenerPos;
337 324504 : move16();
338 : }
339 :
340 973512 : FOR( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
341 : {
342 649008 : p_reverb_signal_fx[ch] = reverb_signal_fx[ch];
343 : }
344 :
345 324504 : subframe_length = idiv1616( output_frame, num_subframes );
346 :
347 324504 : c_indx = 0;
348 324504 : move16();
349 886568 : FOR( nS = 0; nS < num_src; nS++ )
350 : {
351 562064 : test();
352 562064 : IF( !( EQ_16( ivas_format, MC_FORMAT ) && EQ_16( nS, lfe_idx ) ) ) /* Skip LFE for MC */
353 : {
354 550564 : hBinRendererTd->Sources[c_indx]->InputFrame_p_fx = output_fx[nS]; /* Q11 */
355 550564 : hBinRendererTd->Sources[c_indx]->SrcRend_p->InputAvailable = TRUE;
356 550564 : move16();
357 550564 : c_indx = add( c_indx, 1 );
358 : }
359 : }
360 :
361 843714 : FOR( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
362 : {
363 519210 : IF( EQ_16( subframe_idx, ism_md_subframe_update ) )
364 : {
365 : /* Update object position(s) */
366 324504 : IF( NE_32( ( error = TDREND_Update_object_positions_fx( hBinRendererTd, num_src, ivas_format, hIsmMetaData ) ), IVAS_ERR_OK ) )
367 : {
368 0 : return error;
369 : }
370 : }
371 :
372 : /* Update the listener's location/orientation */
373 : Word16 tmp_headRotEnabled;
374 519210 : tmp_headRotEnabled = 0;
375 519210 : move16();
376 519210 : if ( enableCombinedOrientation != NULL )
377 : {
378 519210 : tmp_headRotEnabled = enableCombinedOrientation[hCombinedOrientationData->subframe_idx];
379 519210 : move16();
380 : }
381 :
382 519210 : IF( NE_32( ( error = TDREND_Update_listener_orientation_fx( hBinRendererTd, tmp_headRotEnabled, &Quaternions[hCombinedOrientationData->subframe_idx], &Pos[hCombinedOrientationData->subframe_idx] ) ), IVAS_ERR_OK ) )
383 : {
384 0 : return error;
385 : }
386 :
387 519210 : IF( hReverb != NULL )
388 : {
389 : Word16 i;
390 :
391 4236400 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
392 : {
393 3987200 : scale_sig32( output_fx[i], L_FRAME48k, -4 ); // Q11 - 4 = Q7
394 : }
395 :
396 249200 : IF( NE_32( ( error = ivas_reverb_process_fx( hReverb, transport_config, 0, output_fx, p_reverb_signal_fx, subframe_idx ) ), IVAS_ERR_OK ) ) // Q p_reverb_signal_fx = Q output_fx - 2 = 5
397 : {
398 0 : return error;
399 : }
400 :
401 4236400 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
402 : {
403 3987200 : scale_sig32( output_fx[i], L_FRAME48k, 4 ); // Q7 + 4 = Q11
404 : }
405 :
406 747600 : FOR( i = 0; i < BINAURAL_CHANNELS; ++i )
407 : {
408 498400 : scale_sig32( p_reverb_signal_fx[i] + subframe_idx * hReverb->full_block_size, hReverb->full_block_size, 2 + 4 ); // Q5 + 6 = Q11
409 : }
410 : }
411 :
412 : /* Render subframe */
413 519210 : IF( NE_32( ( error = TDREND_GetMix_fx( hBinRendererTd, output_fx, subframe_length, subframe_idx, ism_md_subframe_update ) ), IVAS_ERR_OK ) )
414 : {
415 0 : return error;
416 : }
417 :
418 :
419 : /* Advance subframe pointer */
420 519210 : c_indx = 0;
421 519210 : move16();
422 1418570 : FOR( nS = 0; nS < num_src; nS++ )
423 : {
424 899360 : test();
425 899360 : IF( !( EQ_16( ivas_format, MC_FORMAT ) && EQ_16( nS, lfe_idx ) ) ) /* Skip LFE for MC */
426 : {
427 880960 : hBinRendererTd->Sources[c_indx]->InputFrame_p_fx += subframe_length;
428 880960 : c_indx = add( c_indx, 1 );
429 : }
430 : }
431 :
432 : /* update combined orientation access index */
433 519210 : ivas_combined_orientation_update_index( hCombinedOrientationData, subframe_length );
434 : }
435 :
436 324504 : IF( hReverb != NULL )
437 : {
438 155750 : v_add_32( reverb_signal_fx[0], output_fx[0], output_fx[0], output_frame ); // Q11
439 155750 : v_add_32( reverb_signal_fx[1], output_fx[1], output_fx[1], output_frame ); // Q11
440 : }
441 :
442 324504 : return IVAS_ERR_OK;
443 : }
444 :
445 :
446 : /*---------------------------------------------------------------------*
447 : * TDREND_GetMix()
448 : *
449 : * Render one 5 ms subframe from the mixer
450 : *---------------------------------------------------------------------*/
451 :
452 664495 : ivas_error TDREND_GetMix_fx(
453 : BINAURAL_TD_OBJECT_RENDERER_HANDLE hBinRendererTd, /* i/o: TD renderer handle */
454 : Word32 *output[], /* i/o: ISM object synth / rendered output in 0,1 Q11 */
455 : const Word16 subframe_length, /* i/o: subframe length */
456 : const Word16 subframe_idx, /* i : Subframe index to 5 ms subframe */
457 : const Word16 ism_md_subframe_update /* i : Number of subframes to delay ism metadata to sync with audio */
458 : )
459 : {
460 : Word16 i;
461 : TDREND_SRC_t *Src_p;
462 : TDREND_SRC_SPATIAL_t *SrcSpatial_p;
463 : TDREND_SRC_REND_t *SrcRend_p;
464 : ivas_error error;
465 : Word32 output_buf[2][L_SPATIAL_SUBFR_48k]; /* Temp buffer for left/right rendered signal */
466 : Word32 hrf_left_delta[SFX_SPAT_BIN_MAX_FILTER_LENGTH];
467 : Word32 hrf_right_delta[SFX_SPAT_BIN_MAX_FILTER_LENGTH];
468 : Word16 intp_count;
469 : Word16 subframe_update_flag;
470 664495 : Word16 hrf_left_delta_e = 0, hrf_right_delta_e = 0;
471 664495 : move16();
472 664495 : move16();
473 :
474 664495 : subframe_update_flag = (Word16) EQ_16( subframe_idx, ism_md_subframe_update );
475 664495 : move16();
476 :
477 664495 : error = IVAS_ERR_OK;
478 664495 : move32();
479 : /* Clear the output buffer to accumulate rendered sources */
480 664495 : set32_fx( output_buf[0], 0, subframe_length );
481 664495 : set32_fx( output_buf[1], 0, subframe_length );
482 : /* Clear interpolation buffers and counter */
483 664495 : set32_fx( hrf_left_delta, 0, SFX_SPAT_BIN_MAX_FILTER_LENGTH );
484 664495 : set32_fx( hrf_right_delta, 0, SFX_SPAT_BIN_MAX_FILTER_LENGTH );
485 :
486 664495 : intp_count = 0;
487 664495 : move16();
488 :
489 : /* Create the mix */
490 : /* Loop through the source list and render each source */
491 1993937 : FOR( i = 0; i < hBinRendererTd->NumOfSrcs; i++ )
492 : {
493 1329442 : Src_p = hBinRendererTd->Sources[i];
494 1329442 : SrcSpatial_p = Src_p->SrcSpatial_p;
495 1329442 : SrcRend_p = Src_p->SrcRend_p;
496 :
497 : /* Update rendering params if needed */
498 1329442 : test();
499 1329442 : test();
500 1329442 : IF( EQ_16( SrcRend_p->PlayStatus, TDREND_PLAYSTATUS_PLAYING ) && ( hBinRendererTd->Listener_p->PoseUpdated || SrcSpatial_p->Updated ) )
501 : {
502 903144 : TDREND_SRC_REND_UpdateFiltersFromSpatialParams_fx( hBinRendererTd, SrcRend_p, SrcSpatial_p,
503 903144 : Src_p->hrf_left_prev_fx, &Src_p->hrf_left_prev_e, Src_p->hrf_right_prev_fx, &Src_p->hrf_right_prev_e,
504 : hrf_left_delta, &hrf_left_delta_e, hrf_right_delta, &hrf_right_delta_e,
505 : &intp_count, &Src_p->filterlength, &Src_p->itd,
506 : &Src_p->Gain_fx,
507 : Src_p, subframe_update_flag );
508 : }
509 :
510 : /* Render source if needed */
511 1329442 : test();
512 1329442 : IF( EQ_16( SrcRend_p->InputAvailable, TRUE ) && EQ_16( SrcRend_p->PlayStatus, TDREND_PLAYSTATUS_PLAYING ) )
513 : {
514 1329442 : error = TDREND_REND_RenderSourceHRFilt_fx( Src_p, hrf_left_delta, &hrf_left_delta_e,
515 : hrf_right_delta, &hrf_right_delta_e, intp_count, output_buf, subframe_length );
516 : }
517 : }
518 :
519 :
520 : /* Populate output variable */
521 664495 : Copy32( output_buf[0], output[0] + imult1616( subframe_idx, subframe_length ), subframe_length ); /* Left same Q as Src_p->InputFrame_p_fx Q11 */
522 664495 : Copy32( output_buf[1], output[1] + imult1616( subframe_idx, subframe_length ), subframe_length ); /* Right same Q as Src_p->InputFrame_p_fx Q11 */
523 :
524 : /* Clear the PoseUpdated and Source position update flags */
525 664495 : TDREND_Clear_Update_flags_fx( hBinRendererTd );
526 :
527 664495 : return error;
528 : }
529 :
530 :
531 : /*---------------------------------------------------------------------*
532 : * TDREND_Clear_Update_flags()
533 : *
534 : * Initializes the audio mixer module
535 : *---------------------------------------------------------------------*/
536 :
537 664495 : static void TDREND_Clear_Update_flags_fx(
538 : BINAURAL_TD_OBJECT_RENDERER_HANDLE hBinRendererTd /* i/o: TD renderer handle */
539 : )
540 : {
541 : Word16 i;
542 :
543 664495 : hBinRendererTd->Listener_p->PoseUpdated = FALSE;
544 664495 : move16();
545 :
546 1993937 : FOR( i = 0; i < hBinRendererTd->NumOfSrcs; i++ )
547 : {
548 1329442 : hBinRendererTd->Sources[i]->SrcSpatial_p->Updated = FALSE;
549 1329442 : move16();
550 : }
551 :
552 664495 : return;
553 : }
554 :
555 :
556 : /*---------------------------------------------------------------------*
557 : * TDREND_Update_object_positions_fx()
558 : *
559 : * Update object position(s)
560 : *---------------------------------------------------------------------*/
561 :
562 360835 : ivas_error TDREND_Update_object_positions_fx(
563 : BINAURAL_TD_OBJECT_RENDERER_HANDLE hBinRendererTd, /* i/o: TD Renderer handle */
564 : const Word16 num_src, /* i : number of sources to render */
565 : const IVAS_FORMAT in_format, /* i : Format of input sources */
566 : const ISM_METADATA_HANDLE *hIsmMetaData /* i : Input metadata for ISM objects */
567 : )
568 : {
569 : TDREND_DirAtten_t *DirAtten_p;
570 : Word16 nS;
571 : Word32 Pos_fx[3]; // Q25
572 : Word32 Dir_fx[3]; // Q30
573 : ivas_error error;
574 :
575 360835 : DirAtten_p = hBinRendererTd->DirAtten_p;
576 :
577 : /* For each source, write the frame data to the source object*/
578 1038105 : FOR( nS = 0; nS < num_src; nS++ )
579 : {
580 677270 : test();
581 677270 : test();
582 677270 : IF( EQ_16( in_format, ISM_FORMAT ) || EQ_16( in_format, MASA_ISM_FORMAT ) || EQ_16( in_format, SBA_ISM_FORMAT ) )
583 : {
584 : /* Update the source positions */
585 : /* Source position and direction */
586 396726 : angles_to_vec_fx( hIsmMetaData[nS]->radius_fx /*Q9*/, hIsmMetaData[nS]->azimuth_fx, hIsmMetaData[nS]->elevation_fx, Pos_fx );
587 396726 : angles_to_vec_fx( ONE_IN_Q14, hIsmMetaData[nS]->yaw_fx, hIsmMetaData[nS]->pitch_fx, Dir_fx );
588 :
589 : // DirAtten_p->ConeInnerAngle_fx = DEG_360_IN_Q22;
590 : // move32();
591 : // DirAtten_p->ConeOuterAngle_fx = DEG_360_IN_Q22;
592 : // move32();
593 : // DirAtten_p->ConeOuterGain_fx = ONE_IN_Q30;
594 : // move32();
595 :
596 396726 : IF( NE_32( ( error = TDREND_MIX_SRC_SetPos_fx( hBinRendererTd, nS, Pos_fx ) ), IVAS_ERR_OK ) )
597 : {
598 0 : return error;
599 : }
600 :
601 396726 : IF( NE_32( ( error = TDREND_MIX_SRC_SetDirAtten_fx( hBinRendererTd, nS, DirAtten_p ) ), IVAS_ERR_OK ) )
602 : {
603 0 : return error;
604 : }
605 :
606 396726 : IF( hIsmMetaData[nS]->non_diegetic_flag )
607 : {
608 828 : Pos_fx[0] = 0;
609 : /* Pos[1] = hIsmMetaData[nS]->azimuth / 90.f; */
610 828 : Pos_fx[1] = L_shl( Mpy_32_32_r( hIsmMetaData[nS]->azimuth_fx, 23860929 /* 1 / 90.f in Q31 */ ), Q3 ); /* Q25 */
611 828 : move32();
612 828 : Pos_fx[2] = 0;
613 828 : move32();
614 :
615 828 : IF( NE_32( ( error = TDREND_MIX_SRC_SetPos_fx( hBinRendererTd, nS, Pos_fx ) ), IVAS_ERR_OK ) )
616 : {
617 0 : return error;
618 : }
619 828 : hBinRendererTd->Sources[nS]->SrcSpatial_p->PosType = TDREND_POSTYPE_NON_DIEGETIC;
620 828 : move16();
621 : }
622 : ELSE
623 : {
624 395898 : hBinRendererTd->Sources[nS]->SrcSpatial_p->PosType = TDREND_POSTYPE_ABSOLUTE;
625 395898 : move16();
626 : }
627 :
628 396726 : IF( NE_32( ( error = TDREND_MIX_SRC_SetDir_fx( hBinRendererTd, nS, Dir_fx, Q30 ) ), IVAS_ERR_OK ) )
629 : {
630 0 : return error;
631 : }
632 : }
633 : }
634 :
635 360835 : return IVAS_ERR_OK;
636 : }
637 :
638 : /*---------------------------------------------------------------------*
639 : * TDREND_Update_listener_orientation()
640 : *
641 : * Update listener orientation (s)
642 : *---------------------------------------------------------------------*/
643 :
644 664495 : ivas_error TDREND_Update_listener_orientation_fx(
645 : BINAURAL_TD_OBJECT_RENDERER_HANDLE hBinRendererTd, /* i/o: TD Renderer handle */
646 : const Word16 headRotEnabled, /* i : Headrotation flag */
647 : const IVAS_QUATERNION *headPosition_fx, /* i : Listener orientation Qx */
648 : const IVAS_VECTOR3 *Pos_fx /* i : Listener Position */
649 : )
650 : {
651 : Word32 FrontVec_fx[3];
652 : Word32 UpVec_fx[3];
653 : Word32 Rmat_fx[3][3];
654 : Word16 orient_q, headPosition_q;
655 : Word32 Pos_p_fx[3];
656 : ivas_error error;
657 :
658 664495 : IF( headRotEnabled )
659 : {
660 : Word16 Rmat_q;
661 :
662 353645 : headPosition_q = headPosition_fx->q_fact;
663 353645 : move16();
664 :
665 : /* Obtain head rotation matrix */
666 353645 : QuatToRotMat_fx( *headPosition_fx, Rmat_fx ); // Rmat_fx Q: 2*headPosition_q-32
667 353645 : Rmat_q = sub( shl( headPosition_q, 1 ), 32 );
668 :
669 : /* Apply rotation matrix to looking vector [1;0;0] */
670 353645 : FrontVec_fx[0] = Rmat_fx[0][0]; // Q Rmat_q
671 353645 : move32();
672 353645 : FrontVec_fx[1] = Rmat_fx[0][1]; // Q Rmat_q
673 353645 : move32();
674 353645 : FrontVec_fx[2] = Rmat_fx[0][2]; // Q Rmat_q
675 353645 : move32();
676 :
677 : /* Apply rotation matrix to up vector [0;0;1] */
678 353645 : UpVec_fx[0] = Rmat_fx[2][0]; // Q Rmat_q
679 353645 : move32();
680 353645 : UpVec_fx[1] = Rmat_fx[2][1]; // Q Rmat_q
681 353645 : move32();
682 353645 : UpVec_fx[2] = Rmat_fx[2][2]; // Q Rmat_q
683 353645 : move32();
684 :
685 353645 : orient_q = Rmat_q;
686 353645 : move16();
687 :
688 353645 : IF( Pos_fx != NULL )
689 : {
690 : /* Input position */
691 353645 : Pos_p_fx[0] = ( *Pos_fx ).x_fx; // Q Pos_fx->q_fact
692 353645 : Pos_p_fx[1] = ( *Pos_fx ).y_fx; // Q Pos_fx->q_fact
693 353645 : Pos_p_fx[2] = ( *Pos_fx ).z_fx; // Q Pos_fx->q_fact
694 : }
695 : ELSE
696 : {
697 : /* Listener at the origin */
698 0 : Pos_p_fx[0] = 0;
699 0 : Pos_p_fx[1] = 0;
700 0 : Pos_p_fx[2] = 0;
701 : }
702 353645 : move32();
703 353645 : move32();
704 353645 : move32();
705 : }
706 : ELSE
707 : {
708 : /* Oriented with looking vector along the x axis */
709 310850 : FrontVec_fx[0] = ONE_IN_Q30;
710 310850 : move32();
711 310850 : FrontVec_fx[1] = 0;
712 310850 : move32();
713 310850 : FrontVec_fx[2] = 0;
714 310850 : move32();
715 : /* Oriented with up vector along the z axis */
716 310850 : UpVec_fx[0] = 0;
717 310850 : move32();
718 310850 : UpVec_fx[1] = 0;
719 310850 : move32();
720 310850 : UpVec_fx[2] = ONE_IN_Q30;
721 310850 : move32();
722 :
723 310850 : orient_q = Q30;
724 310850 : move32();
725 :
726 : /* Listener at the origin */
727 310850 : Pos_p_fx[0] = 0;
728 310850 : move32();
729 310850 : Pos_p_fx[1] = 0;
730 310850 : move32();
731 310850 : Pos_p_fx[2] = 0;
732 310850 : move32();
733 : }
734 :
735 : /* Set the listener position and orientation:*/
736 664495 : TDREND_MIX_LIST_SetPos_fx( hBinRendererTd, Pos_p_fx );
737 664495 : error = TDREND_MIX_LIST_SetOrient_fx( hBinRendererTd, FrontVec_fx, UpVec_fx, orient_q );
738 :
739 664495 : return error;
740 : }
741 :
742 :
743 : /*---------------------------------------------------------------------*
744 : * ivas_td_binaural_open_ext()
745 : *
746 : *
747 : *---------------------------------------------------------------------*/
748 405 : ivas_error ivas_td_binaural_open_ext_fx(
749 : TDREND_WRAPPER *pTDRend,
750 : AUDIO_CONFIG inConfig,
751 : RENDER_CONFIG_DATA *hRendCfg, /* i : Renderer configuration */
752 : LSSETUP_CUSTOM_STRUCT *customLsInput,
753 : const Word32 outFs,
754 : Word16 *SrcInd,
755 : Word16 *num_src )
756 : {
757 : Word16 nchan_transport;
758 : AUDIO_CONFIG transport_config;
759 : IVAS_FORMAT ivas_format;
760 : IVAS_OUTPUT_SETUP hTransSetup;
761 : ivas_error error;
762 :
763 405 : Word16 *directivity_fx = NULL;
764 :
765 405 : IF( NE_16( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
766 : {
767 381 : IF( NE_32( ( error = getAudioConfigNumChannels( inConfig, &nchan_transport ) ), IVAS_ERR_OK ) )
768 : {
769 0 : return error;
770 : }
771 : }
772 : ELSE
773 : {
774 24 : nchan_transport = customLsInput->num_spk;
775 24 : move16();
776 : }
777 405 : *num_src = nchan_transport;
778 405 : move16();
779 :
780 405 : transport_config = inConfig;
781 405 : move16();
782 405 : IF( ( getAudioConfigType( inConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
783 : {
784 40 : ivas_format = MC_FORMAT;
785 40 : move16();
786 : }
787 : ELSE
788 : {
789 365 : ivas_format = ISM_FORMAT;
790 365 : move16();
791 : }
792 405 : hTransSetup.ls_azimuth_fx = NULL;
793 405 : hTransSetup.ls_elevation_fx = NULL;
794 :
795 405 : IF( EQ_16( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
796 : {
797 24 : hTransSetup.ls_azimuth_fx = customLsInput->ls_azimuth_fx;
798 24 : hTransSetup.ls_elevation_fx = customLsInput->ls_elevation_fx;
799 : }
800 :
801 405 : if ( NULL != hRendCfg )
802 : {
803 120 : directivity_fx = hRendCfg->directivity_fx;
804 : }
805 :
806 405 : return ivas_td_binaural_open_unwrap_fx( &pTDRend->hHrtfTD, outFs, *num_src, ivas_format, transport_config, directivity_fx, hTransSetup, &pTDRend->hBinRendererTd, &pTDRend->binaural_latency_ns, SrcInd );
807 : }
808 : /*---------------------------------------------------------------------*
809 : * ivas_td_binaural_renderer_ext()
810 : *
811 : * Receives the current frames for the object streams, updates metadata
812 : * and renders the current frame.
813 : *---------------------------------------------------------------------*/
814 :
815 324504 : ivas_error ivas_td_binaural_renderer_ext_fx(
816 : const TDREND_WRAPPER *pTDRend, /* i : TD Renderer wrapper structure */
817 : const AUDIO_CONFIG inConfig, /* i : Input audio configuration */
818 : const LSSETUP_CUSTOM_STRUCT *customLsInput, /* i : Input custom loudspeaker layout */
819 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */
820 : const IVAS_ISM_METADATA *currentPos, /* i : Object position */
821 : const REVERB_HANDLE hReverb, /* i : Reverberator handle */
822 : const Word16 ism_md_subframe_update_ext, /* i : Metadata Delay in subframes to sync with audio delay */
823 : const Word32 output_Fs, /* i : output sampling rate */
824 : const Word16 output_frame, /* i : output frame length */
825 : Word32 output[][L_FRAME48k], /* i/o: SCE channels / Binaural synthesis Q11 */
826 : Word16 *exp )
827 : {
828 : ISM_METADATA_FRAME hIsmMetaDataFrame;
829 : ISM_METADATA_HANDLE hIsmMetaData[1];
830 : Word16 lfe_idx, exp_tmp;
831 : Word16 num_src;
832 : IVAS_FORMAT ivas_format;
833 : IVAS_REND_AudioConfigType inConfigType;
834 : AUDIO_CONFIG transport_config;
835 : ivas_error error;
836 :
837 : Word32 *p_output_fx[MAX_OUTPUT_CHANNELS];
838 5516568 : FOR( Word16 i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
839 : {
840 5192064 : p_output_fx[i] = output[i];
841 : }
842 :
843 324504 : push_wmops( "ivas_td_binaural_renderer_ext" );
844 :
845 324504 : inConfigType = getAudioConfigType( inConfig );
846 324504 : lfe_idx = LFE_CHANNEL;
847 324504 : move16();
848 324504 : hIsmMetaData[0] = NULL;
849 :
850 :
851 324504 : IF( EQ_32( inConfigType, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
852 : {
853 24504 : ivas_format = MC_FORMAT;
854 24504 : move16();
855 24504 : transport_config = inConfig;
856 24504 : move16();
857 :
858 24504 : IF( NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
859 : {
860 11500 : IF( NE_32( ( error = getAudioConfigNumChannels( inConfig, &num_src ) ), IVAS_ERR_OK ) )
861 : {
862 0 : return error;
863 : }
864 : }
865 : ELSE
866 : {
867 13004 : IF( customLsInput->num_lfe > 0 )
868 : {
869 0 : lfe_idx = customLsInput->lfe_idx[0];
870 0 : move16();
871 : }
872 : ELSE
873 : {
874 13004 : lfe_idx = -1;
875 13004 : move16();
876 : }
877 13004 : num_src = add( customLsInput->num_spk, customLsInput->num_lfe );
878 : }
879 : }
880 : ELSE
881 : {
882 300000 : ivas_format = ISM_FORMAT;
883 300000 : move16();
884 300000 : num_src = 1;
885 300000 : move16();
886 300000 : transport_config = IVAS_AUDIO_CONFIG_ISM1;
887 300000 : move16();
888 300000 : hIsmMetaData[0] = &hIsmMetaDataFrame;
889 300000 : move16();
890 300000 : hIsmMetaData[0]->azimuth_fx = currentPos->azimuth_fx;
891 300000 : move32();
892 300000 : hIsmMetaData[0]->elevation_fx = currentPos->elevation_fx;
893 300000 : move32();
894 300000 : hIsmMetaData[0]->yaw_fx = currentPos->yaw_fx;
895 300000 : move32();
896 300000 : hIsmMetaData[0]->pitch_fx = currentPos->pitch_fx;
897 300000 : move32();
898 300000 : hIsmMetaData[0]->radius_fx = currentPos->radius_fx;
899 300000 : move32();
900 300000 : hIsmMetaData[0]->non_diegetic_flag = currentPos->non_diegetic_flag;
901 300000 : move16();
902 : }
903 :
904 324504 : Word16 num_subframes = BASOP_Util_Divide3232_Scale( L_mult0( output_frame, FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ), output_Fs, &exp_tmp );
905 324504 : IF( sub( 15, exp_tmp ) )
906 : {
907 324504 : num_subframes = shr( num_subframes, sub( 15, exp_tmp ) );
908 : }
909 843714 : FOR( Word16 subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
910 : {
911 519210 : Word16 idx = subframe_idx;
912 519210 : move16();
913 519210 : Word16 pos_q = Q25;
914 519210 : move16();
915 519210 : IF( ( *hCombinedOrientationData )->listenerPos != NULL )
916 : {
917 519210 : ( *hCombinedOrientationData )->listenerPos[idx].x_fx = L_shr( ( *hCombinedOrientationData )->listenerPos[idx].x_fx, sub( ( *hCombinedOrientationData )->listenerPos[idx].q_fact, pos_q ) );
918 519210 : move32();
919 519210 : ( *hCombinedOrientationData )->listenerPos[idx].y_fx = L_shr( ( *hCombinedOrientationData )->listenerPos[idx].y_fx, sub( ( *hCombinedOrientationData )->listenerPos[idx].q_fact, pos_q ) );
920 519210 : move32();
921 519210 : ( *hCombinedOrientationData )->listenerPos[idx].z_fx = L_shr( ( *hCombinedOrientationData )->listenerPos[idx].z_fx, sub( ( *hCombinedOrientationData )->listenerPos[idx].q_fact, pos_q ) );
922 519210 : move32();
923 519210 : ( *hCombinedOrientationData )->listenerPos[idx].q_fact = pos_q;
924 519210 : move16();
925 : }
926 2076840 : FOR( Word16 i = 0; i < 3; i++ )
927 : {
928 1557630 : pTDRend->hBinRendererTd->Listener_p->Pos_fx[i] = L_shr( pTDRend->hBinRendererTd->Listener_p->Pos_fx[i], sub( pTDRend->hBinRendererTd->Listener_p->Pos_q, pos_q ) );
929 1557630 : pTDRend->hBinRendererTd->Listener_p->Pos_q = pos_q;
930 1557630 : move32();
931 1557630 : move16();
932 : }
933 : }
934 :
935 :
936 324504 : IF( NE_32( ( error = ivas_td_binaural_renderer_unwrap_fx( hReverb, transport_config, pTDRend->hBinRendererTd, num_src, lfe_idx, ivas_format, hIsmMetaData, *hCombinedOrientationData,
937 : ism_md_subframe_update_ext, p_output_fx, output_frame, num_subframes ) ),
938 : IVAS_ERR_OK ) )
939 : {
940 0 : return error;
941 : }
942 324504 : IF( hReverb != NULL )
943 : {
944 155750 : *exp = sub( *exp, 2 );
945 155750 : move16();
946 : }
947 :
948 324504 : pop_wmops();
949 :
950 324504 : return IVAS_ERR_OK;
951 : }
952 :
953 :
954 : /*---------------------------------------------------------------------*
955 : * angles_to_vec()
956 : *
957 : * Convert azimuth and elevation angles to position/orientation vector
958 : *---------------------------------------------------------------------*/
959 793726 : static void angles_to_vec_fx(
960 : const Word16 radius, /* i : radius Qx */
961 : const Word32 azimuth, /* i : Azimuth angle Q22 */
962 : const Word32 elevation, /* i : Elevation angle Q22 */
963 : Word32 *vec /* o : Pos/Dir vector Qx+16 */
964 : )
965 : {
966 : Word16 elevation_fx, azimuth_fx;
967 793726 : elevation_fx = (Word16) L_shr( Mult_32_16( elevation, 91 ), 7 ); // Q15
968 793726 : move16();
969 793726 : azimuth_fx = (Word16) L_shr( Mult_32_16( azimuth, 91 ), 7 ); // Q15
970 793726 : move16();
971 793726 : vec[0] = L_mult( radius, mult( getCosWord16R2( elevation_fx ), getCosWord16R2( azimuth_fx ) ) ); // Qx + 16
972 793726 : move32();
973 793726 : vec[1] = L_mult( radius, mult( getCosWord16R2( elevation_fx ), getSineWord16R2( azimuth_fx ) ) ); // Qx + 16
974 793726 : move32();
975 793726 : vec[2] = L_mult( radius, getSineWord16R2( elevation_fx ) ); // Qx + 16
976 793726 : move32();
977 793726 : return;
978 : }
|