From d93402ef87ff955266763485625e0de42794c3bd Mon Sep 17 00:00:00 2001 From: Raphael Date: Wed, 26 May 2021 16:19:17 +0200 Subject: [PATCH 1/3] there's no "set_E_color" for encoders so remove it! --- QSetup.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/QSetup.py b/QSetup.py index c618e0b..7659e78 100644 --- a/QSetup.py +++ b/QSetup.py @@ -143,8 +143,9 @@ def __init__(self): funcs = self._get_callbacks(c) setattr(self, "set_B_" + key, funcs[0]) setattr(self, "get_B_" + key, funcs[1]) - setattr(self, "set_E_" + key, funcs[2]) - setattr(self, "get_E_" + key, funcs[3]) + if key != "color": + setattr(self, "set_E_" + key, funcs[2]) + setattr(self, "get_E_" + key, funcs[3]) E_acc_set, E_acc_get = self._get_acceleration_callback() setattr(self, "set_E_acceleration", E_acc_set) From 7a37dc228701d6f55988609756bb136b66194716 Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 1 Jun 2021 23:23:21 +0200 Subject: [PATCH 2/3] use only "full-notes" for sequence initialization improve sequence-initializer info message --- QControlComponent.py | 6 +++++- QSequencer.py | 49 ++++++++++++++++++++++++++++++++------------ 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/QControlComponent.py b/QControlComponent.py index 254b8e2..84aabf7 100644 --- a/QControlComponent.py +++ b/QControlComponent.py @@ -1756,7 +1756,11 @@ def _transpose(self, value, set_values=True): ) if set_values: self._set_notes(self._transpose_val) - self._parent.show_message(get_midi_note_name(self._transpose_val)) + + if not self._sequencer: + self._parent.show_message(get_midi_note_name(self._transpose_val)) + else: + self.QSequencer.show_sequence_info(keepalive=False) # --------------- # indicate the transposed note via button lights diff --git a/QSequencer.py b/QSequencer.py index 4e56fba..bfe3df8 100644 --- a/QSequencer.py +++ b/QSequencer.py @@ -1,6 +1,7 @@ import Live from .QSetup import QSetup import time +from itertools import groupby # fmt: off symb_voltage = u"\u26A1" @@ -47,6 +48,13 @@ def simplify_fraction(numer, denom): return f"{reduced_num:.0f}/{reduced_den:.0f}" +def get_midi_note_name(value): + octave = int(value / 12) - 2 + note = "C C#D D#E F F#G G#A A#B "[(value % 12) * 2: (value % 12) * 2 + 2] + return (note.strip() + str(octave)).ljust(3) + +fullnotes = [i for i in range(128) if "#" not in get_midi_note_name(i)] + # class QSequencer(ControlSurface): class QSequencer(object): def __init__(self, parent): @@ -712,12 +720,13 @@ def get_all_note_specs(self, note): # ------------------------------------------- - def show_sequence_info(self): + def show_sequence_info(self, keepalive=True): # keep message alive until a clip is created - if self.clip is None: - self._parent._parent.schedule_message(16, self.show_sequence_info) - else: - self._parent._parent._task_group.clear() + if keepalive: + if self.clip is None: + self._parent._parent.schedule_message(16, self.show_sequence_info) + else: + self._parent._parent._task_group.clear() n_velocity = self.note_velocities.index(self.note_velocity) v_symb = v_bars[n_velocity] @@ -731,6 +740,14 @@ def show_sequence_info(self): pitchmsg = f"(pitch {self.sequence_up} every {self.sequence_n} notes)" + + + sequence = self.set_sequence() + + seqmsg = f" {symb_blue_diamond_small} ".join([" ".join(i[1]) for i in groupby(map(get_midi_note_name, sequence))]) + seqmsg = f"{symb_blue_diamond_small} {seqmsg} {symb_blue_diamond_small}" + + self._parent._parent.show_message( " " * 15 + msg @@ -738,6 +755,8 @@ def show_sequence_info(self): + f"{simplify_fraction(self.sequence_length, self.n_notes * 4)} BARS " + " " * 15 + pitchmsg + + " " * 15 + + seqmsg ) def set_sequence_length_button(self, i): @@ -839,16 +858,20 @@ def init_sequence(self): self.add_handler() def set_sequence(self): - notes = [self._parent._transpose_val for i in range(16)] + basenote = self._parent._transpose_val + if "#" in get_midi_note_name(basenote): + basenote += 1 + + pos = fullnotes.index(basenote) + notes = [basenote for i in range(16)] if self.sequence_n > 0: - for i in range(0, 16, self.sequence_n): - for j in range(self.sequence_n): - if i + j < len(notes): - notes[i + j] = ( - notes[i + j] + i // self.sequence_n * - self.sequence_up - ) + for n, i in enumerate(range(0, 16, self.sequence_n)): + for j in range(i, i + self.sequence_n): + if j == 16: break + note = fullnotes[pos + n * self.sequence_up] + notes[j] = note + return notes # get_notes_extended( (int)from_pitch, (int)pitch_span, (float)from_time, (float)time_span) -> From 860d1d13199bae1902d9c3856bedfdd311c7b578 Mon Sep 17 00:00:00 2001 From: Raphael Date: Wed, 2 Jun 2021 01:31:53 +0200 Subject: [PATCH 3/3] fix "clip can not be copied while it is recording" error - add status-bar messages on fail --- QControlComponent.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/QControlComponent.py b/QControlComponent.py index 84aabf7..36ce31c 100644 --- a/QControlComponent.py +++ b/QControlComponent.py @@ -192,7 +192,10 @@ def __init__(self, parent): self._update_lights() def _set_color(self, buttonid, color): + + colordict = dict(black=0, red=1, blue=16, magenta=17) + self._parent._send_midi( self._parent.QS.set_B_color(buttonid, colordict[color])) @@ -1254,9 +1257,13 @@ def callback(): def _duplicate_loop(self): clip_slot = self._parent.song().view.highlighted_clip_slot if clip_slot == None: + self._parent.show_message(symb_stop + " no loop to duplicate") return - if clip_slot.has_clip: - clip_slot.clip.duplicate_loop() + if not clip_slot.has_clip: + self._parent.show_message(symb_stop + " no loop to duplicate") + return + + clip_slot.clip.duplicate_loop() def _duplicate_or_delete_track(self): if self.__control_layer_permanent and self._shift_pressed: @@ -1334,9 +1341,15 @@ def _delete_scene(self): def _delete_clip(self): clip_slot = self._parent.song().view.highlighted_clip_slot - if clip_slot != None: - if clip_slot.has_clip: - clip_slot.delete_clip() + if clip_slot == None: + self._parent.show_message(symb_stop + " no clip to delete") + return + if not clip_slot.has_clip: + self._parent.show_message(symb_stop + " no clip to delete") + return + + clip_slot.delete_clip() + def _delete_device(self): track = self._parent.song().view.selected_track @@ -1404,6 +1417,13 @@ def _stop_clip_or_allclips(self): def _duplicate_clip(self): # duplicate the clip slot if self.selected_track == None: + self._parent.show_message(symb_stop + " no clip to duplicate") + return + if not self.selected_clip_slot.has_clip: + self._parent.show_message(symb_stop + " no clip to duplicate") + return + if self.selected_clip_slot.is_recording: + self._parent.show_message(symb_stop + " A clip cannot be copied while it is recording.") return duplicated_id = self.selected_track.duplicate_clip_slot(