diff --git a/tools/sfxconvert.py b/tools/sfxconvert.py new file mode 100755 index 0000000000..22044dd594 --- /dev/null +++ b/tools/sfxconvert.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 + +import os +import argparse + +AudioFunctions = {} +Verbose = False +Verbose2 = False + +def set_verbose(v): + global Verbose + global Verbose2 + + Verbose = v + Verbose2 = v + return 1 + +def make_audio_dict(AudioFunctions, repo): + with open(repo + os.sep + 'include' + os.sep + 'functions.h','r') as funcfile: + funcdata = funcfile.readlines() + for i, line in enumerate(funcdata): + if(line.count('sfxId')): + funcname, argnum = get_func_data(funcdata,i) + if(funcname != None): + AudioFunctions[funcname] = argnum + return 1 + +def get_func_data(funcdata,i): + j = i + while(funcdata[j - 1].count(';') == 0): + j -= 1 + k = i + 1 + while(funcdata[k - 1].count(';') == 0): + k += 1 + prototype = "".join(funcdata[j:k]) + argdata = prototype.replace('(',',').replace(')',',').split(',') + funcname = argdata[0].split(' ')[1] + for x in range(len(argdata)): + if(argdata[x].count('sfxId')): + break; + if(x == len(argdata) - 1): + print('sfxId not found in ', funcname) + return None,-1 + return funcname, x - 1 + +def lookup_sfx(idnum, repo): + if(type(idnum) is int): + id = '0x' + format(idnum,'X') + elif(idnum.isnumeric()): + id = '0x' + format(int(idnum),'X') + else: + id = idnum + idfix,sfxFlag = fix_sfx_flag(id) + with open(repo + os.sep + 'include' + os.sep + 'sfx.h','r') as sfxfile: + for line in sfxfile: + if(line.count(idfix)): + return line.split(' ')[1] + sfxFlag + return 'INVALID_ID' + +def fix_sfx_flag(id): + if(id.endswith(' - SFX_FLAG')): + splitdata = id.split('-') + return splitdata[0].strip(), ' -' + splitdata[1] + if not(int(id,16) & 0x800): + newid = '0x' + format(int(id,16) + 0x800,'X') + sfxFlag = ' - SFX_FLAG' + else : + newid = id + sfxFlag = '' + return newid,sfxFlag + +def fix_sfx_func(sourcedata, i, j, repo): + data = ''.join(sourcedata[i:j]) + func = data.split('(')[0].strip() + index = data.find(func) + argnum = AudioFunctions.get(func,-1) + if(argnum == -1 or index == -1): + print('Function lookup error at line', i, 'in', func) + return -1 + args = data[index:].replace('(',',').replace(')',',').split(',') + sfxId = args[argnum + 1].strip() + if(sfxId.count('NA_SE') != 0): + return 0 + newId = lookup_sfx(sfxId, repo) + if(newId == 'INVALID_ID'): + print('ID parse error at line', i, 'in', func) + return -2 + for k in range(i, j): + sourcedata[k] = sourcedata[k].replace(sfxId,newId) + if Verbose: + print('Replaced', sfxId, 'with', newId, 'in', func, 'at line', i + 1) + return 1 + +def find_audio_func(line): + audiofuncs = list(AudioFunctions.keys()) + funcname = line.split('(')[0].strip() + for func in audiofuncs: + if(line.count(func)): + return func + return False + +def fix_sfx_all(repo): + global Verbose2 + + tv = Verbose2 + Verbose2 = False + + for subdir, dirs, files in os.walk(repo + os.sep + 'src'): + for filename in files: + if(filename.endswith('.c')): + file = subdir + os.sep + filename + fix_sfx(file, repo) + + Verbose2 = tv + return 1 + +def fix_sfx(file, repo, outfile = None): + if(outfile == None): + outfile = file + make_audio_dict(AudioFunctions, repo) + with open(file,'r',encoding='utf-8') as sourcefile: + sourcedata = sourcefile.readlines() + replacements = set() + j = 0 + lookuperrors = 0 + funcerrors = 0 + iderrors = 0 + fixes = 0 + for i, line in enumerate(sourcedata): + if(i < j): + continue + if(find_audio_func(line)): + j = i + while(sourcedata[j].count(';') == 0): + j += 1 + status = fix_sfx_func(sourcedata, i, j + 1, repo) + if(status == -2): + iderrors += 1 + elif(status == -1): + lookuperrors += 1 + elif(status > 0): + fixes += 1 + if(fixes > 0): + with open(outfile,'w',encoding ='utf-8',newline='\n') as outfile: + outfile.writelines(sourcedata) + if Verbose: + print(file, 'updated') + elif Verbose2: + print('No changes made to', file) + if(lookuperrors > 0): + print('Problem with function lookup. Try formatting functions.h') + if(iderrors > 0): + print('Problem with id parsing. Make sure your SFX ids are in hex.') + return 1 + +parser = argparse.ArgumentParser(description='Convert hex SFX ids to macros') +parser.add_argument('file', help="source file to be processed") +parser.add_argument('repo', help="directory of the decomp repo") +parser.add_argument('-o', metavar='outfile',dest='outfile',help='file to write to instead of original') +parser.add_argument('-v', action='store_true',help='show what changes are made') + +if __name__ == "__main__": + args = parser.parse_args() + set_verbose(args.v) + fix_sfx(args.file, args.repo, outfile=args.outfile) + +