上回提取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+文件 - -

© 2018-2025 0xFFFF