コード例 #1
0
class MaschineTransport(TransportComponent):
    """
    this override changes the following from the default behavious:
        - reverses the stop button color behaviour
        - reverses tap_tempo_button lighting behaviour
    """
    # ? consider adding follow_song + observer

    tap_tempo_button = ButtonControl(color='DefaultButton.Off', pressed_color='DefaultButton.On')

    def __init__(self, *a, **k):
        super(MaschineTransport, self).__init__(*a, **k)

    def _update_stop_button_color(self):
        self.stop_button.color = 'DefaultButton.Off' if self.song.is_playing else 'DefaultButton.On'

    @tap_tempo_button.pressed
    def tap_tempo_button(self, _):
        if not self._end_undo_step_task.is_running:
            self.song.begin_undo_step()
        self._end_undo_step_task.restart()
        self.song.tap_tempo()

    def set_tap_tempo_button(self, button):
        self.tap_tempo_button.set_control_element(button)
コード例 #2
0
class MaschineScrollComponent(Component):
    __module__ = __name__
    __events__ = (u'scroll', )
    button = ButtonControl(color='TrackNavigation.TrackNotSelected', repeat=True)

    @button.pressed
    def button(self, button):
        self.notify_scroll()
コード例 #3
0
class MaschineDeviceOrganizer(Component):

    move_backward_button = ButtonControl(color='DefaultButton.Off')
    move_forward_button = ButtonControl(color='DefaultButton.Off')

    # todo: safe guard index range

    def __init__(self, *a, **k):
        super(MaschineDeviceOrganizer, self).__init__(*a, **k)
        self._device = None

    def set_device(self, device):
        self._device = device

    def set_move_backward_button(self, button):
        self.move_backward_button.set_control_element(button)

    def set_move_forward_button(self, button):
        self.move_forward_button.set_control_element(button)

    @move_backward_button.pressed
    def _on_move_backward_button_pressed(self, button):
        self.move_backward()

    @move_forward_button.pressed
    def _on_move_forward_button_pressed(self, button):
        self.move_forward()

    def move_backward(self):
        parent = self._device.canonical_parent
        device_index = list(parent.devices).index(self._device)
        if device_index > 0:
            self.song.move_device(self._device, parent, device_index - 1)

    def move_forward(self):
        parent = self._device.canonical_parent
        device_index = list(parent.devices).index(self._device)
        if device_index < len(parent.devices) - 1:
            self.song.move_device(self._device, parent, device_index + 2)
コード例 #4
0
class MaschineTrackSelectionEnabler(Component):
    """
    this object wraps the track selection matrix. it enable and disable the
    selection matrix so that it act like a layer of selection buttons when enabled.
    and release the matrix to go back to playable mode when disabled
    """
    # ? if in the future, if track provider will dynamically change
    # ? track provider should be observed for changes and updates

    selection_matrix_button = ButtonControl(color='DefaultButton.Off')

    @depends(info_display=None)
    def __init__(self, info_display=None, track_provider=None, *a, **k):
        assert info_display is not None
        assert track_provider is not None
        self._info_display = info_display
        super(MaschineTrackSelectionEnabler, self).__init__(*a, **k)
        self._track_provider = track_provider
        self.selection_matrix = MaschineTrackSelection(
            info_display=info_display,
            track_provider=track_provider,
            parent=self,
            name='Selection_Matrix',
            is_enabled=False)

    def set_select_buttons(self, buttons):
        self.selection_matrix.set_select_buttons(buttons)

    def set_selection_matrix_button(self, button):
        self.selection_matrix_button.set_control_element(button)

    @selection_matrix_button.pressed
    def _on_selection_matrix_button_pressed(self, button):
        self._toggle_selection_matrix()

    @selection_matrix_button.released_delayed
    def _on_selection_matrix_button_released_delated(self, button):
        self._toggle_selection_matrix()

    def set_track_provider(self, new_provider):
        if self._track_provider != new_provider:
            self._track_provider = new_provider

    def _toggle_selection_matrix(self):
        enabled = self.selection_matrix.is_enabled()
        self._set_selection_matrix_enabled(False if enabled else True)

    def _set_selection_matrix_enabled(self, enabled):
        self.selection_matrix.set_enabled(enabled)
        self.selection_matrix_button.color = 'DefaultButton.On' if enabled else 'DefaultButton.Off'
コード例 #5
0
class MaschineView(Component):

    view_button = ButtonControl(color='DefaultButton.Off',
                                pressed_color='DefaultButton.On')

    @depends(info_display=None)
    def __init__(self, info_display=None, *a, **k):
        assert info_display is not None
        self._info_display = info_display
        super(MaschineView, self).__init__(*a, **k)

    @view_button.pressed
    def _on_view_toggled(self, button):
        self.toggle_main_view()

    def toggle_main_view(self):
        view = ''
        app_view = self.application.view
        if app_view.is_view_visible('Session'):
            self.show_view('Arranger')
            view = 'arranger'
        else:
            self.show_view('Session')
            view = 'session'
        self._display_message_on_maschine(view)

    def show_view(self, view):
        assert view in VIEWS
        app_view = self.application.view
        try:
            if view == 'Detail/DeviceChain' or 'Detail/Clip':
                if not app_view.is_view_visible('Detail'):
                    app_view.show_view('Detail')
            if not app_view.is_view_visible(view):
                app_view.show_view(view)
        except RuntimeError:
            pass

    def _display_message_on_maschine(self, view):
        self._tasks.clear()
        message = 'In {} View'.format(view)
        display_task = partial(self._info_display.display_message_on_maschine,
                               message, 3)
        clear_task = partial(self._info_display.clear_display, 3)
        self._tasks.add(
            task.sequence(task.run(display_task), task.wait(1.5),
                          task.run(clear_task)))
コード例 #6
0
class MaschineTrackNavigator(Component):
    """
    long presses scroll through the track list, short presses will select the next track.
    only the latter option was available when using the track scroller directly.
    """
    track_scroller_type = BasicTrackScroller

    master_track_button = ButtonControl(color='DefaultButton.On',
                                        pressed_color='DefaultButton.Off')

    @depends(info_display=None)
    def __init__(self, info_display=None, *a, **k):
        assert info_display is not None
        self._info_display = info_display
        super(MaschineTrackNavigator, self).__init__(*a, **k)
        self._track_scroller = ScrollComponent(self.track_scroller_type(),
                                               parent=self)
        song = self.song
        view = song.view
        self.register_slot(song, self.__on_selected_track_changed,
                           'visible_tracks')
        self.register_slot(song, self.__on_selected_track_changed,
                           'return_tracks')
        self.register_slot(view, self.__on_selected_track_changed,
                           'selected_track')
        self.__on_selected_track_changed()
        self._update_master_track_button()

    @property
    def master_track(self):
        return self.song.master_track

    def set_previous_track_button(self, button):
        self._track_scroller.set_scroll_up_button(button)

    def set_next_track_button(self, button):
        self._track_scroller.set_scroll_down_button(button)

    def set_master_track_button(self, button):
        self.master_track_button.set_control_element(button)

    @master_track_button.pressed
    def _on_master_track_button_pressed(self, button):
        self.select_master_track()

    def select_master_track(self):
        selected_track = self.song.view.selected_track
        if selected_track != self.master_track:
            self.song.view.selected_track = self.master_track
        self._update_master_track_button()

    def _update_master_track_button(self):
        selected_track = self.song.view.selected_track
        self.master_track_button.color = 'DefaultButton.On' if selected_track == self.master_track else 'DefaultButton.Off'

    def __on_selected_track_changed(self):
        track = self.song.view.selected_track
        if liveobj_valid(track):
            if self.is_enabled():
                self._track_scroller.update()
        self.__on_name_changed.subject = track
        self._update_master_track_button()
        self._display_track_name(track)
        if not track.devices:
            self._info_display.clear_display(1)
            self._info_display.clear_display(3)

    @listens('name')
    def __on_name_changed(self):
        track = self.song.view.selected_track
        self._display_track_name(track)

    def _display_track_name(self, track):
        if track in self.song.visible_tracks:
            self._info_display.display_message_on_maschine(
                'Track - {} '.format(track.name), 2)
        elif track in self.song.return_tracks:
            self._info_display.display_message_on_maschine(
                'Return - {}'.format(track.name), 2)
        else:
            self._info_display.display_message_on_maschine(
                'Master Track Selected', 2)
コード例 #7
0
class MaschineNoteRepeatEnabler(Component):
    __module__ = __name__
    """
    this is a wrapper for the note repeat component. it gives a button
    to toggle the note repeat component. the wrapper takes care of
    automatically disabling the note repeat component when an audio
    track is selected (including master and return tracks)
    """

    note_repeat_button = ButtonControl(color='DefaultButton.Off')

    @depends(info_display=None)
    def __init__(self, info_display=None, note_repeat=None, *a, **k):
        assert info_display is not None
        self._info_display = info_display
        super(MaschineNoteRepeatEnabler, self).__init__(*a, **k)
        self.note_repeat_component = MaschineNoteRepeat(note_repeat=note_repeat, name='Note_Repeat', parent=self, is_enabled=False)
        self.__on_selected_track_changed.subject = self.song.view

    @listens('selected_track')
    def __on_selected_track_changed(self):
        self.note_repeat_button.enabled = not self.song.view.selected_track.has_audio_input
        self.note_repeat_component.set_enabled(False)
        self.note_repeat_button.color = 'DefaultButton.Off'

    def set_select_buttons(self, buttons):
        self.note_repeat_component.set_select_buttons(buttons)

    def set_note_repeat_button(self, button):
        self.note_repeat_button.set_control_element(button)

    def set_note_repeat(self, note_repeat):
        self.note_repeat_component.set_note_repeat(note_repeat)

    @note_repeat_button.pressed
    def _on_note_repeat_button_pressed(self, button):
        self._toggle_note_repeat()

    @note_repeat_button.released_delayed
    def _on_note_repeat_button_released_delayed(self, button):
        self._toggle_note_repeat()

    def _toggle_note_repeat(self):
        enabled = self.note_repeat_component.is_enabled()
        self._set_note_repeat_enabled(False if enabled else True)
        rate = self.note_repeat_component._get_internal_repeat_rate_index()
        self.note_repeat_component.selected_rate = rate
        self._display_message_on_maschine(enabled)

    def _display_message_on_maschine(self, enabled):
        message = 'Note Repeate is {}'.format('Off' if enabled else 'Active')
        display_task = partial(self._info_display.display_message_on_maschine, message, 3)
        clear_task = partial(self._info_display.clear_display, 3)
        self._tasks.add(task.sequence(task.run(display_task), task.wait(2.5), task.run(clear_task)))

    # ? maybe consider saving and restoring note repeat on track selection ??
    def _restore_note_repeat_enabled_state(self):
        return self._set_note_repeat_enabled(self._get_note_repeat_enabled())

    def _set_note_repeat_enabled(self, is_enabled):
        self.note_repeat_component.set_enabled(is_enabled)
        self.song.view.selected_track.set_data('maschine-note-repeat-enabled', is_enabled)
        self.note_repeat_button.color = 'DefaultButton.On' if is_enabled else 'DefaultButton.Off'

    def _get_note_repeat_enabled(self):
        return self.song.view.selected_track.get_data('maschine-note-repeat-rate', False)
コード例 #8
0
class MaschineTrackSelection(MaschineTrackListerComponent):

    previous_track_page_button = ButtonControl(color='DefaultButton.Off')
    next_track_page_button = ButtonControl(color='DefaultButton.Off')

    @depends(info_display=None)
    def __init__(self, info_display=None, track_provider=None, *a, **k):
        assert info_display is not None
        self._info_display = info_display
        self._track_list = track_provider
        super(MaschineTrackSelection, self).__init__(track_provider=self._track_list, *a, **k)
        self.register_disconnectable(self._track_list)
        self.__on_selected_track_changed.subject = self.song.view
        self.__on_selected_track_changed()
        self._update_select_buttons()

    def _color_for_button(self, button_index, is_selected):
        tracks = self.track_provider.tracks
        color = self.color_class_name
        if button_index > len(self.track_provider.tracks):
            return color + '.NoTrack'
        if len(self.song.return_tracks) > 0 and tracks[button_index + self.track_offset] in self.song.return_tracks:
            return color + '.ReturnTrackSelected' if is_selected else color + '.ReturnTrackNotSelected'
        elif tracks[button_index + self.track_offset] == self.song.master_track:
            return color + '.MasterTrackSelected' if is_selected else color + '.MasterTrackNotSelected'
        else:
            return color + '.TrackSelected' if is_selected else color + '.TrackNotSelected'

    @property
    def selected_track(self):
        return self.track_provider.selected_track

    @listens('tracks')
    def __on_tracks_changed(self):
        self._update_select_buttons()
        self._scroll_overlay.update_scroll_buttons()

    @listens('selected_track')
    def __on_selected_track_changed(self):
        current_track = self.song.view.selected_track
        self._update_track_provider(current_track)
        # self._update_track_offset()
        self.__on_name_changed.subject = self.selected_track
        self._display_track_name(self.selected_track)
        if not self.selected_track.devices:
            self._info_display.clear_display(1)
            self._info_display.clear_display(3)

    @listens('name')
    def __on_name_changed(self):
        track = self.selected_track
        self._display_track_name(track)

    @previous_track_page_button.pressed
    def _on_previous_track_page_button_pressed(self, button):
        self.select_previous_track_page()

    @next_track_page_button.pressed
    def _on_next_track_page_button_pressed(self, button):
        self.select_next_track_page()

    def can_scroll_left(self):
        return self.track_offset > 0

    def can_scroll_right(self):
        tracks = self._track_provider.tracks
        return self.track_offset < len(tracks) - self._num_visible_tracks

    def scroll_left(self):
        offset = max(0, self.track_offset - self._num_visible_tracks)
        self.track_offset = offset

    def scroll_right(self):
        offset = self.track_offset + self._num_visible_tracks
        self.track_offset = offset

    def link_selection(self):
        track = self.track_provider.tracks[self.track_offset]
        self._select_track(track)

    def select_next_track_page(self):
        if self.can_scroll_right():
            self.scroll_right()
            self.link_selection()

    def select_previous_track_page(self):
        if self.can_scroll_left():
            self.scroll_left()
            self.link_selection()

    def _select_track(self, track):
        if track and track != self.song.view.selected_track:
            self.song.view.selected_track = track
            self._update_track_provider(track)

    def _update_track_provider(self, track):
        self._track_list.selected_track = track

    # def _update_track_offset(self):
    #     # offset = self.track_offset
    #     tracks = self.track_provider.tracks
    #     index = tracks.index(self.track_provider.selected_track)
    #     new_offset = index / self._num_visible_tracks
    #     print(new_offset)
    #     self.track_offset = new_offset
    #     self._create_track_slots()

    def _display_track_name(self, track):
        if track in self.song.visible_tracks:
            self._info_display.display_message_on_maschine('Track - {} '.format(track.name), 2)
        elif track in self.song.return_tracks:
            self._info_display.display_message_on_maschine('Return - {}'.format(track.name), 2)
        else:
            self._info_display.display_message_on_maschine('Master Track Selected', 2)

    def _on_select_button_pressed(self, button):
        if button.index > len(self.track_provider.tracks):
            return
        self._select_track(self.tracks[button.index].track)
コード例 #9
0
class MaschineTrackCreation(Component):
    midi_track_button = ButtonControl(color='DefaultButton.Off', pressed_color='DefaultButton.On')
    audio_track_button = ButtonControl(color='DefaultButton.Off', pressed_color='DefaultButton.On')
    return_track_button = ButtonControl(color='DefaultButton.Off', pressed_color='DefaultButton.On')

    @depends(info_display=None)
    def __init__(self, info_display=None, *a, **k):
        assert info_display is not None
        self._info_display = info_display
        super(MaschineTrackCreation, self).__init__(*a, **k)

    @property
    def selected_track(self):
        return self.song.view.selected_track

    @property
    def master_track(self):
        return self.song.master_track

    @property
    def return_tracks(self):
        return self.song.return_tracks

    @midi_track_button.pressed
    def _on_midi_track_button_pressed(self, _):
        self._create_new_midi_track()

    @audio_track_button.pressed
    def _on_audio_track_button_pressed(self, _):
        self._create_new_audio_track()

    @return_track_button.pressed
    def _on_return_track_button_pressed(self, _):
        self._create_new_return_track()

    def _create_new_midi_track(self):
        track = self.selected_track
        master = self.master_track
        if track == master or track in list(self.return_tracks):
            self.song.create_midi_track(-1)
        else:
            self.song.create_midi_track()
        self._display_message_on_maschine('midi')

    def _create_new_audio_track(self):
        track = self.selected_track
        master = self.master_track
        if track == master or track in list(self.return_tracks):
            self.song.create_audio_track(-1)
        else:
            self.song.create_audio_track()
        self._display_message_on_maschine('audio')

    def _create_new_return_track(self):
        if len(self.song.return_tracks) < 12:
            self.song.create_return_track()
            self._display_message_on_maschine('return')
        else:
            self._info_display.clear_display(3)
            self._tasks.clear()
            message = 'Only 12 sends allowed'
            display_task = partial(self._info_display.display_message_on_maschine, message, 3)
            clear_display = partial(self._info_display.clear_display, 3)
            self._tasks.add(task.sequence(task.run(display_task), task.wait(1), task.run(clear_display)))

    def _display_message_on_maschine(self, track_type):
        self._tasks.clear()
        self._info_display.clear_display(3)
        message = 'Created New {} Track'.format(track_type)
        display_task = partial(self._info_display.display_message_on_maschine, message, 3)
        clear_display = partial(self._info_display.clear_display, 3)
        self._tasks.add(task.sequence(task.run(display_task), task.wait(1), task.run(clear_display)))
コード例 #10
0
class MaschineKeyboard(MaschinePadMixin, PlayableComponent, ScrollComponent):
    __events__ = ('scale', 'root_note')

    next_scale_button = ButtonControl(color='DefaultButton.Off',
                                      pressed_color='DefaultButton.On')
    previous_scale_button = ButtonControl(color='DefaultButton.Off',
                                          pressed_color='DefaultButton.On')
    next_key_button = ButtonControl(color='DefaultButton.Off',
                                    pressed_color='DefaultButton.On')
    previous_key_button = ButtonControl(color='DefaultButton.Off',
                                        pressed_color='DefaultButton.On')

    @depends(info_display=None)
    def __init__(self, translation_channel, info_display=None, *a, **k):
        assert info_display is not None
        self._info_display = info_display
        super(MaschineKeyboard, self).__init__(*a, **k)
        self._translation_channel = translation_channel
        self._scale = None
        self._root_note = self.song.root_note
        self._start_note = 36
        self.__on_selected_track_changed.subject = self.song.view
        self.__on_root_note_changed.subject = self.song
        self.__on_scale_name_changed.subject = self.song
        self.__on_selected_track_changed()
        self._scale = self._get_scale_from_name(self.song.scale_name)

    @next_scale_button.pressed
    def _on_next_scale_button_pressed(self, button):
        self.scroll_scales(1)

    @previous_scale_button.pressed
    def _on_previous_scale_button_pressed(self, button):
        self.scroll_scales(-1)

    @next_key_button.pressed
    def _on_next_key_button_pressed(self, button):
        self.scroll_keys(1)

    @previous_key_button.pressed
    def _on_previous_key_button_pressed(self, button):
        self.scroll_keys(-1)

    def scroll_keys(self, offset):
        index = clamp(self.root_note + offset, 0, 12)
        if index in range(12):
            self.root_note = index
            self._move_start_note(offset)
            self._display_scale_and_key_info()

    def scroll_scales(self, offset):
        if self._scale:
            scale_index = clamp(
                SCALES.index(self.scale) + offset, 0, len(SCALES))
            self.scale = SCALES[scale_index] or SCALES[0]
            self._update_note_translations()
            self._update_led_feedback()
            self._display_scale_and_key_info()

    @property
    def root_note(self):
        return self._root_note

    @root_note.setter
    def root_note(self, root_note):
        self.song.root_note = root_note
        self._root_note = root_note

    @property
    def scale(self):
        return self._scale

    @scale.setter
    def scale(self, scale):
        self._song.scale_name = scale.name
        self._scale = scale

    @listens('root_note')
    def __on_root_note_changed(self):
        self.notify_root_note(self.song.root_note)

    @listens('scale_name')
    def __on_scale_name_changed(self):
        self._scale = self._get_scale_from_name(self.song.scale_name)
        self.notify_scale(self._scale)

    @listens('selected_track')
    def __on_selected_track_changed(self):
        track = self.song.view.selected_track
        self.__on_devices_changed.subject = track
        if not self._has_instrument():
            self._turn_matarix_buttons_off()
        else:
            self._update_led_feedback()

    @listens('devices')
    def __on_devices_changed(self):
        if not self._has_instrument():
            self._turn_matarix_buttons_off()
        else:
            self._update_led_feedback()

    def _get_scale_from_name(self, name):
        return find_if(lambda scale: scale.name == name, SCALES) or SCALES[0]

    def _has_instrument(self):
        track = self.song.view.selected_track
        if track.has_midi_input and track.devices:
            for device in track.devices:
                if device.type == Live.Device.DeviceType.instrument and not device.can_have_drum_pads:
                    return True
        else:
            return False

    def _update_button_color(self, button):
        if not self._has_instrument():
            self._turn_matarix_buttons_off()
        else:
            button.color = ('Keyboard.{}').format(
                'Natural' if (button.identifier - self.root_note) %
                12 in self.scale.notes else 'Sharp')

    def _turn_matarix_buttons_off(self):
        for button in self.matrix:
            button.color = 'DefaultButton.Off'

    def can_scroll_up(self):
        return self._start_note < MAX_START_NOTE

    def can_scroll_down(self):
        return self._start_note > 0

    def scroll_up(self):
        if self.can_scroll_up():
            self._move_start_note(12)

    def scroll_down(self):
        if self.can_scroll_down():
            self._move_start_note(-12)

    def _move_start_note(self, factor):
        self._start_note += factor
        self._update_note_translations()
        self._release_all_pads()

    def _note_translation_for_button(self, button):
        row, column = button.coordinate
        inverted_row = self.matrix.height - row - 1
        return (inverted_row * self.matrix.width + column + self._start_note,
                self._translation_channel)

    def _release_all_pads(self):
        for pad in self.matrix:
            if pad.is_pressed:
                pad._release_button()

    def _display_scale_and_key_info(self):
        self._tasks.clear()
        self._info_display.clear_display(3)
        message = 'Key - {} | Scale - {}'.format(NOTE_NAMES[self.root_note],
                                                 self.scale.name)
        display_task = partial(self._info_display.display_message_on_maschine,
                               message, 3)
        clear_task = partial(self._info_display.clear_display, 3)
        self._tasks.add(
            task.sequence(task.run(display_task), task.wait(1.5),
                          task.run(clear_task)))
コード例 #11
0
class MaschineDevice(DeviceComponent):

    __events__ = (u'bank', )

    previous_bank_button = ButtonControl(color='DefaultButton.On',
                                         pressed_color='DefaultButton.Off')
    next_bank_button = ButtonControl(color='DefaultButton.On',
                                     pressed_color='DefaultButton.Off')
    bypass_device_button = ButtonControl(color='DefaultButton.Off')
    reset_parameters_button = ButtonControl(color='DefaultButton.Off')
    randomize_parameters_button = ButtonControl(color='DefaultButton.Off')

    @depends(info_display=None)
    def __init__(self, info_display=None, *a, **k):
        assert info_display is not None
        self._info_display = info_display
        self._quantized_parameters = {}
        super(MaschineDevice, self).__init__(*a, **k)
        self.__on_bank_changed.subject = self._device_bank_registry
        self.update_bank_buttons()

    @property
    def device_is_active(self):
        return self.device() and self.device().parameters[0].value != 0

    @listens('is_active')
    def __on_is_active_changed(self):
        self.update_bypass_button()
        if self.device():
            message = '{} - {}'.format(
                'Activated' if self.device_is_active else 'Bypassed',
                self.device().name)
            self._display_temprary_message_on_maschine(message, 1)

    @listens('device_bank')
    def __on_bank_changed(self, device, bank):
        if device == self.device():
            self._set_bank_index(bank)
            self.update_bank_buttons()
            self.notify_bank()
            self._display_message_on_maschine()

    def set_previous_bank_button(self, button):
        self.previous_bank_button.set_control_element(button)

    def set_next_bank_button(self, button):
        self.next_bank_button.set_control_element(button)

    def set_bypass_device_button(self, button):
        self.bypass_device_button.set_control_element(button)

    def set_reset_parameters_button(self, button):
        self.reset_parameters_button.set_control_element(button)

    def set_randomize_parameters_button(self, button):
        self.randomize_parameters_button.set_control_element(button)

    @previous_bank_button.pressed
    def _on_previous_bank_button_pressed(self, button):
        self.select_previous_bank()

    @next_bank_button.pressed
    def _on_next_bank_button_pressed(self, button):
        self.select_next_bank()

    @bypass_device_button.pressed
    def _on_bypass_device_button_pressed(self, button):
        self.toggle_device_active_state()
        self.update_bypass_button()

    @reset_parameters_button.pressed
    def _on_reset_parameters_button_pressed(self, button):
        self.reset_device_parameters()

    @randomize_parameters_button.pressed
    def _on_randomize_parameters_button_pressed(self, button):
        self.randomize_device_parameters()

    def select_previous_bank(self):
        self._scroll_banks(-1)

    def select_next_bank(self):
        self._scroll_banks(1)

    def toggle_device_active_state(self):
        if self.device():
            parameter = self.device().parameters[0]
            if parameter.is_enabled:
                self.device().parameters[
                    0].value = False if self.device_is_active else True

    def reset_device_parameters(self):
        if self.device() is None:
            return
        parameters = filter(
            lambda param: param.is_enabled and param.state == 0,
            self.device().parameters)
        for i in range(0, len(parameters)):
            p = parameters[i]
            if not p.is_quantized:
                p.value = p.default_value
            else:
                if p.name in self._quantized_parameters:
                    p.value = self._quantized_parameters[p.name]
        # self._display_temprary_message_on_maschine('Device Reset to defaults', 3)

    def randomize_device_parameters(self):
        if self.device() is None:
            return
        parameters = filter(
            lambda param: param.is_enabled and param.state == 0,
            self.device().parameters[1:])
        for p in parameters:
            if not p.is_quantized:
                value = random.random()
                scaled_value = p.min + (value * (p.max - p.min))
                if in_range(scaled_value, p.min, p.max):
                    p.value = scaled_value

    def _scroll_banks(self, offset):
        if self._bank:
            bank_index = clamp(self._bank.index + offset, 0,
                               self._bank.bank_count())
            self._device_bank_registry.set_device_bank(self.device(),
                                                       bank_index)
            self._set_bank_index(bank_index)

    def update_bypass_button(self):
        self.bypass_device_button.enabled = self.device() is not None
        self.bypass_device_button.color = 'DefaultButton.Off' if self.device_is_active else 'DefaultButton.On'

    def update_bank_buttons(self):
        self.previous_bank_button.enabled = self._bank is not None and self._bank.index > 0
        self.next_bank_button.enabled = self._bank is not None and self._bank.index + 1 < self._bank.bank_count(
        )

    def _set_device(self, device):
        super(MaschineDevice, self)._set_device(device)
        self.__on_is_active_changed.subject = device
        self.update_bank_buttons()
        self.update_bypass_button()
        if device:
            self._collect_device_quantized_parameters(device)
            self._display_message_on_maschine()

    def _collect_device_quantized_parameters(self, device):
        if not device.can_have_chains:
            parameters = device.parameters
            for parameter in parameters:
                if parameter.is_enabled and parameter.is_quantized:
                    self._quantized_parameters[
                        parameter.name] = parameter.value

    def _create_parameter_info(self, parameter, name):
        parameter_info = ParameterInfo(parameter=parameter,
                                       name=name,
                                       default_encoder_sensitivity=1.0,
                                       fine_grain_encoder_sensitivity=0.1)
        return parameter_info

    def _display_temprary_message_on_maschine(self, message, display_index):
        self._tasks.clear()
        self._info_display.clear_display(display_index)
        temp_display = partial(self._info_display.display_message_on_maschine,
                               message, display_index)
        clear_display = partial(self._info_display.clear_display,
                                display_index)
        self._tasks.add(
            task.sequence(task.run(temp_display), task.wait(2.5),
                          task.run(clear_display),
                          task.run(self._display_message_on_maschine)))

    def _display_message_on_maschine(self):
        if self.device():
            self._info_display.clear_display(1)
            message = '{} - {}'.format(self.device().name or '',
                                       self._bank.name or '')
            self._info_display.display_message_on_maschine(message, 1)
コード例 #12
0
class MaschineDeviceNavigation(DeviceNavigationComponent):
    """
    this object will observe the device chain on the selected track. it enables the users to:
        - select devices from the device chain for control
        - move devices backward and forward in the device chain
        - move devices in and out of a rack (when one exists in the device chain)
        - remove the selected device from the device chain.
    """

    # todo: paging buttons should page through by 8 and not 1
    # todo: add device resetting to default state
    # todo: may be add parameter randomizer too?

    next_device_button = ButtonControl(
        color='ItemNavigation.ItemNotSelected',
        pressed_color='ItemNavigation.ItemSelected')
    previous_device_button = ButtonControl(
        color='ItemNavigation.ItemNotSelected',
        pressed_color='ItemNavigation.ItemSelected')
    next_chain_button = ButtonControl(
        color='ItemNavigation.ItemNotSelected',
        pressed_color='ItemNavigation.ItemSelected')
    previous_chain_button = ButtonControl(
        color='ItemNavigation.ItemNotSelected',
        pressed_color='ItemNavigation.ItemSelected')
    next_page_button = ButtonControl(color='DefaultButton.Off',
                                     pressed_color='DefaultButton.On')
    previous_page_button = ButtonControl(color='DefaultButton.Off',
                                         pressed_color='DefaultButton.On')
    remove_device_button = ButtonControl(color='DefaultButton.Off',
                                         pressed_color='DefaultButton.On')
    collapse_device_button = ButtonControl(color='DefaultButton.Off')

    @depends(info_display=None)
    def __init__(self,
                 info_display=None,
                 device_component=None,
                 item_provider=None,
                 *a,
                 **k):
        assert info_display is not None
        self._info_display = info_display
        super(MaschineDeviceNavigation,
              self).__init__(device_component=device_component,
                             item_provider=item_provider,
                             *a,
                             **k)
        self.__on_appointed_device_changed.subject = self.song
        self._device_organizer = MaschineDeviceOrganizer(
            parent=self, name='Device_Organizer')

    @property
    def first_device(self):
        index = self._get_selected_device_index()
        return index == 0

    @property
    def last_device(self):
        index = self._get_selected_device_index()
        return index == len(self.item_provider.items) - 1

    @listens(u'appointed_device')
    def __on_appointed_device_changed(self):
        device = self.song.appointed_device
        self._device_organizer.set_device(device)
        self._info_display.clear_display(3)

    def set_next_device_button(self, button):
        self.next_device_button.set_control_element(button)

    def set_previous_device_button(self, button):
        self.previous_device_button.set_control_element(button)

    def set_next_chain_button(self, button):
        self.next_chain_button.set_control_element(button)

    def set_previous_chain_button(self, button):
        self.previous_chain_button.set_control_element(button)

    def set_remove_device_button(self, button):
        self.remove_device_button.set_control_element(button)

    def set_move_backward_button(self, button):
        self._device_organizer.set_move_backward_button(button)

    def set_move_forward_button(self, button):
        self._device_organizer.set_move_forward_button(button)

    def set_collapse_device_button(self, button):
        self.collapse_device_button.set_control_element(button)

    def set_next_page_button(self, button):
        self.next_page_button.set_control_element(button)

    def set_previous_page_button(self, button):
        self.previous_page_button.set_control_element(button)

    @previous_device_button.pressed
    def _on_previous_device_button_pressed(self, _):
        self.select_previous_device()

    @next_device_button.pressed
    def _on_next_device_button_pressed(self, _):
        self.select_next_device()

    @remove_device_button.pressed
    def _on_remove_device_button_pressed(self, _):
        self.remove_selected_device()

    @collapse_device_button.pressed
    def _on_collapse_device_button_pressed(self, button):
        self.toggle_device_collapsed_state()

    @next_chain_button.pressed
    def _on_next_chain_button_pressed(self, button):
        self.select_next_chain_in_rack()

    @previous_chain_button.pressed
    def _on_previous_chain_button_pressed(self, button):
        self.select_previous_chain_in_rack()

    @next_page_button.pressed
    def _on_next_page_button_pressed(self, button):
        self.select_next_device_page()

    @previous_page_button.pressed
    def _on_previous_page_button_pressed(self, button):
        self.select_previous_device_page()

    def select_next_device(self):
        index = self._get_selected_device_index()
        target_device = None
        if not self.last_device and self._is_valid_index(index):
            target_device = self.item_provider.items[index + 1][0]
            self._select_item(target_device)
            self._show_selected_item()

    def select_previous_device(self):
        index = self._get_selected_device_index()
        target_device = None
        if not self.first_device and self._is_valid_index(index):
            target_device = self.item_provider.items[index - 1][0]
            self._select_item(target_device)
            self._show_selected_item()

    def select_next_chain_in_rack(self):
        device = self.selected_item
        if device:
            rack = is_rack(device)
            target_chain = None
            if rack and not is_empty_rack(device):
                chains = list(device.chains)
                selected_chain = device.view.selected_chain
                index = clamp(
                    chains.index(selected_chain) + 1, 0,
                    len(chains) - 1)
                target_chain = chains[index]
                device.view.selected_chain = target_chain
                self._select_item(device)

    def select_previous_chain_in_rack(self):
        device = self.selected_item
        if device:
            rack = is_rack(device)
            target_chain = None
            if rack and not is_empty_rack(device):
                chains = list(device.chains)
                selected_chain = device.view.selected_chain
                index = clamp(chains.index(selected_chain) - 1, 0, len(chains))
                target_chain = chains[index]
                device.view.selected_chain = target_chain
                self._select_item(device)

    def remove_selected_device(self):
        if self.selected_item is not None:
            parent = self.selected_item.canonical_parent
            index = list(parent.devices).index(self.selected_item)
            parent.delete_device(index)
            self.update_items()

    def toggle_device_collapsed_state(self):
        device = self.selected_item
        if device:
            rack = is_rack(device)
            if rack:
                # if len(list(device.chains)) > 1:
                #     showing_chains = device.is_showing_chains
                #     device.is_showing_chains = False if showing_chains else True
                showing_devices = device.view.is_showing_chain_devices
                device.view.is_showing_chain_devices = False if showing_devices else True

            else:
                collapsed = device.view.is_collapsed
                device.view.is_collapsed = False if collapsed else True

    def _is_valid_index(self, index):
        return 0 <= index < len(self.item_provider.items)

    def _get_selected_device_index(self):
        return index_if(lambda i: i[0] == self.selected_item,
                        self.item_provider.items)

    def _color_for_button(self, button_index, is_selected):
        device = self.items[button_index].item
        if device and is_rack(device):
            return self.color_class_name + '.RackItemSelected' if is_selected else self.color_class_name + '.RackItemNotSelected'
        else:
            return self.color_class_name + '.ItemSelected' if is_selected else self.color_class_name + '.ItemNotSelected'

    def can_scroll_left(self):
        return self.item_offset > 0

    def can_scroll_right(self):
        devices = self._item_provider.items
        return self.item_offset < len(devices) - self._num_visible_items

    def scroll_left(self):
        offset = max(0, self.item_offset - self._num_visible_items)
        self.item_offset = offset

    def scroll_right(self):
        offset = self.item_offset + self._num_visible_items
        self.item_offset = offset

    def link_selection(self):
        device = self._item_provider.items[self.item_offset][0]
        self._select_item(device)

    def select_next_device_page(self):
        if self.can_scroll_right():
            self.scroll_right()
            self.link_selection()

    def select_previous_device_page(self):
        if self.can_scroll_left():
            self.scroll_left()
            self.link_selection()