diff options
Diffstat (limited to 'music_sampler/action.py')
-rw-r--r-- | music_sampler/action.py | 70 |
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... |