aboutsummaryrefslogtreecommitdiff
path: root/music_sampler/action.py
diff options
context:
space:
mode:
Diffstat (limited to 'music_sampler/action.py')
-rw-r--r--music_sampler/action.py70
1 files changed, 47 insertions, 23 deletions
diff --git a/music_sampler/action.py b/music_sampler/action.py
index 22a2bdc..bc62f33 100644
--- a/music_sampler/action.py
+++ b/music_sampler/action.py
@@ -9,8 +9,9 @@ class Action:
9 'failed', 9 'failed',
10 { 10 {
11 'name': 'loaded', 11 'name': 'loaded',
12 'children': ['running'] 12 'children': ['stopped', 'running']
13 } 13 },
14 'destroyed'
14 ] 15 ]
15 16
16 TRANSITIONS = [ 17 TRANSITIONS = [
@@ -21,36 +22,42 @@ class Action:
21 }, 22 },
22 { 23 {
23 'trigger': 'fail', 24 'trigger': 'fail',
24 'source': 'loading', 25 'source': ['loading', 'loaded'],
25 'dest': 'failed', 26 'dest': 'failed',
26 'after': 'poll_loaded'
27 }, 27 },
28 { 28 {
29 'trigger': 'success', 29 'trigger': 'success',
30 'source': 'loading', 30 'source': 'loading',
31 'dest': 'loaded', 31 'dest': 'loaded_stopped',
32 'after': 'poll_loaded'
33 }, 32 },
34 { 33 {
35 'trigger': 'run', 34 'trigger': 'reload',
36 'source': 'loaded', 35 'source': 'loaded',
36 'dest': 'loading',
37 },
38 {
39 'trigger': 'run',
40 'source': 'loaded_stopped',
37 'dest': 'loaded_running', 41 'dest': 'loaded_running',
38 'after': 'finish_action', 42 'after': 'finish_action',
39 # if a child has no transitions, then it is bubbled to the parent,
40 # and we don't want that. Not useful in that machine precisely.
41 'conditions': ['is_loaded']
42 }, 43 },
43 { 44 {
44 'trigger': 'finish_action', 45 'trigger': 'finish_action',
45 'source': 'loaded_running', 46 'source': 'loaded_running',
46 'dest': 'loaded' 47 'dest': 'loaded_stopped'
48 },
49 {
50 'trigger': 'destroy',
51 'source': '*',
52 'dest': 'destroyed'
47 } 53 }
48 ] 54 ]
49 55
50 def __init__(self, action, key, **kwargs): 56 def __init__(self, action, key, **kwargs):
51 Machine(model=self, states=self.STATES, 57 Machine(model=self, states=self.STATES,
52 transitions=self.TRANSITIONS, initial='initial', 58 transitions=self.TRANSITIONS, initial='initial',
53 ignore_invalid_triggers=True, queued=True) 59 ignore_invalid_triggers=True, queued=True,
60 after_state_change=self.notify_state_change)
54 61
55 self.action = action 62 self.action = action
56 self.key = key 63 self.key = key
@@ -62,18 +69,31 @@ class Action:
62 def is_loaded_or_failed(self): 69 def is_loaded_or_failed(self):
63 return self.is_loaded(allow_substates=True) or self.is_failed() 70 return self.is_loaded(allow_substates=True) or self.is_failed()
64 71
65 def callback_music_loaded(self, success): 72 def callback_music_state(self, new_state):
66 if success: 73 # If a music gets unloaded while the action is loaded_running and
67 self.success() 74 # depending on the music, it won't be able to do the finish_action.
68 else: 75 # Can that happen?
76 # a: play 'mp3';
77 # z: wait 'mp3';
78 # e: pause 'mp3';
79 # r: stop 'mp3'; unload_music 'mp3'
80 if new_state == 'failed':
69 self.fail() 81 self.fail()
82 elif self.is_loaded(allow_substates=True) and\
83 new_state in ['initial', 'loading']:
84 self.reload(reloading=True)
85 elif self.is_loading() and new_state.startswith('loaded_'):
86 self.success()
70 87
71 # Machine states / events 88 # Machine states / events
72 def on_enter_loading(self): 89 def on_enter_loading(self, reloading=False):
90 if reloading:
91 return
73 if hasattr(actions, self.action): 92 if hasattr(actions, self.action):
74 if 'music' in self.arguments: 93 if 'music' in self.arguments and\
75 self.arguments['music'].subscribe_loaded( 94 self.action not in ['unload_music', 'load_music']:
76 self.callback_music_loaded) 95 self.arguments['music'].subscribe_state_change(
96 self.callback_music_state)
77 else: 97 else:
78 self.success() 98 self.success()
79 else: 99 else:
@@ -86,9 +106,13 @@ class Action:
86 getattr(actions, self.action).run(self, 106 getattr(actions, self.action).run(self,
87 key_start_time=key_start_time, **self.arguments) 107 key_start_time=key_start_time, **self.arguments)
88 108
89 def poll_loaded(self): 109 def on_enter_destroyed(self):
90 self.key.callback_action_ready(self, 110 if 'music' in self.arguments:
91 self.is_loaded(allow_substates=True)) 111 self.arguments['music'].unsubscribe_state_change(
112 self.callback_music_state)
113
114 def notify_state_change(self, *args, **kwargs):
115 self.key.callback_action_state_changed()
92 116
93 # This one cannot be in the Machine state since it would be queued to run 117 # This one cannot be in the Machine state since it would be queued to run
94 # *after* the wait is ended... 118 # *after* the wait is ended...