Initial commit from version 1e-99
[beatscape.git] / loaders / BMloader.py
1 import pygame
2 import os.path
3 import re
4 from bmevent import *
5 from keyfile import *
6 from util import *
7
8 # Required information for a loader module. If this isn't here, the game 
9 # will crash and burn and it will be ALL YOUR FAULT.
10 name = "BeMusic BMS/BME"
11 version = 0.0
12
13 def detect(file):
14         res = [re.compile("^#PLAYLEVEL"), re.compile("^#WAV"), re.compile("^#BMP")]
15         match = [0,0,0]
16
17         f = open(file)
18         for line in f:
19                 for n in range(0,len(res)):
20                         if res[n].match(line):
21                                 match[n] = 1
22         return sum(match) / float(len(match))
23
24 def info(file):
25         d = {}
26         f = open(file,'r')
27         r = re.compile('(WAV|BMP|\d{5}:)')
28         for line in f:
29                 if len(line) == 0 or line[0] != "#":
30                         continue
31                 line = line[1:]
32                 l = line.split(' ')
33                 arg = ''
34                 cmd = l[0]
35                 if len(l) >= 2:
36                         arg = ' '.join(l[1:])
37                 if not r.match(cmd):
38                         d[cmd.lower()] = arg.strip()
39         return d
40
41 def load(file,status=lambda x,y:None):
42         keymapping = {0:1, 1:2, 2:3, 3:4, 4:5, 5:0, 7:6, 8:7}
43         kf = KeyFile()
44         kf.numkeys = len(keymapping)
45         lastbpm = 0
46         dir = os.path.dirname(file)
47         f = open(file,'r')
48         kf.track = -1
49         for line in f:
50                 line = line.strip()
51                 if len(line) == 0 or line[0] != "#":
52                         continue
53                 line = line[1:]
54                 l = line.split(' ')
55                 arg = ''
56                 cmd = l[0]
57                 if len(l) >= 2:
58                         arg = ' '.join(l[1:])
59                 if cmd == "PLAYER":
60                         kf.player = arg
61                 elif cmd == "GENRE":
62                         kf.genre = arg
63                 elif cmd == "TITLE":
64                         kf.title = arg
65                 elif cmd == "ARTIST":
66                         kf.artist = arg
67                 elif cmd == "BPM":
68                         try:
69                                 lastbpm = float(arg)
70                                 kf.add(BMEvent(0, BME_TEMPO, None, lastbpm))
71                         except ValueError:
72                                 print "Invalid value for BPM"
73                         #kf.ms_per_measure = 240000.0 / kf.bpm
74                 elif cmd == "PLAYLEVEL":
75                         try:
76                                 kf.playlevel = int(arg)
77                         except ValueError:
78                                 print "Invalid value for PLAYLEVEL"
79                 elif cmd == "RANK":
80                         try:
81                                 kf.rank = int(arg)
82                         except ValueError:
83                                 print "Invalid value for RANK"
84                 elif cmd == "STAGEFILE":
85                         # This will stay here for now. Eventually, this
86                         # will go into the "status" routine or somewhere
87                         # further up.
88                         if arg:
89                                 kf.stagefile = loadBMP(os.path.join(dir,arg))
90                                 status("STAGEFILE",kf.stagefile)
91                 elif cmd == "VOLWAV":
92                         kf.volwav = float(arg) / 100.0
93                 elif cmd[0:3] == "WAV":
94                         slot = int(cmd[3:5],36)
95                         if arg[-3:].lower() == 'mp3':
96                                 wav = loadMP3(os.path.join(dir,arg))
97                         else:
98                                 wav = loadWAV(os.path.join(dir,arg))
99                                 if wav:
100                                         wav.set_volume(kf.volwav)
101                         if wav:
102                                 kf.wavs[slot] = wav
103                                 status("WAV",arg)
104                         else:
105                                 status("ERROR","Could not load " + arg)
106                                 pygame.time.wait(1500)
107                 elif cmd[0:3] == "BMP":
108                         slot = int(cmd[3:5],36)
109                         bmp = loadBMP(os.path.join(dir,arg))
110                         if bmp:
111                                 kf.bmps[slot] = bmp
112                                 status("BMP",arg)
113                         else:
114                                 status("ERROR","Could not load " + arg)
115                 elif len(cmd) > 5 and cmd[5] == ":":
116                         # Hmm. Should "track" really be "measure"?
117                         track = int(cmd[0:3])
118                         channel = int(cmd[3:5])
119                         message = cmd[6:]
120
121                         if channel == 2:
122                                 # Channel 2 is a floating-point
123                                 # multiplier that changes the length of
124                                 # the measure.
125                                 kf.add(BMEvent(track*4, BME_LONGMEASURE, None, float(message)))
126                                 continue
127                         if track != kf.track:
128                                 status("TRACK",track)
129                         kf.track = track
130
131                         v = [int(message[n*2:n*2+2],36) for n in range(0,len(message)/2)]
132                         l = float(len(v)) / 4.0
133
134                         bme = None
135                         if channel == 1:
136                                 for n in range(0,len(v)):
137                                         if v[n] == 0:
138                                                 continue
139                                         bme = BMEvent(track*4 + n / l, BME_BGM, None, v[n])
140                                         kf.add(bme)
141                         if channel == 3:
142                                 v = [int(message[n*2:n*2+2],16) for n in range(0,len(message)/2)]
143                                 for n in range(0,len(v)):
144                                         # WTF is up with the low tempos?
145                                         if v[n] == 0 or v[n] < 30:
146                                                 continue
147                                         print "new BPM: " + str(v[n])
148                                         bme = BMEvent(track*4 + n / l, BME_TEMPO, None, v[n])
149                                         kf.add(bme)
150                                         lastbpm = v[n]
151                         if channel == 4:
152                                 for n in range(0,len(v)):
153                                         if v[n] == 0:
154                                                 continue
155                                         bme = BMEvent(track*4 + n / l, BME_BGA, None, v[n])
156                                         kf.add(bme)
157                         elif (channel >= 11 and channel <= 19) or (channel >= 21 and channel <= 29):
158                                 if channel >= 21 and channel <= 29:
159                                         type = BME_NOTE2
160                                         b = 21
161                                 else:
162                                         type = BME_NOTE1
163                                         b = 11
164                                 for n in range(0,len(v)):
165                                         if v[n] == 0 or not (channel - b) in keymapping:
166                                                 continue
167                                         bme = BMEvent(track*4 + n / l, type, keymapping[channel - b], v[n])
168                                         kf.add(bme)
169                 else:
170                         print "Unknown command:",cmd
171         kf.sort()
172         f.close()
173
174         return kf
175