Missing static build libraries.
[libsub.git] / src / sub_time.cc
1 /*
2     Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net>
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.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "sub_time.h"
21 #include "sub_assert.h"
22 #include "exceptions.h"
23 #include <cmath>
24 #include <iomanip>
25 #include <iostream>
26
27 using std::ostream;
28 using std::cout;
29 using std::setw;
30 using std::setfill;
31 using boost::optional;
32 using namespace sub;
33
34 bool
35 sub::operator< (sub::Time const & a, sub::Time const & b)
36 {
37         if (a._seconds != b._seconds) {
38                 return a._seconds < b._seconds;
39         }
40
41         if (!a._rate && !b._rate) {
42                 /* Can compare if neither has a specified frame rate */
43                 return a._frames < b._frames;
44         }
45
46         if ((a._rate && !b._rate) || (!a._rate && b._rate)) {
47                 throw UnknownFrameRateError ();
48         }
49
50         return (a._frames * a._rate.get().numerator * b._rate.get().denominator) < (b._frames * b._rate.get().numerator * a._rate.get().denominator);
51 }
52
53 bool
54 sub::operator> (sub::Time const & a, sub::Time const & b)
55 {
56         if (a._seconds != b._seconds) {
57                 return a._seconds > b._seconds;
58         }
59
60         if (!a._rate && !b._rate) {
61                 /* Can compare if neither has a specified frame rate */
62                 return a._frames > b._frames;
63         }
64
65         if ((a._rate && !b._rate) || (!a._rate && b._rate)) {
66                 throw UnknownFrameRateError ();
67         }
68
69         return (a._frames * a._rate.get().numerator * b._rate.get().denominator) > (b._frames * b._rate.get().numerator * a._rate.get().denominator);
70 }
71
72 bool
73 sub::operator== (sub::Time const & a, sub::Time const & b)
74 {
75         if (!a._rate && !b._rate) {
76                 /* Can compare if neither has a specified frame rate */
77                 return (a._seconds == b._seconds && a._frames == b._frames);
78         }
79
80         if ((a._rate && !b._rate) || (!a._rate && b._rate)) {
81                 throw UnknownFrameRateError ();
82         }
83
84         if (a._seconds != b._seconds) {
85                 return false;
86         }
87
88         return (a._frames * a._rate.get().numerator * b._rate.get().denominator) == (b._frames * b._rate.get().numerator * a._rate.get().denominator);
89 }
90
91 bool
92 sub::operator!= (sub::Time const & a, sub::Time const & b)
93 {
94         return !(a == b);
95 }
96
97 ostream&
98 sub::operator<< (ostream& s, Time const & t)
99 {
100         s << setw (2) << setfill('0') << t.hours() << ":"
101           << setw (2) << setfill('0') << t.minutes() << ":"
102           << setw (2) << setfill('0') << t.seconds() << ":"
103           << t._frames;
104
105         if (t._rate) {
106                 s << " @ " << t._rate.get().numerator << "/" << t._rate.get().denominator;
107         }
108
109         return s;
110 }
111
112 int
113 Time::hours () const
114 {
115         return _seconds / 3600;
116 }
117
118 int
119 Time::minutes () const
120 {
121         return (_seconds - hours() * 3600) / 60;
122 }
123
124 int
125 Time::seconds () const
126 {
127         return (_seconds - hours() * 3600 - minutes() * 60);
128 }
129
130 int
131 Time::frames_at (Rational rate) const
132 {
133         if (!_rate) {
134                 throw UnknownFrameRateError ();
135         }
136
137         return rint (double (_frames) * _rate.get().denominator * rate.numerator / (_rate.get().numerator * rate.denominator));
138 }
139
140 int
141 Time::milliseconds () const
142 {
143         return frames_at (Rational (1000, 1));
144 }
145
146 Time
147 Time::from_hmsf (int h, int m, int s, int f, optional<Rational> rate)
148 {
149         return Time (h * 3600 + m * 60 + s, f, rate);
150 }
151
152 Time
153 Time::from_hms (int h, int m, int s, int ms)
154 {
155         return Time (h * 3600 + m * 60 + s, ms, Rational (1000, 1));
156 }
157
158 /** Create a Time from a number of frames.
159  *  rate must be integer.
160  */
161 Time
162 Time::from_frames (int f, Rational rate)
163 {
164         SUB_ASSERT (rate.denominator != 0);
165         SUB_ASSERT (rate.integer ());
166         return Time (f / rate.integer_fraction(), f % rate.integer_fraction(), rate);
167 }
168
169 double
170 Time::all_as_seconds () const
171 {
172         return _seconds + double(milliseconds()) / 1000;
173 }
174
175 /** Add a time to this one.  Both *this and t must have a specified _rate */
176 void
177 Time::add (Time t)
178 {
179         SUB_ASSERT (_rate);
180         SUB_ASSERT (t._rate);
181
182         Rational result_rate = max (*_rate, *t._rate);
183         *this = Time::from_frames((all_as_seconds() + t.all_as_seconds()) * result_rate.fraction(), result_rate);
184 }
185
186 void
187 Time::scale (float f)
188 {
189         SUB_ASSERT (_rate);
190         SUB_ASSERT (_rate->denominator != 0);
191         SUB_ASSERT (_rate->integer ());
192
193         double const s = Time::all_as_seconds() * f;
194         _seconds = floor (s);
195         _frames = rint ((s - _seconds) * _rate->fraction());
196 }