From a20217417bfebbb0c4d4b0ade7f4d607791b6738 Mon Sep 17 00:00:00 2001 From: Raphael Date: Wed, 26 May 2021 21:06:17 +0200 Subject: [PATCH 01/10] test of delayed task-messages for init-sequence --- BeatStep_Q.py | 93 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 20 deletions(-) diff --git a/BeatStep_Q.py b/BeatStep_Q.py index 3f12035..8bb7fc3 100644 --- a/BeatStep_Q.py +++ b/BeatStep_Q.py @@ -15,6 +15,8 @@ from .QControlComponent import QControlComponent from .QSetup import QSetup +from functools import partial + ENCODER_MSG_IDS = (10, 74, 71, 76, 77, 93, 73, 75, 114, 18, 19, 16, 17, 91, 79, 72) PAD_MSG_IDS = list(range(44, 52)) + list(range(36, 44)) @@ -24,28 +26,44 @@ MEMORY_SLOT = 8 SETUP_HARDWARE_DELAY = 2.1 +INDIVIDUAL_MESSAGE_DELAY = 0.001 + +def split_list(l, size): + for i in range(0, len(l), size): + yield l[i:i + size] + class BeatStep_Q(ControlSurface): def __init__(self, *a, **k): super(BeatStep_Q, self).__init__(*a, **k) + self._messages_to_send = [] self.QS = QSetup() self.control_layer_active = False with self.component_guard(): self._setup_hardware_task = self._tasks.add( - Task.sequence( - Task.wait(SETUP_HARDWARE_DELAY), Task.run(self._setup_hardware) - ) - ) + Task.run(self._init_color_sequence)) self._setup_hardware_task.kill() - self._start_hardware_setup() + self._setup_hardware_task.restart() + - self._create_controls() - self._create_Q_control() - self._create_device() + # self._setup_hardware_task = self._tasks.add( + # Task.sequence( + # Task.run(self._init_color_sequence), + # Task.wait(SETUP_HARDWARE_DELAY), + # Task.run(partial(self._setup_hardware, 0.1)), + # ) + # ) + # self._setup_hardware_task.kill() + # self._start_hardware_setup() + + # self._create_controls() + # self._create_Q_control() + + # self._create_device() def receive_midi(self, midi_bytes): # self.show_message(str(midi_bytes)) @@ -73,21 +91,56 @@ def f(): return f def _init_color_sequence(self): - for i in range(1, 9): - self.schedule_message(i, self._B_color_callback(i, 1)) - self.schedule_message(17 - i, self._B_color_callback(i, 16)) + delay = 0.1 + + sequence = [] + for i in range(1, 17): + sequence.append( + Task.run(partial(self._send_midi,self.QS.set_B_color(i, 1)))) + sequence.append(Task.wait(delay)) + + for i in range(1, 17): + sequence.append( + Task.run(partial(self._send_midi,self.QS.set_B_color(i, 16)))) + sequence.append(Task.wait(delay)) + for i in range(1, 17): - self.schedule_message(20, self._B_color_callback(i, 0)) + sequence.append( + Task.run(partial(self._send_midi,self.QS.set_B_color(i, 0)))) + sequence.append(Task.wait(delay)) + + + self._tasks.add(Task.sequence(*sequence)) + + + + + + + def _setup_hardware(self, delay=None): + if delay is None: + delay = INDIVIDUAL_MESSAGE_DELAY + + sequence_to_run = [] + for msg in self._messages_to_send: + sequence_to_run.append(Task.run(partial(self._send_midi, msg))) + sequence_to_run.append(Task.wait(delay)) + + for subsequence in split_list(sequence_to_run, 40): + self._tasks.add(Task.sequence(*subsequence)) + + self._messages_to_send = [] + - def _setup_hardware(self): - self._init_color_sequence() - self._setup_control_buttons_and_encoders() - self._setup_buttons_and_encoders() + # def _setup_hardware(self): + # self._init_color_sequence() + # self._setup_control_buttons_and_encoders() + # self._setup_buttons_and_encoders() - # set pad velocity to 0 (e.g. linear) on startup - self._send_midi(self.QS.set_B_velocity(0)) - # set encoder acceleration to "slow" on startup - self._send_midi(self.QS.set_E_acceleration(0)) + # # set pad velocity to 0 (e.g. linear) on startup + # self._send_midi(self.QS.set_B_velocity(0)) + # # set encoder acceleration to "slow" on startup + # self._send_midi(self.QS.set_E_acceleration(0)) def _setup_control_buttons_and_encoders(self): """ From fe703a7101514e12d5b823621c47cc33e00f1599 Mon Sep 17 00:00:00 2001 From: Raphael Date: Wed, 26 May 2021 21:36:55 +0200 Subject: [PATCH 02/10] use less messages --- BeatStep_Q.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BeatStep_Q.py b/BeatStep_Q.py index 8bb7fc3..0ecd809 100644 --- a/BeatStep_Q.py +++ b/BeatStep_Q.py @@ -94,17 +94,17 @@ def _init_color_sequence(self): delay = 0.1 sequence = [] - for i in range(1, 17): + for i in range(1, 5): sequence.append( Task.run(partial(self._send_midi,self.QS.set_B_color(i, 1)))) sequence.append(Task.wait(delay)) - for i in range(1, 17): + for i in range(5, 9): sequence.append( Task.run(partial(self._send_midi,self.QS.set_B_color(i, 16)))) sequence.append(Task.wait(delay)) - for i in range(1, 17): + for i in range(1, 9): sequence.append( Task.run(partial(self._send_midi,self.QS.set_B_color(i, 0)))) sequence.append(Task.wait(delay)) From c873a147a7a50d859e122e74cc5c88dad22dfa73 Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 27 May 2021 18:40:44 +0200 Subject: [PATCH 03/10] check longer message sequences --- BeatStep_Q.py | 98 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 32 deletions(-) diff --git a/BeatStep_Q.py b/BeatStep_Q.py index 0ecd809..c2e7dae 100644 --- a/BeatStep_Q.py +++ b/BeatStep_Q.py @@ -25,8 +25,8 @@ # the used memory-slot to store the configurations MEMORY_SLOT = 8 -SETUP_HARDWARE_DELAY = 2.1 -INDIVIDUAL_MESSAGE_DELAY = 0.001 +SETUP_HARDWARE_DELAY = 2.2 +INDIVIDUAL_MESSAGE_DELAY = 0#0.001 def split_list(l, size): for i in range(0, len(l), size): @@ -43,11 +43,16 @@ def __init__(self, *a, **k): self.control_layer_active = False with self.component_guard(): - self._setup_hardware_task = self._tasks.add( - Task.run(self._init_color_sequence)) - self._setup_hardware_task.kill() - self._setup_hardware_task.restart() + self._init_color_sequence() + # self._setup_hardware_task = self._tasks.add( + # Task.sequence( + # Task.wait(SETUP_HARDWARE_DELAY), + # Task.run(self._init_color_sequence), + # Task.run(partial(self._get_task_sequence, delay=0, maintain_order=True)) + # ) + # ) + # self._start_hardware_setup() # self._setup_hardware_task = self._tasks.add( @@ -75,12 +80,14 @@ def handle_sysex(self, midi_bytes): def port_settings_changed(self): super(BeatStep_Q, self).port_settings_changed() - self._start_hardware_setup() + + self._init_color_sequence() def _start_hardware_setup(self): - # kill already running setup tasks: - self._setup_hardware_task.kill() - self._messages_to_send = [] + if self._setup_hardware_task.is_running: + # kill already running setup tasks + self._setup_hardware_task.kill() + self._setup_hardware_task.restart() def _B_color_callback(self, b, c): @@ -90,48 +97,75 @@ def f(): return f - def _init_color_sequence(self): - delay = 0.1 - - sequence = [] - for i in range(1, 5): - sequence.append( - Task.run(partial(self._send_midi,self.QS.set_B_color(i, 1)))) - sequence.append(Task.wait(delay)) - - for i in range(5, 9): - sequence.append( - Task.run(partial(self._send_midi,self.QS.set_B_color(i, 16)))) - sequence.append(Task.wait(delay)) - for i in range(1, 9): - sequence.append( - Task.run(partial(self._send_midi,self.QS.set_B_color(i, 0)))) - sequence.append(Task.wait(delay)) + def _init_color_sequence(self): + msg_delay = 0.05 + init_task = self._tasks - self._tasks.add(Task.sequence(*sequence)) + offmsgs = [self.QS.set_B_color(i, 0) for i in range(1, 17)] + rmsgs = [self.QS.set_B_color(i, 1) for i in range(1, 17)] + bmsgs = [self.QS.set_B_color(i, 16) for i in range(1, 17)] + mmsgs = [self.QS.set_B_color(i, 17) for i in range(1, 17)] + msgs = [] + for i, [o, r, b, m, rr, br, mr] in enumerate(zip(offmsgs, rmsgs, bmsgs, mmsgs, + rmsgs[::-1], bmsgs[::-1], mmsgs[::-1])): + msgs.append([ + Task.wait(SETUP_HARDWARE_DELAY), + Task.run(partial(self._send_midi, o)), + Task.wait(msg_delay * (i + 1)), + Task.run(partial(self._send_midi, r)), + Task.wait(msg_delay * (16)), + Task.run(partial(self._send_midi, b)), + Task.wait(msg_delay * (16)), + Task.run(partial(self._send_midi, m)), + Task.wait(msg_delay * (16)), + Task.run(partial(self._send_midi, rr)), + Task.wait(msg_delay * (16)), + Task.run(partial(self._send_midi, br)), + Task.wait(msg_delay * (16)), + Task.run(partial(self._send_midi, mr)), + Task.wait(msg_delay * (16)), + Task.run(partial(self._send_midi, o)), + ]) + for i in msgs: + init_task.add(Task.sequence(*i)) - def _setup_hardware(self, delay=None): - if delay is None: - delay = INDIVIDUAL_MESSAGE_DELAY + def _get_task_sequence(self, delay=0, maintain_order=False): sequence_to_run = [] for msg in self._messages_to_send: sequence_to_run.append(Task.run(partial(self._send_midi, msg))) - sequence_to_run.append(Task.wait(delay)) + sequence_to_run.append(Task.wait(INDIVIDUAL_MESSAGE_DELAY)) + # bin the tasks into groups of 40 messages for subsequence in split_list(sequence_to_run, 40): self._tasks.add(Task.sequence(*subsequence)) self._messages_to_send = [] + + # def _setup_hardware(self, delay=None): + # if delay is None: + # delay = INDIVIDUAL_MESSAGE_DELAY + + # sequence_to_run = [] + # for msg in self._messages_to_send: + # sequence_to_run.append(Task.run(partial(self._send_midi, msg))) + # sequence_to_run.append(Task.wait(delay)) + + # for subsequence in split_list(sequence_to_run, 40): + # self._tasks.add(Task.sequence(*subsequence)) + + # self._messages_to_send = [] + + # def _setup_hardware(self): # self._init_color_sequence() # self._setup_control_buttons_and_encoders() From 33d21f1836ef0325c0a0cff990a404148efc7df3 Mon Sep 17 00:00:00 2001 From: Raphael Date: Mon, 31 May 2021 21:21:03 +0200 Subject: [PATCH 04/10] treading test --- BeatStep_Q.py | 309 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 214 insertions(+), 95 deletions(-) diff --git a/BeatStep_Q.py b/BeatStep_Q.py index c2e7dae..072e05d 100644 --- a/BeatStep_Q.py +++ b/BeatStep_Q.py @@ -16,6 +16,10 @@ from .QSetup import QSetup from functools import partial +from threading import Thread +from time import sleep + + ENCODER_MSG_IDS = (10, 74, 71, 76, 77, 93, 73, 75, 114, 18, 19, 16, 17, 91, 79, 72) PAD_MSG_IDS = list(range(44, 52)) + list(range(36, 44)) @@ -26,7 +30,7 @@ MEMORY_SLOT = 8 SETUP_HARDWARE_DELAY = 2.2 -INDIVIDUAL_MESSAGE_DELAY = 0#0.001 +INDIVIDUAL_MESSAGE_DELAY = 0.001 def split_list(l, size): for i in range(0, len(l), size): @@ -43,7 +47,30 @@ def __init__(self, *a, **k): self.control_layer_active = False with self.component_guard(): - self._init_color_sequence() + + self._create_controls() + self._create_Q_control() + + self._create_device() + + + # self._setup_hardware_task = self._tasks.add( + # Task.sequence( + # Task.run(self._collect_setup_messages), + # Task.wait(SETUP_HARDWARE_DELAY), + # Task.run(partial(self._setup_hardware, delay=.1)) + # )) + + # self._setup_hardware_task.kill() + # self._start_hardware_setup() + + self._set_init_color_sequence() + self._setup_hardware(msg_delay=0.1) + + self._collect_setup_messages() + self._setup_hardware() + + # self._init_color_sequence() # self._setup_hardware_task = self._tasks.add( # Task.sequence( @@ -79,75 +106,124 @@ def handle_sysex(self, midi_bytes): super(BeatStep_Q, self).handle_sysex(midi_bytes) def port_settings_changed(self): - super(BeatStep_Q, self).port_settings_changed() + #super(BeatStep_Q, self).port_settings_changed() + # self._start_hardware_setup() - self._init_color_sequence() + self._collect_setup_messages() + self._setup_hardware() - def _start_hardware_setup(self): - if self._setup_hardware_task.is_running: - # kill already running setup tasks - self._setup_hardware_task.kill() + # def _start_hardware_setup(self): + # with self.component_guard(): - self._setup_hardware_task.restart() + # if self._setup_hardware_task.is_running: + # # kill already running setup tasks + # self._setup_hardware_task.kill() - def _B_color_callback(self, b, c): - # do this to ensure callback-name closure - def f(): - self._send_midi(self.QS.set_B_color(b, c)) + # self._setup_hardware_task.restart() - return f + # Function with the timer + def send_hardware_change(self, delay=None): + if delay is None: + delay = INDIVIDUAL_MESSAGE_DELAY + + while len(self._messages_to_send) > 0: + sleep(delay) + msg = self._messages_to_send.pop(0) + self.log_message(str(msg)) + self._send_midi(msg) + + + def send_hardware_change(self, messages, delay=None): + #if delay is None: + # delay = INDIVIDUAL_MESSAGE_DELAY + + while len(messages) > 0: + if delay is not None: + sleep(delay) + msg = messages.pop(0) + + #self.log_message('sending...' + str(list(msg))) + + #self.log_message(str(msg)) + self._send_midi(tuple(msg)) + + + + + + + def _setup_hardware(self, delay=None, msg_delay=None, maintain_order=False): + if delay is None: + delay = INDIVIDUAL_MESSAGE_DELAY + + for sublist in split_list(self._messages_to_send, 20): + sleep(delay) + + # send sysex-messages with a delay + myThread = Thread(target=partial(self.send_hardware_change, messages=sublist, delay=msg_delay)) + myThread.start() + + if maintain_order: + sleep() + + self._messages_to_send = [] + + # with self.component_guard(): + # self.log_message("sending " + str(len(self._messages_to_send)) + " messages") + # if delay is None: + # delay = INDIVIDUAL_MESSAGE_DELAY - def _init_color_sequence(self): - msg_delay = 0.05 + # sequence_to_run = [None] * (len(self._messages_to_send) * 2) + # sequence_to_run[::2] = [ Task.run(partial(self._send_midi, msg)) for msg in self._messages_to_send ] + # sequence_to_run[1::2] = [ Task.wait(delay) for _ in self._messages_to_send ] - init_task = self._tasks + # self._tasks.add(Task.sequence(*sequence_to_run)) + + + # seqs = [] + # for subsequence in split_list(sequence_to_run, 40): + + # seqs.append(Task.sequence(*subsequence)) + + # self._tasks.add(Task.sequence(*seqs)) + + + + def _collect_setup_messages(self, layer="init"): + if layer == "init": + + self._setup_buttons_and_encoders() + self._setup_control_buttons_and_encoders() + + # set pad velocity to 0 (e.g. linear) on startup + self._messages_to_send.append(self.QS.set_B_velocity(0)) + # set encoder acceleration to "slow" on startup + self._messages_to_send.append(self.QS.set_E_acceleration(0)) + + + def _set_init_color_sequence(self): offmsgs = [self.QS.set_B_color(i, 0) for i in range(1, 17)] rmsgs = [self.QS.set_B_color(i, 1) for i in range(1, 17)] bmsgs = [self.QS.set_B_color(i, 16) for i in range(1, 17)] mmsgs = [self.QS.set_B_color(i, 17) for i in range(1, 17)] - msgs = [] - - for i, [o, r, b, m, rr, br, mr] in enumerate(zip(offmsgs, rmsgs, bmsgs, mmsgs, - rmsgs[::-1], bmsgs[::-1], mmsgs[::-1])): - msgs.append([ - Task.wait(SETUP_HARDWARE_DELAY), - Task.run(partial(self._send_midi, o)), - Task.wait(msg_delay * (i + 1)), - Task.run(partial(self._send_midi, r)), - Task.wait(msg_delay * (16)), - Task.run(partial(self._send_midi, b)), - Task.wait(msg_delay * (16)), - Task.run(partial(self._send_midi, m)), - Task.wait(msg_delay * (16)), - Task.run(partial(self._send_midi, rr)), - Task.wait(msg_delay * (16)), - Task.run(partial(self._send_midi, br)), - Task.wait(msg_delay * (16)), - Task.run(partial(self._send_midi, mr)), - Task.wait(msg_delay * (16)), - Task.run(partial(self._send_midi, o)), - ]) - - for i in msgs: - init_task.add(Task.sequence(*i)) - - - - def _get_task_sequence(self, delay=0, maintain_order=False): - - sequence_to_run = [] - for msg in self._messages_to_send: - sequence_to_run.append(Task.run(partial(self._send_midi, msg))) - sequence_to_run.append(Task.wait(INDIVIDUAL_MESSAGE_DELAY)) - - # bin the tasks into groups of 40 messages - for subsequence in split_list(sequence_to_run, 40): - self._tasks.add(Task.sequence(*subsequence)) - self._messages_to_send = [] + for msg in offmsgs + rmsgs + bmsgs + rmsgs[::-1] + offmsgs: + self._messages_to_send.append(msg) + + + + + + + def _B_color_callback(self, b, c): + # do this to ensure callback-name closure + def f(): + self._send_midi(self.QS.set_B_color(b, c)) + + return f @@ -182,86 +258,129 @@ def _setup_control_buttons_and_encoders(self): ensure correct assignments of function-buttons and transpose encoder """ # set shift button to note-mode - self._send_midi(self.QS.set_B_mode("shift", 8)) - self._send_midi(self.QS.set_B_channel("shift", CHANNEL)) - self._send_midi(self.QS.set_B_behaviour("shift", 1)) + self._messages_to_send.append(self.QS.set_B_mode("shift", 8)) + self._messages_to_send.append(self.QS.set_B_channel("shift", CHANNEL)) + self._messages_to_send.append(self.QS.set_B_behaviour("shift", 1)) # set stop button to note-mode - self._send_midi(self.QS.set_B_mode("stop", 8)) - self._send_midi(self.QS.set_B_channel("stop", CHANNEL)) - self._send_midi(self.QS.set_B_behaviour("stop", 1)) + self._messages_to_send.append(self.QS.set_B_mode("stop", 8)) + self._messages_to_send.append(self.QS.set_B_channel("stop", CHANNEL)) + self._messages_to_send.append(self.QS.set_B_behaviour("stop", 1)) # set play button to note-mode - self._send_midi(self.QS.set_B_mode("play", 8)) - self._send_midi(self.QS.set_B_channel("play", CHANNEL)) - self._send_midi(self.QS.set_B_behaviour("play", 1)) + self._messages_to_send.append(self.QS.set_B_mode("play", 8)) + self._messages_to_send.append(self.QS.set_B_channel("play", CHANNEL)) + self._messages_to_send.append(self.QS.set_B_behaviour("play", 1)) # set cntrl/seq button to note-mode - self._send_midi(self.QS.set_B_mode("cntrl", 8)) - self._send_midi(self.QS.set_B_channel("cntrl", CHANNEL)) + self._messages_to_send.append(self.QS.set_B_mode("cntrl", 8)) + self._messages_to_send.append(self.QS.set_B_channel("cntrl", CHANNEL)) # set button behaviour to toggle - self._send_midi(self.QS.set_B_behaviour("cntrl", 0)) + self._messages_to_send.append(self.QS.set_B_behaviour("cntrl", 0)) # set chan button to note mode - self._send_midi(self.QS.set_B_mode("chan", 8)) - self._send_midi(self.QS.set_B_channel("chan", CHANNEL)) - self._send_midi(self.QS.set_B_behaviour("chan", 1)) + self._messages_to_send.append(self.QS.set_B_mode("chan", 8)) + self._messages_to_send.append(self.QS.set_B_channel("chan", CHANNEL)) + self._messages_to_send.append(self.QS.set_B_behaviour("chan", 1)) # set store button to note mode - self._send_midi(self.QS.set_B_mode("store", 8)) - self._send_midi(self.QS.set_B_channel("store", CHANNEL)) - self._send_midi(self.QS.set_B_behaviour("store", 1)) + self._messages_to_send.append(self.QS.set_B_mode("store", 8)) + self._messages_to_send.append(self.QS.set_B_channel("store", CHANNEL)) + self._messages_to_send.append(self.QS.set_B_behaviour("store", 1)) # set store button to note mode - self._send_midi(self.QS.set_B_mode("recall", 8)) - self._send_midi(self.QS.set_B_channel("recall", CHANNEL)) - self._send_midi(self.QS.set_B_behaviour("recall", 1)) + self._messages_to_send.append(self.QS.set_B_mode("recall", 8)) + self._messages_to_send.append(self.QS.set_B_channel("recall", CHANNEL)) + self._messages_to_send.append(self.QS.set_B_behaviour("recall", 1)) # set transpose encoder channel - self._send_midi(self.QS.set_E_channel("transpose", CHANNEL)) - self._send_midi(self.QS.set_E_behaviour("transpose", 2)) + self._messages_to_send.append(self.QS.set_E_channel("transpose", CHANNEL)) + self._messages_to_send.append(self.QS.set_E_behaviour("transpose", 2)) # set encoder cc to something else than the shift-encoder cc # (4 is unused since it would represent the ext/sync button) - self._send_midi(self.QS.set_E_cc("transpose", 4)) + self._messages_to_send.append(self.QS.set_E_cc("transpose", 4)) def _setup_buttons_and_encoders(self): # for all buttons and encoders for i in range(1, 17): # set pad to note-mode - self._send_midi(self.QS.set_B_mode(i, 9)) + self._messages_to_send.append(self.QS.set_B_mode(i, 9)) # set pad channel - self._send_midi(self.QS.set_B_channel(i, CHANNEL)) + self._messages_to_send.append(self.QS.set_B_channel(i, CHANNEL)) # set pad behaviour to toggle - self._send_midi(self.QS.set_B_behaviour(i, 1)) + self._messages_to_send.append(self.QS.set_B_behaviour(i, 1)) # set encoder channel - self._send_midi(self.QS.set_E_channel(i, CHANNEL)) + self._messages_to_send.append(self.QS.set_E_channel(i, CHANNEL)) # set all encoders to relative-mode 2 - self._send_midi(self.QS.set_E_behaviour(i, 2)) + self._messages_to_send.append(self.QS.set_E_behaviour(i, 2)) # set all encoders to midi cc mode - self._send_midi(self.QS.set_E_mode(i, 1)) + self._messages_to_send.append(self.QS.set_E_mode(i, 1)) # set midi cc id's for all encoders - self._send_midi(self.QS.set_E_cc(i, ENCODER_MSG_IDS[i - 1])) + self._messages_to_send.append(self.QS.set_E_cc(i, ENCODER_MSG_IDS[i - 1])) + + + + def _set_control_mode_msgs(self): - def _do_activate_control_mode(self): # for all buttons for i in range(1, 17): # set pad to cc-mode - self._send_midi(self.QS.set_B_mode(i, 8)) + self._messages_to_send.append(self.QS.set_B_mode(i, 8)) # set pad channel - self._send_midi(self.QS.set_B_channel(i, CHANNEL)) + self._messages_to_send.append(self.QS.set_B_channel(i, CHANNEL)) # set pad behaviour to toggle - self._send_midi(self.QS.set_B_behaviour(i, 1)) + self._messages_to_send.append(self.QS.set_B_behaviour(i, 1)) # set encoder channel - self._send_midi(self.QS.set_E_channel(i, CHANNEL)) + self._messages_to_send.append(self.QS.set_E_channel(i, CHANNEL)) # set all encoders to relative-mode 2 - self._send_midi(self.QS.set_E_behaviour(i, 2)) + self._messages_to_send.append(self.QS.set_E_behaviour(i, 2)) # set transpose encoder channel to follow global channel - self._send_midi(self.QS.set_E_channel("transpose", CHANNEL)) + self._messages_to_send.append(self.QS.set_E_channel("transpose", CHANNEL)) # set transpose encoder to relative mode 2 - self._send_midi(self.QS.set_E_behaviour("transpose", 2)) + self._messages_to_send.append(self.QS.set_E_behaviour("transpose", 2)) + + + + + def _do_activate_control_mode(self): + self.log_message('activating') + self._set_control_mode_msgs() + self._setup_hardware() + + # with self.component_guard(): + # self._setup_layer_task = self._tasks.add( + # Task.sequence( + # Task.run(self._set_control_mode_msgs), + # Task.wait(INDIVIDUAL_MESSAGE_DELAY), + # Task.run(partial(self._setup_hardware)) + # )) + + # self._setup_layer_task.kill() + # self._setup_layer_task.restart() + + + + # # for all buttons + # for i in range(1, 17): + # # set pad to cc-mode + # self._send_midi(self.QS.set_B_mode(i, 8)) + # # set pad channel + # self._send_midi(self.QS.set_B_channel(i, CHANNEL)) + # # set pad behaviour to toggle + # self._send_midi(self.QS.set_B_behaviour(i, 1)) + + # # set encoder channel + # self._send_midi(self.QS.set_E_channel(i, CHANNEL)) + # # set all encoders to relative-mode 2 + # self._send_midi(self.QS.set_E_behaviour(i, 2)) + + # # set transpose encoder channel to follow global channel + # self._send_midi(self.QS.set_E_channel("transpose", CHANNEL)) + # # set transpose encoder to relative mode 2 + # self._send_midi(self.QS.set_E_behaviour("transpose", 2)) def _deactivate_control_mode(self): self._send_midi(self.QS.recall_preset(MEMORY_SLOT)) From 0d075c47446daf43187008bbda4254fea7333568 Mon Sep 17 00:00:00 2001 From: Raphael Date: Mon, 31 May 2021 21:30:17 +0200 Subject: [PATCH 05/10] threading test --- BeatStep_Q.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/BeatStep_Q.py b/BeatStep_Q.py index 072e05d..d688ce7 100644 --- a/BeatStep_Q.py +++ b/BeatStep_Q.py @@ -134,13 +134,15 @@ def send_hardware_change(self, delay=None): self._send_midi(msg) - def send_hardware_change(self, messages, delay=None): + def send_hardware_change(self, messages, delay=None, msg_delay=None): #if delay is None: # delay = INDIVIDUAL_MESSAGE_DELAY + if msg_delay is not None: + sleep(delay) while len(messages) > 0: - if delay is not None: - sleep(delay) + if msg_delay is not None: + sleep(msg_delay) msg = messages.pop(0) #self.log_message('sending...' + str(list(msg))) @@ -153,19 +155,19 @@ def send_hardware_change(self, messages, delay=None): - def _setup_hardware(self, delay=None, msg_delay=None, maintain_order=False): + def _setup_hardware(self, delay=None, msg_delay=None, maintain_order=True): if delay is None: delay = INDIVIDUAL_MESSAGE_DELAY - for sublist in split_list(self._messages_to_send, 20): - sleep(delay) + for i, sublist in enumerate(split_list(self._messages_to_send, 20)): # send sysex-messages with a delay - myThread = Thread(target=partial(self.send_hardware_change, messages=sublist, delay=msg_delay)) + myThread = Thread(target=partial(self.send_hardware_change, + messages=sublist, + delay=delay + 20*i*msg_delay, + msg_delay=msg_delay)) myThread.start() - if maintain_order: - sleep() self._messages_to_send = [] From af47324632680a177dc96258ba400d755ebdf2b3 Mon Sep 17 00:00:00 2001 From: Raphael Date: Mon, 31 May 2021 21:30:29 +0200 Subject: [PATCH 06/10] more updates --- BeatStep_Q.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/BeatStep_Q.py b/BeatStep_Q.py index d688ce7..f160b84 100644 --- a/BeatStep_Q.py +++ b/BeatStep_Q.py @@ -158,13 +158,14 @@ def send_hardware_change(self, messages, delay=None, msg_delay=None): def _setup_hardware(self, delay=None, msg_delay=None, maintain_order=True): if delay is None: delay = INDIVIDUAL_MESSAGE_DELAY - for i, sublist in enumerate(split_list(self._messages_to_send, 20)): + if msg_delay is not None: + delay += 20*i*msg_delay # send sysex-messages with a delay myThread = Thread(target=partial(self.send_hardware_change, messages=sublist, - delay=delay + 20*i*msg_delay, + delay=delay, msg_delay=msg_delay)) myThread.start() From 054a8090efe76b7260e97943b32d321bb1e60fea Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 1 Jun 2021 20:24:32 +0200 Subject: [PATCH 07/10] get rid of threading - results in boost.python errors... - use simple message-scheduling approach --- BeatStep_Q.py | 167 +++++--------------------------------------------- 1 file changed, 17 insertions(+), 150 deletions(-) diff --git a/BeatStep_Q.py b/BeatStep_Q.py index f160b84..3962f47 100644 --- a/BeatStep_Q.py +++ b/BeatStep_Q.py @@ -30,7 +30,7 @@ MEMORY_SLOT = 8 SETUP_HARDWARE_DELAY = 2.2 -INDIVIDUAL_MESSAGE_DELAY = 0.001 +INDIVIDUAL_MESSAGE_DELAY = 0.01 def split_list(l, size): for i in range(0, len(l), size): @@ -50,53 +50,9 @@ def __init__(self, *a, **k): self._create_controls() self._create_Q_control() - self._create_device() - # self._setup_hardware_task = self._tasks.add( - # Task.sequence( - # Task.run(self._collect_setup_messages), - # Task.wait(SETUP_HARDWARE_DELAY), - # Task.run(partial(self._setup_hardware, delay=.1)) - # )) - - # self._setup_hardware_task.kill() - # self._start_hardware_setup() - - self._set_init_color_sequence() - self._setup_hardware(msg_delay=0.1) - - self._collect_setup_messages() - self._setup_hardware() - - # self._init_color_sequence() - - # self._setup_hardware_task = self._tasks.add( - # Task.sequence( - # Task.wait(SETUP_HARDWARE_DELAY), - # Task.run(self._init_color_sequence), - # Task.run(partial(self._get_task_sequence, delay=0, maintain_order=True)) - # ) - # ) - # self._start_hardware_setup() - - - # self._setup_hardware_task = self._tasks.add( - # Task.sequence( - # Task.run(self._init_color_sequence), - # Task.wait(SETUP_HARDWARE_DELAY), - # Task.run(partial(self._setup_hardware, 0.1)), - # ) - # ) - # self._setup_hardware_task.kill() - # self._start_hardware_setup() - - # self._create_controls() - # self._create_Q_control() - - # self._create_device() - def receive_midi(self, midi_bytes): # self.show_message(str(midi_bytes)) super(BeatStep_Q, self).receive_midi(midi_bytes) @@ -108,94 +64,27 @@ def handle_sysex(self, midi_bytes): def port_settings_changed(self): #super(BeatStep_Q, self).port_settings_changed() # self._start_hardware_setup() + self._set_init_color_sequence() + self._setup_hardware(delay=1, start_delay=SETUP_HARDWARE_DELAY) self._collect_setup_messages() - self._setup_hardware() - - # def _start_hardware_setup(self): - # with self.component_guard(): - - # if self._setup_hardware_task.is_running: - # # kill already running setup tasks - # self._setup_hardware_task.kill() - - # self._setup_hardware_task.restart() - - - # Function with the timer - def send_hardware_change(self, delay=None): - if delay is None: - delay = INDIVIDUAL_MESSAGE_DELAY - - while len(self._messages_to_send) > 0: - sleep(delay) - msg = self._messages_to_send.pop(0) - self.log_message(str(msg)) - self._send_midi(msg) - - - def send_hardware_change(self, messages, delay=None, msg_delay=None): - #if delay is None: - # delay = INDIVIDUAL_MESSAGE_DELAY - if msg_delay is not None: - sleep(delay) - - while len(messages) > 0: - if msg_delay is not None: - sleep(msg_delay) - msg = messages.pop(0) - - #self.log_message('sending...' + str(list(msg))) + self._setup_hardware(start_delay=SETUP_HARDWARE_DELAY) - #self.log_message(str(msg)) - self._send_midi(tuple(msg)) - - - - - - - def _setup_hardware(self, delay=None, msg_delay=None, maintain_order=True): + def _setup_hardware(self, delay=None, start_delay=0.): if delay is None: delay = INDIVIDUAL_MESSAGE_DELAY - for i, sublist in enumerate(split_list(self._messages_to_send, 20)): - if msg_delay is not None: - delay += 20*i*msg_delay - - # send sysex-messages with a delay - myThread = Thread(target=partial(self.send_hardware_change, - messages=sublist, - delay=delay, - msg_delay=msg_delay)) - myThread.start() - - - self._messages_to_send = [] - - # with self.component_guard(): - # self.log_message("sending " + str(len(self._messages_to_send)) + " messages") - # if delay is None: - # delay = INDIVIDUAL_MESSAGE_DELAY - - # sequence_to_run = [None] * (len(self._messages_to_send) * 2) - # sequence_to_run[::2] = [ Task.run(partial(self._send_midi, msg)) for msg in self._messages_to_send ] - # sequence_to_run[1::2] = [ Task.wait(delay) for _ in self._messages_to_send ] - - # self._tasks.add(Task.sequence(*sequence_to_run)) - - - # seqs = [] - # for subsequence in split_list(sequence_to_run, 40): - - # seqs.append(Task.sequence(*subsequence)) - - # self._tasks.add(Task.sequence(*seqs)) - + # add individual message delays + i = 1 + with self.component_guard(): + while len(self._messages_to_send) > 0: + msg = self._messages_to_send.pop(0) + self.schedule_message(i * delay + start_delay, + partial(self._send_midi, msg)) + i += 1 def _collect_setup_messages(self, layer="init"): if layer == "init": - self._setup_buttons_and_encoders() self._setup_control_buttons_and_encoders() @@ -230,31 +119,6 @@ def f(): - # def _setup_hardware(self, delay=None): - # if delay is None: - # delay = INDIVIDUAL_MESSAGE_DELAY - - # sequence_to_run = [] - # for msg in self._messages_to_send: - # sequence_to_run.append(Task.run(partial(self._send_midi, msg))) - # sequence_to_run.append(Task.wait(delay)) - - # for subsequence in split_list(sequence_to_run, 40): - # self._tasks.add(Task.sequence(*subsequence)) - - # self._messages_to_send = [] - - - # def _setup_hardware(self): - # self._init_color_sequence() - # self._setup_control_buttons_and_encoders() - # self._setup_buttons_and_encoders() - - # # set pad velocity to 0 (e.g. linear) on startup - # self._send_midi(self.QS.set_B_velocity(0)) - # # set encoder acceleration to "slow" on startup - # self._send_midi(self.QS.set_E_acceleration(0)) - def _setup_control_buttons_and_encoders(self): """ this function is only called once when the BeatStep is plugged in to @@ -349,8 +213,11 @@ def _set_control_mode_msgs(self): def _do_activate_control_mode(self): - self.log_message('activating') + + + self._set_control_mode_msgs() + self.log_message('activating ' + str(len(self._messages_to_send))) self._setup_hardware() # with self.component_guard(): From 5d07e4d81a0d4d368c2f0dc4bda1d7e4356095ae Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 1 Jun 2021 20:42:11 +0200 Subject: [PATCH 08/10] - increase initial delay - decrease individual messages delay - make sure messages are consumed on deactivate --- BeatStep_Q.py | 67 ++++++--------------------------------------------- 1 file changed, 8 insertions(+), 59 deletions(-) diff --git a/BeatStep_Q.py b/BeatStep_Q.py index 3962f47..d50c3e7 100644 --- a/BeatStep_Q.py +++ b/BeatStep_Q.py @@ -29,8 +29,8 @@ # the used memory-slot to store the configurations MEMORY_SLOT = 8 -SETUP_HARDWARE_DELAY = 2.2 -INDIVIDUAL_MESSAGE_DELAY = 0.01 +SETUP_HARDWARE_DELAY = 8 +INDIVIDUAL_MESSAGE_DELAY = 0.001 def split_list(l, size): for i in range(0, len(l), size): @@ -65,7 +65,7 @@ def port_settings_changed(self): #super(BeatStep_Q, self).port_settings_changed() # self._start_hardware_setup() self._set_init_color_sequence() - self._setup_hardware(delay=1, start_delay=SETUP_HARDWARE_DELAY) + self._setup_hardware(delay=.5, start_delay=SETUP_HARDWARE_DELAY) self._collect_setup_messages() self._setup_hardware(start_delay=SETUP_HARDWARE_DELAY) @@ -101,24 +101,9 @@ def _set_init_color_sequence(self): bmsgs = [self.QS.set_B_color(i, 16) for i in range(1, 17)] mmsgs = [self.QS.set_B_color(i, 17) for i in range(1, 17)] - - for msg in offmsgs + rmsgs + bmsgs + rmsgs[::-1] + offmsgs: + for msg in offmsgs + rmsgs + bmsgs + mmsgs + offmsgs: self._messages_to_send.append(msg) - - - - - - def _B_color_callback(self, b, c): - # do this to ensure callback-name closure - def f(): - self._send_midi(self.QS.set_B_color(b, c)) - - return f - - - def _setup_control_buttons_and_encoders(self): """ this function is only called once when the BeatStep is plugged in to @@ -187,7 +172,6 @@ def _setup_buttons_and_encoders(self): self._messages_to_send.append(self.QS.set_E_cc(i, ENCODER_MSG_IDS[i - 1])) - def _set_control_mode_msgs(self): # for all buttons @@ -210,53 +194,18 @@ def _set_control_mode_msgs(self): self._messages_to_send.append(self.QS.set_E_behaviour("transpose", 2)) - - def _do_activate_control_mode(self): - - - self._set_control_mode_msgs() self.log_message('activating ' + str(len(self._messages_to_send))) self._setup_hardware() - # with self.component_guard(): - # self._setup_layer_task = self._tasks.add( - # Task.sequence( - # Task.run(self._set_control_mode_msgs), - # Task.wait(INDIVIDUAL_MESSAGE_DELAY), - # Task.run(partial(self._setup_hardware)) - # )) - - # self._setup_layer_task.kill() - # self._setup_layer_task.restart() - - - - # # for all buttons - # for i in range(1, 17): - # # set pad to cc-mode - # self._send_midi(self.QS.set_B_mode(i, 8)) - # # set pad channel - # self._send_midi(self.QS.set_B_channel(i, CHANNEL)) - # # set pad behaviour to toggle - # self._send_midi(self.QS.set_B_behaviour(i, 1)) - - # # set encoder channel - # self._send_midi(self.QS.set_E_channel(i, CHANNEL)) - # # set all encoders to relative-mode 2 - # self._send_midi(self.QS.set_E_behaviour(i, 2)) - - # # set transpose encoder channel to follow global channel - # self._send_midi(self.QS.set_E_channel("transpose", CHANNEL)) - # # set transpose encoder to relative mode 2 - # self._send_midi(self.QS.set_E_behaviour("transpose", 2)) def _deactivate_control_mode(self): + # make sure all scheduled messages have resolved + self._process_remaining_scheduled_messages() + self._messages_to_send = [] + # recall state before layer was activated self._send_midi(self.QS.recall_preset(MEMORY_SLOT)) - # make sure that buttons relevant for control-features - # are correctly set - # self._setup_control_buttons_and_encoders() # set pad velocity self._send_midi(self.QS.set_B_velocity(self._control_component._pad_velocity)) From 6233a468c71c523ceb34000827c501e8c8f14092 Mon Sep 17 00:00:00 2001 From: Raphael Date: Wed, 2 Jun 2021 00:30:50 +0200 Subject: [PATCH 09/10] fix quick layer deactivation - causes "Error when executing task" on quick layer changes --- BeatStep_Q.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/BeatStep_Q.py b/BeatStep_Q.py index d50c3e7..a5e19d3 100644 --- a/BeatStep_Q.py +++ b/BeatStep_Q.py @@ -201,9 +201,6 @@ def _do_activate_control_mode(self): def _deactivate_control_mode(self): - # make sure all scheduled messages have resolved - self._process_remaining_scheduled_messages() - self._messages_to_send = [] # recall state before layer was activated self._send_midi(self.QS.recall_preset(MEMORY_SLOT)) From fb6f20716a5c1c51c0074238f029f45d9de16265 Mon Sep 17 00:00:00 2001 From: Raphael Date: Wed, 2 Jun 2021 00:32:39 +0200 Subject: [PATCH 10/10] remove log-message --- BeatStep_Q.py | 1 - 1 file changed, 1 deletion(-) diff --git a/BeatStep_Q.py b/BeatStep_Q.py index a5e19d3..42b67d0 100644 --- a/BeatStep_Q.py +++ b/BeatStep_Q.py @@ -196,7 +196,6 @@ def _set_control_mode_msgs(self): def _do_activate_control_mode(self): self._set_control_mode_msgs() - self.log_message('activating ' + str(len(self._messages_to_send))) self._setup_hardware()