1
0
mirror of synced 2025-02-03 13:13:26 +01:00

tja2fumen.py: Add convertTJAToFumen function

Thie is a first draft with many TODOs.
This commit is contained in:
Viv 2023-06-02 16:33:44 -04:00
parent 8b07fb77d0
commit 185ed46361

View File

@ -2,6 +2,8 @@ import os
import sys import sys
import struct import struct
import argparse import argparse
from copy import deepcopy
from parsetja import parseTJA
tja2fumen_version = "v0.1" tja2fumen_version = "v0.1"
@ -416,6 +418,109 @@ def checkMismatchedBytes(file1, file2):
return incorrect_bytes return incorrect_bytes
TJA_NOTE_TYPES = {
'1': 'Don',
'2': 'Ka',
'3': 'DON',
'4': 'KA',
'5': 'Drumroll',
'6': 'DRUMROLL',
'7': 'Balloon',
'8': 'EndDRB',
'9': 'Kusudama',
'A': 'DON', # hands
'B': 'KA', # hands
}
# Filler metadata that the `writeFumen` function expects
default_note = {'type': '', 'pos': 0.0, 'item': 0, 'padding': 0.0,
'scoreInit': 0, 'scoreDiff': 0, 'durationPadding': 0.0}
default_branch = {'length': 0, 'padding': 0, 'speed': 1.0}
default_measure = {
'bpm': 0.0,
'fumenOffset': 0.0,
'gogo': False,
'hidden': False,
'padding1': 0,
'branchInfo': [-1, -1, -1, -1, -1, -1],
'padding2': 0,
'normal': deepcopy(default_branch),
'advanced': deepcopy(default_branch),
'master': deepcopy(default_branch)
}
def convertTJAToFumen(fumen, tja):
# Fumen offset for the first measure that has a barline
fumenOffset1 = float(tja['metadata']['offset']) * -1000
# Variables that will change over time due to events
currentBPM = 0.0
currentGogo = False
currentHidden = False
currentBranch = 'normal' # TODO: Program in branch support
# Parse TJA measures to create converted TJA -> Fumen file
tjaConverted = { 'measures': [] }
for i, measureTJA in enumerate(tja['measures']):
measureFumenExample = fumen['measures'][i+9]
measureFumen = deepcopy(default_measure)
# TODO Event: GOGOTIME
# TODO Event: HIDDEN
# TODO Event: BARLINE
# TODO Event: MEASURE
# Event: BPMCHANGE
# TODO: Handle TJA measure being broken up into multiple Fumen measures due to mid-measure BPM changes
midMeasureBPM = [(0, currentBPM)]
for event in measureTJA['events']:
if event['name'] == 'bpm':
currentBPM = float(event['value'])
if event['position'] == 0:
midMeasureBPM[0] = (0, currentBPM,)
else:
midMeasureBPM.append((event['position'], currentBPM))
if len(midMeasureBPM) > 1:
test = None
measureFumen['bpm'] = currentBPM
# TODO: `measureFumen['fumenOffset']
# Will need to account for BARLINEON and BARLINEOFF.
# Some examples that line up with actual fumen data:
# fumenOffset0 = (fumenOffset1 - measureLength)
# fumenOffset2 = (fumenOffset1 + measureLength)
measureLength = 240_000 / currentBPM
# measureFumen['fumenOffset'] = prev['fumenOffset'] + measureLength
# Create note dictionaries based on TJA measure data (containing 0's plus 1/2/3/4/etc. for notes)
note_counter = 0
for i, note_value in enumerate(measureTJA['data']):
if note_value != '0':
note = deepcopy(default_note)
note['pos'] = measureLength * (i / len(measureTJA['data']))
note['type'] = TJA_NOTE_TYPES[note_value] # TODO: Handle BALLOON/DRUMROLL
note['scoreInit'] = tja['scoreInit'] # Probably not fully accurate
note['scoreDiff'] = tja['scoreDiff'] # Probably not fully accurate
measureFumen[currentBranch][note_counter] = note
note_counter += 1
measureFumen[currentBranch]['length'] = note_counter
# Append the measure to the tja's list of measures
tjaConverted['measures'].append(measureFumen)
tjaConverted['headerUnknown'] = b'x\00' * 80
tjaConverted['order'] = '<'
tjaConverted['length'] = len(tjaConverted['measures'])
tjaConverted['unknownMetadata'] = 0
tjaConverted['branches'] = False
return tjaConverted
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="tja2fumen {0}".format(tja2fumen_version) description="tja2fumen {0}".format(tja2fumen_version)
@ -483,12 +588,28 @@ if __name__ == "__main__":
if len(sys.argv) == 1: if len(sys.argv) == 1:
parser.print_help() parser.print_help()
else: else:
arguments = parser.parse_args() # arguments = parser.parse_args()
inputFile = getattr(arguments, "file_m.bin") arguments = {
parsedSong = readFumen(inputFile, arguments.order, arguments.debug) "input_fumen": "./roku/ia6cho_m.bin", # NB: Contains only oni chart
outputName = inputFile.name.split('.')[0] + "_rebuilt.bin" "input_tja": "./roku/Rokuchounen to Ichiya Monogatari.tja", # NB: Contains 5 charts
outputFile = open(outputName, "wb") }
writeFumen(outputFile, parsedSong) # Parse fumen
# Read output file back in to validate that the rewritten song is a perfect match inputFile = open(arguments["input_fumen"], "rb")
inputFileOut = open(outputName, "rb") parsedSongFumen = readFumen(inputFile)
print(checkMismatchedBytes(inputFile.name, outputFile.name))
# Steps to validate the `writeFumen` function to make sure it reproduces correct output
validate = False
if validate:
outputName = inputFile.name.split('.')[0] + "_rebuilt.bin"
outputFile = open(outputName, "wb")
writeFumen(outputFile, parsedSongFumen)
# Read output file back in to validate that the rewritten song is a perfect match
print(False if checkMismatchedBytes(inputFile.name, outputFile.name) else True)
# Parse tja
inputFile = open(arguments["input_tja"], "r", encoding="utf-8-sig")
parsedSongsTJA = parseTJA(inputFile)
# Try converting the Oni TJA chart to match the Oni fumen
convertedTJA = convertTJAToFumen(parsedSongFumen, parsedSongsTJA['Oni'])
# writeFumen(outputFile, convertedTJA)