clean up indentation and spacing
[supercollider.git] / server / supernova / utilities / time_tag.hpp
blob86c6c3fe7d8bad575723f52a1f5b8de39daa4e59
1 // server scheduler
2 // Copyright (C) 2008 Tim Blechmann
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; see the file COPYING. If not, write to
16 // the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 // Boston, MA 02111-1307, USA.
19 #ifndef UTILITIES_TIME_TAG_HPP
20 #define UTILITIES_TIME_TAG_HPP
22 #include <boost/cstdint.hpp>
23 #include <cmath>
25 #ifdef BOOST_NO_INT64_T
26 #error "boost doesn't support int64 types"
27 #endif
29 #include "boost/date_time/posix_time/posix_time_types.hpp"
30 #include "boost/date_time/gregorian/gregorian_types.hpp"
32 namespace nova
35 /** time_tag class, compatible to osc time tags */
36 class time_tag
38 typedef boost::uint32_t uint32;
39 typedef boost::uint64_t uint64;
41 typedef union
43 uint64 packed;
44 uint32 unpacked[2];
45 } cast_union;
47 static const uint32 ntp_offset = 2208988800UL; /* seconds between 01-01-1900 and 01-01-1970 */
49 public:
50 static const uint64 fraction_steps = uint64(1)<<32;
52 time_tag(void):
53 data_(0)
56 time_tag(time_tag const & rhs):
57 data_(rhs.data_)
60 time_tag(uint64 timetag):
61 data_(timetag)
64 time_tag(uint32 secs, uint32 fraction)
66 cast_union cu;
67 cu.unpacked[1] = secs;
68 cu.unpacked[0] = fraction;
70 data_ = cu.packed;
73 uint32 get_secs(void) const
75 return reinterpret_cast<const cast_union*>(&data_)->unpacked[1];
78 uint32 get_fraction(void) const
80 return reinterpret_cast<const cast_union*>(&data_)->unpacked[0];
83 double get_nanoseconds(void) const
85 return get_fractional_seconds() * 1e9;
88 double get_fractional_seconds(void) const
90 return get_fraction() / double(fraction_steps);
93 bool operator<(time_tag const & rhs) const
95 return data_ < rhs.data_;
98 bool operator<=(time_tag const & rhs) const
100 return data_ <= rhs.data_;
103 bool operator==(time_tag const & rhs) const
105 return data_ == rhs.data_;
108 bool operator!=(time_tag const & rhs) const
110 return !operator==(rhs);
113 time_tag & operator+=(time_tag const & rhs)
115 data_ += rhs.data_;
116 return *this;
119 time_tag operator+(time_tag const & rhs) const
121 time_tag ret (*this);
122 ret += rhs;
123 return ret;
126 time_tag & operator-=(time_tag const & rhs)
128 data_ -= rhs.data_;
129 return *this;
132 time_tag operator-(time_tag const & rhs) const
134 time_tag ret (*this);
135 ret -= rhs;
136 return ret;
139 template <typename float_t>
140 static time_tag from_ns(float_t ns)
142 const float_t units_per_ns = float_t(fraction_steps) / 1e9;
144 if (ns < 1e9)
145 return time_tag(0, ns * units_per_ns);
146 else
148 float_t secs = std::floor(ns / 1e9);
149 ns = std::fmod(ns, 1e9);
150 return time_tag(secs, ns * units_per_ns);
154 static time_tag from_samples_small(unsigned int sample_count, float samplerate)
156 assert(sample_count < samplerate);
158 const float units_per_sample = float(fraction_steps) / samplerate;
159 return time_tag(0, sample_count * units_per_sample);
162 static time_tag from_samples(unsigned int sample_count, float samplerate)
164 const float_t units_per_sample = float_t(fraction_steps) / samplerate;
166 if (sample_count < samplerate)
167 return from_samples_small(sample_count, samplerate);
168 else
170 float_t secs = std::floor(sample_count / samplerate);
171 float_t samples = std::fmod(sample_count, samplerate);
172 return time_tag(secs, samples * units_per_sample);
176 float to_samples(float samplerate)
178 float seconds = get_fractional_seconds();
179 uint32_t secs = get_secs();
181 if (secs == 0)
182 seconds += (float)secs;
183 return seconds * samplerate;
186 static time_tag from_ptime(boost::posix_time::ptime const & pt)
188 using namespace boost::gregorian;
189 using namespace boost::posix_time;
191 const date base(1970, Jan, 1);
193 time_duration diff = pt - ptime(base);
195 uint32 secs = diff.total_seconds() + ntp_offset;
197 double fraction = double(diff.fractional_seconds());
199 if (diff.resolution() == boost::date_time::nano)
200 fraction /= 1000000000;
201 else if (diff.resolution() == boost::date_time::micro)
202 fraction /= 1000000;
203 else if (diff.resolution() == boost::date_time::milli)
204 fraction /= 1000;
205 else
206 assert(false);
208 assert (fraction < 1.0 && fraction >= 0);
210 uint32 fraction_units = std::floor(fraction * double(std::numeric_limits<uint32>::max()));
211 return time_tag(secs, fraction_units);
214 boost::posix_time::ptime to_ptime(void) const
216 using namespace boost::gregorian;
217 using namespace boost::posix_time;
219 const date base(1970, Jan, 1);
220 #ifdef BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
221 time_duration offset = seconds(get_secs() - ntp_offset) + nanoseconds(get_nanoseconds());
222 #else
223 time_duration offset = seconds(get_secs() - ntp_offset) + microseconds(get_nanoseconds()/1000);
224 #endif
225 return ptime(base, offset);
228 private:
229 uint64 data_;
232 } /* namespace nova */
234 #endif /* UTILITIES_TIME_TAG_HPP */