2011-01-02 01:21:39 +01:00
|
|
|
/*
|
|
|
|
|
Timecode - implementation of fixed grid aligned time specifications
|
|
|
|
|
|
|
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2010, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
* *****************************************************/
|
|
|
|
|
|
|
|
|
|
|
2016-11-03 18:22:31 +01:00
|
|
|
/** @file timecode.cpp
|
2016-11-07 16:22:04 +01:00
|
|
|
** Implementation parts of the timecode handling library.
|
|
|
|
|
** @todo a started implementation exists since 2010,
|
|
|
|
|
** yet crucial parts still need to be filled in as of 2016
|
2016-11-03 18:20:10 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
2011-01-02 01:21:39 +01:00
|
|
|
#include "lib/time/timecode.hpp"
|
2011-01-05 18:15:44 +01:00
|
|
|
#include "lib/time/timevalue.hpp"
|
2011-01-02 01:21:39 +01:00
|
|
|
#include "lib/time/timequant.hpp"
|
|
|
|
|
#include "lib/time/formats.hpp"
|
2011-01-05 18:15:44 +01:00
|
|
|
#include "lib/time.h"
|
2011-01-18 05:01:25 +01:00
|
|
|
#include "lib/util.hpp"
|
2012-03-04 01:34:18 +01:00
|
|
|
#include "lib/util-quant.hpp"
|
2011-01-05 18:15:44 +01:00
|
|
|
|
2019-06-24 02:41:02 +02:00
|
|
|
#include <regex>
|
2014-04-03 22:42:48 +02:00
|
|
|
#include <functional>
|
2011-05-13 06:28:55 +02:00
|
|
|
#include <boost/lexical_cast.hpp>
|
2011-01-05 18:15:44 +01:00
|
|
|
|
2011-01-20 22:17:25 +01:00
|
|
|
using util::unConst;
|
2011-01-21 16:22:01 +01:00
|
|
|
using util::isSameObject;
|
2011-01-21 20:24:41 +01:00
|
|
|
using util::floorwrap;
|
2019-06-24 02:41:02 +02:00
|
|
|
using std::string;
|
|
|
|
|
using std::regex;
|
|
|
|
|
using std::smatch;
|
|
|
|
|
using std::regex_search;
|
2011-05-13 06:28:55 +02:00
|
|
|
using boost::lexical_cast;
|
2011-01-02 01:21:39 +01:00
|
|
|
|
2011-05-13 06:28:55 +02:00
|
|
|
namespace error = lumiera::error;
|
2011-01-02 01:21:39 +01:00
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
namespace time {
|
|
|
|
|
|
|
|
|
|
|
2011-05-13 06:28:55 +02:00
|
|
|
namespace format { /* ================= Timecode implementation details ======== */
|
|
|
|
|
|
|
|
|
|
LUMIERA_ERROR_DEFINE (INVALID_TIMECODE, "timecode format error, illegal value encountered");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** try to parse a frame number specification
|
|
|
|
|
* @param frameNumber string containing an integral number with trailing '#'
|
|
|
|
|
* @param frameGrid coordinate system (and thus framerate) to use for the conversion
|
|
|
|
|
* @return (opaque internal) lumiera time value of the given frame's start position
|
|
|
|
|
* @throw error::Invalid in case of parsing failure
|
|
|
|
|
* @note the string may contain any additional content, as long as a
|
|
|
|
|
* regular-expression search is able to pick out a suitable value
|
|
|
|
|
*/
|
|
|
|
|
TimeValue
|
|
|
|
|
Frames::parse (string const& frameNumber, QuantR frameGrid)
|
|
|
|
|
{
|
2019-06-24 02:41:02 +02:00
|
|
|
static regex frameNr_parser{"(?:^|[^\\d\\.\\-])(\\-?\\d+)#"}; // no leading [.-\d], digit+'#'
|
|
|
|
|
smatch match; // note: ECMA regexp does not support lookbehind
|
2011-05-13 06:28:55 +02:00
|
|
|
if (regex_search (frameNumber, match, frameNr_parser))
|
2013-11-18 00:01:43 +01:00
|
|
|
return frameGrid.timeOf (lexical_cast<FrameCnt> (match[1]));
|
2011-05-13 06:28:55 +02:00
|
|
|
else
|
|
|
|
|
throw error::Invalid ("unable to parse framecount \""+frameNumber+"\""
|
2018-04-02 01:48:51 +02:00
|
|
|
, LERR_(INVALID_TIMECODE));
|
2011-05-13 06:28:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TimeValue
|
|
|
|
|
Smpte::parse (string const&, QuantR)
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED("parsing SMPTE timecode");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TimeValue
|
|
|
|
|
Hms::parse (string const&, QuantR)
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED("parse a hours:mins:secs time specification");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** try to parse a time specification in seconds or fractional seconds.
|
|
|
|
|
* The value is interpreted relative to the origin of a the given time grid
|
|
|
|
|
* This parser recognises full seconds, fractional seconds and both together.
|
|
|
|
|
* In any case, the actual number is required to end with a trailing \c 'sec'
|
|
|
|
|
* @par Example specifications
|
|
|
|
|
\verbatim
|
2018-11-17 18:00:39 +01:00
|
|
|
12sec --> 12 * TimeValue::SCALE
|
|
|
|
|
-4sec --> -4 * TimeValue::SCALE
|
|
|
|
|
5/4sec --> 1.25 * TimeValue::SCALE
|
|
|
|
|
-5/25sec --> -0.2 * TimeValue::SCALE
|
|
|
|
|
1+1/2sec --> 1.5 * TimeValue::SCALE
|
|
|
|
|
1-1/25sec --> 0.96 * TimeValue::SCALE
|
|
|
|
|
-12-1/4sec --> -11.75 * TimeValue::SCALE
|
2011-05-13 06:28:55 +02:00
|
|
|
\endverbatim
|
|
|
|
|
* @param seconds string containing a time spec in seconds
|
|
|
|
|
* @param grid coordinate system the parsed value is based on
|
|
|
|
|
* @return the corresponding (opaque internal) lumiera time value
|
|
|
|
|
* @throw error::Invalid in case of parsing failure
|
|
|
|
|
* @note the string may contain any additional content, as long as a
|
|
|
|
|
* regular-expression search is able to pick out a suitable value
|
|
|
|
|
*/
|
|
|
|
|
TimeValue
|
|
|
|
|
Seconds::parse (string const& seconds, QuantR grid)
|
|
|
|
|
{
|
2019-06-24 02:41:02 +02:00
|
|
|
static regex fracSecs_parser ("(?:^|[^\\./\\d\\-])(\\-?\\d+)(?:([\\-\\+]\\d+)?/(\\d+))?sec");
|
|
|
|
|
//__no leading[./-\d] number [+-] number '/' number 'sec'
|
2011-05-13 06:28:55 +02:00
|
|
|
|
|
|
|
|
#define SUB_EXPR(N) lexical_cast<long> (match[N])
|
|
|
|
|
smatch match;
|
|
|
|
|
if (regex_search (seconds, match, fracSecs_parser))
|
|
|
|
|
if (match[2].matched)
|
|
|
|
|
{
|
|
|
|
|
// complete spec with all parts
|
|
|
|
|
FSecs fractionalPart (SUB_EXPR(2), SUB_EXPR(3));
|
|
|
|
|
long fullSeconds (SUB_EXPR(1));
|
|
|
|
|
return grid.timeOf (fullSeconds + fractionalPart);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
if (match[3].matched)
|
|
|
|
|
{
|
|
|
|
|
// only a fractional part was given
|
|
|
|
|
return grid.timeOf (FSecs (SUB_EXPR(1), SUB_EXPR(3)));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// just simple non-fractional seconds
|
|
|
|
|
return grid.timeOf (FSecs (SUB_EXPR(1)));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw error::Invalid ("unable to parse \""+seconds+"\" as (fractional)seconds"
|
2018-04-02 01:48:51 +02:00
|
|
|
, LERR_(INVALID_TIMECODE));
|
2011-05-13 06:28:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-01-13 23:56:52 +01:00
|
|
|
|
|
|
|
|
/** build up a frame count
|
|
|
|
|
* by quantising the given time value
|
|
|
|
|
*/
|
|
|
|
|
void
|
2011-01-15 00:52:02 +01:00
|
|
|
Frames::rebuild (FrameNr& framecnt, QuantR quantiser, TimeValue const& rawTime)
|
2011-01-13 23:56:52 +01:00
|
|
|
{
|
2011-04-26 06:11:31 +02:00
|
|
|
framecnt.setValueRaw (quantiser.gridPoint (rawTime));
|
2011-01-13 23:56:52 +01:00
|
|
|
}
|
2011-01-14 05:33:50 +01:00
|
|
|
|
|
|
|
|
/** calculate the time point denoted by this frame count */
|
|
|
|
|
TimeValue
|
2011-01-15 00:52:02 +01:00
|
|
|
Frames::evaluate (FrameNr const& framecnt, QuantR quantiser)
|
2011-01-14 05:33:50 +01:00
|
|
|
{
|
2011-01-15 00:52:02 +01:00
|
|
|
return quantiser.timeOf (framecnt);
|
2011-01-14 05:33:50 +01:00
|
|
|
}
|
|
|
|
|
|
2011-01-18 05:01:25 +01:00
|
|
|
|
2011-01-20 13:21:14 +01:00
|
|
|
/** build up a SMPTE timecode
|
|
|
|
|
* by quantising the given time value and then splitting it
|
2011-01-21 11:42:29 +01:00
|
|
|
* into hours, minutes, seconds and frame offset.
|
2011-01-18 05:01:25 +01:00
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
Smpte::rebuild (SmpteTC& tc, QuantR quantiser, TimeValue const& rawTime)
|
|
|
|
|
{
|
2011-01-21 20:24:41 +01:00
|
|
|
tc.clear();
|
2011-01-21 11:42:29 +01:00
|
|
|
tc.frames = quantiser.gridPoint (rawTime);
|
2011-01-22 18:33:15 +01:00
|
|
|
// will automatically wrap over to the seconds, minutes and hour fields
|
2011-01-18 05:01:25 +01:00
|
|
|
}
|
|
|
|
|
|
2011-01-20 13:21:14 +01:00
|
|
|
/** calculate the time point denoted by this SMPTE timecode,
|
|
|
|
|
* by summing up the timecode's components */
|
2011-01-18 05:01:25 +01:00
|
|
|
TimeValue
|
|
|
|
|
Smpte::evaluate (SmpteTC const& tc, QuantR quantiser)
|
|
|
|
|
{
|
2011-05-13 04:04:02 +02:00
|
|
|
uint frameRate = tc.getFps();
|
|
|
|
|
int64_t gridPoint(tc.frames);
|
|
|
|
|
gridPoint += int64_t(tc.secs) * frameRate;
|
|
|
|
|
gridPoint += int64_t(tc.mins) * frameRate * 60;
|
|
|
|
|
gridPoint += int64_t(tc.hours) * frameRate * 60 * 60;
|
2011-01-21 20:24:41 +01:00
|
|
|
return quantiser.timeOf (tc.sgn * gridPoint);
|
2011-01-21 11:42:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** yield the Framerate in effect at that point.
|
|
|
|
|
* Especially Timecode in SMPTE format exposes a "frames" field
|
|
|
|
|
* to contain the remainder of frames in addition to the h:m:s value.
|
|
|
|
|
* Obviously this value has to be kept below the number of frames for
|
|
|
|
|
* a full second and wrap around accordingly.
|
|
|
|
|
* @note SMPTE format assumes this framerate to be constant. Actually,
|
|
|
|
|
* in this implementation the value returned here neither needs
|
|
|
|
|
* to be constant (independent of the given rawTime), nor does
|
|
|
|
|
* it need to be the actual framerate used by the quantiser.
|
|
|
|
|
* Especially in case of NTSC drop-frame, the timecode
|
|
|
|
|
* uses 30fps here, while the quantisation uses 29.97
|
|
|
|
|
* @todo this design just doesn't feel quite right...
|
|
|
|
|
*/
|
|
|
|
|
uint
|
|
|
|
|
Smpte::getFramerate (QuantR quantiser_, TimeValue const& rawTime)
|
|
|
|
|
{
|
2013-11-18 00:01:43 +01:00
|
|
|
FrameCnt refCnt = quantiser_.gridPoint(rawTime);
|
|
|
|
|
FrameCnt newCnt = quantiser_.gridPoint(Time(0,1) + rawTime);
|
|
|
|
|
FrameCnt effectiveFrames = newCnt - refCnt;
|
2011-01-21 11:42:29 +01:00
|
|
|
ENSURE (1000 > effectiveFrames);
|
|
|
|
|
ENSURE (0 < effectiveFrames);
|
|
|
|
|
return uint(effectiveFrames);
|
2011-01-18 05:01:25 +01:00
|
|
|
}
|
2011-01-21 20:24:41 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/** handle the limits of SMPTE timecode range.
|
|
|
|
|
* This is an extension and configuration point to control how
|
|
|
|
|
* to handle values beyond the official SMPTE timecode range of
|
|
|
|
|
* 0:0:0:0 to 23:59:59:##. When this strategy function is invoked,
|
2011-01-22 14:41:58 +01:00
|
|
|
* the frames, seconds, minutes and hours fields have already been processed
|
|
|
|
|
* and stored into the component digxels, under the assumption the overall
|
|
|
|
|
* value stays in range.
|
2011-01-21 20:24:41 +01:00
|
|
|
* @note currently the range is extended "naturally" (i.e. mathematically).
|
|
|
|
|
* The representation is flipped around the zero point and the value
|
|
|
|
|
* of the hours is just allowed to increase beyond 23
|
|
|
|
|
* @todo If necessary, this extension point should be converted into a
|
|
|
|
|
* configurable strategy. Possible variations
|
|
|
|
|
* - clip values beyond the boundaries
|
2011-01-22 14:41:58 +01:00
|
|
|
* - throw an exception on illegal values
|
2011-01-21 20:24:41 +01:00
|
|
|
* - wrap around from 23:59:59:## to 0:0:0:0
|
|
|
|
|
* - just make the hour negative, but continue with the same
|
|
|
|
|
* orientation (0:0:0:0 - 1sec = -1:59:59:0)
|
|
|
|
|
*/
|
|
|
|
|
void
|
2011-04-29 04:04:48 +02:00
|
|
|
Smpte::applyRangeLimitStrategy (SmpteTC& tc)
|
2011-01-21 20:24:41 +01:00
|
|
|
{
|
2011-01-22 18:33:15 +01:00
|
|
|
if (tc.hours < 0)
|
|
|
|
|
tc.invertOrientation();
|
2011-01-21 20:24:41 +01:00
|
|
|
}
|
2011-01-13 23:56:52 +01:00
|
|
|
}
|
2011-01-05 18:15:44 +01:00
|
|
|
|
2011-01-21 20:24:41 +01:00
|
|
|
|
2011-01-20 13:21:14 +01:00
|
|
|
namespace { // Timecode implementation details
|
|
|
|
|
|
2011-01-21 11:42:29 +01:00
|
|
|
typedef util::IDiv<int> Div;
|
2011-01-20 13:21:14 +01:00
|
|
|
|
2011-01-22 14:41:58 +01:00
|
|
|
void
|
2011-01-21 16:22:01 +01:00
|
|
|
wrapFrames (SmpteTC* thisTC, int rawFrames)
|
2011-01-20 13:21:14 +01:00
|
|
|
{
|
2011-01-21 20:24:41 +01:00
|
|
|
Div scaleRelation = floorwrap<int> (rawFrames, thisTC->getFps());
|
2011-01-22 14:41:58 +01:00
|
|
|
thisTC->frames.setValueRaw (scaleRelation.rem);
|
2011-01-21 16:22:01 +01:00
|
|
|
thisTC->secs += scaleRelation.quot;
|
2011-01-20 13:21:14 +01:00
|
|
|
}
|
|
|
|
|
|
2011-01-22 14:41:58 +01:00
|
|
|
void
|
2011-01-21 16:22:01 +01:00
|
|
|
wrapSeconds (SmpteTC* thisTC, int rawSecs)
|
2011-01-20 13:21:14 +01:00
|
|
|
{
|
2011-01-21 20:24:41 +01:00
|
|
|
Div scaleRelation = floorwrap (rawSecs, 60);
|
2011-01-22 14:41:58 +01:00
|
|
|
thisTC->secs.setValueRaw (scaleRelation.rem);
|
2011-01-21 16:22:01 +01:00
|
|
|
thisTC->mins += scaleRelation.quot;
|
2011-01-20 13:21:14 +01:00
|
|
|
}
|
|
|
|
|
|
2011-01-22 14:41:58 +01:00
|
|
|
void
|
2011-01-21 16:22:01 +01:00
|
|
|
wrapMinutes (SmpteTC* thisTC, int rawMins)
|
2011-01-20 13:21:14 +01:00
|
|
|
{
|
2011-01-21 20:24:41 +01:00
|
|
|
Div scaleRelation = floorwrap (rawMins, 60);
|
2011-01-22 14:41:58 +01:00
|
|
|
thisTC->mins.setValueRaw (scaleRelation.rem);
|
2011-01-21 16:22:01 +01:00
|
|
|
thisTC->hours += scaleRelation.quot;
|
2011-01-20 13:21:14 +01:00
|
|
|
}
|
|
|
|
|
|
2011-01-22 14:41:58 +01:00
|
|
|
void
|
2011-01-21 16:22:01 +01:00
|
|
|
wrapHours (SmpteTC* thisTC, int rawHours)
|
2011-01-20 13:21:14 +01:00
|
|
|
{
|
2011-01-22 14:41:58 +01:00
|
|
|
thisTC->hours.setValueRaw (rawHours);
|
2011-04-29 04:04:48 +02:00
|
|
|
format::Smpte::applyRangeLimitStrategy (*thisTC);
|
2011-01-20 13:21:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-04-03 22:42:48 +02:00
|
|
|
using std::bind;
|
|
|
|
|
using std::placeholders::_1;
|
2011-01-21 16:22:01 +01:00
|
|
|
|
|
|
|
|
/** bind the individual Digxel mutation functors
|
|
|
|
|
* to normalise raw component values */
|
|
|
|
|
inline void
|
2011-01-22 14:41:58 +01:00
|
|
|
setupComponentNormalisation (SmpteTC& thisTC)
|
2011-01-21 16:22:01 +01:00
|
|
|
{
|
2011-01-22 14:41:58 +01:00
|
|
|
thisTC.hours.installMutator (wrapHours, thisTC);
|
|
|
|
|
thisTC.mins.installMutator (wrapMinutes, thisTC);
|
|
|
|
|
thisTC.secs.installMutator (wrapSeconds, thisTC);
|
|
|
|
|
thisTC.frames.installMutator(wrapFrames, thisTC);
|
2011-01-21 16:22:01 +01:00
|
|
|
}
|
|
|
|
|
|
2011-01-20 13:21:14 +01:00
|
|
|
}//(End)implementation details
|
2011-01-05 18:15:44 +01:00
|
|
|
|
2011-01-14 05:33:50 +01:00
|
|
|
|
|
|
|
|
/** */
|
|
|
|
|
FrameNr::FrameNr (QuTime const& quantisedTime)
|
|
|
|
|
: TCode(quantisedTime)
|
|
|
|
|
, CountVal()
|
|
|
|
|
{
|
|
|
|
|
quantisedTime.castInto (*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-01-05 18:15:44 +01:00
|
|
|
/** */
|
|
|
|
|
SmpteTC::SmpteTC (QuTime const& quantisedTime)
|
2011-01-14 05:33:50 +01:00
|
|
|
: TCode(quantisedTime)
|
2011-01-21 11:42:29 +01:00
|
|
|
, effectiveFramerate_(Format::getFramerate (*quantiser_, quantisedTime))
|
|
|
|
|
{
|
2011-01-22 14:41:58 +01:00
|
|
|
setupComponentNormalisation (*this);
|
2011-01-21 11:42:29 +01:00
|
|
|
quantisedTime.castInto (*this);
|
|
|
|
|
}
|
2011-01-05 18:15:44 +01:00
|
|
|
|
|
|
|
|
|
2011-01-21 16:22:01 +01:00
|
|
|
SmpteTC::SmpteTC (SmpteTC const& o)
|
|
|
|
|
: TCode(o)
|
|
|
|
|
, effectiveFramerate_(o.effectiveFramerate_)
|
|
|
|
|
{
|
2011-01-22 14:41:58 +01:00
|
|
|
setupComponentNormalisation (*this);
|
2011-01-21 16:22:01 +01:00
|
|
|
sgn = o.sgn;
|
|
|
|
|
hours = o.hours;
|
|
|
|
|
mins = o.mins;
|
|
|
|
|
secs = o.secs;
|
|
|
|
|
frames = o.frames;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SmpteTC&
|
|
|
|
|
SmpteTC::operator= (SmpteTC const& o)
|
|
|
|
|
{
|
|
|
|
|
if (!isSameObject (*this, o))
|
|
|
|
|
{
|
|
|
|
|
TCode::operator= (o);
|
|
|
|
|
effectiveFramerate_ = o.effectiveFramerate_;
|
|
|
|
|
sgn = o.sgn;
|
|
|
|
|
hours = o.hours;
|
|
|
|
|
mins = o.mins;
|
|
|
|
|
secs = o.secs;
|
|
|
|
|
frames = o.frames;
|
|
|
|
|
}
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-01-05 18:15:44 +01:00
|
|
|
/** */
|
|
|
|
|
HmsTC::HmsTC (QuTime const& quantisedTime)
|
2011-01-14 05:33:50 +01:00
|
|
|
: TCode(quantisedTime)
|
|
|
|
|
// : tpoint_(quantisedTime) /////////////////////////////TODO bullshit
|
2011-01-05 18:15:44 +01:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** */
|
|
|
|
|
Secs::Secs (QuTime const& quantisedTime)
|
2011-01-14 05:33:50 +01:00
|
|
|
: TCode(quantisedTime)
|
|
|
|
|
// : sec_(TimeVar(quantisedTime) / GAVL_TIME_SCALE) /////////////TODO bullshit
|
2011-01-05 18:15:44 +01:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-01-18 05:01:25 +01:00
|
|
|
void
|
2011-01-21 20:24:41 +01:00
|
|
|
SmpteTC::clear()
|
|
|
|
|
{
|
|
|
|
|
frames.setValueRaw(0);
|
|
|
|
|
secs.setValueRaw (0);
|
|
|
|
|
mins.setValueRaw (0);
|
|
|
|
|
hours.setValueRaw (0);
|
|
|
|
|
sgn.setValueRaw (+1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SmpteTC::rebuild()
|
2011-01-05 18:15:44 +01:00
|
|
|
{
|
2011-01-21 11:42:29 +01:00
|
|
|
TimeValue point = Format::evaluate (*this, *quantiser_);
|
2011-01-21 20:24:41 +01:00
|
|
|
Format::rebuild (*this, *quantiser_, point);
|
2011-01-21 11:42:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-01-22 18:33:15 +01:00
|
|
|
/** flip the orientation of min, sec, and frames.
|
|
|
|
|
* Besides changing the sign, this will flip the
|
|
|
|
|
* meaning of the component fields, which by
|
|
|
|
|
* definition are always oriented towards zero.
|
|
|
|
|
*
|
|
|
|
|
* Normalised value fields are defined positive,
|
|
|
|
|
* with automatic overflow to next higher field.
|
|
|
|
|
* This might cause the hours to become negative.
|
|
|
|
|
* When invoked in this case, the meaning changes
|
|
|
|
|
* from -h + (m+s+f) to -(h+m+s+f)
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
SmpteTC::invertOrientation()
|
|
|
|
|
{
|
|
|
|
|
int fr (getFps());
|
|
|
|
|
int f (fr - frames); // revert orientation
|
|
|
|
|
int s (60 - secs); // of the components
|
|
|
|
|
int m (60 - mins); //
|
|
|
|
|
int h = -hours; // assumed to be negative
|
|
|
|
|
sgn *= -1; // flip sign field
|
|
|
|
|
|
|
|
|
|
if (f < fr) --s; else f -= fr;
|
|
|
|
|
if (s < 60) --m; else s -= 60;
|
|
|
|
|
if (m < 60) --h; else m -= 60;
|
|
|
|
|
|
|
|
|
|
hours.setValueRaw(h);
|
|
|
|
|
mins = m; // invoking setters
|
|
|
|
|
secs = s; // ensures normalisation
|
|
|
|
|
frames = f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-01-21 11:42:29 +01:00
|
|
|
uint
|
|
|
|
|
SmpteTC::getFps() const
|
|
|
|
|
{
|
|
|
|
|
return effectiveFramerate_; //////////////////////////////////TODO better design. Shouldn't Format::getFramerate(QuantR, TimeValue) be moved here?
|
2011-01-05 18:15:44 +01:00
|
|
|
}
|
|
|
|
|
|
2011-01-18 05:01:25 +01:00
|
|
|
|
|
|
|
|
string
|
|
|
|
|
SmpteTC::show() const
|
2011-01-05 18:15:44 +01:00
|
|
|
{
|
2011-01-18 05:01:25 +01:00
|
|
|
string tc;
|
|
|
|
|
tc.reserve(15);
|
|
|
|
|
tc += sgn.show();
|
|
|
|
|
tc += hours.show();
|
|
|
|
|
tc += ':';
|
|
|
|
|
tc += mins.show();
|
|
|
|
|
tc += ':';
|
|
|
|
|
tc += secs.show();
|
|
|
|
|
tc += ':';
|
|
|
|
|
tc += frames.show();
|
|
|
|
|
return tc;
|
2011-01-05 18:15:44 +01:00
|
|
|
}
|
|
|
|
|
|
2011-01-18 05:01:25 +01:00
|
|
|
SmpteTC&
|
|
|
|
|
SmpteTC::operator++ ()
|
2011-01-05 18:15:44 +01:00
|
|
|
{
|
2011-01-22 02:35:58 +01:00
|
|
|
frames += sgn;
|
2011-01-21 11:42:29 +01:00
|
|
|
return *this;
|
2011-01-05 18:15:44 +01:00
|
|
|
}
|
|
|
|
|
|
2011-01-18 05:01:25 +01:00
|
|
|
SmpteTC&
|
|
|
|
|
SmpteTC::operator-- ()
|
2011-01-05 18:15:44 +01:00
|
|
|
{
|
2011-01-22 02:35:58 +01:00
|
|
|
frames -= sgn;
|
2011-01-21 11:42:29 +01:00
|
|
|
return *this;
|
2011-01-05 18:15:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** */
|
|
|
|
|
int
|
|
|
|
|
HmsTC::getSecs() const
|
|
|
|
|
{
|
|
|
|
|
return lumiera_time_seconds (tpoint_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** */
|
|
|
|
|
int
|
|
|
|
|
HmsTC::getMins() const
|
|
|
|
|
{
|
|
|
|
|
return lumiera_time_minutes (tpoint_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** */
|
|
|
|
|
int
|
|
|
|
|
HmsTC::getHours() const
|
|
|
|
|
{
|
|
|
|
|
return lumiera_time_hours (tpoint_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** */
|
|
|
|
|
double
|
|
|
|
|
HmsTC::getMillis() const
|
|
|
|
|
{
|
|
|
|
|
TODO ("Frame-Quantisation");
|
|
|
|
|
return lumiera_time_millis (tpoint_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** */
|
|
|
|
|
|
2011-01-02 01:21:39 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}} // lib::time
|
|
|
|
|
|