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

Source Code for Module _Framework.ClipSlotComponent

  1  #Embedded file name: /Users/versonator/Hudson/live/Projects/AppLive/Resources/MIDI Remote Scripts/_Framework/ClipSlotComponent.py 
  2  import Live 
  3  from ControlSurfaceComponent import ControlSurfaceComponent 
  4  from Util import in_range 
  5  from SubjectSlot import subject_slot 
  6  INVALID_COLOR = None 
7 8 -class ClipSlotComponent(ControlSurfaceComponent):
9 """ 10 Component representing a ClipSlot within Live. 11 """ 12
13 - def __init__(self, *a, **k):
14 super(ClipSlotComponent, self).__init__(*a, **k) 15 self._clip_slot = None 16 self._triggered_to_play_value = 126 17 self._triggered_to_record_value = 121 18 self._started_value = 127 19 self._recording_value = 120 20 self._stopped_value = 0 21 self._clip_palette = [] 22 self._clip_rgb_table = None 23 self._record_button_value = None 24 self._has_fired_slot = False 25 self._on_playing_state_changed_slot = self.register_slot(None, self._on_playing_state_changed, 'playing_status') 26 self._on_recording_state_changed_slot = self.register_slot(None, self._on_recording_state_changed, 'is_recording') 27 self._on_slot_triggered_changed_slot = self.register_slot(None, self._on_slot_triggered_changed, 'is_triggered') 28 self._on_playing_state_changed_slot_slot = self.register_slot(None, self._on_playing_state_changed, 'playing_status') 29 self._on_clip_state_changed_slot = self.register_slot(None, self._on_clip_state_changed, 'has_clip') 30 self._on_controls_other_changed_slot = self.register_slot(None, self._on_clip_state_changed, 'controls_other_clips') 31 self._on_has_stop_button_changed_slot = self.register_slot(None, self._on_has_stop_button_changed, 'has_stop_button') 32 self._launch_button_value_slot = self.register_slot(None, self._launch_value, 'value') 33 self._on_arm_value_changed_slot = self.register_slot(None, self._on_arm_value_changed, 'arm') 34 self._on_implicit_arm_value_changed_slot = self.register_slot(None, self._on_implicit_arm_value_changed, 'implicit_arm') 35 self._delete_button = None 36 self._select_button = None 37 self._duplicate_button = None
38
39 - def on_enabled_changed(self):
40 self.update()
41
42 - def set_clip_slot(self, clip_slot):
43 if not (clip_slot == None or isinstance(clip_slot, Live.ClipSlot.ClipSlot)): 44 raise AssertionError 45 clip = clip_slot.clip if clip_slot else None 46 self._on_playing_state_changed_slot.subject = clip 47 self._on_recording_state_changed_slot.subject = clip 48 self._on_clip_color_changed.subject = clip 49 self._on_slot_triggered_changed_slot.subject = clip_slot 50 self._on_playing_state_changed_slot_slot.subject = clip_slot 51 self._on_clip_state_changed_slot.subject = clip_slot 52 self._on_controls_other_changed_slot.subject = clip_slot 53 self._on_has_stop_button_changed_slot.subject = clip_slot 54 track = clip_slot.canonical_parent if clip_slot else None 55 self._on_arm_value_changed_slot.subject = track and track.can_be_armed and track 56 self._on_implicit_arm_value_changed_slot.subject = track 57 self._clip_slot = clip_slot 58 self.update()
59
60 - def set_launch_button(self, button):
61 if button != self._launch_button_value_slot.subject: 62 self._launch_button_value_slot.subject = button 63 self.update()
64
65 - def set_delete_button(self, button):
66 self._delete_button = button
67
68 - def set_select_button(self, button):
69 self._select_button = button
70
71 - def set_duplicate_button(self, button):
72 self._duplicate_button = button
73
74 - def set_triggered_to_play_value(self, value):
75 self._triggered_to_play_value = value
76
77 - def set_triggered_to_record_value(self, value):
78 self._triggered_to_record_value = value
79
80 - def set_started_value(self, value):
81 self._started_value = value
82
83 - def set_recording_value(self, value):
84 self._recording_value = value
85
86 - def set_stopped_value(self, value):
87 raise in_range(value, -1, 128) or AssertionError 88 self._stopped_value = value 89 self._clip_palette = []
90
91 - def set_record_button_value(self, value):
92 self._record_button_value = value
93
94 - def set_clip_palette(self, palette):
95 raise palette != None or AssertionError 96 self._stopped_value = INVALID_COLOR 97 self._clip_palette = palette
98
99 - def set_clip_rgb_table(self, rgb_table):
100 """ A list of velocity, hex-rgb color pairs that is used, if the color could not 101 be matched to the clip palette """ 102 self._clip_rgb_table = rgb_table
103
104 - def has_clip(self):
105 raise self._clip_slot != None or AssertionError 106 return self._clip_slot.has_clip
107
108 - def update(self):
109 self._has_fired_slot = False 110 button = self._launch_button_value_slot.subject 111 if self._allow_updates: 112 if self.is_enabled() and button != None: 113 value_to_send = self._feedback_value() 114 if isinstance(value_to_send, int): 115 if in_range(value_to_send, 0, 128): 116 button.send_value(value_to_send) 117 else: 118 button.turn_off() 119 else: 120 button.set_light(value_to_send) 121 else: 122 self._update_requests += 1
123
124 - def _feedback_value(self):
125 value_to_send = -1 126 if self._clip_slot != None: 127 slot_or_clip = self._clip_slot 128 if self.has_clip(): 129 slot_or_clip = self._clip_slot.clip 130 if self._stopped_value != INVALID_COLOR: 131 value_to_send = self._stopped_value 132 else: 133 try: 134 value_to_send = self._clip_palette[self._clip_slot.clip.color] 135 except KeyError: 136 if self._clip_rgb_table != None: 137 value_to_send = self._find_nearest_color(self._clip_rgb_table, self._clip_slot.clip.color) 138 else: 139 value_to_send = 0 140 141 else: 142 track = self._clip_slot.canonical_parent 143 if track and track.can_be_armed and (track.arm or track.implicit_arm) and self._clip_slot.has_stop_button and self._record_button_value: 144 value_to_send = self._record_button_value 145 if slot_or_clip.is_triggered: 146 value_to_send = self._triggered_to_record_value if slot_or_clip.will_record_on_start else self._triggered_to_play_value 147 elif slot_or_clip.is_playing: 148 value_to_send = self._recording_value if slot_or_clip.is_recording else self._started_value 149 elif hasattr(slot_or_clip, 'controls_other_clips') and slot_or_clip.controls_other_clips: 150 value_to_send = self._stopped_value 151 return value_to_send
152
153 - def _find_nearest_color(self, rgb_table, src_hex_color):
154 155 def hex_to_channels(color_in_hex): 156 return ((color_in_hex & 16711680) >> 16, (color_in_hex & 65280) >> 8, color_in_hex & 255)
157 158 def squared_distance(color): 159 return sum([ (a - b) ** 2 for a, b in zip(hex_to_channels(src_hex_color), hex_to_channels(color[1])) ])
160 161 return min(rgb_table, key=squared_distance)[0] 162
163 - def _on_clip_state_changed(self):
164 if not self._clip_slot != None: 165 raise AssertionError 166 clip = self.has_clip() and self._clip_slot.clip 167 self._on_playing_state_changed_slot.subject = clip 168 self._on_recording_state_changed_slot.subject = clip 169 self.update()
170 171 @subject_slot('color')
172 - def _on_clip_color_changed(self):
173 self.update()
174
175 - def _on_playing_state_changed(self):
176 self.update()
177
178 - def _on_recording_state_changed(self):
179 self.update()
180
181 - def _on_arm_value_changed(self):
182 self.update()
183
184 - def _on_implicit_arm_value_changed(self):
185 self.update()
186
187 - def _on_has_stop_button_changed(self):
188 self.update()
189
190 - def _on_slot_triggered_changed(self):
191 if not self.has_clip(): 192 song = self.song() 193 view = song.view 194 if song.select_on_launch and self._clip_slot.is_triggered and self._has_fired_slot and self._clip_slot.will_record_on_start and self._clip_slot != view.highlighted_clip_slot: 195 view.highlighted_clip_slot = self._clip_slot 196 self.update()
197
198 - def _launch_value(self, value):
199 if self.is_enabled(): 200 if self._select_button and self._select_button.is_pressed() and value: 201 self._do_select_clip(self._clip_slot) 202 elif self._clip_slot != None: 203 if self._duplicate_button and self._duplicate_button.is_pressed(): 204 if value: 205 self._do_duplicate_clip() 206 elif self._delete_button and self._delete_button.is_pressed(): 207 if value: 208 self._do_delete_clip() 209 else: 210 self._do_launch_clip(value)
211
212 - def _do_delete_clip(self):
213 if self._clip_slot and self._clip_slot.has_clip: 214 self._clip_slot.delete_clip()
215
216 - def _do_select_clip(self, clip_slot):
217 if self._clip_slot != None: 218 if self.song().view.highlighted_clip_slot != self._clip_slot: 219 self.song().view.highlighted_clip_slot = self._clip_slot
220
221 - def _do_duplicate_clip(self):
222 if self._clip_slot and self._clip_slot.has_clip: 223 try: 224 track = self._clip_slot.canonical_parent 225 track.duplicate_clip_slot(list(track.clip_slots).index(self._clip_slot)) 226 except Live.Base.LimitationError: 227 pass 228 except RuntimeError: 229 pass
230
231 - def _do_launch_clip(self, value):
232 button = self._launch_button_value_slot.subject 233 object_to_launch = self._clip_slot 234 if not value != 0: 235 launch_pressed = not button.is_momentary() 236 if self.has_clip(): 237 object_to_launch = self._clip_slot.clip 238 else: 239 self._has_fired_slot = True 240 if button.is_momentary(): 241 object_to_launch.set_fire_button_state(value != 0) 242 elif value != 0: 243 object_to_launch.fire() 244 self.song().view.highlighted_clip_slot = launch_pressed and self.has_clip() and self.song().select_on_launch and self._clip_slot
245