mirror of
https://github.com/iluvcapra/wavinfo.git
synced 2026-01-02 18:00:41 +00:00
UMID Implementation
This commit is contained in:
BIN
tests/test_files/protools/umid.wav
Normal file
BIN
tests/test_files/protools/umid.wav
Normal file
Binary file not shown.
@@ -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
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user