Skip to content

Instantly share code, notes, and snippets.

@Hattshire
Created July 19, 2020 09:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Hattshire/e387c8e6cf926629146928739ffadf7d to your computer and use it in GitHub Desktop.
Save Hattshire/e387c8e6cf926629146928739ffadf7d to your computer and use it in GitHub Desktop.
Wwise SoundBank(.bnk) and SoundPack(.wpk) metadata reader (JSON output)
#!/usr/bin/python3
import json
import sys
import base64
# TODO: CLEANUP (maybe, what an ugly thing)
uint32_size = 4
sectionid_size = 4
filename = str(sys.argv[1])
sbnk = []
file = open(filename, 'rb')
# Is `file` in EOF
def feof(file=file):
if file.read(1): # Can I read a byte?
file.seek(-1,1)
return False # YES, we're not in the end
return True # NO, this is the end
def get_bkhd(bytes):
# ui32(version)ui32(id)ui32(reserved0)ui32(reserved1)
return {
"version": get_int(bytes[0:4]),
"id": get_int(bytes[4:8]),
"reserved0": get_int(bytes[8:12]),
"reserved1": get_int(bytes[12:16]),
}
def get_hirc(bytes):
# ui32(object_count)var(object_array)
# object_array: 1b(type)ui32(len)ui32(id)[len-ui32](data)
count = get_int(bytes[0:4])
bytes = bytes[4:]
objects = []
for index in range(count):
type = get_int(bytes[0:1])
length = get_int(bytes[1:5]) - uint32_size
id = get_int(bytes[5:9])
data = bytes[9:9+length]
bytes = bytes[9+length:]
objects.append({
"type": get_hirc_type(type),
"length": length,
"id": id,
"data": get_data(data, "hirc:"+get_hirc_type(type)),
})
return {"count":count, "objects": objects}
def get_hirc_type(type):
return {
0x01: "Settings",
0x02: "Sound",
0x03: "Event Action",
0x04: "Event",
0x05: "Sequence Container",
0x06: "Switch Container",
0x07: "Actor Mixer",
0x08: "Audio Bus",
0x09: "Blend Container",
0x0a: "Music Segment",
0x0b: "Music Track",
0x0c: "Music Switch Container",
0x0d: "Music Playlist Container",
0x0e: "Attenuation",
0x0f: "Dialogue Event",
0x10: "Motion Bus",
0x11: "Motion FX",
0x12: "Effect",
0x13: "Auxiliary Bus",
}.get(type, "unknown("+str(type)+")")
def get_hirc_sound(bytes):
sfx={}
sfx["reserved0"]=get_base64(bytes[0:4]) # UNKNOWN
# Stream Source (Embedded, Streamed, Streamed+ZeroLatency/Prefetched)
strmsrc = get_int(bytes[4:8])
if strmsrc > 0:
strm = "Streamed"
if strmsrc == 2:
strm += "(ZeroLatency)"
else:
strm = "Embedded"
sfx["streamSourceType"] = strm
# File ID
sfx["streamFileID"] = get_int(bytes[8:12])
# Source ID
sfx["streamSourceID"] = get_int(bytes[12:16])
# BEGIN Embedded
if strm == 0:
sfx["streamFileOffset"] = get_int(bytes[16:20])
sfx["streamFileLength"] = get_int(bytes[20:24])
# END Embedded
sfx["soundType"] = "Voice" if bytes[24:25] else "SFX"
sfx["soundStructure"] = get_base64(bytes[25:])
return sfx
def get_base64(bytes):
return "base64:"+str(base64.b64encode(bytes), 'ascii')
def get_int(bytes):
return int.from_bytes(bytes, 'little') if type(bytes) is not int else bytes
def get_data(bytes, sectionid):
return {
'BKHD': get_bkhd,
'HIRC': get_hirc,
'hirc:Sound': get_hirc_sound,
}.get(sectionid, get_base64)(bytes)
eof = feof()
while not eof:
# .BNK File structure: 4b(ID)ui32(LENGTH)LENGTH(DATA){repeat}EOF
section = {}
section["id"] = str(file.read(sectionid_size), 'ascii')
section["len"] = get_int(file.read(uint32_size))
section["data"] = get_data(file.read(section["len"]), section["id"])
sbnk.append(section)
eof = feof()
file.close()
print(json.dumps(sbnk, indent=2))
#!/usr/bin/python3
import json
import sys
import base64
filename = str(sys.argv[1])
file = open(filename, 'rb')
def get_base64(bytes):
return "base64:"+str(base64.b64encode(bytes), 'ascii')
def get_int(bytes):
return int.from_bytes(bytes, 'little') if type(bytes) is not int else bytes
def get_strt(file):
# BEGIN HEADER
wpk = {}
wpk["Magic"] = str(file.read(4), 'ascii')
wpk["Version"] = get_int(file.read(4))
wpk["Count"] = get_int(file.read(4))
wpk["Offsets"] = []
for index in range(wpk["Count"]):
wpk["Offsets"].append(get_int(file.read(4)))
# END HEADER
wpk["Files"] = []
for offset in wpk["Offsets"]:
wem = {}
file.seek(offset)
wem["DataOffset"] = get_int(file.read(4))
wem["DataSize"] = get_int(file.read(4))
wem["NameSize"] = get_int(file.read(4))
wem["Name"] = str(file.read(wem["NameSize"]*2), 'utf16')
wpk["Files"].append(wem)
return wpk
print(json.dumps(get_strt(file), indent=2))
file.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment