diff --git a/extract.py b/extract.py
index e81a838..8d2671a 100644
--- a/extract.py
+++ b/extract.py
@@ -153,7 +153,7 @@ class WwiseExtract:
}
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
diff --git a/filereader.py b/filereader.py
index 86c5a9b..ec31744 100644
--- a/filereader.py
+++ b/filereader.py
@@ -8,9 +8,11 @@ class FileReader:
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.endianness = endianness
+ if name:
+ self.name = name
def _read(self, mode:str, bufferLength:int, endianness:str=None) -> bytes:
# endianness override
@@ -76,3 +78,8 @@ class FileReader:
def GetRemainingLength(self) -> int:
return self.GetStreamLength() - self.GetBufferPos()
+
+ def GetName(self) -> str:
+ if self.name:
+ return self.name
+ return ""
diff --git a/gui.ui b/gui.ui
index e017386..2849f4f 100644
--- a/gui.ui
+++ b/gui.ui
@@ -186,8 +186,8 @@
10
10
- 1166
- 111
+ 1041
+ 131
@@ -233,6 +233,9 @@ Subfolders are disabled in this mode, make sure to be in the correct place. For
Qt::AlignCenter
+
+ true
+
diff --git a/wwise.py b/wwise.py
index 49c9cd3..3ab83b6 100644
--- a/wwise.py
+++ b/wwise.py
@@ -2,60 +2,14 @@
# thanks to hcs and bnnm work
def parse_wwise(reader):
- header = reader.ReadBytes(4)
-
- # 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"])
-
+ # default meta config
metadata = {
- "format": reader.ReadUInt16(),
- "channels": reader.ReadUInt16(),
- "sampleRate": reader.ReadUInt32(),
- "avgBitrate": reader.ReadUInt32(),
- "blockSize": reader.ReadUInt16(),
- "bitsPerSample": reader.ReadUInt16(),
+ "format": 0,
+ "channels": 0,
+ "sampleRate": 0,
+ "avgBitrate": 0,
+ "blockSize": 0,
+ "bitsPerSample": 0,
"extraSize": 0,
"channelLayout": None,
"channelType": None,
@@ -64,9 +18,70 @@ def parse_wwise(reader):
"layoutType": None,
"interleaveBlockSize": 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:
metadata["extraSize"] = reader.ReadUInt16()
@@ -78,7 +93,8 @@ def parse_wwise(reader):
metadata["channelLayout"] = metadata["channelLayout"] >> 12
if metadata["format"] == 0x0166:
- raise Exception("XMA2WAVEFORMATEX in fmt")
+ print(f"[WARNING] XMA2WAVEFORMATEX in fmt at {reader.GetName()}")
+ return metadata
# parse codec
codecs = {
@@ -101,16 +117,17 @@ def parse_wwise(reader):
0x8311: "PTADPCM"
}
- # genshin should be PTADPCM
+ # genshin should be *mostly* PTADPCM
# hsr and zzz should be VORBIS
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"]]
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