mirror of
https://github.com/iluvcapra/wavinfo.git
synced 2026-01-02 09:50:41 +00:00
All existing tests pass
This commit is contained in:
@@ -11,8 +11,8 @@ from dataclasses import dataclass
|
|||||||
import encodings
|
import encodings
|
||||||
from .riff_parser import ChunkDescriptor
|
from .riff_parser import ChunkDescriptor
|
||||||
|
|
||||||
from struct import unpack, unpack_from, calcsize
|
from struct import unpack, calcsize
|
||||||
from typing import Optional, NamedTuple, List
|
from typing import Optional, NamedTuple, List, Dict, Any
|
||||||
|
|
||||||
#: Country Codes used in the RIFF standard to resolve locale. These codes
|
#: Country Codes used in the RIFF standard to resolve locale. These codes
|
||||||
#: appear in CSET and LTXT metadata.
|
#: appear in CSET and LTXT metadata.
|
||||||
@@ -113,8 +113,8 @@ class CueEntry(NamedTuple):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def read(cls, data: bytes) -> 'CueEntry':
|
def read(cls, data: bytes) -> 'CueEntry':
|
||||||
assert len(data) == calcsize(cls.Format), \
|
assert len(data) == cls.format_size(), \
|
||||||
"cue data size incorrect, expected {calcsize(cls.Format)} found {len(cues_data)}"
|
f"cue data size incorrect, expected {calcsize(cls.Format)} found {len(data)}"
|
||||||
|
|
||||||
parsed = unpack(cls.Format, data)
|
parsed = unpack(cls.Format, data)
|
||||||
|
|
||||||
@@ -178,12 +178,13 @@ class WavCuesReader:
|
|||||||
if cues is not None:
|
if cues is not None:
|
||||||
cues_data = cues.read_data(f)
|
cues_data = cues.read_data(f)
|
||||||
assert len(cues_data) >= 4, "cue metadata too short"
|
assert len(cues_data) >= 4, "cue metadata too short"
|
||||||
cues_count = unpack("<I", cues_data)
|
|
||||||
|
|
||||||
offset = calcsize("<I")
|
offset = calcsize("<I")
|
||||||
for _ in cues_count:
|
cues_count = unpack("<I", cues_data[0:offset])
|
||||||
cue_bytes = cues_data[offset: CueEntry.format_size() ]
|
|
||||||
|
for _ in range(cues_count[0]):
|
||||||
|
cue_bytes = cues_data[offset: offset + CueEntry.format_size()]
|
||||||
cue_list.append(CueEntry.read(cue_bytes))
|
cue_list.append(CueEntry.read(cue_bytes))
|
||||||
|
offset += CueEntry.format_size()
|
||||||
|
|
||||||
label_list = []
|
label_list = []
|
||||||
for labl in labls:
|
for labl in labls:
|
||||||
@@ -202,6 +203,12 @@ class WavCuesReader:
|
|||||||
return WavCuesReader(cues=cue_list, labels=label_list,
|
return WavCuesReader(cues=cue_list, labels=label_list,
|
||||||
ranges=range_list)
|
ranges=range_list)
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
return dict(cues=[c.__dict__ for c in self.cues],
|
||||||
|
labels=[l.__dict__ for l in self.labels],
|
||||||
|
ranges=[r.__dict__ for r in self.ranges])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ class WavInfoReader:
|
|||||||
#: RIFF INFO metadata.
|
#: RIFF INFO metadata.
|
||||||
self.info :Optional[WavInfoChunkReader]= None
|
self.info :Optional[WavInfoChunkReader]= None
|
||||||
|
|
||||||
|
#: RIFF CUE, LABL and LTXT metadata.
|
||||||
|
self.cues :Optional[WavCuesReader] = None
|
||||||
|
|
||||||
if hasattr(path, 'read'):
|
if hasattr(path, 'read'):
|
||||||
self.get_wav_info(path)
|
self.get_wav_info(path)
|
||||||
self.url = 'about:blank'
|
self.url = 'about:blank'
|
||||||
@@ -102,7 +105,7 @@ class WavInfoReader:
|
|||||||
self.adm = self._get_adm(wavfile)
|
self.adm = self._get_adm(wavfile)
|
||||||
self.info = self._get_info(wavfile, encoding=self.info_encoding)
|
self.info = self._get_info(wavfile, encoding=self.info_encoding)
|
||||||
self.dolby = self._get_dbmd(wavfile)
|
self.dolby = self._get_dbmd(wavfile)
|
||||||
# self.cue = self._get_cue(wavfile)
|
self.cues = self._get_cue(wavfile)
|
||||||
self.data = self._describe_data()
|
self.data = self._describe_data()
|
||||||
|
|
||||||
def _find_chunk_data(self, ident, from_stream, default_none=False) -> Optional[bytes]:
|
def _find_chunk_data(self, ident, from_stream, default_none=False) -> Optional[bytes]:
|
||||||
@@ -188,15 +191,19 @@ class WavInfoReader:
|
|||||||
return WavIXMLFormat(ixml_data.rstrip(b'\0')) if ixml_data else None
|
return WavIXMLFormat(ixml_data.rstrip(b'\0')) if ixml_data else None
|
||||||
|
|
||||||
def _get_cue(self, f):
|
def _get_cue(self, f):
|
||||||
cue = next((cue_chunk for cue_chunk in self.main_list if cue_chunk.ident == b'cue '), None)
|
cue = next((cue_chunk for cue_chunk in self.main_list if \
|
||||||
|
type(cue_chunk) is ChunkDescriptor and \
|
||||||
|
cue_chunk.ident == b'cue '), None)
|
||||||
|
|
||||||
adtl = self._find_list_chunk(b'adtl')
|
adtl = self._find_list_chunk(b'adtl')
|
||||||
labls = []
|
labls = []
|
||||||
ltxts = []
|
ltxts = []
|
||||||
if adtl is not None:
|
if adtl is not None:
|
||||||
labls = [child.read_data(f) for child in adtl.children if child.ident == b'labl']
|
labls = [child for child in adtl.children if child.ident == b'labl']
|
||||||
ltxts = [child.read_data(f) for child in adtl.children if child.ident == b'ltxt']
|
ltxts = [child for child in adtl.children if child.ident == b'ltxt']
|
||||||
|
|
||||||
return WavCuesReader.merge(f, cue, labls, ltxts)
|
return WavCuesReader.merge(f, cue, labls, ltxts,
|
||||||
|
fallback_encoding=self.info_encoding)
|
||||||
|
|
||||||
def walk(self) -> Generator[str,str,Any]: #FIXME: this should probably be named "iter()"
|
def walk(self) -> Generator[str,str,Any]: #FIXME: this should probably be named "iter()"
|
||||||
"""
|
"""
|
||||||
@@ -204,10 +211,10 @@ class WavInfoReader:
|
|||||||
|
|
||||||
:yields: tuples of the *scope*, *key*, and *value* of
|
:yields: tuples of the *scope*, *key*, and *value* of
|
||||||
each metadatum. The *scope* value will be one of
|
each metadatum. The *scope* value will be one of
|
||||||
"fmt", "data", "ixml", "bext", "info", "dolby", "cue" or "adm".
|
"fmt", "data", "ixml", "bext", "info", "dolby", "cues" or "adm".
|
||||||
"""
|
"""
|
||||||
|
|
||||||
scopes = ('fmt', 'data', 'ixml', 'bext', 'info', 'adm', 'dolby')
|
scopes = ('fmt', 'data', 'ixml', 'bext', 'info', 'adm', 'cues', 'dolby')
|
||||||
|
|
||||||
for scope in scopes:
|
for scope in scopes:
|
||||||
if scope in ['fmt', 'data']:
|
if scope in ['fmt', 'data']:
|
||||||
|
|||||||
Reference in New Issue
Block a user