def test_sanity_checks(): seq = Sequence(log_level=SequenceLogLevel.disabled) seq.done() assert seq._state == SequenceState.TERMINATED with pytest.raises(SequenceError): seq.add(wait=3) with pytest.raises(SequenceError): Sequence(log_level=SequenceLogLevel.disabled).done().done()
def test_has_callback_queue_result(): test_res = [] class Example(AbstractObject): __subject_events__ = ('test', ) def __init__(self): super(Example, self).__init__() self.listener_normal.subject = self self.listener_sequence.subject = self self.callback_called = False @defer def test(self): # noinspection PyUnresolvedReferences self.notify_test() @subject_slot("test") def listener_normal(self): pass @subject_slot("test") def listener_sequence(self): return Sequence(log_level=SequenceLogLevel.disabled).done() test_res = {"callback_called": False} # 'normal' listener obj = Example() seq = Sequence(log_level=SequenceLogLevel.disabled) seq.add(obj.test, complete_on=obj.listener_normal) seq.add(lambda: setattr(obj, "callback_called", True)) def check_called(): assert obj.callback_called seq.add(check_called) seq.done() # listener returning sequence test_res = {"callback_called": False} seq = Sequence(log_level=SequenceLogLevel.disabled) seq.add(obj.test, complete_on=obj.listener_sequence) seq.add(lambda: setattr(obj, "callback_called", True)) def check_called(): assert obj.callback_called seq.add(check_called) seq.done()
def handle_error(self): seq = Sequence(bypass_errors=True) self.errored = True self.parent.keyboardShortcutManager.focus_window("logs terminal") seq.add(wait=1) seq.add(lambda: setattr(self, "errored", False)) return seq.done()
def clear_devices(self): seq = Sequence() for _ in range(len(self.devices)): seq.add(lambda: self.delete_device(self.devices[0])) seq.add(wait=1) return seq.done()
def set_device_parameter_value(self, device_name, parameter_name, value, raise_if_not_exists=False): # type: (str, str, Any) -> None device = find_if(lambda d: d.name.lower() == device_name.lower(), self.song.current_track.all_devices) if not device: if not raise_if_not_exists: return raise Protocol0Error("Couldn't find device %s in track devices" % device_name) param = find_if(lambda d: d.name.lower() == parameter_name.lower(), device.parameters) if not param: if not raise_if_not_exists: return raise Protocol0Error("Couldn't find parameter %s in device %s" % (parameter_name, device_name)) if param.is_enabled: seq = Sequence().add(wait=1) seq.add(lambda: setattr(param, "value", value)) return seq.done()
def _added_track_init(self): seq = Sequence() seq.add(wait=1) seq.add(self.link_audio_tracks) seq.add(lambda: setattr(self, "name", self.wrapped_track.name)) return seq.done()
def __init__(self, c_instance=None, init_song=True): super(Protocol0, self).__init__(c_instance=c_instance) # noinspection PyProtectedMember Protocol0.SELF = self self._c_instance.log_message = types.MethodType( lambda s, message: None, self._c_instance) self._is_dev_booted = False with self.component_guard(): self.protocol0_song = Song(song=self.song()) self.deviceManager = DeviceManager() # needs to be here first self.songManager = SongManager() self.sessionManager = SessionManager() self.mixingManager = MixingManager() self.playTrackManager = PlayTrackManager() self.push2Manager = Push2Manager() self.trackManager = TrackManager() self.trackAutomationManager = AutomationTrackManager() self.keyboardShortcutManager = KeyBoardShortcutManager() self.midiManager = MidiManager() self.browserManager = BrowserManager() self.clyphxNavigationManager = NavAndViewActions() self.clyphxGlobalManager = GlobalActions() self.utilsManager = UtilsManager() self.actionManager = ActionManager() self.actionSetManager = ActionSetManager() self.actionTestManager = ActionTestManager() if init_song: seq = Sequence() seq.add(wait=2) seq.add(self.songManager.init_song) seq.add(self.dev_boot) seq.done() self.log_info("Protocol0 script loaded")
def create_automation_group(self, parameter): # type: (DeviceParameter) -> None """ first step, instrument track is selected """ seq = Sequence() self.parent.songManager.abstract_group_track_creation_in_progress = True if self.song.current_track.is_foldable: seq.add( lambda: setattr(self.song.current_track, "is_folded", False)) else: seq.add(self.parent.trackManager.group_track) # this cannot be parallelized seq.add( partial(self.parent.trackManager.create_audio_track, self.song.current_track.index + 1, name="%s:%s:%s" % (AUTOMATION_TRACK_NAME, parameter.device.name, parameter.name))) seq.add( partial(self.parent.trackManager.create_midi_track, self.song.current_track.index + 2, name="%s:%s:%s" % (AUTOMATION_TRACK_NAME, parameter.device.name, parameter.name))) seq.add(lambda: setattr(self.parent.songManager, "abstract_group_track_creation_in_progress", False)) seq.add(wait=1) seq.add(self.parent.songManager._tracks_listener) return seq.done()
def test_async_callback_execution_order(): test_res = [] class Example: @has_callback_queue def listener(self): seq = Sequence(log_level=SequenceLogLevel.disabled) seq.add(lambda: test_res.append(0)) seq.add(wait=1) seq.add(lambda: test_res.append(1)) return seq.done() obj = Example() seq = Sequence(log_level=SequenceLogLevel.disabled) seq.add(nop, complete_on=obj.listener, name="timeout step", check_timeout=2) seq.add(lambda: test_res.append(2)) seq.add(nop, name="after listener step") def check_res(): assert test_res == [0, 1, 2] seq.add(check_res) seq.done() obj.listener()
def focus_window(self, window_name): # type: (str) -> None seq = Sequence(bypass_errors=True) seq.add(self.parent.clyphxNavigationManager.focus_main) seq.add(partial(self._execute_python, "focus_window.py", window_name)) return seq.done()
def subject_slot_listener(self): seq = Sequence(log_level=SequenceLogLevel.disabled) self.test_res.append(self.val) seq.add(wait=3) seq.add(lambda: self.test_res.append(self.val + 1)) return seq.done()
def replace_all_notes(self, notes, cache=True): # type: (Clip, List[Note], bool) -> None self.select_all_notes() new_clip = not len(self._prev_notes) seq = Sequence() seq.add(partial(self.replace_selected_notes, notes, cache=cache)) seq.add(self.deselect_all_notes) return seq.done()
def callback_listener(self): seq = Sequence(log_level=SequenceLogLevel.disabled) self.test_res.append(self.val) seq.add(wait=1) seq.add(lambda: self.test_res.append(self.val + 1)) return seq.done()
def check_plugin_window_showable(self, device): # type: (Device) -> Optional[Sequence] seq = Sequence() seq.add(partial(self._make_device_showable, device), do_if_not=partial(self.is_plugin_window_visible, device, try_show=True)) return seq.done()
def _post_record(self): self.song.metronome = False self.midi.has_monitor_in = False seq = Sequence().add(wait=2) seq.add(lambda: setattr(self.audio.playable_clip, "warp_mode", Live. Clip.WarpMode.complex_pro)) seq.add(lambda: self.audio.playable_clip.quantize()) return seq.done()
def test_simple_timeout(): seq = Sequence(log_level=SequenceLogLevel.disabled) seq.add(nop, complete_on=lambda: False, name="timeout step", check_timeout=0) seq.add(nop, name="unreachable step") seq.done() assert seq._state == SequenceState.TERMINATED assert seq._errored
def _has_clip_listener(self): super(AutomationAudioClipSlot, self)._has_clip_listener() seq = Sequence().add(wait=1) if not self.has_clip and self.automated_midi_clip_slot and self.automated_midi_clip_slot.has_clip: seq.add(self.automated_midi_clip_slot.clip.delete) return seq.done()
def _make_device_showable(self, device): # type: (Device) -> Sequence """ handles only one level of grouping in racks. Should be enough for now """ seq = Sequence() parent_rack = self._find_parent_rack(device) if not parent_rack: [ setattr(d._view, "is_collapsed", True) for d in device.track.devices ] (x_device, y_device) = self._get_device_show_button_click_coordinates(device) seq.add(lambda: self.parent.keyboardShortcutManager.send_click( x=x_device, y=y_device), wait=1, name="click on device show button") seq.add(lambda: setattr(device._view, "is_collapsed", False), wait=1, name="uncollapse all devices") else: [ setattr(d._view, "is_collapsed", True) for d in device.track.devices if d != parent_rack ] [ setattr(d._view, "is_collapsed", True) for d in parent_rack.chains[0].devices ] (x_rack, y_rack) = self._get_rack_show_macros_button_click_coordinates( parent_rack) (x_device, y_device) = self._get_device_show_button_click_coordinates( device, parent_rack) seq.add(lambda: self.parent.keyboardShortcutManager. toggle_device_button(x=x_rack, y=y_rack, activate=False), wait=1, name="hide rack macro controls") seq.add(lambda: self.parent.keyboardShortcutManager.send_click( x=x_device, y=y_device), wait=1, name="click on device show button") seq.add(lambda: self.parent.keyboardShortcutManager. toggle_device_button(x=x_rack, y=y_rack, activate=True), wait=1, name="show rack macro controls") seq.add(lambda: [ setattr(d._view, "is_collapsed", False) for d in parent_rack.chains[0].devices ], wait=0, name="uncollapse all rack devices") # at this point the rack macro controls could still be hidden if the plugin window masks the button return seq.done()
def exclusive_activate(self): # type: () -> Sequence self.active_instance = self seq = Sequence() seq.add(partial(self.song.select_track, self.device_track)) seq.add(self.parent.keyboardShortcutManager.show_and_activate_rev2_editor, wait=3) return seq.done()
def select_track(self, selected_track): # type: (Song, AbstractTrack, bool) -> Sequence seq = Sequence() seq.add(partial(setattr, self._view, "selected_track", selected_track.base_track._track), do_if=lambda: selected_track != self.song.selected_track, complete_on=lambda: lambda: self.song.selected_track == selected_track) return seq.done()
def load_rack_device(self, rack_name, hide=False): # type: (str, bool) -> None seq = Sequence() seq.add(partial(self.load_from_user_library, None, "'%s.adg'" % rack_name), complete_on=lambda: find_if(lambda d: d.name == rack_name, self .song.selected_track.devices)) if hide: seq.add(self.parent.keyboardShortcutManager.hide_plugins, wait=1) return seq.done()
def test_do_if(): class Obj: a = 2 obj = Obj() seq = Sequence(log_level=SequenceLogLevel.disabled) seq.add(lambda: setattr(obj, "a", 3), do_if=lambda: obj.a == 0) seq.add(lambda: setattr(obj, "a", 4), do_if_not=lambda: obj.a == 0) seq.done() assert seq._state == SequenceState.TERMINATED assert obj.a == 4
def _has_clip_listener(self): super(AutomationMidiClipSlot, self)._has_clip_listener() seq = Sequence().add(wait=1) if not self.has_clip and self.automated_audio_clip_slot and self.automated_audio_clip_slot.has_clip: seq.add(self.automated_audio_clip_slot.clip.delete) elif self.has_clip and self.automated_audio_clip_slot and not self.automated_audio_clip_slot.has_clip: seq.add(self.automated_audio_clip_slot.insert_dummy_clip) seq.add(lambda: self.clip._connect(self.automated_audio_clip_slot.clip), name="connect to audio clip slot") return seq.done()
def insert_dummy_clip(self): seq = Sequence() seq.add(partial( self.song.simple_tracks[0].clip_slots[0].duplicate_clip_to, self), complete_on=self._has_clip_listener) seq.add(lambda: setattr(self.clip, "warping", 1), name="enable clip warping") seq.add(wait=1) seq.add(lambda: setattr(self.clip, "looping", 1), name="enable clip looping") return seq.done()
def send_keys(self, keys, repeat=False): # type: (str, bool) -> None seq = Sequence() seq.add(self.parent.clyphxNavigationManager.focus_main) seq.add(partial(self._execute_python, "send_keys.py", keys)) if repeat: # here trying to mitigate shortcuts not received by Live god knows why .. seq.add(wait=1) seq.add(partial(self._execute_python, "send_keys.py", keys)) return seq.done()
def show_hide(self, force_show=False): # here we are on the device track force_show = force_show or not self.activated seq = Sequence() seq.add(self.check_activated) seq.add(wait=1) if force_show: seq.add(self.parent.keyboardShortcutManager.show_plugins) else: seq.add(self.parent.keyboardShortcutManager.show_hide_plugins) return seq.done()
def set_name(): seq = Sequence() seq.add(partial(self.song.selected_track.track_name.set, base_name=name)) seq.add(self.parent.songManager._tracks_listener) # rebuild tracks # the underlying track object should have changed track = self.song.simple_tracks[self.song.selected_track.index] seq.add(wait=1) seq.add(track._added_track_init) # manual call is needed, as _added_track_listener is not going to be called if track.abstract_group_track: seq.add(track.abstract_group_track._added_track_init) # the group track could change type as well return seq.done()
def action_scroll_presets_or_samples(self, go_next): # type: (bool) -> None seq = Sequence() if self.device: seq.add(partial(self.song.select_track, self.device_track)) # note: in the case of fast scrolling on a simpler, _devices_listener is not called in time # so the following could fail but will succeed just after so we just ignore the error seq.add(partial(self.song.select_device, self.device), silent=True) seq.add(lambda: setattr(self.device._view, "is_collapsed", False)) seq.add(partial(self._scroll_presets_or_sample, go_next)) return seq.done()
def _added_track_init(self): seq = Sequence() self.is_folded = False output_routing_tracks = list(set([sub_track.output_routing_type.attached_object for sub_track in self.sub_tracks])) if len(output_routing_tracks) == 1 and output_routing_tracks[0] and output_routing_tracks[0] != self.song.master_track: self.set_output_routing_type(output_routing_tracks[0]) [sub_track.set_output_routing_type(self) for sub_track in self.sub_tracks] if len(self.devices) == 0: seq.add(partial(self.parent.browserManager.load_rack_device, "Mix Base Rack")) return seq.done()
def _added_track_init(self): """ this can be called once, when the Live track is created """ if self.group_track is None: raise Protocol0Error( "An automation track should always be grouped") seq = Sequence() seq.add(wait=1) seq.add(lambda: [self.delete_device(d) for d in self.devices]) if len(self.clips) == 0: seq.add(self._create_base_clips) return seq.done()