nxdata.py
· 20 KiB · Python
Brut
#!/usr/bin/env python
from stepfever import *
import time
import struct
SUPRESS_PRINT = False
class NoteType:
Null = 0
Tap = 1
HoldHead = 2
HoldBody = 3
HoldTail = 4
RollHead = 5
Item = 6
Fake = 7
HoldHeadFake = 8
HoldBodyFake = 9
HoldTailFake = 10
RollHeadFake = 11
ItemFake = 12
class NX10:
Null = 0x00
Fake = 0x73 # 0b00100011
Tap = 0xB3 # 0b01000011
HoldHead = 0xB4 # 0b01010111
HoldBody = 0xB6 # 0b01011011
HoldTail = 0xB7 # 0b01011111
HoldHeadFake = 0x74 # 0b00110111
HoldBodyFake = 0x76 # 0b00111011
HoldTailFake = 0x77 # 0b00111111
Item = 0xF1 # 0b01100001
class NX20:
Null = 0x00
Effect = 0x41 # 0b01000001
DivBrain = 0x42 # 0b01000010
Fake = 0x23 # 0b00100011
Tap = 0x43 # 0b01000011
HoldHeadFake = 0x37 # 0b00110111
HoldHead = 0x57 # 0b01010111
HoldBodyFake = 0x3b # 0b00111011
HoldBody = 0x5B # 0b01011011
HoldTailFake = 0x3f # 0b00111111
HoldTail = 0x5F # 0b01011111
FakeItem = 0x21 # 0b00100001
Item = 0x61 # 0b01100001
Row = 0x80 # 0b10000000
MetaMissionLevel = 1000
MetaChartLevel = 1001
NoteSeedAction = 0
NoteSeedShield = 1
NoteSeedChange = 2
NoteSeedAcceleration = 3
NoteSeedFlash = 4
NoteSeedMineTap = 5
NoteSeedMineHold = 6
NoteSeedAttack = 7
NoteSeedDrain = 8
NoteSeedHeart = 9
NoteSeedSpeed2 = 10
NoteSeedRandom = 11
NoteSeedSpeed3 = 12
NoteSeedSpeed4 = 13
NoteSeedSpeed8 = 14
NoteSeedSpeed1 = 15
NoteSeedPotion = 16
NoteSeedRotate0 = 17
NoteSeedRotate90 = 18
NoteSeedRotate180 = 19
NoteSeedRotate270 = 20
NoteSeedSpeed_ = 21
NoteSeedBomb = 22
NoteSeedHyperPotion = 23
NOTE_NX202SFC = {
NX20.Null : NoteType.Null,
NX20.Fake : NoteType.Fake,
NX20.Tap : NoteType.Tap,
NX20.HoldHead : NoteType.HoldHead,
NX20.HoldHeadFake : NoteType.HoldHeadFake,
NX20.HoldBody : NoteType.HoldBody,
NX20.HoldBodyFake : NoteType.HoldBodyFake,
NX20.HoldTail : NoteType.HoldTail,
NX20.FakeItem : NoteType.ItemFake,
NX20.Item : NoteType.Item
}
NOTE_NX102SFC = {
NX10.Null : NoteType.Null,
NX10.Fake : NoteType.Fake,
NX10.Tap : NoteType.Tap,
NX10.HoldHead : NoteType.HoldHead,
NX10.HoldHeadFake : NoteType.HoldHeadFake,
NX10.HoldBody : NoteType.HoldBody,
NX10.HoldBodyFake : NoteType.HoldBodyFake,
NX10.HoldTail : NoteType.HoldTail,
NX10.Item : NoteType.Item
}
MODE_NX202SFC = {
5 : ChartType.PUMP_SINGLE,
10 : ChartType.PUMP_DOUBLE
}
def ParseStep(stepdata):
if not stepdata[0] in NOTE_NX202SFC or stepdata[0] == NX20.Effect:
return {"type":NoteType.Null,"seed": 0,"skin":0,"trigger":0}
else:
return {"type":NOTE_NX202SFC[stepdata[0]],"seed": stepdata[1],"skin":stepdata[2],"trigger":0}
def ParseStepNX10(stepdata):
if not stepdata[0] in NOTE_NX102SFC:
return {"type":NoteType.Null,"seed": 0,"skin":0,"trigger":0}
else:
return {"type":NOTE_NX102SFC[stepdata[0]],"seed": stepdata[1],"skin":stepdata[2],"trigger":0}
def GetChartData(file):
out = {"level":-1,"type":ChartType.PUMP_SINGLE,"color" : (255,255,255),"added":time.time(), "title":"Converted by Tool","author":"nx2sfm", "file" : file}
f = open(file,"rb")
head = f.read(20)
out["nxtype"] = head[:4]
if head[:4] == "NX20":
startcolumn = struct.unpack("I", head[4:8])[0]
numcolumns = struct.unpack("I", head[8:12])[0]
lightmap = struct.unpack("I", head[12:16])[0]
metablocks = struct.unpack("I", head[16:20])[0]
out["type"] = MODE_NX202SFC[numcolumns]
for i in range(metablocks):
data = f.read(8)
idx = struct.unpack("I", data[:4])[0]
value = struct.unpack("I", data[4:8])[0]
if idx == NX20.MetaChartLevel:
out["level"] = value
break
elif head[:4] == "NX10":
nxversion = struct.unpack("4s", head[0:4])[0]
startcolumn = struct.unpack("I", head[4:8])[0]
numcolumns = struct.unpack("I", head[8:12])[0]
splits = struct.unpack("I", head[12:16])[0]
lightmap = startcolumn > 9
out["type"] = MODE_NX202SFC[numcolumns]
else:
print "NXData::GetChartData() - Invalid file magic: %s" %head[:4]
f.close()
return out
def ParseChartNX20(chart):
print "Parsing NX20 - %s" %chart["file"]
f = open(chart["file"], "rb")
mode = chart["type"]
startbpm = -1
bpmchanges = []
rushchanges = []
sfchanges = []
sschanges = []
effects = []
tcchanges = []
warps = []
bgchanges = []
rows = []
lastbpm = -1
beat = 0
time = 0
head = f.read(20)
nxversion = struct.unpack("4s", head[0:4])[0]
startcolumn = struct.unpack("I", head[4:8])[0]
numcolumns = struct.unpack("I", head[8:12])[0]
lightmap = struct.unpack("I", head[12:16])[0]
metablocks = struct.unpack("I", head[16:20])[0]
# Lets just skip the metadatablocks for now:
junk = f.read(8*metablocks)
numsplits = struct.unpack("I", f.read(4))[0]
lastsf = None
lastss = None
if not SUPRESS_PRINT:
print "Number of splits: %s" %numsplits
for s in range(numsplits):
systemselected = struct.unpack("I", f.read(4))[0]
metablocks = struct.unpack("I", f.read(4))[0]
# We will just skip the metadatablocks from split:
junk = f.read(8*metablocks)
numblocks = struct.unpack("I", f.read(4))[0]
if not SUPRESS_PRINT:
print " System Selected: %s" %systemselected
print " Number of blocks: %s" %numblocks
# Currently, I dont know how System Selected works, but when System Selected != 0, the machine seens to pick a random block.
# This converter is just for test, so we will pick the random block here on convert
SelectedBlock = 0 if systemselected == 0 else ((int)(random()*numblocks))
if not SUPRESS_PRINT:
print " Block Picked: %s" %SelectedBlock
for blk in range(0,numblocks):
steptime = struct.unpack("f", f.read(4))[0]
bpm = struct.unpack("f", f.read(4))[0]
mysteryblock = struct.unpack("f", f.read(4))[0]
delay = struct.unpack("f", f.read(4))[0]
speed = struct.unpack("f", f.read(4))[0]
beatsplit = struct.unpack("B", f.read(1))[0]
beatmeasure = struct.unpack("B", f.read(1))[0]
smoothspeed = struct.unpack("B", f.read(1))[0]
unknownflag = struct.unpack("B", f.read(1))[0]
divisionconds = struct.unpack("I", f.read(4))[0]
freeze = (speed<0);
bps = bpm / 60.0
startbpm = bpm if startbpm == -1 else startbpm
# We will skip division conditions too
junk = f.read(8*divisionconds)
numrows = struct.unpack("I", f.read(4))[0]
if SelectedBlock != blk:
if not SUPRESS_PRINT:
print " Skipping not selected block %s" %blk
for n in range(numrows):
rowt = struct.unpack("BBBB", f.read(4))[0]
if rowt[0] != NX20.Row:
junk = f.read(4*numcolumns)
else:
speed = abs(speed)
if not SUPRESS_PRINT:
print " CurrentTime: %s" %time
print " CurrentBeat: %s" %beat
print " Block(%s)" % blk
print " StepTime: %s" %steptime
print " BPM: %s" %bpm
print " Mystery Block: %s" %mysteryblock
print " Delay: %s" %delay
print " Freeze: %s"%freeze
print " Speed: %s"%speed
print " Beat Split: %s"%beatsplit
print " Beat Measure: %s"%beatmeasure
print " Smooth Speed: %s"%smoothspeed
print " Unknown Flag: %s"%unknownflag
print " Division Conditions: %s" %divisionconds
print " Number of Rows: %s" %numrows
# BPM Changes
if lastbpm != bpm:
bpmchanges.append({"time": steptime/1000, "bpm" : bpm})
lastbpm = bpm
delay = delay / 1000
# Delays
beat += delay * bps
time += delay
# ScrollFactor
sf = mysteryblock * beatsplit
lastsf = {"beat" : beat, "factor" : sf, "smooth" : smoothspeed>0, "smoothtime" : steptime}
if lastsf != None:
lastsf["smoothtime"] = (steptime - lastsf["smoothtime"]) / 1000
sfchanges.append(lastsf)
if not SUPRESS_PRINT:
print " Adding Scrollfactor Change - Factor: %s Smooth: %s Beat: %s SmoothTime: %s" %(lastsf["factor"],lastsf["smooth"],lastsf["beat"],lastsf["smoothtime"])
lastsf = {"beat" : beat, "factor" : sf, "smooth" : smoothspeed>0, "smoothtime" : steptime}
if lastss != None:
lastss["smoothtime"] = (steptime - lastss["smoothtime"]) / 1000
sschanges.append(lastss)
if not SUPRESS_PRINT:
print " Adding ScrollSpeed Change - Factor: %s Smooth: %s Beat: %s SmoothTime: %s" %(lastss["factor"],lastss["smooth"],lastss["beat"],lastss["smoothtime"])
lastss = {"beat" : beat, "factor" : speed, "smooth" : smoothspeed>0, "smoothtime" : steptime}
if s == numsplits-1:
if not SUPRESS_PRINT:
print " Adding last ss"
sschanges.append(lastss)
# Check for warps
if round(steptime*1000) != round(time*1000*1000):
# Lets do an warp!
WarpBeat = ((steptime/1000) - time ) * bps + beat;
if not SUPRESS_PRINT:
print " Time Warp from %s ms to %s ms from beat %s to beat %s" %(steptime,time*1000,WarpBeat,beat)
#warps.append({"beatFrom":beat,"beatTo":WarpBeat})
warps.append({"time":(steptime/1000),"beatTo":beat})
# Process Rows
for n in range(numrows):
notes = []
rowt = struct.unpack("BBBB",f.read(4))
if rowt[0] != NX20.Row: # If its not an empty row
notedata = ParseStep(rowt)
notedata["beat"] = beat
notes.append(notedata)
for k in range(numcolumns-1):
rowt = struct.unpack("BBBB",f.read(4))
notedata = ParseStep(rowt)
notedata["beat"] = beat
notes.append(notedata)
if len(notes) > 0:
rows.append({"beat":beat, "notes":notes})
beat += 1.0 / beatsplit
time += 1.0 / (beatsplit * bps)
f.close()
data = GenSFC(chart["id"], chart["level"], chart["type"], startbpm, chart["title"], chart["author"], bpmchanges, warps, rushchanges, sfchanges, sschanges, tcchanges, effects, bgchanges, rows)
return data
def ParseChartNX10(chart):
print "Parsing NX10 %s" %chart["file"]
f = open(chart["file"], "rb")
mode = chart["type"]
startbpm = -1
bpmchanges = []
rushchanges = []
sfchanges = []
sschanges = []
effects = []
tcchanges = []
warps = []
bgchanges = []
rows = []
lastbpm = -1
beat = 0
time = 0
head = f.read(16)
nxversion = struct.unpack("4s", head[0:4])[0]
startcolumn = struct.unpack("I", head[4:8])[0]
numcolumns = struct.unpack("I", head[8:12])[0]
numsplits = struct.unpack("I", head[12:16])[0]
lightmap = startcolumn > 9
lastsf = None
lastss = None
if not SUPRESS_PRINT:
print "Format: %s - Start Column %d - Num Columns: %d - Splits: %d" %(nxversion,startcolumn,numcolumns,numsplits)
splitsd = f.read(4*numsplits)
splitsd = struct.unpack("%sI"%numsplits,splitsd)
for s in range(numsplits):
file_pos = splitsd[s]
f.seek(file_pos)
blocks = struct.unpack("I", f.read(4))[0]
if not SUPRESS_PRINT:
print "\tNumber of blocks %s" %blocks
blocksd = struct.unpack("%sI"%blocks, f.read(4*blocks))
for z in range(blocks):
f.seek(blocksd[z])
steptime = struct.unpack("f", f.read(4))[0]
bpm = struct.unpack("f", f.read(4))[0]
mysteryblock = struct.unpack("f", f.read(4))[0]
delay = struct.unpack("f", f.read(4))[0]
speed = struct.unpack("f", f.read(4))[0]
divisionconds = struct.unpack("I", f.read(4))[0]
beatsplit = struct.unpack("H", f.read(2))[0]
beatmeasure = struct.unpack("B", f.read(1))[0]
smoothspeed = struct.unpack("B", f.read(1))[0]
numrows = struct.unpack("I", f.read(4))[0]
freeze = (speed<0);
bps = bpm / 60.0
startbpm = bpm if startbpm == -1 else startbpm
if not SUPRESS_PRINT:
print "\t Block(%s)" % z
print "\t StepTime: %s" %steptime
print "\t BPM: %s" %bpm
print "\t Mystery Block: %s" %mysteryblock
print "\t Delay: %s" %delay
print "\t Freeze: %s" %freeze
print "\t Speed: %s" %speed
print "\t Beat Split: %s" %beatsplit
print "\t Beat Measure: %s" %beatmeasure
print "\t Smooth Speed: %s" %smoothspeed
print "\t Number of Rows: %s" %numrows
if divisionconds > 0:
# Skip that conditions
divd = f.read(4*10*2)
if lightmap:
if numrows > 0:
lmpd = f.read(4*numrows)
else:
speed = abs(speed)
# BPM Changes
if lastbpm != bpm:
bpmchanges.append({"time": steptime/1000, "bpm" : bpm})
lastbpm = bpm
# Delays
if time == 0:
time = steptime
beat = steptime * bps
else:
beat += delay * bps
time += delay
# ScrollFactor
sf = mysteryblock * beatsplit
lastsf = {"beat" : beat, "factor" : sf, "smooth" : smoothspeed>0, "smoothtime" : steptime}
if lastsf != None:
lastsf["smoothtime"] = (steptime - lastsf["smoothtime"]) / 1000
sfchanges.append(lastsf)
if not SUPRESS_PRINT:
print " Adding Scrollfactor Change - Factor: %s Smooth: %s Beat: %s SmoothTime: %s" %(lastsf["factor"],lastsf["smooth"],lastsf["beat"],lastsf["smoothtime"])
lastsf = {"beat" : beat, "factor" : sf, "smooth" : smoothspeed>0, "smoothtime" : steptime}
if lastss != None:
lastss["smoothtime"] = (steptime - lastss["smoothtime"]) / 1000
sschanges.append(lastss)
if not SUPRESS_PRINT:
print " Adding ScrollSpeed Change - Factor: %s Smooth: %s Beat: %s SmoothTime: %s" %(lastss["factor"],lastss["smooth"],lastss["beat"],lastss["smoothtime"])
lastss = {"beat" : beat, "factor" : speed, "smooth" : smoothspeed>0, "smoothtime" : steptime}
if s == numsplits-1:
if not SUPRESS_PRINT:
print " Adding last ss"
sschanges.append(lastss)
# Check for warps
if round(steptime/1000) != round(time):
# Lets do an warp!
WarpBeat = ((steptime/1000) - time ) * bps + beat;
if not SUPRESS_PRINT:
print " Time Warp from %s ms to %s ms from beat %s to beat %s" %(steptime/1000,time,WarpBeat,beat)
#warps.append({"beatFrom":beat,"beatTo":WarpBeat})
warps.append({"time":(steptime/1000),"beatTo":beat})
if numrows > 0:
rowd = struct.unpack("%sI"%numrows, f.read(4*numrows))
for r in range(numrows):
notes = []
if rowd[r] > 0:
f.seek(rowd[r])
for p in range(numcolumns):
data = struct.unpack("2B", f.read(2))
#{"type":NOTE_NX102SFC[stepdata[0]],"seed": stepdata[1],"skin":stepdata[2],"trigger":0}
notedata = ParseStepNX10([data[0], data[1] & 0xFC, data[1] & 0x03])
notedata["beat"] = beat
notes.append(notedata)
rows.append({"beat":beat, "notes":notes})
if bps != 0:
beat += 1.0 / beatsplit
time += 1.0 / (beatsplit * bps)
f.close()
data = GenSFC(chart["id"], chart["level"], chart["type"], startbpm, chart["title"], chart["author"], bpmchanges, warps, rushchanges, sfchanges, sschanges, tcchanges, effects, bgchanges, rows)
return data
| 1 | #!/usr/bin/env python |
| 2 | from stepfever import * |
| 3 | import time |
| 4 | import struct |
| 5 | |
| 6 | SUPRESS_PRINT = False |
| 7 | |
| 8 | class NoteType: |
| 9 | Null = 0 |
| 10 | Tap = 1 |
| 11 | HoldHead = 2 |
| 12 | HoldBody = 3 |
| 13 | HoldTail = 4 |
| 14 | RollHead = 5 |
| 15 | Item = 6 |
| 16 | Fake = 7 |
| 17 | HoldHeadFake = 8 |
| 18 | HoldBodyFake = 9 |
| 19 | HoldTailFake = 10 |
| 20 | RollHeadFake = 11 |
| 21 | ItemFake = 12 |
| 22 | |
| 23 | class NX10: |
| 24 | |
| 25 | Null = 0x00 |
| 26 | Fake = 0x73 # 0b00100011 |
| 27 | |
| 28 | Tap = 0xB3 # 0b01000011 |
| 29 | HoldHead = 0xB4 # 0b01010111 |
| 30 | HoldBody = 0xB6 # 0b01011011 |
| 31 | HoldTail = 0xB7 # 0b01011111 |
| 32 | |
| 33 | HoldHeadFake = 0x74 # 0b00110111 |
| 34 | HoldBodyFake = 0x76 # 0b00111011 |
| 35 | HoldTailFake = 0x77 # 0b00111111 |
| 36 | Item = 0xF1 # 0b01100001 |
| 37 | |
| 38 | |
| 39 | class NX20: |
| 40 | |
| 41 | Null = 0x00 |
| 42 | |
| 43 | Effect = 0x41 # 0b01000001 |
| 44 | DivBrain = 0x42 # 0b01000010 |
| 45 | Fake = 0x23 # 0b00100011 |
| 46 | Tap = 0x43 # 0b01000011 |
| 47 | HoldHeadFake = 0x37 # 0b00110111 |
| 48 | HoldHead = 0x57 # 0b01010111 |
| 49 | HoldBodyFake = 0x3b # 0b00111011 |
| 50 | HoldBody = 0x5B # 0b01011011 |
| 51 | HoldTailFake = 0x3f # 0b00111111 |
| 52 | HoldTail = 0x5F # 0b01011111 |
| 53 | FakeItem = 0x21 # 0b00100001 |
| 54 | Item = 0x61 # 0b01100001 |
| 55 | Row = 0x80 # 0b10000000 |
| 56 | |
| 57 | MetaMissionLevel = 1000 |
| 58 | MetaChartLevel = 1001 |
| 59 | |
| 60 | NoteSeedAction = 0 |
| 61 | NoteSeedShield = 1 |
| 62 | NoteSeedChange = 2 |
| 63 | NoteSeedAcceleration = 3 |
| 64 | NoteSeedFlash = 4 |
| 65 | NoteSeedMineTap = 5 |
| 66 | NoteSeedMineHold = 6 |
| 67 | NoteSeedAttack = 7 |
| 68 | NoteSeedDrain = 8 |
| 69 | NoteSeedHeart = 9 |
| 70 | NoteSeedSpeed2 = 10 |
| 71 | NoteSeedRandom = 11 |
| 72 | NoteSeedSpeed3 = 12 |
| 73 | NoteSeedSpeed4 = 13 |
| 74 | NoteSeedSpeed8 = 14 |
| 75 | NoteSeedSpeed1 = 15 |
| 76 | NoteSeedPotion = 16 |
| 77 | NoteSeedRotate0 = 17 |
| 78 | NoteSeedRotate90 = 18 |
| 79 | NoteSeedRotate180 = 19 |
| 80 | NoteSeedRotate270 = 20 |
| 81 | NoteSeedSpeed_ = 21 |
| 82 | NoteSeedBomb = 22 |
| 83 | NoteSeedHyperPotion = 23 |
| 84 | |
| 85 | NOTE_NX202SFC = { |
| 86 | NX20.Null : NoteType.Null, |
| 87 | NX20.Fake : NoteType.Fake, |
| 88 | NX20.Tap : NoteType.Tap, |
| 89 | NX20.HoldHead : NoteType.HoldHead, |
| 90 | NX20.HoldHeadFake : NoteType.HoldHeadFake, |
| 91 | NX20.HoldBody : NoteType.HoldBody, |
| 92 | NX20.HoldBodyFake : NoteType.HoldBodyFake, |
| 93 | NX20.HoldTail : NoteType.HoldTail, |
| 94 | NX20.FakeItem : NoteType.ItemFake, |
| 95 | NX20.Item : NoteType.Item |
| 96 | } |
| 97 | |
| 98 | NOTE_NX102SFC = { |
| 99 | NX10.Null : NoteType.Null, |
| 100 | NX10.Fake : NoteType.Fake, |
| 101 | NX10.Tap : NoteType.Tap, |
| 102 | NX10.HoldHead : NoteType.HoldHead, |
| 103 | NX10.HoldHeadFake : NoteType.HoldHeadFake, |
| 104 | NX10.HoldBody : NoteType.HoldBody, |
| 105 | NX10.HoldBodyFake : NoteType.HoldBodyFake, |
| 106 | NX10.HoldTail : NoteType.HoldTail, |
| 107 | NX10.Item : NoteType.Item |
| 108 | } |
| 109 | |
| 110 | MODE_NX202SFC = { |
| 111 | 5 : ChartType.PUMP_SINGLE, |
| 112 | 10 : ChartType.PUMP_DOUBLE |
| 113 | } |
| 114 | |
| 115 | def ParseStep(stepdata): |
| 116 | if not stepdata[0] in NOTE_NX202SFC or stepdata[0] == NX20.Effect: |
| 117 | return {"type":NoteType.Null,"seed": 0,"skin":0,"trigger":0} |
| 118 | else: |
| 119 | return {"type":NOTE_NX202SFC[stepdata[0]],"seed": stepdata[1],"skin":stepdata[2],"trigger":0} |
| 120 | |
| 121 | |
| 122 | def ParseStepNX10(stepdata): |
| 123 | if not stepdata[0] in NOTE_NX102SFC: |
| 124 | return {"type":NoteType.Null,"seed": 0,"skin":0,"trigger":0} |
| 125 | else: |
| 126 | return {"type":NOTE_NX102SFC[stepdata[0]],"seed": stepdata[1],"skin":stepdata[2],"trigger":0} |
| 127 | |
| 128 | def GetChartData(file): |
| 129 | out = {"level":-1,"type":ChartType.PUMP_SINGLE,"color" : (255,255,255),"added":time.time(), "title":"Converted by Tool","author":"nx2sfm", "file" : file} |
| 130 | f = open(file,"rb") |
| 131 | head = f.read(20) |
| 132 | out["nxtype"] = head[:4] |
| 133 | if head[:4] == "NX20": |
| 134 | startcolumn = struct.unpack("I", head[4:8])[0] |
| 135 | numcolumns = struct.unpack("I", head[8:12])[0] |
| 136 | lightmap = struct.unpack("I", head[12:16])[0] |
| 137 | metablocks = struct.unpack("I", head[16:20])[0] |
| 138 | out["type"] = MODE_NX202SFC[numcolumns] |
| 139 | for i in range(metablocks): |
| 140 | data = f.read(8) |
| 141 | idx = struct.unpack("I", data[:4])[0] |
| 142 | value = struct.unpack("I", data[4:8])[0] |
| 143 | if idx == NX20.MetaChartLevel: |
| 144 | out["level"] = value |
| 145 | break |
| 146 | elif head[:4] == "NX10": |
| 147 | nxversion = struct.unpack("4s", head[0:4])[0] |
| 148 | startcolumn = struct.unpack("I", head[4:8])[0] |
| 149 | numcolumns = struct.unpack("I", head[8:12])[0] |
| 150 | splits = struct.unpack("I", head[12:16])[0] |
| 151 | lightmap = startcolumn > 9 |
| 152 | out["type"] = MODE_NX202SFC[numcolumns] |
| 153 | else: |
| 154 | print "NXData::GetChartData() - Invalid file magic: %s" %head[:4] |
| 155 | f.close() |
| 156 | return out |
| 157 | |
| 158 | def ParseChartNX20(chart): |
| 159 | print "Parsing NX20 - %s" %chart["file"] |
| 160 | f = open(chart["file"], "rb") |
| 161 | mode = chart["type"] |
| 162 | startbpm = -1 |
| 163 | bpmchanges = [] |
| 164 | rushchanges = [] |
| 165 | sfchanges = [] |
| 166 | sschanges = [] |
| 167 | effects = [] |
| 168 | tcchanges = [] |
| 169 | warps = [] |
| 170 | bgchanges = [] |
| 171 | rows = [] |
| 172 | lastbpm = -1 |
| 173 | |
| 174 | beat = 0 |
| 175 | time = 0 |
| 176 | head = f.read(20) |
| 177 | nxversion = struct.unpack("4s", head[0:4])[0] |
| 178 | startcolumn = struct.unpack("I", head[4:8])[0] |
| 179 | numcolumns = struct.unpack("I", head[8:12])[0] |
| 180 | lightmap = struct.unpack("I", head[12:16])[0] |
| 181 | metablocks = struct.unpack("I", head[16:20])[0] |
| 182 | |
| 183 | # Lets just skip the metadatablocks for now: |
| 184 | junk = f.read(8*metablocks) |
| 185 | numsplits = struct.unpack("I", f.read(4))[0] |
| 186 | lastsf = None |
| 187 | lastss = None |
| 188 | |
| 189 | if not SUPRESS_PRINT: |
| 190 | print "Number of splits: %s" %numsplits |
| 191 | for s in range(numsplits): |
| 192 | systemselected = struct.unpack("I", f.read(4))[0] |
| 193 | metablocks = struct.unpack("I", f.read(4))[0] |
| 194 | |
| 195 | # We will just skip the metadatablocks from split: |
| 196 | junk = f.read(8*metablocks) |
| 197 | |
| 198 | numblocks = struct.unpack("I", f.read(4))[0] |
| 199 | if not SUPRESS_PRINT: |
| 200 | print " System Selected: %s" %systemselected |
| 201 | print " Number of blocks: %s" %numblocks |
| 202 | # Currently, I dont know how System Selected works, but when System Selected != 0, the machine seens to pick a random block. |
| 203 | # This converter is just for test, so we will pick the random block here on convert |
| 204 | |
| 205 | SelectedBlock = 0 if systemselected == 0 else ((int)(random()*numblocks)) |
| 206 | if not SUPRESS_PRINT: |
| 207 | print " Block Picked: %s" %SelectedBlock |
| 208 | |
| 209 | for blk in range(0,numblocks): |
| 210 | steptime = struct.unpack("f", f.read(4))[0] |
| 211 | bpm = struct.unpack("f", f.read(4))[0] |
| 212 | mysteryblock = struct.unpack("f", f.read(4))[0] |
| 213 | delay = struct.unpack("f", f.read(4))[0] |
| 214 | speed = struct.unpack("f", f.read(4))[0] |
| 215 | beatsplit = struct.unpack("B", f.read(1))[0] |
| 216 | beatmeasure = struct.unpack("B", f.read(1))[0] |
| 217 | smoothspeed = struct.unpack("B", f.read(1))[0] |
| 218 | unknownflag = struct.unpack("B", f.read(1))[0] |
| 219 | divisionconds = struct.unpack("I", f.read(4))[0] |
| 220 | freeze = (speed<0); |
| 221 | bps = bpm / 60.0 |
| 222 | |
| 223 | startbpm = bpm if startbpm == -1 else startbpm |
| 224 | |
| 225 | # We will skip division conditions too |
| 226 | junk = f.read(8*divisionconds) |
| 227 | |
| 228 | numrows = struct.unpack("I", f.read(4))[0] |
| 229 | if SelectedBlock != blk: |
| 230 | if not SUPRESS_PRINT: |
| 231 | print " Skipping not selected block %s" %blk |
| 232 | for n in range(numrows): |
| 233 | rowt = struct.unpack("BBBB", f.read(4))[0] |
| 234 | if rowt[0] != NX20.Row: |
| 235 | junk = f.read(4*numcolumns) |
| 236 | |
| 237 | |
| 238 | else: |
| 239 | speed = abs(speed) |
| 240 | if not SUPRESS_PRINT: |
| 241 | print " CurrentTime: %s" %time |
| 242 | print " CurrentBeat: %s" %beat |
| 243 | print " Block(%s)" % blk |
| 244 | print " StepTime: %s" %steptime |
| 245 | print " BPM: %s" %bpm |
| 246 | print " Mystery Block: %s" %mysteryblock |
| 247 | print " Delay: %s" %delay |
| 248 | print " Freeze: %s"%freeze |
| 249 | print " Speed: %s"%speed |
| 250 | print " Beat Split: %s"%beatsplit |
| 251 | print " Beat Measure: %s"%beatmeasure |
| 252 | print " Smooth Speed: %s"%smoothspeed |
| 253 | print " Unknown Flag: %s"%unknownflag |
| 254 | print " Division Conditions: %s" %divisionconds |
| 255 | print " Number of Rows: %s" %numrows |
| 256 | |
| 257 | # BPM Changes |
| 258 | if lastbpm != bpm: |
| 259 | bpmchanges.append({"time": steptime/1000, "bpm" : bpm}) |
| 260 | lastbpm = bpm |
| 261 | delay = delay / 1000 |
| 262 | |
| 263 | # Delays |
| 264 | beat += delay * bps |
| 265 | time += delay |
| 266 | |
| 267 | # ScrollFactor |
| 268 | sf = mysteryblock * beatsplit |
| 269 | lastsf = {"beat" : beat, "factor" : sf, "smooth" : smoothspeed>0, "smoothtime" : steptime} |
| 270 | if lastsf != None: |
| 271 | lastsf["smoothtime"] = (steptime - lastsf["smoothtime"]) / 1000 |
| 272 | sfchanges.append(lastsf) |
| 273 | if not SUPRESS_PRINT: |
| 274 | print " Adding Scrollfactor Change - Factor: %s Smooth: %s Beat: %s SmoothTime: %s" %(lastsf["factor"],lastsf["smooth"],lastsf["beat"],lastsf["smoothtime"]) |
| 275 | |
| 276 | lastsf = {"beat" : beat, "factor" : sf, "smooth" : smoothspeed>0, "smoothtime" : steptime} |
| 277 | |
| 278 | if lastss != None: |
| 279 | lastss["smoothtime"] = (steptime - lastss["smoothtime"]) / 1000 |
| 280 | sschanges.append(lastss) |
| 281 | if not SUPRESS_PRINT: |
| 282 | print " Adding ScrollSpeed Change - Factor: %s Smooth: %s Beat: %s SmoothTime: %s" %(lastss["factor"],lastss["smooth"],lastss["beat"],lastss["smoothtime"]) |
| 283 | |
| 284 | lastss = {"beat" : beat, "factor" : speed, "smooth" : smoothspeed>0, "smoothtime" : steptime} |
| 285 | |
| 286 | if s == numsplits-1: |
| 287 | if not SUPRESS_PRINT: |
| 288 | print " Adding last ss" |
| 289 | sschanges.append(lastss) |
| 290 | |
| 291 | # Check for warps |
| 292 | if round(steptime*1000) != round(time*1000*1000): |
| 293 | # Lets do an warp! |
| 294 | WarpBeat = ((steptime/1000) - time ) * bps + beat; |
| 295 | if not SUPRESS_PRINT: |
| 296 | print " Time Warp from %s ms to %s ms from beat %s to beat %s" %(steptime,time*1000,WarpBeat,beat) |
| 297 | #warps.append({"beatFrom":beat,"beatTo":WarpBeat}) |
| 298 | warps.append({"time":(steptime/1000),"beatTo":beat}) |
| 299 | |
| 300 | # Process Rows |
| 301 | for n in range(numrows): |
| 302 | notes = [] |
| 303 | rowt = struct.unpack("BBBB",f.read(4)) |
| 304 | if rowt[0] != NX20.Row: # If its not an empty row |
| 305 | notedata = ParseStep(rowt) |
| 306 | notedata["beat"] = beat |
| 307 | notes.append(notedata) |
| 308 | for k in range(numcolumns-1): |
| 309 | rowt = struct.unpack("BBBB",f.read(4)) |
| 310 | notedata = ParseStep(rowt) |
| 311 | notedata["beat"] = beat |
| 312 | notes.append(notedata) |
| 313 | if len(notes) > 0: |
| 314 | rows.append({"beat":beat, "notes":notes}) |
| 315 | beat += 1.0 / beatsplit |
| 316 | time += 1.0 / (beatsplit * bps) |
| 317 | f.close() |
| 318 | data = GenSFC(chart["id"], chart["level"], chart["type"], startbpm, chart["title"], chart["author"], bpmchanges, warps, rushchanges, sfchanges, sschanges, tcchanges, effects, bgchanges, rows) |
| 319 | return data |
| 320 | |
| 321 | def ParseChartNX10(chart): |
| 322 | print "Parsing NX10 %s" %chart["file"] |
| 323 | f = open(chart["file"], "rb") |
| 324 | mode = chart["type"] |
| 325 | |
| 326 | startbpm = -1 |
| 327 | bpmchanges = [] |
| 328 | rushchanges = [] |
| 329 | sfchanges = [] |
| 330 | sschanges = [] |
| 331 | effects = [] |
| 332 | tcchanges = [] |
| 333 | warps = [] |
| 334 | bgchanges = [] |
| 335 | rows = [] |
| 336 | lastbpm = -1 |
| 337 | beat = 0 |
| 338 | time = 0 |
| 339 | |
| 340 | |
| 341 | head = f.read(16) |
| 342 | nxversion = struct.unpack("4s", head[0:4])[0] |
| 343 | startcolumn = struct.unpack("I", head[4:8])[0] |
| 344 | numcolumns = struct.unpack("I", head[8:12])[0] |
| 345 | numsplits = struct.unpack("I", head[12:16])[0] |
| 346 | lightmap = startcolumn > 9 |
| 347 | |
| 348 | lastsf = None |
| 349 | lastss = None |
| 350 | |
| 351 | if not SUPRESS_PRINT: |
| 352 | print "Format: %s - Start Column %d - Num Columns: %d - Splits: %d" %(nxversion,startcolumn,numcolumns,numsplits) |
| 353 | splitsd = f.read(4*numsplits) |
| 354 | splitsd = struct.unpack("%sI"%numsplits,splitsd) |
| 355 | |
| 356 | for s in range(numsplits): |
| 357 | file_pos = splitsd[s] |
| 358 | f.seek(file_pos) |
| 359 | blocks = struct.unpack("I", f.read(4))[0] |
| 360 | if not SUPRESS_PRINT: |
| 361 | print "\tNumber of blocks %s" %blocks |
| 362 | blocksd = struct.unpack("%sI"%blocks, f.read(4*blocks)) |
| 363 | for z in range(blocks): |
| 364 | f.seek(blocksd[z]) |
| 365 | steptime = struct.unpack("f", f.read(4))[0] |
| 366 | bpm = struct.unpack("f", f.read(4))[0] |
| 367 | mysteryblock = struct.unpack("f", f.read(4))[0] |
| 368 | delay = struct.unpack("f", f.read(4))[0] |
| 369 | speed = struct.unpack("f", f.read(4))[0] |
| 370 | divisionconds = struct.unpack("I", f.read(4))[0] |
| 371 | beatsplit = struct.unpack("H", f.read(2))[0] |
| 372 | beatmeasure = struct.unpack("B", f.read(1))[0] |
| 373 | smoothspeed = struct.unpack("B", f.read(1))[0] |
| 374 | numrows = struct.unpack("I", f.read(4))[0] |
| 375 | freeze = (speed<0); |
| 376 | bps = bpm / 60.0 |
| 377 | startbpm = bpm if startbpm == -1 else startbpm |
| 378 | if not SUPRESS_PRINT: |
| 379 | print "\t Block(%s)" % z |
| 380 | print "\t StepTime: %s" %steptime |
| 381 | print "\t BPM: %s" %bpm |
| 382 | print "\t Mystery Block: %s" %mysteryblock |
| 383 | print "\t Delay: %s" %delay |
| 384 | print "\t Freeze: %s" %freeze |
| 385 | print "\t Speed: %s" %speed |
| 386 | print "\t Beat Split: %s" %beatsplit |
| 387 | print "\t Beat Measure: %s" %beatmeasure |
| 388 | print "\t Smooth Speed: %s" %smoothspeed |
| 389 | print "\t Number of Rows: %s" %numrows |
| 390 | |
| 391 | if divisionconds > 0: |
| 392 | # Skip that conditions |
| 393 | divd = f.read(4*10*2) |
| 394 | |
| 395 | if lightmap: |
| 396 | if numrows > 0: |
| 397 | lmpd = f.read(4*numrows) |
| 398 | else: |
| 399 | speed = abs(speed) |
| 400 | # BPM Changes |
| 401 | if lastbpm != bpm: |
| 402 | bpmchanges.append({"time": steptime/1000, "bpm" : bpm}) |
| 403 | lastbpm = bpm |
| 404 | # Delays |
| 405 | if time == 0: |
| 406 | time = steptime |
| 407 | beat = steptime * bps |
| 408 | else: |
| 409 | beat += delay * bps |
| 410 | time += delay |
| 411 | |
| 412 | # ScrollFactor |
| 413 | sf = mysteryblock * beatsplit |
| 414 | lastsf = {"beat" : beat, "factor" : sf, "smooth" : smoothspeed>0, "smoothtime" : steptime} |
| 415 | if lastsf != None: |
| 416 | lastsf["smoothtime"] = (steptime - lastsf["smoothtime"]) / 1000 |
| 417 | sfchanges.append(lastsf) |
| 418 | if not SUPRESS_PRINT: |
| 419 | print " Adding Scrollfactor Change - Factor: %s Smooth: %s Beat: %s SmoothTime: %s" %(lastsf["factor"],lastsf["smooth"],lastsf["beat"],lastsf["smoothtime"]) |
| 420 | |
| 421 | lastsf = {"beat" : beat, "factor" : sf, "smooth" : smoothspeed>0, "smoothtime" : steptime} |
| 422 | |
| 423 | if lastss != None: |
| 424 | lastss["smoothtime"] = (steptime - lastss["smoothtime"]) / 1000 |
| 425 | sschanges.append(lastss) |
| 426 | if not SUPRESS_PRINT: |
| 427 | print " Adding ScrollSpeed Change - Factor: %s Smooth: %s Beat: %s SmoothTime: %s" %(lastss["factor"],lastss["smooth"],lastss["beat"],lastss["smoothtime"]) |
| 428 | |
| 429 | lastss = {"beat" : beat, "factor" : speed, "smooth" : smoothspeed>0, "smoothtime" : steptime} |
| 430 | |
| 431 | if s == numsplits-1: |
| 432 | if not SUPRESS_PRINT: |
| 433 | print " Adding last ss" |
| 434 | sschanges.append(lastss) |
| 435 | |
| 436 | # Check for warps |
| 437 | if round(steptime/1000) != round(time): |
| 438 | # Lets do an warp! |
| 439 | WarpBeat = ((steptime/1000) - time ) * bps + beat; |
| 440 | if not SUPRESS_PRINT: |
| 441 | print " Time Warp from %s ms to %s ms from beat %s to beat %s" %(steptime/1000,time,WarpBeat,beat) |
| 442 | #warps.append({"beatFrom":beat,"beatTo":WarpBeat}) |
| 443 | warps.append({"time":(steptime/1000),"beatTo":beat}) |
| 444 | |
| 445 | if numrows > 0: |
| 446 | rowd = struct.unpack("%sI"%numrows, f.read(4*numrows)) |
| 447 | for r in range(numrows): |
| 448 | notes = [] |
| 449 | if rowd[r] > 0: |
| 450 | f.seek(rowd[r]) |
| 451 | for p in range(numcolumns): |
| 452 | data = struct.unpack("2B", f.read(2)) |
| 453 | #{"type":NOTE_NX102SFC[stepdata[0]],"seed": stepdata[1],"skin":stepdata[2],"trigger":0} |
| 454 | notedata = ParseStepNX10([data[0], data[1] & 0xFC, data[1] & 0x03]) |
| 455 | notedata["beat"] = beat |
| 456 | notes.append(notedata) |
| 457 | rows.append({"beat":beat, "notes":notes}) |
| 458 | if bps != 0: |
| 459 | beat += 1.0 / beatsplit |
| 460 | time += 1.0 / (beatsplit * bps) |
| 461 | f.close() |
| 462 | data = GenSFC(chart["id"], chart["level"], chart["type"], startbpm, chart["title"], chart["author"], bpmchanges, warps, rushchanges, sfchanges, sschanges, tcchanges, effects, bgchanges, rows) |
| 463 | return data |