1
2 import Live
3 from ControlSurfaceComponent import ControlSurfaceComponent
4 from Util import in_range
5 from SubjectSlot import subject_slot
6 INVALID_COLOR = None
9 """
10 Component representing a ClipSlot within Live.
11 """
12
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
41
59
64
67
70
73
75 self._triggered_to_play_value = value
76
78 self._triggered_to_record_value = value
79
81 self._started_value = value
82
84 self._recording_value = value
85
87 raise in_range(value, -1, 128) or AssertionError
88 self._stopped_value = value
89 self._clip_palette = []
90
93
95 raise palette != None or AssertionError
96 self._stopped_value = INVALID_COLOR
97 self._clip_palette = palette
98
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
105 raise self._clip_slot != None or AssertionError
106 return self._clip_slot.has_clip
107
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
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
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
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')
174
177
180
183
186
189
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
211
213 if self._clip_slot and self._clip_slot.has_clip:
214 self._clip_slot.delete_clip()
215
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
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
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