Skip to content

7.34.0 - TrueHD Atmos keeps its heights, rendered to APAC

Choose a tag to compare

@superuser404notfound superuser404notfound released this 11 Oct 11:41
· 307 commits to main since this release

Added

  • TrueHD Atmos keeps its heights. Apple TV cannot bitstream TrueHD and no Apple platform gives a third-party app a compressed audio output, so the audio bridge decoded a TrueHD track's 7.1 channel presentation and every height and object position was gone before the audio left the engine. LoadOptions.objectAudioRendering = .apac(layout) keeps them: the engine decodes the Atmos object presentation (the bed, up to 15 dynamic objects and their object audio metadata, ETSI TS 103 420), renders it into the host's SpatialSpeakerLayout bed (5.1.2, 5.1.4, 7.1.2, 7.1.4 or 9.1.6) and encodes that bed as Apple Positional Audio. tvOS sends APAC to an Atmos receiver or soundbar as Dolby MAT, the way it delivers its own spatial content, and iOS plays it as Spatial Audio. Verified on an Apple TV 4K (3rd gen, tvOS 27.0) into a Sonos soundbar, which reports Dolby Atmos.

    • Renderer: allocentric dual-balance panning (the model Atmos metadata is authored in, ITU-R BS.2127's Cartesian approach), constant power everywhere in the room, object size, snap, zone masks, objects without elevation kept off the ceiling, bed channels routed discretely (a 7.1 bed's surrounds fold onto a 5.1 layout's pair), and gain ramps applied sample-accurately as the metadata states them.
    • Encoder: AVAudioConverter APAC at 320 kbps per bed channel (3.84 Mbit/s for 7.1.4), dynamic range control off because its analysis holds 1.5 to 5+ s before the first packet, which would leave the first segment after every seek silent. The 2048 priming frames stay in the stream, since AVFoundation presents an APAC packet that far before its timestamp. movenc cannot write APAC, so the track is muxed behind an ALAC stand-in whose init sample entry is replaced with the real apac entry and the encoder's dapa box. The master advertises CODECS="…,apac.31.LL" and CHANNELS with the bed's channel count.
    • Headroom: the APAC encoder does not clip (a tone at amplitude 4.0 decodes back at 4.001), and a rendered bed can exceed full scale, so a linked peak limiter sits before it: one gain for all channels so nothing moves, instant attack without a lookahead that would shift the audio, 250 ms release, bit-transparent below −0.18 dBFS. Dolby's Unfold demo needs up to −1.2 dB on 10458 of its 1.3 M frames.
    • Track choice: with the option on, the automatic audio pick prefers a TrueHD Atmos track over the other tracks of the same language and dub, only where the bed can be rendered (a VOD video session off the software path), never over audioSourceStreamIndexOverride.
    • Scope and fallback: only TrueHD that FFmpeg marks Atmos (profile 30), at 48 kHz, on OS 26+, VOD only. Any other source, an OS without the encoder, and any bridge or header failure keep audioBridgeMode with the audio intact. Opt-in, because it is a lossy encode in place of the lossless 7.1.
    • Diagnostics: [SpatialAudioBridge] object configuration names the presentation, and a bed levels line gives every bed channel's RMS and peak with its CoreAudio name, active and elevated object counts, the LFE level and the limiter's work, after the first 5 s and then every 30 s. aetherctl serve --atmos-bed <layout> --audio-index <n> serves a file this way.
    • Cost: decoding and encoding run at about 9.5x realtime for a 7.1.4 bed in a release build on Apple Silicon (EAC3 bridge: about 50x), roughly half Apple's encoder and 40 % the TrueHD decoder, so the first segments after a seek past the buffer take longer than on the channel bridge.

    Silo built the first implementation in its fork and offered it as the reference this is ported from (Silo-Server#6, #8 and #17); the port adds the limiter, re-anchoring after a decoder self-reset, the track preference and the review fixes. Thanks to @Quick104 and the Silo team, who also handed over the decoder package. (#731)

Dependencies

  • LibTrueHD 2.1.0 (new, .upToNextMinor(from: "2.1.0")): the Rust truehd crate from truehdd behind a C API, prebuilt as a static xcframework like LibDovi, so consumers need no Rust. Transferred from Silo-Server/SiloObjectAudio, rebuilt from source and verified bit-exact against truehdd. The wrapper is MIT; the truehd and oamd crates it compiles in are Apache-2.0, so apps ship its LICENSE, LICENSE-APACHE and NOTICE (README › License). Release notes: https://github.com/superuser404notfound/LibTrueHD/releases/tag/2.1.0