-
Notifications
You must be signed in to change notification settings - Fork 0
/
TrackDevSelectHandler.py
357 lines (279 loc) · 15 KB
/
TrackDevSelectHandler.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
# ******************************************************************************
# This file is part of the AaMakro5oul project
# (An OSC/MIDI controller for Ableton Live with DJ features)
#
# Full project source: https://github.com/hiramegl/AaMakro5oul
#
# License : Apache License 2.0
# Full license: https://github.com/hiramegl/AaMakro5oul/blob/master/LICENSE
#
# Copyright 2018, 2019 by Hiram Galicia ([email protected])
# http://www.unasystems.com
#
# All rights reserved.
# ******************************************************************************
import copy
from CoreHandler import CoreHandler
# ******************************************************************************
# Track selection used to handle device controller events
# ******************************************************************************
class TrackDevSelectHandler(CoreHandler):
def __init__(self, _oCtrlInstance, _oOscServer, _hConfig):
CoreHandler.__init__(self, _oCtrlInstance, _oOscServer, _hConfig)
self.m_bIgnoreRelease = False # we need to listen to toggle off messages (release messages)
self.m_bLogRxMsgs = False
self.config('/track/dev/select', self.m_bIgnoreRelease, self.m_bLogRxMsgs)
for sCmd in ['track','reset','solo','volume']:
self.add_callbacks_pref(sCmd, CoreHandler.m_aChannels)
self.add_callbacks(['mode'])
self.reset_track_selection()
self.m_bReturnMode = False
bActive = 1.0 if self.m_bReturnMode else 0.0
self.send_msg('mode', bActive)
def disconnect(self):
self.reset_track_selection()
self.m_bReturnMode = False
bActive = 1.0 if self.m_bReturnMode else 0.0
self.send_msg('mode', bActive)
def update(self, _sEvent, _oArgs = None):
if (_sEvent == 'track_reboot'): # TrackCmdHandler
nTrackIdxAbs = _oArgs['nTrackIdxAbs']
self.reset_channels_for_track(nTrackIdxAbs)
elif (_sEvent == 'track_solo_update'): # TrackCmdHandler
nTrackIdxAbs = _oArgs['nTrackIdxAbs']
bSolo = _oArgs['bSolo']
sChannel = self.search_channel_for_track('track', nTrackIdxAbs)
if (sChannel != None):
nValue = 1.0 if (bSolo == True) else 0.0
self.send_msg('solo/%s' % (sChannel), nValue) # update solo toggle for channel
elif (_sEvent == 'new_tracks_sel'): # SessionCmdHandler
self.update_toggles()
def update_toggles(self):
if (self.m_bReturnMode == True):
return # nothing else to do here, we are in 'return' mode
aTrackMsgs = []
# we are in 'track' mode, we need to update the track toggles!
for sChannel in CoreHandler.m_aChannels:
aDevTrackSel = self.sel_track_dev(sChannel)
sTrackType = aDevTrackSel[0]
nIdxAbs = aDevTrackSel[1]
if (sTrackType == 'return'):
next # nothing else to do here, the selected track is a return track
bIsVisible = self.is_track_visible(nIdxAbs)
nIdxRel = self.track_idx_rel(nIdxAbs)
for nTrackIdxRel in range(self.max_track_sels()):
nValue = 1.0 if (nTrackIdxRel == nIdxRel and bIsVisible) else 0.0
self.append_mul_msg('track/%s' % (sChannel), nTrackIdxRel, nValue, aTrackMsgs)
sMsg = 'TrackDevSelectHandler, update_toggles, track indeces changed, updating'
self.send_bundle(sMsg, aTrackMsgs)
def reset_channels_for_track(self, _nTrackIdxAbs):
# reset the devices in the _TRACK_ itself (if a channel is found)
sChannel = self.search_channel_for_track('track', _nTrackIdxAbs)
if (sChannel != None):
hArgs = { 'sChannel': sChannel }
else:
hArgs = { 'sTrackType': 'track', 'nIdxAbs': _nTrackIdxAbs }
# TrackDevBaseHandler: device values reset
self.update_observers('device_values_reset', hArgs)
# reset the devices in the track's used _RETURNS_ (if any channel is found)
oTrack = self.get_track(_nTrackIdxAbs)
aSends = oTrack.mixer_device.sends
# iterate through the list of sends for this track
# and find out which channel needs to be reseted
nReturnIdxAbs = 0
for oSend in aSends:
if (oSend.value > 0.1):
sChannel = self.search_channel_for_track('return', nReturnIdxAbs)
if (sChannel != None):
hArgs = { 'sChannel': sChannel }
else:
hArgs = { 'sTrackType': 'return', 'nIdxAbs': nReturnIdxAbs }
# TrackDev[*]Handler: device values reset
self.update_observers('device_values_reset', hArgs)
nReturnIdxAbs += 1
def search_channel_for_track(self, _sType, _nTrackIdxAbs):
for sChannel in CoreHandler.m_hDevTrackSel.keys():
aDevTrackSel = CoreHandler.m_hDevTrackSel[sChannel]
# check if the type and the index match
if (aDevTrackSel[0] == _sType and aDevTrackSel[1] == _nTrackIdxAbs):
return sChannel # channel found!
return None # channel not found!
def reset_track_selection(self):
aTrackMsgs = []
for sChannel in CoreHandler.m_aChannels:
for nTrackIdxRel in range(self.max_track_sels()):
self.append_mul_msg('track/%s' % (sChannel), nTrackIdxRel, 0.0, aTrackMsgs)
sId = 'track_dev_select_reset_%s' % (sChannel)
sAttrs = '{"label": "-", "css": "background-color: var(--color-raised)"}'
self.send('/EDIT', [sId, sAttrs])
self.send_msg('solo/%s' % (sChannel), 0.0) # turn solo off
sMsg = 'TrackDevSelectHandler, reset_track_selection, track/dev/select, reset'
self.send_bundle(sMsg, aTrackMsgs)
def handle(self, _aMessage):
sCmd = self.m_aParts[0] # 'track', 'mode' or 'reset'
# handle 'mode' subcommand
if (sCmd == 'mode'):
bReturnMode = _aMessage[2] > 0
self.m_bReturnMode = bReturnMode
if (bReturnMode == True):
self.alert('> Device-track selection mode: Return')
else:
self.alert('> Device-track selection mode: Track')
# update the track toggle taking into consideration the new mode
for sChannel in CoreHandler.m_aChannels:
aDevTrackSel = self.sel_track_dev(sChannel)
sTrackType = aDevTrackSel[0]
nIdxAbs = aDevTrackSel[1]
# check if there is actually a track assigned to this channel
if (sTrackType == 'track'):
bIsVisible = self.is_track_visible(nIdxAbs)
nIdxRel = self.track_idx_rel(nIdxAbs)
nValue = 1.0 if (self.m_bReturnMode == False and bIsVisible) else 0.0
self.send_msg('track/%s' % (sChannel), [nIdxRel, nValue])
elif (sTrackType == 'return'):
nValue = 1.0 if (self.m_bReturnMode == True) else 0.0
self.send_msg('track/%s' % (sChannel), [nIdxAbs, nValue])
return # nothing else to do here!
sChannel = self.m_aParts[1] # 'a', 'b', 'c' or 'd'
# handle 'reset' subcommand
if (sCmd == 'reset'):
hArgs = { 'sChannel': sChannel }
self.update_observers('device_values_reset', hArgs)
return # nothing else to do here!
# handle 'solo' subcommand
if (sCmd == 'solo'):
aDevTrackSel = self.sel_track_dev(sChannel)
sTrackType = aDevTrackSel[0]
nIdxAbs = aDevTrackSel[1]
# check if there is actually a track assigned to that channel
if (sTrackType != 'none'):
if (sTrackType == 'track'):
oTrack = self.get_track(nIdxAbs)
else:
oTrack = self.get_return(nIdxAbs)
oTrack.solo = _aMessage[2] > 0.5
self.send_msg('solo/%s' % (sChannel), _aMessage[2])
else:
self.send_msg('solo/%s' % (sChannel), 0.0) # turn toggle off immediately!
return # nothing else to do here!
if (sCmd == 'volume'):
aDevTrackSel = self.sel_track_dev(sChannel)
sTrackType = aDevTrackSel[0]
nIdxAbs = aDevTrackSel[1]
# check if there is actually a track assigned to that channel
if (sTrackType != 'none'):
if (sTrackType == 'track'):
oTrack = self.get_track(nIdxAbs)
else:
oTrack = self.get_return(nIdxAbs)
oMixDev = oTrack.mixer_device
oMixDev.volume.value = _aMessage[2]
#self.send_msg('volume/%s' % (sChannel), _aMessage[2])
else:
self.send_msg('volume/%s' % (sChannel), 0.0) # turn volume off immediately!
return # nothing else to do here!
# handle 'track' subcommand
sTrackIdx = _aMessage[2] # track index relative or return index absolute
nValue = _aMessage[3] # toggle value
nTrackIdx = int(sTrackIdx)
bActive = (nValue > 0.5) # is toggle active
aOthers = copy.copy(CoreHandler.m_aChannels)
aOthers.remove(sChannel) # the other channels
# validate index
if (self.m_bReturnMode == False):
# 'track' selection mode
sTrackType = 'track'
nIdxAbs = self.track_idx_abs(nTrackIdx)
if (self.is_track_available(nIdxAbs) == False):
self.send_msg('track/%s' % (sChannel), [nTrackIdx, 0.0]) # turn off the toggle button!
return; # track does not exist, nothing else to do here
else:
# 'return' selection mode
sTrackType = 'return'
nIdxAbs = nTrackIdx
if (self.is_return_available(nIdxAbs) == False):
self.send_msg('track/%s' % (sChannel), [nTrackIdx, 0.0]) # turn off the toggle button!
return; # return-track does not exist, nothing else to do here
aDevTrackSelOld = self.sel_track_dev(sChannel)
sTrackTypeOld = aDevTrackSelOld[0]
nIdxAbsOld = aDevTrackSelOld[1]
if (bActive == True):
# check if the track is already selected in other channel
for sOtherChannel in aOthers:
aDevTrackSelOther = self.sel_track_dev(sOtherChannel)
sTrackTypeOther = aDevTrackSelOther[0]
nIdxAbsOther = aDevTrackSelOther[1]
if (sTrackTypeOther == sTrackTypeOld and nIdxAbsOther == nIdxAbsOld):
# TrackDev[*]Handler: all devices in order to send their clear values in the GUI
hArgs = { 'sChannel': sOtherChannel }
self.update_observers('device_values_clear', hArgs)
# unregister it from the other channel (delete it)
self.sel_track_dev(sOtherChannel, 'none')
self.send_msg('track/%s' % (sOtherChannel), [nTrackIdx, 0.0])
sId = 'track_dev_select_reset_%s' % (sOtherChannel)
sAttrs = '{"label": "-", "css": "background-color: var(--color-raised)"}'
self.send('/EDIT', [sId, sAttrs])
# check if there is any track already selected in this channel,
# if there is any then remove it first from this channel
if (sTrackTypeOld != 'none'):
# TrackDev[*]Handler: all devices in order to send their clear values in the GUI
hArgs = { 'sChannel': sChannel }
self.update_observers('device_values_clear', hArgs)
if (sTrackTypeOld == 'track' and self.is_track_visible(nIdxAbsOld)):
# is a track and is gui visible
nIdxRelOld = self.track_idx_rel(nIdxAbsOld)
self.send_msg('track/%s' % (sChannel), [nIdxRelOld, 0.0])
else:
# is a return track
self.send_msg('track/%s' % (sChannel), [nIdxAbsOld, 0.0])
# unregister it from this channel (delete it)
self.sel_track_dev(sChannel, 'none')
sId = 'track_dev_select_reset_%s' % (sChannel)
sAttrs = '{"label": "-", "css": "background-color: var(--color-raised)"}'
self.send('/EDIT', [sId, sAttrs])
self.send_msg('solo/%s' % (sChannel), 0.0) # turn solo off
# register in this channel and toggle on
self.sel_track_dev(sChannel, sTrackType, nIdxAbs)
self.send_msg('track/%s' % (sChannel), [nTrackIdx, 1.0])
if (sTrackType == 'track'):
oTrack = self.get_track(nIdxAbs)
sType = 'T'
else:
oTrack = self.get_return(nIdxAbs)
sType = 'R'
sName = self.to_ascii(oTrack.name)
sId = 'track_dev_select_reset_%s' % (sChannel)
sAttrs = '{"label": "%s%d: %s", "css": "background-color: %s"}' % (sType, nIdxAbs, sName, self.to_color(oTrack.color))
self.send('/EDIT', [sId, sAttrs])
# update solo state and volume for selected track
nSolo = 1.0 if (oTrack.solo) else 0.0
self.send_msg('solo/%s' % (sChannel), nSolo)
self.send_msg('volume/%s' % (sChannel), oTrack.mixer_device.volume.value)
# TrackDev[*]Handler: all devices in order to send their values to the GUI
hArgs = {
'sChannel' : sChannel,
'sTrackType': sTrackType,
'nIdxAbs' : nIdxAbs
}
self.update_observers('device_values_update', hArgs)
self.log('> channel: %s, type: %s, track sel: %d' % (sChannel, sTrackType, nIdxAbs))
self.alert('> channel: %s, type: %s, track sel: %d' % (sChannel, sTrackType, nIdxAbs))
else:
# TrackDev[*]Handler: all devices in order to send their clear values in the GUI
hArgs = { 'sChannel': sChannel }
self.update_observers('device_values_clear', hArgs)
if (sTrackTypeOld == 'track' and self.is_track_visible(nIdxAbsOld)):
# is a track and is gui visible
nIdxRelOld = self.track_idx_rel(nIdxAbsOld)
self.send_msg('track/%s' % (sChannel), [nIdxRelOld, 0.0])
else:
# is a return track (always gui visible)
self.send_msg('track/%s' % (sChannel), [nIdxAbsOld, 0.0])
# unregister in this channel and toggle off
self.sel_track_dev(sChannel, 'none')
sId = 'track_dev_select_reset_%s' % (sChannel)
sAttrs = '{"label": "-", "css": "background-color: var(--color-raised)"}'
self.send('/EDIT', [sId, sAttrs])
self.send_msg('solo/%s' % (sChannel), 0.0) # turn solo off
self.log('> channel: %s -> cleared' % (sChannel))
self.alert('> channel: %s -> cleared' % (sChannel))