11"""Functions to get OSC types from datagrams and vice versa"""
22
3- import decimal
43import struct
54
65from pythonosc .parsing import ntp
@@ -22,9 +21,10 @@ class BuildError(Exception):
2221
2322# Datagram length in bytes for types that have a fixed size.
2423_INT_DGRAM_LEN = 4
24+ _UINT64_DGRAM_LEN = 8
2525_FLOAT_DGRAM_LEN = 4
2626_DOUBLE_DGRAM_LEN = 8
27- _DATE_DGRAM_LEN = _INT_DGRAM_LEN * 2
27+ _TIMETAG_DGRAM_LEN = 8
2828# Strings and blob dgram length is always a multiple of 4 bytes.
2929_STRING_DGRAM_PAD = 4
3030_BLOB_DGRAM_PAD = 4
@@ -126,7 +126,31 @@ def get_int(dgram: bytes, start_index: int) -> Tuple[int, int]:
126126 raise ParseError ('Could not parse datagram %s' % e )
127127
128128
129- def get_ttag (dgram : bytes , start_index : int ) -> Tuple [datetime , int ]:
129+ def get_uint64 (dgram : bytes , start_index : int ) -> Tuple [int , int ]:
130+ """Get a 64-bit big-endian unsigned integer from the datagram.
131+
132+ Args:
133+ dgram: A datagram packet.
134+ start_index: An index where the integer starts in the datagram.
135+
136+ Returns:
137+ A tuple containing the integer and the new end index.
138+
139+ Raises:
140+ ParseError if the datagram could not be parsed.
141+ """
142+ try :
143+ if len (dgram [start_index :]) < _UINT64_DGRAM_LEN :
144+ raise ParseError ('Datagram is too short' )
145+ return (
146+ struct .unpack ('>Q' ,
147+ dgram [start_index :start_index + _UINT64_DGRAM_LEN ])[0 ],
148+ start_index + _UINT64_DGRAM_LEN )
149+ except (struct .error , TypeError ) as e :
150+ raise ParseError ('Could not parse datagram %s' % e )
151+
152+
153+ def get_timetag (dgram : bytes , start_index : int ) -> Tuple [datetime , int ]:
130154 """Get a 64-bit OSC time tag from the datagram.
131155
132156 Args:
@@ -140,29 +164,22 @@ def get_ttag(dgram: bytes, start_index: int) -> Tuple[datetime, int]:
140164 Raises:
141165 ParseError if the datagram could not be parsed.
142166 """
143-
144- _TTAG_DGRAM_LEN = 8
145-
146167 try :
147- if len (dgram [start_index :]) < _TTAG_DGRAM_LEN :
168+ if len (dgram [start_index :]) < _TIMETAG_DGRAM_LEN :
148169 raise ParseError ('Datagram is too short' )
149170
150- seconds , idx = get_int (dgram , start_index )
151- second_decimals , _ = get_int (dgram , idx )
152-
153- if seconds < 0 :
154- seconds += ntp .FRACTIONAL_CONVERSION
155-
156- if second_decimals < 0 :
157- second_decimals += ntp .FRACTIONAL_CONVERSION
171+ timetag , _ = get_uint64 (dgram , start_index )
172+ seconds_float = timetag * ntp ._NTP_TIMESTAMP_TO_SECONDS
173+ seconds = int (seconds_float )
174+ fraction = seconds_float - seconds
158175
159176 hours , seconds = seconds // 3600 , seconds % 3600
160177 minutes , seconds = seconds // 60 , seconds % 60
161178
162- utc = datetime .combine (ntp ._NTP_EPOCH , datetime .min .time ()) + timedelta ( hours = hours , minutes = minutes ,
163- seconds = seconds )
179+ utc = ( datetime .combine (ntp ._NTP_EPOCH , datetime .min .time ()) +
180+ timedelta ( hours = hours , minutes = minutes , seconds = seconds ) )
164181
165- return (utc , second_decimals ), start_index + _TTAG_DGRAM_LEN
182+ return (utc , fraction ), start_index + _TIMETAG_DGRAM_LEN
166183 except (struct .error , TypeError ) as e :
167184 raise ParseError ('Could not parse datagram %s' % e )
168185
@@ -284,7 +301,7 @@ def write_blob(val: bytes) -> bytes:
284301 return dgram
285302
286303
287- def get_date (dgram : bytes , start_index : int ) -> Tuple [Union [ int , float ] , int ]:
304+ def get_date (dgram : bytes , start_index : int ) -> Tuple [float , int ]:
288305 """Get a 64-bit big-endian fixed-point time tag as a date from the datagram.
289306
290307 According to the specifications, a date is represented as is:
@@ -304,16 +321,13 @@ def get_date(dgram: bytes, start_index: int) -> Tuple[Union[int, float], int]:
304321 ParseError if the datagram could not be parsed.
305322 """
306323 # Check for the special case first.
307- if dgram [start_index :start_index + _DATE_DGRAM_LEN ] == ntp .IMMEDIATELY :
308- return IMMEDIATELY , start_index + _DATE_DGRAM_LEN
309- if len (dgram [start_index :]) < _DATE_DGRAM_LEN :
324+ if dgram [start_index :start_index + _TIMETAG_DGRAM_LEN ] == ntp .IMMEDIATELY :
325+ return IMMEDIATELY , start_index + _TIMETAG_DGRAM_LEN
326+ if len (dgram [start_index :]) < _TIMETAG_DGRAM_LEN :
310327 raise ParseError ('Datagram is too short' )
311- num_secs , start_index = get_int (dgram , start_index )
312- fraction , start_index = get_int (dgram , start_index )
313- # Sum seconds and fraction of second:
314- system_time = num_secs + (fraction / ntp .FRACTIONAL_CONVERSION )
315-
316- return ntp .ntp_to_system_time (system_time ), start_index
328+ timetag , start_index = get_uint64 (dgram , start_index )
329+ seconds = timetag * ntp ._NTP_TIMESTAMP_TO_SECONDS
330+ return ntp .ntp_time_to_system_epoch (seconds ), start_index
317331
318332
319333def write_date (system_time : Union [int , float ]) -> bytes :
0 commit comments