Exemple #1
0
 def _setup_transport_control(self):
     is_momentary = True
     transport = TransportComponent()
     transport.set_play_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, 80))
     transport.set_record_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, 81))
     transport.set_nudge_buttons(ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, 86), ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, 85))
     transport.set_loop_button(ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, 84))
     transport.set_punch_buttons(ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, 82), ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, 83))
     transport.set_tempo_control(SliderElement(MIDI_CC_TYPE, 12, 26), SliderElement(MIDI_CC_TYPE, 12, 25))
 def _setup_transport_control(self):
     is_momentary = True
     transport = TransportComponent()
     transport.set_play_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, 80))
     transport.set_record_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, 81))
     transport.set_nudge_buttons(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, 86),
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, 85))
     transport.set_loop_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, 84))
     transport.set_punch_buttons(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, 82),
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, 12, 83))
     transport.set_tempo_control(SliderElement(MIDI_CC_TYPE, 12, 26),
                                 SliderElement(MIDI_CC_TYPE, 12, 25))
 def _init_transport_component(self, transport_controls, global_channel, macro_map_mode):
     is_momentary = True
     if transport_controls:
         transport = TransportComponent()
         transport.name = 'Transport'
         #THIS IS NEW STUFF
         #if 'TEMPO' in transport_control.keys() and transport_controls['TEMPO'] in range(128):
         tempo_slider = EncoderElement(MIDI_CC_TYPE, global_channel, 1, macro_map_mode)
         tempo_slider.name = 'Tempo_Slider'
         transport.set_tempo_control(tempo_slider)
         #END NEW STUFF
         if 'STOP' in transport_controls.keys() and transport_controls['STOP'] in range(128):
             stop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, global_channel, transport_controls['STOP'])
             stop_button.name = 'Stop_Button'
             transport.set_stop_button(stop_button)
         
         if 'PLAY' in transport_controls.keys() and transport_controls['PLAY'] in range(128):
             play_button = ButtonElement(is_momentary, MIDI_CC_TYPE, global_channel, transport_controls['PLAY'])
             play_button.name = 'Play_Button'
             transport.set_play_button(play_button)
         
         if 'REC' in transport_controls.keys() and transport_controls['REC'] in range(128):
             rec_button = ButtonElement(is_momentary, MIDI_CC_TYPE, global_channel, transport_controls['REC'])
             rec_button.name = 'Record_Button'
             transport.set_record_button(rec_button)
         
         if 'LOOP' in transport_controls.keys() and transport_controls['LOOP'] in range(128):
             loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, global_channel, transport_controls['LOOP'])
             loop_button.name = 'Loop_Button'
             transport.set_loop_button(loop_button)
         
         ffwd_button = None
         rwd_button = None
         momentary_seek = 'NORELEASE' not in transport_controls.keys()
         if 'FFWD' in transport_controls.keys() and transport_controls['FFWD'] in range(128):
             ffwd_button = ButtonElement(momentary_seek, MIDI_CC_TYPE, global_channel, transport_controls['FFWD'])
             ffwd_button.name = 'FFwd_Button'
         
         if 'RWD' in transport_controls.keys() and transport_controls['RWD'] in range(128):
             rwd_button = ButtonElement(momentary_seek, MIDI_CC_TYPE, global_channel, transport_controls['RWD'])
             rwd_button.name = 'Rwd_Button'
         
         transport.set_seek_buttons(ffwd_button, rwd_button)
 def _init_transport_component(self, transport_controls, global_channel, macro_map_mode):
     is_momentary = True
     if transport_controls:
         transport = TransportComponent()
         transport.name = 'Transport'
         #THIS IS NEW STUFF
         #if 'TEMPO' in transport_control.keys() and transport_controls['TEMPO'] in range(128):
         tempo_slider = EncoderElement(MIDI_CC_TYPE, global_channel, 1, macro_map_mode)
         tempo_slider.name = 'Tempo_Slider'
         transport.set_tempo_control(tempo_slider)
         #END NEW STUFF
         if 'STOP' in transport_controls.keys() and transport_controls['STOP'] in range(128):
             stop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, global_channel, transport_controls['STOP'])
             stop_button.name = 'Stop_Button'
             transport.set_stop_button(stop_button)
         
         if 'PLAY' in transport_controls.keys() and transport_controls['PLAY'] in range(128):
             play_button = ButtonElement(is_momentary, MIDI_CC_TYPE, global_channel, transport_controls['PLAY'])
             play_button.name = 'Play_Button'
             transport.set_play_button(play_button)
         
         if 'REC' in transport_controls.keys() and transport_controls['REC'] in range(128):
             rec_button = ButtonElement(is_momentary, MIDI_CC_TYPE, global_channel, transport_controls['REC'])
             rec_button.name = 'Record_Button'
             transport.set_record_button(rec_button)
         
         if 'LOOP' in transport_controls.keys() and transport_controls['LOOP'] in range(128):
             loop_button = ButtonElement(is_momentary, MIDI_CC_TYPE, global_channel, transport_controls['LOOP'])
             loop_button.name = 'Loop_Button'
             transport.set_loop_button(loop_button)
         
         ffwd_button = None
         rwd_button = None
         momentary_seek = 'NORELEASE' not in transport_controls.keys()
         if 'FFWD' in transport_controls.keys() and transport_controls['FFWD'] in range(128):
             ffwd_button = ButtonElement(momentary_seek, MIDI_CC_TYPE, global_channel, transport_controls['FFWD'])
             ffwd_button.name = 'FFwd_Button'
         
         if 'RWD' in transport_controls.keys() and transport_controls['RWD'] in range(128):
             rwd_button = ButtonElement(momentary_seek, MIDI_CC_TYPE, global_channel, transport_controls['RWD'])
             rwd_button.name = 'Rwd_Button'
         
         transport.set_seek_buttons(ffwd_button, rwd_button)
Exemple #5
0
    def _setup_mixer_control(self):
        num_tracks = GRIDSIZE[0] # Here we define the mixer width in tracks (a mixer has only one dimension)
        global mixer # We want to instantiate the global mixer as a MixerComponent object (it was a global "None" type up until now...)
        mixer = MixerComponent(num_tracks) #(num_tracks, num_returns, with_eqs, with_filters)
        mixer.set_track_offset(0) #Sets start point for mixer strip (offset from left)
        """set up the mixer buttons"""
        self.song().view.selected_track = mixer.channel_strip(0)._track
        master = mixer.master_strip()
        master.set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL_USER, MASTER_VOLUME))
        mixer.set_prehear_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL_USER, PREHEAR))

        for index in xrange(GRIDSIZE[0]):
            mixer.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, MIX_FADERS[index]))
            # mixer.channel_strip(index).set_volume_control(SliderElement(MIDI_CC_TYPE, CHANNEL_INST, MIX_FADERS[index]))
            mixer.channel_strip(index).set_pan_control(SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, PAN_CONTROLS[index]))
            mixer.channel_strip(index).set_arm_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL_INST, ARM_BUTTONS[index])) #sets the record arm button
            mixer.channel_strip(index).set_solo_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL_INST, SOLO_BUTTONS[index]))
            mixer.channel_strip(index).set_mute_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL_INST, MUTE_BUTTONS[index]))
            mixer.channel_strip(index).set_select_button(ButtonElement(True, MIDI_CC_TYPE, CHANNEL_INST, TRACK_SELECTS[index]))
            mixer.channel_strip(index).set_send_controls([SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, SEND_CONTROLS[index][0]),
                                                              SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, SEND_CONTROLS[index][1]),
                                                              SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, SEND_CONTROLS[index][2]),
                                                              SliderElement(MIDI_CC_TYPE, CHANNEL_MIXER, SEND_CONTROLS[index][3])])




        """TRANSPORT CONTROLS"""
        stop_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL_MIXER, STOP_BUTTON)
        play_button = ButtonElement(False, MIDI_CC_TYPE, CHANNEL_MIXER, PLAY_BUTTON)
        record_button = ButtonElement(False,MIDI_CC_TYPE,CHANNEL_MIXER,RECORD_BUTTON)
        overdub_button = ButtonElement(False,MIDI_CC_TYPE,CHANNEL_MIXER,OVERDUB_BUTTON)
        transport = TransportComponent()
        transport.TEMPO_TOP = 188
        transport.set_stop_button(stop_button)
        transport.set_play_button(play_button)
        transport.set_overdub_button(overdub_button)
        transport.set_record_button(record_button)
        transport.set_seek_buttons(ButtonElement(False,MIDI_CC_TYPE,0,SEEK_LEFT),ButtonElement(False,MIDI_CC_TYPE,0,SEEK_RIGHT))
        transport.set_tempo_control(SliderElement(MIDI_CC_TYPE, CHANNEL_USER, TEMPO))
        transport.set_metronome_button(ButtonElement(False,MIDI_CC_TYPE,CHANNEL_USER, METRONOME))
        transport.set_tap_tempo_button(ButtonElement(False,MIDI_CC_TYPE,CHANNEL_USER,TAP_TEMPO))
Exemple #6
0
 def _setup_transport_control(self):
     is_momentary = True  # We'll only be using momentary buttons here
     transport = TransportComponent()  #Instantiate a Transport Component
     return
     """set up the buttons"""
     transport.set_play_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 61)
     )  #ButtonElement(is_momentary, msg_type, channel, identifier) Note that the MIDI_NOTE_TYPE constant is defined in the InputControlElement module
     transport.set_stop_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 63))
     transport.set_record_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 66))
     transport.set_overdub_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 68))
     transport.set_nudge_buttons(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 75),
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                       73))  #(up_button, down_button)
     transport.set_tap_tempo_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 78))
     transport.set_metronome_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 80)
     )  #For some reason, in Ver 7.x.x this method's name has no trailing "e" , and must be called as "set_metronom_button()"...
     transport.set_loop_button(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 82))
     transport.set_punch_buttons(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 85),
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                       87))  #(in_button, out_button)
     transport.set_seek_buttons(
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 90),
         ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                       92))  # (ffwd_button, rwd_button)
     """set up the sliders"""
     transport.set_tempo_control(
         SliderElement(MIDI_CC_TYPE, CHANNEL, 26),
         SliderElement(MIDI_CC_TYPE, CHANNEL, 25))  #(control, fine_control)
     transport.set_song_position_control(
         SliderElement(MIDI_CC_TYPE, CHANNEL, 24))
Exemple #7
0
class ProjectX(ControlSurface):
    __module__ = __name__
    __doc__ = " ProjectX keyboard controller script "

    def __init__(self, c_instance):
        """everything except the '_on_selected_track_changed' override and 'disconnect' runs from here"""
        ControlSurface.__init__(self, c_instance)

        self.log_message(
            time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) +
            "--------------= ProjectX log opened =--------------")

        with self.component_guard():
            self._create_transport_control()
            self._create_mixer_control()
            self._create_session_control()

        self.request_rebuild_midi_map()
        self.log_message("Captain's last log stardate ****")

    def _create_transport_control(self):
        is_momentary = True

        self._transport = TransportComponent(is_enabled=True, name='Transport')
        """set up the buttons"""
        self._transport.set_play_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 61))
        self._transport.set_stop_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 63))
        self._transport.set_record_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 66))
        self._transport.set_overdub_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 68))
        self._transport.set_nudge_buttons(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 75),
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 73))
        self._transport.set_tap_tempo_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 78))
        self._transport.set_metronome_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 80))
        self._transport.set_loop_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 82))
        self._transport.set_punch_buttons(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 85),
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 87))
        self._transport.set_seek_buttons(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 90),
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 92))
        """set up the sliders"""
        self._transport.set_tempo_control(
            SliderElement(MIDI_CC_TYPE, CHANNEL, 26),
            SliderElement(MIDI_CC_TYPE, CHANNEL, 25))
        self._transport.set_song_position_control(
            SliderElement(MIDI_CC_TYPE, CHANNEL, 24))

        self.log_message("Captain's log stardate 1")

    def _create_mixer_control(self):
        is_momentary = True
        num_tracks = 7
        """Here we set up the global mixer"""
        global mixer
        mixer = MixerComponent(name='Mixer',
                               num_tracks=num_tracks,
                               is_enabled=False,
                               num_returns=2)
        mixer.set_enabled(True)
        mixer.set_track_offset(0)
        self.song().view.selected_track = mixer.channel_strip(0)._track
        mixer.channel_strip(0)
        """set up the mixer buttons"""
        mixer.set_select_buttons(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 56),
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 54))
        mixer.master_strip().set_select_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 94))
        mixer.selected_strip().set_mute_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 42))
        mixer.selected_strip().set_solo_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 44))
        mixer.selected_strip().set_arm_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 46))
        """set up the mixer sliders"""
        mixer.selected_strip().set_volume_control(
            SliderElement(MIDI_CC_TYPE, CHANNEL, 14))
        """note that we have split the mixer functions across two scripts, in order to have two session highlight 
        boxes (one red, one yellow), so there are a few things which we are not doing here... """

        self.log_message("Captain's log stardate 2")

    def _create_session_control(self):
        is_momentary = True
        num_tracks = 1
        num_scenes = 7
        global session
        session = SessionComponent(num_tracks, num_scenes)
        session.set_offsets(0, 0)
        """set up the session navigation buttons"""
        session.set_select_buttons(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 25),
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 27))
        session.set_scene_bank_buttons(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 51),
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 49))
        session.set_stop_all_clips_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 70))
        session.selected_scene().set_launch_button(
            ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL, 30))
        """Here we set up the scene launch assignments for the session"""
        launch_notes = [60, 62, 64, 65, 67, 69, 71]
        for index in range(num_scenes):
            session.scene(index).set_launch_button(
                ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                              launch_notes[index]))
        """Here we set up the track stop launch assignment(s) for the session"""
        stop_track_buttons = []
        for index in range(num_tracks):
            stop_track_buttons.append(
                ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                              58 + index))
        session.set_stop_track_clip_buttons(tuple(stop_track_buttons))
        """Here we set up the clip launch assignments for the session"""
        clip_launch_notes = [48, 50, 52, 53, 55, 57, 59]
        for index in range(num_scenes):
            session.scene(index).clip_slot(0).set_launch_button(
                ButtonElement(is_momentary, MIDI_NOTE_TYPE, CHANNEL,
                              clip_launch_notes[index]))
        """Here we set up a mixer and channel strip(s) which move with the session"""

        self.log_message("Captain's log stardate 3")

    def _on_selected_track_changed(self):
        """This is an override, to add special functionality (we want to move the session to the selected track,
        when it changes) Note that it is sometimes necessary to reload Live (not just the script) when making changes
        to this function"""
        ControlSurface._on_selected_track_changed(self)
        """here we set the mixer and session to the selected track, when the selected track changes"""
        selected_track = self.song().view.selected_track
        mixer.channel_strip(0).set_track(selected_track)
        all_tracks = ((self.song().tracks + self.song().return_tracks) +
                      (self.song().master_track, ))
        index = list(all_tracks).index(selected_track)
        session.set_offsets(index, session._scene_offset)

    def disconnect(self):
        """clean things up on disconnect"""
        self.log_message(
            time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()) +
            "--------------= ProjectX log closed =--------------")
        ControlSurface.disconnect(self)
        return None
class VoidMaschine(ControlSurface):
  """
  Originally Created on Nov 7, 2010  :: Matt Howell
  Thanks to Hanz Petrov, Native Instruments, Ableton, Liine
  """
  

      
  def __init__(self, c_instance):
    """
    Constructor
    """
    ControlSurface.__init__(self, c_instance)
    self.name = 'VoidMaschine'
    self.log_message(self.name + " opened =-- @ "+ time.strftime("%d.%m.%Y %H:%M:%S", time.localtime()))
    self.set_suppress_rebuild_requests(True)
    self._suppress_session_highlight = False
    self._suppress_send_midi = True
    self._suggested_input_port = MASCHINE_DEVICE_PORT_NAME
    self._suggested_output_port = MASCHINE_DEVICE_PORT_NAME
    self._shift_button = None
    self.transport = TransportComponent()
    self.transport.name = 'Transport'
    self.session = None
    self.session_zoom = None
    self.mixer = None
    self.back_to_arranger_button = None
    self.is_momentary = True
    self.bpmBeatTime = 0
    self.lastBeat = 0
    
    self._setup_transport_control()
    self._session = VoidSessionComponent(c_instance)
    self._session.name = 'Session_Control'
    
    self._setup_mixer_control()
    
    #self._session_zoom = SessionZoomingComponent(self._session)
    #self._session_zoom.name = 'Session_Overview'
    #self._session_zoom.set_button_matrix(self._session._matrix)
    
    self._set_back_to_arranger_button(ButtonElement(True, MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_BACK_TO_ARRANGER))
    self.set_suppress_rebuild_requests(False)
    self._display = PhysicalDisplayElement(56, 8)
    self._void_message()
    self._register_timer_callback(self.update_controller)
    self._register_timer_callback(self.updateTempo)
    self._register_timer_callback(self.onTempoChange)
    
  def _void_message(self):
    self.sendScreenSysex(self.translateString((SYSEX_SCREEN_BUFFER_15 + 'VoidMaschine' + SYSEX_SCREEN_BUFFER_15)), 1)
    self.sendScreenSysex(self.translateString(('Voidrunner.com' + SYSEX_SCREEN_BUFFER_15 + '    maschine/ableton')), 2)

  def _setup_mixer_control(self):
    self.mixer = MixerComponent(0, 0, with_eqs=False, with_filters=False)
    master_volume_control = EncoderElement(MIDI_CC_TYPE, MIXER_CHANNEL, MASTER_VOLUME, Live.MidiMap.MapMode.absolute)
    booth_volume_control = EncoderElement(MIDI_CC_TYPE, MIXER_CHANNEL, MASTER_BOOTH, Live.MidiMap.MapMode.absolute)
    self.mixer.set_prehear_volume_control(booth_volume_control)
    self.mixer.master_strip().set_volume_control(master_volume_control)

  def _setup_transport_control(self):
    play_button = ButtonElement(self.is_momentary, MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_PLAY)
    stop_button = ButtonElement(self.is_momentary, MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_STOP)
    record_button = ButtonElement(self.is_momentary, MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_RECORD)
    seek_ffwd_button = ButtonElement(self.is_momentary, MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_SEEK_FFWD)
    seek_rwd_button = ButtonElement(self.is_momentary, MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_SEEK_RWD)
    tap_tempo_button = ButtonElement(self.is_momentary, MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_TAP_TEMPO)
    tempo_control = EncoderElement(MIDI_CC_TYPE, TRANSPORT_CHANNEL, TRANSPORT_COARSE_TEMPO, Live.MidiMap.MapMode.absolute)
    play_button.name = 'Play_Button'
    stop_button.name = 'Stop_Button'
    record_button.name = 'Record_Button'
    seek_ffwd_button.name = 'Seek_FFWD_Button'
    seek_rwd_button.name = 'Seek_RWD_Button'
    tap_tempo_button.name = 'Tap_Tempo_Button'
    self.transport.set_play_button(play_button)
    self.transport.set_stop_button(stop_button)
    self.transport.set_record_button(record_button)
    self.transport.set_tap_tempo_button(tap_tempo_button)
    self.transport.set_tempo_control(tempo_control)
    self.transport.set_seek_buttons(seek_ffwd_button, seek_rwd_button)

  def _set_back_to_arranger_button(self, button):
    button.add_value_listener(self.back_to_arranger)
    self.back_to_arranger_button = button

  def disconnect(self):
    self.send_midi((240, 0, 66, 89, 69, 247)) #goodbye message in sysex stream
  
  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.
    """
    assert isinstance(midi_event_bytes, tuple)
    self._send_midi(midi_event_bytes)
    return True

  def translateString(self, text):
    """
    Convert a string into a sysex safe string
    """
    result = ()
    length = len(text)
    for i in range(0, length):
      charCode = ord(text[i])
      if (charCode < 32):
        charCode = 32
      elif (charCode > 127):
        charCode = 127
      result = (result + (charCode,))
    
    return result
  
  def sendScreenSysex(self, data, line=1):
    """
    Data must be a tuple of bytes, remember only 7-bit data is allowed for sysex
    """
    if not data:
      pass
    if(line==1):
        self._send_midi(((SYSEX_SCREEN_BEGIN_LINE_1 + data) + SYSEX_SCREEN_END))
    else:
        if(line==2):
            self._send_midi(((SYSEX_SCREEN_BEGIN_LINE_2 + data) + SYSEX_SCREEN_END))
  
  def send_value(self, msg_type, channel, id, value, force_send = False):
    assert (value != None)
    assert isinstance(value, int)
    assert (value in range(128))
    
    data_byte1 = id
    data_byte2 = value
    status_byte = channel
    if (msg_type == MIDI_NOTE_TYPE):
      status_byte += MIDI_NOTE_ON_STATUS
    elif (msg_type == MIDI_CC_TYPE):
      status_byte += MIDI_CC_STATUS
    else:
        assert False
    self._send_midi((status_byte, data_byte1, data_byte2))
  
  def back_to_arranger(self, *args, **kwargs):
    self.song().back_to_arranger = False
  
  def update_controller(self):
    """
    controller event loop
    this may also update every 100 miliseconds.
    decoupling the data updates from live and the controller communication
    may help keep latency to a minimum.
    """
    
  def onTempoChange(self):      
    self.bpmBeatTime = self.song().get_current_beats_song_time()
  
  def updateTempo(self):                          
    if self.song().is_playing:
      if (self.bpmBeatTime.beats > self.lastBeat):
        self.updateBPMLightOff()
      else:
        self.updateBPMLightOn()
  
  def updateBPMLightOn(self):  
    self.transport._play_button.turn_on()
    #self.send_value(MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_TEMPO, MASCHINE_DISPLAY_BPM)

  def updateBPMLightOff(self): 
    self.transport._play_button.turn_off()
    #self.send_value(MIDI_NOTE_TYPE, TRANSPORT_CHANNEL, TRANSPORT_TEMPO, 0)