cuemsutils 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cuemsutils/CTimecode.py +157 -0
- cuemsutils/__init__.py +4 -0
- cuemsutils/cues/ActionCue.py +124 -0
- cuemsutils/cues/AudioCue.py +282 -0
- cuemsutils/cues/Cue.py +251 -0
- cuemsutils/cues/CueList.py +160 -0
- cuemsutils/cues/CueOutput.py +13 -0
- cuemsutils/cues/CuemsScript.py +124 -0
- cuemsutils/cues/DmxCue.py +309 -0
- cuemsutils/cues/VideoCue.py +287 -0
- cuemsutils/cues/__init__.py +0 -0
- cuemsutils/log.py +77 -0
- cuemsutils/schemas/outputs.xsd +21 -0
- cuemsutils/schemas/project_mappings.xsd +74 -0
- cuemsutils/schemas/project_settings.xsd +23 -0
- cuemsutils/schemas/script.xsd +405 -0
- cuemsutils/schemas/settings.xsd +113 -0
- cuemsutils/xml/CMLCuemsConverter.py +177 -0
- cuemsutils/xml/DictParser.py +258 -0
- cuemsutils/xml/XmlBuilder.py +299 -0
- cuemsutils/xml/XmlReaderWriter.py +84 -0
- cuemsutils/xml/__init__.py +0 -0
- cuemsutils-0.0.1.dist-info/METADATA +47 -0
- cuemsutils-0.0.1.dist-info/RECORD +26 -0
- cuemsutils-0.0.1.dist-info/WHEEL +4 -0
- cuemsutils-0.0.1.dist-info/licenses/LICENSE +674 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
from threading import Thread
|
|
2
|
+
from time import sleep
|
|
3
|
+
|
|
4
|
+
from collections.abc import Mapping
|
|
5
|
+
# from os import path
|
|
6
|
+
# from pyossia import ossia
|
|
7
|
+
from Cue import Cue
|
|
8
|
+
# from ..players.DmxPlayer import DmxPlayer
|
|
9
|
+
# from ..OssiaServer import OssiaServer, OSCConfData, PlayerOSCConfData
|
|
10
|
+
from cuemsutils.log import logged, Logger
|
|
11
|
+
|
|
12
|
+
#### TODO: asegurar asignacion de escenas a cue, no copia!!
|
|
13
|
+
|
|
14
|
+
class DmxCue(Cue):
|
|
15
|
+
# OSC_DMXPLAYER_CONF = { '/quit' : [ossia.ValueType.Impulse, None],
|
|
16
|
+
# '/load' : [ossia.ValueType.String, None],
|
|
17
|
+
# '/wait' : [ossia.ValueType.Float, None],
|
|
18
|
+
# '/play' : [ossia.ValueType.Impulse, None],
|
|
19
|
+
# '/stop' : [ossia.ValueType.Impulse, None],
|
|
20
|
+
# '/stoponlost' : [ossia.ValueType.Bool, None],
|
|
21
|
+
# # TODO '/mtcfollow' : [ossia.ValueType.Bool, None],
|
|
22
|
+
# '/check' : [ossia.ValueType.Impulse, None]
|
|
23
|
+
# }
|
|
24
|
+
|
|
25
|
+
def __init__(self, init_dict = None):
|
|
26
|
+
super().__init__(init_dict)
|
|
27
|
+
|
|
28
|
+
self._player = None
|
|
29
|
+
self._osc_route = None
|
|
30
|
+
self._offset_route = '/offset'
|
|
31
|
+
|
|
32
|
+
# self.OSC_DMXPLAYER_CONF[self._offset_route] = [ossia.ValueType.Float, None]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def media(self):
|
|
37
|
+
return super().__getitem__('Media')
|
|
38
|
+
|
|
39
|
+
@media.setter
|
|
40
|
+
def media(self, media):
|
|
41
|
+
super().__setitem__('Media', media)
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def fadein_time(self):
|
|
45
|
+
return super().__getitem__('fadein_time')
|
|
46
|
+
|
|
47
|
+
@fadein_time.setter
|
|
48
|
+
def fadein_time(self, fadein_time):
|
|
49
|
+
super().__setitem__('fadein_time', fadein_time)
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def fadeout_time(self):
|
|
53
|
+
return super().__getitem__('fadeout_time')
|
|
54
|
+
|
|
55
|
+
@fadeout_time.setter
|
|
56
|
+
def fadeout_time(self, fadeout_time):
|
|
57
|
+
super().__setitem__('fadeout_time', fadeout_time)
|
|
58
|
+
|
|
59
|
+
def player(self, player):
|
|
60
|
+
self._player = player
|
|
61
|
+
|
|
62
|
+
def osc_route(self, osc_route):
|
|
63
|
+
self._osc_route = osc_route
|
|
64
|
+
|
|
65
|
+
def offset_route(self, offset_route):
|
|
66
|
+
self._offset_route = offset_route
|
|
67
|
+
|
|
68
|
+
def review_offset(self, timecode):
|
|
69
|
+
return -(float(timecode.milliseconds))
|
|
70
|
+
|
|
71
|
+
def arm(self, conf, ossia, armed_list, init = False):
|
|
72
|
+
self._conf = conf
|
|
73
|
+
self._armed_list = armed_list
|
|
74
|
+
|
|
75
|
+
if not self.enabled:
|
|
76
|
+
if self.loaded and self in self._armed_list:
|
|
77
|
+
self.disarm(ossia)
|
|
78
|
+
return False
|
|
79
|
+
elif self.loaded and not init:
|
|
80
|
+
if not self in self._armed_list:
|
|
81
|
+
self._armed_list.append(self)
|
|
82
|
+
return True
|
|
83
|
+
|
|
84
|
+
# Assign its own audioplayer object
|
|
85
|
+
# try:
|
|
86
|
+
# self._player = DmxPlayer(
|
|
87
|
+
# self._conf.players_port_index,
|
|
88
|
+
# self._conf.node_conf['dmxplayer']['path'],
|
|
89
|
+
# str(self._conf.node_conf['dmxplayer']['args']),
|
|
90
|
+
# str(
|
|
91
|
+
# path.join(
|
|
92
|
+
# self._conf.library_path,
|
|
93
|
+
# 'media',
|
|
94
|
+
# self.media['file_name']
|
|
95
|
+
# )
|
|
96
|
+
# )
|
|
97
|
+
# )
|
|
98
|
+
# except Exception as e:
|
|
99
|
+
# raise e
|
|
100
|
+
|
|
101
|
+
# self._player.start()
|
|
102
|
+
|
|
103
|
+
# And dinamically attach it to the ossia for remote control it
|
|
104
|
+
self._osc_route = f'/players/dmxplayer-{self.uuid}'
|
|
105
|
+
|
|
106
|
+
# ossia.add_player_nodes(
|
|
107
|
+
# PlayerOSCConfData(
|
|
108
|
+
# device_name=self._osc_route,
|
|
109
|
+
# host=self._conf.node_conf['osc_dest_host'],
|
|
110
|
+
# in_port=self._player.port,
|
|
111
|
+
# out_port=self._player.port + 1,
|
|
112
|
+
# dictionary=self.OSC_DMXPLAYER_CONF
|
|
113
|
+
# )
|
|
114
|
+
# )
|
|
115
|
+
|
|
116
|
+
self.loaded = True
|
|
117
|
+
if not self in self._armed_list:
|
|
118
|
+
self._armed_list.append(self)
|
|
119
|
+
|
|
120
|
+
if self.post_go == 'go' and self._target_object:
|
|
121
|
+
self._target_object.arm(self._conf, ossia, self._armed_list, init)
|
|
122
|
+
|
|
123
|
+
return True
|
|
124
|
+
|
|
125
|
+
@logged
|
|
126
|
+
def go(self, ossia, mtc):
|
|
127
|
+
if not self.loaded:
|
|
128
|
+
raise Exception(f'{self.__class__.__name__} {self.uuid} not loaded to go')
|
|
129
|
+
else:
|
|
130
|
+
# THREADED GO
|
|
131
|
+
thread = Thread(
|
|
132
|
+
name = f'GO:{self.__class__.__name__}:{self.uuid}',
|
|
133
|
+
target = self.go_thread,
|
|
134
|
+
args = [ossia, mtc]
|
|
135
|
+
)
|
|
136
|
+
thread.start()
|
|
137
|
+
|
|
138
|
+
def go_thread(self, ossia, mtc):
|
|
139
|
+
# ARM NEXT TARGET
|
|
140
|
+
if self._target_object:
|
|
141
|
+
self._target_object.arm(self._conf, ossia, self._armed_list)
|
|
142
|
+
|
|
143
|
+
# PREWAIT
|
|
144
|
+
if self.prewait > 0:
|
|
145
|
+
sleep(self.prewait.milliseconds / 1000)
|
|
146
|
+
|
|
147
|
+
# PLAY : specific DMX cue stuff
|
|
148
|
+
try:
|
|
149
|
+
key = f'{self._osc_route}{self._offset_route}'
|
|
150
|
+
ossia.osc_registered_nodes[key][0].value = self.review_offset(mtc)
|
|
151
|
+
Logger.log_info(
|
|
152
|
+
f"DMX play {self.uuid}: {key} {str(ossia.osc_registered_nodes[key][0].value)}",
|
|
153
|
+
extra = {"caller": self.__class__.__name__}
|
|
154
|
+
)
|
|
155
|
+
except KeyError:
|
|
156
|
+
Logger.log_debug(
|
|
157
|
+
f'OSC Key error 1 in go_callback {key}',
|
|
158
|
+
extra = {"caller": self.__class__.__name__}
|
|
159
|
+
)
|
|
160
|
+
try:
|
|
161
|
+
key = f'{self._osc_route}/mtcfollow'
|
|
162
|
+
ossia.osc_registered_nodes[key][0].value = True
|
|
163
|
+
except KeyError:
|
|
164
|
+
Logger.log_debug(
|
|
165
|
+
f'OSC Key error 2 in go_callback {key}',
|
|
166
|
+
extra = {"caller": self.__class__.__name__}
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# POSTWAIT
|
|
170
|
+
if self.postwait > 0:
|
|
171
|
+
sleep(self.postwait.milliseconds / 1000)
|
|
172
|
+
|
|
173
|
+
# POST-GO GO
|
|
174
|
+
if self.post_go == 'go' and self._target_object:
|
|
175
|
+
self._target_object.go(ossia, mtc)
|
|
176
|
+
|
|
177
|
+
try:
|
|
178
|
+
while self._player.is_alive():
|
|
179
|
+
sleep(0.05)
|
|
180
|
+
except AttributeError:
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
if self in self._armed_list:
|
|
184
|
+
self.disarm(ossia)
|
|
185
|
+
|
|
186
|
+
def disarm(self, ossia):
|
|
187
|
+
if self.loaded is True:
|
|
188
|
+
try:
|
|
189
|
+
self._player.kill()
|
|
190
|
+
self._conf.players_port_index['used'].remove(self._player.port)
|
|
191
|
+
self._player.join()
|
|
192
|
+
self._player = None
|
|
193
|
+
|
|
194
|
+
# ossia.remove_nodes( OSCConfData(device_name=self._osc_route, dictionary = self.OSC_DMXPLAYER_CONF) )
|
|
195
|
+
|
|
196
|
+
except Exception as e:
|
|
197
|
+
Logger.log_warning(
|
|
198
|
+
f'Could not properly unload {self.uuid} : {e}',
|
|
199
|
+
extra = {"caller": self.__class__.__name__}
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
try:
|
|
203
|
+
if self in self._armed_list:
|
|
204
|
+
self._armed_list.remove(self)
|
|
205
|
+
except:
|
|
206
|
+
pass
|
|
207
|
+
|
|
208
|
+
self.loaded = False
|
|
209
|
+
|
|
210
|
+
return True
|
|
211
|
+
else:
|
|
212
|
+
return False
|
|
213
|
+
|
|
214
|
+
@property
|
|
215
|
+
def scene(self):
|
|
216
|
+
return self['dmx_scene']
|
|
217
|
+
|
|
218
|
+
@scene.setter
|
|
219
|
+
def scene(self, scene):
|
|
220
|
+
if isinstance(scene, DmxScene):
|
|
221
|
+
super().__setitem__('dmx_scene', scene)
|
|
222
|
+
elif isinstance(scene, dict):
|
|
223
|
+
super().__setitem__('dmx_scene', DmxScene(init_dict=scene))
|
|
224
|
+
else:
|
|
225
|
+
raise NotImplementedError
|
|
226
|
+
|
|
227
|
+
class DmxScene(dict):
|
|
228
|
+
def __init__(self, init_dict=None):
|
|
229
|
+
super().__init__()
|
|
230
|
+
if init_dict:
|
|
231
|
+
for k, v, in init_dict.items():
|
|
232
|
+
if isinstance(k, int):
|
|
233
|
+
super().__setitem__(k, DmxUniverse(v))
|
|
234
|
+
elif k == 'DmxUniverse':
|
|
235
|
+
for u in v:
|
|
236
|
+
super().__setitem__(u['id'], DmxUniverse(init_dict=u))
|
|
237
|
+
|
|
238
|
+
def universe(self, num=None):
|
|
239
|
+
if num is not None:
|
|
240
|
+
return super().__getitem__(num)
|
|
241
|
+
|
|
242
|
+
def universes(self):
|
|
243
|
+
return self
|
|
244
|
+
|
|
245
|
+
def set_universe(self, universe, num=0):
|
|
246
|
+
super().__setitem__(num, DmxUniverse(universe))
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
#merge two universes, priority on the newcoming
|
|
251
|
+
def merge_universe(self, universe, num=0):
|
|
252
|
+
super().__getitem__(num).update(universe)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
class DmxUniverse(dict):
|
|
257
|
+
|
|
258
|
+
def __init__(self, init_dict=None):
|
|
259
|
+
super().__init__()
|
|
260
|
+
if init_dict:
|
|
261
|
+
for k, v, in init_dict.items():
|
|
262
|
+
if isinstance(k, int):
|
|
263
|
+
super().__setitem__(k, DmxChannel(v))
|
|
264
|
+
elif k == 'DmxChannel':
|
|
265
|
+
for u in v:
|
|
266
|
+
super().__setitem__(u['id'], DmxChannel(u['&']))
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def channel(self, channel):
|
|
271
|
+
return super().__getitem__(channel)
|
|
272
|
+
|
|
273
|
+
def set_channel(self, channel, value):
|
|
274
|
+
if isinstance(value, DmxChannel):
|
|
275
|
+
super().__setitem__(channel, value)
|
|
276
|
+
else:
|
|
277
|
+
super().__setitem__(channel, DmxChannel(value))
|
|
278
|
+
return self
|
|
279
|
+
|
|
280
|
+
def setall(self, value):
|
|
281
|
+
for channel in range(512):
|
|
282
|
+
super().__setitem__(channel, value)
|
|
283
|
+
return self #TODO: valorate return self to be able to do things like 'universe_full = DmxUniverse().setall(255)'
|
|
284
|
+
|
|
285
|
+
def update(self, other=None, **kwargs):
|
|
286
|
+
if other is not None:
|
|
287
|
+
for k, v in other.items() if isinstance(other, Mapping) else other:
|
|
288
|
+
self[k] = DmxChannel(v)
|
|
289
|
+
for k, v in kwargs.items():
|
|
290
|
+
self[k] = DmxChannel(v)
|
|
291
|
+
|
|
292
|
+
class DmxChannel():
|
|
293
|
+
def __init__(self, value=None, init_dict = None):
|
|
294
|
+
self._value = value
|
|
295
|
+
if init_dict is not None:
|
|
296
|
+
self.value = init_dict
|
|
297
|
+
|
|
298
|
+
def __repr__(self):
|
|
299
|
+
return str(self.value)
|
|
300
|
+
|
|
301
|
+
@property
|
|
302
|
+
def value(self):
|
|
303
|
+
return self._value
|
|
304
|
+
|
|
305
|
+
@value.setter
|
|
306
|
+
def value (self, value):
|
|
307
|
+
if value > 255:
|
|
308
|
+
value = 255
|
|
309
|
+
self._value = value
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
from os import path
|
|
2
|
+
# from pyossia import ossia
|
|
3
|
+
from threading import Thread
|
|
4
|
+
from time import sleep
|
|
5
|
+
|
|
6
|
+
from Cue import Cue
|
|
7
|
+
from cuemsutils.CTimecode import CTimecode
|
|
8
|
+
# from ..players.VideoPlayer import VideoPlayer
|
|
9
|
+
# from ..OssiaServer import OssiaServer, OSCConfData, PlayerOSCConfData
|
|
10
|
+
from cuemsutils.log import logged, Logger
|
|
11
|
+
class VideoCue(Cue):
|
|
12
|
+
'''
|
|
13
|
+
OSC_VIDEOPLAYER_CONF = {'/jadeo/xscale' : [ossia.ValueType.Float, None],
|
|
14
|
+
'/jadeo/yscale' : [ossia.ValueType.Float, None],
|
|
15
|
+
'/jadeo/corners' : [ossia.ValueType.List, None],
|
|
16
|
+
'/jadeo/corner1' : [ossia.ValueType.List, None],
|
|
17
|
+
'/jadeo/corner2' : [ossia.ValueType.List, None],
|
|
18
|
+
'/jadeo/corner3' : [ossia.ValueType.List, None],
|
|
19
|
+
'/jadeo/corner4' : [ossia.ValueType.List, None],
|
|
20
|
+
'/jadeo/start' : [ossia.ValueType.Bool, None],
|
|
21
|
+
'/jadeo/load' : [ossia.ValueType.String, None],
|
|
22
|
+
'/jadeo/quit' : [ossia.ValueType.Bool, None],
|
|
23
|
+
'/jadeo/midi/connect' : [ossia.ValueType.String, None],
|
|
24
|
+
'/jadeo/midi/disconnect' : [ossia.ValueType.Impulse, None]
|
|
25
|
+
}
|
|
26
|
+
'''
|
|
27
|
+
|
|
28
|
+
def __init__(self, init_dict = None):
|
|
29
|
+
super().__init__(init_dict)
|
|
30
|
+
|
|
31
|
+
self._player = None
|
|
32
|
+
self._osc_route = None
|
|
33
|
+
self._go_thread = None
|
|
34
|
+
|
|
35
|
+
# TODO: Adjust framerates for universal use, by now 25 fps for video
|
|
36
|
+
self._start_mtc = CTimecode(framerate=25)
|
|
37
|
+
self._end_mtc = CTimecode(framerate=25)
|
|
38
|
+
|
|
39
|
+
'''
|
|
40
|
+
self.OSC_VIDEOPLAYER_CONF['/jadeo/offset'] = [ossia.ValueType.String, None]
|
|
41
|
+
self.OSC_VIDEOPLAYER_CONF['/jadeo/offset'] = [ossia.ValueType.Int, None]
|
|
42
|
+
'''
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def media(self):
|
|
46
|
+
return super().__getitem__('Media')
|
|
47
|
+
|
|
48
|
+
@media.setter
|
|
49
|
+
def media(self, media):
|
|
50
|
+
super().__setitem__('Media', media)
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def outputs(self):
|
|
54
|
+
return super().__getitem__('Outputs')
|
|
55
|
+
|
|
56
|
+
@outputs.setter
|
|
57
|
+
def outputs(self, outputs):
|
|
58
|
+
super().__setitem__('Outputs', outputs)
|
|
59
|
+
|
|
60
|
+
def player(self, player):
|
|
61
|
+
self._player = player
|
|
62
|
+
|
|
63
|
+
def osc_route(self, osc_route):
|
|
64
|
+
self._osc_route = osc_route
|
|
65
|
+
|
|
66
|
+
def arm(self, conf, ossia, armed_list, init = False):
|
|
67
|
+
self._conf = conf
|
|
68
|
+
self._armed_list = armed_list
|
|
69
|
+
|
|
70
|
+
if not self.enabled:
|
|
71
|
+
if self.loaded and self in self._armed_list:
|
|
72
|
+
self.disarm(ossia)
|
|
73
|
+
return False
|
|
74
|
+
elif self.loaded and not init:
|
|
75
|
+
if not self in self._armed_list:
|
|
76
|
+
self._armed_list.append(self)
|
|
77
|
+
return True
|
|
78
|
+
|
|
79
|
+
if self._local:
|
|
80
|
+
try:
|
|
81
|
+
key = f'{self._osc_route}/jadeo/cmd'
|
|
82
|
+
ossia.send_message(key, 'midi disconnect')
|
|
83
|
+
Logger.log_info(
|
|
84
|
+
key + " " + str(ossia._oscquery_registered_nodes[key][0].value),
|
|
85
|
+
extra = {"caller": self.__class__.__name__}
|
|
86
|
+
)
|
|
87
|
+
except KeyError:
|
|
88
|
+
Logger.log_debug(
|
|
89
|
+
f'Key error 1 (disconnect) in arm_callback {key}',
|
|
90
|
+
extra = {"caller": self.__class__.__name__}
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
key = f'{self._osc_route}/jadeo/load'
|
|
95
|
+
value = str(path.join(self._conf.library_path, 'media', self.media.file_name))
|
|
96
|
+
ossia.send_message(key, value)
|
|
97
|
+
Logger.log_info(
|
|
98
|
+
key + " " + str(ossia._oscquery_registered_nodes[key][0].value),
|
|
99
|
+
extra = {"caller": self.__class__.__name__}
|
|
100
|
+
)
|
|
101
|
+
except KeyError:
|
|
102
|
+
Logger.log_debug(
|
|
103
|
+
f'Key error 2 (load) in arm_callback {key}',
|
|
104
|
+
extra = {"caller": self.__class__.__name__}
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
self.loaded = True
|
|
108
|
+
if not self in self._armed_list:
|
|
109
|
+
self._armed_list.append(self)
|
|
110
|
+
|
|
111
|
+
if self.post_go == 'go' and self._target_object:
|
|
112
|
+
self._target_object.arm(self._conf, ossia, self._armed_list, init)
|
|
113
|
+
|
|
114
|
+
return True
|
|
115
|
+
|
|
116
|
+
@logged
|
|
117
|
+
def go(self, ossia, mtc):
|
|
118
|
+
if not self.loaded:
|
|
119
|
+
raise Exception(f'{self.__class__.__name__} {self.uuid} not loaded to go')
|
|
120
|
+
else:
|
|
121
|
+
# THREADED GO
|
|
122
|
+
self._go_thread = Thread(name = f'GO:{self.__class__.__name__}:{self.uuid}', target = self.go_thread_func, args = [ossia, mtc])
|
|
123
|
+
self._go_thread.start()
|
|
124
|
+
|
|
125
|
+
def go_thread_func(self, ossia, mtc):
|
|
126
|
+
# ARM NEXT TARGET
|
|
127
|
+
if self._target_object:
|
|
128
|
+
self._target_object.arm(self._conf, ossia, self._armed_list)
|
|
129
|
+
|
|
130
|
+
# PREWAIT
|
|
131
|
+
if self.prewait > 0:
|
|
132
|
+
sleep(self.prewait.milliseconds / 1000)
|
|
133
|
+
|
|
134
|
+
### harcoded for TODO: proto_fruta, need fixx
|
|
135
|
+
#try to make all cues start at sync at 10 second timecode!
|
|
136
|
+
harcoded_go_offset = 20000
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
if self._local:
|
|
140
|
+
# PLAY : specific video cue stuff
|
|
141
|
+
try:
|
|
142
|
+
key = f'{self._osc_route}/jadeo/offset'
|
|
143
|
+
#self._start_mtc = mtc.main_tc
|
|
144
|
+
|
|
145
|
+
### harcoded for TODO: proto_fruta, need fixx
|
|
146
|
+
self._start_mtc = CTimecode(frames=harcoded_go_offset)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
duration = self.media.regions[0].out_time - self.media.regions[0].in_time
|
|
150
|
+
duration = duration.return_in_other_framerate(mtc.main_tc.framerate)
|
|
151
|
+
self._end_mtc = self._start_mtc + duration
|
|
152
|
+
cue_in_time_fr_adjusted = self.media.regions[0].in_time.return_in_other_framerate(mtc.main_tc.framerate)
|
|
153
|
+
offset_to_go = cue_in_time_fr_adjusted.frame_number - self._start_mtc.frame_number
|
|
154
|
+
# ossia._oscquery_registered_nodes[key][0].value = offset_to_go
|
|
155
|
+
ossia.send_message(key, offset_to_go)
|
|
156
|
+
Logger.log_info(
|
|
157
|
+
key + " " + str(ossia._oscquery_registered_nodes[key][0].value),
|
|
158
|
+
extra = {"caller": self.__class__.__name__}
|
|
159
|
+
)
|
|
160
|
+
except KeyError:
|
|
161
|
+
Logger.log_debug(
|
|
162
|
+
f'Key error 1 (offset) in go_callback {key}',
|
|
163
|
+
extra = {"caller": self.__class__.__name__}
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
try:
|
|
167
|
+
key = f'{self._osc_route}/jadeo/cmd'
|
|
168
|
+
ossia.send_message(key, "midi connect Midi Through")
|
|
169
|
+
except KeyError:
|
|
170
|
+
Logger.log_debug(
|
|
171
|
+
f'Key error 2 (connect) in go_callback {key}',
|
|
172
|
+
extra = {"caller": self.__class__.__name__}
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# POSTWAIT
|
|
176
|
+
if self.postwait > 0:
|
|
177
|
+
sleep(self.postwait.milliseconds / 1000)
|
|
178
|
+
|
|
179
|
+
if self.post_go == 'go' and self._target_object:
|
|
180
|
+
self._target_object.go(ossia, mtc)
|
|
181
|
+
|
|
182
|
+
try:
|
|
183
|
+
loop_counter = 0
|
|
184
|
+
duration = self.media.regions[0].out_time - self.media.regions[0].in_time
|
|
185
|
+
duration = duration.return_in_other_framerate(mtc.main_tc.framerate)
|
|
186
|
+
in_time_adjusted = self.media.regions[0].in_time.return_in_other_framerate(mtc.main_tc.framerate)
|
|
187
|
+
|
|
188
|
+
while not self.media.regions[0].loop or loop_counter < self.media.regions[0].loop:
|
|
189
|
+
while mtc.main_tc.milliseconds < self._end_mtc.milliseconds:
|
|
190
|
+
sleep(0.005)
|
|
191
|
+
|
|
192
|
+
if self._local:
|
|
193
|
+
try:
|
|
194
|
+
key = f'{self._osc_route}/jadeo/offset'
|
|
195
|
+
self._start_mtc = mtc.main_tc
|
|
196
|
+
self._end_mtc = self._start_mtc + duration
|
|
197
|
+
offset_to_go = in_time_adjusted.frame_number - self._start_mtc.frame_number
|
|
198
|
+
ossia.send_message(key, offset_to_go)
|
|
199
|
+
Logger.log_info(
|
|
200
|
+
key + " " + str(ossia._oscquery_registered_nodes[key][0].value),
|
|
201
|
+
extra = {"caller": self.__class__.__name__}
|
|
202
|
+
)
|
|
203
|
+
except KeyError:
|
|
204
|
+
Logger.log_debug(
|
|
205
|
+
f'Key error 1 (offset) in go_callback {key}',
|
|
206
|
+
extra = {"caller": self.__class__.__name__}
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
loop_counter += 1
|
|
210
|
+
|
|
211
|
+
if self._local:
|
|
212
|
+
try:
|
|
213
|
+
key = f'{self._osc_route}/jadeo/cmd'
|
|
214
|
+
ossia.send_message(key, 'midi disconnect')
|
|
215
|
+
Logger.log_info(
|
|
216
|
+
key + " " + str(ossia._oscquery_registered_nodes[key][0].value),
|
|
217
|
+
extra = {"caller": self.__class__.__name__}
|
|
218
|
+
)
|
|
219
|
+
except KeyError:
|
|
220
|
+
Logger.log_debug(
|
|
221
|
+
f'Key error 1 (disconnect) in arm_callback {key}',
|
|
222
|
+
extra = {"caller": self.__class__.__name__}
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
except AttributeError:
|
|
226
|
+
pass
|
|
227
|
+
|
|
228
|
+
if self in self._armed_list:
|
|
229
|
+
self.disarm(ossia)
|
|
230
|
+
|
|
231
|
+
def disarm(self, ossia = None):
|
|
232
|
+
if self.loaded is True:
|
|
233
|
+
'''
|
|
234
|
+
# Needed when each cue launched its own player
|
|
235
|
+
try:
|
|
236
|
+
self._player.kill()
|
|
237
|
+
self._conf.osc_port_index['used'].remove(self._player.port)
|
|
238
|
+
self._player.join()
|
|
239
|
+
self._player = None
|
|
240
|
+
|
|
241
|
+
ossia.remove_nodes( OSCConfData(device_name=self._osc_route, dictionary = self.OSC_VIDEOPLAYER_CONF) )
|
|
242
|
+
|
|
243
|
+
except Exception as e:
|
|
244
|
+
logger.warning(f'Could not properly unload {self.__class__.__name__} {self.uuid} : {e}')
|
|
245
|
+
'''
|
|
246
|
+
|
|
247
|
+
try:
|
|
248
|
+
if self in self._armed_list:
|
|
249
|
+
self._armed_list.remove(self)
|
|
250
|
+
except:
|
|
251
|
+
pass
|
|
252
|
+
|
|
253
|
+
self.loaded = False
|
|
254
|
+
|
|
255
|
+
return True
|
|
256
|
+
else:
|
|
257
|
+
return False
|
|
258
|
+
|
|
259
|
+
def stop(self):
|
|
260
|
+
self._stop_requested = True
|
|
261
|
+
|
|
262
|
+
def check_mappings(self, settings):
|
|
263
|
+
if not settings.project_node_mappings:
|
|
264
|
+
return True
|
|
265
|
+
|
|
266
|
+
found = True
|
|
267
|
+
|
|
268
|
+
map_list = ['default']
|
|
269
|
+
|
|
270
|
+
if settings.project_node_mappings['video']['outputs']:
|
|
271
|
+
for elem in settings.project_node_mappings['video']['outputs']:
|
|
272
|
+
for map in elem['mappings']:
|
|
273
|
+
map_list.append(map['mapped_to'])
|
|
274
|
+
|
|
275
|
+
for output in self.outputs:
|
|
276
|
+
# if output['node_uuid'] == settings.node_conf['uuid']:
|
|
277
|
+
|
|
278
|
+
if output['output_name'][:36] == settings.node_conf['uuid']:
|
|
279
|
+
self._local = True
|
|
280
|
+
if output['output_name'][37:] not in map_list:
|
|
281
|
+
found = False
|
|
282
|
+
break
|
|
283
|
+
else:
|
|
284
|
+
self._local = False
|
|
285
|
+
found = True
|
|
286
|
+
|
|
287
|
+
return found
|
|
File without changes
|
cuemsutils/log.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from logging import getLogger, StreamHandler, Formatter, DEBUG, INFO, ERROR, WARNING
|
|
3
|
+
from logging.handlers import SysLogHandler
|
|
4
|
+
from functools import wraps
|
|
5
|
+
|
|
6
|
+
cuemsFormatter = Formatter('[%(asctime)s][%(levelname)s] \tFormitGo (PID: %(process)d)-(%(threadName)-9s)-(%(name)s:%(funcName)s:%(caller)s)> %(message)s')
|
|
7
|
+
|
|
8
|
+
def root_logger(with_syslog = True, with_stdout = True):
|
|
9
|
+
"""
|
|
10
|
+
Create a root logger with a custom formatter.
|
|
11
|
+
"""
|
|
12
|
+
logger = getLogger()
|
|
13
|
+
logger.setLevel(DEBUG)
|
|
14
|
+
|
|
15
|
+
if with_stdout:
|
|
16
|
+
sh = StreamHandler(sys.stdout)
|
|
17
|
+
sh.setFormatter(cuemsFormatter)
|
|
18
|
+
logger.addHandler(sh)
|
|
19
|
+
|
|
20
|
+
if with_syslog:
|
|
21
|
+
syslog_handler = SysLogHandler(
|
|
22
|
+
address = '/dev/log', facility = 'local0'
|
|
23
|
+
)
|
|
24
|
+
syslog_handler.setFormatter(cuemsFormatter)
|
|
25
|
+
logger.addHandler(syslog_handler)
|
|
26
|
+
|
|
27
|
+
return logger
|
|
28
|
+
|
|
29
|
+
class Logger:
|
|
30
|
+
logger = root_logger()
|
|
31
|
+
|
|
32
|
+
@staticmethod
|
|
33
|
+
def log(level, message, extra):
|
|
34
|
+
Logger.logger.log(level, message, stacklevel = 4, extra = extra)
|
|
35
|
+
|
|
36
|
+
@staticmethod
|
|
37
|
+
def log_debug(message, extra = {"caller": ''}):
|
|
38
|
+
Logger.log(DEBUG, message, extra = extra)
|
|
39
|
+
|
|
40
|
+
@staticmethod
|
|
41
|
+
def log_info(message, extra = {"caller": ''}):
|
|
42
|
+
Logger.log(INFO, message, extra = extra)
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def log_error(message, extra = {"caller": ''}):
|
|
46
|
+
Logger.log(ERROR, message, extra = extra)
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
def log_warning(message, extra = {"caller": ''}):
|
|
50
|
+
Logger.log(WARNING, message, extra = extra)
|
|
51
|
+
|
|
52
|
+
def logged(func):
|
|
53
|
+
"""
|
|
54
|
+
A decorator function to log information about function calls and their results.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
@wraps(func)
|
|
58
|
+
def wrapper(*args, **kwargs):
|
|
59
|
+
"""
|
|
60
|
+
The wrapper function that logs function calls and their results.
|
|
61
|
+
"""
|
|
62
|
+
d = {"caller": func.__name__}
|
|
63
|
+
Logger.logger = getLogger(func.__module__)
|
|
64
|
+
Logger.log_info(f"Call recieved", extra = d)
|
|
65
|
+
Logger.log_debug(f"Using args: {args} and kwargs: {kwargs}", extra = d)
|
|
66
|
+
try:
|
|
67
|
+
result = func(*args, **kwargs)
|
|
68
|
+
Logger.log_debug(f"Finished with result: {result}", extra = d)
|
|
69
|
+
|
|
70
|
+
except Exception as e:
|
|
71
|
+
Logger.log_error(f"Error occurred: {e}", extra = d)
|
|
72
|
+
raise
|
|
73
|
+
|
|
74
|
+
else:
|
|
75
|
+
return result
|
|
76
|
+
|
|
77
|
+
return wrapper
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<xs:schema targetNamespace="http://stagelab.net/cuems" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:cms="http://stagelab.net/cuems">
|
|
3
|
+
<xs:element name="CuemsOutputs">
|
|
4
|
+
<xs:complexType>
|
|
5
|
+
<xs:sequence>
|
|
6
|
+
<xs:element name="video_outputs" type="cms:OutputsType" />
|
|
7
|
+
<xs:element name="default_video_output" type="xs:string" />
|
|
8
|
+
<xs:element name="audio_outputs" type="cms:OutputsType" />
|
|
9
|
+
<xs:element name="default_audio_output" type="xs:string" />
|
|
10
|
+
</xs:sequence>
|
|
11
|
+
</xs:complexType>
|
|
12
|
+
</xs:element>
|
|
13
|
+
|
|
14
|
+
<!-- TYPES DEFINITIONS -->
|
|
15
|
+
<xs:complexType name="OutputsType">
|
|
16
|
+
<xs:sequence>
|
|
17
|
+
<xs:element name="output" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
|
|
18
|
+
</xs:sequence>
|
|
19
|
+
</xs:complexType>
|
|
20
|
+
|
|
21
|
+
</xs:schema>
|