mirror of
https://github.com/Escartem/AnimeWwise.git
synced 2026-06-16 07:40:23 +08:00
switch from bms to wavescan script
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,4 +2,5 @@ output/
|
|||||||
temp/
|
temp/
|
||||||
*.pck
|
*.pck
|
||||||
*.hdiff
|
*.hdiff
|
||||||
tools.zip
|
tools.zip
|
||||||
|
__pycache__/
|
||||||
25
extract.py
25
extract.py
@@ -2,6 +2,7 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import zipfile
|
import zipfile
|
||||||
import filecmp
|
import filecmp
|
||||||
|
import wavescan
|
||||||
import subprocess
|
import subprocess
|
||||||
from halo import Halo
|
from halo import Halo
|
||||||
from progress.bar import PixelBar
|
from progress.bar import PixelBar
|
||||||
@@ -60,20 +61,10 @@ def main():
|
|||||||
if alone:
|
if alone:
|
||||||
output_path = "wem"
|
output_path = "wem"
|
||||||
|
|
||||||
# prepare args
|
|
||||||
args = [
|
|
||||||
path("tools/quickbms/quickbms.exe"),
|
|
||||||
"-o",
|
|
||||||
"-Y",
|
|
||||||
path("tools/quickbms/wavescan.bms"),
|
|
||||||
path(f"temp/{file}"),
|
|
||||||
path(f"temp/{output_path}")
|
|
||||||
]
|
|
||||||
|
|
||||||
# update spinner and call program
|
# update spinner and call program
|
||||||
spinner.text = f"[{curr}/{steps}] Extracting"
|
spinner.text = f"[{curr}/{steps}] Extracting"
|
||||||
spinner.start()
|
spinner.start()
|
||||||
call(args)
|
wavescan.extract(path(f"temp/{file}"), path(f"temp/{output_path}"))
|
||||||
spinner.stop()
|
spinner.stop()
|
||||||
print(f"[{curr}/{steps}] Extracting")
|
print(f"[{curr}/{steps}] Extracting")
|
||||||
|
|
||||||
@@ -114,20 +105,10 @@ def main():
|
|||||||
if not alone:
|
if not alone:
|
||||||
curr += 1
|
curr += 1
|
||||||
|
|
||||||
# prepare args
|
|
||||||
args = [
|
|
||||||
path("tools/quickbms/quickbms.exe"),
|
|
||||||
"-o",
|
|
||||||
"-Y",
|
|
||||||
path("tools/quickbms/wavescan.bms"),
|
|
||||||
path(f"temp/{file}"),
|
|
||||||
path(f"temp/patched_decoded")
|
|
||||||
]
|
|
||||||
|
|
||||||
# update spinner and call program
|
# update spinner and call program
|
||||||
spinner.text = f"[{curr}/{steps}] Extracting patch"
|
spinner.text = f"[{curr}/{steps}] Extracting patch"
|
||||||
spinner.start()
|
spinner.start()
|
||||||
call(args)
|
wavescan.extract(path(f"temp/{file}"), path(f"temp/patched_decoded"))
|
||||||
spinner.stop()
|
spinner.stop()
|
||||||
print(f"[{curr}/{steps}] Extracting patch")
|
print(f"[{curr}/{steps}] Extracting patch")
|
||||||
|
|
||||||
|
|||||||
@@ -3,16 +3,15 @@ import struct
|
|||||||
|
|
||||||
class FileReader:
|
class FileReader:
|
||||||
"""
|
"""
|
||||||
Simplified byte file reader with buffer
|
Simplified byte file reader with buffer, it's not particularly optimised but good enough
|
||||||
Not particularly optimised, contains repetitive functions
|
In the scope of this project, not everything will be used in here
|
||||||
In the scope of this project, not everything will be used either
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, file, endianness: str):
|
|
||||||
|
def __init__(self, file, endianness:str):
|
||||||
self.stream = file
|
self.stream = file
|
||||||
self.endianness = endianness
|
self.endianness = endianness
|
||||||
|
|
||||||
def _read(self, mode:str, bufferLength:int, endianness=None) -> bytes:
|
def _read(self, mode:str, bufferLength:int, endianness:str=None) -> bytes:
|
||||||
# endianness override
|
# endianness override
|
||||||
if endianness is None:
|
if endianness is None:
|
||||||
endianness = self.endianness
|
endianness = self.endianness
|
||||||
@@ -22,31 +21,31 @@ class FileReader:
|
|||||||
return struct.unpack(f"{endianness}{mode}", bytearray(self.stream.read(bufferLength)))[0]
|
return struct.unpack(f"{endianness}{mode}", bytearray(self.stream.read(bufferLength)))[0]
|
||||||
|
|
||||||
# read methods
|
# read methods
|
||||||
def ReadInt16(self, endianness=None) -> int:
|
def ReadInt16(self, endianness:str=None) -> int:
|
||||||
return self._read("h", 2, endianness)
|
return self._read("h", 2, endianness)
|
||||||
|
|
||||||
def ReadUInt16(self, endianness=None) -> int:
|
def ReadUInt16(self, endianness:str=None) -> int:
|
||||||
return self._read("H", 2, endianness)
|
return self._read("H", 2, endianness)
|
||||||
|
|
||||||
def ReadInt32(self, endianness=None) -> int:
|
def ReadInt32(self, endianness:str=None) -> int:
|
||||||
return self._read("i", 4, endianness)
|
return self._read("i", 4, endianness)
|
||||||
|
|
||||||
def ReadUInt32(self, endianness=None) -> int:
|
def ReadUInt32(self, endianness:str=None) -> int:
|
||||||
return self._read("I", 4, endianness)
|
return self._read("I", 4, endianness)
|
||||||
|
|
||||||
def ReadLong(self, endianness=None) -> int:
|
def ReadLong(self, endianness:str=None) -> int:
|
||||||
return self._read("l", 4, endianness)
|
return self._read("l", 4, endianness)
|
||||||
|
|
||||||
def ReadULong(self, endianness=None) -> int:
|
def ReadULong(self, endianness:str=None) -> int:
|
||||||
return self._read("L", 4, endianness)
|
return self._read("L", 4, endianness)
|
||||||
|
|
||||||
def ReadLongLong(self, endianness=None) -> int:
|
def ReadLongLong(self, endianness:str=None) -> int:
|
||||||
return self._read("q", 8, endianness)
|
return self._read("q", 8, endianness)
|
||||||
|
|
||||||
def ReadULongLong(self, endianness=None) -> int:
|
def ReadULongLong(self, endianness:str=None) -> int:
|
||||||
return self._read("Q", 8, endianness)
|
return self._read("Q", 8, endianness)
|
||||||
|
|
||||||
def ReadBytes(self, length:int, endianness=None) -> bytes:
|
def ReadBytes(self, length:int, endianness:str=None) -> bytes:
|
||||||
return self._read(f"{str(length)}s", int(length), endianness)
|
return self._read(f"{str(length)}s", int(length), endianness)
|
||||||
|
|
||||||
# buffer utils
|
# buffer utils
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -1,67 +0,0 @@
|
|||||||
# modified version to ignore filenames (and wav)
|
|
||||||
#
|
|
||||||
# scan data for wave files
|
|
||||||
# RIFF and RIFX header supported
|
|
||||||
# note: There are wave files with a wrong file size after RIFF/RIFX
|
|
||||||
# This script takes the stream size, adds the header size and writes the correct size after RIFF/RIFX
|
|
||||||
# (c) 2012-06-26 by AlphaTwentyThree
|
|
||||||
#
|
|
||||||
# future update plans:
|
|
||||||
# - option to also write data between found wave files to disk
|
|
||||||
# - option to automatically transform the file to a playable or at least decodable format
|
|
||||||
|
|
||||||
for i = 1 # run through loop with count variable i
|
|
||||||
FindLoc OFFSET string "WAVE" 0 "" # search for "WAVE", save position as variable OFFSET
|
|
||||||
if OFFSET == "" # when nothing is found
|
|
||||||
cleanexit # the script exits (e.g. at end of file)
|
|
||||||
endif
|
|
||||||
math OFFSET -= 8 # jump to possible
|
|
||||||
goto OFFSET # RIFF/RIFX file start
|
|
||||||
getDstring IDENT 4 # read string of 4 bytes, save variable as IDENT
|
|
||||||
if IDENT == "RIFX" # differentiate between header possibilities
|
|
||||||
endian big # set endianness to big, if file has RIFX identifier
|
|
||||||
callfunction write 1 # see function section below
|
|
||||||
elif IDENT == "RIFF" # endianness stays little
|
|
||||||
callfunction write 1 # also run function
|
|
||||||
else # string "WAVE" found, but doesn't belong to wave file
|
|
||||||
set SIZE 0xc # do as if something with 0xc bytes was found to continue search from the right position
|
|
||||||
endif
|
|
||||||
set SEARCH OFFSET # set marker to position from where to search next
|
|
||||||
math SEARCH += SIZE # (that would be after the file that was found)
|
|
||||||
if SEARCH == FSIZE # in case the last found file ends with the main file, we exit
|
|
||||||
cleanexit
|
|
||||||
endif
|
|
||||||
goto SEARCH # if we haven't exited the script above, we set out cursor to after the last found file
|
|
||||||
next i
|
|
||||||
|
|
||||||
startfunction write # function "write" starts here, is called when a wave file is found above
|
|
||||||
get NAME basename # save name without extension under variable NAME
|
|
||||||
string NAME += "_" # add underscore to the name
|
|
||||||
string NAME += i # add the loop variable to the name
|
|
||||||
goto OFFSET # set cursor to the beginning of the found file
|
|
||||||
get DUMMY long # RIFF/RIFX identifier, not needed
|
|
||||||
get DUMMY long # riff size, not needed
|
|
||||||
get DUMMY long # "WAVE", not needed, we arrive at the "fmt " section
|
|
||||||
for # loop search for the "data" section at the start of the stream (get the stream size from there)
|
|
||||||
getDstring AREA_NAME 4 # name of area in header
|
|
||||||
get AREA_SIZE long # size of area in header
|
|
||||||
savepos MYOFF # save position we are at
|
|
||||||
if AREA_NAME == "data" # when we arrive at the needed "data" area:
|
|
||||||
break # we exit the loop
|
|
||||||
else # otherwise:
|
|
||||||
math MYOFF += AREA_SIZE # not reached "data" area -> adjust cursor position...
|
|
||||||
goto MYOFF # ... and go there
|
|
||||||
endif
|
|
||||||
next # remember: the cursor is now directly at the stream start
|
|
||||||
set STREAMSIZE AREA_SIZE # the last AREA_SIZE is the size we need (size of the audio stream)
|
|
||||||
set HEADERSIZE MYOFF #
|
|
||||||
math HEADERSIZE -= OFFSET # calculate the size of the stream header (offset - offset = size)
|
|
||||||
set SIZE HEADERSIZE #
|
|
||||||
math SIZE += STREAMSIZE # calculate complete file size (header + stream = file)
|
|
||||||
log MEMORY_FILE OFFSET SIZE # write file to memory
|
|
||||||
math SIZE -= 8 # subtract 8 bytes to get the riff size
|
|
||||||
putVarChr MEMORY_FILE 4 SIZE long # write the correct riff size to the header inside the memory
|
|
||||||
string NAME += ".wem" # add extension to the name (the name could contain the name of the first marker if the file has markers)
|
|
||||||
math SIZE += 8 # add the subtracted 8 bytes again
|
|
||||||
log NAME 0 SIZE MEMORY_FILE # write file in memory to disk
|
|
||||||
endfunction # remember that we continue with our next i now!
|
|
||||||
26
wavescan.py
26
wavescan.py
@@ -1,16 +1,18 @@
|
|||||||
# Custom rewrite of the Wwise AKPK packages extractor, original by Nicknine and bnnm
|
# Custom rewrite of the Wwise AKPK packages extractor, original by Nicknine and bnnm
|
||||||
# TODO: use extracted files id with the mapping table to restore file names
|
# TODO: use extracted files id with the mapping table to restore file names
|
||||||
# TODO: make this script callable by the main one
|
|
||||||
from filereader import FileReader
|
from filereader import FileReader
|
||||||
import os
|
import os
|
||||||
|
|
||||||
filename = "External0.pck"
|
|
||||||
cwd = os.getcwd()
|
reader = None
|
||||||
reader = FileReader(open(filename, "rb"), "little") # defaults to little endian
|
|
||||||
bank_version = 0
|
bank_version = 0
|
||||||
|
|
||||||
def main():
|
|
||||||
|
def extract(input_file, output_folder):
|
||||||
global bank_version
|
global bank_version
|
||||||
|
global reader
|
||||||
|
|
||||||
|
reader = FileReader(open(input_file, "rb"), "little") # defaults to little endian
|
||||||
|
|
||||||
# check file
|
# check file
|
||||||
if reader.ReadBytes(4) != b"AKPK":
|
if reader.ReadBytes(4) != b"AKPK":
|
||||||
@@ -50,7 +52,7 @@ def main():
|
|||||||
|
|
||||||
# extract each sector
|
# extract each sector
|
||||||
for sector in sectors:
|
for sector in sectors:
|
||||||
extract_sector(*sector[1:], endianness, lang_array, bank_version)
|
extract_sector(*sector[1:], endianness, lang_array, bank_version, output_folder)
|
||||||
|
|
||||||
if sector[0] and bank_version == 0:
|
if sector[0] and bank_version == 0:
|
||||||
if externals_sector_size == 0:
|
if externals_sector_size == 0:
|
||||||
@@ -109,7 +111,7 @@ def detect_bank_version(offset):
|
|||||||
|
|
||||||
reader.SetBufferPos(current)
|
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):
|
def extract_sector(section_size, is_sounds, is_externals, ext, endianness, lang_array, bank_version, output_folder, filter_bnk_only=0, filter_wem_only=0):
|
||||||
# check sector validity
|
# check sector validity
|
||||||
if section_size == 0:
|
if section_size == 0:
|
||||||
return
|
return
|
||||||
@@ -193,20 +195,18 @@ def extract_sector(section_size, is_sounds, is_externals, ext, endianness, lang_
|
|||||||
if filter_wem_only == 1 and ext != "wem":
|
if filter_wem_only == 1 and ext != "wem":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
print(f"NAME - {name} | OFFSET - {offset} | SIZE - {size}")
|
# file infos
|
||||||
|
# print(f"NAME - {name} | OFFSET - {offset} | SIZE - {size}")
|
||||||
|
|
||||||
# save file into disk
|
# save file into disk
|
||||||
current = reader.GetBufferPos()
|
current = reader.GetBufferPos()
|
||||||
reader.SetBufferPos(offset)
|
reader.SetBufferPos(offset)
|
||||||
file_data = reader.ReadBytes(size)
|
file_data = reader.ReadBytes(size)
|
||||||
|
|
||||||
os.makedirs(os.path.join(cwd, os.path.dirname(name)), exist_ok=True)
|
os.makedirs(output_folder, exist_ok=True)
|
||||||
|
|
||||||
with open(os.path.join(cwd, name), "wb+") as f:
|
with open(os.path.join(output_folder, os.path.basename(name)), "wb+") as f:
|
||||||
f.write(file_data)
|
f.write(file_data)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
reader.SetBufferPos(current)
|
reader.SetBufferPos(current)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|||||||
Reference in New Issue
Block a user