summaryrefslogtreecommitdiff
path: root/tools/sfxconvert.py
blob: a125467aefd3afc4f2e2e181403fe15a3e7ea9d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
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)