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 2427 : 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 2427 : error = IVAS_ERR_OK;
88 :
89 2427 : 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 2427 : 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 2427 : 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 2427 : 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 2427 : pBinRendTd->NumOfSrcs = 0;
107 2427 : pBinRendTd->MaxSrcInd = -1;
108 :
109 : /* Mixer spatial setup */
110 2427 : pBinRendTd->TdRend_MixSpatSpec_p->UseCommonDistAttenModel = TRUE;
111 2427 : pBinRendTd->TdRend_MixSpatSpec_p->DistAttenModel = 0; /* 0=Turned off, else use TDREND_DIST_ATTEN_MODEL_INV_DIST_CLAMPED */
112 :
113 2427 : 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 2427 : 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 2427 : PosType = TDREND_POSTYPE_ABSOLUTE; /* or TDREND_POSTYPE_RELATIVE_TO_LISTENER */
126 :
127 2427 : nchan_rend = nchan_transport;
128 2427 : if ( ( ivas_format == MC_FORMAT ) && ( transport_config != IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
129 : {
130 49 : nchan_rend--; /* Skip LFE channel -- added to the others */
131 : }
132 :
133 7715 : for ( nS = 0; nS < nchan_rend; nS++ )
134 : {
135 5288 : if ( ( error = TDREND_MIX_AddSrc( pBinRendTd, &SrcInd[nS], PosType ) ) != IVAS_ERR_OK )
136 : {
137 0 : return error;
138 : }
139 : }
140 :
141 2427 : if ( ivas_format == MC_FORMAT )
142 : {
143 97 : switch ( transport_config )
144 : {
145 17 : case IVAS_AUDIO_CONFIG_5_1:
146 17 : ls_azimuth = ls_azimuth_CICP6;
147 17 : ls_elevation = ls_elevation_CICP6;
148 17 : break;
149 32 : case IVAS_AUDIO_CONFIG_7_1:
150 32 : ls_azimuth = ls_azimuth_CICP12;
151 32 : ls_elevation = ls_elevation_CICP12;
152 32 : 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 48 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
166 48 : ls_azimuth = hTransSetup.ls_azimuth;
167 48 : ls_elevation = hTransSetup.ls_elevation;
168 48 : break;
169 0 : default:
170 0 : ls_azimuth = NULL;
171 0 : ls_elevation = NULL;
172 : }
173 :
174 97 : DirAtten_p = pBinRendTd->DirAtten_p;
175 :
176 718 : for ( nS = 0; nS < nchan_rend; nS++ )
177 : {
178 : /* Set source positions according to loudspeaker layout */
179 621 : angles_to_vec( 1.0f, ls_azimuth[nS], ls_elevation[nS], Pos );
180 621 : Dir[0] = 1.0f;
181 621 : Dir[1] = 0.0f;
182 621 : Dir[2] = 0.0f;
183 :
184 : /* Source directivity info */
185 621 : DirAtten_p->ConeInnerAngle = 360.0f;
186 621 : DirAtten_p->ConeOuterAngle = 360.0f;
187 621 : DirAtten_p->ConeOuterGain = 1.0f;
188 :
189 621 : DistAtten.DistAttenModel = TDREND_DIST_ATTEN_MODEL_INV_DIST_CLAMPED;
190 621 : DistAtten.MaxDist = 15.75f;
191 621 : DistAtten.RefDist = 1.0f;
192 621 : DistAtten.RollOffFactor = 1.0f;
193 :
194 621 : if ( ( error = TDREND_MIX_SRC_SetPos( pBinRendTd, nS, Pos ) ) != IVAS_ERR_OK )
195 : {
196 0 : return error;
197 : }
198 :
199 621 : if ( ( error = TDREND_MIX_SRC_SetDir( pBinRendTd, nS, Dir ) ) != IVAS_ERR_OK )
200 : {
201 0 : return error;
202 : }
203 :
204 621 : if ( ( error = TDREND_MIX_SRC_SetPlayState( pBinRendTd, nS, TDREND_PLAYSTATUS_PLAYING ) ) != IVAS_ERR_OK )
205 : {
206 0 : return error;
207 : }
208 :
209 621 : if ( ( error = TDREND_MIX_SRC_SetDirAtten( pBinRendTd, nS, DirAtten_p ) ) != IVAS_ERR_OK )
210 : {
211 0 : return error;
212 : }
213 621 : if ( ( error = TDREND_MIX_SRC_SetDistAtten( pBinRendTd, nS, &DistAtten ) ) != IVAS_ERR_OK )
214 : {
215 0 : return error;
216 : }
217 : }
218 : }
219 :
220 2427 : if ( ivas_format == ISM_FORMAT || ivas_format == MASA_ISM_FORMAT || ivas_format == SBA_ISM_FORMAT )
221 : {
222 2330 : DirAtten_p = pBinRendTd->DirAtten_p;
223 :
224 6997 : for ( nS = 0; nS < nchan_rend; nS++ )
225 : {
226 4667 : if ( NULL == directivity )
227 : {
228 570 : DirAtten_p->ConeInnerAngle = 360.0f; /* Front cone */
229 570 : DirAtten_p->ConeOuterAngle = 360.0f; /* Back cone */
230 570 : DirAtten_p->ConeOuterGain = 1.0f; /* Back attenuation */
231 : }
232 : else
233 : {
234 4097 : DirAtten_p->ConeInnerAngle = directivity[nS * 3];
235 4097 : DirAtten_p->ConeOuterAngle = directivity[nS * 3 + 1];
236 4097 : DirAtten_p->ConeOuterGain = directivity[nS * 3 + 2];
237 : }
238 4667 : if ( NULL == distAtt )
239 : {
240 570 : DistAtten.DistAttenModel = TDREND_DIST_ATTEN_MODEL_INV_DIST_CLAMPED;
241 570 : DistAtten.MaxDist = 15.75f;
242 570 : DistAtten.RefDist = 1.0f;
243 570 : DistAtten.RollOffFactor = 1.0f;
244 : }
245 : else
246 : {
247 4097 : DistAtten.DistAttenModel = TDREND_DIST_ATTEN_MODEL_INV_DIST_CLAMPED;
248 4097 : DistAtten.MaxDist = distAtt[0];
249 4097 : DistAtten.RefDist = distAtt[1];
250 4097 : DistAtten.RollOffFactor = distAtt[2];
251 : }
252 4667 : if ( ( error = TDREND_MIX_SRC_SetDirAtten( pBinRendTd, nS, DirAtten_p ) ) != IVAS_ERR_OK )
253 : {
254 0 : return error;
255 : }
256 4667 : if ( ( error = TDREND_MIX_SRC_SetDistAtten( pBinRendTd, nS, &DistAtten ) ) != IVAS_ERR_OK )
257 : {
258 0 : return error;
259 : }
260 : }
261 : }
262 :
263 2427 : *hBinRendererTd = pBinRendTd;
264 :
265 2427 : if ( ivas_format != MASA_ISM_FORMAT && ivas_format != SBA_ISM_FORMAT )
266 : {
267 1758 : *binaural_latency_ns = (int32_t) ( ( *hBinRendererTd )->HrFiltSet_p->latency_s * 1000000000.f );
268 : }
269 :
270 2427 : return error;
271 : }
272 :
273 :
274 : /*---------------------------------------------------------------------*
275 : * ivas_td_binaural_close()
276 : *
277 : * Close TD Object binaural renderer
278 : *---------------------------------------------------------------------*/
279 :
280 38955 : void ivas_td_binaural_close(
281 : BINAURAL_TD_OBJECT_RENDERER_HANDLE *hBinRendererTd /* i/o: TD binaural object renderer handle */
282 : )
283 : {
284 38955 : if ( hBinRendererTd == NULL || *hBinRendererTd == NULL )
285 : {
286 36528 : return;
287 : }
288 :
289 2427 : free( ( *hBinRendererTd )->TdRend_MixSpatSpec_p );
290 2427 : free( ( *hBinRendererTd )->DirAtten_p );
291 :
292 2427 : TDREND_MIX_Dealloc( *hBinRendererTd );
293 :
294 2427 : free( *hBinRendererTd );
295 2427 : *hBinRendererTd = NULL;
296 :
297 2427 : return;
298 : }
299 :
300 :
301 : /*---------------------------------------------------------------------*
302 : * ivas_td_binaural_renderer_unwrap()
303 : *
304 : * Call ivas_td_binaural_renderer() without st_ivas.
305 : *---------------------------------------------------------------------*/
306 :
307 649008 : 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 649008 : enableCombinedOrientation = NULL;
334 649008 : Quaternions = NULL;
335 649008 : Pos = NULL;
336 649008 : if ( hCombinedOrientationData != NULL )
337 : {
338 336004 : enableCombinedOrientation = hCombinedOrientationData->enableCombinedOrientation;
339 336004 : Quaternions = hCombinedOrientationData->Quaternions;
340 336004 : Pos = hCombinedOrientationData->listenerPos;
341 : }
342 :
343 1947024 : for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
344 : {
345 1298016 : p_reverb_signal[ch] = reverb_signal[ch];
346 : }
347 :
348 649008 : subframe_length = output_frame / num_subframes;
349 :
350 649008 : c_indx = 0;
351 1773136 : for ( nS = 0; nS < num_src; nS++ )
352 : {
353 1124128 : if ( !( ivas_format == MC_FORMAT && nS == lfe_idx ) ) /* Skip LFE for MC */
354 : {
355 1101128 : hBinRendererTd->Sources[c_indx]->InputFrame_p = output[nS];
356 1101128 : hBinRendererTd->Sources[c_indx]->SrcRend_p->InputAvailable = TRUE;
357 1101128 : c_indx++;
358 : }
359 : }
360 :
361 1687428 : for ( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
362 : {
363 1038420 : if ( subframe_idx == ism_md_subframe_update )
364 : {
365 : /* Update object position(s) */
366 649008 : 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 1038420 : 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 1038420 : if ( hReverb != NULL )
379 : {
380 498400 : 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 1038420 : 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 1038420 : c_indx = 0;
394 2837140 : for ( nS = 0; nS < num_src; nS++ )
395 : {
396 1798720 : if ( !( ivas_format == MC_FORMAT && nS == lfe_idx ) ) /* Skip LFE for MC */
397 : {
398 1761920 : hBinRendererTd->Sources[c_indx]->InputFrame_p += subframe_length;
399 1761920 : c_indx++;
400 : }
401 : }
402 :
403 : /* update combined orientation access index */
404 1038420 : ivas_combined_orientation_update_index( hCombinedOrientationData, subframe_length );
405 : }
406 :
407 649008 : if ( hReverb != NULL )
408 : {
409 : /* add reverb to rendered signals */
410 311500 : v_add( reverb_signal[0], output[0], output[0], output_frame );
411 311500 : v_add( reverb_signal[1], output[1], output[1], output_frame );
412 : }
413 :
414 649008 : return IVAS_ERR_OK;
415 : }
416 :
417 :
418 : /*---------------------------------------------------------------------*
419 : * TDREND_GetMix()
420 : *
421 : * Render one 5 ms subframe from the mixer
422 : *---------------------------------------------------------------------*/
423 :
424 1583868 : 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 1583868 : error = IVAS_ERR_OK;
443 :
444 : /* Clear the output buffer to accumulate rendered sources */
445 1583868 : set_f( output_buf[0], 0.0f, subframe_length );
446 1583868 : set_f( output_buf[1], 0.0f, subframe_length );
447 :
448 : /* Clear interpolation buffers and counter */
449 1583868 : set_f( hrf_left_delta, 0.0f, SFX_SPAT_BIN_MAX_FILTER_LENGTH );
450 1583868 : set_f( hrf_right_delta, 0.0f, SFX_SPAT_BIN_MAX_FILTER_LENGTH );
451 1583868 : intp_count = 0;
452 :
453 : /* Create the mix */
454 : /* Loop through the source list and render each source */
455 5045195 : for ( i = 0; i < hBinRendererTd->NumOfSrcs; i++ )
456 : {
457 3461327 : Src_p = hBinRendererTd->Sources[i];
458 3461327 : SrcSpatial_p = Src_p->SrcSpatial_p;
459 3461327 : SrcRend_p = Src_p->SrcRend_p;
460 :
461 : /* Update rendering params if needed */
462 3461327 : if ( ( SrcRend_p->PlayStatus == TDREND_PLAYSTATUS_PLAYING ) && ( hBinRendererTd->Listener_p->PoseUpdated || SrcSpatial_p->Updated ) )
463 : {
464 2139222 : TDREND_SRC_REND_UpdateFiltersFromSpatialParams( hBinRendererTd, SrcRend_p, SrcSpatial_p, Src_p->hrf_left_prev,
465 2139222 : 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 2139222 : if ( Src_p->itd * Src_p->previtd < 0 )
469 : {
470 99684 : currShift = (int16_t) abs( Src_p->itd );
471 99684 : prevShift = (int16_t) abs( Src_p->previtd );
472 99684 : transition_len = subframe_length - max( 0, SFX_SPAT_BIN_SINC_M - currShift );
473 99684 : length_in2 = transition_len - (int16_t) ( ( (float) ( transition_len * prevShift ) / ( (float) ( prevShift + currShift ) ) ) + 0.5f ) - currShift;
474 99684 : 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 3461327 : if ( ( SrcRend_p->InputAvailable == TRUE ) && ( SrcRend_p->PlayStatus == TDREND_PLAYSTATUS_PLAYING ) )
484 : {
485 3461327 : 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 1583868 : mvr2r( output_buf[0], output[0] + subframe_idx * subframe_length, subframe_length ); /* Left */
491 1583868 : mvr2r( output_buf[1], output[1] + subframe_idx * subframe_length, subframe_length ); /* Right */
492 :
493 : /* Clear the PoseUpdated and Source position update flags */
494 1583868 : TDREND_Clear_Update_flags( hBinRendererTd );
495 :
496 1583868 : return error;
497 : }
498 :
499 :
500 : /*---------------------------------------------------------------------*
501 : * TDREND_Clear_Update_flags()
502 : *
503 : * Initializes the audio mixer module
504 : *---------------------------------------------------------------------*/
505 :
506 1583868 : 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 1583868 : hBinRendererTd->Listener_p->PoseUpdated = FALSE;
513 :
514 5045195 : for ( i = 0; i < hBinRendererTd->NumOfSrcs; i++ )
515 : {
516 3461327 : hBinRendererTd->Sources[i]->SrcSpatial_p->Updated = FALSE;
517 3461327 : hBinRendererTd->Sources[i]->SrcRend_p->SrcGainUpdated = FALSE;
518 : }
519 :
520 1583868 : return;
521 : }
522 :
523 :
524 : /*---------------------------------------------------------------------*
525 : * TDREND_Update_object_positions()
526 : *
527 : * Update object position(s)
528 : *---------------------------------------------------------------------*/
529 :
530 785586 : 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 : TDREND_DirAtten_t *DirAtten_p;
538 : int16_t nS;
539 : float Pos[3];
540 : float Dir[3];
541 : ivas_error error;
542 :
543 785586 : DirAtten_p = hBinRendererTd->DirAtten_p;
544 :
545 : /* For each source, write the frame data to the source object*/
546 2344705 : for ( nS = 0; nS < num_src; nS++ )
547 : {
548 1559119 : if ( in_format == ISM_FORMAT || in_format == MASA_ISM_FORMAT || in_format == SBA_ISM_FORMAT )
549 : {
550 : /* Update the source positions */
551 : /* Source position and direction */
552 978015 : angles_to_vec( hIsmMetaData[nS]->radius, hIsmMetaData[nS]->azimuth, hIsmMetaData[nS]->elevation, Pos );
553 978015 : angles_to_vec( 1.0f, hIsmMetaData[nS]->yaw, hIsmMetaData[nS]->pitch, Dir );
554 :
555 978015 : if ( ( error = TDREND_MIX_SRC_SetPos( hBinRendererTd, nS, Pos ) ) != IVAS_ERR_OK )
556 : {
557 0 : return error;
558 : }
559 :
560 978015 : if ( ( error = TDREND_MIX_SRC_SetDirAtten( hBinRendererTd, nS, DirAtten_p ) ) != IVAS_ERR_OK )
561 : {
562 0 : return error;
563 : }
564 :
565 978015 : if ( ( error = TDREND_MIX_SRC_SetGain( hBinRendererTd, nS, hIsmMetaData[nS]->gain ) ) != IVAS_ERR_OK )
566 : {
567 0 : return error;
568 : }
569 :
570 978015 : if ( hIsmMetaData[nS]->non_diegetic_flag )
571 : {
572 2484 : Pos[0] = 0;
573 2484 : Pos[1] = hIsmMetaData[nS]->azimuth / 90.f;
574 2484 : Pos[2] = 0;
575 2484 : if ( ( error = TDREND_MIX_SRC_SetPos( hBinRendererTd, nS, Pos ) ) != IVAS_ERR_OK )
576 : {
577 0 : return error;
578 : }
579 2484 : hBinRendererTd->Sources[nS]->SrcSpatial_p->PosType = TDREND_POSTYPE_NON_DIEGETIC;
580 : }
581 : else
582 : {
583 975531 : hBinRendererTd->Sources[nS]->SrcSpatial_p->PosType = TDREND_POSTYPE_ABSOLUTE;
584 : }
585 :
586 978015 : if ( ( error = TDREND_MIX_SRC_SetDir( hBinRendererTd, nS, Dir ) ) != IVAS_ERR_OK )
587 : {
588 0 : return error;
589 : }
590 : }
591 : }
592 :
593 785586 : return IVAS_ERR_OK;
594 : }
595 :
596 :
597 : /*---------------------------------------------------------------------*
598 : * TDREND_Update_listener_orientation()
599 : *
600 : * Update listener orientation (s)
601 : *---------------------------------------------------------------------*/
602 :
603 1583868 : ivas_error TDREND_Update_listener_orientation(
604 : BINAURAL_TD_OBJECT_RENDERER_HANDLE hBinRendererTd, /* i/o: TD Renderer handle */
605 : const int16_t headRotEnabled, /* i : Headrotation flag */
606 : const IVAS_QUATERNION *headPosition, /* i : Listener orientation */
607 : const IVAS_VECTOR3 *Pos /* i : Listener Position */
608 : )
609 : {
610 : float FrontVec[3];
611 : float UpVec[3];
612 : float Rmat[3][3];
613 : float Pos_p[3];
614 : ivas_error error;
615 :
616 1583868 : if ( headRotEnabled )
617 : {
618 : /* Obtain head rotation matrix */
619 794617 : QuatToRotMat( *headPosition, Rmat );
620 : /* Apply rotation matrix to looking vector [1;0;0] */
621 794617 : FrontVec[0] = Rmat[0][0];
622 794617 : FrontVec[1] = Rmat[0][1];
623 794617 : FrontVec[2] = Rmat[0][2];
624 : /* Apply rotation matrix to up vector [0;0;1] */
625 794617 : UpVec[0] = Rmat[2][0];
626 794617 : UpVec[1] = Rmat[2][1];
627 794617 : UpVec[2] = Rmat[2][2];
628 794617 : if ( Pos != NULL )
629 : {
630 : /* Input position */
631 794617 : Pos_p[0] = ( *Pos ).x;
632 794617 : Pos_p[1] = ( *Pos ).y;
633 794617 : Pos_p[2] = ( *Pos ).z;
634 : }
635 : else
636 : {
637 : /* Listener at the origin */
638 0 : Pos_p[0] = 0.0f;
639 0 : Pos_p[1] = 0.0f;
640 0 : Pos_p[2] = 0.0f;
641 : }
642 : }
643 : else
644 : {
645 : /* Oriented with looking vector along the x axis */
646 789251 : FrontVec[0] = 1.0f;
647 789251 : FrontVec[1] = 0.0f;
648 789251 : FrontVec[2] = 0.0f;
649 : /* Oriented with up vector along the z axis */
650 789251 : UpVec[0] = 0.0f;
651 789251 : UpVec[1] = 0.0f;
652 789251 : UpVec[2] = 1.0f;
653 : /* Listener at the origin */
654 789251 : Pos_p[0] = 0.0f;
655 789251 : Pos_p[1] = 0.0f;
656 789251 : Pos_p[2] = 0.0f;
657 : }
658 :
659 : /* Set the listener position and orientation:*/
660 1583868 : TDREND_MIX_LIST_SetPos( hBinRendererTd, Pos_p );
661 1583868 : error = TDREND_MIX_LIST_SetOrient( hBinRendererTd, FrontVec, UpVec );
662 :
663 1583868 : return error;
664 : }
665 :
666 :
667 : /*---------------------------------------------------------------------*
668 : * ivas_td_binaural_open_ext()
669 : *
670 : *
671 : *---------------------------------------------------------------------*/
672 :
673 1434 : ivas_error ivas_td_binaural_open_ext(
674 : TDREND_WRAPPER *pTDRend,
675 : AUDIO_CONFIG inConfig,
676 : RENDER_CONFIG_DATA *hRendCfg, /* i : Renderer configuration */
677 : LSSETUP_CUSTOM_STRUCT *customLsInput,
678 : const int32_t outFs )
679 : {
680 : int16_t nchan_transport;
681 : AUDIO_CONFIG transport_config;
682 : IVAS_FORMAT ivas_format;
683 : IVAS_OUTPUT_SETUP hTransSetup;
684 : ivas_error error;
685 :
686 1434 : float *distAtt = NULL;
687 1434 : float *directivity = NULL;
688 :
689 1434 : if ( inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM )
690 : {
691 1386 : if ( ( error = getAudioConfigNumChannels( inConfig, &nchan_transport ) ) != IVAS_ERR_OK )
692 : {
693 0 : return error;
694 : }
695 : }
696 : else
697 : {
698 48 : nchan_transport = customLsInput->num_spk;
699 : }
700 :
701 1434 : transport_config = inConfig;
702 1434 : ivas_format = ( getAudioConfigType( inConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) ? MC_FORMAT : ISM_FORMAT;
703 :
704 1434 : hTransSetup.ls_azimuth = NULL;
705 1434 : hTransSetup.ls_elevation = NULL;
706 :
707 1434 : if ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
708 : {
709 48 : hTransSetup.ls_azimuth = customLsInput->ls_azimuth;
710 48 : hTransSetup.ls_elevation = customLsInput->ls_elevation;
711 : }
712 :
713 1434 : if ( NULL != hRendCfg )
714 : {
715 864 : directivity = hRendCfg->directivity;
716 864 : distAtt = hRendCfg->distAtt;
717 : }
718 :
719 1434 : return ivas_td_binaural_open_unwrap( pTDRend->hHrtfTD, outFs, nchan_transport, ivas_format, transport_config, directivity, distAtt, hTransSetup, &pTDRend->hBinRendererTd, &pTDRend->binaural_latency_ns );
720 : }
721 :
722 :
723 : /*---------------------------------------------------------------------*
724 : * ivas_td_binaural_renderer_ext()
725 : *
726 : * Receives the current frames for the object streams, updates metadata
727 : * and renders the current frame.
728 : *---------------------------------------------------------------------*/
729 :
730 649008 : ivas_error ivas_td_binaural_renderer_ext(
731 : const TDREND_WRAPPER *pTDRend, /* i : TD Renderer wrapper structure */
732 : const AUDIO_CONFIG inConfig, /* i : Input audio configuration */
733 : const LSSETUP_CUSTOM_STRUCT *customLsInput, /* i : Input custom loudspeaker layout */
734 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */
735 : const IVAS_ISM_METADATA *currentPos, /* i : Object position */
736 : const REVERB_HANDLE hReverb, /* i : Reverberator handle */
737 : const int16_t ism_md_subframe_update_ext, /* i : Metadata Delay in subframes to sync with audio delay */
738 : const int32_t output_Fs, /* i : output sampling rate */
739 : const int16_t output_frame, /* i : output frame length */
740 : float output[][L_FRAME48k] /* i/o: SCE channels / Binaural synthesis */
741 : )
742 : {
743 : ISM_METADATA_FRAME hIsmMetaDataFrame;
744 : ISM_METADATA_HANDLE hIsmMetaData[1];
745 : int16_t lfe_idx;
746 : int16_t num_src;
747 : IVAS_FORMAT ivas_format;
748 : IVAS_REND_AudioConfigType inConfigType;
749 : AUDIO_CONFIG transport_config;
750 : ivas_error error;
751 : float *p_output[MAX_OUTPUT_CHANNELS];
752 : int16_t ch;
753 :
754 11033136 : for ( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
755 : {
756 10384128 : p_output[ch] = output[ch];
757 : }
758 :
759 649008 : push_wmops( "ivas_td_binaural_renderer_ext" );
760 :
761 649008 : inConfigType = getAudioConfigType( inConfig );
762 649008 : lfe_idx = LFE_CHANNEL;
763 649008 : hIsmMetaData[0] = NULL;
764 :
765 :
766 649008 : if ( inConfigType == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
767 : {
768 49008 : ivas_format = MC_FORMAT;
769 49008 : transport_config = inConfig;
770 49008 : if ( inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM )
771 : {
772 23000 : if ( ( error = getAudioConfigNumChannels( inConfig, &num_src ) ) != IVAS_ERR_OK )
773 : {
774 0 : return error;
775 : }
776 : }
777 : else
778 : {
779 26008 : lfe_idx = ( customLsInput->num_lfe > 0 ) ? customLsInput->lfe_idx[0] : -1;
780 26008 : num_src = customLsInput->num_spk + customLsInput->num_lfe;
781 : }
782 : }
783 : else
784 : {
785 600000 : ivas_format = ISM_FORMAT;
786 600000 : num_src = 1;
787 600000 : transport_config = IVAS_AUDIO_CONFIG_ISM1;
788 600000 : hIsmMetaData[0] = &hIsmMetaDataFrame;
789 600000 : hIsmMetaData[0]->azimuth = currentPos->azimuth;
790 600000 : hIsmMetaData[0]->elevation = currentPos->elevation;
791 600000 : hIsmMetaData[0]->yaw = currentPos->yaw;
792 600000 : hIsmMetaData[0]->pitch = currentPos->pitch;
793 600000 : hIsmMetaData[0]->radius = currentPos->radius;
794 600000 : hIsmMetaData[0]->gain = 1.0f;
795 :
796 600000 : hIsmMetaData[0]->non_diegetic_flag = currentPos->non_diegetic_flag;
797 : }
798 :
799 649008 : if ( ( error = ivas_td_binaural_renderer_unwrap( hReverb, transport_config, pTDRend->hBinRendererTd, num_src, lfe_idx, ivas_format, hIsmMetaData, *hCombinedOrientationData,
800 649008 : 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 )
801 : {
802 0 : return error;
803 : }
804 :
805 649008 : pop_wmops();
806 :
807 649008 : return IVAS_ERR_OK;
808 : }
809 :
810 :
811 : /*---------------------------------------------------------------------*
812 : * angles_to_vec()
813 : *
814 : * Convert azimuth and elevation angles to position/orientation vector
815 : *---------------------------------------------------------------------*/
816 :
817 1956651 : static void angles_to_vec(
818 : const float radius, /* i : radius */
819 : const float azimuth, /* i : Azimuth angle */
820 : const float elevation, /* i : Elevation angle */
821 : float *vec /* o : Pos/Dir vector */
822 : )
823 : {
824 1956651 : vec[0] = radius * cosf( elevation * PI_OVER_180 ) * cosf( azimuth * PI_OVER_180 );
825 1956651 : vec[1] = radius * cosf( elevation * PI_OVER_180 ) * sinf( azimuth * PI_OVER_180 );
826 1956651 : vec[2] = radius * sinf( elevation * PI_OVER_180 );
827 :
828 1956651 : return;
829 : }
|