parsetja.py
: Slightly refactor the getCourse
function
The big if/elses were a little hard to parse, so I broke things into subfunctions.
This commit is contained in:
parent
35ba7bfeba
commit
b7670b54a3
@ -5,20 +5,108 @@ import re
|
|||||||
# Valid strings for headers and chart commands
|
# Valid strings for headers and chart commands
|
||||||
HEADER_GLOBAL = ['TITLE', 'TITLEJA', 'SUBTITLE', 'SUBTITLEJA', 'BPM', 'WAVE', 'OFFSET', 'DEMOSTART', 'GENRE']
|
HEADER_GLOBAL = ['TITLE', 'TITLEJA', 'SUBTITLE', 'SUBTITLEJA', 'BPM', 'WAVE', 'OFFSET', 'DEMOSTART', 'GENRE']
|
||||||
HEADER_COURSE = ['COURSE', 'LEVEL', 'BALLOON', 'SCOREINIT', 'SCOREDIFF', 'TTRO' 'WBEAT']
|
HEADER_COURSE = ['COURSE', 'LEVEL', 'BALLOON', 'SCOREINIT', 'SCOREDIFF', 'TTRO' 'WBEAT']
|
||||||
COMMAND = ['START', 'END', 'GOGOSTART', 'GOGOEND', 'BRANCHSTART', 'BRANCHEND', 'BARLINEON', 'BARLINEOFF', 'MEASURE',
|
BRANCH_COMMANDS = ['START', 'END', 'BRANCHSTART', 'BRANCHEND', 'N', 'E', 'M']
|
||||||
'BPMCHANGE', 'DELAY', 'SECTION', 'N', 'E', 'M', 'LEVELHOLD', 'SCROLL', 'BMSCROLL', 'HBSCROLL', 'TTBREAK']
|
MEASURE_COMMANDS = ['MEASURE', 'GOGOSTART', 'GOGOEND', 'SCROLL', 'BPMCHANGE', 'TTBREAK' 'LEVELHOLD']
|
||||||
|
UNUSED_COMMANDS = ['DELAY', 'SECTION', 'BMSCROLL', 'HBSCROLL', 'BARLINEON', 'BARLINEOFF']
|
||||||
|
COMMAND = BRANCH_COMMANDS + MEASURE_COMMANDS + UNUSED_COMMANDS
|
||||||
|
|
||||||
|
|
||||||
def getCourse(tjaHeaders, lines):
|
def getCourse(tjaHeaders, lines):
|
||||||
headers = {
|
def parseHeaderMetadata(line):
|
||||||
"course": 'Oni',
|
nonlocal headers
|
||||||
"level": 0,
|
if line["name"] == 'COURSE':
|
||||||
"balloon": [],
|
headers['course'] = line['value']
|
||||||
"scoreInit": 100,
|
elif line["name"] == 'LEVEL':
|
||||||
"scoreDiff": 100,
|
headers['level'] = int(line['value'])
|
||||||
"ttRowBeat": 16,
|
elif line["name"] == 'SCOREINIT':
|
||||||
}
|
headers['scoreInit'] = int(line['value'])
|
||||||
|
elif line["name"] == 'SCOREDIFF':
|
||||||
|
headers['scoreDiff'] = int(line['value'])
|
||||||
|
elif line["name"] == 'TTROWBEAT':
|
||||||
|
headers['ttRowBeat'] = int(line['value'])
|
||||||
|
elif line["name"] == 'BALLOON':
|
||||||
|
if line['value']:
|
||||||
|
balloons = [int(v) for v in line['value'].split(",")]
|
||||||
|
else:
|
||||||
|
balloons = []
|
||||||
|
headers['balloon'] = balloons
|
||||||
|
|
||||||
|
def parseBranchCommands(line):
|
||||||
|
nonlocal flagLevelhold, targetBranch, currentBranch
|
||||||
|
if line["name"] == 'BRANCHSTART':
|
||||||
|
if flagLevelhold:
|
||||||
|
return
|
||||||
|
values = line['value'].split(',')
|
||||||
|
if values[0] == 'r':
|
||||||
|
if len(values) >= 3:
|
||||||
|
targetBranch = 'M'
|
||||||
|
elif len(values) == 2:
|
||||||
|
targetBranch = 'E'
|
||||||
|
else:
|
||||||
|
targetBranch = 'N'
|
||||||
|
elif values[0] == 'p':
|
||||||
|
if len(values) >= 3 and float(values[2]) <= 100:
|
||||||
|
targetBranch = 'M'
|
||||||
|
elif len(values) >= 2 and float(values[1]) <= 100:
|
||||||
|
targetBranch = 'E'
|
||||||
|
else:
|
||||||
|
targetBranch = 'N'
|
||||||
|
elif line["name"] == 'BRANCHEND':
|
||||||
|
currentBranch = targetBranch
|
||||||
|
elif line["name"] == 'N':
|
||||||
|
currentBranch = 'N'
|
||||||
|
elif line["name"] == 'E':
|
||||||
|
currentBranch = 'E'
|
||||||
|
elif line["name"] == 'M':
|
||||||
|
currentBranch = 'M'
|
||||||
|
elif line["name"] == 'START' or line['name'] == 'END':
|
||||||
|
currentBranch = 'N'
|
||||||
|
targetBranch = 'N'
|
||||||
|
flagLevelhold = False
|
||||||
|
|
||||||
|
def parseMeasureCommands(line):
|
||||||
|
nonlocal measureDivisor, measureDividend, measureEvents, measureProperties, flagLevelhold
|
||||||
|
if line['name'] == 'MEASURE':
|
||||||
|
matchMeasure = re.match(r"(\d+)/(\d+)", line['value'])
|
||||||
|
if not matchMeasure:
|
||||||
|
return
|
||||||
|
measureDividend = int(matchMeasure.group(1))
|
||||||
|
measureDivisor = int(matchMeasure.group(2))
|
||||||
|
elif line['name'] == 'GOGOSTART':
|
||||||
|
measureEvents.append({"name": 'gogoStart', "position": len(measureData)})
|
||||||
|
elif line['name'] == 'GOGOEND':
|
||||||
|
measureEvents.append({"name": 'gogoEnd', "position": len(measureData)})
|
||||||
|
elif line['name'] == 'SCROLL':
|
||||||
|
measureEvents.append({"name": 'scroll', "position": len(measureData), "value": float(line['value'])})
|
||||||
|
elif line['name'] == 'BPMCHANGE':
|
||||||
|
measureEvents.append({"name": 'bpm', "position": len(measureData), "value": float(line['value'])})
|
||||||
|
elif line['name'] == 'TTBREAK':
|
||||||
|
measureProperties['ttBreak'] = True
|
||||||
|
elif line['name'] == 'LEVELHOLD':
|
||||||
|
flagLevelhold = True
|
||||||
|
|
||||||
|
def parseMeasureData(line):
|
||||||
|
nonlocal measures, measureData, measureDividend, measureDivisor, measureEvents, measureProperties
|
||||||
|
data = line['data']
|
||||||
|
# If measure has ended, then append the measure and start anew
|
||||||
|
if data.endswith(','):
|
||||||
|
measureData += data[0:-1]
|
||||||
|
measure = {
|
||||||
|
"length": [measureDividend, measureDivisor],
|
||||||
|
"properties": measureProperties,
|
||||||
|
"data": measureData,
|
||||||
|
"events": measureEvents,
|
||||||
|
}
|
||||||
|
measures.append(measure)
|
||||||
|
measureData = ''
|
||||||
|
measureEvents = []
|
||||||
|
measureProperties = {}
|
||||||
|
# Otherwise, keep tracking measureData
|
||||||
|
else:
|
||||||
|
measureData += data
|
||||||
|
|
||||||
|
# Define state variables
|
||||||
|
headers = {}
|
||||||
measures = []
|
measures = []
|
||||||
measureDividend = 4
|
measureDividend = 4
|
||||||
measureDivisor = 4
|
measureDivisor = 4
|
||||||
@ -29,167 +117,31 @@ def getCourse(tjaHeaders, lines):
|
|||||||
targetBranch = 'N'
|
targetBranch = 'N'
|
||||||
flagLevelhold = False
|
flagLevelhold = False
|
||||||
|
|
||||||
# Process lines
|
# Process course lines
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if line["type"] == 'header':
|
if line["type"] == 'header':
|
||||||
if line["name"] == 'COURSE':
|
parseHeaderMetadata(line)
|
||||||
headers['course'] = line['value']
|
elif line["type"] == 'command' and line['name'] in BRANCH_COMMANDS:
|
||||||
|
parseBranchCommands(line)
|
||||||
elif line["name"] == 'LEVEL':
|
elif line["type"] == 'command' and line['name'] in MEASURE_COMMANDS and currentBranch == targetBranch:
|
||||||
headers['level'] = int(line['value'])
|
parseMeasureCommands(line)
|
||||||
|
elif line['type'] == 'data' and currentBranch == targetBranch:
|
||||||
elif line["name"] == 'BALLOON':
|
parseMeasureData(line)
|
||||||
if line['value']:
|
|
||||||
balloons = [int(v) for v in line['value'].split(",")]
|
|
||||||
else:
|
|
||||||
balloons = []
|
|
||||||
headers['balloon'] = balloons
|
|
||||||
|
|
||||||
elif line["name"] == 'SCOREINIT':
|
|
||||||
headers['scoreInit'] = int(line['value'])
|
|
||||||
|
|
||||||
elif line["name"] == 'SCOREDIFF':
|
|
||||||
headers['scoreDiff'] = int(line['value'])
|
|
||||||
|
|
||||||
elif line["name"] == 'TTROWBEAT':
|
|
||||||
headers['ttRowBeat'] = int(line['value'])
|
|
||||||
|
|
||||||
elif line["type"] == 'command':
|
# Post-processing: Ensure the first measure has a BPM event
|
||||||
if line["name"] == 'BRANCHSTART':
|
if measures:
|
||||||
if flagLevelhold:
|
|
||||||
continue
|
|
||||||
values = line['value'].split(',')
|
|
||||||
if values[0] == 'r':
|
|
||||||
if len(values) >= 3:
|
|
||||||
targetBranch = 'M'
|
|
||||||
elif len(values) == 2:
|
|
||||||
targetBranch = 'E'
|
|
||||||
else:
|
|
||||||
targetBranch = 'N'
|
|
||||||
elif values[0] == 'p':
|
|
||||||
if len(values) >= 3 and float(values[2]) <= 100:
|
|
||||||
targetBranch = 'M'
|
|
||||||
elif len(values) >= 2 and float(values[1]) <= 100:
|
|
||||||
targetBranch = 'E'
|
|
||||||
else:
|
|
||||||
targetBranch = 'N'
|
|
||||||
|
|
||||||
elif line["name"] == 'BRANCHEND':
|
|
||||||
currentBranch = targetBranch
|
|
||||||
|
|
||||||
elif line["name"] == 'N':
|
|
||||||
currentBranch = 'N'
|
|
||||||
|
|
||||||
elif line["name"] == 'E':
|
|
||||||
currentBranch = 'E'
|
|
||||||
|
|
||||||
elif line["name"] == 'M':
|
|
||||||
currentBranch = 'M'
|
|
||||||
|
|
||||||
elif line["name"] == 'START':
|
|
||||||
currentBranch = 'N'
|
|
||||||
targetBranch = 'N'
|
|
||||||
flagLevelhold = False
|
|
||||||
|
|
||||||
elif line["name"] == 'END':
|
|
||||||
currentBranch = 'N'
|
|
||||||
targetBranch = 'N'
|
|
||||||
flagLevelhold = False
|
|
||||||
|
|
||||||
else:
|
|
||||||
if currentBranch != targetBranch:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if line['name'] == 'MEASURE':
|
|
||||||
matchMeasure = re.match(r"(\d+)/(\d+)", line['value'])
|
|
||||||
if not matchMeasure:
|
|
||||||
continue
|
|
||||||
measureDividend = int(matchMeasure.group(1))
|
|
||||||
measureDivisor = int(matchMeasure.group(2))
|
|
||||||
|
|
||||||
elif line['name'] == 'GOGOSTART':
|
|
||||||
measureEvents.append({
|
|
||||||
"name": 'gogoStart',
|
|
||||||
"position": len(measureData),
|
|
||||||
})
|
|
||||||
|
|
||||||
elif line['name'] == 'GOGOEND':
|
|
||||||
measureEvents.append({
|
|
||||||
"name": 'gogoEnd',
|
|
||||||
"position": len(measureData),
|
|
||||||
})
|
|
||||||
|
|
||||||
elif line['name'] == 'SCROLL':
|
|
||||||
measureEvents.append({
|
|
||||||
"name": 'scroll',
|
|
||||||
"position": len(measureData),
|
|
||||||
"value": float(line['value']),
|
|
||||||
})
|
|
||||||
|
|
||||||
elif line['name'] == 'BPMCHANGE':
|
|
||||||
measureEvents.append({
|
|
||||||
"name": 'bpm',
|
|
||||||
"position": len(measureData),
|
|
||||||
"value": float(line['value']),
|
|
||||||
})
|
|
||||||
|
|
||||||
elif line['name'] == 'TTBREAK':
|
|
||||||
measureProperties['ttBreak'] = True
|
|
||||||
|
|
||||||
elif line['name'] == 'LEVELHOLD':
|
|
||||||
flagLevelhold = True
|
|
||||||
|
|
||||||
else:
|
|
||||||
print(line['name']) # Unknown: BARLINEOFF, BARLINEON
|
|
||||||
|
|
||||||
elif line['type'] == 'data' and currentBranch is targetBranch:
|
|
||||||
data = line['data']
|
|
||||||
if data.endswith(','):
|
|
||||||
measureData += data[0:-1]
|
|
||||||
measure = {
|
|
||||||
"length": [measureDividend, measureDivisor],
|
|
||||||
"properties": measureProperties,
|
|
||||||
"data": measureData,
|
|
||||||
"events": measureEvents,
|
|
||||||
}
|
|
||||||
measures.append(measure)
|
|
||||||
measureData = ''
|
|
||||||
measureEvents = []
|
|
||||||
measureProperties = {}
|
|
||||||
else:
|
|
||||||
measureData += data
|
|
||||||
|
|
||||||
if len(measures):
|
|
||||||
# Make first BPM event
|
|
||||||
firstBPMEventFound = False
|
firstBPMEventFound = False
|
||||||
# Search for BPM event in the first measure
|
# Search for BPM event in the first measure
|
||||||
for i in range(len(measures[0]['events'])):
|
for i in range(len(measures[0]['events'])):
|
||||||
evt = measures[0]['events'][i]
|
evt = measures[0]['events'][i]
|
||||||
if evt.name == 'bpm' and evt.position == 0:
|
if evt.name == 'bpm' and evt.position == 0:
|
||||||
firstBPMEventFound = True
|
firstBPMEventFound = True
|
||||||
|
# If not present, insert a BPM event into the first measure using the global header metadata
|
||||||
if not firstBPMEventFound:
|
if not firstBPMEventFound:
|
||||||
# noinspection PyTypeChecker
|
# noinspection PyTypeChecker
|
||||||
measures[0]['events'].insert(0, {
|
measures[0]['events'].insert(0, {"name": 'bpm', "position": 0, "value": tjaHeaders['bpm']})
|
||||||
"name": 'bpm',
|
|
||||||
"position": 0,
|
|
||||||
"value": tjaHeaders['bpm'],
|
|
||||||
})
|
|
||||||
|
|
||||||
# Helper values
|
|
||||||
course = 0
|
|
||||||
courseValue = headers['course'].lower()
|
|
||||||
|
|
||||||
if courseValue in ['easy', '0']:
|
|
||||||
course = 0
|
|
||||||
elif courseValue in ['normal', '1']:
|
|
||||||
course = 1
|
|
||||||
elif courseValue in ['hard', '2']:
|
|
||||||
course = 2
|
|
||||||
elif courseValue in ['oni', '3']:
|
|
||||||
course = 3
|
|
||||||
elif courseValue in ['ura', 'edit', '4']:
|
|
||||||
course = 4
|
|
||||||
|
|
||||||
|
# Post-processing: In case the file doesn't end on a "measure end" symbol (','), append whatever is left
|
||||||
if measureData:
|
if measureData:
|
||||||
measures.append({
|
measures.append({
|
||||||
"length": [measureDividend, measureDivisor],
|
"length": [measureDividend, measureDivisor],
|
||||||
@ -197,15 +149,15 @@ def getCourse(tjaHeaders, lines):
|
|||||||
"data": measureData,
|
"data": measureData,
|
||||||
"events": measureEvents,
|
"events": measureEvents,
|
||||||
})
|
})
|
||||||
else:
|
|
||||||
|
# Post-processing: Otherwise, if the file ends on a measure event (e.g. #GOGOEND), append any remaining events
|
||||||
|
elif measureEvents:
|
||||||
for event in measureEvents:
|
for event in measureEvents:
|
||||||
event['position'] = len(measures[len(measures) - 1]['data'])
|
event['position'] = len(measures[len(measures) - 1]['data'])
|
||||||
# noinspection PyTypeChecker
|
# noinspection PyTypeChecker
|
||||||
measures[len(measures) - 1]['events'].append(event)
|
measures[len(measures) - 1]['events'].append(event)
|
||||||
|
|
||||||
# Output
|
return headers, measures
|
||||||
print(measures[len(measures) - 1])
|
|
||||||
return course, headers, measures
|
|
||||||
|
|
||||||
|
|
||||||
def parseLine(line):
|
def parseLine(line):
|
||||||
@ -249,7 +201,7 @@ def parseTJA(tja):
|
|||||||
currentCourse = ''
|
currentCourse = ''
|
||||||
for line in lines:
|
for line in lines:
|
||||||
parsed = parseLine(line)
|
parsed = parseLine(line)
|
||||||
# Case 1: Comments (ignore
|
# Case 1: Comments (ignore)
|
||||||
if parsed['type'] == 'comment':
|
if parsed['type'] == 'comment':
|
||||||
pass
|
pass
|
||||||
# Case 2: Global header metadata
|
# Case 2: Global header metadata
|
||||||
|
Loading…
x
Reference in New Issue
Block a user