mirror of
https://github.com/Escartem/AnimeWwise.git
synced 2026-06-04 23:40:25 +08:00
229 lines
5.5 KiB
Python
229 lines
5.5 KiB
Python
# Custom rewrite of the Wwise AKPK packages extractor, original by Nicknine and bnnm
|
|
import os
|
|
import traceback
|
|
from bnk import bnk2wem
|
|
|
|
|
|
reader = None
|
|
bank_version = 0
|
|
wwise_data = []
|
|
filename = ""
|
|
|
|
|
|
def get_data(_reader, _filename):
|
|
global wwise_data
|
|
global bank_version
|
|
global reader
|
|
global filename
|
|
|
|
filename = _filename
|
|
wwise_data = []
|
|
reader = _reader
|
|
|
|
# check file
|
|
if reader.ReadBytes(4) != b"AKPK":
|
|
# file.close()
|
|
raise Exception("not a valid audio file")
|
|
|
|
# check endianness
|
|
reader.SetBufferPos(0x08)
|
|
endian_check = reader.ReadLong() # this is the same bytes as the flag sector, which seems to be always 1
|
|
|
|
if endian_check == 1:
|
|
endianness = 0 # little
|
|
elif endian_check == 0x1000000:
|
|
endianness = 1 # big
|
|
else:
|
|
raise Exception("couldn't detect endianness")
|
|
|
|
# retrieve sectors in header
|
|
reader.SetBufferPos(0x04)
|
|
|
|
header_size = reader.ReadLong()
|
|
flag = reader.ReadLong()
|
|
|
|
languages_sector_size = reader.ReadLong()
|
|
banks_sector_size = reader.ReadLong()
|
|
sounds_sector_size = reader.ReadLong()
|
|
externals_sector_size = 0
|
|
|
|
if languages_sector_size + banks_sector_size + sounds_sector_size + 0x10 < header_size:
|
|
externals_sector_size = reader.ReadLong()
|
|
|
|
sectors = [[True, banks_sector_size, 0, 0, "bnk"], [False, sounds_sector_size, 1, 0, "wem"], [False, externals_sector_size, 1, 1, "wem"]]
|
|
|
|
# get langs in the file
|
|
try:
|
|
lang_array = get_langs(languages_sector_size)
|
|
except Exception as e:
|
|
raise Exception(f"failed to read languages, {e}, {traceback.format_exc()}")
|
|
|
|
# extract each sector
|
|
curr_sector = None
|
|
try:
|
|
for sector in sectors:
|
|
curr_sector = sector
|
|
extract_sector(*sector[1:], endianness, lang_array, bank_version)
|
|
|
|
if sector[0] and bank_version == 0:
|
|
if externals_sector_size == 0:
|
|
print("can't detect bank version")
|
|
bank_version = 62
|
|
except Exception as e:
|
|
raise Exception(f"failed to extract sector {curr_sector}, {e}, {traceback.format_exc()}")
|
|
|
|
return wwise_data
|
|
|
|
def get_langs(langs_sector_size):
|
|
string_offset = reader.GetBufferPos()
|
|
lang_array = {}
|
|
langs = reader.ReadLong()
|
|
|
|
for i in range(langs):
|
|
lang_offset = reader.ReadLong()
|
|
lang_id = reader.ReadLong()
|
|
|
|
lang_offset += string_offset
|
|
|
|
current = reader.GetBufferPos()
|
|
|
|
reader.SetBufferPos(lang_offset)
|
|
|
|
# get dummy bytes to detect encoding
|
|
test_byte_1 = reader.ReadBytes(1)
|
|
test_byte_2 = reader.ReadBytes(1)
|
|
|
|
reader.SetBufferPos(lang_offset)
|
|
|
|
if test_byte_1 == 0 or test_byte_2 == 0:
|
|
lang_name = reader.ReadBytes(0x20).decode("utf-16le", "ignore").replace("\x00", "")
|
|
else:
|
|
lang_name = reader.ReadBytes(0x10).decode("utf-8", "ignore").replace("\x00", "")
|
|
|
|
lang_array[lang_id] = lang_name
|
|
|
|
reader.SetBufferPos(current)
|
|
|
|
reader.SetBufferPos(string_offset + langs_sector_size)
|
|
|
|
return lang_array
|
|
|
|
def detect_bank_version(offset):
|
|
global bank_version
|
|
|
|
current = reader.GetBufferPos()
|
|
reader.SetBufferPos(offset)
|
|
|
|
# maybe update buffer pos instead
|
|
dummy = reader.ReadLong()
|
|
dummy = reader.ReadLong()
|
|
|
|
bank_version = reader.ReadLong()
|
|
|
|
if bank_version > 0x1000:
|
|
print("wrong bank version")
|
|
bank_version = 62
|
|
|
|
reader.SetBufferPos(current)
|
|
|
|
def extract_sector(section_size, is_sounds, is_externals, ext, endianness, lang_array, bank_version, filter_bnk_only=0, filter_wem_only=0, include_name=False):
|
|
global wwise_data
|
|
|
|
# check sector validity
|
|
if section_size == 0:
|
|
return
|
|
files = reader.ReadLong()
|
|
if files == 0:
|
|
return
|
|
|
|
entry_size = (section_size - 0x04) / files
|
|
|
|
if entry_size == 0x18:
|
|
alt_mode = 1
|
|
else:
|
|
alt_mode = 0
|
|
|
|
for i in range(files):
|
|
# ids must be unsigned here, if signed you need to do id += 2**32 afterwards
|
|
if alt_mode == 1 and is_externals == 1:
|
|
if endianness == 0:
|
|
file_id_2 = reader.ReadULong()
|
|
file_id_1 = reader.ReadULong()
|
|
else:
|
|
file_id_1 = reader.ReadULong()
|
|
file_id_2 = reader.ReadULong()
|
|
else:
|
|
file_id = reader.ReadULong()
|
|
|
|
block_size = reader.ReadLong()
|
|
|
|
# get file size
|
|
if alt_mode == 1 and is_externals == 1:
|
|
size = reader.ReadLong()
|
|
elif alt_mode == 1:
|
|
size = reader.ReadLongLong()
|
|
else:
|
|
size = reader.ReadLong()
|
|
|
|
offset = reader.ReadLong()
|
|
lang_id = reader.ReadLong()
|
|
|
|
if block_size != 0:
|
|
offset *= block_size
|
|
|
|
# bank version must be detected at this offset
|
|
if is_sounds == 0 and bank_version == 0:
|
|
detect_bank_version(offset)
|
|
|
|
# update extension for olders banks using differents codecs
|
|
if is_sounds == 1 and bank_version < 62:
|
|
current = reader.GetBufferPos()
|
|
|
|
codec_offset = offset + 0x14
|
|
reader.SetBufferPos(codec_offset)
|
|
|
|
codec = reader.ReadInt16()
|
|
|
|
if codec == 0x0401 or codec == 0x0166:
|
|
ext = "xma"
|
|
elif codec == 0xFFFF:
|
|
ext = "ogg"
|
|
else:
|
|
ext = "wav"
|
|
|
|
reader.SetBufferPos(current)
|
|
|
|
# set file path
|
|
if lang_id == 0:
|
|
path = ""
|
|
else:
|
|
path = "".join([f"{e}/" for e in list(lang_array.values())])
|
|
|
|
# set file name
|
|
if alt_mode == 1 and is_externals == 1:
|
|
name = f"externals/{path}{file_id_1:08x}{file_id_2:08x}.{ext}"
|
|
else:
|
|
name = f"{path}{file_id}.{ext}"
|
|
|
|
# filtering utilities
|
|
if filter_bnk_only == 1 and ext != "bnk":
|
|
continue
|
|
|
|
if filter_wem_only == 1 and ext != "wem":
|
|
continue
|
|
|
|
# file infos
|
|
if ext == "bnk":
|
|
# get data from bnk
|
|
pos = reader.GetBufferPos()
|
|
reader.SetBufferPos(offset)
|
|
bnk_data = reader.ReadBytes(size)
|
|
reader.SetBufferPos(pos)
|
|
|
|
wems = bnk2wem(bnk_data, f"{filename}@{pos}.{size}")
|
|
|
|
for wem in wems:
|
|
wwise_data.append([f"{os.path.basename(name).split('.')[0]}_{wem[0]}.wem", offset+wem[1], wem[2], filename])
|
|
else:
|
|
wwise_data.append([os.path.basename(name), offset, size, filename])
|