tja2fumen.py
: Rewrite song information to fumen files
On at least one song I've tested, this creates a perfect match, meaning that we now have the ability to create a fumen file from a "song" object. The next challenge is reading TJA files into "song" objects.
This commit is contained in:
parent
adbc81a9c2
commit
9879cd9b7c
@ -36,6 +36,7 @@ noteTypes = {
|
||||
0x22: "Unknown13", # ? (Present in some Wii1 songs)
|
||||
0x62: "Drumroll2" # ?
|
||||
}
|
||||
typeNotes = {v: k for k, v in noteTypes.items()}
|
||||
|
||||
# Fumen headers are made up of smaller substrings of bytes
|
||||
b_x00 = b'\x00\x00\x00\x00\x00\x00'
|
||||
@ -296,6 +297,73 @@ def readStruct(file, order, format_string, seek=None):
|
||||
return interpreted_string
|
||||
|
||||
|
||||
def writeFumen(file, song):
|
||||
# Fetch the byte order (little/big endian)
|
||||
order = song['order']
|
||||
|
||||
# Write the header
|
||||
file.write(simpleHeaders[0]) # Write known, valid header
|
||||
file.write(song['headerUnknown']) # Write unknown header
|
||||
|
||||
# Preallocate space in the file
|
||||
len_metadata = 8
|
||||
len_measures = 0
|
||||
for measureNumber in range(song['length']):
|
||||
len_measures += 40
|
||||
measure = song[measureNumber]
|
||||
for branchNumber in range(len(branchNames)):
|
||||
len_measures += 8
|
||||
branch = measure[branchNames[branchNumber]]
|
||||
for noteNumber in range(branch['length']):
|
||||
len_measures += 24
|
||||
note = branch[noteNumber]
|
||||
if note['type'].lower() == "drumroll":
|
||||
len_measures += 8
|
||||
file.write(b'\x00' * (len_metadata + len_measures))
|
||||
|
||||
# Write metadata
|
||||
writeStruct(file, order, format_string="B", value_list=[putBool(song['branches'])], seek=0x1b0)
|
||||
writeStruct(file, order, format_string="I", value_list=[song['length']], seek=0x200)
|
||||
|
||||
# Write measure data
|
||||
file.seek(0x208)
|
||||
for measureNumber in range(song['length']):
|
||||
measure = song[measureNumber]
|
||||
measureStruct = [measure['bpm'], measure['fumenOffset'], int(measure['gogo']), int(measure['hidden'])]
|
||||
measureStruct.extend([measure['padding1']] + measure['branchInfo'] + [measure['padding2']])
|
||||
writeStruct(file, order, format_string="ffBBHiiiiiii", value_list=measureStruct)
|
||||
|
||||
for branchNumber in range(len(branchNames)):
|
||||
branch = measure[branchNames[branchNumber]]
|
||||
branchStruct = [branch['length'], branch['padding'], branch['speed']]
|
||||
writeStruct(file, order, format_string="HHf", value_list=branchStruct)
|
||||
|
||||
for noteNumber in range(branch['length']):
|
||||
note = branch[noteNumber]
|
||||
noteStruct = [typeNotes[note['type']], note['pos'], note['item'], note['padding']]
|
||||
# Balloon hits
|
||||
if 'hits' in note.keys():
|
||||
noteStruct.extend([note["hits"], note['hitsPadding']])
|
||||
else:
|
||||
noteStruct.extend([note['scoreInit'], int(note['scoreDiff'] * 4)])
|
||||
# Drumroll or balloon duration
|
||||
if 'duration' in note.keys():
|
||||
noteStruct.append(note['duration'])
|
||||
else:
|
||||
noteStruct.append(note['durationPadding'])
|
||||
writeStruct(file, order, format_string="ififHHf", value_list=noteStruct)
|
||||
if note['type'].lower() == "drumroll":
|
||||
file.seek(0x8, os.SEEK_CUR)
|
||||
file.close()
|
||||
|
||||
|
||||
def writeStruct(file, order, format_string, value_list, seek=None):
|
||||
if seek:
|
||||
file.seek(seek)
|
||||
packed_bytes = struct.pack(order + format_string, *value_list)
|
||||
file.write(packed_bytes)
|
||||
|
||||
|
||||
def shortHex(number):
|
||||
return hex(number)[2:]
|
||||
|
||||
@ -304,6 +372,10 @@ def getBool(number):
|
||||
return True if number == 0x1 else False if number == 0x0 else number
|
||||
|
||||
|
||||
def putBool(boolean):
|
||||
return 0x1 if boolean is True else 0x0 if boolean is False else boolean
|
||||
|
||||
|
||||
def nameValue(*lists):
|
||||
string = []
|
||||
for lst in lists:
|
||||
@ -392,4 +464,6 @@ if __name__ == "__main__":
|
||||
arguments = parser.parse_args()
|
||||
inputFile = getattr(arguments, "file_m.bin")
|
||||
parsedSong = readFumen(inputFile, arguments.order, arguments.debug)
|
||||
breakpoint()
|
||||
outputName = inputFile.name.split('.')[0] + "_rebuilt.bin"
|
||||
outputFile = open(outputName, "wb")
|
||||
writeFumen(outputFile, parsedSong)
|
||||
|
Loading…
Reference in New Issue
Block a user