1
0
mirror of https://github.com/Escartem/AnimeWwise.git synced 2026-06-04 23:40:25 +08:00

improve error handling

This commit is contained in:
Escartem
2024-12-03 18:25:01 +01:00
parent 75821caf62
commit 4faf25df5a
4 changed files with 89 additions and 62 deletions

View File

@@ -153,7 +153,7 @@ class WwiseExtract:
} }
wem_data = data[file_data["offset"]:file_data["offset"]+file_data["size"]] wem_data = data[file_data["offset"]:file_data["offset"]+file_data["size"]]
parsed_wem = wwise.parse_wwise(FileReader(io.BytesIO(wem_data), "little")) parsed_wem = wwise.parse_wwise(FileReader(io.BytesIO(wem_data), "little", name=f"{file[0]}:{file[1]}"))
file_data["metadata"] = parsed_wem file_data["metadata"] = parsed_wem

View File

@@ -8,9 +8,11 @@ class FileReader:
File reader for files, not much too say File reader for files, not much too say
""" """
def __init__(self, file, endianness:str): def __init__(self, file, endianness:str, name:str=None):
self.stream = file self.stream = file
self.endianness = endianness self.endianness = endianness
if name:
self.name = name
def _read(self, mode:str, bufferLength:int, endianness:str=None) -> bytes: def _read(self, mode:str, bufferLength:int, endianness:str=None) -> bytes:
# endianness override # endianness override
@@ -76,3 +78,8 @@ class FileReader:
def GetRemainingLength(self) -> int: def GetRemainingLength(self) -> int:
return self.GetStreamLength() - self.GetBufferPos() return self.GetStreamLength() - self.GetBufferPos()
def GetName(self) -> str:
if self.name:
return self.name
return ""

7
gui.ui
View File

@@ -186,8 +186,8 @@
<rect> <rect>
<x>10</x> <x>10</x>
<y>10</y> <y>10</y>
<width>1166</width> <width>1041</width>
<height>111</height> <height>131</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="hdiffGrid"> <layout class="QGridLayout" name="hdiffGrid">
@@ -233,6 +233,9 @@ Subfolders are disabled in this mode, make sure to be in the correct place. For
<property name="alignment"> <property name="alignment">
<set>Qt::AlignCenter</set> <set>Qt::AlignCenter</set>
</property> </property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>

133
wwise.py
View File

@@ -2,60 +2,14 @@
# thanks to hcs and bnnm work # thanks to hcs and bnnm work
def parse_wwise(reader): def parse_wwise(reader):
header = reader.ReadBytes(4) # default meta config
# endian check header
if header == b"RIFX":
reader.endianness = "big"
elif header == b"RIFF":
reader.endianness = "little"
else:
raise Exception("invalid header")
# additional check
reader.SetBufferPos(0x08)
check = reader.ReadBytes(4)
if check != b"WAVE" and check != "XWMA":
raise Exception("invalid file")
# read chunks
reader.SetBufferPos(0x0C)
chunks = {}
while reader.GetBufferPos() < reader.GetStreamLength():
# relevants chunks types
# "fmt "
# "data"
# "JUNK"
chunk_type = reader.ReadBytes(4)
if chunk_type not in [b"fmt ", b"JUNK", b"data"]:
raise Exception("invalid chunk")
formatted_chunk_type = chunk_type.decode("utf-8").replace(" ", "")
chunk_length = reader.ReadUInt32()
chunks[formatted_chunk_type] = {
"length": chunk_length,
"offset": reader.GetBufferPos(),
"data": reader.ReadBytes(chunk_length)
}
# reader fmt header
if chunks["fmt"]["length"] < 0x10:
raise Exception("invalid fmt chunk length")
reader.SetBufferPos(chunks["fmt"]["offset"])
metadata = { metadata = {
"format": reader.ReadUInt16(), "format": 0,
"channels": reader.ReadUInt16(), "channels": 0,
"sampleRate": reader.ReadUInt32(), "sampleRate": 0,
"avgBitrate": reader.ReadUInt32(), "avgBitrate": 0,
"blockSize": reader.ReadUInt16(), "blockSize": 0,
"bitsPerSample": reader.ReadUInt16(), "bitsPerSample": 0,
"extraSize": 0, "extraSize": 0,
"channelLayout": None, "channelLayout": None,
"channelType": None, "channelType": None,
@@ -64,9 +18,70 @@ def parse_wwise(reader):
"layoutType": None, "layoutType": None,
"interleaveBlockSize": None, "interleaveBlockSize": None,
"numSamples": None, "numSamples": None,
"duration": None "duration": 0
} }
if reader.GetStreamLength() == 0:
print(f"[WARNING] null stream size at {reader.GetName()}, unreadable block")
return metadata
header = reader.ReadBytes(4)
# endian check header
if header == b"RIFX":
reader.endianness = "big"
elif header == b"RIFF":
reader.endianness = "little"
else:
print(f"[WARNING] invalid header {header} at {reader.GetName()}, assuming unreadable")
return metadata
# additional check
reader.SetBufferPos(0x08)
check = reader.ReadBytes(4)
if check != b"WAVE" and check != "XWMA":
print(f"[WARNING] invalid check mark {check}, assuming unreadable")
return metadata
# read chunks
reader.SetBufferPos(0x0C)
chunks = {}
while reader.GetBufferPos() < reader.GetStreamLength():
chunk_type = reader.ReadBytes(4)
if chunk_type not in [b"fmt ", b"JUNK", b"data", b"akd ", b"cue ", b"LIST", b"smpl"]:
print(f"[WARNING] unexpected chunk {chunk_type} at {reader.GetName()}")
formatted_chunk_type = chunk_type.decode("utf-8").replace(" ", "")
chunk_length = reader.ReadUInt32()
if chunk_type == b"data" and chunk_length > reader.GetRemainingLength():
chunk_length = reader.GetRemainingLength()
chunks[formatted_chunk_type] = {
"length": chunk_length,
"offset": reader.GetBufferPos(),
"data": reader.ReadBytes(chunk_length)
}
# reader fmt header
fmt_length = chunks["fmt"]["length"]
if fmt_length < 0x10:
print(f"[WARNING] invalid fmt chunk length {fmt_length} at {reader.GetName()}, skipping")
return metadata
reader.SetBufferPos(chunks["fmt"]["offset"])
metadata["format"] = reader.ReadUInt16()
metadata["channels"] = reader.ReadUInt16()
metadata["sampleRate"] = reader.ReadUInt32()
metadata["avgBitrate"] = reader.ReadUInt32()
metadata["blockSize"] = reader.ReadUInt16()
metadata["bitsPerSample"] = reader.ReadUInt16()
if chunks["fmt"]["length"] > 0x10 and metadata["format"] != 0x0165 and metadata["format"] != 0x0166: if chunks["fmt"]["length"] > 0x10 and metadata["format"] != 0x0165 and metadata["format"] != 0x0166:
metadata["extraSize"] = reader.ReadUInt16() metadata["extraSize"] = reader.ReadUInt16()
@@ -78,7 +93,8 @@ def parse_wwise(reader):
metadata["channelLayout"] = metadata["channelLayout"] >> 12 metadata["channelLayout"] = metadata["channelLayout"] >> 12
if metadata["format"] == 0x0166: if metadata["format"] == 0x0166:
raise Exception("XMA2WAVEFORMATEX in fmt") print(f"[WARNING] XMA2WAVEFORMATEX in fmt at {reader.GetName()}")
return metadata
# parse codec # parse codec
codecs = { codecs = {
@@ -101,16 +117,17 @@ def parse_wwise(reader):
0x8311: "PTADPCM" 0x8311: "PTADPCM"
} }
# genshin should be PTADPCM # genshin should be *mostly* PTADPCM
# hsr and zzz should be VORBIS # hsr and zzz should be VORBIS
if metadata["format"] not in codecs: if metadata["format"] not in codecs:
raise Exception("unknown codec") print(f'[WARNING] unknown codec {metadata["format"]} at {reader.GetName()}')
return metadata
codec = codecs[metadata["format"]] codec = codecs[metadata["format"]]
if codec not in ["PTADPCM", "VORBIS"]: # Platinum "PtADPCM" custom ADPCM for Wwise if codec not in ["PTADPCM", "VORBIS"]: # Platinum "PtADPCM" custom ADPCM for Wwise
print(f"unhandled codec -> {codec}") print(f"[WARNING] unhandled codec {codec}, need to implement this later")
metadata["codec"] = codec metadata["codec"] = codec