Skip to content

Instantly share code, notes, and snippets.

@Senarin
Last active June 13, 2017 08:38
Show Gist options
  • Save Senarin/f3b51781df01f3b523f2 to your computer and use it in GitHub Desktop.
Save Senarin/f3b51781df01f3b523f2 to your computer and use it in GitHub Desktop.
Python version of BMS Parser core class (non-complete)
#!/usr/bin/python
# -*- coding: utf-8 -*-
import os, sys, math, cmath, hashlib, codecs
def md5_file(fname):
md5ob = hashlib.md5()
with open(fname,"rb") as f:
for chunk in iter(lambda: f.read(8192), ""):
md5ob.update(chunk)
return md5ob.hexdigest()
def strstr(haystack, needle, b_needle = False):
pos = haystack.find(needle)
if pos < 0:
return None
else:
if b_needle == True:
return haystack[:pos]
else:
return haystack[pos:]
class BMS_Reader:
# Directives for basic information (metadatas)
B_PLAYTYPE = "PLAYER" # Play mode
B_MUSIC_GENRE="GENRE" # Genre of the music
B_SCORE_TITLE="TITLE" # Title of the music
B_MUSIC_ARTIST="ARTIST" # Artist name
B_MUSIC_BPM="BPM" # BPM (beats per minute / Tempo)
B_SCORE_LEVEL="PLAYLEVEL" # Playing Difficulty
B_BRIEF_RANK="RANK" # Judge Level
B_PARAM_TOTAL="TOTAL" # Gauge Totals
B_MIXLEVEL="DIFFICULTY" # Display difficulty name
B_DET_RANK="DEFEXRANK" # Judge Rank (detailed)
B_BGMFILE="MIDIFILE" # Name of Background Music file
B_VOLUME="VOLWAV" # Sound Volume
# Maximum channel numbers
SP5KEYS = 16 # Single Play (5 keys) / 11~15: Keys 1~5, 16: SC
SP7KEYS = 19 # Single Play (7 keys) / 11~15: Keys 1~5, 16: SC, 18~19: Keys 6~7
DP9KEYS = 25 # Double Play (9 keys) / 11~15: Keys 1~5, 22~25: Keys 6~9
DP10KEYS = 26 # Double Play (10 keys) / 11~15: 1P Keys 1~5, 16: 1P SC, 21~25: 2P Keys 1~5, 26: 2P SC
DP14KEYS = 29 # Double Play (14 keys) / 11~15: 1P Keys 1~5, 16: 1P SC, 18~19: 1P Keys 6~7, 21~25: 2P Keys 1~5, 26: 2P SC, 28~29: 2P Keys 6~7
# for Long-notes
LN_SP5KEYS = 56
LN_SP7KEYS = 59
LN_DP9KEYS = 65
LN_DP10KEYS = 66
LN_DP14KEYS = 69
# Channel number for scratch notes
SCR_LEFT = 16
SCR_RIGHT = 26
LN_SCR_LEFT = 56
LN_SCR_RIGHT = 66
mixlevels = {}
mixlevels[1] = "Beginner"
mixlevels[2] = "Normal"
mixlevels[3] = "Hyper"
mixlevels[4] = "Another"
mixlevels[5] = "Insane"
playtypes = {}
playtypes[1] = "Single"
playtypes[2] = "Two"
playtypes[3] = "Double or 9-key"
brief_ranks = ["Very Hard", "Hard", "Normal", "Easy"]
def __init__(self, path):
self.path = path
#self.charset = charset
self.handle = open(path,"r",encoding = "sjis")
def parseMetadata(self):
data = {}
flagsfound = 0
playtyped = False
tpath = os.path.abspath(self.path)
data["filepath"] = tpath.replace(os.pathsep,"/")
data["path"] = os.path.dirname(data["filepath"])
data["filename"] = os.path.basename(self.path)
data["filesize"] = os.path.getsize(tpath)
#data["filehash"] = md5_file(tpath)
#parameter = ""
self.handle.seek(0)
for eachlines in self.handle.readlines():
if eachlines[0] == "#":
parameter = strstr(eachlines," ",True)
print("b--"+str(eachlines[0]))
parameter = parameter.replace("#","")
print("a--"+str(parameter))
parameter = parameter.upper()
value = strstr(eachlines," ")
value = value.strip()
else:
continue
if parameter == self.B_PLAYTYPE:
data["playtype_id"] = int(value)
data["playtype_name"] = self.playtypes[int(value)]
playtyped = True
elif parameter == self.B_MUSIC_GENRE:
data["genre"] = value
elif parameter == self.B_SCORE_TITLE:
data["title"] = value
elif parameter == self.B_BGMFILE:
data["bgmfile"] = value
elif parameter == self.B_VOLUME:
if value.isdight() == False or (value is None):
data["volume"] = 100
else:
data["volume"] = float(value)
elif parameter == self.B_MUSIC_BPM:
data["bpm"] = float(value)
if value.isdight() == False:
data["bpm"] = 130
elif parameter == self.B_SCORE_LEVEL:
data["plevel"] = int(value)
elif parameter == self.B_BRIEF_RANK:
if (value is None) or value.isdight() == False:
data["rank_id"] = 0
data["rank_name"] = "Unknown"
else:
data["rank_id"] = int(value)
data["rank_name"] = self.brief_ranks[int(value)]
elif parameter == self.B_PARAM_TOTAL:
data["total"] = int(value)
elif parameter == self.B_MIXLEVEL:
data["mixlevel"] = self.mixlevels[int(value)]
elif parameter == self.B_DET_RANK:
data["decrank"] = value
if playtyped == False:
del data
data = {"error_code": 0x0F, "error_desc": "This file is not a valid BMS file!"}
return data
return data
example = BMS_Reader(os.path.abspath("example.bme"))
print(example.parseMetadata())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment