Add .tja file support
This commit is contained in:
330
public/src/js/parsetja.js
Normal file
330
public/src/js/parsetja.js
Normal file
@@ -0,0 +1,330 @@
|
||||
class ParseTja{
|
||||
constructor(file, difficulty, offset){
|
||||
this.data = []
|
||||
for(let line of file){
|
||||
line = line.replace(/\/\/.*/, "").trim()
|
||||
if(line !== ""){
|
||||
this.data.push(line)
|
||||
}
|
||||
}
|
||||
this.difficulty = difficulty
|
||||
this.offset = (offset || 0) * -1000
|
||||
this.soundOffset = 0
|
||||
this.noteTypes = [
|
||||
{name: false, txt: false},
|
||||
{name: "don", txt: "ドン"},
|
||||
{name: "ka", txt: "カッ"},
|
||||
{name: "daiDon", txt: "ドン(大)"},
|
||||
{name: "daiKa", txt: "カッ(大)"},
|
||||
{name: "drumroll", txt: "連打ーっ!!"},
|
||||
{name: "daiDrumroll", txt: "連打(大)ーっ!!"},
|
||||
{name: "balloon", txt: "ふうせん"},
|
||||
{name: false, txt: false},
|
||||
{name: "balloon", txt: "ふうせん"}
|
||||
]
|
||||
this.courseTypes = ["easy", "normal", "hard", "oni"]
|
||||
|
||||
this.metadata = this.parseMetadata()
|
||||
this.measures = []
|
||||
this.beatInfo = {}
|
||||
this.circles = this.parseCircles()
|
||||
}
|
||||
parseMetadata(){
|
||||
var metaNumbers = ["bpm", "offset"]
|
||||
var inSong = false
|
||||
var courses = {}
|
||||
var currentCourse = {}
|
||||
var courseName = this.difficulty
|
||||
for(var lineNum = 0; lineNum < this.data.length; lineNum++){
|
||||
var line = this.data[lineNum]
|
||||
|
||||
if(line.slice(0, 1) === "#"){
|
||||
|
||||
var name = line.slice(1).toLowerCase()
|
||||
if(name === "start" && !inSong){
|
||||
|
||||
inSong = true
|
||||
for(var name in currentCourse){
|
||||
if(!(courseName in courses)){
|
||||
courses[courseName] = {}
|
||||
}
|
||||
courses[courseName][name] = currentCourse[name]
|
||||
}
|
||||
courses[courseName].start = lineNum + 1
|
||||
courses[courseName].end = this.data.length
|
||||
|
||||
}else if(name === "end" && inSong){
|
||||
inSong = false
|
||||
courses[courseName].end = lineNum
|
||||
}
|
||||
|
||||
}else if(!inSong){
|
||||
|
||||
if(line.indexOf(":") > 0){
|
||||
|
||||
var [name, value] = this.split(line, ":")
|
||||
name = name.toLowerCase().trim()
|
||||
value = value.trim()
|
||||
|
||||
if(name === "course"){
|
||||
if(value in this.courseTypes){
|
||||
courseName = this.courseTypes[value]
|
||||
}else{
|
||||
courseName = value.toLowerCase()
|
||||
}
|
||||
}else if(name === "balloon"){
|
||||
value = value ? value.split(",").map(digit => parseInt(digit)) : []
|
||||
}else if(this.inArray(name, metaNumbers)){
|
||||
value = parseFloat(value)
|
||||
}
|
||||
|
||||
currentCourse[name] = value
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return courses
|
||||
}
|
||||
inArray(string, array){
|
||||
return array.indexOf(string) >= 0
|
||||
}
|
||||
split(string, delimiter){
|
||||
var index = string.indexOf(delimiter)
|
||||
if(index < 0){
|
||||
return [string, ""]
|
||||
}
|
||||
return [string.slice(0, index), string.slice(index + delimiter.length)]
|
||||
}
|
||||
parseCircles(){
|
||||
var meta = this.metadata[this.difficulty]
|
||||
var ms = (meta.offset || 0) * -1000 + this.offset
|
||||
var bpm = meta.bpm || 0
|
||||
if(bpm <= 0){
|
||||
bpm = 1
|
||||
}
|
||||
var scroll = 1
|
||||
var measure = 4
|
||||
this.beatInfo.beatInterval = 60000 / bpm
|
||||
var gogo = false
|
||||
var barLine = true
|
||||
|
||||
var balloonID = 0
|
||||
var balloons = meta.balloon || []
|
||||
|
||||
var lastDrumroll = false
|
||||
var branch = false
|
||||
var branchType
|
||||
var branchPreference = "m"
|
||||
|
||||
var currentMeasure = []
|
||||
var firstMeasure = true
|
||||
var firstNote = true
|
||||
var circles = []
|
||||
var circleID = 0
|
||||
|
||||
var pushMeasure = () => {
|
||||
for(var i = 0; i < currentMeasure.length; i++){
|
||||
var note = currentMeasure[i]
|
||||
if(firstNote && note.type){
|
||||
firstNote = false
|
||||
if(ms < 0){
|
||||
this.soundOffset = ms
|
||||
ms = 0
|
||||
}
|
||||
}
|
||||
note.start = ms
|
||||
if(note.endDrumroll){
|
||||
note.endDrumroll.endTime = ms
|
||||
}
|
||||
var msPerMeasure = 60000 * measure / bpm
|
||||
ms += msPerMeasure / currentMeasure.length
|
||||
}
|
||||
for(var i = 0; i < currentMeasure.length; i++){
|
||||
var note = currentMeasure[i]
|
||||
if(note.type){
|
||||
circleID++
|
||||
var circleObj = new Circle({
|
||||
id: circleID,
|
||||
start: note.start,
|
||||
type: note.type,
|
||||
txt: note.txt,
|
||||
speed: note.bpm * note.scroll / 60,
|
||||
gogoTime: note.gogo,
|
||||
endTime: note.endTime,
|
||||
requiredHits: note.requiredHits
|
||||
})
|
||||
if(lastDrumroll === note){
|
||||
lastDrumroll = circleObj
|
||||
}
|
||||
|
||||
circles.push(circleObj)
|
||||
}
|
||||
}
|
||||
if(barLine){
|
||||
var note = currentMeasure[0]
|
||||
if(note){
|
||||
var speed = note.bpm * note.scroll / 60
|
||||
}else{
|
||||
var speed = bpm * scroll / 60
|
||||
}
|
||||
this.measures.push({
|
||||
ms: ms,
|
||||
speed: speed
|
||||
})
|
||||
if(firstMeasure){
|
||||
firstMeasure = false
|
||||
var msPerMeasure = 60000 * measure / bpm
|
||||
for(var measureMs = ms - msPerMeasure; measureMs > 0; measureMs -= msPerMeasure){
|
||||
this.measures.push({
|
||||
ms: measureMs,
|
||||
speed: speed
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(var lineNum = meta.start; lineNum < meta.end; lineNum++){
|
||||
var line = this.data[lineNum]
|
||||
if(line.slice(0, 1) === "#"){
|
||||
|
||||
var line = line.slice(1).toLowerCase()
|
||||
var [name, value] = this.split(line, " ")
|
||||
|
||||
switch(name){
|
||||
case "gogostart":
|
||||
gogo = true
|
||||
break
|
||||
case "gogoend":
|
||||
gogo = false
|
||||
break
|
||||
case "bpmchange":
|
||||
bpm = parseFloat(value)
|
||||
break
|
||||
case "scroll":
|
||||
scroll = parseFloat(value)
|
||||
break
|
||||
case "branchstart":
|
||||
branch = true
|
||||
branchType = ""
|
||||
value = value.split(",")
|
||||
var forkType = value[0].toLowerCase()
|
||||
if(forkType === "r" || parseFloat(value[2]) <= 100){
|
||||
branchPreference = "m"
|
||||
}else if(parseFloat(value[1]) <= 100){
|
||||
branchPreference = "e"
|
||||
}else{
|
||||
branchPreference = "n"
|
||||
}
|
||||
break
|
||||
case "branchend":
|
||||
case "section":
|
||||
branch = false
|
||||
break
|
||||
case "n": case "e": case "m":
|
||||
branchType = name
|
||||
break
|
||||
case "measure":
|
||||
var [numerator, denominator] = value.split("/")
|
||||
measure = numerator / denominator * 4
|
||||
break
|
||||
case "delay":
|
||||
ms += (parseFloat(value) || 0) * 1000
|
||||
break
|
||||
case "barlineoff":
|
||||
barLine = false
|
||||
break
|
||||
}
|
||||
|
||||
}else if(!branch || branch && branchType === branchPreference){
|
||||
|
||||
var string = line.split("")
|
||||
|
||||
for(let symbol of string){
|
||||
|
||||
var error = false
|
||||
switch(symbol){
|
||||
|
||||
case "0":
|
||||
currentMeasure.push({
|
||||
bpm: bpm,
|
||||
scroll: scroll
|
||||
})
|
||||
break
|
||||
case "1": case "2": case "3": case "4":
|
||||
var type = this.noteTypes[symbol]
|
||||
var circleObj = {
|
||||
type: type.name,
|
||||
txt: type.txt,
|
||||
gogo: gogo,
|
||||
bpm: bpm,
|
||||
scroll: scroll
|
||||
}
|
||||
if(lastDrumroll){
|
||||
circleObj.endDrumroll = lastDrumroll
|
||||
lastDrumroll = false
|
||||
}
|
||||
currentMeasure.push(circleObj)
|
||||
break
|
||||
case "5": case "6": case "7": case "9":
|
||||
var type = this.noteTypes[symbol]
|
||||
var circleObj = {
|
||||
type: type.name,
|
||||
txt: type.txt,
|
||||
gogo: gogo,
|
||||
bpm: bpm,
|
||||
scroll: scroll
|
||||
}
|
||||
if(lastDrumroll){
|
||||
circleObj.endDrumroll = lastDrumroll
|
||||
}
|
||||
if(symbol === "7" || symbol === "9"){
|
||||
var hits = balloons[balloonID]
|
||||
if(!hits || hits < 1){
|
||||
hits = 1
|
||||
}
|
||||
circleObj.requiredHits = hits
|
||||
balloonID++
|
||||
}
|
||||
lastDrumroll = circleObj
|
||||
currentMeasure.push(circleObj)
|
||||
break
|
||||
case "8":
|
||||
if(lastDrumroll){
|
||||
currentMeasure.push({
|
||||
endDrumroll: lastDrumroll,
|
||||
bpm: bpm,
|
||||
scroll: scroll
|
||||
})
|
||||
lastDrumroll = false
|
||||
}else{
|
||||
currentMeasure.push({
|
||||
bpm: bpm,
|
||||
scroll: scroll
|
||||
})
|
||||
}
|
||||
break
|
||||
case ",":
|
||||
pushMeasure()
|
||||
currentMeasure = []
|
||||
break
|
||||
default:
|
||||
error = true
|
||||
break
|
||||
|
||||
}
|
||||
if(error){
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
pushMeasure()
|
||||
if(lastDrumroll){
|
||||
lastDrumroll.endTime = ms
|
||||
}
|
||||
|
||||
return circles
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user