From f7a1896f99fa6afe42ffba5fbb19f0a1a6688b09 Mon Sep 17 00:00:00 2001 From: Jamie Hardt Date: Thu, 24 Nov 2022 20:28:41 -0800 Subject: [PATCH] dbmd doc and implementation --- docs/source/index.rst | 1 + docs/source/metadata_scopes/dolby.rst | 14 + wavinfo/dolby_parser.py | 188 ----------- wavinfo/wave_dbmd_reader.py | 432 ++++++++++++++++++++++++++ 4 files changed, 447 insertions(+), 188 deletions(-) create mode 100644 docs/source/metadata_scopes/dolby.rst delete mode 100644 wavinfo/dolby_parser.py create mode 100644 wavinfo/wave_dbmd_reader.py diff --git a/docs/source/index.rst b/docs/source/index.rst index 99cf24d..d4b8bd3 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -13,6 +13,7 @@ Welcome to wavinfo's documentation! quickstart metadata_scopes/adm.rst metadata_scopes/bext.rst + metadata_scopes/dolby.rst metadata_scopes/info.rst metadata_scopes/ixml.rst diff --git a/docs/source/metadata_scopes/dolby.rst b/docs/source/metadata_scopes/dolby.rst new file mode 100644 index 0000000..5e7ec9a --- /dev/null +++ b/docs/source/metadata_scopes/dolby.rst @@ -0,0 +1,14 @@ +Dolby Metadata +============== + +Notes +----- + + +Class Reference +--------------- + +.. automodule:: wavinfo.wave_dbmd_reader + +.. autoclass:: wavinfo.wave_dbmd_reader.DolbyDigitalPlusMetadata + :members: \ No newline at end of file diff --git a/wavinfo/dolby_parser.py b/wavinfo/dolby_parser.py deleted file mode 100644 index 220c0ed..0000000 --- a/wavinfo/dolby_parser.py +++ /dev/null @@ -1,188 +0,0 @@ -# Dolby RMU Metadata per EBU Tech 3285 Supp 6 -# -# https://tech.ebu.ch/docs/tech/tech3285s6.pdf -# - -from struct import unpack, calcsize -from enum import (Enum, IntEnum) - -CHUNK_IDENT = "dbmd" -DOLBY_VERSION = "1.0.0.6" - - -class _DPPGenericDownMixLevel(Enum): - PLUS_3DB = 0b000 - PLUS_1_5DB = 0b001 - UNITY = 0b010 - MINUS_1_5DB = 0b011 - MINUS_3DB = 0b100 - MINUS_4_5DB = 0b101 - MINUS_6DB = 0b110 - MUTE = 0b111 - - -class DPPDolbySurroundEncodingMode(Enum): - RESERVED = 0b11 - IN_USE = 0b10 - NOT_IN_USE = 0b01 - NOT_INDICATED = 0b00 - -# DPPLoRoDownMixCenterLevel -# DPPLtRtCenterMixLevel -# DPPLtRtSurroundMixLevel - -class DolbyMetadataSegmentTypes(IntEnum): - END_MARKER = 0 - DOLBY_E_METADATA = 1 - DOLBY_DIGITAL_METADATA = 3 - DOLBY_DIGITAL_PLUS_METADATA = 7 - AUDIO_INFO = 8 - - -class DDPBitStreamMode(Enum): - """ - Dolby Digital Plus `bsmod` field - § 4.3.2.2 - """ - COMPLETE_MAIN = 0b000 - MUSIC_AND_EFFECTS = 0b001 - VISUALLY_IMPAIRED = 0b010 - HEARING_IMPAIRED = 0b011 - DIALOGUE_ONLY = 0b100 - COMMENTARY = 0b101 - EMERGENCY = 0b110 - VOICEOVER = 0b111 # if audioconfigmode is 1_0 - KARAOKE = 0b1000 # if audioconfigmode is not 1_0 - - -class DDPAudioCodingMode(Enum): - """ - Dolby Digital Plus `acmod` field - § 4.3.2.3 - """ - RESERVED = 0b000 - CH_ORD_1_0 = 0b001 - CH_ORD_2_0 = 0b010 - CH_ORD_3_0 = 0b011 - CH_ORD_2_1 = 0b100 - CH_ORD_3_1 = 0b101 - CH_ORD_2_2 = 0b110 - CH_ORD_3_2 = 0b111 - - -class DPPCenterDownMixLevel(Enum): - """ - § 4.3.3.1 - """ - DOWN_3DB = 0b00 - DOWN_45DB = 0b01 - DOWN_6DB = 0b10 - RESERVED = 0b11 - - -class DPPSurroundDownMixLevel(Enum): - """ - Dolby Digital Plus `surmixlev` field - § 4.3.3.2 - """ - DOWN_3DB = 0b00 - DOWN_6DB = 0b01 - MUTE = 0b10 - RESERVED = 0b11 - - -class DPPLanguageCode(Enum): - """ - § 4.3.4.1 , 4.3.5 (always 0xFF) - """ - # this is removed in https://www.atsc.org/wp-content/uploads/2015/03/A52-201212-17.pdf § 5.4.2.12 - # It should just be 0xff - pass - - -class DPPMixLevel(int): - pass - - -class DPPDialnormLevel(int): - pass - - -class DPPRoomTime(Enum): - """ - `roomtyp` 4.3.6.3 - """ - NOT_INDICATED = 0b00 - LARGE_ROOM_X_CURVE = 0b01 - SMALL_ROOM_FLAT_CURVE = 0b10 - RESERVED = 0b11 - - -class DPPPreferredDownMixMode(Enum): - """ - § 4.3.8.1 - """ - NOT_INDICATED = 0b00 - PRO_LOGIC = 0b01 - STEREO = 0b10 - PRO_LOGIC_2 = 0b11 - - -# class DPPLtRtCenterMixLevel(_DPPGenericDownMixLevel): -# pass -# -# -# class DPPLtRtSurroundMixLevel(_DPPGenericDownMixLevel): -# pass -# -# -# class DPPSurroundEXMode(_DPPGenericInUseIndicator): -# pass -# -# -# class DPPHeadphoneMode(_DPPGenericInUseIndicator): -# pass - - -class DPPADConverterType(Enum): - STANDARD = 0 - HDCD = 1 - - -class DDPStreamDependency(Enum): - """ - Encodes `ddplus_info1.stream_type` field § 4.3.12.1 - """ - INDEPENDENT = 0 - DEPENDENT = 1 - INDEPENDENT_FROM_DOLBY_DIGITAL = 2 - RESERVED = 3 - - -class DDPDataRate(int): - pass - - -class DPPRFCompressionProfile(Enum): - NONE = 0 - FILM_STANDARD = 1 - FILM_LIGHT = 2 - MUSIC_STANDARD = 3 - MUSIC_LIGHT = 4 - SPEECH = 5 - - -class DolbyDigitalPlusMetadata: - - @classmethod - def parse(cls, binary_data): - binary_format = "= calcsize(binary_format)) - fields = unpack(binary_format, binary_data) - - -class WavDolbyReader: - def __init__(self, dolby_data): - version, remainder = unpack(" int: + return unpack(" 0, \ + DolbyDigitalPlusMetadata.BitStreamMode(b & 0x38 >> 3), \ + DolbyDigitalPlusMetadata.AudioCodingMode(b & 0x7) + + def ddplus_reserved1(_): + pass + + def surround_config(b): + return DolbyDigitalPlusMetadata.CenterDownMixLevel(b & 0x30 >> 4), \ + DolbyDigitalPlusMetadata.SurroundDownMixLevel(b & 0xc >> 2), \ + DolbyDigitalPlusMetadata.DolbySurroundEncodingMode(b & 0x3) + + def dialnorm_info(b): + return (b & 0x80) > 0 , b & 0x40 > 0, b & 0x20 > 0, \ + DolbyDigitalPlusMetadata.DialnormLevel(b & 0x1f) + + def langcod(b) -> int: + return unpack("B", b) + + def audio_prod_info(b): + return (b & 0x80) > 0, \ + DolbyDigitalPlusMetadata.MixLevel(b & 0x7c >> 2), \ + DolbyDigitalPlusMetadata.RoomType(b & 0x3) + + # loro_center_downmix_level, loro_surround_downmix_level + def ext_bsi1_word1(b): + return DolbyDigitalPlusMetadata.DownMixLevelToken(b & 0x38 >> 3), \ + DolbyDigitalPlusMetadata.DownMixLevelToken(b & 0x7) + + # downmix_mode, ltrt_center_downmix_level, ltrt_surround_downmix_level + def ext_bsi1_word2(b): + return DolbyDigitalPlusMetadata.PreferredDownMixMode(b & 0xC0 >> 6), \ + DolbyDigitalPlusMetadata.DownMixLevelToken(b & 0x38 >> 3), \ + DolbyDigitalPlusMetadata.DownMixLevelToken(b & 0x7) + + #surround_ex_mode, dolby_headphone_encoded, ad_converter_type + def ext_bsi2_word1(b): + return DolbyDigitalPlusMetadata.SurroundEXMode(b & 0x60 >> 5), \ + DolbyDigitalPlusMetadata.HeadphoneMode(b & 0x18 >> 3), \ + DolbyDigitalPlusMetadata.ADConverterType( b & 0x4 >> 2) + + def ddplus_reserved2(_): + pass + + def compr1(b): + return DolbyDigitalPlusMetadata.RFCompressionProfile(unpack("B", b)) + + def dynrng1(b): + DolbyDigitalPlusMetadata.RFCompressionProfile(unpack("B",b)) + + def ddplus_reserved3(_): + pass + + def ddplus_info1(b): + return DolbyDigitalPlusMetadata.StreamDependency(b & 0xc >> 2) + + def ddplus_reserved4(_): + pass + + def datarate(b) -> int: + return unpack("