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.h"
37 : #include "ivas_prot.h"
38 : #include "ivas_prot_rend.h"
39 : #include <math.h>
40 : #include "ivas_rom_com.h"
41 : #ifdef DEBUGGING
42 : #include "debug.h"
43 : #endif
44 : #include "wmc_auto.h"
45 :
46 :
47 : /*---------------------------------------------------------------------*
48 : * Local function prototypes
49 : *---------------------------------------------------------------------*/
50 :
51 : static void TDREND_Clear_Update_flags( BINAURAL_TD_OBJECT_RENDERER_HANDLE hBinRendererTd );
52 :
53 : static void angles_to_vec( const float radius, const float azimuth, const float elevation, float *vec );
54 :
55 :
56 : /*---------------------------------------------------------------------*
57 : * ivas_td_binaural_open_unwrap()
58 : *
59 : * Call TD open/init function without st_ivas
60 : *---------------------------------------------------------------------*/
61 :
62 69371 : ivas_error ivas_td_binaural_open_unwrap(
63 : TDREND_HRFILT_FiltSet_t **hHrtfTD, /* i/o: HR filter model (from file or NULL) */
64 : const int32_t output_Fs, /* i : Output sampling rate */
65 : const int16_t nchan_transport, /* i : Number of channels */
66 : const IVAS_FORMAT ivas_format, /* i : IVAS format (ISM/MC) */
67 : const AUDIO_CONFIG transport_config, /* i : Transport configuration */
68 : const float *directivity, /* i : Directivity pattern (used for ISM) */
69 : const float *distAtt, /* i : Distance attenuation (used for ISM) */
70 : const IVAS_OUTPUT_SETUP hTransSetup, /* i : Loudspeaker layout */
71 : BINAURAL_TD_OBJECT_RENDERER_HANDLE *hBinRendererTd, /* o : TD renderer handle */
72 : int32_t *binaural_latency_ns /* i : Binauralization delay */
73 : )
74 : {
75 : BINAURAL_TD_OBJECT_RENDERER_HANDLE pBinRendTd;
76 : TDREND_PosType_t PosType;
77 : int16_t nS;
78 : int16_t SrcInd[MAX_NUM_TDREND_CHANNELS];
79 : const float *ls_azimuth, *ls_elevation;
80 : float Pos[3];
81 : float Dir[3];
82 : TDREND_DirAtten_t *DirAtten_p;
83 : TDREND_DistAtten_t DistAtten;
84 : int16_t nchan_rend;
85 : ivas_error error;
86 :
87 69371 : error = IVAS_ERR_OK;
88 :
89 69371 : if ( ( pBinRendTd = malloc( sizeof( BINAURAL_TD_OBJECT_RENDERER ) ) ) == NULL )
90 : {
91 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for TD renderer\n" ) );
92 : }
93 69371 : if ( ( pBinRendTd->TdRend_MixSpatSpec_p = malloc( sizeof( TDREND_MixSpatSpec_t ) ) ) == NULL )
94 : {
95 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for TD renderer\n" ) );
96 : }
97 69371 : if ( ( pBinRendTd->DirAtten_p = malloc( sizeof( TDREND_DirAtten_t ) ) ) == NULL )
98 : {
99 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for TD renderer\n" ) );
100 : }
101 69371 : if ( ( pBinRendTd->Listener_p = malloc( sizeof( TDREND_MIX_Listener_t ) ) ) == NULL )
102 : {
103 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for TD renderer\n" ) );
104 : }
105 :
106 69371 : pBinRendTd->NumOfSrcs = 0;
107 69371 : pBinRendTd->MaxSrcInd = -1;
108 :
109 : /* Mixer spatial setup */
110 69371 : pBinRendTd->TdRend_MixSpatSpec_p->UseCommonDistAttenModel = TRUE;
111 69371 : pBinRendTd->TdRend_MixSpatSpec_p->DistAttenModel = 0; /* 0=Turned off, else use TDREND_DIST_ATTEN_MODEL_INV_DIST_CLAMPED */
112 :
113 69371 : if ( ( error = TDREND_MIX_Init( pBinRendTd, hHrtfTD, pBinRendTd->TdRend_MixSpatSpec_p, output_Fs ) ) != IVAS_ERR_OK )
114 : {
115 0 : return error;
116 : }
117 :
118 : /* Set the attenuation (or can set MixSpatSpec.DistAttenModel above) */
119 69371 : if ( ( error = TDREND_MIX_SetDistAttenModel( pBinRendTd, TDREND_DIST_ATTEN_MODEL_INV_DIST_CLAMPED ) ) != IVAS_ERR_OK )
120 : {
121 0 : return error;
122 : }
123 :
124 : /* Add sources to module and mixer, headphones */
125 69371 : PosType = TDREND_POSTYPE_ABSOLUTE; /* or TDREND_POSTYPE_RELATIVE_TO_LISTENER */
126 :
127 69371 : nchan_rend = nchan_transport;
128 69371 : if ( ( ivas_format == MC_FORMAT ) && ( transport_config != IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
129 : {
130 3666 : nchan_rend--; /* Skip LFE channel -- added to the others */
131 : }
132 :
133 209506 : for ( nS = 0; nS < nchan_rend; nS++ )
134 : {
135 140135 : if ( ( error = TDREND_MIX_AddSrc( pBinRendTd, &SrcInd[nS], PosType ) ) != IVAS_ERR_OK )
136 : {
137 0 : return error;
138 : }
139 : }
140 :
141 69371 : if ( ivas_format == MC_FORMAT )
142 : {
143 3906 : switch ( transport_config )
144 : {
145 2314 : case IVAS_AUDIO_CONFIG_5_1:
146 2314 : ls_azimuth = ls_azimuth_CICP6;
147 2314 : ls_elevation = ls_elevation_CICP6;
148 2314 : break;
149 1352 : case IVAS_AUDIO_CONFIG_7_1:
150 1352 : ls_azimuth = ls_azimuth_CICP12;
151 1352 : ls_elevation = ls_elevation_CICP12;
152 1352 : break;
153 0 : case IVAS_AUDIO_CONFIG_5_1_2:
154 0 : ls_azimuth = ls_azimuth_CICP14;
155 0 : ls_elevation = ls_elevation_CICP14;
156 0 : break;
157 0 : case IVAS_AUDIO_CONFIG_5_1_4:
158 0 : ls_azimuth = ls_azimuth_CICP16;
159 0 : ls_elevation = ls_elevation_CICP16;
160 0 : break;
161 0 : case IVAS_AUDIO_CONFIG_7_1_4:
162 0 : ls_azimuth = ls_azimuth_CICP19;
163 0 : ls_elevation = ls_elevation_CICP19;
164 0 : break;
165 240 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
166 240 : ls_azimuth = hTransSetup.ls_azimuth;
167 240 : ls_elevation = hTransSetup.ls_elevation;
168 240 : break;
169 0 : default:
170 0 : ls_azimuth = NULL;
171 0 : ls_elevation = NULL;
172 : }
173 :
174 3906 : DirAtten_p = pBinRendTd->DirAtten_p;
175 :
176 26500 : for ( nS = 0; nS < nchan_rend; nS++ )
177 : {
178 : /* Set source positions according to loudspeaker layout */
179 22594 : angles_to_vec( 1.0f, ls_azimuth[nS], ls_elevation[nS], Pos );
180 22594 : Dir[0] = 1.0f;
181 22594 : Dir[1] = 0.0f;
182 22594 : Dir[2] = 0.0f;
183 :
184 : /* Source directivity info */
185 22594 : DirAtten_p->ConeInnerAngle = 360.0f;
186 22594 : DirAtten_p->ConeOuterAngle = 360.0f;
187 22594 : DirAtten_p->ConeOuterGain = 1.0f;
188 :
189 22594 : DistAtten.DistAttenModel = TDREND_DIST_ATTEN_MODEL_INV_DIST_CLAMPED;
190 22594 : DistAtten.MaxDist = 15.75f;
191 22594 : DistAtten.RefDist = 1.0f;
192 22594 : DistAtten.RollOffFactor = 1.0f;
193 :
194 22594 : if ( ( error = TDREND_MIX_SRC_SetPos( pBinRendTd, nS, Pos ) ) != IVAS_ERR_OK )
195 : {
196 0 : return error;
197 : }
198 :
199 22594 : if ( ( error = TDREND_MIX_SRC_SetDir( pBinRendTd, nS, Dir ) ) != IVAS_ERR_OK )
200 : {
201 0 : return error;
202 : }
203 :
204 22594 : if ( ( error = TDREND_MIX_SRC_SetPlayState( pBinRendTd, nS, TDREND_PLAYSTATUS_PLAYING ) ) != IVAS_ERR_OK )
205 : {
206 0 : return error;
207 : }
208 :
209 22594 : if ( ( error = TDREND_MIX_SRC_SetDirAtten( pBinRendTd, nS, DirAtten_p ) ) != IVAS_ERR_OK )
210 : {
211 0 : return error;
212 : }
213 22594 : if ( ( error = TDREND_MIX_SRC_SetDistAtten( pBinRendTd, nS, &DistAtten ) ) != IVAS_ERR_OK )
214 : {
215 0 : return error;
216 : }
217 : }
218 : }
219 :
220 69371 : if ( ivas_format == ISM_FORMAT || ivas_format == MASA_ISM_FORMAT || ivas_format == SBA_ISM_FORMAT )
221 : {
222 65465 : DirAtten_p = pBinRendTd->DirAtten_p;
223 :
224 183006 : for ( nS = 0; nS < nchan_rend; nS++ )
225 : {
226 117541 : if ( NULL == directivity )
227 : {
228 13490 : DirAtten_p->ConeInnerAngle = 360.0f; /* Front cone */
229 13490 : DirAtten_p->ConeOuterAngle = 360.0f; /* Back cone */
230 13490 : DirAtten_p->ConeOuterGain = 1.0f; /* Back attenuation */
231 : }
232 : else
233 : {
234 104051 : DirAtten_p->ConeInnerAngle = directivity[nS * 3];
235 104051 : DirAtten_p->ConeOuterAngle = directivity[nS * 3 + 1];
236 104051 : DirAtten_p->ConeOuterGain = directivity[nS * 3 + 2];
237 : }
238 117541 : if ( NULL == distAtt )
239 : {
240 13490 : DistAtten.DistAttenModel = TDREND_DIST_ATTEN_MODEL_INV_DIST_CLAMPED;
241 13490 : DistAtten.MaxDist = 15.75f;
242 13490 : DistAtten.RefDist = 1.0f;
243 13490 : DistAtten.RollOffFactor = 1.0f;
244 : }
245 : else
246 : {
247 104051 : DistAtten.DistAttenModel = TDREND_DIST_ATTEN_MODEL_INV_DIST_CLAMPED;
248 104051 : DistAtten.MaxDist = distAtt[0];
249 104051 : DistAtten.RefDist = distAtt[1];
250 104051 : DistAtten.RollOffFactor = distAtt[2];
251 : }
252 117541 : if ( ( error = TDREND_MIX_SRC_SetDirAtten( pBinRendTd, nS, DirAtten_p ) ) != IVAS_ERR_OK )
253 : {
254 0 : return error;
255 : }
256 117541 : if ( ( error = TDREND_MIX_SRC_SetDistAtten( pBinRendTd, nS, &DistAtten ) ) != IVAS_ERR_OK )
257 : {
258 0 : return error;
259 : }
260 : }
261 : }
262 :
263 69371 : *hBinRendererTd = pBinRendTd;
264 :
265 69371 : if ( ivas_format != MASA_ISM_FORMAT && ivas_format != SBA_ISM_FORMAT )
266 : {
267 48790 : *binaural_latency_ns = (int32_t) ( ( *hBinRendererTd )->HrFiltSet_p->latency_s * 1000000000.f );
268 : }
269 :
270 69371 : return error;
271 : }
272 :
273 :
274 : /*---------------------------------------------------------------------*
275 : * ivas_td_binaural_close()
276 : *
277 : * Close TD Object binaural renderer
278 : *---------------------------------------------------------------------*/
279 :
280 448739 : void ivas_td_binaural_close(
281 : BINAURAL_TD_OBJECT_RENDERER_HANDLE *hBinRendererTd /* i/o: TD binaural object renderer handle */
282 : )
283 : {
284 448739 : if ( hBinRendererTd == NULL || *hBinRendererTd == NULL )
285 : {
286 379368 : return;
287 : }
288 :
289 69371 : free( ( *hBinRendererTd )->TdRend_MixSpatSpec_p );
290 69371 : free( ( *hBinRendererTd )->DirAtten_p );
291 :
292 69371 : TDREND_MIX_Dealloc( *hBinRendererTd );
293 :
294 69371 : free( *hBinRendererTd );
295 69371 : *hBinRendererTd = NULL;
296 :
297 69371 : return;
298 : }
299 :
300 :
301 : /*---------------------------------------------------------------------*
302 : * ivas_td_binaural_renderer_unwrap()
303 : *
304 : * Call ivas_td_binaural_renderer() without st_ivas.
305 : *---------------------------------------------------------------------*/
306 :
307 33226046 : ivas_error ivas_td_binaural_renderer_unwrap(
308 : const REVERB_HANDLE hReverb, /* i : Reverberator handle */
309 : const AUDIO_CONFIG transport_config, /* i : Transport configuration */
310 : BINAURAL_TD_OBJECT_RENDERER_HANDLE hBinRendererTd, /* i/o: TD binaural object renderer handle */
311 : const int16_t num_src, /* i : number of sources to render */
312 : const int16_t lfe_idx, /* i : LFE channel index */
313 : const IVAS_FORMAT ivas_format, /* i : IVAS format */
314 : ISM_METADATA_HANDLE *hIsmMetaData, /* i : ISM metadata handle */
315 : COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientaton data handle */
316 : const int16_t ism_md_subframe_update, /* i : Number of subframes to delay ism metadata to sync with audio */
317 : float *output[], /* i/o: SCE channels / Binaural synthesis */
318 : const int16_t output_frame, /* i : output frame length */
319 : const int16_t num_subframes /* i : number of subframes to render */
320 : )
321 : {
322 : int16_t subframe_length;
323 : int16_t subframe_idx;
324 : float reverb_signal[BINAURAL_CHANNELS][L_FRAME48k];
325 : ivas_error error;
326 : int16_t c_indx, nS;
327 : float *p_reverb_signal[BINAURAL_CHANNELS];
328 : int16_t ch;
329 : int16_t *enableCombinedOrientation; /* i : Combined orientation flag */
330 : IVAS_QUATERNION *Quaternions; /* i : Head tracking data per subframe */
331 : IVAS_VECTOR3 *Pos; /* i : Listener position data per subframe */
332 :
333 33226046 : enableCombinedOrientation = NULL;
334 33226046 : Quaternions = NULL;
335 33226046 : Pos = NULL;
336 33226046 : if ( hCombinedOrientationData != NULL )
337 : {
338 17838915 : enableCombinedOrientation = hCombinedOrientationData->enableCombinedOrientation;
339 17838915 : Quaternions = hCombinedOrientationData->Quaternions;
340 17838915 : Pos = hCombinedOrientationData->listenerPos;
341 : }
342 :
343 99678138 : for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
344 : {
345 66452092 : p_reverb_signal[ch] = reverb_signal[ch];
346 : }
347 :
348 33226046 : subframe_length = output_frame / num_subframes;
349 :
350 33226046 : c_indx = 0;
351 80180850 : for ( nS = 0; nS < num_src; nS++ )
352 : {
353 46954804 : if ( !( ivas_format == MC_FORMAT && nS == lfe_idx ) ) /* Skip LFE for MC */
354 : {
355 46114988 : hBinRendererTd->Sources[c_indx]->InputFrame_p = output[nS];
356 46114988 : hBinRendererTd->Sources[c_indx]->SrcRend_p->InputAvailable = TRUE;
357 46114988 : c_indx++;
358 : }
359 : }
360 :
361 86154742 : for ( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
362 : {
363 52928696 : if ( subframe_idx == ism_md_subframe_update )
364 : {
365 : /* Update object position(s) */
366 27191726 : if ( ( error = TDREND_Update_object_positions( 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 52928696 : if ( ( error = TDREND_Update_listener_orientation( hBinRendererTd, ( enableCombinedOrientation != NULL ) ? enableCombinedOrientation[hCombinedOrientationData->subframe_idx] : 0, ( Quaternions != NULL ) ? &Quaternions[hCombinedOrientationData->subframe_idx] : NULL, ( Pos != NULL ) ? &Pos[hCombinedOrientationData->subframe_idx] : NULL ) ) != IVAS_ERR_OK )
374 : {
375 0 : return error;
376 : }
377 :
378 52928696 : if ( hReverb != NULL )
379 : {
380 25226166 : if ( ( error = ivas_reverb_process( hReverb, transport_config, 0, output, p_reverb_signal, subframe_idx ) ) != IVAS_ERR_OK )
381 : {
382 0 : return error;
383 : }
384 : }
385 :
386 : /* Render subframe */
387 52928696 : if ( ( error = TDREND_GetMix( hBinRendererTd, output, subframe_length, subframe_idx ) ) != IVAS_ERR_OK )
388 : {
389 0 : return error;
390 : }
391 :
392 : /* Advance subframe pointer */
393 52928696 : c_indx = 0;
394 127285980 : for ( nS = 0; nS < num_src; nS++ )
395 : {
396 74357284 : if ( !( ivas_format == MC_FORMAT && nS == lfe_idx ) ) /* Skip LFE for MC */
397 : {
398 73089944 : hBinRendererTd->Sources[c_indx]->InputFrame_p += subframe_length;
399 73089944 : c_indx++;
400 : }
401 : }
402 :
403 : /* update combined orientation access index */
404 52928696 : ivas_combined_orientation_update_index( hCombinedOrientationData, subframe_length );
405 : }
406 :
407 33226046 : if ( hReverb != NULL )
408 : {
409 : /* add reverb to rendered signals */
410 16065816 : v_add( reverb_signal[0], output[0], output[0], output_frame );
411 16065816 : v_add( reverb_signal[1], output[1], output[1], output_frame );
412 : }
413 :
414 33226046 : return IVAS_ERR_OK;
415 : }
416 :
417 :
418 : /*---------------------------------------------------------------------*
419 : * TDREND_GetMix()
420 : *
421 : * Render one 5 ms subframe from the mixer
422 : *---------------------------------------------------------------------*/
423 :
424 62486342 : ivas_error TDREND_GetMix(
425 : BINAURAL_TD_OBJECT_RENDERER_HANDLE hBinRendererTd, /* i/o: TD renderer handle */
426 : float *output[], /* i/o: ISM object synth / rendered output in 0,1 */
427 : const int16_t subframe_length, /* i/o: subframe length */
428 : const int16_t subframe_idx /* i : Subframe index to 5 ms subframe */
429 : )
430 : {
431 : int16_t i;
432 : TDREND_SRC_t *Src_p;
433 : TDREND_SRC_SPATIAL_t *SrcSpatial_p;
434 : TDREND_SRC_REND_t *SrcRend_p;
435 : ivas_error error;
436 : float output_buf[2][L_SPATIAL_SUBFR_48k]; /* Temp buffer for left/right rendered signal */
437 : float hrf_left_delta[SFX_SPAT_BIN_MAX_FILTER_LENGTH];
438 : float hrf_right_delta[SFX_SPAT_BIN_MAX_FILTER_LENGTH];
439 : int16_t intp_count;
440 : int16_t currShift, prevShift, transition_len, length_in2;
441 :
442 62486342 : error = IVAS_ERR_OK;
443 :
444 : /* Clear the output buffer to accumulate rendered sources */
445 62486342 : set_f( output_buf[0], 0.0f, subframe_length );
446 62486342 : set_f( output_buf[1], 0.0f, subframe_length );
447 :
448 : /* Clear interpolation buffers and counter */
449 62486342 : set_f( hrf_left_delta, 0.0f, SFX_SPAT_BIN_MAX_FILTER_LENGTH );
450 62486342 : set_f( hrf_right_delta, 0.0f, SFX_SPAT_BIN_MAX_FILTER_LENGTH );
451 62486342 : intp_count = 0;
452 :
453 : /* Create the mix */
454 : /* Loop through the source list and render each source */
455 166449659 : for ( i = 0; i < hBinRendererTd->NumOfSrcs; i++ )
456 : {
457 103963317 : Src_p = hBinRendererTd->Sources[i];
458 103963317 : SrcSpatial_p = Src_p->SrcSpatial_p;
459 103963317 : SrcRend_p = Src_p->SrcRend_p;
460 :
461 : /* Update rendering params if needed */
462 103963317 : if ( ( SrcRend_p->PlayStatus == TDREND_PLAYSTATUS_PLAYING ) && ( hBinRendererTd->Listener_p->PoseUpdated || SrcSpatial_p->Updated ) )
463 : {
464 63691212 : TDREND_SRC_REND_UpdateFiltersFromSpatialParams( hBinRendererTd, SrcRend_p, SrcSpatial_p, Src_p->hrf_left_prev,
465 63691212 : Src_p->hrf_right_prev, hrf_left_delta, hrf_right_delta, &intp_count, &Src_p->filterlength, &Src_p->itd, &Src_p->Gain, Src_p );
466 :
467 : /* For large ITD values at lower sampling rate, check if the transition can be done */
468 63691212 : if ( Src_p->itd * Src_p->previtd < 0 )
469 : {
470 1757404 : currShift = (int16_t) abs( Src_p->itd );
471 1757404 : prevShift = (int16_t) abs( Src_p->previtd );
472 1757404 : transition_len = subframe_length - max( 0, SFX_SPAT_BIN_SINC_M - currShift );
473 1757404 : length_in2 = transition_len - (int16_t) ( ( (float) ( transition_len * prevShift ) / ( (float) ( prevShift + currShift ) ) ) + 0.5f ) - currShift;
474 1757404 : if ( length_in2 <= 0 )
475 : {
476 : /* Subframe too short for ITD transition -- change to ITD=0 and push the rest of the transition to next subframe */
477 0 : Src_p->itd = 0;
478 : }
479 : }
480 : }
481 :
482 : /* Render source if needed */
483 103963317 : if ( ( SrcRend_p->InputAvailable == TRUE ) && ( SrcRend_p->PlayStatus == TDREND_PLAYSTATUS_PLAYING ) )
484 : {
485 103963317 : error = TDREND_REND_RenderSourceHRFilt( Src_p, hrf_left_delta, hrf_right_delta, intp_count, output_buf, subframe_length );
486 : }
487 : }
488 :
489 : /* Populate output variable */
490 62486342 : mvr2r( output_buf[0], output[0] + subframe_idx * subframe_length, subframe_length ); /* Left */
491 62486342 : mvr2r( output_buf[1], output[1] + subframe_idx * subframe_length, subframe_length ); /* Right */
492 :
493 : /* Clear the PoseUpdated and Source position update flags */
494 62486342 : TDREND_Clear_Update_flags( hBinRendererTd );
495 :
496 62486342 : return error;
497 : }
498 :
499 :
500 : /*---------------------------------------------------------------------*
501 : * TDREND_Clear_Update_flags()
502 : *
503 : * Initializes the audio mixer module
504 : *---------------------------------------------------------------------*/
505 :
506 62486342 : static void TDREND_Clear_Update_flags(
507 : BINAURAL_TD_OBJECT_RENDERER_HANDLE hBinRendererTd /* i/o: TD renderer handle */
508 : )
509 : {
510 : int16_t i;
511 :
512 62486342 : hBinRendererTd->Listener_p->PoseUpdated = FALSE;
513 :
514 166449659 : for ( i = 0; i < hBinRendererTd->NumOfSrcs; i++ )
515 : {
516 103963317 : hBinRendererTd->Sources[i]->SrcSpatial_p->Updated = FALSE;
517 103963317 : hBinRendererTd->Sources[i]->SrcRend_p->SrcGainUpdated = FALSE;
518 : }
519 :
520 62486342 : return;
521 : }
522 :
523 :
524 : /*---------------------------------------------------------------------*
525 : * TDREND_Update_object_positions()
526 : *
527 : * Update object position(s)
528 : *---------------------------------------------------------------------*/
529 :
530 29578385 : ivas_error TDREND_Update_object_positions(
531 : BINAURAL_TD_OBJECT_RENDERER_HANDLE hBinRendererTd, /* i/o: TD Renderer handle */
532 : const int16_t num_src, /* i : number of sources to render */
533 : const IVAS_FORMAT in_format, /* i : Format of input sources */
534 : const ISM_METADATA_HANDLE *hIsmMetaData /* i : Input metadata for ISM objects */
535 : )
536 : {
537 : int16_t nS;
538 : float Pos[3];
539 : float Dir[3];
540 : ivas_error error;
541 :
542 : /* For each source, write the frame data to the source object*/
543 78655387 : for ( nS = 0; nS < num_src; nS++ )
544 : {
545 49077002 : if ( in_format == ISM_FORMAT || in_format == MASA_ISM_FORMAT || in_format == SBA_ISM_FORMAT )
546 : {
547 : /* Update the source positions */
548 : /* Source position and direction */
549 30991376 : angles_to_vec( hIsmMetaData[nS]->radius, hIsmMetaData[nS]->azimuth, hIsmMetaData[nS]->elevation, Pos );
550 30991376 : angles_to_vec( 1.0f, hIsmMetaData[nS]->yaw, hIsmMetaData[nS]->pitch, Dir );
551 :
552 30991376 : if ( ( error = TDREND_MIX_SRC_SetPos( hBinRendererTd, nS, Pos ) ) != IVAS_ERR_OK )
553 : {
554 0 : return error;
555 : }
556 :
557 30991376 : if ( ( error = TDREND_MIX_SRC_SetGain( hBinRendererTd, nS, hIsmMetaData[nS]->gain ) ) != IVAS_ERR_OK )
558 : {
559 0 : return error;
560 : }
561 :
562 30991376 : if ( hIsmMetaData[nS]->non_diegetic_flag )
563 : {
564 281978 : Pos[0] = 0;
565 281978 : Pos[1] = hIsmMetaData[nS]->azimuth / 90.f;
566 281978 : Pos[2] = 0;
567 281978 : if ( ( error = TDREND_MIX_SRC_SetPos( hBinRendererTd, nS, Pos ) ) != IVAS_ERR_OK )
568 : {
569 0 : return error;
570 : }
571 281978 : hBinRendererTd->Sources[nS]->SrcSpatial_p->PosType = TDREND_POSTYPE_NON_DIEGETIC;
572 : }
573 : else
574 : {
575 30709398 : hBinRendererTd->Sources[nS]->SrcSpatial_p->PosType = TDREND_POSTYPE_ABSOLUTE;
576 : }
577 :
578 30991376 : if ( ( error = TDREND_MIX_SRC_SetDir( hBinRendererTd, nS, Dir ) ) != IVAS_ERR_OK )
579 : {
580 0 : return error;
581 : }
582 : }
583 : }
584 :
585 29578385 : return IVAS_ERR_OK;
586 : }
587 :
588 :
589 : /*---------------------------------------------------------------------*
590 : * TDREND_Update_listener_orientation()
591 : *
592 : * Update listener orientation (s)
593 : *---------------------------------------------------------------------*/
594 :
595 62486342 : ivas_error TDREND_Update_listener_orientation(
596 : BINAURAL_TD_OBJECT_RENDERER_HANDLE hBinRendererTd, /* i/o: TD Renderer handle */
597 : const int16_t headRotEnabled, /* i : Headrotation flag */
598 : const IVAS_QUATERNION *headPosition, /* i : Listener orientation */
599 : const IVAS_VECTOR3 *Pos /* i : Listener Position */
600 : )
601 : {
602 : float FrontVec[3];
603 : float UpVec[3];
604 : float Rmat[3][3];
605 : float Pos_p[3];
606 : ivas_error error;
607 :
608 62486342 : if ( headRotEnabled )
609 : {
610 : /* Obtain head rotation matrix */
611 34180174 : QuatToRotMat( *headPosition, Rmat );
612 : /* Apply rotation matrix to looking vector [1;0;0] */
613 34180174 : FrontVec[0] = Rmat[0][0];
614 34180174 : FrontVec[1] = Rmat[0][1];
615 34180174 : FrontVec[2] = Rmat[0][2];
616 : /* Apply rotation matrix to up vector [0;0;1] */
617 34180174 : UpVec[0] = Rmat[2][0];
618 34180174 : UpVec[1] = Rmat[2][1];
619 34180174 : UpVec[2] = Rmat[2][2];
620 34180174 : if ( Pos != NULL )
621 : {
622 : /* Input position */
623 34180174 : Pos_p[0] = ( *Pos ).x;
624 34180174 : Pos_p[1] = ( *Pos ).y;
625 34180174 : Pos_p[2] = ( *Pos ).z;
626 : }
627 : else
628 : {
629 : /* Listener at the origin */
630 0 : Pos_p[0] = 0.0f;
631 0 : Pos_p[1] = 0.0f;
632 0 : Pos_p[2] = 0.0f;
633 : }
634 : }
635 : else
636 : {
637 : /* Oriented with looking vector along the x axis */
638 28306168 : FrontVec[0] = 1.0f;
639 28306168 : FrontVec[1] = 0.0f;
640 28306168 : FrontVec[2] = 0.0f;
641 : /* Oriented with up vector along the z axis */
642 28306168 : UpVec[0] = 0.0f;
643 28306168 : UpVec[1] = 0.0f;
644 28306168 : UpVec[2] = 1.0f;
645 : /* Listener at the origin */
646 28306168 : Pos_p[0] = 0.0f;
647 28306168 : Pos_p[1] = 0.0f;
648 28306168 : Pos_p[2] = 0.0f;
649 : }
650 :
651 : /* Set the listener position and orientation:*/
652 62486342 : TDREND_MIX_LIST_SetPos( hBinRendererTd, Pos_p );
653 62486342 : error = TDREND_MIX_LIST_SetOrient( hBinRendererTd, FrontVec, UpVec );
654 :
655 62486342 : return error;
656 : }
657 :
658 :
659 : /*---------------------------------------------------------------------*
660 : * ivas_td_binaural_open_ext()
661 : *
662 : *
663 : *---------------------------------------------------------------------*/
664 :
665 40754 : ivas_error ivas_td_binaural_open_ext(
666 : TDREND_WRAPPER *pTDRend, /* i/o: TD Renderer wrapper structure */
667 : const AUDIO_CONFIG inConfig, /* i : input audio configuration */
668 : RENDER_CONFIG_DATA *hRendCfg, /* i : Renderer configuration */
669 : LSSETUP_CUSTOM_STRUCT *customLsInput, /* i : Input custom loudspeaker layout */
670 : const int32_t outFs, /* i : output sampling rate */
671 : const int16_t object_id /* i : Object ID */
672 : )
673 : {
674 : int16_t nchan_transport;
675 : AUDIO_CONFIG transport_config;
676 : IVAS_FORMAT ivas_format;
677 : IVAS_OUTPUT_SETUP hTransSetup;
678 : ivas_error error;
679 :
680 40754 : float *distAtt = NULL;
681 40754 : float *directivity = NULL;
682 :
683 40754 : if ( inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM )
684 : {
685 40514 : if ( ( error = getAudioConfigNumChannels( inConfig, &nchan_transport ) ) != IVAS_ERR_OK )
686 : {
687 0 : return error;
688 : }
689 : }
690 : else
691 : {
692 240 : nchan_transport = customLsInput->num_spk;
693 : }
694 :
695 40754 : transport_config = inConfig;
696 40754 : ivas_format = ( getAudioConfigType( inConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) ? MC_FORMAT : ISM_FORMAT;
697 :
698 40754 : hTransSetup.ls_azimuth = NULL;
699 40754 : hTransSetup.ls_elevation = NULL;
700 :
701 40754 : if ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
702 : {
703 240 : hTransSetup.ls_azimuth = customLsInput->ls_azimuth;
704 240 : hTransSetup.ls_elevation = customLsInput->ls_elevation;
705 : }
706 :
707 40754 : if ( NULL != hRendCfg )
708 : {
709 27264 : directivity = hRendCfg->directivity + 3 * object_id;
710 27264 : distAtt = hRendCfg->distAtt;
711 : }
712 :
713 40754 : return ivas_td_binaural_open_unwrap( pTDRend->hHrtfTD, outFs, nchan_transport, ivas_format, transport_config, directivity, distAtt, hTransSetup, &pTDRend->hBinRendererTd, &pTDRend->binaural_latency_ns );
714 : }
715 :
716 :
717 : /*---------------------------------------------------------------------*
718 : * ivas_td_binaural_renderer_ext()
719 : *
720 : * Receives the current frames for the object streams, updates metadata
721 : * and renders the current frame.
722 : *---------------------------------------------------------------------*/
723 :
724 33226046 : ivas_error ivas_td_binaural_renderer_ext(
725 : const TDREND_WRAPPER *pTDRend, /* i : TD Renderer wrapper structure */
726 : const AUDIO_CONFIG inConfig, /* i : Input audio configuration */
727 : const LSSETUP_CUSTOM_STRUCT *customLsInput, /* i : Input custom loudspeaker layout */
728 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */
729 : const IVAS_ISM_METADATA *currentPos, /* i : Object position */
730 : const REVERB_HANDLE hReverb, /* i : Reverberator handle */
731 : const int16_t ism_md_subframe_update_ext, /* i : Metadata Delay in subframes to sync with audio delay */
732 : const int32_t output_Fs, /* i : output sampling rate */
733 : const int16_t output_frame, /* i : output frame length */
734 : float output[][L_FRAME48k] /* i/o: SCE channels / Binaural synthesis */
735 : )
736 : {
737 : ISM_METADATA_FRAME hIsmMetaDataFrame;
738 : ISM_METADATA_HANDLE hIsmMetaData[1];
739 : int16_t lfe_idx;
740 : int16_t num_src;
741 : IVAS_FORMAT ivas_format;
742 : IVAS_REND_AudioConfigType inConfigType;
743 : AUDIO_CONFIG transport_config;
744 : ivas_error error;
745 : float *p_output[MAX_OUTPUT_CHANNELS];
746 : int16_t ch;
747 :
748 564842782 : for ( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
749 : {
750 531616736 : p_output[ch] = output[ch];
751 : }
752 :
753 33226046 : push_wmops( "ivas_td_binaural_renderer_ext" );
754 :
755 33226046 : inConfigType = getAudioConfigType( inConfig );
756 33226046 : lfe_idx = LFE_CHANNEL;
757 33226046 : hIsmMetaData[0] = NULL;
758 :
759 :
760 33226046 : if ( inConfigType == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
761 : {
762 1625866 : ivas_format = MC_FORMAT;
763 1625866 : transport_config = inConfig;
764 1625866 : if ( inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM )
765 : {
766 839816 : if ( ( error = getAudioConfigNumChannels( inConfig, &num_src ) ) != IVAS_ERR_OK )
767 : {
768 0 : return error;
769 : }
770 : }
771 : else
772 : {
773 786050 : lfe_idx = ( customLsInput->num_lfe > 0 ) ? customLsInput->lfe_idx[0] : -1;
774 786050 : num_src = customLsInput->num_spk + customLsInput->num_lfe;
775 : }
776 : }
777 : else
778 : {
779 31600180 : ivas_format = ISM_FORMAT;
780 31600180 : num_src = 1;
781 31600180 : transport_config = IVAS_AUDIO_CONFIG_ISM1;
782 31600180 : hIsmMetaData[0] = &hIsmMetaDataFrame;
783 31600180 : hIsmMetaData[0]->azimuth = currentPos->azimuth;
784 31600180 : hIsmMetaData[0]->elevation = currentPos->elevation;
785 31600180 : hIsmMetaData[0]->yaw = currentPos->yaw;
786 31600180 : hIsmMetaData[0]->pitch = currentPos->pitch;
787 31600180 : hIsmMetaData[0]->radius = currentPos->radius;
788 31600180 : hIsmMetaData[0]->gain = 1.0f;
789 :
790 31600180 : hIsmMetaData[0]->non_diegetic_flag = currentPos->non_diegetic_flag;
791 : }
792 :
793 33226046 : if ( ( error = ivas_td_binaural_renderer_unwrap( hReverb, transport_config, pTDRend->hBinRendererTd, num_src, lfe_idx, ivas_format, hIsmMetaData, *hCombinedOrientationData,
794 33226046 : ism_md_subframe_update_ext, p_output, output_frame, (int16_t) ( ( output_frame * FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ) / output_Fs ) ) ) != IVAS_ERR_OK )
795 : {
796 0 : return error;
797 : }
798 :
799 33226046 : pop_wmops();
800 :
801 33226046 : return IVAS_ERR_OK;
802 : }
803 :
804 :
805 : /*---------------------------------------------------------------------*
806 : * angles_to_vec()
807 : *
808 : * Convert azimuth and elevation angles to position/orientation vector
809 : *---------------------------------------------------------------------*/
810 :
811 62005346 : static void angles_to_vec(
812 : const float radius, /* i : radius */
813 : const float azimuth, /* i : Azimuth angle */
814 : const float elevation, /* i : Elevation angle */
815 : float *vec /* o : Pos/Dir vector */
816 : )
817 : {
818 62005346 : vec[0] = radius * cosf( elevation * PI_OVER_180 ) * cosf( azimuth * PI_OVER_180 );
819 62005346 : vec[1] = radius * cosf( elevation * PI_OVER_180 ) * sinf( azimuth * PI_OVER_180 );
820 62005346 : vec[2] = radius * sinf( elevation * PI_OVER_180 );
821 :
822 62005346 : return;
823 : }
|