-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathgenerateTimecode.py
More file actions
220 lines (179 loc) · 5.48 KB
/
generateTimecode.py
File metadata and controls
220 lines (179 loc) · 5.48 KB
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
#!/usr/bin/env python3
"""
Sends a full frame MTC packet to a given address.
MTC calculated based on https://en.wikipedia.org/wiki/MIDI_timecode
Qurater-frames are not handled, nor are they needed. Full frames only.
"""
__version__ = "0.2.5"
import argparse
import math
import time
# Handle the arguments
parser = argparse.ArgumentParser()
timecodeArgs = parser.add_argument_group("Timecode")
ipArgs = parser.add_argument_group("IP")
timecodeArgs.add_argument(
"-f",
"--startFrame",
type=int,
help="The frame to start on",
action="store",
default=0,
)
timecodeArgs.add_argument(
"-r",
"--framerate",
type=int,
help="what framerate to use",
action="store",
choices=[24, 25, 29, 30],
default=30,
)
timecodeArgs.add_argument(
"-e",
"--endFrame",
type=int,
help="The last frame in the timecode sequence",
action="store",
default=None,
)
timecodeArgs.add_argument(
"-R",
"--rollover",
help="Determines if the code should rollover when end frame is hit",
action="store_true",
default=False,
)
ipArgs.add_argument(
"-a",
"--ipAddress",
help="The IP Address to send to. Defaults to localhost",
action="store",
default="127.0.0.1",
)
ipArgs.add_argument(
"-b",
"--bindAddress",
help="The Source IP Address. Defaults to localhost",
action="store",
default="",
)
ipArgs.add_argument(
"-p", "--port", help="The port to send to.", action="store", type=int, default=5005
)
args = parser.parse_args()
# TODO: Might want to make this a class so its easier to work with
# Now that we've got our arguments sorted lets do something with them
frame = args.startFrame
frameRate = args.framerate
# If the end frame is set use that othewise use the calculated end of the 24 hours
# TODO: Set a check to make sure this falls within an actual usable range...
endFrame = args.endFrame if args.endFrame else (frameRate * 60 * 60 * 24)
# This is totally based on an MTC full frame message. No hiding it.
tcPacket = [
0xF0, # Message Start
0x7F, # Universal Message
0x7F, # Global Broadcast
0x01, # Timecode Message
0x01, # The article was right. Framerate is baked into the binary data of the hours byte. You sneaky...
0x00, # Hours
0x00, # Minutes
0x00, # Seconds
0x00, # Frames
0xF7, # EoE message
]
def incrementFrame():
"""
Increments the current frame.
It's a hard job, but someone needs to do it...
"""
global frame
frame += 1
# TODO: Decide on a better name for the function
def frameToTime(frames, framerate, showCode=False):
"""Converts the current frame to time based on the selected framerate
Arguments:
frames {int} -- The frame to be coverted
framerate {int} -- the framerate to be used
Keyword Arguments:
showCode {bool} -- Prints the data to the screen. (default: {False})
Returns:
list -- The final packet data
"""
packet = tcPacket
second = framerate if framerate != 29.97 else (30 * 1.001)
# second = frameRate
minute = second * 60
hour = minute * 60
# fr = 0 # Just a placeholder for the framerate
# TODO: Why does checking if framerate == 29 not work? I probably made a booboo somewhere...
if framerate == 24:
fr = 0b00000000
elif framerate == 25:
fr = 0b00100000
# elif framerate == 29:
# fr = 0b10000000
# else:
# fr = 0b11000000
elif framerate == 30:
fr = 0b01100000
else:
fr = 0b01000000
# fr = fr << 6 # shift it to far side of the hour
hours = math.floor(frames / hour)
minFrames = frames - (hour * hours)
minutes = math.floor(minFrames / minute)
secFrames = minFrames - (minute * minutes)
seconds = math.floor(secFrames / second)
frameFrames = math.floor(secFrames - (second * seconds))
if showCode == True:
# TODO: F-string this for clarity
print(
str(hours).zfill(2),
str(minutes).zfill(2),
str(seconds).zfill(2),
str(frameFrames).zfill(2),
)
print(frames)
# now that we've shown pretty things, lets add the framerate to hour
# print(fr)
hours = hours + fr
packet[5] = hours
packet[6] = minutes
packet[7] = seconds
packet[8] = frameFrames
return packet
if __name__ == "__main__":
import socket
# Send the data over UDP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((args.bindAddress, 0))
while True:
# print(s)
# s.sendto(bytearray(frameToTime(frame, frameRate, True)), ("10.0.1.201", 5007))
currentFrame = frameToTime(frame, frameRate, True)
print(args.ipAddress, args.port)
# print(bytearray(currentFrame))
print(currentFrame)
try:
s.sendto(bytearray(currentFrame), (args.ipAddress, args.port))
except Exception as e:
print(e)
print("---")
if frame == endFrame:
if args.rollover:
frame = args.startFrame
print("Rollover")
print("---")
else:
print("Fisnished Rolling Code")
exit(0)
now = time.time()
# time.sleep() is too slow. Genereate speed based off of the frameRate
while True:
newNow = time.time()
if frameRate == 29:
frameRate = 29.97
if newNow >= now + 1 / frameRate:
break
incrementFrame()