/* Copyright (C) 2015 Carl Hetherington This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "sub_time.h" #include "exceptions.h" #include using std::ostream; using boost::optional; using namespace sub; /** @return The whole time as a number of milliseconds */ int64_t Time::as_milliseconds () const { if (_frames && !_frame_rate) { throw UnknownFrameRateException (); } int64_t s = (int64_t (hours) * 3600 + minutes * 60 + seconds) * 1000; if (_frames) { s += rint (_frames.get() * 1000 / enum_to_value (_frame_rate.get ())); } else { s += _milliseconds.get(); } return s; } int Time::frames (FrameRate r) const { if (_frames && !_frame_rate) { throw UnknownFrameRateException (); } if (_frames) { if (_frame_rate == r) { return _frames.get(); } else { return rint (double (_frames.get()) * enum_to_value (r) / _frame_rate.get()); } } else { return rint (double (_milliseconds.get()) * enum_to_value (r) / 1000); } } Time Time::from_hmsf (int h, int m, int s, int f) { return Time (h, m, s, optional (), f, optional ()); } Time Time::from_hmsf (int h, int m, int s, int f, sub::FrameRate r) { return Time (h, m, s, optional (), f, r); } Time Time::from_hms (int h, int m, double s) { int const is = int (s); return Time (h, m, is, rint ((s - is) * 1000), optional (), optional ()); } Time Time::from_hmsm (int h, int m, int s, int ms) { return Time (h, m, s, ms, optional (), optional ()); } Time Time::from_frames (int64_t f, FrameRate r) { double s = f / enum_to_value (r); int const hours = floor (s / 3600); s -= hours * 3600; int const minutes = floor (s / 60); s -= minutes * 60; int const seconds = floor (s); s -= seconds; int const frames = rint (s * enum_to_value (r)); return Time::from_hmsf (hours, minutes, seconds, frames, r); } Time Time::from_milliseconds (int64_t m) { int const hours = m / 3600000; m -= hours * 3600000; int const minutes = m / 60000; m -= minutes * 60000; int const seconds = m / 1000; m -= seconds * 1000; return Time (hours, minutes, seconds, m, optional (), optional ()); } bool Time::operator<= (Time const & other) const { return *this < other || *this == other; } bool Time::operator>= (Time const & other) const { return *this > other || *this == other; } bool Time::operator< (Time const & other) const { if ((_frames && !_frame_rate) || (other._frames && !other._frame_rate)) { throw UnknownFrameRateException (); } if (hours != other.hours) { return hours < other.hours; } if (minutes != other.minutes) { return minutes < other.minutes; } if (seconds != other.seconds) { return seconds < other.seconds; } /* Both frames with the same rate */ if (_frames && other._frames && _frame_rate.get() == other._frame_rate.get()) { return _frames.get() < other._frames.get(); } /* Otherwise we have to do it by comparing milliseconds */ return as_milliseconds() < other.as_milliseconds(); } bool Time::operator> (Time const & other) const { if ((_frames && !_frame_rate) || (other._frames && !other._frame_rate)) { throw UnknownFrameRateException (); } if (hours != other.hours) { return hours > other.hours; } if (minutes != other.minutes) { return minutes > other.minutes; } if (seconds != other.seconds) { return seconds > other.seconds; } /* Both frames with the same rate */ if (_frames && other._frames && _frame_rate.get() == other._frame_rate.get()) { return _frames.get() > other._frames.get(); } /* Otherwise we have to do it by comparing milliseconds */ return as_milliseconds() > other.as_milliseconds(); } bool Time::operator== (Time const & other) const { if (hours != other.hours || minutes != other.minutes || seconds != other.seconds) { return false; } if ((_frames && !_frame_rate) || (other._frames && !other._frame_rate)) { throw UnknownFrameRateException (); } /* Both frames with the same rate */ if (_frames && other._frames && _frame_rate.get() == other._frame_rate.get()) { return _frames.get() == other._frames.get(); } /* Otherwise we have to do it by comparing milliseconds */ return as_milliseconds() == other.as_milliseconds(); } bool Time::operator!= (Time const & other) const { return !(*this == other); } ostream & sub::operator<< (ostream& s, Time const & t) { s << t.hours << "h " << t.minutes << "m " << t.seconds << "s "; if (t._frames) { s << t._frames.get() << "f"; } if (t._frame_rate) { s << " @ " << enum_to_value (t._frame_rate.get ()); } if (t._milliseconds) { s << t._milliseconds.get() << "ms"; } return s; } Time sub::operator+ (Time const & a, Time const & b) { int seconds = 0; int minutes = 0; int hours = 0; optional frames; optional frame_rate; optional milliseconds; if (a._frames && b._frames) { if (!a._frame_rate || !b._frame_rate) { throw UnknownFrameRateException (); } if (a._frame_rate.get() != b._frame_rate.get()) { throw MismatchedFrameRateException (); } frame_rate = a._frame_rate.get (); frames = a._frames.get() + b._frames.get(); if (frames.get() >= enum_to_value (frame_rate.get ())) { frames = frames.get() - enum_to_value (frame_rate.get ()); ++seconds; } } else if (a._milliseconds && b._milliseconds) { milliseconds = a._milliseconds.get() + b._milliseconds.get(); if (milliseconds >= 1000) { milliseconds = milliseconds.get() - 1000; ++seconds; } } else { return Time::from_milliseconds (a.as_milliseconds() + b.as_milliseconds()); } seconds += a.seconds + b.seconds; if (seconds >= 60) { seconds -= 60; ++minutes; } minutes += a.minutes + b.minutes; if (minutes >= 60) { minutes -= 60; ++hours; } hours += a.hours + b.hours; if (frames) { return sub::Time (hours, minutes, seconds, optional (), frames.get(), frame_rate.get()); } else { return sub::Time (hours, minutes, seconds, milliseconds.get(), optional (), optional ()); } } Time sub::operator- (Time const & a, Time const & b) { int seconds = 0; int minutes = 0; int hours = 0; optional frames; optional frame_rate; optional milliseconds; if (a._frames && b._frames) { if (!a._frame_rate || !b._frame_rate) { throw UnknownFrameRateException (); } if (a._frame_rate.get() != b._frame_rate.get()) { throw MismatchedFrameRateException (); } frame_rate = a._frame_rate.get (); frames = a._frames.get() - b._frames.get(); if (frames.get() < 0) { frames = frames.get() + enum_to_value (frame_rate.get ()); --seconds; } } else if (a._milliseconds && b._milliseconds) { milliseconds = a._milliseconds.get() - b._milliseconds.get(); if (milliseconds < 0) { milliseconds = milliseconds.get() + 1000; --seconds; } } else { return Time::from_milliseconds (a.as_milliseconds() - b.as_milliseconds()); } seconds += a.seconds - b.seconds; if (seconds < 0) { seconds += 60; --minutes; } minutes += a.minutes - b.minutes; if (minutes < 0) { minutes += 60; --hours; } hours += a.hours - b.hours; if (frames) { return sub::Time (hours, minutes, seconds, optional (), frames.get(), frame_rate.get()); } else { return sub::Time (hours, minutes, seconds, milliseconds.get(), optional (), optional ()); } } double sub::operator/ (Time const & a, Time const & b) { return double (a.as_milliseconds()) / b.as_milliseconds(); } Time::Time (int h, int m, int s, optional ms, optional f, optional r) : hours (h) , minutes (m) , seconds (s) , _milliseconds (ms) , _frames (f) , _frame_rate (r) { }