def __init__(self, c_instance):
     self.__c_instance = c_instance
     self.__current_track = self.song().view.selected_track
     self.__current_device = self.__current_track.view.selected_device
     self.song().add_visible_tracks_listener(self.__tracks_changed)
     self.__transport_unit = Transport(self)
     self.__encoder_unit = Encoders(self, False)
     self.__pad_unit = Pads(self)
     self._device_appointer = DeviceAppointer(song=self.song(), appointed_device_setter=self._set_appointed_device)
 def __init__(self, c_instance):
     self.__c_instance = c_instance
     self.__automap_has_control = False
     self.__display_controller = DisplayController(self)
     self.__effect_controller = EffectController(self, self.__display_controller)
     self.__mixer_controller = MixerController(self, self.__display_controller)
     self.__components = [self.__effect_controller, self.__mixer_controller, self.__display_controller]
     self.__update_hardware_delay = -1
     self._device_appointer = DeviceAppointer(song=self.song(), appointed_device_setter=self._set_appointed_device)
Exemple #3
0
 def realinit(self, c_instance):
     self.c_instance = c_instance
     self.helper = FaderfoxHelper(self)
     self.param_map = ParamMap(self)
     self.mixer_controller = None
     self.device_controller = None
     self.transport_controller = None
     self.components = []
     live = u'Live 6 & 7'
     if self.is_live_5():
         live = u'Live 5'
     self.show_message(self.__name__ + u' ' + self.__version__ + u' for ' + live)
     self.is_lv1 = False
     self._device_appointer = DeviceAppointer(song=self.song(), appointed_device_setter=self._set_appointed_device)
 def __init__(self, c_instance):
     self.__c_instance = c_instance
     self.__current_track = self.song().view.selected_track
     self.__current_device = self.__current_track.view.selected_device
     self.song().add_visible_tracks_listener(self.__tracks_changed)
     self.__transport_unit = Transport(self)
     self.__encoder_unit = Encoders(self, False)
     self.__pad_unit = Pads(self)
     self._device_appointer = DeviceAppointer(song=self.song(), appointed_device_setter=self._set_appointed_device)
Exemple #5
0
 def realinit(self, c_instance):
     self.c_instance = c_instance
     self.helper = FaderfoxHelper(self)
     self.param_map = ParamMap(self)
     self.mixer_controller = None
     self.device_controller = None
     self.transport_controller = None
     self.components = []
     live = 'Live 6 & 7'
     if self.is_live_5():
         live = 'Live 5'
     self.show_message(self.__name__ + ' ' + self.__version__ + ' for ' + live)
     self.is_lv1 = False
     self._device_appointer = DeviceAppointer(song=self.song(), appointed_device_setter=self._set_appointed_device)
Exemple #6
0
    def init_locked_device(self):

        self.locked_device = LiveUtils.getSong(
        ).view.selected_track.view.selected_device
        self.lock_to_device(self.locked_device)
        self._device_appointer = None
        self._device_selection_follows_track_selection = True

        if self._device_selection_follows_track_selection == True:
            self.tA_log("devices DO follow track selection..")
        else:
            self.tA_log("devices DO NOT!!! follow track selection..")

        self.show_message("loading touchAble Pro Control Surface..")

        try:
            self._device_appointer = DeviceAppointer(
                song=LiveUtils.getSong(),
                appointed_device_setter=self._set_appointed_device)
        except:
            self.error_log("touchAble: DeviceAppointer init failed")
            pass
class RemoteSL:
    """' Automap script for the Novation Remote SL.
    TODO: Add some general comments about the mappings, FX, MX left/right side...
    """
    __module__ = __name__

    def __init__(self, c_instance):
        self.__c_instance = c_instance
        self.__automap_has_control = False
        self.__display_controller = DisplayController(self)
        self.__effect_controller = EffectController(self,
                                                    self.__display_controller)
        self.__mixer_controller = MixerController(self,
                                                  self.__display_controller)
        self.__components = [
            self.__effect_controller, self.__mixer_controller,
            self.__display_controller
        ]
        self.__update_hardware_delay = -1
        self._device_appointer = DeviceAppointer(
            song=self.song(),
            appointed_device_setter=self._set_appointed_device)

    def disconnect(self):
        u"""Called right before we get disconnected from Live
        """
        for c in self.__components:
            c.disconnect()

        self._device_appointer.disconnect()
        self.send_midi(ALL_LEDS_OFF_MESSAGE)
        self.send_midi(GOOD_BYE_SYSEX_MESSAGE)

    def application(self):
        u"""returns a reference to the application that we are running in
        """
        return Live.Application.get_application()

    def song(self):
        u"""returns a reference to the Live song instance that we do control
        """
        return self.__c_instance.song()

    def suggest_input_port(self):
        u"""Live -> Script
        Live can ask the script for an input port name to find a suitable one.
        """
        return 'RemoteSL'

    def suggest_output_port(self):
        u"""Live -> Script
        Live can ask the script for an output port name to find a suitable one.
        """
        return 'RemoteSL'

    def can_lock_to_devices(self):
        u"""Live -> Script
        Live can ask the script whether it can be locked to devices
        """
        return True

    def lock_to_device(self, device):
        u"""Live -> Script
        Live can tell the script to lock to a given device
        """
        self.__effect_controller.lock_to_device(device)

    def unlock_from_device(self, device):
        u"""Live -> Script
        Live can tell the script to unlock from a given device
        """
        self.__effect_controller.unlock_from_device(device)

    def _set_appointed_device(self, device):
        u"""Live -> Script
        Live can tell the script which device to use if it is not locked
        This is a substitute mechanism for the listeners used by older scripts
        """
        self.__effect_controller.set_appointed_device(device)

    def toggle_lock(self):
        u"""Script -> Live
        Use this function to toggle the script's lock on devices
        """
        self.__c_instance.toggle_lock()

    def suggest_map_mode(self, cc_no, channel):
        u"""Live -> Script
        Live can ask the script to suggest a map mode for the given CC
        """
        result = Live.MidiMap.MapMode.absolute
        if cc_no in fx_encoder_row_ccs:
            result = Live.MidiMap.MapMode.relative_smooth_signed_bit
        return result

    def restore_bank(self, bank):
        self.__effect_controller.restore_bank(bank)

    def supports_pad_translation(self):
        return True

    def show_message(self, message):
        self.__c_instance.show_message(message)

    def instance_identifier(self):
        return self.__c_instance.instance_identifier()

    def connect_script_instances(self, instanciated_scripts):
        u"""
        Called by the Application as soon as all scripts are initialized.
        You can connect yourself to other running scripts here, as we do it
        connect the extension modules (MackieControlXTs).
        """
        pass

    def request_rebuild_midi_map(self):
        u"""When the internal MIDI controller has changed in a way that you need to rebuild
        the MIDI mappings, request a rebuild by calling this function
        This is processed as a request, to be sure that its not too often called, because
        its time-critical.
        """
        self.__c_instance.request_rebuild_midi_map()

    def send_midi(self, midi_event_bytes):
        u"""Use this function to send MIDI events through Live to the _real_ MIDI devices
        that this script is assigned to.
        """
        if not self.__automap_has_control:
            self.__c_instance.send_midi(midi_event_bytes)

    def refresh_state(self):
        u"""Send out MIDI to completely update the attached MIDI controller.
        Will be called when requested by the user, after for example having reconnected
        the MIDI cables...
        """
        self.__update_hardware_delay = 5

    def __update_hardware(self):
        self.__automap_has_control = False
        self.send_midi(WELCOME_SYSEX_MESSAGE)
        for c in self.__components:
            c.refresh_state()

    def build_midi_map(self, midi_map_handle):
        u"""Build DeviceParameter Mappings, that are processed in Audio time, or
        forward MIDI messages explicitly to our receive_midi_functions.
        Which means that when you are not forwarding MIDI, nor mapping parameters, you will
        never get any MIDI messages at all.
        """
        if not self.__automap_has_control:
            for c in self.__components:
                c.build_midi_map(self.__c_instance.handle(), midi_map_handle)

        self.__c_instance.set_pad_translation(PAD_TRANSLATION)

    def update_display(self):
        u"""Aka on_timer. Called every 100 ms and should be used to update display relevant
        parts of the controller only...
        """
        if self.__update_hardware_delay > 0:
            self.__update_hardware_delay -= 1
            if self.__update_hardware_delay == 0:
                self.__update_hardware()
                self.__update_hardware_delay = -1
        for c in self.__components:
            c.update_display()

    def receive_midi(self, midi_bytes):
        u"""MIDI messages are only received through this function, when explicitly
        forwarded in 'build_midi_map'.
        """
        if midi_bytes[0] & 240 in (NOTE_ON_STATUS, NOTE_OFF_STATUS):
            channel = midi_bytes[0] & 15
            note = midi_bytes[1]
            velocity = midi_bytes[2]
            if note in fx_notes:
                self.__effect_controller.receive_midi_note(note, velocity)
            elif note in mx_notes:
                self.__mixer_controller.receive_midi_note(note, velocity)
            else:
                print('unknown MIDI message %s' % str(midi_bytes))
        elif midi_bytes[0] & 240 == CC_STATUS:
            channel = midi_bytes[0] & 15
            cc_no = midi_bytes[1]
            cc_value = midi_bytes[2]
            if cc_no in fx_ccs:
                self.__effect_controller.receive_midi_cc(cc_no, cc_value)
            elif cc_no in mx_ccs:
                self.__mixer_controller.receive_midi_cc(cc_no, cc_value)
            else:
                print('unknown MIDI message %s' % str(midi_bytes))
        elif midi_bytes[0] == 240:
            if len(midi_bytes) == 13 and midi_bytes[1:4] == (0, 32, 41):
                if midi_bytes[8] == ABLETON_PID and midi_bytes[10] == 1:
                    self.__automap_has_control = midi_bytes[11] == 0
                    support_mkII = midi_bytes[6] * 100 + midi_bytes[7] >= 1800
                    if not self.__automap_has_control:
                        self.send_midi(ALL_LEDS_OFF_MESSAGE)
                    for c in self.__components:
                        c.set_support_mkII(support_mkII)
                        if not self.__automap_has_control:
                            c.refresh_state()

                    self.request_rebuild_midi_map()
        else:
            print('unknown MIDI message %s' % str(midi_bytes))
Exemple #8
0
class FaderfoxScript:
    __filter_funcs__ = ['update_display', 'log', 'song']
    __module__ = __name__
    __doc__ = 'Automap script for Faderfox controllers'
    __version__ = 'V1.1'
    __name__ = 'Generic Faderfox Script'

    def __init__(self, c_instance):
        self.suffix = ''
        self.is_lv1 = False
        FaderfoxScript.realinit(self, c_instance)

    def realinit(self, c_instance):
        self.c_instance = c_instance
        self.helper = FaderfoxHelper(self)
        self.param_map = ParamMap(self)
        self.mixer_controller = None
        self.device_controller = None
        self.transport_controller = None
        self.components = []
        live = 'Live 6 & 7'
        if self.is_live_5():
            live = 'Live 5'
        self.show_message(self.__name__ + ' ' + self.__version__ + ' for ' +
                          live)
        self.is_lv1 = False
        self._device_appointer = DeviceAppointer(
            song=self.song(),
            appointed_device_setter=self._set_appointed_device)
        return

    def is_live_5(self):
        return hasattr(Live, 'is_live_5')

    def log(self, string):
        pass

    def logfmt(self, fmt, *args):
        pass

    def disconnect(self):
        for c in self.components:
            c.disconnect()

        self._device_appointer.disconnect()

    def application(self):
        return Live.Application.get_application()

    def song(self):
        return self.c_instance.song()

    def suggest_input_port(self):
        return str('')

    def suggest_output_port(self):
        return str('')

    def can_lock_to_devices(self):
        return True

    def lock_to_device(self, device):
        if self.device_controller:
            self.device_controller.lock_to_device(device)

    def unlock_to_device(self, device):
        if self.device_controller:
            self.device_controller.unlock_from_device(device)

    def _set_appointed_device(self, device):
        if self.device_controller:
            self.device_controller.set_appointed_device(device)

    def toggle_lock(self):
        self.c_instance.toggle_lock()

    def suggest_map_mode(self, cc_no, channel):
        return Live.MidiMap.MapMode.absolute

    def restore_bank(self, bank):
        pass

    def show_message(self, message):
        if hasattr(self.c_instance, 'show_message'):
            self.c_instance.show_message(message)

    def instance_identifier(self):
        return self.c_instance.instance_identifier()

    def connect_script_instances(self, instanciated_scripts):
        pass

    def request_rebuild_midi_map(self):
        self.c_instance.request_rebuild_midi_map()

    def send_midi(self, midi_event_bytes):
        self.c_instance.send_midi(midi_event_bytes)

    def refresh_state(self):
        for c in self.components:
            c.refresh_state()

    def build_midi_map(self, midi_map_handle):
        self.log('script build midi map')
        script_handle = self.c_instance.handle()
        self.param_map.remove_mappings()
        for c in self.components:
            self.log('build midi map on %s' % c)
            c.build_midi_map(script_handle, midi_map_handle)

    def update_display(self):
        for c in self.components:
            c.update_display()

    def receive_midi(self, midi_bytes):
        channel = midi_bytes[0] & CHAN_MASK
        status = midi_bytes[0] & STATUS_MASK
        if status == CC_STATUS:
            cc_no = midi_bytes[1]
            cc_value = midi_bytes[2]
            for c in self.components:
                c.receive_midi_cc(channel, cc_no, cc_value)

            self.param_map.receive_midi_cc(channel, cc_no, cc_value)
        else:
            if status == NOTEON_STATUS or status == NOTEOFF_STATUS:
                note_no = midi_bytes[1]
                note_vel = midi_bytes[2]
                for c in self.components:
                    c.receive_midi_note(channel, status, note_no, note_vel)

                self.param_map.receive_midi_note(channel, status, note_no,
                                                 note_vel)
            else:
                assert False, 'Unknown MIDI message %s' % str(midi_bytes)
Exemple #9
0
class Axiom:
    """ A controller script for the M-Audio Axiom Keyboard/Controller series """
    def __init__(self, c_instance):
        self.__c_instance = c_instance
        self.__current_track = self.song().view.selected_track
        self.__current_device = self.__current_track.view.selected_device
        self.song().add_visible_tracks_listener(self.__tracks_changed)
        self.__transport_unit = Transport(self)
        self.__encoder_unit = Encoders(self, False)
        self.__pad_unit = Pads(self)
        self._device_appointer = DeviceAppointer(
            song=self.song(),
            appointed_device_setter=self._set_appointed_device)

    def application(self):
        """returns a reference to the application that we are running in
        """
        return Live.Application.get_application()

    def song(self):
        """returns a reference to the Live song instance that we do control
        """
        return self.__c_instance.song()

    def disconnect(self):
        """Live -> Script
        Called right before we get disconnected from Live.
        """
        self.song().remove_visible_tracks_listener(self.__tracks_changed)
        self._device_appointer.disconnect()
        self.__encoder_unit.disconnect()

    def can_lock_to_devices(self):
        return True

    def suggest_input_port(self):
        """Live -> Script
        Live can ask the script for an input port name to find a suitable one.
        """
        return str(b'USB Axiom 25')

    def suggest_output_port(self):
        """Live -> Script
        Live can ask the script for an output port name to find a suitable one.
        """
        return str(b'USB Axiom 25')

    def suggest_map_mode(self, cc_no, channel):
        """Live -> Script
        Live can ask the script for a suitable mapping mode for a given CC.
        """
        suggested_map_mode = Live.MidiMap.MapMode.absolute
        if cc_no in AXIOM_ENCODERS:
            suggested_map_mode = Live.MidiMap.MapMode.relative_smooth_binary_offset
        return suggested_map_mode

    def show_message(self, message):
        self.__c_instance.show_message(message)

    def supports_pad_translation(self):
        return True

    def connect_script_instances(self, instanciated_scripts):
        """Called by the Application as soon as all scripts are initialized.
        You can connect yourself to other running scripts here, as we do it
        connect the extension modules (MackieControlXTs).
        """
        pass

    def request_rebuild_midi_map(self):
        """Script -> Live
        When the internal MIDI controller has changed in a way that you need to rebuild
        the MIDI mappings, request a rebuild by calling this function
        This is processed as a request, to be sure that its not too often called, because
        its time-critical.
        """
        self.__c_instance.request_rebuild_midi_map()

    def send_midi(self, midi_event_bytes):
        """Script -> Live
        Use this function to send MIDI events through Live to the _real_ MIDI devices
        that this script is assigned to.
        """
        self.__c_instance.send_midi(midi_event_bytes)

    def refresh_state(self):
        """Live -> Script
        Send out MIDI to completely update the attached MIDI controller.
        Will be called when requested by the user, after for example having reconnected
        the MIDI cables...
        """
        pass

    def build_midi_map(self, midi_map_handle):
        """Live -> Script
        Build DeviceParameter Mappings, that are processed in Audio time, or
        forward MIDI messages explicitly to our receive_midi_functions.
        Which means that when you are not forwarding MIDI, nor mapping parameters, you will
        never get any MIDI messages at all.
        """
        script_handle = self.__c_instance.handle()
        for channel in range(4):
            Live.MidiMap.forward_midi_cc(script_handle, midi_map_handle,
                                         channel, EXP_PEDAL_CC)

        self.__transport_unit.build_midi_map(script_handle, midi_map_handle)
        self.__encoder_unit.build_midi_map(script_handle, midi_map_handle)
        self.__pad_unit.build_midi_map(script_handle, midi_map_handle)
        self.__c_instance.set_pad_translation(PAD_TRANSLATION)

    def update_display(self):
        """Live -> Script
        Aka on_timer. Called every 100 ms and should be used to update display relevant
        parts of the controller
        """
        if self.__transport_unit:
            self.__transport_unit.refresh_state()

    def receive_midi(self, midi_bytes):
        """Live -> Script
        MIDI messages are only received through this function, when explicitly
        forwarded in 'build_midi_map'.
        """
        if midi_bytes[0] & 240 == CC_STATUS:
            channel = midi_bytes[0] & 15
            cc_no = midi_bytes[1]
            cc_value = midi_bytes[2]
            if list(AXIOM_TRANSPORT).count(cc_no) > 0:
                self.__transport_unit.receive_midi_cc(cc_no, cc_value)
            elif list(AXIOM_ENCODERS).count(cc_no) > 0:
                self.__encoder_unit.receive_midi_cc(cc_no, cc_value, channel)
            elif list(AXIOM_PADS).count(cc_no) > 0:
                self.__pad_unit.receive_midi_cc(cc_no, cc_value, channel)
            elif cc_no == EXP_PEDAL_CC:
                self.__encoder_unit.set_modifier(cc_value == 0)
                self.request_rebuild_midi_map()
        elif midi_bytes[0] == 240:
            pass

    def lock_to_device(self, device):
        self.__encoder_unit.lock_to_device(device)

    def unlock_from_device(self, device):
        self.__encoder_unit.unlock_from_device(device)

    def _set_appointed_device(self, device):
        self.__encoder_unit.set_appointed_device(device)

    def __tracks_changed(self):
        self.request_rebuild_midi_map()

    def bank_changed(self, new_bank):
        if self.__encoder_unit.set_bank(new_bank):
            self.request_rebuild_midi_map()

    def restore_bank(self, bank):
        self.__encoder_unit.restore_bank(bank)
        self.request_rebuild_midi_map()

    def instance_identifier(self):
        return self.__c_instance.instance_identifier()
class RemoteSL:
    """ Automap script for the Novation Remote SL.
    TODO: Add some general comments about the mappings, FX, MX left/right side...
    """


    def __init__(self, c_instance):
        self.__c_instance = c_instance
        self.__automap_has_control = False
        self.__display_controller = DisplayController(self)
        self.__effect_controller = EffectController(self, self.__display_controller)
        self.__mixer_controller = MixerController(self, self.__display_controller)
        self.__components = [self.__effect_controller, self.__mixer_controller, self.__display_controller]
        self.__update_hardware_delay = -1
        self._device_appointer = DeviceAppointer(song=self.song(), appointed_device_setter=self._set_appointed_device)



    def disconnect(self):
        """Called right before we get disconnected from Live
        """
        for c in self.__components:
            c.disconnect()

        self._device_appointer.disconnect()
        self.send_midi(ALL_LEDS_OFF_MESSAGE)
        self.send_midi(GOOD_BYE_SYSEX_MESSAGE)



    def application(self):
        """returns a reference to the application that we are running in
        """
        return Live.Application.get_application()



    def song(self):
        """returns a reference to the Live song instance that we do control
        """
        return self.__c_instance.song()



    def suggest_input_port(self):
        """Live -> Script
        Live can ask the script for an input port name to find a suitable one.
        """
        return 'RemoteSL'



    def suggest_output_port(self):
        """Live -> Script
        Live can ask the script for an output port name to find a suitable one.
        """
        return 'RemoteSL'



    def can_lock_to_devices(self):
        """Live -> Script
        Live can ask the script whether it can be locked to devices
        """
        return True



    def lock_to_device(self, device):
        """Live -> Script
        Live can tell the script to lock to a given device
        """
        self.__effect_controller.lock_to_device(device)



    def unlock_from_device(self, device):
        """Live -> Script
        Live can tell the script to unlock from a given device
        """
        self.__effect_controller.unlock_from_device(device)



    def _set_appointed_device(self, device):
        """Live -> Script
        Live can tell the script which device to use if it is not locked
        This is a substitute mechanism for the listeners used by older scripts
        """
        self.__effect_controller.set_appointed_device(device)



    def toggle_lock(self):
        """Script -> Live
        Use this function to toggle the script's lock on devices
        """
        self.__c_instance.toggle_lock()



    def suggest_map_mode(self, cc_no, channel):
        """Live -> Script
        Live can ask the script to suggest a map mode for the given CC
        """
        result = Live.MidiMap.MapMode.absolute
        if cc_no in fx_encoder_row_ccs:
            result = Live.MidiMap.MapMode.relative_smooth_signed_bit
        return result



    def restore_bank(self, bank):
        self.__effect_controller.restore_bank(bank)



    def supports_pad_translation(self):
        return True



    def show_message(self, message):
        self.__c_instance.show_message(message)



    def instance_identifier(self):
        return self.__c_instance.instance_identifier()



    def connect_script_instances(self, instanciated_scripts):
        """
        Called by the Application as soon as all scripts are initialized.
        You can connect yourself to other running scripts here, as we do it
        connect the extension modules (MackieControlXTs).
        """
        pass



    def request_rebuild_midi_map(self):
        """When the internal MIDI controller has changed in a way that you need to rebuild
        the MIDI mappings, request a rebuild by calling this function
        This is processed as a request, to be sure that its not too often called, because
        its time-critical.
        """
        self.__c_instance.request_rebuild_midi_map()



    def send_midi(self, midi_event_bytes):
        """Use this function to send MIDI events through Live to the _real_ MIDI devices
        that this script is assigned to.
        """
        if not self.__automap_has_control:
            self.__c_instance.send_midi(midi_event_bytes)



    def refresh_state(self):
        """Send out MIDI to completely update the attached MIDI controller.
        Will be called when requested by the user, after for example having reconnected
        the MIDI cables...
        """
        self.__update_hardware_delay = 5



    def __update_hardware(self):
        self.__automap_has_control = False
        self.send_midi(WELCOME_SYSEX_MESSAGE)
        for c in self.__components:
            c.refresh_state()




    def build_midi_map(self, midi_map_handle):
        """Build DeviceParameter Mappings, that are processed in Audio time, or
        forward MIDI messages explicitly to our receive_midi_functions.
        Which means that when you are not forwarding MIDI, nor mapping parameters, you will
        never get any MIDI messages at all.
        """
        if not self.__automap_has_control:
            for c in self.__components:
                c.build_midi_map(self.__c_instance.handle(), midi_map_handle)

        self.__c_instance.set_pad_translation(PAD_TRANSLATION)



    def update_display(self):
        """Aka on_timer. Called every 100 ms and should be used to update display relevant
        parts of the controller only...
        """
        if self.__update_hardware_delay > 0:
            self.__update_hardware_delay -= 1
            if self.__update_hardware_delay == 0:
                self.__update_hardware()
                self.__update_hardware_delay = -1
        for c in self.__components:
            c.update_display()




    def receive_midi(self, midi_bytes):
        """MIDI messages are only received through this function, when explicitly
        forwarded in 'build_midi_map'.
        """
        if midi_bytes[0] & 240 in (NOTE_ON_STATUS, NOTE_OFF_STATUS):
            channel = midi_bytes[0] & 15
            note = midi_bytes[1]
            velocity = midi_bytes[2]
            if note in fx_notes:
                self.__effect_controller.receive_midi_note(note, velocity)
            elif note in mx_notes:
                self.__mixer_controller.receive_midi_note(note, velocity)
            else:
                print 'unknown MIDI message %s' % str(midi_bytes)
        elif midi_bytes[0] & 240 == CC_STATUS:
            channel = midi_bytes[0] & 15
            cc_no = midi_bytes[1]
            cc_value = midi_bytes[2]
            if cc_no in fx_ccs:
                self.__effect_controller.receive_midi_cc(cc_no, cc_value)
            elif cc_no in mx_ccs:
                self.__mixer_controller.receive_midi_cc(cc_no, cc_value)
            else:
                print 'unknown MIDI message %s' % str(midi_bytes)
        elif midi_bytes[0] == 240:
            if len(midi_bytes) == 13 and midi_bytes[1:4] == (0, 32, 41):
                if midi_bytes[8] == ABLETON_PID and midi_bytes[10] == 1:
                    self.__automap_has_control = midi_bytes[11] == 0
                    support_mkII = midi_bytes[6] * 100 + midi_bytes[7] >= 1800
                    if not self.__automap_has_control:
                        self.send_midi(ALL_LEDS_OFF_MESSAGE)
                    for c in self.__components:
                        c.set_support_mkII(support_mkII)
                        if not self.__automap_has_control:
                            c.refresh_state()

                    self.request_rebuild_midi_map()
        else:
            print 'unknown MIDI message %s' % str(midi_bytes)
class RemoteSL(object):
    def __init__(self, c_instance):
        self._RemoteSL__c_instance = c_instance
        self._RemoteSL__automap_has_control = False
        self._RemoteSL__display_controller = DisplayController(self)
        self._RemoteSL__effect_controller = EffectController(
            self, self._RemoteSL__display_controller)
        self._RemoteSL__mixer_controller = MixerController(
            self, self._RemoteSL__display_controller)
        self._RemoteSL__components = [
            self._RemoteSL__effect_controller,
            self._RemoteSL__mixer_controller,
            self._RemoteSL__display_controller
        ]
        self._RemoteSL__update_hardware_delay = -1
        self._device_appointer = DeviceAppointer(
            song=(self.song()),
            appointed_device_setter=(self._set_appointed_device))

    def disconnect(self):
        for c in self._RemoteSL__components:
            c.disconnect()

        self._device_appointer.disconnect()
        self.send_midi(ALL_LEDS_OFF_MESSAGE)
        self.send_midi(GOOD_BYE_SYSEX_MESSAGE)

    def application(self):
        return Live.Application.get_application()

    def song(self):
        return self._RemoteSL__c_instance.song()

    def suggest_input_port(self):
        return 'RemoteSL'

    def suggest_output_port(self):
        return 'RemoteSL'

    def can_lock_to_devices(self):
        return True

    def lock_to_device(self, device):
        self._RemoteSL__effect_controller.lock_to_device(device)

    def unlock_from_device(self, device):
        self._RemoteSL__effect_controller.unlock_from_device(device)

    def _set_appointed_device(self, device):
        self._RemoteSL__effect_controller.set_appointed_device(device)

    def toggle_lock(self):
        self._RemoteSL__c_instance.toggle_lock()

    def suggest_map_mode(self, cc_no, channel):
        result = Live.MidiMap.MapMode.absolute
        if cc_no in fx_encoder_row_ccs:
            result = Live.MidiMap.MapMode.relative_smooth_signed_bit
        return result

    def restore_bank(self, bank):
        self._RemoteSL__effect_controller.restore_bank(bank)

    def supports_pad_translation(self):
        return True

    def show_message(self, message):
        self._RemoteSL__c_instance.show_message(message)

    def instance_identifier(self):
        return self._RemoteSL__c_instance.instance_identifier()

    def connect_script_instances(self, instanciated_scripts):
        pass

    def request_rebuild_midi_map(self):
        self._RemoteSL__c_instance.request_rebuild_midi_map()

    def send_midi(self, midi_event_bytes):
        if not self._RemoteSL__automap_has_control:
            self._RemoteSL__c_instance.send_midi(midi_event_bytes)

    def refresh_state(self):
        self._RemoteSL__update_hardware_delay = 5

    def __update_hardware(self):
        self._RemoteSL__automap_has_control = False
        self.send_midi(WELCOME_SYSEX_MESSAGE)
        for c in self._RemoteSL__components:
            c.refresh_state()

    def build_midi_map(self, midi_map_handle):
        if not self._RemoteSL__automap_has_control:
            for c in self._RemoteSL__components:
                c.build_midi_map(self._RemoteSL__c_instance.handle(),
                                 midi_map_handle)

        self._RemoteSL__c_instance.set_pad_translation(PAD_TRANSLATION)

    def update_display(self):
        if self._RemoteSL__update_hardware_delay > 0:
            self._RemoteSL__update_hardware_delay -= 1
            if self._RemoteSL__update_hardware_delay == 0:
                self._RemoteSL__update_hardware()
                self._RemoteSL__update_hardware_delay = -1
        for c in self._RemoteSL__components:
            c.update_display()

    def receive_midi(self, midi_bytes):
        if midi_bytes[0] & 240 in (NOTE_ON_STATUS, NOTE_OFF_STATUS):
            channel = midi_bytes[0] & 15
            note = midi_bytes[1]
            velocity = midi_bytes[2]
            if note in fx_notes:
                self._RemoteSL__effect_controller.receive_midi_note(
                    note, velocity)
            elif note in mx_notes:
                self._RemoteSL__mixer_controller.receive_midi_note(
                    note, velocity)
            else:
                print('unknown MIDI message %s' % str(midi_bytes))
        elif midi_bytes[0] & 240 == CC_STATUS:
            channel = midi_bytes[0] & 15
            cc_no = midi_bytes[1]
            cc_value = midi_bytes[2]
            if cc_no in fx_ccs:
                self._RemoteSL__effect_controller.receive_midi_cc(
                    cc_no, cc_value)
            elif cc_no in mx_ccs:
                self._RemoteSL__mixer_controller.receive_midi_cc(
                    cc_no, cc_value)
            else:
                print('unknown MIDI message %s' % str(midi_bytes))
        elif midi_bytes[0] == 240:
            if len(midi_bytes) == 13:
                if midi_bytes[1:4] == (0, 32, 41):
                    if not midi_bytes[8] == ABLETON_PID or midi_bytes[10] == 1:
                        self._RemoteSL__automap_has_control = midi_bytes[
                            11] == 0
                        support_mkII = midi_bytes[6] * 100 + midi_bytes[
                            7] >= 1800
                        if not self._RemoteSL__automap_has_control:
                            self.send_midi(ALL_LEDS_OFF_MESSAGE)
                        for c in self._RemoteSL__components:
                            c.set_support_mkII(support_mkII)
                            if not self._RemoteSL__automap_has_control:
                                c.refresh_state()

                        self.request_rebuild_midi_map()
        else:
            print('unknown MIDI message %s' % str(midi_bytes))
Exemple #12
0
class FaderfoxScript:
    __filter_funcs__ = ['update_display', 'log', 'song']
    __module__ = __name__
    __doc__ = 'Automap script for Faderfox controllers'
    __version__ = 'V1.1'
    __name__ = 'Generic Faderfox Script'

    def __init__(self, c_instance):
        self.suffix = ''
        self.is_lv1 = False
        FaderfoxScript.realinit(self, c_instance)

    def realinit(self, c_instance):
        self.c_instance = c_instance
        self.helper = FaderfoxHelper(self)
        self.param_map = ParamMap(self)
        self.mixer_controller = None
        self.device_controller = None
        self.transport_controller = None
        self.components = []
        live = 'Live 6 & 7'
        if self.is_live_5():
            live = 'Live 5'
        self.show_message(self.__name__ + ' ' + self.__version__ + ' for ' + live)
        self.is_lv1 = False
        self._device_appointer = DeviceAppointer(song=self.song(), appointed_device_setter=self._set_appointed_device)

    def is_live_5(self):
        return hasattr(Live, 'is_live_5')

    def log(self, string):
        pass

    def logfmt(self, fmt, *args):
        pass

    def disconnect(self):
        for c in self.components:
            c.disconnect()

        self._device_appointer.disconnect()

    def application(self):
        return Live.Application.get_application()

    def song(self):
        return self.c_instance.song()

    def suggest_input_port(self):
        return str('')

    def suggest_output_port(self):
        return str('')

    def can_lock_to_devices(self):
        return True

    def lock_to_device(self, device):
        if self.device_controller:
            self.device_controller.lock_to_device(device)

    def unlock_to_device(self, device):
        if self.device_controller:
            self.device_controller.unlock_from_device(device)

    def _set_appointed_device(self, device):
        if self.device_controller:
            self.device_controller.set_appointed_device(device)

    def toggle_lock(self):
        self.c_instance.toggle_lock()

    def suggest_map_mode(self, cc_no, channel):
        return Live.MidiMap.MapMode.absolute

    def restore_bank(self, bank):
        pass

    def show_message(self, message):
        if hasattr(self.c_instance, 'show_message'):
            self.c_instance.show_message(message)

    def instance_identifier(self):
        return self.c_instance.instance_identifier()

    def connect_script_instances(self, instanciated_scripts):
        pass

    def request_rebuild_midi_map(self):
        self.c_instance.request_rebuild_midi_map()

    def send_midi(self, midi_event_bytes):
        self.c_instance.send_midi(midi_event_bytes)

    def refresh_state(self):
        for c in self.components:
            c.refresh_state()

    def build_midi_map(self, midi_map_handle):
        self.log('script build midi map')
        script_handle = self.c_instance.handle()
        self.param_map.remove_mappings()
        for c in self.components:
            self.log('build midi map on %s' % c)
            c.build_midi_map(script_handle, midi_map_handle)

    def update_display(self):
        for c in self.components:
            c.update_display()

    def receive_midi(self, midi_bytes):
        channel = midi_bytes[0] & CHAN_MASK
        status = midi_bytes[0] & STATUS_MASK
        if status == CC_STATUS:
            cc_no = midi_bytes[1]
            cc_value = midi_bytes[2]
            for c in self.components:
                c.receive_midi_cc(channel, cc_no, cc_value)

            self.param_map.receive_midi_cc(channel, cc_no, cc_value)
        elif status == NOTEON_STATUS or status == NOTEOFF_STATUS:
            note_no = midi_bytes[1]
            note_vel = midi_bytes[2]
            for c in self.components:
                c.receive_midi_note(channel, status, note_no, note_vel)

            self.param_map.receive_midi_note(channel, status, note_no, note_vel)
        else:
            raise False or AssertionError('Unknown MIDI message %s' % str(midi_bytes))
class Axiom:
    """ A controller script for the M-Audio Axiom Keyboard/Controller series """

    def __init__(self, c_instance):
        self.__c_instance = c_instance
        self.__current_track = self.song().view.selected_track
        self.__current_device = self.__current_track.view.selected_device
        self.song().add_visible_tracks_listener(self.__tracks_changed)
        self.__transport_unit = Transport(self)
        self.__encoder_unit = Encoders(self, False)
        self.__pad_unit = Pads(self)
        self._device_appointer = DeviceAppointer(song=self.song(), appointed_device_setter=self._set_appointed_device)

    def application(self):
        """returns a reference to the application that we are running in
        """
        return Live.Application.get_application()

    def song(self):
        """returns a reference to the Live song instance that we do control
        """
        return self.__c_instance.song()

    def disconnect(self):
        """Live -> Script
        Called right before we get disconnected from Live.
        """
        self.song().remove_visible_tracks_listener(self.__tracks_changed)
        self._device_appointer.disconnect()
        self.__encoder_unit.disconnect()

    def can_lock_to_devices(self):
        return True

    def suggest_input_port(self):
        """Live -> Script
        Live can ask the script for an input port name to find a suitable one.
        """
        return str('USB Axiom 25')

    def suggest_output_port(self):
        """Live -> Script
        Live can ask the script for an output port name to find a suitable one.
        """
        return str('USB Axiom 25')

    def suggest_map_mode(self, cc_no, channel):
        """Live -> Script
        Live can ask the script for a suitable mapping mode for a given CC.
        """
        suggested_map_mode = Live.MidiMap.MapMode.absolute
        if cc_no in AXIOM_ENCODERS:
            suggested_map_mode = Live.MidiMap.MapMode.relative_smooth_binary_offset
        return suggested_map_mode

    def show_message(self, message):
        self.__c_instance.show_message(message)

    def supports_pad_translation(self):
        return True

    def connect_script_instances(self, instanciated_scripts):
        """Called by the Application as soon as all scripts are initialized.
        You can connect yourself to other running scripts here, as we do it
        connect the extension modules (MackieControlXTs).
        """
        pass

    def request_rebuild_midi_map(self):
        """Script -> Live
        When the internal MIDI controller has changed in a way that you need to rebuild
        the MIDI mappings, request a rebuild by calling this function
        This is processed as a request, to be sure that its not too often called, because
        its time-critical.
        """
        self.__c_instance.request_rebuild_midi_map()

    def send_midi(self, midi_event_bytes):
        """Script -> Live
        Use this function to send MIDI events through Live to the _real_ MIDI devices
        that this script is assigned to.
        """
        self.__c_instance.send_midi(midi_event_bytes)

    def refresh_state(self):
        """Live -> Script
        Send out MIDI to completely update the attached MIDI controller.
        Will be called when requested by the user, after for example having reconnected
        the MIDI cables...
        """
        pass

    def build_midi_map(self, midi_map_handle):
        """Live -> Script
        Build DeviceParameter Mappings, that are processed in Audio time, or
        forward MIDI messages explicitly to our receive_midi_functions.
        Which means that when you are not forwarding MIDI, nor mapping parameters, you will
        never get any MIDI messages at all.
        """
        script_handle = self.__c_instance.handle()
        for channel in range(4):
            Live.MidiMap.forward_midi_cc(script_handle, midi_map_handle, channel, EXP_PEDAL_CC)

        self.__transport_unit.build_midi_map(script_handle, midi_map_handle)
        self.__encoder_unit.build_midi_map(script_handle, midi_map_handle)
        self.__pad_unit.build_midi_map(script_handle, midi_map_handle)
        self.__c_instance.set_pad_translation(PAD_TRANSLATION)

    def update_display(self):
        """Live -> Script
        Aka on_timer. Called every 100 ms and should be used to update display relevant
        parts of the controller
        """
        if self.__transport_unit:
            self.__transport_unit.refresh_state()

    def receive_midi(self, midi_bytes):
        """Live -> Script
        MIDI messages are only received through this function, when explicitly
        forwarded in 'build_midi_map'.
        """
        if midi_bytes[0] & 240 == CC_STATUS:
            channel = midi_bytes[0] & 15
            cc_no = midi_bytes[1]
            cc_value = midi_bytes[2]
            if list(AXIOM_TRANSPORT).count(cc_no) > 0:
                self.__transport_unit.receive_midi_cc(cc_no, cc_value)
            elif list(AXIOM_ENCODERS).count(cc_no) > 0:
                self.__encoder_unit.receive_midi_cc(cc_no, cc_value, channel)
            elif list(AXIOM_PADS).count(cc_no) > 0:
                self.__pad_unit.receive_midi_cc(cc_no, cc_value, channel)
            elif cc_no == EXP_PEDAL_CC:
                self.__encoder_unit.set_modifier(cc_value == 0)
                self.request_rebuild_midi_map()
        elif midi_bytes[0] == 240:
            pass

    def lock_to_device(self, device):
        self.__encoder_unit.lock_to_device(device)

    def unlock_from_device(self, device):
        self.__encoder_unit.unlock_from_device(device)

    def _set_appointed_device(self, device):
        self.__encoder_unit.set_appointed_device(device)

    def __tracks_changed(self):
        self.request_rebuild_midi_map()

    def bank_changed(self, new_bank):
        if self.__encoder_unit.set_bank(new_bank):
            self.request_rebuild_midi_map()

    def restore_bank(self, bank):
        self.__encoder_unit.restore_bank(bank)
        self.request_rebuild_midi_map()

    def instance_identifier(self):
        return self.__c_instance.instance_identifier()
Exemple #14
0
    def _setup_custom_controls(self):
        is_momentary = True
        select_buttons = []

        encoders = []
        for track in range(8):
            select_buttons.append(
                ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL,
                              select_buttons_ccs[track]))
        show_pot_values_button = ButtonElement(is_momentary, MIDI_CC_TYPE,
                                               MIDI_CHANNEL,
                                               SHOW_POT_VALUES_BUTTON)

        for index in range(8):
            encoder_led_mode_button = ButtonElement(
                not is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL,
                encoder_led_mode_ccs[index])
            encoder_feedback = EncoderElement(MIDI_CC_TYPE, MIDI_CHANNEL,
                                              encoder_feedback_ccs[index],
                                              Live.MidiMap.MapMode.absolute)
            ringed_encoder = SLEncoder(
                MIDI_CC_TYPE, MIDI_CHANNEL, encoder_row_ccs[index],
                Live.MidiMap.MapMode.relative_smooth_signed_bit)
            ringed_encoder.add_value_listener(self._mixer.encoder_moved)
            ringed_encoder.set_ring_mode_button(encoder_led_mode_button)
            ringed_encoder.set_led_ring_feedback(encoder_feedback)
            ringed_encoder.name = 'Device_Control_' + str(index)
            encoder_led_mode_button.name = ringed_encoder.name + '_Ring_Mode_Button'
            encoders.append(ringed_encoder)
        self._encoders = encoders

        self._device = SLDevice(self._mixer, self._display)
        self._device.name = 'Device_Component'
        self._device.set_parameter_controls(tuple(encoders))
        self.set_device_component(self._device)
        self._mixer._device = self._device

        self._device_appointer = DeviceAppointer(
            song=self.song(),
            appointed_device_setter=self._set_appointed_device)

        p1_buttons = []
        p1_buttons.append(
            ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, P1_UP))
        p1_buttons.append(
            ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, P1_DOWN))

        self._encoder_modes = SLEncoderModeSelector(self._mixer, self._device,
                                                    tuple(encoders))
        self._encoder_modes.name = 'encoder_modes'
        self._encoder_modes.set_controls_to_translate(tuple(encoders))

        #==== OLD MODES
        #mute_buttons = [ ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, mute_buttons_ccs[index]) for index in range(8) ]
        #mute_mode_button = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, MUTE_MODE_BUTTON)
        #self._mute_mode = SLMuteModeSelector(mute_mode_button, tuple(mute_buttons), self._mixer)
        #solo_buttons = [ ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, solo_buttons_ccs[index]) for index in range(8) ]
        #ts_buttons = [ ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, ts_ccs[index]) for index in range(6) ]
        #solo_mode_button = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, SOLO_MODE_BUTTON)
        #ts_lock_button = ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, TS_LOCK)
        #self._transport = SLTransport(self, self._display)
        #self._transport.name = 'Transport'
        #self._transport_mode = SLTransportModeSelector(ts_lock_button, tuple(ts_buttons), solo_mode_button, solo_buttons, self._transport, self._mixer)
        #==== NEW MODES
        mx_first_buttons = [
            ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL,
                          mute_buttons_ccs[index]) for index in range(8)
        ]
        mx_first_row_select = ButtonElement(is_momentary, MIDI_CC_TYPE,
                                            MIDI_CHANNEL, MUTE_MODE_BUTTON)
        mx_second_buttons = [
            ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL,
                          solo_buttons_ccs[index]) for index in range(8)
        ]
        mx_second_row_select = ButtonElement(is_momentary, MIDI_CC_TYPE,
                                             MIDI_CHANNEL, SOLO_MODE_BUTTON)

        for index in range(6):
            self._ts_buttons.append(
                ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL,
                              ts_ccs[index]))
        ts_lock_button = SLSpecialButton(is_momentary, MIDI_CC_TYPE,
                                         MIDI_CHANNEL, TS_LOCK)
        self._transport = SLTransport(self, self._display)
        self._transport.name = 'Transport'

        self._button_modes = SLButtonModeSelector(
            self._mixer, self._session, mx_first_buttons, mx_second_buttons,
            self._transport, ts_lock_button, self._ts_buttons)
        #self._button_modes.set_mode_buttons((mx_first_row_select, mx_second_row_select))
        #self._button_modes.set_mode_toggle(mx_first_row_select)

        #--- SLSessionModeSelector TEST ---------------------
        for index in range(8):
            self._clip_launch_buttons.append(
                ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL,
                              clip_launch_buttons_ccs[index]))
        #session_modes = SLSessionModeSelector(self._session, self._mixer, self._scene_launch_button, tuple(self._clip_launch_buttons))
        #session_modes.set_mode_toggle(self._clip_launch_buttons[7])
        #session_modes.set_enabled(0)
        pots = []
        for index in range(8):
            pot = SliderElement(MIDI_CC_TYPE, MIDI_CHANNEL, pot_row_ccs[index])
            pot.add_value_listener(self._mixer.pot_moved)
            pots.append(pot)
        self._pot_modes = SLPotModeSelector(self._mixer, tuple(pots))
        self._pot_modes.set_controls_to_translate(tuple(pots))
        self._pot_modes.name = 'pot_modes'
        self._mixer._pots = tuple(pots)
        #----------------------------------------------------
        self._device_control = SLDeviceControl(self._device, self._display)

        self._shift_mode = SLShiftableSelector(
            tuple(select_buttons), show_pot_values_button, tuple(p1_buttons),
            self._scene_up_button, self._scene_down_button,
            self._scene_launch_button, self._session, self._mixer,
            self._encoder_modes, self._device, self._device_control,
            tuple(self._clip_launch_buttons), self._pot_modes)
        self._shift_mode.name = 'Shift_Modes'
        self._shift_mode.set_mode_toggle(self._shift_button)

        sliders = []
        for track in range(8):
            slider = SliderElement(MIDI_CC_TYPE, MIDI_CHANNEL,
                                   slider_row_ccs[track])
            slider.add_value_listener(self._mixer.slider_moved)
            sliders.append(slider)
            sliders[-1].name = str(track) + '_Volume_Control'

        mx_slider_row_select = ButtonElement(is_momentary, MIDI_CC_TYPE,
                                             MIDI_CHANNEL, SLIDER_MODE_BUTTON)
        self.master_mode = SLMasterModeSelector(self._mixer, self._session,
                                                tuple(sliders),
                                                self._button_modes,
                                                self._shift_mode,
                                                self._encoder_modes,
                                                self._pot_modes)
        self.master_mode.set_controls_to_translate(tuple(sliders))
        self.master_mode.name = 'Master_Mode'

        self._right_shift = SLRightShiftSelector(
            self._mixer, self._session, self._transport, self.master_mode,
            mx_slider_row_select, self._button_modes, mx_first_row_select)
        self._right_shift.name = 'Right_Shift_Mode'
        self._right_shift.set_mode_toggle(mx_second_row_select)
        self._transport.set_shift_button(mx_second_row_select)
        self._session.set_shift_button(mx_second_row_select)
        self._session.set_track_bank_buttons(
            ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, P2_UP),
            ButtonElement(is_momentary, MIDI_CC_TYPE, MIDI_CHANNEL, P2_DOWN))
        for index in range(8):
            strip = self._mixer.channel_strip(index)
            strip.set_shift_button(mx_second_row_select)
Exemple #15
0
class Axiom(object):
    def __init__(self, c_instance):
        self._Axiom__c_instance = c_instance
        self._Axiom__current_track = self.song().view.selected_track
        self._Axiom__current_device = self._Axiom__current_track.view.selected_device
        self.song().add_visible_tracks_listener(self._Axiom__tracks_changed)
        self._Axiom__transport_unit = Transport(self)
        self._Axiom__encoder_unit = Encoders(self, True)
        self._Axiom__slider_unit = SliderSection(self)
        self._Axiom__pad_unit = Pads(self)
        self._device_appointer = DeviceAppointer(
            song=(self.song()),
            appointed_device_setter=(self._set_appointed_device))

    def application(self):
        return Live.Application.get_application()

    def song(self):
        return self._Axiom__c_instance.song()

    def disconnect(self):
        self.song().remove_visible_tracks_listener(self._Axiom__tracks_changed)
        self._device_appointer.disconnect()
        self._Axiom__encoder_unit.disconnect()

    def can_lock_to_devices(self):
        return True

    def suggest_input_port(self):
        return str('USB Axiom')

    def suggest_output_port(self):
        return str('USB Axiom')

    def suggest_map_mode(self, cc_no, channel):
        suggested_map_mode = Live.MidiMap.MapMode.absolute
        if cc_no in AXIOM_ENCODERS:
            suggested_map_mode = Live.MidiMap.MapMode.relative_smooth_binary_offset
        return suggested_map_mode

    def show_message(self, message):
        self._Axiom__c_instance.show_message(message)

    def supports_pad_translation(self):
        return True

    def connect_script_instances(self, instanciated_scripts):
        pass

    def request_rebuild_midi_map(self):
        self._Axiom__c_instance.request_rebuild_midi_map()

    def send_midi(self, midi_event_bytes):
        self._Axiom__c_instance.send_midi(midi_event_bytes)

    def refresh_state(self):
        pass

    def build_midi_map(self, midi_map_handle):
        script_handle = self._Axiom__c_instance.handle()
        self._Axiom__transport_unit.build_midi_map(script_handle,
                                                   midi_map_handle)
        self._Axiom__encoder_unit.build_midi_map(script_handle,
                                                 midi_map_handle)
        self._Axiom__slider_unit.build_midi_map(script_handle, midi_map_handle)
        self._Axiom__pad_unit.build_midi_map(script_handle, midi_map_handle)
        self._Axiom__c_instance.set_pad_translation(PAD_TRANSLATION)

    def update_display(self):
        if self._Axiom__transport_unit:
            self._Axiom__transport_unit.refresh_state()

    def receive_midi(self, midi_bytes):
        if midi_bytes[0] & 240 == CC_STATUS:
            channel = midi_bytes[0] & 15
            cc_no = midi_bytes[1]
            cc_value = midi_bytes[2]
            if list(AXIOM_TRANSPORT).count(cc_no) > 0:
                self._Axiom__transport_unit.receive_midi_cc(cc_no, cc_value)
            elif list(AXIOM_BUTTONS).count(cc_no) > 0:
                self._Axiom__slider_unit.receive_midi_cc(
                    cc_no, cc_value, channel)
            elif list(AXIOM_ENCODERS).count(cc_no) > 0:
                self._Axiom__encoder_unit.receive_midi_cc(
                    cc_no, cc_value, channel)
            elif list(AXIOM_PADS).count(cc_no) > 0:
                self._Axiom__pad_unit.receive_midi_cc(cc_no, cc_value, channel)
        elif midi_bytes[0] == 240:
            pass

    def lock_to_device(self, device):
        self._Axiom__encoder_unit.lock_to_device(device)

    def unlock_from_device(self, device):
        self._Axiom__encoder_unit.unlock_from_device(device)

    def _set_appointed_device(self, device):
        self._Axiom__encoder_unit.set_appointed_device(device)

    def __tracks_changed(self):
        self.request_rebuild_midi_map()

    def bank_changed(self, new_bank):
        if self._Axiom__encoder_unit.set_bank(new_bank):
            self.request_rebuild_midi_map()

    def restore_bank(self, bank):
        self._Axiom__encoder_unit.restore_bank(bank)
        self.request_rebuild_midi_map()

    def instance_identifier(self):
        return self._Axiom__c_instance.instance_identifier()