aboutsummaryrefslogtreecommitdiff
path: root/music_sampler/key.py
diff options
context:
space:
mode:
Diffstat (limited to 'music_sampler/key.py')
-rw-r--r--music_sampler/key.py156
1 files changed, 89 insertions, 67 deletions
diff --git a/music_sampler/key.py b/music_sampler/key.py
index bdae5bd..534a3db 100644
--- a/music_sampler/key.py
+++ b/music_sampler/key.py
@@ -9,7 +9,7 @@ import time
9import threading 9import threading
10from transitions.extensions import HierarchicalMachine as Machine 10from transitions.extensions import HierarchicalMachine as Machine
11 11
12class Key(ButtonBehavior, Widget): 12class KeyMachine(Widget):
13 STATES = [ 13 STATES = [
14 'initial', 14 'initial',
15 'configuring', 15 'configuring',
@@ -101,11 +101,84 @@ class Key(ButtonBehavior, Widget):
101 }, 101 },
102 ] 102 ]
103 103
104 state = StringProperty("")
105
106 def __init__(self, key, **kwargs):
107 self.key = key
108
109 Machine(model=self, states=self.STATES,
110 transitions=self.TRANSITIONS, initial='initial',
111 ignore_invalid_triggers=True, queued=True)
112 super(KeyMachine, self).__init__(**kwargs)
113
114 # Machine states / events
115 def is_loaded_or_failed(self):
116 return self.is_loaded(allow_substates=True) or self.is_failed()
117
118 def is_loaded_inactive(self):
119 return self.is_loaded_no_config() or self.is_loaded_no_actions()
120
121 def on_enter_configuring(self):
122 if self.key.key_sym in self.key.parent.key_config:
123 self.key.config = self.key.parent.key_config[self.key.key_sym]
124
125 self.key.actions = []
126 for key_action in self.key.config['actions']:
127 self.key.add_action(key_action[0], **key_action[1])
128
129 if 'description' in self.key.config['properties']:
130 self.key.set_description(self.key.config['properties']['description'])
131 else:
132 self.key.unset_description()
133 if 'color' in self.key.config['properties']:
134 self.key.set_color(self.key.config['properties']['color'])
135 else:
136 self.key.unset_color()
137 self.success()
138 else:
139 self.no_config()
140
141 def on_enter_loading(self):
142 if len(self.key.actions) > 0:
143 for action in self.key.actions:
144 action.load()
145 else:
146 self.no_actions()
147
148 def run_actions(self, modifiers):
149 self.key.parent.parent.ids['KeyList'].append(self.key.key_sym)
150 debug_print("running actions for {}".format(self.key.key_sym))
151 start_time = time.time()
152 self.key.parent.start_running(self, start_time)
153 for self.key.current_action in self.key.actions:
154 if self.key.parent.keep_running(self, start_time):
155 self.key.list_actions()
156 self.key.current_action.run(start_time)
157 self.key.list_actions(last_action_finished=True)
158
159 self.key.parent.finished_running(self, start_time)
160
161 def on_enter_loaded_protecting_repeat(self, modifiers):
162 if 'repeat_delay' in self.key.config['properties']:
163 self.key.protecting_repeat_timer = threading.Timer(
164 self.key.config['properties']['repeat_delay'],
165 self.key.repeat_protection_finished)
166 self.key.protecting_repeat_timer.start()
167 else:
168 self.key.repeat_protection_finished()
169
170 # Callbacks
171 def key_loaded_callback(self):
172 self.key.parent.key_loaded_callback()
173
174
175class Key(ButtonBehavior, Widget):
176
104 key_sym = StringProperty(None) 177 key_sym = StringProperty(None)
105 custom_color = ListProperty([0, 1, 0]) 178 custom_color = ListProperty([0, 1, 0])
106 description_title = StringProperty("") 179 description_title = StringProperty("")
107 description = ListProperty([]) 180 description = ListProperty([])
108 state = StringProperty("") 181 machine_state = StringProperty("")
109 182
110 def get_alias_line_cross_color(self): 183 def get_alias_line_cross_color(self):
111 if not self.is_failed() and ( 184 if not self.is_failed() and (
@@ -122,7 +195,7 @@ class Key(ButtonBehavior, Widget):
122 line_cross_color = AliasProperty( 195 line_cross_color = AliasProperty(
123 get_alias_line_cross_color, 196 get_alias_line_cross_color,
124 set_alias_line_cross_color, 197 set_alias_line_cross_color,
125 bind=['state']) 198 bind=['machine_state'])
126 199
127 def get_alias_line_color(self): 200 def get_alias_line_color(self):
128 if self.is_loaded_running(): 201 if self.is_loaded_running():
@@ -134,7 +207,7 @@ class Key(ButtonBehavior, Widget):
134 pass 207 pass
135 208
136 line_color = AliasProperty(get_alias_line_color, set_alias_line_color, 209 line_color = AliasProperty(get_alias_line_color, set_alias_line_color,
137 bind=['state']) 210 bind=['machine_state'])
138 211
139 def get_alias_color(self): 212 def get_alias_color(self):
140 if self.is_loaded_inactive(): 213 if self.is_loaded_inactive():
@@ -153,15 +226,23 @@ class Key(ButtonBehavior, Widget):
153 pass 226 pass
154 227
155 color = AliasProperty(get_alias_color, set_alias_color, 228 color = AliasProperty(get_alias_color, set_alias_color,
156 bind=['state', 'custom_color']) 229 bind=['machine_state', 'custom_color'])
230
231 def __getattr__(self, name):
232 if hasattr(self.machine, name):
233 return getattr(self.machine, name)
234 else:
235 raise AttributeError
236
237 def machine_state_changed(self, instance, machine_state):
238 self.machine_state = self.machine.state
157 239
158 def __init__(self, **kwargs): 240 def __init__(self, **kwargs):
159 self.actions = [] 241 self.actions = []
160 self.current_action = None 242 self.current_action = None
243 self.machine = KeyMachine(self)
244 self.machine.bind(state=self.machine_state_changed)
161 245
162 Machine(model=self, states=self.STATES,
163 transitions=self.TRANSITIONS, initial='initial',
164 ignore_invalid_triggers=True, queued=True)
165 super(Key, self).__init__(**kwargs) 246 super(Key, self).__init__(**kwargs)
166 247
167 # Kivy events 248 # Kivy events
@@ -172,71 +253,12 @@ class Key(ButtonBehavior, Widget):
172 def on_press(self): 253 def on_press(self):
173 self.list_actions() 254 self.list_actions()
174 255
175 # Machine states / events
176 def is_loaded_or_failed(self):
177 return self.is_loaded(allow_substates=True) or self.is_failed()
178
179 def is_loaded_inactive(self):
180 return self.is_loaded_no_config() or self.is_loaded_no_actions()
181
182 def on_enter_configuring(self):
183 if self.key_sym in self.parent.key_config:
184 self.config = self.parent.key_config[self.key_sym]
185
186 self.actions = []
187 for key_action in self.config['actions']:
188 self.add_action(key_action[0], **key_action[1])
189
190 if 'description' in self.config['properties']:
191 self.set_description(self.config['properties']['description'])
192 else:
193 self.unset_description()
194 if 'color' in self.config['properties']:
195 self.set_color(self.config['properties']['color'])
196 else:
197 self.unset_color()
198 self.success()
199 else:
200 self.no_config()
201
202 def on_enter_loading(self):
203 if len(self.actions) > 0:
204 for action in self.actions:
205 action.load()
206 else:
207 self.no_actions()
208
209 def run_actions(self, modifiers):
210 self.parent.parent.ids['KeyList'].append(self.key_sym)
211 debug_print("running actions for {}".format(self.key_sym))
212 start_time = time.time()
213 self.parent.start_running(self, start_time)
214 for self.current_action in self.actions:
215 if self.parent.keep_running(self, start_time):
216 self.list_actions()
217 self.current_action.run(start_time)
218 self.list_actions(last_action_finished=True)
219
220 self.parent.finished_running(self, start_time)
221
222 def on_enter_loaded_protecting_repeat(self, modifiers):
223 if 'repeat_delay' in self.config['properties']:
224 self.protecting_repeat_timer = threading.Timer(
225 self.config['properties']['repeat_delay'],
226 self.repeat_protection_finished)
227 self.protecting_repeat_timer.start()
228 else:
229 self.repeat_protection_finished()
230
231 # This one cannot be in the Machine state since it would be queued to run 256 # This one cannot be in the Machine state since it would be queued to run
232 # *after* the loop is ended... 257 # *after* the loop is ended...
233 def interrupt(self): 258 def interrupt(self):
234 self.current_action.interrupt() 259 self.current_action.interrupt()
235 260
236 # Callbacks 261 # Callbacks
237 def key_loaded_callback(self):
238 self.parent.key_loaded_callback()
239
240 def callback_action_ready(self, action, success): 262 def callback_action_ready(self, action, success):
241 if not success: 263 if not success:
242 self.fail() 264 self.fail()