Package _Framework :: Module TransportComponent
[hide private]
[frames] | no frames]

Source Code for Module _Framework.TransportComponent

  1  #Embedded file name: /Users/versonator/Hudson/live/Projects/AppLive/Resources/MIDI Remote Scripts/_Framework/TransportComponent.py 
  2  import Live 
  3  from functools import partial 
  4  from CompoundComponent import CompoundComponent 
  5  from ToggleComponent import ToggleComponent 
  6  from Util import const, in_range, clamp 
  7  from SubjectSlot import subject_slot 
  8  import Task 
  9  TEMPO_TOP = 200.0 
 10  TEMPO_BOTTOM = 60.0 
 11  TEMPO_FINE_RANGE = 2.56 
 12  SEEK_SPEED = 10.0 
13 14 -class TransportComponent(CompoundComponent):
15 """ 16 Class encapsulating all functions in Live's transport section. 17 """ 18
19 - def __init__(self, *a, **k):
20 super(TransportComponent, self).__init__(*a, **k) 21 self._ffwd_button = None 22 self._rwd_button = None 23 self._tap_tempo_button = None 24 self._tempo_control = None 25 self._tempo_fine_control = None 26 self._song_position_control = None 27 self._rwd_task = Task.Task() 28 self._ffwd_task = Task.Task() 29 self._fine_tempo_needs_pickup = True 30 self._prior_fine_tempo_value = -1 31 self._end_undo_step_task = self._tasks.add(Task.sequence(Task.wait(1.5), Task.run(self.song().end_undo_step))) 32 self._end_undo_step_task.kill() 33 song = self.song() 34 self._loop_toggle, self._punch_in_toggle, self._punch_out_toggle, self._record_toggle, self._play_toggle, self._stop_toggle, self._nudge_down_toggle, self._nudge_up_toggle, self._metronome_toggle, self._session_record_toggle, self.arrangement_overdub_toggle, self._overdub_toggle = self.register_components(ToggleComponent('loop', song), ToggleComponent('punch_in', song, is_momentary=True), ToggleComponent('punch_out', song, is_momentary=True), ToggleComponent('record_mode', song), ToggleComponent('is_playing', song, model_transform=const(True)), ToggleComponent('is_playing', song, model_transform=const(False), view_transform=const(False)), ToggleComponent('nudge_down', song, is_momentary=True), ToggleComponent('nudge_up', song, is_momentary=True), ToggleComponent('metronome', song), ToggleComponent('session_record', song), ToggleComponent('arrangement_overdub', song), ToggleComponent('overdub', song))
35
36 - def set_stop_button(self, button):
37 self._stop_toggle.set_toggle_button(button)
38
39 - def set_play_button(self, button):
40 self._play_toggle.set_toggle_button(button)
41
42 - def set_seek_buttons(self, ffwd_button, rwd_button):
43 if self._ffwd_button != ffwd_button: 44 self._ffwd_button = ffwd_button 45 self._ffwd_value_slot.subject = ffwd_button 46 self._ffwd_task.kill() 47 if self._rwd_button != rwd_button: 48 self._rwd_button = rwd_button 49 self._rwd_value_slot.subject = rwd_button 50 self._rwd_task.kill()
51
52 - def set_seek_forward_button(self, ffwd_button):
53 if self._ffwd_button != ffwd_button: 54 self._ffwd_button = ffwd_button 55 self._ffwd_value_slot.subject = ffwd_button 56 self._ffwd_task.kill()
57
58 - def set_seek_backward_button(self, rwd_button):
59 if self._rwd_button != rwd_button: 60 self._rwd_button = rwd_button 61 self._rwd_value_slot.subject = rwd_button 62 self._rwd_task.kill()
63
64 - def set_nudge_buttons(self, up_button, down_button):
65 self._nudge_up_toggle.set_toggle_button(up_button) 66 self._nudge_down_toggle.set_toggle_button(down_button)
67
68 - def set_nudge_up_button(self, up_button):
69 self._nudge_up_toggle.set_toggle_button(up_button)
70
71 - def set_nudge_down_button(self, down_button):
72 self._nudge_down_toggle.set_toggle_button(down_button)
73
74 - def set_record_button(self, button):
75 self._record_toggle.set_toggle_button(button)
76
77 - def set_tap_tempo_button(self, button):
78 if self._tap_tempo_button != button: 79 self._tap_tempo_button = button 80 self._tap_tempo_value.subject = button 81 self._update_tap_tempo_button()
82
83 - def set_loop_button(self, button):
84 self._loop_toggle.set_toggle_button(button)
85
86 - def set_punch_buttons(self, in_button, out_button):
87 self._punch_in_toggle.set_toggle_button(in_button) 88 self._punch_out_toggle.set_toggle_button(out_button)
89
90 - def set_punch_in_button(self, in_button):
91 self._punch_in_toggle.set_toggle_button(in_button)
92
93 - def set_punch_out_button(self, out_button):
94 self._punch_out_toggle.set_toggle_button(out_button)
95
96 - def set_metronome_button(self, button):
97 self._metronome_toggle.set_toggle_button(button)
98
99 - def set_session_overdub_button(self, button):
100 self._session_overdub_toggle.set_toggle_button(button)
101
102 - def set_arrangement_overdub_button(self, button):
103 self._arrangement_overdub_toggle.set_toggle_button(button)
104
105 - def set_overdub_button(self, button):
106 self._overdub_toggle.set_toggle_button(button)
107
108 - def set_tempo_control(self, control, fine_control = None):
109 if not (not control or control.message_map_mode() is Live.MidiMap.MapMode.absolute): 110 raise AssertionError 111 if not (not fine_control or fine_control.message_map_mode() is Live.MidiMap.MapMode.absolute): 112 raise AssertionError 113 self._tempo_control = self._tempo_control != control and control 114 self._tempo_value.subject = control 115 self._tempo_fine_control = self._tempo_fine_control != fine_control and fine_control 116 self._tempo_fine_value.subject = fine_control 117 self._fine_tempo_needs_pickup = True 118 self._prior_fine_tempo_value = -1
119
120 - def set_tempo_fine_control(self, fine_control):
121 if not (not fine_control or fine_control.message_map_mode() is Live.MidiMap.MapMode.absolute): 122 raise AssertionError 123 self._tempo_fine_control = self._tempo_fine_control != fine_control and fine_control 124 self._tempo_fine_value.subject = fine_control 125 self._fine_tempo_needs_pickup = True 126 self._prior_fine_tempo_value = -1
127
128 - def set_song_position_control(self, control):
129 if self._song_position_control != control: 130 self._song_position_control = control 131 self._song_position_value.subject = control
132
133 - def update(self):
134 if self.is_enabled(): 135 self._update_tap_tempo_button()
136 137 @subject_slot('value')
138 - def _ffwd_value_slot(self, value):
139 self._ffwd_value(value)
140
141 - def _ffwd_value(self, value):
142 if self._ffwd_button.is_momentary(): 143 self._ffwd_task.kill() 144 if value: 145 self._ffwd_task = self._tasks.add(partial(self._move_current_song_time, SEEK_SPEED)) 146 elif self.is_enabled(): 147 self.song().current_song_time += 1
148 149 @subject_slot('value')
150 - def _rwd_value_slot(self, value):
151 self._rwd_value(value)
152
153 - def _rwd_value(self, value):
154 if self._rwd_button.is_momentary(): 155 self._rwd_task.kill() 156 if value: 157 self._rwd_task = self._tasks.add(partial(self._move_current_song_time, -SEEK_SPEED)) 158 elif self.is_enabled(): 159 song = self.song() 160 song.current_song_time = max(0.0, song.current_song_time - 1)
161
162 - def _move_current_song_time(self, speed, delta):
163 song = self.song() 164 song.current_song_time = max(0.0, song.current_song_time + speed * delta) 165 return Task.RUNNING
166 167 @subject_slot('value')
168 - def _tap_tempo_value(self, value):
169 if self.is_enabled(): 170 if value or not self._tap_tempo_button.is_momentary(): 171 if not self._end_undo_step_task.is_running: 172 self.song().begin_undo_step() 173 self._end_undo_step_task.restart() 174 self.song().tap_tempo() 175 self._update_tap_tempo_button()
176
177 - def _update_tap_tempo_button(self):
178 if self.is_enabled() and self._tap_tempo_button: 179 self._tap_tempo_button.set_light(self._tap_tempo_button.is_pressed())
180 181 @subject_slot('value')
182 - def _tempo_value(self, value):
183 if self.is_enabled(): 184 fraction = (TEMPO_TOP - TEMPO_BOTTOM) / 127.0 185 self.song().tempo = fraction * value + TEMPO_BOTTOM
186 187 @subject_slot('value')
188 - def _tempo_fine_value(self, value):
189 if self.is_enabled(): 190 if self._fine_tempo_needs_pickup: 191 if in_range(self._prior_fine_tempo_value, 0, 128): 192 range_max = max(value, self._prior_fine_tempo_value) 193 range_min = min(value, self._prior_fine_tempo_value) 194 if in_range(64, range_min, range_max + 1): 195 self._fine_tempo_needs_pickup = False 196 else: 197 raise in_range(self._prior_fine_tempo_value, 0, 128) or AssertionError 198 difference = value - self._prior_fine_tempo_value 199 ratio = 127.0 / TEMPO_FINE_RANGE 200 new_tempo = clamp(self.song().tempo + difference / ratio, TEMPO_BOTTOM, TEMPO_TOP) 201 self.song().tempo = new_tempo 202 self._prior_fine_tempo_value = value
203 204 @subject_slot('value')
205 - def _song_position_value(self, value):
206 raise NotImplementedError
207