aboutsummaryrefslogtreecommitdiff
path: root/helpers
diff options
context:
space:
mode:
authorIsmaël Bouya <ismael.bouya@normalesup.org>2016-06-18 00:29:15 +0200
committerIsmaël Bouya <ismael.bouya@normalesup.org>2016-06-18 00:29:15 +0200
commite7f8dab4980d8a477f305e3565ca3c80abd7d790 (patch)
tree494ecdd65d720825234e220bc9aa798f5fe94859 /helpers
parent1b79473633242db1c180e07d7165a5bd837eb62e (diff)
downloadMusicSampler-e7f8dab4980d8a477f305e3565ca3c80abd7d790.tar.gz
MusicSampler-e7f8dab4980d8a477f305e3565ca3c80abd7d790.tar.zst
MusicSampler-e7f8dab4980d8a477f305e3565ca3c80abd7d790.zip
Modifications to mapping/keys
Diffstat (limited to 'helpers')
-rw-r--r--helpers/__init__.py495
1 files changed, 329 insertions, 166 deletions
diff --git a/helpers/__init__.py b/helpers/__init__.py
index 7dbffdd..ec7da22 100644
--- a/helpers/__init__.py
+++ b/helpers/__init__.py
@@ -1,6 +1,11 @@
1# -*- coding: utf-8 -*- 1# -*- coding: utf-8 -*-
2from pygame import * 2from pygame import *
3import pydub
3import sys 4import sys
5import time
6import threading
7
8draw_lock = threading.RLock()
4 9
5class Action: 10class Action:
6 action_types = [ 11 action_types = [
@@ -8,6 +13,7 @@ class Action:
8 'pause', 13 'pause',
9 'play', 14 'play',
10 'stop', 15 'stop',
16 'stop_all_actions',
11 'volume', 17 'volume',
12 'wait', 18 'wait',
13 ] 19 ]
@@ -20,49 +26,120 @@ class Action:
20 26
21 self.arguments = kwargs 27 self.arguments = kwargs
22 28
23 def run(self, callback): 29 def ready(self):
24 getattr(self, self.action)(callback, **self.arguments) 30 if 'music' in self.arguments:
31 return self.arguments['music'].loaded
32 else:
33 return True
25 34
26 def command(self, callback, command = "", **kwargs): 35 def run(self):
27 pass 36 print(getattr(self, self.action + "_print")(**self.arguments))
37 return getattr(self, self.action)(**self.arguments)
28 38
29 def pause(self, callback, music = None, **kwargs): 39 def command(self, command = "", **kwargs):
30 pass 40 pass
31 41
32 def play(self, callback, 42 def pause(self, music = None, **kwargs):
33 music = None, 43 if music is not None:
34 fade_in = 0, 44 music.pause()
35 restart_if_running = False, 45 else:
36 volume = 100, 46 mixer.pause()
37 **kwargs):
38 pass
39 47
40 def stop(self, callback, music = None, fade_out = 0, **kwargs): 48 def play(self, music = None, fade_in = 0, start_at = 0,
41 print('stopping') 49 restart_if_running = False, volume = 100, **kwargs):
42 return callback() 50 if music is not None:
51 music.play()
52 else:
53 mixer.unpause()
43 54
44 def volume(self, callback, music = None, value = 100, **kwargs): 55 def stop(self, music = None, fade_out = 0, **kwargs):
45 pass 56 if music is not None:
57 music.stop()
58 else:
59 mixer.stop()
60
61 def stop_all_actions(self, **kwargs):
62 Key.running = []
46 63
47 def wait(self, callback, time = 0, **kwargs): 64 def volume(self, music = None, value = 100, **kwargs):
48 pass 65 pass
49 66
67 def wait(self, duration = 0, **kwargs):
68 time.sleep(duration)
69
70 def command_print(self, command = "", **kwargs):
71 return "running command {}".format(command)
72
73 def pause_print(self, music = None, **kwargs):
74 if music is not None:
75 return "pausing {}".format(music.filename)
76 else:
77 return "pausing all musics"
78
79 def play_print(self, music = None, fade_in = 0, start_at = 0,
80 restart_if_running = False, volume = 100, **kwargs):
81 message = "starting "
82 if music is not None:
83 message += music.filename
84 else:
85 message += "music"
86
87 if start_at != 0:
88 message += " at {}s".format(start_at)
89
90 if fade_in != 0:
91 message += " with {}s fade_in".format(fade_in)
92
93 message += " at volume {}%".format(volume)
94
95 if restart_if_running:
96 message += " (restarting if already running)"
97
98 return message
99
100 def stop_print(self, music = None, fade_out = 0, **kwargs):
101 if music is not None:
102 if fade_out == 0:
103 return "stopping music {}".format(music.filename)
104 else:
105 return "stopping music {} with {}s fadeout".format(music.filename, fade_out)
106 else:
107 if fade_out == 0:
108 return "stopping all musics"
109 else:
110 return "stopping all musics with {}s fadeout".format(fade_out)
111
112 def stop_all_actions_print(self):
113 return "stopping all actions"
114
115 def volume_print(self, music = None, value = 100, *kwargs):
116 if music is not None:
117 return "setting volume of {} to {}%".format(music.filename, value)
118 else:
119 return "setting volume to {}%".format(value)
120
121 def wait_print(self, duration, **kwargs):
122 return "waiting {}s".format(duration)
123
50class Key: 124class Key:
51 row_positions = { 125 row_positions = {
52 'first': 5, 126 'first': 0,
53 'second': 55, 127 'second': 50,
54 'third': 105, 128 'third': 100,
55 'fourth': 155, 129 'fourth': 150,
56 'fifth': 205, 130 'fifth': 200,
57 'sixth': 255, 131 'sixth': 250,
58 } 132 }
59 133
60 default_outer_color = (120, 120, 120) 134 default_outer_color = (120, 120, 120)
61 lighter_outer_color = (200, 200, 200) 135 lighter_outer_color = (200, 200, 200)
62 default_inner_color = (255, 255, 255) 136 default_inner_color = (255, 255, 255)
63 mapped_inner_color = ( 0, 255, 0) 137 mapped_inner_color = ( 0, 255, 0)
138 mapped_unready_inner_color = (255, 165, 0)
139 running = []
64 140
65 def __init__(self, key_name, key_sym, top, left, width = 48, height = 48, disabled = False): 141 def __init__(self, mapping, key_name, key_sym, top, left, width = 48, height = 48, disabled = False):
142 self.mapping = mapping
66 self.key_name = key_name 143 self.key_name = key_name
67 self.key_sym = key_sym 144 self.key_sym = key_sym
68 145
@@ -91,9 +168,12 @@ class Key:
91 self.inner_color = self.default_inner_color 168 self.inner_color = self.default_inner_color
92 self.actions = [] 169 self.actions = []
93 170
94 def square(self): 171 def square(self, all_actions_ready):
95 if self.has_action(): 172 if self.has_actions():
96 self.inner_color = self.mapped_inner_color 173 if all_actions_ready:
174 self.inner_color = self.mapped_inner_color
175 else:
176 self.inner_color = self.mapped_unready_inner_color
97 177
98 return RoundedRect((0, 0, self.width, self.height), 178 return RoundedRect((0, 0, self.width, self.height),
99 self.outer_color, self.inner_color, self.linewidth) 179 self.outer_color, self.inner_color, self.linewidth)
@@ -105,7 +185,10 @@ class Key:
105 ) 185 )
106 186
107 def draw(self, background_surface): 187 def draw(self, background_surface):
108 self.surface = self.square().surface() 188 draw_lock.acquire()
189 all_actions_ready = self.all_actions_ready()
190
191 self.surface = self.square(all_actions_ready).surface()
109 192
110 if getattr(sys, 'frozen', False): 193 if getattr(sys, 'frozen', False):
111 police = font.Font(sys._MEIPASS + "/Ubuntu-Regular.ttf", 14) 194 police = font.Font(sys._MEIPASS + "/Ubuntu-Regular.ttf", 14)
@@ -115,154 +198,229 @@ class Key:
115 text = police.render(self.key_sym, True, (0,0,0)) 198 text = police.render(self.key_sym, True, (0,0,0))
116 self.surface.blit(text, (5,5)) 199 self.surface.blit(text, (5,5))
117 background_surface.blit(self.surface, self.position) 200 background_surface.blit(self.surface, self.position)
201 draw_lock.release()
202
203 return not all_actions_ready
118 204
119 def has_action(self): 205 def poll_redraw(self, background):
206 while True:
207 time.sleep(1)
208 if self.all_actions_ready():
209 self.draw(background)
210 self.mapping.blit()
211 break
212
213 def has_actions(self):
120 return len(self.actions) > 0 214 return len(self.actions) > 0
121 215
216 def all_actions_ready(self):
217 return all(action.ready() for action in self.actions)
218
122 def add_action(self, action_name, **arguments): 219 def add_action(self, action_name, **arguments):
123 self.actions.append(Action(action_name, **arguments)) 220 self.actions.append(Action(action_name, **arguments))
124 221
125 def next_action(self):
126 print("running next action")
127
128 def do_actions(self): 222 def do_actions(self):
129 self.current_action = 0
130 print("running actions for {}".format(self.key_sym)) 223 print("running actions for {}".format(self.key_sym))
131 if len(self.actions) > 0: 224 Key.running.append(self)
132 self.actions[0].run(self.next_action) 225 for action in self.actions:
226 #FIXME: si on stop_all_actions et qu'on relance, "self" est de
227 #nouveau dans Key.running
228 if self in Key.running:
229 action.run()
230
231 if self in Key.running:
232 Key.running.remove(self)
133 233
134 def list_actions(self, surface): 234 def list_actions(self, surface):
235 # FIXME: Todo
135 print("bouh", self.key_sym) 236 print("bouh", self.key_sym)
136 surface.fill((255, 0, 0)) 237 surface.fill((255, 0, 0))
137 238
138 def find_by_key_num(key_num): 239
139 if key_num in Mapping.KEYS: 240class Mapping:
140 return Mapping.KEYS[key_num] 241 WIDTH = 903
242 HEIGHT = 298
243 SIZE = WIDTH, HEIGHT
244
245 KEYS = [
246 (K_ESCAPE, 'ESC', 'first', 0, {}),
247
248 (K_F1, 'F1', 'first', 100, {}),
249 (K_F2, 'F2', 'first', 150, {}),
250 (K_F3, 'F3', 'first', 200, {}),
251 (K_F4, 'F4', 'first', 250, {}),
252
253 (K_F5, 'F5', 'first', 325, {}),
254 (K_F6, 'F6', 'first', 375, {}),
255 (K_F7, 'F7', 'first', 425, {}),
256 (K_F8, 'F8', 'first', 475, {}),
257
258 (K_F9, 'F9', 'first', 550, {}),
259 (K_F10, 'F10', 'first', 600, {}),
260 (K_F11, 'F11', 'first', 650, {}),
261 (K_F12, 'F12', 'first', 700, {}),
262
263
264 (178, '²', 'second', 0, {}),
265 (K_AMPERSAND, '&', 'second', 50, {}),
266 (233, 'é', 'second', 100, {}),
267 (K_QUOTEDBL, '"', 'second', 150, {}),
268 (K_QUOTE, "'", 'second', 200, {}),
269 (K_LEFTPAREN, '(', 'second', 250, {}),
270 (K_MINUS, '-', 'second', 300, {}),
271 (232, 'è', 'second', 350, {}),
272 (K_UNDERSCORE, '_', 'second', 400, {}),
273 (231, 'ç', 'second', 450, {}),
274 (224, 'à', 'second', 500, {}),
275 (K_RIGHTPAREN, ')', 'second', 550, {}),
276 (K_EQUALS, '=', 'second', 600, {}),
277
278 (K_BACKSPACE, '<-', 'second', 650, { 'width': 98 }),
279
280
281 (K_TAB, 'tab', 'third', 0, { 'width' : 73 }),
282 (K_a, 'a', 'third', 75, {}),
283 (K_z, 'z', 'third', 125, {}),
284 (K_e, 'e', 'third', 175, {}),
285 (K_r, 'r', 'third', 225, {}),
286 (K_t, 't', 'third', 275, {}),
287 (K_y, 'y', 'third', 325, {}),
288 (K_u, 'u', 'third', 375, {}),
289 (K_i, 'i', 'third', 425, {}),
290 (K_o, 'o', 'third', 475, {}),
291 (K_p, 'p', 'third', 525, {}),
292 (K_CARET, '^', 'third', 575, {}),
293 (K_DOLLAR, '$', 'third', 625, {}),
294
295 (K_RETURN, 'Enter', 'third', 692, { 'width': 56, 'height': 98 }),
296
297 (K_CAPSLOCK, 'CAPS', 'fourth', 0, { 'width': 88, 'disabled': True }),
298
299 (K_q, 'q', 'fourth', 90, {}),
300 (K_s, 's', 'fourth', 140, {}),
301 (K_d, 'd', 'fourth', 190, {}),
302 (K_f, 'f', 'fourth', 240, {}),
303 (K_g, 'g', 'fourth', 290, {}),
304 (K_h, 'h', 'fourth', 340, {}),
305 (K_j, 'j', 'fourth', 390, {}),
306 (K_k, 'k', 'fourth', 440, {}),
307 (K_l, 'l', 'fourth', 490, {}),
308 (K_m, 'm', 'fourth', 540, {}),
309 (249, 'ù', 'fourth', 590, {}),
310 (K_ASTERISK, '*', 'fourth', 640, {}),
311
312
313 (K_LSHIFT, 'LShift', 'fifth', 0, { 'width': 63, 'disabled': True }),
314
315 (K_LESS, '<', 'fifth', 65, {}),
316 (K_w, 'w', 'fifth', 115, {}),
317 (K_x, 'x', 'fifth', 165, {}),
318 (K_c, 'c', 'fifth', 215, {}),
319 (K_v, 'v', 'fifth', 265, {}),
320 (K_b, 'b', 'fifth', 315, {}),
321 (K_n, 'n', 'fifth', 365, {}),
322 (K_COMMA, ',', 'fifth', 415, {}),
323 (K_SEMICOLON, ';', 'fifth', 465, {}),
324 (K_COLON, ':', 'fifth', 515, {}),
325 (K_EXCLAIM, '!', 'fifth', 565, {}),
326
327 (K_RSHIFT, 'RShift', 'fifth', 615, { 'width': 133, 'disabled': True }),
328
329 (K_LCTRL, 'LCtrl', 'sixth', 0, { 'width': 63, 'disabled': True }),
330 (K_LSUPER, 'LSuper', 'sixth', 115, { 'disabled': True }),
331 (K_LALT, 'LAlt', 'sixth', 165, { 'disabled': True }),
332 (K_SPACE, 'Espace', 'sixth', 215, { 'width': 248 }),
333 (K_MODE, 'AltGr', 'sixth', 465, { 'disabled': True }),
334 (314, 'Compose', 'sixth', 515, { 'disabled': True }),
335 (K_RCTRL, 'RCtrl', 'sixth', 565, { 'width': 63, 'disabled': True }),
336
337
338 (K_INSERT, 'ins', 'second', 755, {}),
339 (K_HOME, 'home', 'second', 805, {}),
340 (K_PAGEUP, 'pg_u', 'second', 855, {}),
341 (K_DELETE, 'del', 'third', 755, {}),
342 (K_END, 'end', 'third', 805, {}),
343 (K_PAGEDOWN, 'pg_d', 'third', 855, {}),
344
345
346 (K_UP, 'up', 'fifth', 805, {}),
347 (K_DOWN, 'down', 'sixth', 805, {}),
348 (K_LEFT, 'left', 'sixth', 755, {}),
349 (K_RIGHT, 'right', 'sixth', 855, {}),
350 ]
351
352 def __init__(self, screen):
353 self.screen = screen
354 self.background = Surface(self.SIZE).convert()
355 self.background.fill((250, 250, 250))
356 self.keys = {}
357 for key in self.KEYS:
358 self.keys[key[0]] = Key(self, *key[0:4], **key[4])
359
360 def draw(self):
361 for key_name in self.keys:
362 key = self.keys[key_name]
363 should_redraw_key = key.draw(self.background)
364
365 if should_redraw_key:
366 threading.Thread(target = key.poll_redraw, args = [self.background]).start()
367 self.blit()
368
369 def blit(self):
370 draw_lock.acquire()
371 self.screen.blit(self.background, (5, 5))
372 display.flip()
373 draw_lock.release()
374
375 def find_by_key_num(self, key_num):
376 if key_num in self.keys:
377 return self.keys[key_num]
141 return None 378 return None
142 379
143 def find_by_collidepoint(position): 380 def find_by_collidepoint(self, position):
144 for key in Mapping.KEYS: 381 for key in self.keys:
145 if Mapping.KEYS[key].collidepoint(position): 382 if self.keys[key].collidepoint(position):
146 return Mapping.KEYS[key] 383 return self.keys[key]
147 return None 384 return None
148 385
149 def find_by_unicode(key_sym): 386 def find_by_unicode(self, key_sym):
150 for key in Mapping.KEYS: 387 for key in self.keys:
151 if Mapping.KEYS[key].key_sym == key_sym: 388 if self.keys[key].key_sym == key_sym:
152 return Mapping.KEYS[key] 389 return self.keys[key]
153 return None 390 return None
154 391
155class Mapping: 392
156 KEYS = {
157 K_ESCAPE: Key(K_ESCAPE, 'ESC', 'first', 0),
158
159 K_F1: Key(K_F1, 'F1', 'first', 100),
160 K_F2: Key(K_F2, 'F2', 'first', 150),
161 K_F3: Key(K_F3, 'F3', 'first', 200),
162 K_F4: Key(K_F4, 'F4', 'first', 250),
163
164 K_F5: Key(K_F5, 'F5', 'first', 325),
165 K_F6: Key(K_F6, 'F6', 'first', 375),
166 K_F7: Key(K_F7, 'F7', 'first', 425),
167 K_F8: Key(K_F8, 'F8', 'first', 475),
168
169 K_F9: Key(K_F9, 'F9', 'first', 550),
170 K_F10: Key(K_F10, 'F10', 'first', 600),
171 K_F11: Key(K_F11, 'F11', 'first', 650),
172 K_F12: Key(K_F12, 'F12', 'first', 700),
173
174
175 178: Key(178, '²', 'second', 0),
176 K_AMPERSAND: Key(K_AMPERSAND, '&', 'second', 50),
177 233: Key(233, 'é', 'second', 100),
178 K_QUOTEDBL: Key(K_QUOTEDBL, '"', 'second', 150),
179 K_QUOTE: Key(K_QUOTE, "'", 'second', 200),
180 K_LEFTPAREN: Key(K_LEFTPAREN, '(', 'second', 250),
181 K_MINUS: Key(K_MINUS, '-', 'second', 300),
182 232: Key(232, 'è', 'second', 350),
183 K_UNDERSCORE: Key(K_UNDERSCORE, '_', 'second', 400),
184 231: Key(231, 'ç', 'second', 450),
185 224: Key(224, 'à', 'second', 500),
186 K_RIGHTPAREN: Key(K_RIGHTPAREN, ')', 'second', 550),
187 K_EQUALS: Key(K_EQUALS, '=', 'second', 600),
188
189 K_BACKSPACE: Key(K_BACKSPACE, '<-', 'second', 650, width = 98),
190
191
192 K_TAB: Key(K_TAB, 'tab', 'third', 0, width = 73),
193 K_a: Key(K_a, 'a', 'third', 75),
194 K_z: Key(K_z, 'z', 'third', 125),
195 K_e: Key(K_e, 'e', 'third', 175),
196 K_r: Key(K_r, 'r', 'third', 225),
197 K_t: Key(K_t, 't', 'third', 275),
198 K_y: Key(K_y, 'y', 'third', 325),
199 K_u: Key(K_u, 'u', 'third', 375),
200 K_i: Key(K_i, 'i', 'third', 425),
201 K_o: Key(K_o, 'o', 'third', 475),
202 K_p: Key(K_p, 'p', 'third', 525),
203 K_CARET: Key(K_CARET, '^', 'third', 575),
204 K_DOLLAR: Key(K_DOLLAR, '$', 'third', 625),
205
206 K_RETURN: Key(K_RETURN, 'Enter', 'third', 692, width = 56, height = 98),
207
208 K_CAPSLOCK: Key(K_CAPSLOCK, 'CAPS', 'fourth', 0, width = 88, disabled = True),
209
210 K_q: Key(K_q, 'q', 'fourth', 90),
211 K_s: Key(K_s, 's', 'fourth', 140),
212 K_d: Key(K_d, 'd', 'fourth', 190),
213 K_f: Key(K_f, 'f', 'fourth', 240),
214 K_g: Key(K_g, 'g', 'fourth', 290),
215 K_h: Key(K_h, 'h', 'fourth', 340),
216 K_j: Key(K_j, 'j', 'fourth', 390),
217 K_k: Key(K_k, 'k', 'fourth', 440),
218 K_l: Key(K_l, 'l', 'fourth', 490),
219 K_m: Key(K_m, 'm', 'fourth', 540),
220 249: Key(249, 'ù', 'fourth', 590),
221 K_ASTERISK: Key(K_ASTERISK, '*', 'fourth', 640),
222
223
224 K_LSHIFT: Key(K_LSHIFT, 'LShift', 'fifth', 0, width = 63, disabled = True),
225
226 K_LESS: Key(K_LESS, '<', 'fifth', 65),
227 K_w: Key(K_w, 'w', 'fifth', 115),
228 K_x: Key(K_x, 'x', 'fifth', 165),
229 K_c: Key(K_c, 'c', 'fifth', 215),
230 K_v: Key(K_v, 'v', 'fifth', 265),
231 K_b: Key(K_b, 'b', 'fifth', 315),
232 K_n: Key(K_n, 'n', 'fifth', 365),
233 K_COMMA: Key(K_COMMA, ',', 'fifth', 415),
234 K_SEMICOLON: Key(K_SEMICOLON, ';', 'fifth', 465),
235 K_COLON: Key(K_COLON, ':', 'fifth', 515),
236 K_EXCLAIM: Key(K_EXCLAIM, '!', 'fifth', 565),
237
238 K_RSHIFT: Key(K_RSHIFT, 'RShift', 'fifth', 615, width = 133, disabled = True),
239
240 K_LCTRL: Key(K_LCTRL, 'LCtrl', 'sixth', 0, width = 63, disabled = True),
241 K_LSUPER: Key(K_LSUPER, 'LSuper', 'sixth', 115, disabled = True),
242 K_LALT: Key(K_LALT, 'LAlt', 'sixth', 165, disabled = True),
243 K_SPACE: Key(K_SPACE, 'Espace', 'sixth', 215, width = 248),
244 K_MODE: Key(K_MODE, 'AltGr', 'sixth', 465, disabled = True),
245 314: Key(314, 'Compose', 'sixth', 515, disabled = True),
246 K_RCTRL: Key(K_RCTRL, 'RCtrl', 'sixth', 565, width = 63, disabled = True),
247
248
249 K_INSERT: Key(K_INSERT, 'ins', 'second', 755),
250 K_HOME: Key(K_HOME, 'home', 'second', 805),
251 K_PAGEUP: Key(K_PAGEUP, 'pg_u', 'second', 855),
252 K_DELETE: Key(K_DELETE, 'del', 'third', 755),
253 K_END: Key(K_END, 'end', 'third', 805),
254 K_PAGEDOWN: Key(K_PAGEDOWN, 'pg_d', 'third', 855),
255
256
257 K_UP: Key(K_UP, 'up', 'fifth', 805),
258 K_DOWN: Key(K_DOWN, 'down', 'sixth', 805),
259 K_LEFT: Key(K_LEFT, 'left', 'sixth', 755),
260 K_RIGHT: Key(K_RIGHT, 'right', 'sixth', 855),
261 }
262 393
263class MusicFile: 394class MusicFile:
264 def __init__(self, filename): 395 def __init__(self, filename, lock):
265 self.filename = filename 396 self.filename = filename
397 self.channel = None
398 self.raw_data = None
399 self.sound = None
400
401 self.loaded = False
402 threading.Thread(target = self.load_sound, args = [lock]).start()
403
404 def load_sound(self, lock):
405 lock.acquire()
406 print("Loading {}".format(self.filename))
407 self.raw_data = pydub.AudioSegment.from_file(self.filename).raw_data
408 self.sound = mixer.Sound(self.raw_data)
409 print("Loaded {}".format(self.filename))
410 self.loaded = True
411 lock.release()
412
413 def play(self):
414 self.channel = self.sound.play()
415
416 def pause(self):
417 if self.channel is not None:
418 self.channel.pause()
419
420 def stop(self):
421 self.channel = None
422 self.sound.stop()
423
266 424
267class RoundedRect: 425class RoundedRect:
268 def __init__(self, rect, outer_color, inner_color, linewidth = 2, radius = 0.4): 426 def __init__(self, rect, outer_color, inner_color, linewidth = 2, radius = 0.4):
@@ -324,7 +482,7 @@ class RoundedRect:
324 return rectangle 482 return rectangle
325 483
326 484
327def parse_config(): 485def parse_config(mapping):
328 import yaml 486 import yaml
329 stream = open("config.yml", "r") 487 stream = open("config.yml", "r")
330 config = yaml.load(stream) 488 config = yaml.load(stream)
@@ -333,8 +491,10 @@ def parse_config():
333 aliases = config['aliases'] 491 aliases = config['aliases']
334 seen_files = {} 492 seen_files = {}
335 493
494 file_lock = threading.RLock()
495
336 for mapped_key in config['keys']: 496 for mapped_key in config['keys']:
337 key = Key.find_by_unicode(mapped_key) 497 key = mapping.find_by_unicode(mapped_key)
338 if key is None: 498 if key is None:
339 continue 499 continue
340 500
@@ -344,18 +504,21 @@ def parse_config():
344 if action[action_name] is None: 504 if action[action_name] is None:
345 action[action_name] = [] 505 action[action_name] = []
346 506
507 if 'include' in action[action_name]:
508 included = action[action_name]['include']
509 del(action[action_name]['include'])
510
511 if isinstance(included, str):
512 action[action_name].update(aliases[included], **action[action_name])
513 else:
514 for included_ in included:
515 action[action_name].update(aliases[included_], **action[action_name])
516
347 for argument in action[action_name]: 517 for argument in action[action_name]:
348 if argument == 'include': 518 if argument == 'file':
349 included = action[action_name]['include']
350 if isinstance(included, str):
351 action_args.update(aliases[included])
352 else:
353 for included_ in included:
354 action_args.update(aliases[included_])
355 elif argument == 'file':
356 filename = action[action_name]['file'] 519 filename = action[action_name]['file']
357 if filename not in seen_files: 520 if filename not in seen_files:
358 seen_files[filename] = MusicFile.new(filename) 521 seen_files[filename] = MusicFile(filename, file_lock)
359 522
360 action_args['music'] = seen_files[filename] 523 action_args['music'] = seen_files[filename]
361 524