from collections.abc import Sequence from typing import Final, Protocol from ear.fileio.adm.elements import FormatDefinition, Frequency LFE_LOWPASS_HZ: Final = 120.0 class _Frequency(Protocol): lowPass: float | None highPass: float | None class _ChannelFormat(Protocol): id: str audioChannelFormatName: str frequency: _Frequency class _StreamFormat(Protocol): id: str format: object audioChannelFormat: object | None audioPackFormat: object | None class _Adm(Protocol): @property def audioChannelFormats(self) -> Sequence[_ChannelFormat]: ... @property def audioStreamFormats(self) -> Sequence[_StreamFormat]: ... # Python mirrors of EAT's fix_dolby.json pre-fixes (ebu/ebu-adm-toolbox # src/eat/process/misc.cpp), applied to the parsed EAR ADM instead of # re-writing the file. Real Dolby ADM Profile masters need both before # adm.validate() passes. The third fix_dolby process, fix_block_durations, is # covered by EAR's own timing_fixes.check_blockFormat_timings(adm, fix=True). def fix_ds_frequency(adm: _Adm) -> tuple[str, ...]: # EAT: every audioChannelFormat whose name contains "LFE" gets lowPass=120. # EAR's ADM also holds the common-definitions channels (EAT operates on the # axml document alone), so skip channels that already carry a lowPass — # same outcome, and no-op fixes are not reported. fixed_channel_format_ids = [] for channel_format in adm.audioChannelFormats: if "LFE" in channel_format.audioChannelFormatName and channel_format.frequency.lowPass is None: # Set only the missing lowPass; preserve any existing highPass. channel_format.frequency = Frequency( lowPass=LFE_LOWPASS_HZ, highPass=channel_format.frequency.highPass, ) fixed_channel_format_ids.append(channel_format.id) return tuple(fixed_channel_format_ids) def fix_stream_pack_refs(adm: _Adm) -> tuple[str, ...]: # EAT: PCM audioStreamFormats that reference an audioChannelFormat drop # their audioPackFormat reference (Dolby writes both; BS.2076 allows one) fixed_stream_format_ids = [] for stream_format in adm.audioStreamFormats: if ( stream_format.format == FormatDefinition.PCM and stream_format.audioChannelFormat is not None and stream_format.audioPackFormat is not None ): stream_format.audioPackFormat = None fixed_stream_format_ids.append(stream_format.id) return tuple(fixed_stream_format_ids)