接上回提取MIDI后提取音频时发现2代的音频存储和1代的有挺大差别的(不再是明文存储了:)这次的音频好像是用了一个叫SoundBanks的东西来处理(相关的名词还有Wwise、JetGen、AK...,不知道是不是新的Unity都是这样搞了?),背景部分我就只知道这么多了,就直接说怎么提取的吧:
首先和提取MIDI一样,要先拿到音频的asset数据:游戏安装完后把那2G的资源下载完,然后手机插电脑,复制Android/com.rayark.deemo2/files/aaremote/data/
下面所有soundbanks_android
开头的文件,然后扔进AssetStudio里面,如无意外会看到一堆Json
格式的MonoBehaviour
,其中content
部分是个bytes
(就是0~255)的数组(m_Name
会看到音频资源的名字,比如歌名)。
把全部Export出来,会拿到MonoBehaviour
的文件夹和里面的一堆Json文件,先记住这个文件夹的路径。先说一下content
是个啥,其实里面是一个BNK(Wwise SoundBank)文件,把数组的数字转成bytes后输出到文件,然后用二进制编辑器打开是可以看到BNK文件的格式的,比如开头是BKHD
,然后对应的DIDX
段、DATA
段和HIRC
段:
所以接下来做的就是把全部Json文件的content的BNK提取出来,直接上Python就好了(最后再给代码,逃
按照BNK格式的说明,DATA
段对应的会是一个WEM文件,好像是Wwies的某个音频格式,但其实更像一个加密了的WAV文件,因为头部是和WAV一样的,但是内容却是乱的(没有WAV那样“明显”的规律)。然后跟 @c10udlnk 俩撒子逆了一晚上,发现已经有现成的解密工具 RadicalMusic-Decryptor了,就直接调用了。
所以基本思路就是:ASSET -> BNK -> WEM -> OGG -(看需求)-> WAV
参考代码(同懒得优化了):
import os
import json
import shutil
RESULT_DIR = '...\\path\\to\\outDIR\\' # create by yourself!
MONO_DIR = '...\\path\\to\\MonoBehaviour\\'
RMD_DIR = '...\\path\\to\\RadicalMusic-Decryptor-master\\'
# get file name
tmp = []
for _,_,f in os.walk(MONO_DIR):
tmp = f
files = []
for t in tmp:
if '.json' in t:
files.append(t[:-5])
#print(files)
songs = []
for fi in files:
with open(MONO_DIR+fi+'.json', 'r', encoding='utf-8') as f:
data = json.loads(f.read())
try:
content = data['content']
content[0] + 1
except:
continue
with open(RESULT_DIR+fi+'.bnk', 'wb') as f:
f.write(bytes(content))
songs.append(fi)
print(fi + ' - done bnk')
print('')
serror = []
for s in songs:
# API
os.system(RMD_DIR + 'bnk2wem\\bnkextr.exe ' + RESULT_DIR + s +'.bnk')
# change dir
for _,_,f in os.walk(RESULT_DIR + s):
sname = f
for i in range(len(sname)):
try:
name = s + '_%d'%i
if i == 0:
name = s
shutil.move(RESULT_DIR + s + '\\' + sname[i], RESULT_DIR + name + '.wem')
print(name + ' - done wem')
# API again...
os.system(RMD_DIR + '\\wem2ogg\\ww2ogg024\\ww2ogg.exe ' + RESULT_DIR + name + '.wem --pcb "' + RMD_DIR + '\\wem2ogg\\ww2ogg024\\packed_codebooks_aoTuV_603.bin"')
os.system(RMD_DIR + '\\wem2ogg\\revorb.exe ' + RESULT_DIR + name + '.ogg')
print(name + ' - done ogg')
except:
serror.append(s)
continue
# delete old dir
try:
os.rmdir(RESULT_DIR + s)
os.remove(RESULT_DIR + s + '.bnk')
for i in range(len(sname)):
name = s + '_%d'%i
if i == 0:
name = s
os.remove(RESULT_DIR + name + '.wem')
except:
serror.append(s + ' - dir')
pass
print(serror)
用法:把三个DIR
填好后运行就行了;RESULT_DIR
是最后的OGG文件放的目录,需要自己手动创建,过程中会产生大量的中间文件(当然最后会自动删掉),所以运行的时候不要用文件管理器打开这个目录;MONO_DIR
是用AssetStudio提取出来的那堆Json的目录;RMD_DIR
是把RadicalMusic-Decryptor Clone下来后的目录(我是Windows里直接下zip的,所以带个master?)
如无意外的话运行完后RESULT_DIR
里就是所有音频的OGG文件了(已经可以播放了,大小大概1G)。然后还可以按需转成WAV(大小大概25G - -),这里会调用ffmpeg
,所以转之前应该先保证ffmpeg
已经安装好了:
import os
IN_DIR ='...\\path\\to\\your\\RESULT_DIR \\'
OUT_DIR ='...\\path\\to\\outWav\\' # create by yourself
for _,_,f in os.walk(IN_DIR):
tmp = f
files = []
for t in tmp:
if '.ogg' in t:
files.append(t[:-4])
for f in files:
os.system('ffmpeg -i out\\%s.ogg outWav\\%s.wav' % (f, f)) # 这里忘了改路径了,自己改吧,逃
(不骗你,真25G,8K+文件 - -