24 # Allows us to continuously map time to the current beat
27 # Keymapping is a sequence of keycodes, mapping the index to the
35 self.bmelist.append(bme)
38 return self.bmelist.remove(bme)
48 self.bmelist.sort(sortfun)
51 for b in self.bmelist:
54 # AWFUL DIRTY NO GOOD HACK
55 # (but does find the end of the song within 10ms)
57 if len(self.beatfunc) >= 2:
58 t = self.beatfunc[-2][0]
61 last_beat = self.bmelist[-1].beat
62 b = self.eval_beatfunc(t)
65 b = self.eval_beatfunc(t)
68 # It's time to get func-y
69 def generate_beatfunc(self):
71 bpms = filter(lambda x: x.type & (BME_TEMPO | BME_LONGMEASURE | BME_STOP), self.bmelist)
72 self.beatfunc = self.generate_beatfunc_r(bpms)
74 def generate_beatfunc_r(self, bpms, ct=0):
76 return [(3600000.0,0)]
81 ms_per_beat = 60000.0 / bpms[0].dataref
82 func = lambda t: (t - ct) / ms_per_beat + beat
87 duration = (next - beat) * ms_per_beat
88 self.lastbpm = bpms[0].dataref
89 elif type == BME_LONGMEASURE:
90 # Long measures only last one measure, so we do
91 # the slow measure just like a tempo change,
92 # then add a tempo change back at the end.
93 ms_per_beat = (60000.0 / self.lastbpm) * bpms[0].dataref
94 func = lambda t: (t - ct) / ms_per_beat + beat
96 print "Last BPM:",self.lastbpm
97 duration = 4 * ms_per_beat
98 bpms.insert(1,BMEvent(beat+4,BME_TEMPO,0,self.lastbpm))
99 elif type == BME_STOP:
100 func = lambda t: beat
101 duration = bpms[0].dataref
103 raise Exception("WTF? Invalid type in generate_beatfunc_r")
104 l = self.generate_beatfunc_r(bpms[1:], ct + duration)
105 l.insert(0,(ct,func))
108 def eval_beatfunc(self,t):
109 for n in range(0,len(self.beatfunc)-1):
110 if self.beatfunc[n][0] <= t and self.beatfunc[n+1][0] > t:
111 return self.beatfunc[n][1](t)
113 def show_beatfunc(self,surface):
115 xscale = end / surface.get_width()
116 yscale = self.bmelist[-1].beat / surface.get_height()
118 for t in range(0,end,100):
119 beat = self.eval_beatfunc(t)
121 pygame.draw.circle(surface,(255,255,255),(t/xscale,480 - beat / yscale),1)
123 pygame.draw.line(surface,(255,0,0), (t/140.625,0), (t/140.625,480))
129 def __init__(self,bmelist):
130 self.bmelist = bmelist
135 l = len(self.bmelist) - 1
138 while self.i > 0 and b < self.bmelist[self.i].beat:
140 while self.i < l and b > self.bmelist[self.i].beat:
143 def window(self,db,type=None):
144 l = len(self.bmelist)
148 while ei < l and eb >= self.bmelist[ei].beat:
152 return filter(lambda x: x.type & type, self.bmelist[self.i:ei])
154 return self.bmelist[self.i:ei]
161 for x in ["BMloader","SMloader"]:
162 f = open("loaders/" + x + ".py")
163 loaders.append(imp.load_module(x,f,x + ".py",(".py",'r',imp.PY_SOURCE)))
166 def vmessage(message):
167 fs = font.render(message, 0, (255,255,255),(0,0,0))
168 screen.fill((0,0,0),(0,450,640,30))
169 screen.blit(fs,(0,450))
171 def vstatus(type,arg):
172 if type == "STAGEFILE":
173 screen.blit(arg,(0,0))
175 vmessage("Loaded WAV " + arg)
177 vmessage("Loaded BMP " + arg)
178 elif type == "TRACK":
179 vmessage("Parsing track " + str(arg))
180 elif type == "ERROR":
181 vmessage("ERROR: " + arg)
182 pygame.display.flip()
184 def likelihood(file):
185 likelihoods = map(lambda l: l.detect(file), loaders)
188 for n in range(0,len(likelihoods)):
189 if likelihoods[n] > gl:
196 screen = pygame.display.get_surface()
197 font = pygame.font.SysFont("Helvetica Normal",30)
198 gn = likelihood(file)
201 kf = loaders[gn].load(file,vstatus)
202 kf.generate_beatfunc()
209 gn = likelihood(file)
210 d = loaders[gn].info(file)
211 d['loader.name'] = loaders[gn].name
212 d['loader.version'] = loaders[gn].version