Closed xavriley closed 8 years ago
From the OSC 1.0 spec http://opensoundcontrol.org/node/3/#timetags
Time tags are represented by a 64 bit fixed point number. The first 32 bits specify the number of seconds since midnight on January 1, 1900, and the last 32 bits specify fractional parts of a second to a precision of about 200 picoseconds. This is the representation used by Internet NTP timestamps.The time tag value consisting of 63 zero bits followed by a one in the least signifigant bit is a special case meaning "immediately."
I think the most idiomatic ruby way of writing that is
(Time.new-Time.new("1900-01-01"))*(2**32)
which would end up losing some precision, but it should still be useful enough. The resulting floating point number would just be converted to a 64 bit integer and that should be passed in as the time tag.
Wouldn't it make more sense to do this on the C side?
My apologies. I was getting to the end of my tether before opening this as I thought there was something special going on with emplace_uint64
that was changing my input, but it turns out I wasn't dereferencing a pointer in the approach I was trying.
I've ended up with a much simpler method of merging the uint32
s for second and fraction into a uint64_t
which I've gone with here:
uint64_t ruby_time_to_osc_timetag(VALUE rubytime) {
uint64_t timetag;
double floattime;
uint32_t sec;
uint32_t frac;
switch(TYPE(rubytime)) {
case T_NIL:
timetag = 1;
break;
default:
// convert Time object to ntp
floattime = JAN_1970 + NUM2DBL(rb_funcall(rubytime, rb_intern("to_f"), 0));
sec = NUM2UINT(DBL2NUM(floattime));
frac = (int)(fmod(floattime, 1.0) * 4294967296); // * (2 ** 32)
timetag = (uint64_t)((uint64_t)sec << 32 | (uint64_t)frac);
break;
}
return timetag;
}
https://github.com/xavriley/fast_osc/blob/master/ext/fast_osc/fast_osc_wrapper.c#L187
My tests are all passing now so I'll just leave that in case anyone else finds it useful. Thanks again for the help.
@samaaron A simple routine to convert unix time to timetags (i.e. seconds + nanoseconds) and vice versa might be an appropriate addition to the core API. I don't use timetags much in my own OSC use, but I'd be fine with a patch along those lines.
Regarding
emplace_uint64
I'm having a hard time formatting the input timestamp in such a way as to produce valid output. As I've read it so far, I need to add the magic number to make the Unix timestamp count from 1900, and then pack the seconds and fractions in a double manually before handing it tortosc_bundle
- is that correct? From that point, isemplace
then reversing the endianness?If so it might be useful to provide some kind of helper function that takes a Unix timestamp as a float or something. If that's not desirable, any advice on formatting would be very welcome as I'm struggling to get this working with my Ruby wrapper at the moment.