# Head-Tracking Library For Immersive Audio This library handles the processing of head-tracking information, necessary for Immersive Audio functionality. It goes from bare sensor reading into the final pose fed into a virtualizer. ## Basic Usage The main entry point into this library is the `HeadTrackingProcessor` class. This class is provided with the following inputs: - Head pose, relative to some arbitrary world frame. - Screen pose, relative to some arbitrary world frame. - Display orientation, defined as the angle between the "physical" screen and the "logical" screen. - Transform between the screen and the sound stage. - Desired operational mode: - Static: only the sound stage pose is taken into account. This will result in an experience where the sound stage moved with the listener's head. - World-relative: both the head pose and stage pose are taken into account. This will result in an experience where the sound stage is perceived to be located at a fixed place in the world. - Screen-relative: the head pose, screen pose and stage pose are all taken into account. This will result in an experience where the sound stage is perceived to be located at a fixed place relative to the screen. Once inputs are provided, the `calculate()` method will make the following output available: - Stage pose, relative to the head. This aggregates all the inputs mentioned above and is ready to be fed into a virtualizer. - Actual operational mode. May deviate from the desired one in cases where the desired mode cannot be calculated (for example, as result of dropped messages from one of the sensors). A `recenter()` operation is also available, which indicates to the system that whatever pose the screen and head are currently at should be considered as the "center" pose, or frame of reference. ## Pose-Related Conventions ### Naming and Composition When referring to poses in code, it is always good practice to follow conventional naming, which highlights the reference and target frames clearly: Bad: ``` Pose3f headPose; ``` Good: ``` Pose3f worldToHead; // “world” is the reference frame, // “head” is the target frame. ``` By following this convention, it is easy to follow correct composition of poses, by making sure adjacent frames are identical: ``` Pose3f aToD = aToB * bToC * cToD; ``` And similarly, inverting the transform simply flips the reference and target: ``` Pose3f aToB = bToA.inverse(); ``` ### Twist “Twist” is to pose what velocity is to distance: it is the time-derivative of a pose, representing the change in pose over a short period of time. Its naming convention always states one frame, e.g.: Twist3f headTwist; This means that this twist represents the head-at-time-T to head-at-time-T+dt transform. Twists are not composable in the same way as poses. ### Frames of Interest The frames of interest in this library are defined as follows: #### Head This is the listener’s head. The origin is at the center point between the ear-drums, the X-axis goes from left ear to right ear, Y-axis goes from the back of the head towards the face and Z-axis goes from the bottom of the head to the top. #### Screen This is the primary screen that the user will be looking at, which is relevant for some Immersive Audio use-cases, such as watching a movie. We will follow a different convention for this frame than what the Sensor framework uses. The origin is at the center of the screen. X-axis goes from left to right, Z-axis goes from the screen bottom to the screen top, Y-axis goes “into” the screen ( from the direction of the viewer). The up/down/left/right of the screen are defined as the logical directions used for display. So when flipping the display orientation between “landscape” and “portrait”, the frame of reference will change with respect to the physical screen. #### Stage This is the frame of reference used by the virtualizer for positioning sound objects. It is not associated with any physical frame. In a typical multi-channel scenario, the listener is at the origin, the X-axis goes from left to right, Y-axis from back to front and Z-axis from down to up. For example, a front-right speaker is located at positive X, Y and Z=0, a height speaker will have a positive Z. #### World It is sometimes convenient to use an intermediate frame when dealing with head-to-screen transforms. The “world” frame is a frame of reference in the physical world, relative to which we can measure the head pose and screen pose. It is arbitrary, but expected to be stable (fixed). ## Processing Description ![Pose processing graph](PoseProcessingGraph.png) The diagram above illustrates the processing that takes place from the inputs to the outputs. ### Predictor The Predictor block gets pose + twist (pose derivative) and extrapolates to obtain a predicted head pose (w/ given latency). ### Bias The Bias blocks establish the reference frame for the poses by having the ability to set the current pose as the reference for future poses (recentering). ### Orientation Compensation The Orientation Compensation block applies the display orientation to the screen pose to obtain the pose of the “logical screen” frame, in which the Y-axis is pointing in the direction of the logical screen “up” rather than the physical one. ### Screen-Relative Pose The Screen-Relative Pose block is provided with a head pose and a screen pose and estimates the pose of the head relative to the screen. Optionally, this module may indicate that the user is likely not in front of the screen via the “valid” output. ### Stillness Detector The stillness detector blocks detect when their incoming pose stream has been stable for a given amount of time (allowing for a configurable amount of error). When the head is considered still, we would trigger a recenter operation (“auto-recentering”) and when the screen is considered not still, the mode selector would use this information to force static mode. ### Mode Selector The Mode Selector block aggregates the various sources of pose information into a head-to-stage pose that is going to feed the virtualizer. It is controlled by the “desired mode” signal that indicates whether the preference is to be in either static, world-relative or screen-relative. The actual mode may diverge from the desired mode. It is determined as follows: - If the desired mode is static, the actual mode is static. - If the desired mode is world-relative: - If head and screen poses are fresh and the screen is stable (stillness detector output is true), the actual mode is world-relative. - Otherwise the actual mode is static. - If the desired mode is screen-relative: - If head and screen poses are fresh and the ‘valid’ signal is asserted, the actual mode is screen-relative. - Otherwise, apply the same rules as the desired mode being world-relative. ### Rate Limiter A Rate Limiter block is applied to the final output to smooth out any abrupt transitions caused by any of the following events: - Mode switch. - Display orientation switch. - Recenter operation.