-
Notifications
You must be signed in to change notification settings - Fork 4
/
mcu_base_class.py
346 lines (291 loc) · 16.8 KB
/
mcu_base_class.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
import device
import ui
import time
import utils
import mixer
import midi
import transport
import general
import channels
import mcu_constants
import mcu_device
import mcu_track
import mcu_pages
import mcu_knob_mode
import tracknames
class McuBaseClass():
""" Shared base class for both the extender and the main mackie unit """
def __init__(self, device: mcu_device.McuDevice):
self.MsgT = ["", ""]
self.Tracks = [mcu_track.McuTrack() for i in range(0)] # empty array, since "import typing" is not supported
self.Shift = False # indicates that the shift button is pressed
self.MsgDirty = False
self.FirstTrack = 0 # the count mode for the tracks (0 = normal, 1 = free mode)
self.FirstTrackT = [0, 0]
self.FreeCtrlT = [0 for x in range(mcu_constants.FreeTrackCount + 1)] # 64+1 sliders
self.Clicking = False
self.Page = 0
self.Flip = False
self.SmoothSpeed = 0
self.McuDevice = device
def OnInit(self):
""" Called when the script has been started """
self.FirstTrackT[0] = 1
self.FirstTrack = 0
self.SmoothSpeed = 0 # TODO: is not required if OnInit is not called more than once, need to check if this is the case
self.Clicking = True
device.setHasMeters()
# set free mode faders to center
for m in range(0, len(self.FreeCtrlT)):
self.FreeCtrlT[m] = 8192
# init hardware
self.McuDevice.Initialize()
self.McuDevice.SetBackLightTimeout(2) # backlight timeout to 2 minutes
self.McuDevice.SetClicking(self.Clicking)
def OnDeInit(self):
""" Called before the script will be stopped """
self.McuDevice.DisableMeters()
if device.isAssigned():
if ui.isClosing():
self.McuDevice.SetTextDisplay(ui.getProgTitle() + ' session closed at ' + time.ctime(time.time()), 0, skipIsAssignedCheck = True)
else:
self.McuDevice.SetTextDisplay('', skipIsAssignedCheck = True)
self.McuDevice.SetTextDisplay('', 1, skipIsAssignedCheck = True)
self.McuDevice.SetScreenColors(skipIsAssignedCheck = True)
def OnDirtyMixerTrack(self, SetTrackNum):
"""
Called on mixer track(s) change, 'SetTrackNum' indicates track index of track that changed or -1 when all tracks changed
collect info about 'dirty' tracks here but do not handle track(s) refresh, wait for OnRefresh event with HW_Dirty_Mixer_Controls flag
"""
for m in range(0, len(self.Tracks)):
if (self.Tracks[m].TrackNum == SetTrackNum) | (SetTrackNum == -1):
self.Tracks[m].Dirty = True
def UpdateTextDisplay(self):
""" Updates the mixer track names and colors """
# Update names
s1 = ''
for m in range(0, len(self.Tracks) - 1):
s = ''
if self.Page == mcu_pages.Free:
s = ' ' + utils.Zeros(self.Tracks[m].TrackNum + 1, 2, ' ')
else:
s = tracknames.GetAsciiSafeTrackName(self.Tracks[m].TrackNum, 7)
for n in range(1, 7 - len(s) + 1):
s = s + ' '
s1 = s1 + s
self.McuDevice.SetTextDisplay(s1, 1)
# Update colors
if self.Page == mcu_pages.Free:
self.McuDevice.SetScreenColors() # all white
else:
colorArr = []
for m in range(0, len(self.Tracks) - 1):
c = mixer.getTrackColor(self.Tracks[m].TrackNum)
colorArr.append(c)
self.McuDevice.SetScreenColors(colorArr)
def UpdateMeterMode(self):
self.McuDevice.ClearMeters()
self.McuDevice.DisableMeters() #TODO: check if it's actually required to disable and then enable again here
# reset stuff
self.UpdateTextDisplay()
self.McuDevice.EnableMeters()
def OnUpdateMeters(self):
""" Called when peak meters have updated values """
if self.Page != mcu_pages.Free:
for track in self.McuDevice.tracksWithMeters:
currentPeak = mixer.getTrackPeaks(self.Tracks[track.index].TrackNum, midi.PEAK_LR_INV)
track.meter.SetValue(currentPeak)
def OnIdle(self):
""" Called from time to time. Can be used to do some small tasks, mostly UI related """
# temp message
if self.MsgDirty:
self.UpdateMsg()
self.MsgDirty = False
def UpdateColT(self):
firstTrackNum = self.FirstTrackT[self.FirstTrack]
CurID = mixer.getTrackPluginId(mixer.trackNumber(), 0)
for i in range(0, len(self.Tracks)):
if self.Page == mcu_pages.Free:
# free controls
if i == 8:
self.Tracks[i].TrackNum = mcu_constants.FreeTrackCount
else:
self.Tracks[i].TrackNum = (firstTrackNum + i) % mcu_constants.FreeTrackCount
self.Tracks[i].KnobName = 'Knob ' + str(self.Tracks[i].TrackNum + 1)
self.Tracks[i].SliderName = 'Slider ' + str(self.Tracks[i].TrackNum + 1)
self.Tracks[i].BaseEventID = mcu_constants.FreeEventID + self.Tracks[i].TrackNum * 8 # first virtual CC
else:
self.Tracks[i].KnobPressEventID = -1
# mixer
if i == 8:
self.Tracks[i].TrackNum = -2
self.Tracks[i].BaseEventID = midi.REC_MainVol
self.Tracks[i].SliderEventID = self.Tracks[i].BaseEventID
self.Tracks[i].SliderName = 'Master Vol'
else:
self.Tracks[i].TrackNum = midi.TrackNum_Master + ((firstTrackNum + i) % mixer.trackCount())
self.Tracks[i].BaseEventID = mixer.getTrackPluginId(self.Tracks[i].TrackNum, 0)
self.Tracks[i].SliderEventID = self.Tracks[i].BaseEventID + midi.REC_Mixer_Vol
s = tracknames.GetAsciiSafeTrackName(self.Tracks[i].TrackNum)
self.Tracks[i].SliderName = s + ' - Vol'
self.Tracks[i].KnobEventID = -1
self.Tracks[i].KnobResetEventID = -1
self.Tracks[i].KnobResetValue = midi.FromMIDI_Max >> 1
self.Tracks[i].KnobName = ''
self.Tracks[i].KnobMode = mcu_knob_mode.BoostCut # parameter, pan, volume, off
self.Tracks[i].KnobCenter = -1
if self.Page == mcu_pages.Pan:
self.Tracks[i].KnobEventID = self.Tracks[i].BaseEventID + midi.REC_Mixer_Pan
self.Tracks[i].KnobResetEventID = self.Tracks[i].KnobEventID
self.Tracks[i].KnobName = tracknames.GetAsciiSafeTrackName(self.Tracks[i].TrackNum) + ' - ' + 'Pan'
elif self.Page == mcu_pages.Stereo:
self.Tracks[i].KnobEventID = self.Tracks[i].BaseEventID + midi.REC_Mixer_SS
self.Tracks[i].KnobResetEventID = self.Tracks[i].KnobEventID
self.Tracks[i].KnobName = tracknames.GetAsciiSafeTrackName(self.Tracks[i].TrackNum) + ' - ' + 'Sep'
elif self.Page == mcu_pages.Sends:
self.Tracks[i].KnobEventID = CurID + midi.REC_Mixer_Send_First + self.Tracks[i].TrackNum
s = mixer.getEventIDName(self.Tracks[i].KnobEventID)
self.Tracks[i].KnobName = s
self.Tracks[i].KnobResetValue = round(12800 * midi.FromMIDI_Max / 16000)
self.Tracks[i].KnobCenter = mixer.getRouteSendActive(mixer.trackNumber(),self.Tracks[i].TrackNum)
if self.Tracks[i].KnobCenter == 0:
self.Tracks[i].KnobMode = mcu_knob_mode.Off
else:
self.Tracks[i].KnobMode = mcu_knob_mode.Wrap
elif self.Page == mcu_pages.Effects:
CurID = mixer.getTrackPluginId(mixer.trackNumber(), i)
self.Tracks[i].KnobEventID = CurID + midi.REC_Plug_MixLevel
s = mixer.getEventIDName(self.Tracks[i].KnobEventID)
self.Tracks[i].KnobName = s
self.Tracks[i].KnobResetValue = midi.FromMIDI_Max
IsValid = mixer.isTrackPluginValid(mixer.trackNumber(), i)
IsEnabledAuto = mixer.isTrackAutomationEnabled(mixer.trackNumber(), i)
if IsValid:
self.Tracks[i].KnobMode = mcu_knob_mode.Wrap
self.Tracks[i].KnobPressEventID = CurID + midi.REC_Plug_Mute
else:
self.Tracks[i].KnobMode = mcu_knob_mode.Off
self.Tracks[i].KnobCenter = int(IsValid & IsEnabledAuto)
elif self.Page == mcu_pages.Equalizer:
if self.McuDevice.isExtender or i >= 6:
# disable encoders on extenders and tracks > 6
self.Tracks[i].SliderEventID = -1
self.Tracks[i].KnobEventID = -1
self.Tracks[i].KnobMode = mcu_knob_mode.Off
elif i < 3:
# gain & freq
self.Tracks[i].SliderEventID = CurID + midi.REC_Mixer_EQ_Gain + i
self.Tracks[i].KnobResetEventID = self.Tracks[i].SliderEventID
s = mixer.getEventIDName(self.Tracks[i].SliderEventID)
self.Tracks[i].SliderName = s
self.Tracks[i].KnobEventID = CurID + midi.REC_Mixer_EQ_Freq + i
s = mixer.getEventIDName(self.Tracks[i].KnobEventID)
self.Tracks[i].KnobName = s
self.Tracks[i].KnobResetValue = midi.FromMIDI_Max >> 1
self.Tracks[i].KnobCenter = -2
self.Tracks[i].KnobMode = mcu_knob_mode.SingleDot
else:
# Q
self.Tracks[i].SliderEventID = CurID + midi.REC_Mixer_EQ_Q + i - 3
self.Tracks[i].KnobResetEventID = self.Tracks[i].SliderEventID
s = mixer.getEventIDName(self.Tracks[i].SliderEventID)
self.Tracks[i].SliderName = s
self.Tracks[i].KnobEventID = self.Tracks[i].SliderEventID
self.Tracks[i].KnobName = self.Tracks[i].SliderName
self.Tracks[i].KnobResetValue = 17500
self.Tracks[i].KnobCenter = -1
self.Tracks[i].KnobMode = mcu_knob_mode.Wrap
# self.Flip knob & slider
if self.Flip:
self.Tracks[i].KnobEventID, self.Tracks[i].SliderEventID = utils.SwapInt(self.Tracks[i].KnobEventID, self.Tracks[i].SliderEventID)
s = self.Tracks[i].SliderName
self.Tracks[i].SliderName = self.Tracks[i].KnobName
self.Tracks[i].KnobName = s
self.Tracks[i].KnobMode = mcu_knob_mode.Wrap
if not (self.Page in [mcu_pages.Sends, mcu_pages.Effects, mcu_pages.Equalizer if self.McuDevice.isExtender else -1 ]):
self.Tracks[i].KnobCenter = -1
self.Tracks[i].KnobResetValue = round(12800 * midi.FromMIDI_Max / 16000)
self.Tracks[i].KnobResetEventID = self.Tracks[i].KnobEventID
self.UpdateTrack(i)
def UpdateTrack(self, Num):
""" Updates the sliders, buttons & rotary encoders for a specific track """
# do not process tracks above 8 on extenders
if self.McuDevice.isExtender and Num >= 8:
return
if device.isAssigned():
if self.Page == mcu_pages.Free:
baseID = midi.EncodeRemoteControlID(device.getPortNumber(), 0, self.Tracks[Num].BaseEventID)
# slider
sliderValue = self.FreeCtrlT[self.Tracks[Num].TrackNum]
self.McuDevice.GetTrack(Num).fader.SetLevel(sliderValue, True)
#encoder knobs
if Num < 8:
# ring
d = mixer.remoteFindEventValue(baseID + int(self.Tracks[Num].KnobHeld)) # float 0.0-1.0
if d >= 0:
value = 1 + round(d * 10) # 1-11
self.McuDevice.GetTrack(Num).knob.setLedsValue(mcu_knob_mode.SingleDot, False, value)
else:
if self.Tracks[Num].KnobHeld:
self.McuDevice.GetTrack(Num).knob.setLedsValueAll()
else:
self.McuDevice.GetTrack(Num).knob.SetLedsValueNone()
# buttons
for buttonIndex in range(0, 4):
d = mixer.remoteFindEventValue(baseID + 3 + buttonIndex)
buttonActive = d >= 0.5 if d >= 0 else False
self.McuDevice.GetTrack(Num).buttons.SetButtonByIndex(buttonIndex, buttonActive, True)
else:
sv = mixer.getEventValue(self.Tracks[Num].SliderEventID)
if Num < 8:
# V-Pot
center = self.Tracks[Num].KnobCenter
knobMode = self.Tracks[Num].KnobMode
value = 0
if self.Tracks[Num].KnobEventID >= 0:
m = mixer.getEventValue(self.Tracks[Num].KnobEventID, midi.MaxInt, False)
if center < 0:
if self.Tracks[Num].KnobResetEventID == self.Tracks[Num].KnobEventID:
center = int(m != self.Tracks[Num].KnobResetValue)
else:
center = int(sv != self.Tracks[Num].KnobResetValue)
if knobMode == mcu_knob_mode.SingleDot or knobMode == mcu_knob_mode.BoostCut:
value = 1 + round(m * (10 / midi.FromMIDI_Max))
elif knobMode == mcu_knob_mode.Wrap:
value = round(m * (11 / midi.FromMIDI_Max))
else:
print('Unsupported knob mode')
# device.midiOutNewMsg(midi.MIDI_CONTROLCHANGE + ((0x30 + Num) << 8) + (data1 << 16), self.Tracks[Num].LastValueIndex)
self.McuDevice.GetTrack(Num).knob.setLedsValue(knobMode, center, value)
# arm, solo, mute
self.McuDevice.GetTrack(Num).buttons.SetArmButton(mixer.isTrackArmed(self.Tracks[Num].TrackNum), transport.isRecording(), True)
self.McuDevice.GetTrack(Num).buttons.SetSoloButton(mixer.isTrackSolo(self.Tracks[Num].TrackNum), True)
self.McuDevice.GetTrack(Num).buttons.SetMuteButton(not mixer.isTrackEnabled(self.Tracks[Num].TrackNum), True)
# slider
self.McuDevice.GetTrack(Num).fader.SetLevelFromFlsFader(sv, True)
self.Tracks[Num].Dirty = False
def OnSendMsg(self, Msg):
self.MsgT[1] = Msg
self.MsgDirty = True
def SetKnobValue(self, trackNumber, midiValue, resolution = midi.EKRes):
""" Sets the value of a knob in FL Studio (for all except free page?) (and shows it on the display) """
if not (self.Tracks[trackNumber].KnobEventID >= 0) & (self.Tracks[trackNumber].KnobMode != mcu_knob_mode.Off):
return
if midiValue == midi.MaxInt:
if self.Page == mcu_pages.Effects:
if self.Tracks[trackNumber].KnobPressEventID >= 0:
midiValue = channels.incEventValue(self.Tracks[trackNumber].KnobPressEventID, 0, midi.EKRes)
general.processRECEvent(self.Tracks[trackNumber].KnobPressEventID, midiValue, midi.REC_Controller)
s = mixer.getEventIDName(self.Tracks[trackNumber].KnobPressEventID)
self.OnSendMsg(s)
return
else:
mixer.automateEvent(self.Tracks[trackNumber].KnobResetEventID, self.Tracks[trackNumber].KnobResetValue, midi.REC_MIDIController, self.SmoothSpeed)
else:
mixer.automateEvent(self.Tracks[trackNumber].KnobEventID, midiValue, midi.REC_Controller, self.SmoothSpeed, 1, resolution)
# show the value of the knob on the display
n = mixer.getAutoSmoothEventValue(self.Tracks[trackNumber].KnobEventID)
s = mixer.getEventIDValueString(self.Tracks[trackNumber].KnobEventID, n)
if s != '':
s = ': ' + s
self.OnSendMsg(self.Tracks[trackNumber].KnobName + s)