From d4217fda2ff3991eb1ee9a9bec6acff751798507 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Isma=C3=ABl=20Bouya?= Date: Fri, 12 Aug 2016 18:21:22 +0200 Subject: [PATCH] wait actions are now pausable and resettable This fixes https://git.immae.eu/mantisbt/view.php?id=6 --- config.yml | 65 +++++++++++++------ documentation_en.md | 19 +++++- documentation_fr.md | 15 +++++ music_sampler/action.py | 18 +++++ music_sampler/actions/__init__.py | 3 + music_sampler/actions/pause_wait.py | 8 +++ music_sampler/actions/reset_wait.py | 8 +++ music_sampler/actions/unpause_wait.py | 8 +++ music_sampler/actions/wait.py | 54 ++++++++++++++- .../locales/fr/LC_MESSAGES/music_sampler.po | 24 +++++++ music_sampler/mapping.py | 33 ++++++++-- 11 files changed, 227 insertions(+), 28 deletions(-) create mode 100644 music_sampler/actions/pause_wait.py create mode 100644 music_sampler/actions/reset_wait.py create mode 100644 music_sampler/actions/unpause_wait.py diff --git a/config.yml b/config.yml index 37e085a..36c804b 100644 --- a/config.yml +++ b/config.yml @@ -75,6 +75,8 @@ music_properties: key_properties: 'common': repeat_delay: 1 + include: blue + 'a': description: - @@ -145,6 +147,11 @@ key_properties: - Low vol - Up vol include: green + 'ù': + description: + - + - stop + - wait 'home': description: @@ -160,18 +167,21 @@ key_properties: - "!" - STOP! include: red + repeat_delay: 0 'F5': description: - "||" - PAUSE include: light_green + repeat_delay: 0 'F6': description: - ">" - UNPAUSE include: light_green + repeat_delay: 0 'F1': description: @@ -179,6 +189,7 @@ key_properties: - Stop - fade include: orange + repeat_delay: 0 'F2': description: @@ -186,6 +197,7 @@ key_properties: - Stop - actions include: orange + repeat_delay: 0 'F4': description: @@ -193,30 +205,51 @@ key_properties: - Skip - wait include: pink + repeat_delay: 0 + + 'F8': + description: + - + - Pause + - wait + 'F9': + description: + - + - Unpause + - wait + 'F10': + description: + - + - Reset + - wait 'F12': description: - - vol+ include: yellow + repeat_delay: 0 'F11': description: - - "vol-" include: yellow + repeat_delay: 0 'right': description: - - +10s include: blue + repeat_delay: 0 'left': description: - - -10s include: blue + repeat_delay: 0 ################################################################# ##### Keys: what do the key actually do when you press them ##### @@ -246,10 +279,8 @@ keys: - stop: fade_out: 3 wait: true - set_wait_id: y1 - wait: duration: 3 - set_wait_id: y2 - play: include: music2 @@ -263,7 +294,6 @@ keys: include: music1 - wait: duration: 3 - set_wait_id: u - play: include: music2 @@ -274,7 +304,6 @@ keys: start_at: 30 - wait: duration: 5 - set_wait_id: g - seek: include: music1 delta: false @@ -293,6 +322,11 @@ keys: - play: include: music2 +# skip waiting for the end of music1 + 'ù': + - interrupt_wait: + wait_id: m + # Lowers the volume of music 1 and 2 (if playing), during the duration of noise + 1 second 'i': - volume: @@ -306,7 +340,6 @@ keys: - wait: include: noise duration: 1 - set_wait_id: i - volume: include: music1 value: 100 @@ -328,7 +361,6 @@ keys: fade: 5 - wait: duration: 5 - set_wait_id: n - volume: include: music1 value: 100 @@ -381,20 +413,15 @@ keys: # Skip wait 'F4': - interrupt_wait: - wait_id: n - - interrupt_wait: - wait_id: m - - interrupt_wait: - wait_id: i - - interrupt_wait: - wait_id: y1 - - interrupt_wait: - wait_id: y2 - - interrupt_wait: - wait_id: u - - interrupt_wait: - wait_id: g + 'F8': + - pause_wait: + + 'F9': + - unpause_wait: + + 'F10': + - reset_wait: # Changing volume 'F12': diff --git a/documentation_en.md b/documentation_en.md index 899ef1a..e92b85c 100644 --- a/documentation_en.md +++ b/documentation_en.md @@ -386,9 +386,22 @@ actions. action. When false, it is thus useless to add actions after that one. - `interrupt_wait`: stop a wait event (normal `wait` or fade out wait). The keys that were waiting will move to the next actions. Parameters: - * `wait_id: name` (optional) gives the id of the `wait` to interrupt (defined with - `set_wait_id`, see actions `wait` and `stop`). If not given, interrupts - all wait events. + * `wait_id: name` (optional) gives the id of the `wait` to interrupt + (defined with `set_wait_id`, see actions `wait` and `stop`). If not given, + interrupts all wait events. +- `pause_wait`: pauses a wait event (only for a wait with duration). The key + that were waiting will keep waiting until the `wait` is unpaused. Parameters: + * `wait_id: name` (optional) gives the id of the `wait` to pause. If not + given, pauses all compatible wait events. +- `unpause_wait`: unpauses a paused wait event (only a wait with duration). The + countdown will resume for the corresponding keys. Parameters: + * `wait_id: name` (optional) gives the id of the `wait` to unpause. If not + given, unpauses all compatible wait events. +- `reset_wait`: resets a wait counter (only a wait with duration). If the wait + was paused, it will stay paused and start at the beginning once it is + unpaused. Parameters: + * `wait_id: name` (optional) gives the id of the `wait` to reset. If not + given, resets all compatible wait events. - `run_command` : Run a command. Parameters: * `command: my_command` : Gives the command to run. * `wait: true/false` (optional, default false) if true, waits for the diff --git a/documentation_fr.md b/documentation_fr.md index ff3cfe8..cc2bf8f 100644 --- a/documentation_fr.md +++ b/documentation_fr.md @@ -435,6 +435,21 @@ successivement mais sans attendre (donc presque simultanément) : ne pas hésite * `wait_id: name` (facultatif) précise l'identifiant du `wait` à stopper (défini par `set_wait_id`, voir les actions `wait` et `stop`). Si absent, interrompt toutes les attentes. +- `pause_wait`: met une attente en pause (uniquement pour une attente ayant une + durée définie). La touche qui attend cet événement ne continuera pas tant que + l'attente n'est pas reprise. Paramètres : + * `wait_id: name` (facultatif) précise l'identifiant du `wait` à mettre en + pause. Si absent, met en pause toutes les attentes compatibles. +- `unpause_wait`: reprend une attente en pause (uniquement pour une attente + ayant une durée définie). Le compte à rebours reprendra pour la touche + correspondante en train d'attendre. Paramètres: + * `wait_id: name` (facultatif) précise l'identifiant du `wait` à reprendre. + Si absent, reprend toutes les attentes compatibles. +- `reset_wait`: réinitialise une attente (uniquement pour une attente ayant une + durée définie). Si l'attente est en pause, le compte à rebours ne recommencera + au début que lorsque l'attente sera reprise. Paramètres: + * `wait_id: name` (facultatif) précise l'identifiant du `wait` à + réinitialiser. Si absent, réinitialise toutes les attentes compatibles. - `run_command` : lance une commande. Paramètres : * `command: my_command` : précise la commande à lancer. * `wait: true/false` (facultatif, défaut : false) : si `wait` est true, diff --git a/music_sampler/action.py b/music_sampler/action.py index d269d0e..22a2bdc 100644 --- a/music_sampler/action.py +++ b/music_sampler/action.py @@ -98,6 +98,24 @@ class Action: return getattr(getattr(actions, self.action), 'interrupt')( self, **self.arguments) + def pause(self): + if getattr(actions, self.action, None) and\ + hasattr(getattr(actions, self.action), 'pause'): + return getattr(getattr(actions, self.action), 'pause')( + self, **self.arguments) + + def unpause(self): + if getattr(actions, self.action, None) and\ + hasattr(getattr(actions, self.action), 'unpause'): + return getattr(getattr(actions, self.action), 'unpause')( + self, **self.arguments) + + def reset(self): + if getattr(actions, self.action, None) and\ + hasattr(getattr(actions, self.action), 'reset'): + return getattr(getattr(actions, self.action), 'reset')( + self, **self.arguments) + # Helpers def music_list(self, music): if music is not None: diff --git a/music_sampler/actions/__init__.py b/music_sampler/actions/__init__.py index 658cef0..7c812cb 100644 --- a/music_sampler/actions/__init__.py +++ b/music_sampler/actions/__init__.py @@ -1,10 +1,13 @@ from . import interrupt_wait from . import pause +from . import pause_wait from . import play +from . import reset_wait from . import run_command from . import seek from . import stop from . import stop_all_actions from . import unpause +from . import unpause_wait from . import volume from . import wait diff --git a/music_sampler/actions/pause_wait.py b/music_sampler/actions/pause_wait.py new file mode 100644 index 0000000..e4ab6ea --- /dev/null +++ b/music_sampler/actions/pause_wait.py @@ -0,0 +1,8 @@ +def run(action, wait_id=None, **kwargs): + action.mapping.pause_wait(wait_id) + +def description(action, wait_id=None, **kwargs): + if wait_id is None: + return _("pause all waits") + else: + return _("pause wait with id {}").format(wait_id) diff --git a/music_sampler/actions/reset_wait.py b/music_sampler/actions/reset_wait.py new file mode 100644 index 0000000..500bcca --- /dev/null +++ b/music_sampler/actions/reset_wait.py @@ -0,0 +1,8 @@ +def run(action, wait_id=None, **kwargs): + action.mapping.reset_wait(wait_id) + +def description(action, wait_id=None, **kwargs): + if wait_id is None: + return _("reset all waits") + else: + return _("reset wait with id {}").format(wait_id) diff --git a/music_sampler/actions/unpause_wait.py b/music_sampler/actions/unpause_wait.py new file mode 100644 index 0000000..25e9a11 --- /dev/null +++ b/music_sampler/actions/unpause_wait.py @@ -0,0 +1,8 @@ +def run(action, wait_id=None, **kwargs): + action.mapping.unpause_wait(wait_id) + +def description(action, wait_id=None, **kwargs): + if wait_id is None: + return _("unpause all waits") + else: + return _("unpause wait with id {}").format(wait_id) diff --git a/music_sampler/actions/wait.py b/music_sampler/actions/wait.py index bcee649..31439b8 100644 --- a/music_sampler/actions/wait.py +++ b/music_sampler/actions/wait.py @@ -1,4 +1,5 @@ import threading +import time def run(action, duration=0, music=None, set_wait_id=None, **kwargs): action.mapping.add_wait(action, wait_id=set_wait_id) @@ -8,10 +9,17 @@ def run(action, duration=0, music=None, set_wait_id=None, **kwargs): duration, action.sleep_event.set) + action.sleep_event_initial_duration = duration + action.sleep_event_paused = False + action.sleep_event_left_time = duration + if music is not None: music.wait_end() - action.sleep_event_timer.start() + if duration <= 0 or not action.sleep_event_paused: + action.sleep_event_timer.start() + action.sleep_event_started_time = time.time() + action.sleep_event.wait() def description(action, duration=0, music=None, set_wait_id=None, **kwargs): @@ -34,6 +42,50 @@ def description(action, duration=0, music=None, set_wait_id=None, **kwargs): return _(message).format(*formats) +def pause(action, **kwargs): + if action.sleep_event_paused: + return + + action.sleep_event_paused = True + + if not action.sleep_event_timer.is_alive(): + return + + action.sleep_event_timer.cancel() + + action.sleep_event_left_time = action.sleep_event_left_time\ + - (time.time() - action.sleep_event_started_time) + if action.sleep_event_left_time < 0: + action.sleep_event.set() + +def unpause(action, **kwargs): + if not action.sleep_event_paused: + return + + action.sleep_event_paused = False + + action.sleep_event_timer = threading.Timer( + action.sleep_event_left_time, + action.sleep_event.set) + + action.sleep_event_timer.start() + action.sleep_event_started_time = time.time() + +def reset(action, **kwargs): + action.sleep_event_timer.cancel() + + action.sleep_event_left_time = action.sleep_event_initial_duration + + if action.sleep_event_paused: + return + + action.sleep_event_timer = threading.Timer( + action.sleep_event_left_time, + action.sleep_event.set) + + action.sleep_event_timer.start() + action.sleep_event_started_time = time.time() + def interrupt(action, duration=0, music=None, **kwargs): if action.sleep_event is not None: action.sleep_event.set() diff --git a/music_sampler/locales/fr/LC_MESSAGES/music_sampler.po b/music_sampler/locales/fr/LC_MESSAGES/music_sampler.po index 888d7a5..af27ca9 100644 --- a/music_sampler/locales/fr/LC_MESSAGES/music_sampler.po +++ b/music_sampler/locales/fr/LC_MESSAGES/music_sampler.po @@ -103,6 +103,14 @@ msgstr "mise en pause de « {} »" msgid "pausing all musics" msgstr "mise en pause des musiques" +#: music_sampler/actions/pause_wait.py:5 +msgid "pause wait with id {}" +msgstr "Mettre en pause l'attente d'identifiant {}" + +#: music_sampler/actions/pause_wait.py:5 +msgid "pause all waits" +msgstr "Mettre en pause toutes les attentes" + #: music_sampler/actions/play.py:50 msgid "starting « {} » at volume {}%" msgstr "lance « {} » au volume {}%" @@ -295,6 +303,14 @@ msgstr "lance « {} » à {}s avec un fondu de {}s au volume {}% en boucle (re msgid "starting all musics at {}s with {}s fade_in at volume {}% in loop (restarting if already running)" msgstr "lance toutes les musiques à {}s avec un fondu de {}s au volume {}% en boucle (redémarre si déjà lancée)" +#: music_sampler/actions/reset_wait.py:5 +msgid "reset wait with id {}" +msgstr "Réinitialise l'attente d'identifiant {}" + +#: music_sampler/actions/reset_wait.py:5 +msgid "reset all waits" +msgstr "Réinitialise toutes les attentes" + #: music_sampler/actions/run_command.py:15 msgid "running command {}" msgstr "lance la commande {}" @@ -367,6 +383,14 @@ msgstr "reprend « {} »" msgid "unpausing all musics" msgstr "reprend toutes les musiques" +#: music_sampler/actions/unpause_wait.py:5 +msgid "unpause wait with id {}" +msgstr "Reprendre l'attente d'identifiant {}" + +#: music_sampler/actions/unpause_wait.py:5 +msgid "unpause all waits" +msgstr "Reprendre toutes les attentes" + #: music_sampler/actions/volume.py:32 msgid "{:+d}% to volume of « {} »" msgstr "{:+d}% sur le volume de « {} »" diff --git a/music_sampler/mapping.py b/music_sampler/mapping.py index 99c9977..9e40d40 100644 --- a/music_sampler/mapping.py +++ b/music_sampler/mapping.py @@ -206,15 +206,17 @@ class Mapping(RelativeLayout): self.wait_ids[None] = [] self.wait_ids[None].append(action_or_wait) - def interrupt_wait(self, wait_id=None): + def matching_wait_ids(self, wait_id=None): if wait_id is None: - ids_to_interrupt = list(self.wait_ids.keys()) + matching_ids = list(self.wait_ids.keys()) elif wait_id in self.wait_ids: - ids_to_interrupt = [wait_id] + matching_ids = [wait_id] else: - ids_to_interrupt = [] + matching_ids = [] + return matching_ids - for _wait_id in ids_to_interrupt: + def interrupt_wait(self, wait_id=None): + for _wait_id in self.matching_wait_ids(wait_id=wait_id): action_or_waits = self.wait_ids[_wait_id] del(self.wait_ids[_wait_id]) for action_or_wait in action_or_waits: @@ -223,6 +225,27 @@ class Mapping(RelativeLayout): else: action_or_wait.set() + def pause_wait(self, wait_id=None): + for _wait_id in self.matching_wait_ids(wait_id=wait_id): + action_or_waits = self.wait_ids[_wait_id] + for action_or_wait in action_or_waits: + if isinstance(action_or_wait, Action): + action_or_wait.pause() + + def unpause_wait(self, wait_id=None): + for _wait_id in self.matching_wait_ids(wait_id=wait_id): + action_or_waits = self.wait_ids[_wait_id] + for action_or_wait in action_or_waits: + if isinstance(action_or_wait, Action): + action_or_wait.unpause() + + def reset_wait(self, wait_id=None): + for _wait_id in self.matching_wait_ids(wait_id=wait_id): + action_or_waits = self.wait_ids[_wait_id] + for action_or_wait in action_or_waits: + if isinstance(action_or_wait, Action): + action_or_wait.reset() + # Methods to control running keys def start_running(self, key, start_time): self.running.append((key, start_time)) -- 2.41.0