Blame synfig-core/src/synfig/time.cpp

Carlos Lopez a09598
/* === S Y N F I G ========================================================= */
Carlos Lopez a09598
/*!	\file time.cpp
Carlos Lopez a09598
**	\brief Template File
Carlos Lopez a09598
**
Carlos Lopez a09598
**	$Id$
Carlos Lopez a09598
**
Carlos Lopez a09598
**	\legal
Carlos Lopez a09598
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
Carlos Lopez a09598
**	Copyright (c) 2007, 2008 Chris Moore
Carlos Lopez a09598
**  Copyright (c) 2008 Gerco Ballintijn
Carlos Lopez a09598
**  Copyright (c) 2008 Carlos Lรณpez
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is free software; you can redistribute it and/or
Carlos Lopez a09598
**	modify it under the terms of the GNU General Public License as
Carlos Lopez a09598
**	published by the Free Software Foundation; either version 2 of
Carlos Lopez a09598
**	the License, or (at your option) any later version.
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is distributed in the hope that it will be useful,
Carlos Lopez a09598
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
Carlos Lopez a09598
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Carlos Lopez a09598
**	General Public License for more details.
Carlos Lopez a09598
**	\endlegal
Carlos Lopez a09598
*/
Carlos Lopez a09598
/* ========================================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === H E A D E R S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef USING_PCH
Carlos Lopez a09598
#	include "pch.h"
Carlos Lopez a09598
#else
Carlos Lopez a09598
#ifdef HAVE_CONFIG_H
Carlos Lopez a09598
#	include <config.h></config.h>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
6eb56a
#include <cassert></cassert>
6eb56a
#include <cctype></cctype>
6eb56a
#include <cmath></cmath>
6eb56a
#include <cstdio></cstdio>
6eb56a
6eb56a
#include <algorithm></algorithm>
6eb56a
Carlos Lopez a09598
#include <etl stringf=""></etl>
Carlos Lopez a09598
#include <etl misc=""></etl>
6eb56a
Carlos Lopez a09598
#include "general.h"
6eb56a
#include "real.h"
6eb56a
6eb56a
#include "time.h"
6eb56a
bw 94d8a6
#include <synfig localization.h=""></synfig>
Carlos Lopez a09598
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
/* === U S I N G =========================================================== */
Carlos Lopez a09598
Carlos Lopez a09598
using namespace std;
Carlos Lopez a09598
using namespace etl;
Carlos Lopez a09598
using namespace synfig;
Carlos Lopez a09598
Carlos Lopez a09598
#define tolower ::tolower
Carlos Lopez a09598
Carlos Lopez a09598
/* === M A C R O S ========================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === G L O B A L S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === M E T H O D S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
Time::Time(const String &str_, float fps):
Carlos Lopez a09598
	value_(0)
Carlos Lopez a09598
{
Carlos Lopez a09598
	String str(str_);
Carlos Lopez a09598
	std::transform(str.begin(),str.end(),str.begin(),&tolower);
Carlos Lopez a09598
Carlos Lopez a09598
	// Start/Begin Of Time
Carlos Lopez a09598
	if(str=="sot" || str=="bot")
Carlos Lopez a09598
	{
Carlos Lopez a09598
		operator=(begin());
Carlos Lopez a09598
		return;
Carlos Lopez a09598
	}
Carlos Lopez a09598
	// End Of Time
Carlos Lopez a09598
	if(str=="eot")
Carlos Lopez a09598
	{
Carlos Lopez a09598
		operator=(end());
Carlos Lopez a09598
		return;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
	unsigned int pos=0;
Carlos Lopez a09598
	int read;
Carlos Lopez a09598
	float amount;
Carlos Lopez a09598
Carlos Lopez a09598
	// Now try to read it in the letter-abbreviated format
Carlos Lopez a09598
	while(pos
Carlos Lopez a09598
	{
Carlos Lopez a09598
		pos+=read;
Carlos Lopez a09598
		if(pos>=str.size() || read==0)
Carlos Lopez a09598
		{
Carlos Lopez a09598
			// Throw up a warning if there are no units
Carlos Lopez a09598
			// and the amount isn't zero. There is no need
Carlos Lopez a09598
			// to warn about units if the value is zero
Carlos Lopez a09598
			// it is the only case where units are irrelevant.
Carlos Lopez 40bd85
			if(amount!=0 && fps)
Carlos Lopez 40bd85
			{
Carlos Lopez 40bd85
				synfig::warning(_("Time(): No unit provided in time code, assuming FRAMES (\"%s\")"),str.c_str());
Carlos Lopez 40bd85
				value_+=amount/fps;
Carlos Lopez 40bd85
			}
Carlos Lopez 40bd85
			else
Carlos Lopez 40bd85
			{
Carlos Lopez 40bd85
				synfig::warning(_("Time(): No unit provided in time code and frame rate is unknown! Assuming SECONDS"));
Carlos Lopez 40bd85
				value_+=amount;
Carlos Lopez 40bd85
			}
Carlos Lopez a09598
			return;
Carlos Lopez a09598
		}
Carlos Lopez a09598
		switch(str[pos])
Carlos Lopez a09598
		{
Carlos Lopez a09598
			case 'h':
Carlos Lopez a09598
			case 'H':
Carlos Lopez a09598
				value_+=amount*3600;
Carlos Lopez a09598
				break;
Carlos Lopez a09598
			case 'm':
Carlos Lopez a09598
			case 'M':
Carlos Lopez a09598
				value_+=amount*60;
Carlos Lopez a09598
				break;
Carlos Lopez a09598
			case 's':
Carlos Lopez a09598
			case 'S':
Carlos Lopez a09598
				value_+=amount;
Carlos Lopez a09598
				break;
Carlos Lopez a09598
			case 'f':
Carlos Lopez a09598
			case 'F':
Carlos Lopez a09598
				if(fps)
Carlos Lopez a09598
					value_+=amount/fps;
Carlos Lopez a09598
				else
Carlos Lopez a09598
					synfig::warning("Time(): Individual frames referenced, but frame rate is unknown");
Carlos Lopez a09598
				break;
Carlos Lopez a09598
			case ':':
Carlos Lopez a09598
				// try to read it in as a traditional time format
Carlos Lopez a09598
				{
Carlos Lopez a09598
					int hour,minute,second;
Carlos Lopez a09598
					float frame;
Carlos Lopez a09598
					if(fps && sscanf(str.c_str(),"%d:%d:%d.%f",&hour,&minute,&second,&frame)==4)
Carlos Lopez a09598
					{
Carlos Lopez a09598
							value_=frame/fps+(hour*3600+minute*60+second);
Carlos Lopez a09598
							return;
Carlos Lopez a09598
					}
Carlos Lopez a09598
Carlos Lopez a09598
					if(sscanf(str.c_str(),"%d:%d:%d",&hour,&minute,&second)==3)
Carlos Lopez a09598
					{
Carlos Lopez a09598
						value_=hour*3600+minute*60+second;
Carlos Lopez a09598
						return;
Carlos Lopez a09598
					}
Carlos Lopez a09598
				}
Carlos Lopez a09598
				synfig::warning("Time(): Bad time format");
Carlos Lopez a09598
				break;
Carlos Lopez a09598
Carlos Lopez a09598
			default:
Carlos Lopez a09598
				value_+=amount;
Carlos Lopez a09598
				synfig::warning("Time(): Unexpected character '%c' when parsing time string \"%s\"",str[pos],str.c_str());
Carlos Lopez a09598
				break;
Carlos Lopez a09598
		}
Carlos Lopez a09598
		pos++;
Carlos Lopez a09598
		amount=0;
Carlos Lopez a09598
	}
Carlos Lopez a09598
}
Carlos Lopez a09598
ff1868
// This functions suggests what time is in seconds
ff1868
std::string Time::get_string(Time::Format format) const
ff1868
{
ff1868
	Time time(*this);
ff1868
	if (time <= begin())
ff1868
		return "SOT";	// Start Of Time
ff1868
	if (time >= end())
ff1868
		return "EOT";	// End Of Time
ff1868
ff1868
	if(format <= FORMAT_NORMAL)
ff1868
	{
ff1868
		synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
ff1868
		return strprintf("%.3f", (float)time);
ff1868
	}
ff1868
ff1868
ff1868
	if(format<=FORMAT_VIDEO)
ff1868
	{
ff1868
		int hours, minutes, seconds, microseconds;
ff1868
		hours = time / 3600;
ff1868
		time -= hours*3600;
ff1868
ff1868
		minutes = time / 60;
ff1868
		time -= minutes*60;
ff1868
ff1868
		seconds=time;
ff1868
		time -= seconds;
ff1868
ff1868
		microseconds = time*1000;
ff1868
ff1868
		return strprintf("%02d:%02d:%02d.%02d", hours, minutes, seconds, microseconds);
ff1868
	}
ff1868
ff1868
	synfig::error(_("Translating Time to unknown format (not implemented)"));
ff1868
ff1868
	return "";
ff1868
}
ff1868
Carlos Lopez a09598
String
Carlos Lopez a09598
Time::get_string(float fps, Time::Format format)const
Carlos Lopez a09598
{
Carlos Lopez a09598
	Time time(*this);
Carlos Lopez a09598
Carlos Lopez a09598
	if(time<=begin())
Carlos Lopez a09598
		return "SOT";	// Start Of Time
Carlos Lopez a09598
	if(time>=end())
Carlos Lopez a09598
		return "EOT";	// End Of Time
Carlos Lopez a09598
Carlos Lopez a09598
	if(fps<0)fps=0;
Carlos Lopez a09598
Carlos Lopez a09598
	if(ceil(time.value_)-time.value_
Carlos Lopez a09598
		time.value_=ceil(time.value_);
Carlos Lopez a09598
Carlos Lopez a09598
	int hour = 0, minute = 0;
Carlos Lopez a09598
	if(!(format<=FORMAT_FRAMES))
Carlos Lopez a09598
	{
Carlos Lopez a09598
		hour=time/3600;time-=hour*3600;
Carlos Lopez a09598
		minute=time/60;time-=minute*60;
Carlos Lopez a09598
	}
Carlos Lopez a09598
	// <= is redefined, so this means "is the FORMAT_VIDEO bit set in the format?"
Carlos Lopez a09598
	if(format<=FORMAT_VIDEO)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		int second;
Carlos Lopez a09598
		second=time;time-=second;
Carlos Lopez a09598
Carlos Lopez a09598
		if(fps && fps>1)
Carlos Lopez a09598
		{
Carlos Lopez a09598
			int frame;
Carlos Lopez a09598
			frame=round_to_int(time*fps);
Carlos Lopez a09598
Carlos Lopez a09598
			return strprintf("%02d:%02d:%02d.%02d",hour,minute,second,frame);
Carlos Lopez a09598
		}
Carlos Lopez a09598
		else
Carlos Lopez a09598
			return strprintf("%02d:%02d:%02d",hour,minute,second);
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	if (format <= FORMAT_FRAMES)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		if (fps && fps>0)
Carlos Lopez a09598
			return strprintf("%df", round_to_int(time * fps));
Carlos Lopez a09598
		else
Carlos Lopez a09598
			return strprintf("%ds", round_to_int(time * 1));
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	String ret;
Carlos Lopez a09598
	bool started = false;
Carlos Lopez a09598
Carlos Lopez a09598
	if(format<=FORMAT_FULL || hour)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		ret+=strprintf("%dh",hour);
Carlos Lopez a09598
		started = true;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	if(format<=FORMAT_FULL || minute)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		if (!(format<=FORMAT_NOSPACES) && started)
Carlos Lopez a09598
			ret += " ";
Carlos Lopez a09598
Carlos Lopez a09598
		ret += strprintf("%dm", minute);
Carlos Lopez a09598
		started = true;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	if(fps && fps>1)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		int second;
Carlos Lopez a09598
		float frame;
Carlos Lopez a09598
		second=time;time-=second;
Carlos Lopez a09598
		frame=time*fps;
Carlos Lopez a09598
Carlos Lopez a09598
		if(format<=FORMAT_FULL || second)
Carlos Lopez a09598
		{
Carlos Lopez a09598
			if (!(format<=FORMAT_NOSPACES) && started)
Carlos Lopez a09598
				ret += " ";
Carlos Lopez a09598
Carlos Lopez a09598
			ret += strprintf("%ds", (int)second);
Carlos Lopez a09598
			started = true;
Carlos Lopez a09598
		}
Carlos Lopez a09598
Carlos Lopez a09598
		if(format<=FORMAT_FULL || abs(frame) > epsilon_() || !started)
Carlos Lopez a09598
		{
Carlos Lopez a09598
			if (!(format<=FORMAT_NOSPACES) && started)
Carlos Lopez a09598
				ret += " ";
Carlos Lopez a09598
3b709a
			if (fabs(frame-floor(frame)) >= epsilon_())
Carlos Lopez a09598
				ret += strprintf("%0.3ff", frame);
Carlos Lopez a09598
			else
Carlos Lopez a09598
				ret += strprintf("%0.0ff", frame);
Carlos Lopez a09598
		}
Carlos Lopez a09598
	}
Carlos Lopez a09598
	else
Carlos Lopez a09598
	{
Carlos Lopez a09598
		float second;
Carlos Lopez a09598
		second=time;
Carlos Lopez a09598
		if(format<=FORMAT_FULL || second || !started)
Carlos Lopez a09598
		{
Carlos Lopez a09598
			if (!(format<=FORMAT_NOSPACES) && started)
Carlos Lopez a09598
				ret += " ";
Carlos Lopez a09598
Carlos Lopez a09598
			if(abs(second-floor(second))>=epsilon_())
Carlos Lopez a09598
			{
Carlos Lopez a09598
				String seconds(strprintf("%0.8f",second));
Carlos Lopez a09598
Carlos Lopez a09598
				// skip trailing zeros
Carlos Lopez a09598
				int count = 0;
Carlos Lopez a09598
				String::reverse_iterator i = seconds.rbegin();
Carlos Lopez a09598
				for ( ; (*i) == '0'; i++)
Carlos Lopez a09598
					count++;
Carlos Lopez a09598
Carlos Lopez a09598
				// if we removed too many, go back one place, leaving one zero
Carlos Lopez a09598
				if (*i < '0' || *i > '9') count--;
Carlos Lopez a09598
Carlos Lopez a09598
				ret += seconds.substr(0, seconds.size()-count) + "s";
Carlos Lopez a09598
			}
Carlos Lopez a09598
			else
Carlos Lopez a09598
				ret+=strprintf("%0.0fs",second);
Carlos Lopez a09598
		}
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	return ret;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
Time
Carlos Lopez a09598
Time::round(float fps)const
Carlos Lopez a09598
{
6eb56a
	// the aim is to make results for the same frame are absolutelly idential
6eb56a
	assert(approximate_greater_lp(fps, 0.f));
6eb56a
	if (!approximate_greater_lp(fps, 0.f)) return *this;
6eb56a
	return Time(floor(value_*fps + 0.5)/fps);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef _DEBUG
Carlos Lopez a09598
const char *
Carlos Lopez a09598
Time::c_str()const
Carlos Lopez a09598
{
Carlos Lopez a09598
	return get_string().c_str();
Carlos Lopez a09598
}
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
//! \writeme
Carlos Lopez a09598
bool
Carlos Lopez a09598
Time::is_valid()const
Carlos Lopez a09598
{
[d.j.a.y] Jerome Blanchi c14c8d
	return !std::isnan(value_);
Carlos Lopez a09598
}