class library: Volume - use ServerBoot to send synthdef
[supercollider.git] / server / supernova / utilities / time_tag.hpp
blob532f4dd9942e2c86c4340b49d0396fd1274d47a1
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 <cstdint>
23 #include <cmath>
25 #include "boost/date_time/posix_time/posix_time_types.hpp"
26 #include "boost/date_time/gregorian/gregorian_types.hpp"
28 namespace nova {
30 /** time_tag class, compatible to osc time tags */
31 class time_tag
33 typedef std::uint32_t uint32;
34 typedef std::uint64_t uint64;
36 typedef union
38 uint64 packed;
39 uint32 unpacked[2];
40 } cast_union;
42 static const uint32 ntp_offset = 2208988800UL; /* seconds between 01-01-1900 and 01-01-1970 */
44 public:
45 static const uint64 fraction_steps = uint64(1)<<32;
47 time_tag(void):
48 data_(0)
51 time_tag(time_tag const & rhs):
52 data_(rhs.data_)
55 time_tag(uint64 timetag):
56 data_(timetag)
59 time_tag(uint32 secs, uint32 fraction)
61 cast_union cu;
62 cu.unpacked[1] = secs;
63 cu.unpacked[0] = fraction;
65 data_ = cu.packed;
68 uint32 get_secs(void) const
70 return reinterpret_cast<const cast_union*>(&data_)->unpacked[1];
73 uint32 get_fraction(void) const
75 return reinterpret_cast<const cast_union*>(&data_)->unpacked[0];
78 double get_nanoseconds(void) const
80 return get_fractional_seconds() * 1e9;
83 double get_fractional_seconds(void) const
85 return get_fraction() / double(fraction_steps);
88 bool operator<(time_tag const & rhs) const
90 return data_ < rhs.data_;
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 !operator==(rhs);
108 time_tag & operator+=(time_tag const & rhs)
110 data_ += rhs.data_;
111 return *this;
114 time_tag operator+(time_tag const & rhs) const
116 time_tag ret (*this);
117 ret += rhs;
118 return ret;
121 time_tag & operator-=(time_tag const & rhs)
123 data_ -= rhs.data_;
124 return *this;
127 time_tag operator-(time_tag const & rhs) const
129 time_tag ret (*this);
130 ret -= rhs;
131 return ret;
134 template <typename float_t>
135 static time_tag from_ns(float_t ns)
137 const float_t units_per_ns = float_t(fraction_steps) / 1e9;
139 if (ns < 1e9)
140 return time_tag(0, ns * units_per_ns);
141 else
143 float_t secs = std::floor(ns / 1e9);
144 ns = std::fmod(ns, 1e9);
145 return time_tag(secs, ns * units_per_ns);
149 static time_tag from_samples_small(unsigned int sample_count, float samplerate)
151 assert(sample_count < samplerate);
153 const float units_per_sample = float(fraction_steps) / samplerate;
154 return time_tag(0, sample_count * units_per_sample);
157 static time_tag from_samples(unsigned int sample_count, float samplerate)
159 const float_t units_per_sample = float_t(fraction_steps) / samplerate;
161 if (sample_count < samplerate)
162 return from_samples_small(sample_count, samplerate);
163 else
165 float_t secs = std::floor(sample_count / samplerate);
166 float_t samples = std::fmod(sample_count, samplerate);
167 return time_tag(secs, samples * units_per_sample);
171 float to_samples(float samplerate)
173 float seconds = get_fractional_seconds();
174 uint32_t secs = get_secs();
176 if (secs == 0)
177 seconds += (float)secs;
178 return seconds * samplerate;
181 static time_tag from_ptime(boost::posix_time::ptime const & pt)
183 using namespace boost::gregorian;
184 using namespace boost::posix_time;
186 const date base(1970, Jan, 1);
188 time_duration diff = pt - ptime(base);
190 uint32 secs = diff.total_seconds() + ntp_offset;
192 double fraction = double(diff.fractional_seconds());
194 if (diff.resolution() == boost::date_time::nano)
195 fraction /= 1000000000;
196 else if (diff.resolution() == boost::date_time::micro)
197 fraction /= 1000000;
198 else if (diff.resolution() == boost::date_time::milli)
199 fraction /= 1000;
200 else
201 assert(false);
203 assert (fraction < 1.0 && fraction >= 0);
205 uint32 fraction_units = std::floor(fraction * double(std::numeric_limits<uint32>::max()));
206 return time_tag(secs, fraction_units);
209 boost::posix_time::ptime to_ptime(void) const
211 using namespace boost::gregorian;
212 using namespace boost::posix_time;
214 const date base(1970, Jan, 1);
215 #ifdef BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
216 time_duration offset = seconds(get_secs() - ntp_offset) + nanoseconds(get_nanoseconds());
217 #else
218 time_duration offset = seconds(get_secs() - ntp_offset) + microseconds(get_nanoseconds()/1000);
219 #endif
220 return ptime(base, offset);
223 private:
224 uint64 data_;
227 } /* namespace nova */
229 #endif /* UTILITIES_TIME_TAG_HPP */