UMID Implementation

This commit is contained in:
Jamie Hardt
2020-01-06 08:27:34 -08:00
parent 1b9547e8c2
commit 5a30ce3afc
4 changed files with 185 additions and 203 deletions

Binary file not shown.

View File

@@ -1,5 +1,10 @@
import struct
from typing import Union from typing import Union
import binascii
def binary_to_string(binary_value):
return str(binascii.hexlify(binary_value), encoding='ascii')
class UMIDParser: class UMIDParser:
""" """
@@ -9,121 +14,111 @@ class UMIDParser:
""" """
def __init__(self, raw_umid: bytearray): def __init__(self, raw_umid: bytearray):
self.raw_umid = raw_umid self.raw_umid = raw_umid
#
@classmethod # @property
def binary_to_string(cls, binary_value): # def universal_label(self) -> bytearray:
result_str = '' # return self.raw_umid[0:12]
for n in range(len(binary_value)): #
result_str = '{:x}'.format(binary_value[n]) + result_str # @property
# def basic_umid(self):
return result_str # return self.raw_umid[0:32]
@property
def universal_label(self) -> bytearray:
return self.raw_umid[0:12]
@property
def basic_umid(self):
return self.raw_umid[0:32]
def basic_umid_to_str(self): def basic_umid_to_str(self):
return "%024x-%06x-%032x" % (self.binary_to_string(self.universal_label), return binary_to_string(self.raw_umid[0:13]) + '-' + binary_to_string(self.raw_umid[13:3])
self.binary_to_string(self.instance_number), #
self.binary_to_string(self.material_number)) # @property
# def universal_label_is_valid(self) -> bool:
@property # valid_preamble = b'\x06\x0a\x2b\x34\x01\x01\x01\x05\x01\x01'
def universal_label_is_valid(self) -> bool: # return self.universal_label[0:len(valid_preamble)] == valid_preamble
valid_preamble = b'\x06\x0a\x2b\x34\x01\x01\x01\x05\x01\x01' #
return self.universal_label[0:len(valid_preamble)] == valid_preamble # @property
# def material_type(self) -> str:
@property # material_byte = self.raw_umid[10]
def material_type(self) -> str: # if material_byte == 0x1:
material_byte = self.raw_umid[10] # return 'picture'
if material_byte == 0x1: # elif material_byte == 0x2:
return 'picture' # return 'audio'
elif material_byte == 0x2: # elif material_byte == 0x3:
return 'audio' # return 'data'
elif material_byte == 0x3: # elif material_byte == 0x4:
return 'data' # return 'other'
elif material_byte == 0x4: # elif material_byte == 0x5:
return 'other' # return 'picture_single_component'
elif material_byte == 0x5: # elif material_byte == 0x6:
return 'picture_single_component' # return 'picture_multiple_component'
elif material_byte == 0x6: # elif material_byte == 0x7:
return 'picture_multiple_component' # return 'audio_single_component'
elif material_byte == 0x7: # elif material_byte == 0x9:
return 'audio_single_component' # return 'audio_multiple_component'
elif material_byte == 0x9: # elif material_byte == 0xb:
return 'audio_multiple_component' # return 'auxiliary_single_component'
elif material_byte == 0xb: # elif material_byte == 0xc:
return 'auxiliary_single_component' # return 'auxiliary_multiple_component'
elif material_byte == 0xc: # elif material_byte == 0xd:
return 'auxiliary_multiple_component' # return 'mixed_components'
elif material_byte == 0xd: # elif material_byte == 0xf:
return 'mixed_components' # return 'not_identified'
elif material_byte == 0xf: # else:
return 'not_identified' # return 'not_recognized'
else: #
return 'not_recognized' # @property
# def material_number_creation_method(self) -> str:
@property # method_byte = self.raw_umid[11]
def material_number_creation_method(self) -> str: # method_byte = (method_byte << 4) & 0xf
method_byte = self.raw_umid[11] # if method_byte == 0x0:
method_byte = (method_byte << 4) & 0xf # return 'undefined'
if method_byte == 0x0: # elif method_byte == 0x1:
return 'undefined' # return 'smpte'
elif method_byte == 0x1: # elif method_byte == 0x2:
return 'smpte' # return 'uuid'
elif method_byte == 0x2: # elif method_byte == 0x3:
return 'uuid' # return 'masked'
elif method_byte == 0x3: # elif method_byte == 0x4:
return 'masked' # return 'ieee1394'
elif method_byte == 0x4: # elif 0x5 <= method_byte <= 0x7:
return 'ieee1394' # return 'reserved_undefined'
elif 0x5 <= method_byte <= 0x7: # else:
return 'reserved_undefined' # return 'unrecognized'
else: #
return 'unrecognized' # @property
# def instance_number_creation_method(self) -> str:
@property # method_byte = self.raw_umid[11]
def instance_number_creation_method(self) -> str: # method_byte = method_byte & 0xf
method_byte = self.raw_umid[11] # if method_byte == 0x0:
method_byte = method_byte & 0xf # return 'undefined'
if method_byte == 0x0: # elif method_byte == 0x01:
return 'undefined' # return 'local_registration'
elif method_byte == 0x01: # elif method_byte == 0x02:
return 'local_registration' # return '24_bit_prs'
elif method_byte == 0x02: # elif method_byte == 0x03:
return '24_bit_prs' # return 'copy_number_and_16_bit_prs'
elif method_byte == 0x03: # elif 0x04 <= method_byte <= 0x0e:
return 'copy_number_and_16_bit_prs' # return 'reserved_undefined'
elif 0x04 <= method_byte <= 0x0e: # elif method_byte == 0x0f:
return 'reserved_undefined' # return 'live_stream'
elif method_byte == 0x0f: # else:
return 'live_stream' # return 'unrecognized'
else: #
return 'unrecognized' # @property
# def indicated_length(self) -> str:
@property # if self.raw_umid[12] == 0x13:
def indicated_length(self) -> str: # return 'basic'
if self.raw_umid[12] == 0x13: # elif self.raw_umid[12] == 0x33:
return 'basic' # return 'extended'
elif self.raw_umid[12] == 0x33: #
return 'extended' # @property
# def instance_number(self) -> bytearray:
@property # return self.raw_umid[13:3]
def instance_number(self) -> bytearray: #
return self.raw_umid[13:3] # @property
# def material_number(self) -> bytearray:
@property # return self.raw_umid[16:16]
def material_number(self) -> bytearray: #
return self.raw_umid[16:16] # @property
# def source_pack(self) -> Union[bytearray, None]:
@property # if self.indicated_length == 'extended':
def source_pack(self) -> Union[bytearray, None]: # return self.raw_umid[32:32]
if self.indicated_length == 'extended': # else:
return self.raw_umid[32:32] # return None
else:
return None

View File

@@ -1,5 +1,6 @@
import struct import struct
import binascii import binascii
from .umid_parser import UMIDParser
class WavBextReader: class WavBextReader:
def __init__(self, bext_data, encoding): def __init__(self, bext_data, encoding):
@@ -67,13 +68,13 @@ class WavBextReader:
self.max_momentary_loudness = unpacked[11] / 100.0 self.max_momentary_loudness = unpacked[11] / 100.0
self.max_shortterm_loudness = unpacked[12] / 100.0 self.max_shortterm_loudness = unpacked[12] / 100.0
def umid_to_str(self):
if self.umid:
return str(binascii.hexlify(self.umid), encoding='ascii')
else:
return None
def to_dict(self): def to_dict(self):
if self.umid is not None:
umid_parsed = UMIDParser(self.umid)
umid_str = umid_parsed.basic_umid_to_str()
else:
umid_str = None
return {'description': self.description, return {'description': self.description,
'originator': self.originator, 'originator': self.originator,
'originator_ref': self.originator_ref, 'originator_ref': self.originator_ref,
@@ -81,7 +82,7 @@ class WavBextReader:
'originator_time': self.originator_time, 'originator_time': self.originator_time,
'time_reference': self.time_reference, 'time_reference': self.time_reference,
'version': self.version, 'version': self.version,
'umid': self.umid_to_str(), 'umid': umid_str,
'coding_history': self.coding_history, 'coding_history': self.coding_history,
'loudness_value': self.loudness_value, 'loudness_value': self.loudness_value,
'loudness_range': self.loudness_range, 'loudness_range': self.loudness_range,
@@ -89,4 +90,3 @@ class WavBextReader:
'max_momentary_loudness': self.max_momentary_loudness, 'max_momentary_loudness': self.max_momentary_loudness,
'max_shortterm_loudness': self.max_shortterm_loudness 'max_shortterm_loudness': self.max_shortterm_loudness
} }

View File

@@ -1,6 +1,6 @@
from .riff_parser import parse_chunk, ListChunkDescriptor from .riff_parser import parse_chunk, ListChunkDescriptor
class WavInfoChunkReader: class WavInfoChunkReader:
def __init__(self, f, encoding): def __init__(self, f, encoding):
@@ -9,11 +9,9 @@ class WavInfoChunkReader:
f.seek(0) f.seek(0)
parsed_chunks = parse_chunk(f) parsed_chunks = parse_chunk(f)
list_chunks = [chunk for chunk in parsed_chunks.children \ list_chunks = [chunk for chunk in parsed_chunks.children if type(chunk) is ListChunkDescriptor]
if type(chunk) is ListChunkDescriptor]
self.info_chunk = next((chunk for chunk in list_chunks \ self.info_chunk = next((chunk for chunk in list_chunks if chunk.signature == b'INFO'), None)
if chunk.signature == b'INFO'), None)
#: 'ICOP' Copyright #: 'ICOP' Copyright
self.copyright = self._get_field(f, b'ICOP') self.copyright = self._get_field(f, b'ICOP')
@@ -50,12 +48,9 @@ class WavInfoChunkReader:
#: 'ICSM' Commissioned #: 'ICSM' Commissioned
self.commissioned = self._get_field(f, b'ICMS') self.commissioned = self._get_field(f, b'ICMS')
def _get_field(self, f, field_ident): def _get_field(self, f, field_ident):
search = next(((chunk.start, chunk.length) for chunk in self.info_chunk.children if chunk.ident == field_ident),
search = next( ( (chunk.start, chunk.length) for chunk in self.info_chunk.children \ None)
if chunk.ident == field_ident ), None)
if search is not None: if search is not None:
f.seek(search[0]) f.seek(search[0])
@@ -64,7 +59,6 @@ class WavInfoChunkReader:
else: else:
return None return None
def to_dict(self): def to_dict(self):
""" """
A dictionary with all of the key/values read from the INFO scope. A dictionary with all of the key/values read from the INFO scope.
@@ -82,14 +76,7 @@ class WavInfoChunkReader:
'source': self.source, 'source': self.source,
'tape': self.tape, 'tape': self.tape,
'commissioned': self.commissioned, 'commissioned': self.commissioned,
'software': self.software,
'archival_location': self.archival_location, 'archival_location': self.archival_location,
'subject': self.subject, 'subject': self.subject,
'technician': self.technician 'technician': self.technician
} }