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_cnst.h"
34 : #include <assert.h>
35 : #include <stdint.h>
36 : #include "options.h"
37 : #include <math.h>
38 : #include "cnst.h"
39 : #include "prot.h"
40 : #include "ivas_prot.h"
41 : #include "ivas_prot_rend.h"
42 : #ifdef DEBUGGING
43 : #include "debug.h"
44 : #endif
45 : #include "wmc_auto.h"
46 :
47 :
48 : /*-----------------------------------------------------------------------*
49 : * Local funtion declarations
50 : *-----------------------------------------------------------------------*/
51 :
52 :
53 : static ivas_error combine_external_and_head_orientations( IVAS_QUATERNION *headRotQuaternions, IVAS_VECTOR3 *listenerPos, ISAR_SPLIT_REND_ROT_AXIS sr_pose_pred_axis, EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, COMBINED_ORIENTATION_HANDLE hCombinedOrientationData );
54 :
55 : static void external_target_interpolation( EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, const int16_t i );
56 :
57 : static bool are_orientations_same( const IVAS_QUATERNION *orientation1, const IVAS_QUATERNION *orientation2 );
58 :
59 :
60 : /*-----------------------------------------------------------------------*
61 : * ivas_headTrack_open()
62 : *
63 : * Allocate and initialize Head-Tracking handle
64 : *-----------------------------------------------------------------------*/
65 :
66 3709 : ivas_error ivas_headTrack_open(
67 : HEAD_TRACK_DATA_HANDLE *hHeadTrackData /* o : head track handle */
68 : )
69 : {
70 : int16_t i;
71 : ivas_error error;
72 :
73 : /* Allocate Head-Tracking handle */
74 3709 : if ( ( *hHeadTrackData = (HEAD_TRACK_DATA_HANDLE) malloc( sizeof( HEAD_TRACK_DATA ) ) ) == NULL )
75 : {
76 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for head-tracking memory\n" ) );
77 : }
78 :
79 : /* Initialization */
80 3709 : ( *hHeadTrackData )->lrSwitchInterpVal = 0.0f;
81 3709 : ( *hHeadTrackData )->lrSwitchedCurrent = 0;
82 3709 : ( *hHeadTrackData )->lrSwitchedNext = 0;
83 3709 : if ( ( ( *hHeadTrackData )->OrientationTracker = (ivas_orient_trk_state_t *) malloc( sizeof( ivas_orient_trk_state_t ) ) ) == NULL )
84 : {
85 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Orientation tracking" );
86 : }
87 :
88 3709 : if ( ( error = ivas_orient_trk_Init( ( *hHeadTrackData )->OrientationTracker ) ) != IVAS_ERR_OK )
89 : {
90 0 : return error;
91 : }
92 :
93 : /* Initialise Rmat_prev to I, Rmat will be computed later */
94 14836 : for ( i = 0; i < 3; i++ )
95 : {
96 11127 : set_zero( ( *hHeadTrackData )->Rmat_prev[i], 3 );
97 11127 : ( *hHeadTrackData )->Rmat_prev[i][i] = 1.0f;
98 : }
99 :
100 3709 : ( *hHeadTrackData )->sr_pose_pred_axis = DEFAULT_AXIS;
101 :
102 3709 : set_zero( ( *hHeadTrackData )->chEneIIR[0], MASA_FREQUENCY_BANDS );
103 3709 : set_zero( ( *hHeadTrackData )->chEneIIR[1], MASA_FREQUENCY_BANDS );
104 3709 : set_zero( ( *hHeadTrackData )->procChEneIIR[0], MASA_FREQUENCY_BANDS );
105 3709 : set_zero( ( *hHeadTrackData )->procChEneIIR[1], MASA_FREQUENCY_BANDS );
106 :
107 3709 : return IVAS_ERR_OK;
108 : }
109 :
110 :
111 : /*-----------------------------------------------------------------------*
112 : * ivas_headTrack_close()
113 : *
114 : * Deallocate Head-Tracking handle
115 : *-----------------------------------------------------------------------*/
116 :
117 89671 : void ivas_headTrack_close(
118 : HEAD_TRACK_DATA_HANDLE *hHeadTrackData /* i/o: head track handle */
119 : )
120 : {
121 89671 : if ( hHeadTrackData == NULL || *hHeadTrackData == NULL )
122 : {
123 85962 : return;
124 : }
125 :
126 3709 : if ( ( *hHeadTrackData )->OrientationTracker != NULL )
127 : {
128 3709 : free( ( *hHeadTrackData )->OrientationTracker );
129 3709 : ( *hHeadTrackData )->OrientationTracker = NULL;
130 : }
131 :
132 3709 : free( ( *hHeadTrackData ) );
133 3709 : *hHeadTrackData = NULL;
134 :
135 3709 : return;
136 : }
137 :
138 :
139 : /*----------------------------------------------------------------------------------
140 : * QuatToRotMat()
141 : *
142 : * Quaternion handling: calculate rotation matrices in real-space and SHD
143 : *---------------------------------------------------------------------------------*/
144 :
145 89000670 : void QuatToRotMat(
146 : const IVAS_QUATERNION quat, /* i : quaternion describing the rotation */
147 : float Rmat[3][3] /* o : real-space rotation matrix for this rotation */
148 : )
149 : {
150 89000670 : if ( quat.w == -3.0 )
151 : {
152 : IVAS_QUATERNION quat_local;
153 9154480 : Euler2Quat( deg2rad( quat.x ), deg2rad( quat.y ), deg2rad( quat.z ), &quat_local );
154 9154480 : QuatToRotMat( quat_local, Rmat );
155 : }
156 : else
157 : {
158 79846190 : Rmat[0][0] = quat.w * quat.w + quat.x * quat.x - quat.y * quat.y - quat.z * quat.z;
159 79846190 : Rmat[0][1] = 2.0f * ( quat.x * quat.y - quat.w * quat.z );
160 79846190 : Rmat[0][2] = 2.0f * ( quat.x * quat.z + quat.w * quat.y );
161 :
162 79846190 : Rmat[1][0] = 2.0f * ( quat.x * quat.y + quat.w * quat.z );
163 79846190 : Rmat[1][1] = quat.w * quat.w - quat.x * quat.x + quat.y * quat.y - quat.z * quat.z;
164 79846190 : Rmat[1][2] = 2.0f * ( quat.y * quat.z - quat.w * quat.x );
165 :
166 79846190 : Rmat[2][0] = 2.0f * ( quat.x * quat.z - quat.w * quat.y );
167 79846190 : Rmat[2][1] = 2.0f * ( quat.y * quat.z + quat.w * quat.x );
168 79846190 : Rmat[2][2] = quat.w * quat.w - quat.x * quat.x - quat.y * quat.y + quat.z * quat.z;
169 : }
170 :
171 89000670 : return;
172 : }
173 :
174 :
175 : /*-------------------------------------------------------------------------
176 : * rad2deg()
177 : *
178 : * Converts normalized radians to degrees
179 : *------------------------------------------------------------------------*/
180 :
181 20340 : float rad2deg(
182 : float radians )
183 : {
184 20553 : while ( radians >= EVS_PI )
185 : {
186 213 : radians = radians - EVS_PI;
187 : }
188 20340 : while ( radians <= -EVS_PI )
189 : {
190 0 : radians = radians + EVS_PI;
191 : }
192 :
193 20340 : return _180_OVER_PI * radians;
194 : }
195 :
196 :
197 : /*-------------------------------------------------------------------------
198 : * rotateAziEle()
199 : *
200 : * Apply rotation to direction parameters azimuth and elevation
201 : *------------------------------------------------------------------------*/
202 :
203 594296491 : void rotateAziEle(
204 : float azi_in, /* i : output elevation */
205 : float ele_in, /* i : input elevation */
206 : int16_t *azi, /* o : rotated azimuth */
207 : int16_t *ele, /* o : rotated elevation */
208 : float Rmat[3][3], /* i : real-space rotation matrix */
209 : const int16_t isPlanar /* i : is rotation planar and elevation meaningless? */
210 : )
211 : {
212 : int16_t n;
213 : float dv[3], dv_r[3];
214 : float w;
215 :
216 : /*Conversion spherical to cartesian coordinates*/
217 594296491 : w = cosf( ele_in * PI_OVER_180 );
218 594296491 : dv[0] = w * cosf( azi_in * PI_OVER_180 );
219 594296491 : dv[1] = w * sinf( azi_in * PI_OVER_180 );
220 594296491 : dv[2] = sinf( ele_in * PI_OVER_180 );
221 :
222 : /*Rotation mtx multiplication*/
223 2377185964 : for ( n = 0; n < 3; n++ )
224 : {
225 1782889473 : dv_r[n] = Rmat[n][0] * dv[0] + Rmat[n][1] * dv[1] + Rmat[n][2] * dv[2];
226 : }
227 :
228 : /*Conversion cartesian to spherical coordinates*/
229 594296491 : *azi = (int16_t) roundf( max( -180.0f, min( 180.0f, atan2f( dv_r[1], dv_r[0] ) * _180_OVER_PI ) ) );
230 594296491 : if ( isPlanar == 0 )
231 : {
232 585299715 : *ele = (int16_t) roundf( max( -90.0f, min( 90.0f, atan2f( dv_r[2], sqrtf( dv_r[0] * dv_r[0] + dv_r[1] * dv_r[1] ) ) * _180_OVER_PI ) ) );
233 : }
234 : else
235 : {
236 8996776 : *ele = 0;
237 : }
238 :
239 594296491 : return;
240 : }
241 :
242 :
243 : /*-------------------------------------------------------------------------
244 : * rotateFrame_shd()
245 : *
246 : * Apply rotation to signals in Spherical Harmonic Domain
247 : *------------------------------------------------------------------------*/
248 :
249 351720 : void rotateFrame_shd(
250 : COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : head and external orientation combined handle */
251 : float *output[], /* i/o: unrotated HOA3 signal buffer in TD */
252 : const int16_t subframe_len, /* i : subframe length per channel */
253 : const IVAS_OUTPUT_SETUP hTransSetup, /* i : format for rotation */
254 : const int16_t subframe_idx /* i : subframe index */
255 : )
256 : {
257 : int16_t i, l, n, m;
258 : int16_t m1, m2;
259 : int16_t shd_rot_max_order;
260 :
261 : float tmp;
262 : float tmpRot[2 * HEADROT_ORDER + 1];
263 : float SHrotmat_prev[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM];
264 : float SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM];
265 : float cross_fade[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES];
266 :
267 351720 : shd_rot_max_order = hTransSetup.ambisonics_order;
268 :
269 351720 : tmp = 1.0f / ( subframe_len - 1 );
270 84764520 : for ( i = 0; i < subframe_len; i++ )
271 : {
272 84412800 : cross_fade[i] = i * tmp;
273 : }
274 :
275 : /* initialize rotation matrices with zeros */
276 5979240 : for ( i = 0; i < HEADROT_SHMAT_DIM; i++ )
277 : {
278 5627520 : set_zero( SHrotmat_prev[i], HEADROT_SHMAT_DIM );
279 5627520 : set_zero( SHrotmat[i], HEADROT_SHMAT_DIM );
280 : }
281 :
282 : /* calculate ambisonics rotation matrices for the previous and current frames */
283 351720 : SHrotmatgen( SHrotmat_prev, hCombinedOrientationData->Rmat_prev[0], shd_rot_max_order );
284 :
285 351720 : SHrotmatgen( SHrotmat, hCombinedOrientationData->Rmat[hCombinedOrientationData->subframe_idx], shd_rot_max_order );
286 :
287 84764520 : for ( i = 0; i < subframe_len; i++ )
288 : {
289 : /*As the rotation matrix becomes block diagonal in a SH basis, we can
290 : apply each angular-momentum block individually to save complexity. */
291 :
292 : /* loop over l blocks */
293 84412800 : m1 = 1;
294 84412800 : m2 = 4;
295 337651200 : for ( l = 1; l <= shd_rot_max_order; l++ )
296 : {
297 : /* compute mtx-vector product for this l */
298 1519430400 : for ( n = m1; n < m2; n++ )
299 : {
300 1266192000 : tmpRot[n - m1] = 0.f;
301 :
302 8272454400 : for ( m = m1; m < m2; m++ )
303 : {
304 : /* crossfade with previous rotation gains */
305 7006262400 : tmpRot[n - m1] += cross_fade[i] * SHrotmat[n][m] * output[m][subframe_idx * subframe_len + i] + ( 1 - cross_fade[i] ) * SHrotmat_prev[n][m] * output[m][subframe_idx * subframe_len + i];
306 : }
307 : }
308 :
309 : /* write back the result */
310 1519430400 : for ( n = m1; n < m2; n++ )
311 : {
312 1266192000 : output[n][subframe_idx * subframe_len + i] = tmpRot[n - m1];
313 : }
314 253238400 : m1 = m2;
315 253238400 : m2 += 2 * ( l + 1 ) + 1;
316 : }
317 :
318 : /* unoptimized code for reference (full matrix multiplication)
319 : for ( n = 0; n < nchan; n++ )
320 : {
321 : tmpRot[n] = 0.f;
322 :
323 : for ( m = 0; m < nchan; m++ )
324 : {
325 : tmpRot[n] += SHrotmat[n][m] * output[m][i];
326 : }
327 : }
328 : for ( n = 0; n < nchan; n++ )
329 : {
330 : output[n][i] = tmpRot[n];
331 : }
332 : */
333 : }
334 :
335 : /* move Rmat to Rmat_prev */
336 1406880 : for ( i = 0; i < 3; i++ )
337 : {
338 1055160 : mvr2r(
339 1055160 : hCombinedOrientationData->Rmat[hCombinedOrientationData->subframe_idx][i],
340 1055160 : hCombinedOrientationData->Rmat_prev[0][i],
341 : 3 );
342 : }
343 :
344 351720 : return;
345 : }
346 :
347 :
348 : /*-------------------------------------------------------------------------
349 : * rotateFrame_sd()
350 : *
351 : * Apply rotation to signals in Spatial Domain
352 : *------------------------------------------------------------------------*/
353 :
354 454432 : void rotateFrame_sd(
355 : COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i : head and external orientation combined handle */
356 : float *output[], /* i/o: unrotated SD signal buffer in TD */
357 : const int16_t subframe_len, /* i : subframe length per channel */
358 : const IVAS_OUTPUT_SETUP hTransSetup, /* i : format for rotation */
359 : const EFAP_HANDLE hEFAPdata, /* i : EFAP structure */
360 : const int16_t subframe_idx /* i : subframe index */
361 : )
362 : {
363 : int16_t i, j;
364 : int16_t nchan, index_lfe;
365 : int16_t ch_in, ch_in_woLFE, ch_out, ch_out_woLFE;
366 : int16_t azimuth, elevation;
367 :
368 : float tmp;
369 : float tmp_gains[MAX_LS_CHANNELS - 1];
370 : float gains[MAX_LS_CHANNELS][MAX_LS_CHANNELS];
371 : float gains_prev[MAX_LS_CHANNELS][MAX_LS_CHANNELS];
372 : float output_tmp[MAX_LS_CHANNELS][L_FRAME48k];
373 : float cross_fade[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES];
374 454432 : push_wmops( "rotateFrame_sd" );
375 :
376 454432 : nchan = hTransSetup.nchan_out_woLFE + hTransSetup.num_lfe;
377 454432 : index_lfe = hTransSetup.index_lfe[0];
378 :
379 454432 : tmp = 1.0f / ( subframe_len - 1 );
380 109518112 : for ( i = 0; i < subframe_len; i++ )
381 : {
382 109063680 : cross_fade[i] = i * tmp;
383 : }
384 :
385 3181024 : for ( ch_in = 0; ch_in < nchan; ch_in++ )
386 : {
387 : /* zero output and gain buffers */
388 2726592 : set_zero( &output_tmp[ch_in][subframe_idx * subframe_len], subframe_len );
389 2726592 : set_zero( gains_prev[ch_in], nchan );
390 2726592 : set_zero( gains[ch_in], nchan );
391 :
392 : /* set gains to passthrough by default */
393 2726592 : gains_prev[ch_in][ch_in] = 1.0f;
394 2726592 : gains[ch_in][ch_in] = 1.0f;
395 :
396 : /* skip LFE */
397 2726592 : if ( ch_in == index_lfe )
398 : {
399 454432 : continue;
400 : }
401 :
402 : /* input channel index without LFE */
403 2272160 : ch_in_woLFE = ( ch_in >= index_lfe ) ? ch_in - 1 : ch_in;
404 :
405 : /* gains for previous subframe rotation */
406 2272160 : rotateAziEle( hTransSetup.ls_azimuth[ch_in_woLFE], hTransSetup.ls_elevation[ch_in_woLFE], &azimuth, &elevation, hCombinedOrientationData->Rmat_prev[0], hTransSetup.is_planar_setup );
407 :
408 2272160 : if ( hEFAPdata != NULL && ( hTransSetup.ls_azimuth[ch_in_woLFE] != azimuth || hTransSetup.ls_elevation[ch_in_woLFE] != elevation ) )
409 : {
410 1706655 : efap_determine_gains( hEFAPdata, tmp_gains, azimuth, elevation, EFAP_MODE_EFAP );
411 11946585 : for ( ch_out = 0; ch_out < nchan; ch_out++ )
412 : {
413 : /* skip LFE */
414 10239930 : if ( ch_out == index_lfe )
415 : {
416 1706655 : continue;
417 : }
418 :
419 : /* output channel index without LFE */
420 8533275 : ch_out_woLFE = ( ch_out >= index_lfe ) ? ch_out - 1 : ch_out;
421 :
422 8533275 : gains_prev[ch_in][ch_out] = tmp_gains[ch_out_woLFE];
423 : }
424 : }
425 :
426 : /* gains for current subframe rotation */
427 2272160 : rotateAziEle( hTransSetup.ls_azimuth[ch_in_woLFE], hTransSetup.ls_elevation[ch_in_woLFE], &azimuth, &elevation, hCombinedOrientationData->Rmat[hCombinedOrientationData->subframe_idx], hTransSetup.is_planar_setup );
428 :
429 2272160 : if ( hEFAPdata != NULL && ( hTransSetup.ls_azimuth[ch_in_woLFE] != azimuth || hTransSetup.ls_elevation[ch_in_woLFE] != elevation ) )
430 : {
431 1706775 : efap_determine_gains( hEFAPdata, tmp_gains, azimuth, elevation, EFAP_MODE_EFAP );
432 :
433 11947425 : for ( ch_out = 0; ch_out < nchan; ch_out++ )
434 : {
435 : /* skip LFE */
436 10240650 : if ( ch_out == index_lfe )
437 : {
438 1706775 : continue;
439 : }
440 :
441 : /* output channel index without LFE */
442 8533875 : ch_out_woLFE = ( ch_out >= index_lfe ) ? ch_out - 1 : ch_out;
443 :
444 8533875 : gains[ch_in][ch_out] = tmp_gains[ch_out_woLFE];
445 : }
446 : }
447 : }
448 :
449 : /* apply panning gains by mtx multiplication */
450 3181024 : for ( ch_out = 0; ch_out < nchan; ch_out++ )
451 : {
452 19086144 : for ( ch_in = 0; ch_in < nchan; ch_in++ )
453 : {
454 : /* crossfade with previous rotation gains */
455 3942652032 : for ( i = subframe_idx * subframe_len, j = 0; j < subframe_len; i++, j++ )
456 : {
457 3926292480 : output_tmp[ch_out][i] += ( cross_fade[j] ) * gains[ch_in][ch_out] * output[ch_in][i] + ( 1 - cross_fade[j] ) * gains_prev[ch_in][ch_out] * output[ch_in][i];
458 : }
459 : }
460 : }
461 :
462 : /* move Rmat to Rmat_prev */
463 1817728 : for ( i = 0; i < 3; i++ )
464 : {
465 1363296 : mvr2r(
466 1363296 : hCombinedOrientationData->Rmat[hCombinedOrientationData->subframe_idx][i],
467 1363296 : hCombinedOrientationData->Rmat_prev[0][i],
468 : 3 );
469 : }
470 :
471 : /* copy to output */
472 3181024 : for ( ch_out = 0; ch_out < nchan; ch_out++ )
473 : {
474 2726592 : mvr2r( &output_tmp[ch_out][subframe_idx * subframe_len], &output[ch_out][subframe_idx * subframe_len], subframe_len );
475 : }
476 :
477 454432 : pop_wmops();
478 454432 : return;
479 : }
480 :
481 :
482 : /*-------------------------------------------------------------------------
483 : * rotateFrame_shd_cldfb()
484 : *
485 : * Apply rotation to signals in Spherical Harmonic Domain and in CLDFB
486 : *------------------------------------------------------------------------*/
487 :
488 3152678 : void rotateFrame_shd_cldfb(
489 : float Cldfb_RealBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i/o: unrotated HOA3 signal buffer in cldfb domain real part */
490 : float Cldfb_ImagBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i/o: unrotated HOA3 signal buffer in cldfb domain imag part */
491 : float Rmat[3][3], /* i : real-space rotation matrix */
492 : const int16_t nInChannels, /* i : number of channels */
493 : const int16_t numTimeSlots, /* i : number of time slots to process */
494 : const int16_t shd_rot_max_order /* i : split-order rotation method */
495 : )
496 : {
497 3152678 : int16_t n = 0;
498 3152678 : int16_t m = 0;
499 3152678 : int16_t i = 0;
500 3152678 : int16_t iBand = 0;
501 3152678 : int16_t l = 0, m1 = 0, m2 = 0;
502 : float realRot[2 * HEADROT_ORDER + 1], imagRot[2 * HEADROT_ORDER + 1];
503 : float SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM];
504 :
505 3152678 : assert( ( nInChannels == HOA3_CHANNELS || nInChannels == HOA2_CHANNELS || nInChannels == FOA_CHANNELS ) &&
506 : "Number of channels must correspond to an ambisonics order!" );
507 :
508 : /* initialize rotation matrices with zeros */
509 53595526 : for ( i = 0; i < HEADROT_SHMAT_DIM; i++ )
510 : {
511 50442848 : set_zero( SHrotmat[i], HEADROT_SHMAT_DIM );
512 : }
513 :
514 : /* calculate Ambisonics rotation matrix from the quaternion */
515 3152678 : SHrotmatgen( SHrotmat, Rmat, shd_rot_max_order );
516 :
517 : /* rotation by mtx multiplication */
518 15392123 : for ( i = 0; i < numTimeSlots; i++ )
519 : {
520 746606145 : for ( iBand = 0; iBand < CLDFB_NO_CHANNELS_MAX; iBand++ )
521 : {
522 : /*As the rotation matrix becomes block diagonal in a SH basis, we can
523 : apply each angular-momentum block individually to save complexity. */
524 :
525 : /* loop over l blocks */
526 734366700 : m1 = 1;
527 734366700 : m2 = 4;
528 2937466800 : for ( l = 1; l <= shd_rot_max_order; l++ )
529 : {
530 : /* compute mtx-vector product for this l */
531 13218600600 : for ( n = m1; n < m2; n++ )
532 : {
533 11015500500 : realRot[n - m1] = 0.f;
534 11015500500 : imagRot[n - m1] = 0.f;
535 :
536 71967936600 : for ( m = m1; m < m2; m++ )
537 : {
538 60952436100 : realRot[n - m1] += SHrotmat[n][m] * Cldfb_RealBuffer[m][i][iBand];
539 60952436100 : imagRot[n - m1] += SHrotmat[n][m] * Cldfb_ImagBuffer[m][i][iBand];
540 : }
541 : }
542 : /* write back the result */
543 13218600600 : for ( n = m1; n < m2; n++ )
544 : {
545 11015500500 : Cldfb_RealBuffer[n][i][iBand] = realRot[n - m1];
546 11015500500 : Cldfb_ImagBuffer[n][i][iBand] = imagRot[n - m1];
547 : }
548 2203100100 : m1 = m2;
549 2203100100 : m2 += 2 * ( l + 1 ) + 1;
550 : }
551 :
552 : /* unoptimized code for reference (full matrix multiplication)
553 : for (n = 0; n < nInChannels; n++)
554 : {
555 : realRot[n] = 0.f;
556 : imagRot[n] = 0.f;
557 :
558 : for (m = 0; m < nInChannels; m++)
559 : {
560 : realRot[n] += SHrotmat[n][m] * Cldfb_RealBuffer[m][i][iBand];
561 : imagRot[n] += SHrotmat[n][m] * Cldfb_ImagBuffer[m][i][iBand];
562 : }
563 : }
564 : for (n = 0; n < nInChannels; n++)
565 : {
566 : Cldfb_RealBuffer[n][i][iBand] = realRot[n];
567 : Cldfb_ImagBuffer[n][i][iBand] = imagRot[n];
568 : }
569 : */
570 : }
571 : }
572 :
573 3152678 : return;
574 : }
575 :
576 :
577 : /*-------------------------------------------------------------------------
578 : * rotateFrame_sd_cldfb()
579 : *
580 : * Apply rotation to signals in Spatial Domain and in CLDFB
581 : *------------------------------------------------------------------------*/
582 :
583 227216 : void rotateFrame_sd_cldfb(
584 : float Rmat[3][3], /* i : real-space rotation matrix */
585 : float Cldfb_RealBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i/o: unrotated HOA3 signal buffer in cldfb domain real part */
586 : float Cldfb_ImagBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i/o: unrotated HOA3 signal buffer in cldfb domain imag part */
587 : const IVAS_OUTPUT_SETUP_HANDLE hOutputSetup, /* i : output format setup number of channels */
588 : const EFAP_HANDLE hEFAPdata, /* i : EFAP structure */
589 : const int16_t numTimeSlots, /* i : number of time slots to process */
590 : const int16_t nb_band /* i : number of CLDFB bands to process */
591 : )
592 : {
593 : int16_t iBlock, iBand, m, n;
594 : float gains[MAX_LS_CHANNELS - 1][MAX_LS_CHANNELS - 1];
595 : int16_t azimuth, elevation;
596 : float g1;
597 : float realRot[MAX_LS_CHANNELS - 1][MAX_PARAM_SPATIAL_SUBFRAMES * CLDFB_NO_CHANNELS_MAX];
598 : float imagRot[MAX_LS_CHANNELS - 1][MAX_PARAM_SPATIAL_SUBFRAMES * CLDFB_NO_CHANNELS_MAX];
599 : float *p_realRot, *p_imagRot;
600 : float *p_real, *p_imag;
601 : int16_t nInChannels;
602 : int16_t isPlanar;
603 227216 : push_wmops( "rotateFrame_sd_cldfb" );
604 :
605 227216 : nInChannels = hOutputSetup->nchan_out_woLFE;
606 227216 : isPlanar = 1;
607 1363296 : for ( n = 0; n < nInChannels; n++ )
608 : {
609 1136080 : if ( hOutputSetup->ls_elevation[n] != 0 )
610 : {
611 0 : isPlanar = 0;
612 0 : break;
613 : }
614 : }
615 :
616 : /* rotation of Euler angles */
617 1363296 : for ( n = 0; n < nInChannels; n++ )
618 : {
619 1136080 : rotateAziEle( hOutputSetup->ls_azimuth[n], hOutputSetup->ls_elevation[n], &azimuth, &elevation, Rmat, isPlanar );
620 1136080 : if ( hEFAPdata != NULL && ( hOutputSetup->ls_azimuth[n] != azimuth || hOutputSetup->ls_elevation[n] != elevation ) )
621 : {
622 976880 : efap_determine_gains( hEFAPdata, gains[n], azimuth, elevation, EFAP_MODE_EFAP );
623 : }
624 : else
625 : {
626 159200 : set_zero( gains[n], nInChannels );
627 159200 : gains[n][n] = 1.0f;
628 : }
629 : }
630 :
631 : /* Apply panning gains by mtx multiplication*/
632 1363296 : for ( n = 0; n < nInChannels; n++ )
633 : {
634 1136080 : set_zero( realRot[n], MAX_PARAM_SPATIAL_SUBFRAMES * nb_band );
635 1136080 : set_zero( imagRot[n], MAX_PARAM_SPATIAL_SUBFRAMES * nb_band );
636 6816480 : for ( m = 0; m < nInChannels; m++ )
637 : {
638 5680400 : g1 = gains[m][n];
639 5680400 : p_realRot = realRot[n];
640 5680400 : p_imagRot = imagRot[n];
641 5680400 : if ( g1 > 0.f )
642 : {
643 10522880 : for ( iBlock = 0; iBlock < numTimeSlots; iBlock++ )
644 : {
645 8418304 : p_real = Cldfb_RealBuffer[m][iBlock];
646 8418304 : p_imag = Cldfb_ImagBuffer[m][iBlock];
647 429333504 : for ( iBand = 0; iBand < nb_band; iBand++ )
648 : {
649 420915200 : *( p_realRot ) = *p_realRot + g1 * *( p_real++ );
650 420915200 : *( p_imagRot ) = *p_imagRot + g1 * *( p_imag++ );
651 420915200 : p_realRot++;
652 420915200 : p_imagRot++;
653 : }
654 : }
655 : }
656 : }
657 : }
658 :
659 1363296 : for ( n = 0; n < nInChannels; n++ )
660 : {
661 1136080 : p_realRot = realRot[n];
662 1136080 : p_imagRot = imagRot[n];
663 5680400 : for ( iBlock = 0; iBlock < numTimeSlots; iBlock++ )
664 : {
665 4544320 : p_real = Cldfb_RealBuffer[n][iBlock];
666 4544320 : p_imag = Cldfb_ImagBuffer[n][iBlock];
667 231760320 : for ( iBand = 0; iBand < nb_band; iBand++ )
668 : {
669 227216000 : *( p_real++ ) = *( p_realRot++ );
670 227216000 : *( p_imag++ ) = *( p_imagRot++ );
671 : }
672 49987520 : for ( ; iBand < CLDFB_NO_CHANNELS_MAX; iBand++ )
673 : {
674 45443200 : *( p_real++ ) = 0.f;
675 45443200 : *( p_imag++ ) = 0.f;
676 : }
677 : }
678 : }
679 227216 : pop_wmops();
680 :
681 227216 : return;
682 : }
683 :
684 :
685 : /*-----------------------------------------------------------------------*
686 : * ivas_external_orientation_open()
687 : *
688 : * Allocate and initialize external orientation handle
689 : *-----------------------------------------------------------------------*/
690 :
691 217 : ivas_error ivas_external_orientation_open(
692 : EXTERNAL_ORIENTATION_HANDLE *hExtOrientationData, /* o : external orientation handle */
693 : const int16_t num_subframes /* i : number of subframes */
694 : )
695 : {
696 :
697 : int16_t i;
698 : IVAS_QUATERNION identity;
699 :
700 217 : identity.w = 1.0f;
701 217 : identity.x = identity.y = identity.z = 0.0f;
702 :
703 : /* Allocate handle */
704 217 : if ( ( *hExtOrientationData = (EXTERNAL_ORIENTATION_HANDLE) malloc( sizeof( EXTERNAL_ORIENTATION_DATA ) ) ) == NULL )
705 : {
706 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for external orientation memory\n" ) );
707 : }
708 217 : ( *hExtOrientationData )->num_subframes = num_subframes;
709 :
710 : /* Enable head rotation and disable external orientation as default */
711 1085 : for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
712 : {
713 868 : ( *hExtOrientationData )->enableHeadRotation[i] = 1;
714 868 : ( *hExtOrientationData )->enableExternalOrientation[i] = 0;
715 868 : ( *hExtOrientationData )->enableRotationInterpolation[i] = 0;
716 868 : ( *hExtOrientationData )->numFramesToTargetOrientation[i] = 0;
717 868 : ( *hExtOrientationData )->Quaternions[i] = identity;
718 : }
719 :
720 217 : return IVAS_ERR_OK;
721 : }
722 :
723 :
724 : /*-----------------------------------------------------------------------*
725 : * ivas_external_orientation_close()
726 : *
727 : * Deallocate external orientation handle
728 : *-----------------------------------------------------------------------*/
729 :
730 105967 : void ivas_external_orientation_close(
731 : EXTERNAL_ORIENTATION_HANDLE *hExtOrientationData /* i/o: external orientation handle */
732 : )
733 : {
734 105967 : if ( hExtOrientationData == NULL || *hExtOrientationData == NULL )
735 : {
736 105750 : return;
737 : }
738 :
739 217 : free( ( *hExtOrientationData ) );
740 217 : *hExtOrientationData = NULL;
741 :
742 217 : return;
743 : }
744 :
745 :
746 : /*-----------------------------------------------------------------------*
747 : * ivas_combined_orientation_open()
748 : *
749 : * Allocate and initialize combined orientation handle
750 : *-----------------------------------------------------------------------*/
751 :
752 6800 : ivas_error ivas_combined_orientation_open(
753 : COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* o : combined orientation handle */
754 : const int32_t fs, /* i : sampling rate */
755 : const int16_t num_subframes /* i : number of subframes */
756 : )
757 : {
758 : int16_t i;
759 : int16_t j;
760 : IVAS_QUATERNION identity;
761 : IVAS_VECTOR3 origo;
762 : int16_t pos_idx;
763 :
764 6800 : identity.w = 1.0f;
765 6800 : identity.x = identity.y = identity.z = 0.0f;
766 6800 : origo.x = origo.y = origo.z = 0.0f;
767 :
768 : /* Allocate handle */
769 6800 : if ( ( *hCombinedOrientationData = (COMBINED_ORIENTATION_HANDLE) malloc( sizeof( COMBINED_ORIENTATION_DATA ) ) ) == NULL )
770 : {
771 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for combined orientation memory\n" ) );
772 : }
773 :
774 : /* Initialization */
775 6800 : ( *hCombinedOrientationData )->num_subframes = num_subframes;
776 6800 : ( *hCombinedOrientationData )->interpolationCoefficient = 1.0f;
777 6800 : ( *hCombinedOrientationData )->interpolationIncrement = 1.0f;
778 6800 : ( *hCombinedOrientationData )->maximumFramesToTargetOrientation = 500;
779 6800 : ( *hCombinedOrientationData )->lrSwitchedNext = 0;
780 6800 : ( *hCombinedOrientationData )->lrSwitchedCurrent = 0;
781 6800 : ( *hCombinedOrientationData )->lrSwitchInterpVal = 0.0f;
782 6800 : ( *hCombinedOrientationData )->isInterpolationOngoing = FALSE;
783 6800 : ( *hCombinedOrientationData )->Quaternions_ext_interpolation_start = identity;
784 6800 : ( *hCombinedOrientationData )->Quaternions_ext_interpolation_target = identity;
785 :
786 : /* Initialise orientations to identity */
787 34000 : for ( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
788 : {
789 27200 : ( *hCombinedOrientationData )->enableCombinedOrientation[i] = 0;
790 27200 : ( *hCombinedOrientationData )->Quaternions[i] = identity;
791 27200 : ( *hCombinedOrientationData )->listenerPos[i] = origo;
792 :
793 108800 : for ( j = 0; j < 3; j++ )
794 : {
795 81600 : set_zero( ( *hCombinedOrientationData )->Rmat[i][j], 3 );
796 81600 : ( *hCombinedOrientationData )->Rmat[i][j][j] = 1.0f;
797 : }
798 : }
799 :
800 61200 : for ( pos_idx = 0; pos_idx < MAX_HEAD_ROT_POSES; pos_idx++ )
801 : {
802 217600 : for ( j = 0; j < 3; j++ )
803 : {
804 163200 : set_zero( ( *hCombinedOrientationData )->Rmat_prev[pos_idx][j], 3 );
805 163200 : ( *hCombinedOrientationData )->Rmat_prev[pos_idx][j][j] = 1.0f;
806 : }
807 : }
808 6800 : ( *hCombinedOrientationData )->sr_pose_pred_axis = DEFAULT_AXIS;
809 6800 : ( *hCombinedOrientationData )->sr_low_res_flag = 0;
810 :
811 6800 : ( *hCombinedOrientationData )->Quaternion_prev_extOrientation = identity;
812 6800 : ( *hCombinedOrientationData )->Quaternion_frozen_ext = identity;
813 6800 : ( *hCombinedOrientationData )->Quaternion_frozen_head = identity;
814 :
815 :
816 6800 : set_zero( ( *hCombinedOrientationData )->chEneIIR[0], MASA_FREQUENCY_BANDS );
817 6800 : set_zero( ( *hCombinedOrientationData )->chEneIIR[1], MASA_FREQUENCY_BANDS );
818 6800 : set_zero( ( *hCombinedOrientationData )->procChEneIIR[0], MASA_FREQUENCY_BANDS );
819 6800 : set_zero( ( *hCombinedOrientationData )->procChEneIIR[1], MASA_FREQUENCY_BANDS );
820 :
821 6800 : ( *hCombinedOrientationData )->isExtOrientationFrozen = 0;
822 6800 : ( *hCombinedOrientationData )->isHeadRotationFrozen = 0;
823 :
824 6800 : ( *hCombinedOrientationData )->subframe_idx = 0;
825 6800 : ( *hCombinedOrientationData )->subframe_size = (int16_t) ( fs / ( FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ) );
826 6800 : ( *hCombinedOrientationData )->cur_subframe_samples_rendered = 0;
827 :
828 40800 : for ( i = 0; i < ( 1 + IVAS_MAX_NUM_OBJECTS ); i++ )
829 : {
830 34000 : ( *hCombinedOrientationData )->isDiegeticInputPI[i] = true;
831 : }
832 6800 : ( *hCombinedOrientationData )->isDiegeticInputPISet = false;
833 :
834 6800 : return IVAS_ERR_OK;
835 : }
836 :
837 :
838 : /*-----------------------------------------------------------------------*
839 : * ivas_combined_orientation_close()
840 : *
841 : * Deallocate combined orientation handle
842 : *-----------------------------------------------------------------------*/
843 :
844 105967 : void ivas_combined_orientation_close(
845 : COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData /* i/o: combined orientation handle */
846 : )
847 : {
848 105967 : if ( hCombinedOrientationData == NULL || *hCombinedOrientationData == NULL )
849 : {
850 99167 : return;
851 : }
852 :
853 6800 : free( ( *hCombinedOrientationData ) );
854 6800 : *hCombinedOrientationData = NULL;
855 :
856 6800 : return;
857 : }
858 :
859 :
860 : /*-------------------------------------------------------------------------
861 : * combine_external_and_head_orientations_dec()
862 : *
863 : *
864 : *------------------------------------------------------------------------*/
865 :
866 5784028 : ivas_error combine_external_and_head_orientations_dec(
867 : HEAD_TRACK_DATA_HANDLE hHeadTrackData, /* i : head track handle */
868 : EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */
869 : COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */
870 : )
871 : {
872 : ISAR_SPLIT_REND_ROT_AXIS sr_pose_pred_axis;
873 5784028 : IVAS_QUATERNION *pHeadRotQuaternion = NULL;
874 5784028 : IVAS_VECTOR3 *listenerPos = NULL;
875 :
876 5784028 : if ( hHeadTrackData != NULL )
877 : {
878 5784028 : pHeadRotQuaternion = hHeadTrackData->Quaternions;
879 5784028 : listenerPos = hHeadTrackData->Pos;
880 5784028 : sr_pose_pred_axis = hHeadTrackData->sr_pose_pred_axis;
881 : }
882 : else
883 : {
884 0 : sr_pose_pred_axis = DEFAULT_AXIS;
885 : }
886 :
887 5784028 : return combine_external_and_head_orientations( pHeadRotQuaternion, listenerPos, sr_pose_pred_axis, hExtOrientationData, hCombinedOrientationData );
888 : }
889 :
890 :
891 : /*-------------------------------------------------------------------------
892 : * combine_external_and_head_orientations_rend()
893 : *
894 : *
895 : *------------------------------------------------------------------------*/
896 :
897 100402549 : ivas_error combine_external_and_head_orientations_rend(
898 : IVAS_REND_HeadRotData *hHeadTrackData, /* i : head track handle */
899 : EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */
900 : COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */
901 : )
902 : {
903 : ISAR_SPLIT_REND_ROT_AXIS sr_pose_pred_axis;
904 100402549 : IVAS_QUATERNION *headRotQuaternions = NULL;
905 100402549 : IVAS_VECTOR3 *listenerPos = NULL;
906 : int16_t i;
907 :
908 100402549 : sr_pose_pred_axis = DEFAULT_AXIS;
909 100402549 : if ( hHeadTrackData->headRotEnabled )
910 : {
911 19588925 : headRotQuaternions = hHeadTrackData->headPositions;
912 19588925 : listenerPos = hHeadTrackData->Pos;
913 19588925 : sr_pose_pred_axis = hHeadTrackData->sr_pose_pred_axis;
914 : }
915 80813624 : else if ( hExtOrientationData != NULL )
916 : {
917 : /* Head rotation data not available, use the freezed value or disable */
918 0 : for ( i = 0; i < hExtOrientationData->num_subframes; i++ )
919 : {
920 0 : if ( hExtOrientationData->enableHeadRotation[i] != 2 )
921 : {
922 0 : hExtOrientationData->enableHeadRotation[i] = 0;
923 : }
924 : }
925 : }
926 :
927 100402549 : return combine_external_and_head_orientations( headRotQuaternions, listenerPos, sr_pose_pred_axis, hExtOrientationData, hCombinedOrientationData );
928 : }
929 :
930 :
931 : /*-------------------------------------------------------------------------
932 : * combine_external_and_head_orientations()
933 : *
934 : * Combine the external orientations and the head orientation.
935 : * NOTE that the external orientations are inversed.
936 : *------------------------------------------------------------------------*/
937 :
938 106186577 : ivas_error combine_external_and_head_orientations(
939 : IVAS_QUATERNION *headRotQuaternions, /* i : quaternions for head rotation */
940 : IVAS_VECTOR3 *listenerPos, /* i : listener position */
941 : ISAR_SPLIT_REND_ROT_AXIS sr_pose_pred_axis, /* i : split rend pose prediction axis */
942 : EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */
943 : COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */
944 : )
945 : {
946 : int16_t i;
947 : int16_t j;
948 : IVAS_QUATERNION identity;
949 : IVAS_VECTOR3 origo;
950 :
951 106186577 : identity.w = 1.0f;
952 106186577 : identity.x = identity.y = identity.z = 0.0f;
953 106186577 : origo.x = origo.y = origo.z = 0.0f;
954 :
955 : /* Form combined orientations or return if no data available */
956 106186577 : if ( hCombinedOrientationData == NULL )
957 : {
958 80813624 : if ( headRotQuaternions != NULL || hExtOrientationData != NULL )
959 : {
960 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
961 : }
962 : else
963 : {
964 80813624 : return IVAS_ERR_OK;
965 : }
966 : }
967 25372953 : else if ( headRotQuaternions == NULL && hExtOrientationData == NULL )
968 : {
969 : /* Reset the combined orientations and rotations */
970 0 : hCombinedOrientationData->isInterpolationOngoing = FALSE;
971 0 : hCombinedOrientationData->interpolationCoefficient = 1.0f;
972 0 : hCombinedOrientationData->interpolationIncrement = 1.0f;
973 0 : hCombinedOrientationData->Quaternions_ext_interpolation_start = identity;
974 0 : hCombinedOrientationData->Quaternions_ext_interpolation_target = identity;
975 0 : for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
976 : {
977 0 : hCombinedOrientationData->enableCombinedOrientation[i] = 0;
978 0 : hCombinedOrientationData->Quaternions[i] = identity;
979 0 : hCombinedOrientationData->listenerPos[i] = origo;
980 :
981 0 : for ( j = 0; j < 3; j++ )
982 : {
983 0 : set_zero( hCombinedOrientationData->Rmat[i][j], 3 );
984 0 : hCombinedOrientationData->Rmat[i][j][j] = 1.0f;
985 : }
986 : }
987 : }
988 25372953 : else if ( hExtOrientationData == NULL && headRotQuaternions != NULL )
989 : {
990 : /* Disable head rotation if diegetic PI data indicating non-diegetic audio is received */
991 23373063 : if ( hCombinedOrientationData->isDiegeticInputPISet && !hCombinedOrientationData->isDiegeticInputPI[0] && !hCombinedOrientationData->isDiegeticInputPI[1] && !hCombinedOrientationData->isDiegeticInputPI[2] && !hCombinedOrientationData->isDiegeticInputPI[3] && !hCombinedOrientationData->isDiegeticInputPI[4] )
992 : {
993 0 : for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
994 : {
995 0 : hCombinedOrientationData->Quaternions[i] = identity;
996 : }
997 : }
998 : else
999 : {
1000 : /* Head rotation only */
1001 59440139 : for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
1002 : {
1003 36067076 : hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i];
1004 : }
1005 : }
1006 : }
1007 :
1008 25372953 : if ( hExtOrientationData != NULL )
1009 : {
1010 : /* External orientations */
1011 5503930 : for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
1012 : {
1013 : /* Check for frozen external orientation */
1014 3504040 : if ( hExtOrientationData->enableExternalOrientation[i] == 2 )
1015 : {
1016 616674 : if ( hCombinedOrientationData->isExtOrientationFrozen != 1 )
1017 : {
1018 1104 : hCombinedOrientationData->Quaternion_frozen_ext = hExtOrientationData->Quaternions[i];
1019 1104 : hCombinedOrientationData->isExtOrientationFrozen = 1;
1020 : }
1021 : }
1022 : else
1023 : {
1024 2887366 : hCombinedOrientationData->Quaternion_frozen_ext = identity;
1025 2887366 : hCombinedOrientationData->isExtOrientationFrozen = 0;
1026 : }
1027 :
1028 3504040 : if ( hExtOrientationData->enableRotationInterpolation[i] == 1 && hExtOrientationData->enableExternalOrientation[i] > 0 )
1029 : {
1030 1580796 : if ( hCombinedOrientationData->isInterpolationOngoing == true && hCombinedOrientationData->interpolationCoefficient <= 1.0f && are_orientations_same( &hCombinedOrientationData->Quaternions_ext_interpolation_target, &hExtOrientationData->Quaternions[i] ) == true )
1031 : {
1032 : /* Continue interpolation */
1033 1391220 : QuaternionSlerp( hCombinedOrientationData->Quaternions_ext_interpolation_start, hCombinedOrientationData->Quaternions_ext_interpolation_target, hCombinedOrientationData->interpolationCoefficient, &hCombinedOrientationData->Quaternions[i] );
1034 1391220 : hCombinedOrientationData->interpolationCoefficient += hCombinedOrientationData->interpolationIncrement;
1035 : }
1036 : else
1037 : {
1038 : /* Stop interpolation or check for new interpolation */
1039 189576 : hCombinedOrientationData->isInterpolationOngoing = FALSE;
1040 189576 : hCombinedOrientationData->interpolationCoefficient = 1.0f;
1041 189576 : hCombinedOrientationData->interpolationIncrement = 1.0f;
1042 189576 : external_target_interpolation( hExtOrientationData, hCombinedOrientationData, i );
1043 : }
1044 : }
1045 : else
1046 : {
1047 : /* Interpolation disabled, use the current orientation values */
1048 :
1049 : /* Use the most recent external orientation */
1050 1923244 : if ( hExtOrientationData->enableExternalOrientation[i] == 1 )
1051 : {
1052 1221328 : hCombinedOrientationData->Quaternions[i] = hExtOrientationData->Quaternions[i];
1053 : }
1054 : /* Use the freezed external orientation */
1055 701916 : else if ( hExtOrientationData->enableExternalOrientation[i] == 2 )
1056 : {
1057 454170 : hCombinedOrientationData->Quaternions[i] = hCombinedOrientationData->Quaternion_frozen_ext;
1058 : }
1059 : }
1060 : }
1061 : }
1062 :
1063 25372953 : if ( hExtOrientationData != NULL && headRotQuaternions != NULL )
1064 : {
1065 : /* Combine head and external orientations */
1066 5503930 : for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
1067 : {
1068 : /* Check for frozen head rotation */
1069 3504040 : if ( hExtOrientationData->enableHeadRotation[i] == 2 )
1070 : {
1071 442914 : if ( hCombinedOrientationData->isHeadRotationFrozen != 1 )
1072 : {
1073 2238 : hCombinedOrientationData->Quaternion_frozen_head = headRotQuaternions[i];
1074 2238 : hCombinedOrientationData->isHeadRotationFrozen = 1;
1075 : }
1076 : }
1077 : else
1078 : {
1079 3061126 : hCombinedOrientationData->Quaternion_frozen_head = identity;
1080 3061126 : hCombinedOrientationData->isHeadRotationFrozen = 0;
1081 : }
1082 :
1083 : /* Disable head rotation if diegetic PI data indicating non-diegetic audio is received */
1084 3504040 : if ( hCombinedOrientationData->isDiegeticInputPISet && !hCombinedOrientationData->isDiegeticInputPI[0] && !hCombinedOrientationData->isDiegeticInputPI[1] && !hCombinedOrientationData->isDiegeticInputPI[2] && !hCombinedOrientationData->isDiegeticInputPI[3] && !hCombinedOrientationData->isDiegeticInputPI[4] )
1085 : {
1086 0 : continue;
1087 : }
1088 : else
1089 : {
1090 : /* Use the most recent head rotation */
1091 3504040 : if ( hExtOrientationData->enableHeadRotation[i] == 1 )
1092 : {
1093 2392047 : if ( hExtOrientationData->enableExternalOrientation[i] > 0 )
1094 : {
1095 2144301 : QuaternionProduct( hCombinedOrientationData->Quaternions[i], headRotQuaternions[i], &hCombinedOrientationData->Quaternions[i] );
1096 : }
1097 : else
1098 : {
1099 247746 : hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i];
1100 : }
1101 : }
1102 : /* Use the freezed head rotation */
1103 1111993 : else if ( hExtOrientationData->enableHeadRotation[i] == 2 )
1104 : {
1105 442914 : if ( hExtOrientationData->enableExternalOrientation[i] > 0 )
1106 : {
1107 442914 : QuaternionProduct( hCombinedOrientationData->Quaternions[i], hCombinedOrientationData->Quaternion_frozen_head, &hCombinedOrientationData->Quaternions[i] );
1108 : }
1109 : else
1110 : {
1111 0 : hCombinedOrientationData->Quaternions[i] = hCombinedOrientationData->Quaternion_frozen_head;
1112 : }
1113 : }
1114 : }
1115 :
1116 : /* Reset the combined orientations to identity */
1117 3504040 : if ( hExtOrientationData->enableHeadRotation[i] == 0 && hExtOrientationData->enableExternalOrientation[i] == 0 )
1118 : {
1119 0 : hCombinedOrientationData->Quaternions[i] = identity;
1120 : }
1121 : }
1122 : }
1123 :
1124 25372953 : if ( headRotQuaternions != NULL || hExtOrientationData != NULL )
1125 : {
1126 : /* Calculate the combined rotation matrix */
1127 64944069 : for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
1128 : {
1129 39571116 : QuatToRotMat( hCombinedOrientationData->Quaternions[i], hCombinedOrientationData->Rmat[i] );
1130 : }
1131 : }
1132 :
1133 : /* Save the current orientations */
1134 25372953 : if ( hExtOrientationData != NULL )
1135 : {
1136 1999890 : if ( hExtOrientationData->enableExternalOrientation[hExtOrientationData->num_subframes - 1] > 0 )
1137 : {
1138 1858140 : hCombinedOrientationData->Quaternion_prev_extOrientation = hExtOrientationData->Quaternions[hExtOrientationData->num_subframes - 1];
1139 : }
1140 : else
1141 : {
1142 141750 : hCombinedOrientationData->Quaternion_prev_extOrientation = identity;
1143 : }
1144 : }
1145 25372953 : if ( headRotQuaternions != NULL )
1146 : {
1147 64944069 : for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
1148 : {
1149 39571116 : hCombinedOrientationData->listenerPos[i] = listenerPos[i];
1150 : }
1151 : }
1152 :
1153 : /* Check if combined orientation is enabled */
1154 25372953 : if ( headRotQuaternions != NULL && hExtOrientationData == NULL )
1155 : {
1156 59440139 : for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
1157 : {
1158 36067076 : hCombinedOrientationData->enableCombinedOrientation[i] = 1;
1159 : }
1160 : }
1161 1999890 : else if ( headRotQuaternions == NULL && hExtOrientationData != NULL )
1162 : {
1163 0 : for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
1164 : {
1165 0 : if ( hExtOrientationData->enableExternalOrientation[i] > 0 )
1166 : {
1167 0 : hCombinedOrientationData->enableCombinedOrientation[i] = 1;
1168 : }
1169 : else
1170 : {
1171 0 : hCombinedOrientationData->enableCombinedOrientation[i] = 0;
1172 : }
1173 : }
1174 : }
1175 1999890 : else if ( headRotQuaternions != NULL && hExtOrientationData != NULL )
1176 : {
1177 5503930 : for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
1178 : {
1179 3504040 : if ( hExtOrientationData->enableExternalOrientation[i] > 0 || ( hExtOrientationData->enableHeadRotation[i] > 0 ) )
1180 : {
1181 3504040 : hCombinedOrientationData->enableCombinedOrientation[i] = 1;
1182 : }
1183 : else
1184 : {
1185 0 : hCombinedOrientationData->enableCombinedOrientation[i] = 0;
1186 : }
1187 : }
1188 : }
1189 : else
1190 : {
1191 0 : for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
1192 : {
1193 0 : hCombinedOrientationData->enableCombinedOrientation[i] = 0;
1194 : }
1195 : }
1196 :
1197 : #ifdef DEBUG_MODE_ORIENTATION
1198 : for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
1199 : {
1200 : dbgwrite( &hCombinedOrientationData->enableCombinedOrientation[i], sizeof( int16_t ), 1, 1, "res/dec_orientation_enabled.dat" );
1201 : dbgwrite( &( hCombinedOrientationData->Quaternions[i].w ), sizeof( float ), 1, 1, "res/dec_orientation_quaternion_w.dat" );
1202 : dbgwrite( &( hCombinedOrientationData->Quaternions[i].x ), sizeof( float ), 1, 1, "res/dec_orientation_quaternion_x.dat" );
1203 : dbgwrite( &( hCombinedOrientationData->Quaternions[i].y ), sizeof( float ), 1, 1, "res/dec_orientation_quaternion_y.dat" );
1204 : dbgwrite( &( hCombinedOrientationData->Quaternions[i].z ), sizeof( float ), 1, 1, "res/dec_orientation_quaternion_z.dat" );
1205 : }
1206 : #endif
1207 25372953 : hCombinedOrientationData->sr_pose_pred_axis = sr_pose_pred_axis;
1208 25372953 : hCombinedOrientationData->subframe_idx = 0;
1209 25372953 : hCombinedOrientationData->cur_subframe_samples_rendered = 0;
1210 25372953 : hCombinedOrientationData->subframe_idx_start = 0;
1211 25372953 : hCombinedOrientationData->cur_subframe_samples_rendered_start = 0;
1212 :
1213 : /* Reset external orientations */
1214 25372953 : if ( hExtOrientationData != NULL )
1215 : {
1216 5503930 : for ( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
1217 : {
1218 3504040 : hExtOrientationData->Quaternions[i] = identity;
1219 : }
1220 : }
1221 :
1222 25372953 : return IVAS_ERR_OK;
1223 : }
1224 :
1225 :
1226 : /*-------------------------------------------------------------------------
1227 : * external_target_interpolation()
1228 : *
1229 : *
1230 : *------------------------------------------------------------------------*/
1231 :
1232 189576 : static void external_target_interpolation(
1233 : EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, /* i : external orientation handle */
1234 : COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle */
1235 : const int16_t i /* i : subframe index */
1236 : )
1237 : {
1238 : /* Sanity check for number of frames */
1239 189576 : hExtOrientationData->numFramesToTargetOrientation[i] = min( hExtOrientationData->numFramesToTargetOrientation[i], hCombinedOrientationData->maximumFramesToTargetOrientation );
1240 189576 : hExtOrientationData->numFramesToTargetOrientation[i] = max( hExtOrientationData->numFramesToTargetOrientation[i], 0 );
1241 :
1242 : /* Interpolate from the current orientation to the target orientation */
1243 189576 : if ( hExtOrientationData->numFramesToTargetOrientation[i] > 0 )
1244 : {
1245 28794 : if ( are_orientations_same( &hCombinedOrientationData->Quaternions_ext_interpolation_target, &hExtOrientationData->Quaternions[i] ) == false )
1246 : {
1247 : /* Target orientation is different from the previous target, update the values */
1248 :
1249 : /* Set the received orientation as the target */
1250 7094 : hCombinedOrientationData->Quaternions_ext_interpolation_target = hExtOrientationData->Quaternions[i];
1251 :
1252 : /* Use the most recent external orientation as the starting orientation */
1253 7094 : if ( hExtOrientationData->enableExternalOrientation[i] == 1 )
1254 : {
1255 5996 : if ( i > 0 )
1256 : {
1257 2104 : if ( hExtOrientationData->enableExternalOrientation[i - 1] == 0 )
1258 : {
1259 : IVAS_QUATERNION identity;
1260 778 : identity.w = 1.0f;
1261 778 : identity.x = identity.y = identity.z = 0.0f;
1262 778 : hCombinedOrientationData->Quaternions_ext_interpolation_start = identity;
1263 : }
1264 1326 : else if ( hExtOrientationData->enableExternalOrientation[i - 1] == 2 )
1265 : {
1266 0 : hCombinedOrientationData->Quaternions_ext_interpolation_start = hCombinedOrientationData->Quaternion_frozen_ext;
1267 : }
1268 : else
1269 : {
1270 1326 : hCombinedOrientationData->Quaternions_ext_interpolation_start = hExtOrientationData->Quaternions[i - 1];
1271 : }
1272 : }
1273 : else
1274 : {
1275 3892 : hCombinedOrientationData->Quaternions_ext_interpolation_start = hCombinedOrientationData->Quaternion_prev_extOrientation;
1276 : }
1277 : }
1278 1098 : else if ( hExtOrientationData->enableExternalOrientation[i] == 2 )
1279 : {
1280 1098 : hCombinedOrientationData->Quaternions_ext_interpolation_start = hCombinedOrientationData->Quaternion_frozen_ext;
1281 : }
1282 :
1283 : /* Calculate the interpolation increment and coefficient */
1284 7094 : hCombinedOrientationData->interpolationIncrement = 1.0f / ( (float) hExtOrientationData->numFramesToTargetOrientation[i] * (float) MAX_PARAM_SPATIAL_SUBFRAMES );
1285 7094 : hCombinedOrientationData->interpolationCoefficient = hCombinedOrientationData->interpolationIncrement;
1286 : }
1287 :
1288 : /* Interpolate */
1289 28794 : hCombinedOrientationData->isInterpolationOngoing = TRUE;
1290 28794 : QuaternionSlerp( hCombinedOrientationData->Quaternions_ext_interpolation_start, hCombinedOrientationData->Quaternions_ext_interpolation_target, hCombinedOrientationData->interpolationCoefficient, &hCombinedOrientationData->Quaternions[i] );
1291 28794 : hCombinedOrientationData->interpolationCoefficient += hCombinedOrientationData->interpolationIncrement;
1292 : }
1293 : else
1294 : {
1295 : /* Use the target orientation immediately */
1296 160782 : hCombinedOrientationData->isInterpolationOngoing = FALSE;
1297 160782 : hCombinedOrientationData->interpolationCoefficient = 1.0f;
1298 160782 : hCombinedOrientationData->interpolationIncrement = 1.0f;
1299 160782 : hCombinedOrientationData->Quaternions[i] = hExtOrientationData->Quaternions[i];
1300 : }
1301 :
1302 189576 : return;
1303 : }
1304 :
1305 :
1306 : /*-------------------------------------------------------------------------
1307 : * are_orientations_same()
1308 : *
1309 : *
1310 : *------------------------------------------------------------------------*/
1311 :
1312 1426891 : static bool are_orientations_same(
1313 : const IVAS_QUATERNION *orientation1,
1314 : const IVAS_QUATERNION *orientation2 )
1315 : {
1316 1426891 : bool orientationsAreSame = true;
1317 1426891 : float error_margin = 0.05f;
1318 :
1319 1426891 : if ( fabsf( orientation1->w - orientation2->w ) > error_margin ||
1320 1416501 : fabsf( orientation1->x - orientation2->x ) > error_margin ||
1321 1416501 : fabsf( orientation1->y - orientation2->y ) > error_margin ||
1322 1416501 : fabsf( orientation1->z - orientation2->z ) > error_margin )
1323 : {
1324 13971 : orientationsAreSame = false;
1325 : }
1326 :
1327 1426891 : return orientationsAreSame;
1328 : }
1329 :
1330 :
1331 : /*-----------------------------------------------------------------------*
1332 : * Local Function definitions
1333 : *-----------------------------------------------------------------------*/
1334 :
1335 : /*-------------------------------------------------------------------------
1336 : * Helper functions used by SHrotmatgen,
1337 : * an implementation of the algorithm in
1338 : * Ivanic, J. & Ruedenberg, K., J. Phys. Chem. 100, 6342 (1996)
1339 : *------------------------------------------------------------------------*/
1340 :
1341 2257171970 : static float SHrot_p(
1342 : const int16_t i,
1343 : const int16_t l,
1344 : const int16_t a,
1345 : const int16_t b,
1346 : float SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM],
1347 : float R_lm1[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM] )
1348 : {
1349 2257171970 : float ri1 = 0.0f, rim1 = 0.0f, ri0 = 0.0f, p = 0.0f, R_lm1_1 = 0.0f, R_lm1_2 = 0.0f;
1350 :
1351 2257171970 : ri1 = SHrotmat[i + 1 + 1][1 + 1 + 1];
1352 2257171970 : rim1 = SHrotmat[i + 1 + 1][-1 + 1 + 1];
1353 2257171970 : ri0 = SHrotmat[i + 1 + 1][0 + 1 + 1];
1354 :
1355 2257171970 : if ( b == -l )
1356 : {
1357 371401110 : R_lm1_1 = R_lm1[a + l - 1][0];
1358 371401110 : R_lm1_2 = R_lm1[a + l - 1][2 * l - 2];
1359 371401110 : p = ri1 * R_lm1_1 + rim1 * R_lm1_2;
1360 : }
1361 : else
1362 : {
1363 1885770860 : if ( b == l )
1364 : {
1365 371401110 : R_lm1_1 = R_lm1[a + l - 1][2 * l - 2];
1366 371401110 : R_lm1_2 = R_lm1[a + l - 1][0];
1367 371401110 : p = ri1 * R_lm1_1 - rim1 * R_lm1_2;
1368 : }
1369 : else
1370 : {
1371 1514369750 : R_lm1_1 = R_lm1[a + l - 1][b + l - 1];
1372 1514369750 : p = ri0 * R_lm1_1;
1373 : }
1374 : }
1375 :
1376 2257171970 : return p;
1377 : }
1378 :
1379 502148950 : static float SHrot_u(
1380 : const int16_t l,
1381 : const int16_t m,
1382 : const int16_t n,
1383 : float SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM],
1384 : float R_lm1[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM] )
1385 : {
1386 502148950 : return SHrot_p( 0, l, m, n, SHrotmat, R_lm1 );
1387 : }
1388 :
1389 755721730 : static float SHrot_v(
1390 : const int16_t l,
1391 : const int16_t m,
1392 : const int16_t n,
1393 : float SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM],
1394 : float R_lm1[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM] )
1395 : {
1396 :
1397 : float result, d, p0, p1;
1398 :
1399 755721730 : if ( m == 0 )
1400 : {
1401 126786390 : p0 = SHrot_p( 1, l, 1, n, SHrotmat, R_lm1 );
1402 126786390 : p1 = SHrot_p( -1, l, -1, n, SHrotmat, R_lm1 );
1403 126786390 : result = p0 + p1;
1404 : }
1405 : else
1406 : {
1407 628935340 : if ( m > 0 )
1408 : {
1409 314467670 : d = ( m == 1 ) ? 1.0f : 0.0f;
1410 314467670 : p0 = SHrot_p( 1, l, m - 1, n, SHrotmat, R_lm1 );
1411 314467670 : p1 = SHrot_p( -1, l, -m + 1, n, SHrotmat, R_lm1 );
1412 314467670 : result = p0 * sqrtf( 1.0f + d ) - p1 * ( 1.0f - d );
1413 : }
1414 : else
1415 : {
1416 314467670 : d = ( m == -1 ) ? 1.0f : 0.0f;
1417 314467670 : p0 = SHrot_p( 1, l, m + 1, n, SHrotmat, R_lm1 );
1418 314467670 : p1 = SHrot_p( -1, l, -m - 1, n, SHrotmat, R_lm1 );
1419 314467670 : result = p0 * ( 1.0f - d ) + p1 * sqrtf( 1.0f + d );
1420 : }
1421 : }
1422 :
1423 755721730 : return result;
1424 : }
1425 :
1426 121789780 : static float SHrot_w(
1427 : const int16_t l,
1428 : const int16_t m,
1429 : const int16_t n,
1430 : float SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM],
1431 : float R_lm1[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM] )
1432 : {
1433 : float result, p0, p1;
1434 :
1435 121789780 : if ( m == 0 )
1436 : {
1437 0 : assert( 0 && "ERROR should not be called\n" );
1438 : return 0.0f;
1439 : }
1440 : else
1441 : {
1442 121789780 : if ( m > 0 )
1443 : {
1444 60894890 : p0 = SHrot_p( 1, l, m + 1, n, SHrotmat, R_lm1 );
1445 60894890 : p1 = SHrot_p( -1, l, -m - 1, n, SHrotmat, R_lm1 );
1446 60894890 : result = p0 + p1;
1447 : }
1448 : else
1449 : {
1450 60894890 : p0 = SHrot_p( 1, l, m - 1, n, SHrotmat, R_lm1 );
1451 60894890 : p1 = SHrot_p( -1, l, -m + 1, n, SHrotmat, R_lm1 );
1452 60894890 : result = p0 - p1;
1453 : }
1454 : }
1455 :
1456 121789780 : return result;
1457 : }
1458 :
1459 :
1460 : /*-------------------------------------------------------------------------
1461 : * rotateFrame_sd_cldfb()
1462 : *
1463 : *
1464 : *------------------------------------------------------------------------*/
1465 :
1466 17963048 : void SHrotmatgen(
1467 : float SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM], /* o : rotation matrix in SHD */
1468 : float Rmat[3][3], /* i : real-space rotation matrix */
1469 : const int16_t order /* i : ambisonics order */
1470 : )
1471 : {
1472 17963048 : int16_t d = 0;
1473 17963048 : int16_t band_idx = 0;
1474 : int16_t i, j;
1475 : int16_t l, m, n;
1476 : int16_t absm;
1477 17963048 : float sqdenom = 0.0f, sql2mm2 = 0.0f, sqdabsm = 0.0f, sqlabsm = 0.0f;
1478 17963048 : float u = 0.0f, v = 0.0f, w = 0.0f;
1479 : float R_lm1[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM];
1480 : float R_l[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM];
1481 :
1482 17963048 : SHrotmat[0][0] = 1.0f;
1483 :
1484 17963048 : SHrotmat[1][1] = Rmat[1][1];
1485 17963048 : SHrotmat[1][2] = Rmat[1][2];
1486 17963048 : SHrotmat[1][3] = Rmat[1][0];
1487 :
1488 17963048 : SHrotmat[2][1] = Rmat[2][1];
1489 17963048 : SHrotmat[2][2] = Rmat[2][2];
1490 17963048 : SHrotmat[2][3] = Rmat[2][0];
1491 :
1492 17963048 : SHrotmat[3][1] = Rmat[0][1];
1493 17963048 : SHrotmat[3][2] = Rmat[0][2];
1494 17963048 : SHrotmat[3][3] = Rmat[0][0];
1495 :
1496 71852192 : for ( i = 0; i < 2 * 1 + 1; i++ )
1497 : {
1498 215556576 : for ( j = 0; j < 2 * 1 + 1; j++ )
1499 : {
1500 161667432 : R_lm1[i][j] = SHrotmat[i + 1][j + 1];
1501 : }
1502 : }
1503 :
1504 17963048 : band_idx = 4;
1505 39840618 : for ( l = 2; l <= order; l++ )
1506 : {
1507 21877570 : set_zero( &R_l[0][0], HEADROT_SHMAT_DIM2 );
1508 :
1509 148663960 : for ( m = -l; m <= l; m++ )
1510 : {
1511 126786390 : d = ( m == 0 ) ? 1 : 0;
1512 126786390 : absm = (int16_t) abs( m );
1513 126786390 : sql2mm2 = sqrtf( (float) ( l * l - m * m ) );
1514 126786390 : sqdabsm = sqrtf( (float) ( ( 1 + d ) * ( l + absm - 1 ) * ( l + absm ) ) );
1515 126786390 : sqlabsm = sqrtf( (float) ( ( l - absm - 1 ) * ( l - absm ) ) );
1516 :
1517 882508120 : for ( n = -l; n <= l; n++ )
1518 : {
1519 755721730 : if ( abs( n ) == l )
1520 : {
1521 253572780 : sqdenom = sqrtf( (float) ( ( 2 * l ) * ( 2 * l - 1 ) ) );
1522 : }
1523 : else
1524 : {
1525 502148950 : sqdenom = sqrtf( (float) ( l * l - n * n ) );
1526 : }
1527 :
1528 755721730 : u = sql2mm2 / sqdenom;
1529 755721730 : v = sqdabsm / sqdenom * ( 1 - 2 * d ) * 0.5f;
1530 755721730 : w = sqlabsm / sqdenom * ( 1 - d ) * ( -0.5f );
1531 :
1532 755721730 : if ( u != 0 )
1533 : {
1534 502148950 : u = u * SHrot_u( l, m, n, SHrotmat, R_lm1 );
1535 : }
1536 755721730 : if ( v != 0 )
1537 : {
1538 755721730 : v = v * SHrot_v( l, m, n, SHrotmat, R_lm1 );
1539 : }
1540 755721730 : if ( w != 0 )
1541 : {
1542 121789780 : w = w * SHrot_w( l, m, n, SHrotmat, R_lm1 );
1543 : }
1544 755721730 : R_l[m + l][n + l] = u + v + w;
1545 : }
1546 : }
1547 :
1548 148663960 : for ( i = 0; i < 2 * l + 1; i++ )
1549 : {
1550 882508120 : for ( j = 0; j < 2 * l + 1; j++ )
1551 : {
1552 755721730 : SHrotmat[band_idx + i][band_idx + j] = R_l[i][j];
1553 : }
1554 : }
1555 :
1556 148663960 : for ( i = 0; i < 2 * l + 1; i++ )
1557 : {
1558 882508120 : for ( j = 0; j < 2 * l + 1; j++ )
1559 : {
1560 755721730 : R_lm1[i][j] = R_l[i][j];
1561 : }
1562 : }
1563 :
1564 21877570 : band_idx += 2 * l + 1;
1565 : }
1566 :
1567 17963048 : return;
1568 : }
1569 :
1570 :
1571 : /*-------------------------------------------------------------------------
1572 : * ivas_combined_orientation_update_index()
1573 : *
1574 : * update read index based on the number of rendered samples
1575 : *------------------------------------------------------------------------*/
1576 :
1577 248199592 : void ivas_combined_orientation_update_index(
1578 : COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle */
1579 : const int16_t samples_rendered /* i : samples rendered since the last call */
1580 : )
1581 : {
1582 248199592 : if ( hCombinedOrientationData != NULL )
1583 : {
1584 48666326 : if ( hCombinedOrientationData->num_subframes == 1 || hCombinedOrientationData->sr_low_res_flag )
1585 : {
1586 : /* only one orientation available anyway or split rendering with low resolution*/
1587 20011733 : hCombinedOrientationData->subframe_idx = 0;
1588 : }
1589 : else
1590 : {
1591 28654593 : hCombinedOrientationData->cur_subframe_samples_rendered += samples_rendered;
1592 28654593 : hCombinedOrientationData->subframe_idx += hCombinedOrientationData->cur_subframe_samples_rendered / hCombinedOrientationData->subframe_size;
1593 28654593 : hCombinedOrientationData->cur_subframe_samples_rendered = hCombinedOrientationData->cur_subframe_samples_rendered % hCombinedOrientationData->subframe_size;
1594 28654593 : hCombinedOrientationData->subframe_idx = min( hCombinedOrientationData->subframe_idx, hCombinedOrientationData->num_subframes - 1 );
1595 : }
1596 : }
1597 :
1598 248199592 : return;
1599 : }
1600 :
1601 :
1602 : /*-------------------------------------------------------------------------
1603 : * ivas_combined_orientation_update_index()
1604 : *
1605 : * update read index based on the number of rendered samples
1606 : *------------------------------------------------------------------------*/
1607 :
1608 246158688 : void ivas_combined_orientation_set_to_start_index(
1609 : COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle */
1610 : )
1611 : {
1612 246158688 : if ( hCombinedOrientationData != NULL )
1613 : {
1614 49321221 : hCombinedOrientationData->subframe_idx = hCombinedOrientationData->subframe_idx_start;
1615 49321221 : hCombinedOrientationData->cur_subframe_samples_rendered = hCombinedOrientationData->cur_subframe_samples_rendered_start;
1616 : }
1617 :
1618 246158688 : return;
1619 : }
1620 :
1621 :
1622 : /*-------------------------------------------------------------------------
1623 : * ivas_combined_orientation_update_start_index()
1624 : *
1625 : * update start index based on the number of rendered samples
1626 : *------------------------------------------------------------------------*/
1627 :
1628 143303949 : void ivas_combined_orientation_update_start_index(
1629 : COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle */
1630 : const int16_t samples_rendered /* i : samples rendered since the last call */
1631 : )
1632 : {
1633 143303949 : if ( hCombinedOrientationData != NULL )
1634 : {
1635 25490967 : if ( hCombinedOrientationData->num_subframes == 1 || hCombinedOrientationData->sr_low_res_flag )
1636 : {
1637 : /* only one orientation available anyway or split rendering with low resolution*/
1638 19644718 : hCombinedOrientationData->subframe_idx = 0;
1639 : }
1640 : else
1641 : {
1642 5846249 : hCombinedOrientationData->cur_subframe_samples_rendered_start += samples_rendered;
1643 5846249 : hCombinedOrientationData->subframe_idx_start += hCombinedOrientationData->cur_subframe_samples_rendered / hCombinedOrientationData->subframe_size;
1644 5846249 : hCombinedOrientationData->cur_subframe_samples_rendered_start = hCombinedOrientationData->cur_subframe_samples_rendered % hCombinedOrientationData->subframe_size;
1645 5846249 : hCombinedOrientationData->subframe_idx_start = min( hCombinedOrientationData->subframe_idx, hCombinedOrientationData->num_subframes - 1 );
1646 : }
1647 : }
1648 :
1649 143303949 : return;
1650 : }
|