From 65be19c725a4c1f95a2c2e23dc14d292b8ea7b25 Mon Sep 17 00:00:00 2001 From: Joan Duat <5954961+yannxou@users.noreply.github.com> Date: Sat, 7 Dec 2024 12:03:47 +0100 Subject: [PATCH] More stop actions (#6) * added action to stop playing clips from all armed tracks * added hint messages for quick-actions * added action to stop all recording clips * added missing action hint * added action to play all recording clips * swap D+F# and D+G# actions * add play scene action * swap C+C# and C+F# actions * F#+C action to stop all recording clips * F#+D action to play all recording clips --- README.md | 8 ++++++- Reface_CP/SongUtil.py | 20 ++++++++++++++++ Reface_CP/TransportController.py | 39 ++++++++++++++++++++++++++------ 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 87cbe56..c6aac1a 100644 --- a/README.md +++ b/README.md @@ -173,8 +173,10 @@ Here are all the actions that can be triggered from the MIDI keyboard: #### C ⏐ *Stop actions* * Press and release the key to stop playing. +* Press and hold + C# to stop playing clips from all armed tracks. * Press and hold + E to stop all clips from all tracks. * Press and hold + F to stop the current track clip (if any). +* Press and hold + F# to stop all recording clips. #### C# ⏐ *Recording actions* @@ -191,7 +193,9 @@ Here are all the actions that can be triggered from the MIDI keyboard: * Press and hold + use the white keys to change the song position (jump) according to the distance between the first key (D) and the second. This means the position can jump forwards by pressing a second higher white note or backwards by pressing a second lower white note. * Press and hold + C# to jump to the previous cue marker. * Press and hold + D# to jump to the next cue marker. -* Press and hold + F# to continue playback from the current position. +* Press and hold + F# to play all recording clips. +* Press and hold + G# to continue playback from the current position. +* Press and hold + A# to play the selected scene. #### E ⏐ *Tempo actions* @@ -214,7 +218,9 @@ Here are all the actions that can be triggered from the MIDI keyboard: #### F# ⏐ *Quick-recording actions* * Press and release the key to start a quick clip recording on all selected tracks. This starts recording on the next free scene of all selected tracks, creating a new scene if necessary. If a track is not armed it will be armed automatically if possible. +* Press and hold + C to stop all recording clips. * Press and hold + C# to start a quick recording on all armed tracks. This starts recording clips on the next free scene of all armed tracks, creating a new scene if necessary. +* Press and hold + D to play all recording clips. * Press and hold + F to start an Audio track resampling. This starts recording a new Audio clip into a track that takes the audio signal from the selected track's output, creating a new track if none is found. * Press and hold + G to start a MIDI track resampling. This starts recording a new MIDI clip into a track that takes the MIDI signal from the selected track's output, creating a new track if none is found. * Press and hold + G# to start a quick resampling. This starts recording a new clip in the next free scene of a track with a resampling input. If no resampling track is found a new one is created. diff --git a/Reface_CP/SongUtil.py b/Reface_CP/SongUtil.py index 144e08a..4df5c64 100644 --- a/Reface_CP/SongUtil.py +++ b/Reface_CP/SongUtil.py @@ -39,6 +39,26 @@ def find_track_index(track) -> int: if t == track: return idx return -1 + + @staticmethod + def play_all_recording_clips(): + """ + Play all the currently recording clips + """ + for track in SongUtil.find_armed_tracks(): + recording_clip_slot = next((slot for slot in track.clip_slots if slot.has_clip and slot.clip.is_recording), None) + if recording_clip_slot: + recording_clip_slot.fire() + + @staticmethod + def stop_all_recording_clips(): + """ + Stop all the currently recording clips + """ + for track in SongUtil.find_armed_tracks(): + recording_clip_slot = next((slot for slot in track.clip_slots if slot.has_clip and slot.clip.is_recording), None) + if recording_clip_slot: + recording_clip_slot.stop() # - Clip navigation diff --git a/Reface_CP/TransportController.py b/Reface_CP/TransportController.py index bfa5180..0e91c8d 100644 --- a/Reface_CP/TransportController.py +++ b/Reface_CP/TransportController.py @@ -109,11 +109,11 @@ def _on_note_key(self, value, sender): def _begin_action(self, action_key): action = action_key % 12 if action == Note.c: - self._logger.show_message("◼︎ Release to stop playing. │◼︎│ Hold+D: Stop track clips. │◼︎◼︎◼︎│ Hold+E: Stop all clips.") + self._logger.show_message("◼︎ Release to stop playing. │◼●│ Hold+C#: Stop armed tracks. │◼︎│ Hold+D: Stop track clips. │◼︎◼︎◼︎│ Hold+E: Stop all clips. [◼●] Hold+F#: Stop recording clips.") elif action == Note.c_sharp: self._logger.show_message("● Release to toggle record. ▶= Hold+C: Back to Arranger. ✚ Hold+D: Arrangement overdub. ○ Hold+D#: Session record •-• Hold+E: Automation arm. ◀︎- Hold+F: Reenable automation.") elif action == Note.d: - self._logger.show_message("▶ Release to start playing. ◀︎┼▶︎ Hold+white keys to jump. ▶│◀︎ Hold+C#/D#: Jump to prev/next cue. │▶ Hold+F#: Continue playback.") + self._logger.show_message("▶ Release to start playing. ◀︎┼▶︎ Hold+white keys to jump. ▶│◀︎ Hold+C#/D#: Jump to prev/next cue. [●]▶ Hold+F#: Play recording clips. │▶ Hold+G#: Continue playback. [▶…] Hold+A#: Play scene.") elif action == Note.e: self._logger.show_message("[○ ●] Release to toggle metronome. [↓▶] Hold+F/G: Inc/Dec Trigger Quantization. [1Bar] Hold+F#: Reset Quantization. [TAP] Hold+A.") elif action == Note.f: @@ -122,7 +122,7 @@ def _begin_action(self, action_key): else: self._logger.show_message("⚙︎ Release to toggle device/clip view. [M] Hold+C: Mute. [●] Hold+C#: Arm. [S] Hold+D: Solo. |←|→| Hold+E/G: Prev/Next track.") elif action == Note.f_sharp: - self._logger.show_message("[●] Release to start quick-recording. [●|←] Hold+F: Audio track resample. [●|←♪] Hold+G: MIDI track resample. │●…←│ Hold+G#: Quick-resampling.") + self._logger.show_message("[●] Release for quick-recording. [◼●] Hold+C: Stop recording clips. │●│ Hold+C#: Quick-record armed tracks. [●]▶ Hold+D: Play recording clips. [●|←] Hold+F: Audio track resample. [●|←♪] Hold+G: MIDI track resample. │●…←│ Hold+G#: Quick-resampling.") elif action == Note.g: self._logger.show_message("[◼︎] Hold+C: Stop clip. [x] Hold+C#: Delete clip. [▶] Hold+D: Fire clip. [▶..] Hold+E: Fire scene. [←|→] Hold+F/A: Prev/Next clip slot.") elif action == Note.a: @@ -193,12 +193,19 @@ def _handle_subaction(self, action_key, subaction_key): # Stop actions if action == Note.c: - if subaction == Note.e and is_same_octave: + if subaction == Note.c_sharp and is_same_octave: + self._logger.show_message("Stop clips from armed tracks.") + for track in SongUtil.find_armed_tracks(): + track.stop_all_clips() + elif subaction == Note.e and is_same_octave: self._logger.show_message("Stop all clips.") self._song.stop_all_clips() elif subaction == Note.f and is_same_octave: self._logger.show_message("Stop current track clip.") self._song.view.selected_track.stop_all_clips() + elif subaction == Note.f_sharp and is_same_octave: + self._logger.show_message("Stop recording clips.") + SongUtil.stop_all_recording_clips() else: self._logger.show_message("") self._current_action_key = None # Consume action (force to press again first note to redo action) @@ -241,9 +248,16 @@ def _handle_subaction(self, action_key, subaction_key): self._song.jump_to_next_cue() self._logger.show_message("Jump to next cue.") elif subaction == Note.f_sharp and is_same_octave: + self._logger.show_message("Play all recording clips.") + SongUtil.play_all_recording_clips() + elif subaction == Note.g_sharp and is_same_octave: self._logger.show_message("Play from selection.") self._song.continue_playing() # Continue playing the song from the current position self._current_action_key = None # Consume action (force to press again first note to redo action) + elif subaction == Note.a_sharp and is_same_octave: + self._logger.show_message("Play selected scene.") + self._song.view.selected_scene.fire() + self._current_action_skips_ending = True # Avoid sending main action on note off but allow sending more subactions. # Tempo actions @@ -293,15 +307,26 @@ def _handle_subaction(self, action_key, subaction_key): # Quick-recording actions elif action == Note.f_sharp: - if subaction == Note.c_sharp and is_same_octave: + if subaction == Note.c and is_same_octave: + self._logger.show_message("Stop recording clips.") + SongUtil.stop_all_recording_clips() + + elif subaction == Note.c_sharp and is_same_octave: armed_tracks = SongUtil.find_armed_tracks() SongUtil.start_quick_recording(tracks=armed_tracks) + self._logger.show_message("Quick-recording.") + + elif subaction == Note.d and is_same_octave: + self._logger.show_message("Play all recording clips.") + SongUtil.play_all_recording_clips() elif subaction == Note.f and is_same_octave: - SongUtil.start_track_audio_resampling(self._song.view.selected_track) + SongUtil.start_track_audio_resampling(self._song.view.selected_track) + self._logger.show_message("Audio track resampling.") elif subaction == Note.g and is_same_octave: - SongUtil.start_track_midi_resampling(self._song.view.selected_track) + SongUtil.start_track_midi_resampling(self._song.view.selected_track) + self._logger.show_message("MIDI track resampling.") elif subaction == Note.g_sharp and is_same_octave: SongUtil.start_quick_resampling(select_first=True)