more updates
[synfig.git] / synfig-core / trunk / src / synfig / time.cpp
1 /* === S I N F G =========================================================== */
2 /*!     \file time.cpp
3 **      \brief Template File
4 **
5 **      $Id: time.cpp,v 1.1.1.1 2005/01/04 01:23:15 darco Exp $
6 **
7 **      \legal
8 **      Copyright (c) 2002 Robert B. Quattlebaum Jr.
9 **
10 **      This software and associated documentation
11 **      are CONFIDENTIAL and PROPRIETARY property of
12 **      the above-mentioned copyright holder.
13 **
14 **      You may not copy, print, publish, or in any
15 **      other way distribute this software without
16 **      a prior written agreement with
17 **      the copyright holder.
18 **      \endlegal
19 */
20 /* ========================================================================= */
21
22 /* === H E A D E R S ======================================================= */
23
24 #ifdef USING_PCH
25 #       include "pch.h"
26 #else
27 #ifdef HAVE_CONFIG_H
28 #       include <config.h>
29 #endif
30
31 #include "time.h"
32 #include <ETL/stringf>
33 #include <ETL/misc>
34 #include "general.h"
35 #include <cmath>
36 #include <cassert>
37 #include <ctype.h>
38 #include <math.h>
39
40 #ifndef isnan
41
42 #ifdef WIN32
43 #include <float.h>
44 #ifndef isnan
45 extern "C" { int _isnan(double x); }
46 #define isnan _isnan
47 #endif
48 #endif
49
50 #ifdef __APPLE__
51 #define isnan __isnan
52 #endif
53
54 #endif
55
56 #endif
57
58 /* === U S I N G =========================================================== */
59
60 using namespace std;
61 using namespace etl;
62 using namespace sinfg;
63
64 #define tolower ::tolower
65
66 /* === M A C R O S ========================================================= */
67
68 /* === G L O B A L S ======================================================= */
69
70 /* === M E T H O D S ======================================================= */
71
72 Time::Time(const String &str_, float fps):
73         value_(0)
74 {
75         String str(str_);
76         std::transform(str.begin(),str.end(),str.begin(),&tolower);
77
78         // Start/Begin Of Time
79         if(str=="SOT" || str=="BOT")
80         {
81                 operator=(begin());
82                 return;
83         }
84         // End Of Time
85         if(str=="EOT")
86         {
87                 operator=(end());
88                 return;
89         }
90
91
92         unsigned int pos=0;
93         int read;
94         float amount;
95         
96         // Now try to read it in the letter-abreviated format
97         while(pos<str.size() && sscanf(String(str,pos).c_str(),"%f%n",&amount,&read))
98         {
99                 pos+=read;
100                 if(pos>=str.size() || read==0)
101                 {
102                         // Throw up a warning if there are no units
103                         // and the amount isn't zero. There is no need
104                         // to warn about units if the value is zero
105                         // it is the only case where units are irrelevant.
106                         if(amount!=0)
107                                 sinfg::warning("Time(): No unit provided in time code, assuming SECONDS (\"%s\")",str.c_str());
108                         value_+=amount;
109                         return;
110                 }
111                 switch(str[pos])
112                 {
113                         case 'h':
114                         case 'H':
115                                 value_+=amount*3600;
116                                 break;
117                         case 'm':
118                         case 'M':
119                                 value_+=amount*60;
120                                 break;
121                         case 's':
122                         case 'S':
123                                 value_+=amount;
124                                 break;
125                         case 'f':
126                         case 'F':
127                                 if(fps)
128                                         value_+=amount/fps;
129                                 else
130                                         sinfg::warning("Time(): Individual frames referenced, but frame rate is unknown");
131                                 break;
132                         case ':':
133                                 // try to read it in as a traditional time format
134                                 {
135                                         int hour,minute,second;
136                                         float frame;
137                                         if(fps && sscanf(str.c_str(),"%d:%d:%d.%f",&hour,&minute,&second,&frame)==4)
138                                         {
139                                                         value_=frame/fps+(hour*3600+minute*60+second);
140                                                         return;
141                                         }
142                         
143                                         if(sscanf(str.c_str(),"%d:%d:%d",&hour,&minute,&second)==3)
144                                         {
145                                                 value_=hour*3600+minute*60+second;
146                                                 return;
147                                         }
148                                 }
149                                 sinfg::warning("Time(): Bad time format");
150                                 break;
151
152                         default:
153                                 value_+=amount;
154                                 sinfg::warning("Time(): Unexpected character '%c' when parsing time string \"%s\"",str[pos],str.c_str());
155                                 break;
156                 }
157                 pos++;
158                 amount=0;
159         }
160 }
161
162 String
163 Time::get_string(float fps, Time::Format format)const
164 {
165         Time time(*this);
166         
167         if(time<=begin())
168                 return "SOT";   // Start Of Time
169         if(time>=end())
170                 return "EOT";   // End Of Time
171         
172         if(fps<0)fps=0;
173         
174         if(ceil(time.value_)-time.value_<epsilon_())
175                 time.value_=ceil(time.value_);
176         
177         int hour,minute;
178         
179         hour=time/3600;time-=hour*3600;
180         minute=time/60;time-=minute*60;
181         
182         if(format<=FORMAT_VIDEO)
183         {
184                 int second;
185                 second=time;time-=second;
186
187                 if(fps)
188                 {
189                         int frame;
190                         frame=round_to_int(time*fps);
191
192                         return strprintf("%02d:%02d:%02d.%02d",hour,minute,second,frame);
193                 }
194                 else
195                         return strprintf("%02d:%02d:%02d",hour,minute,second);
196         }
197         
198         String ret;
199
200         if(format<=FORMAT_FULL || hour)
201                 ret+=strprintf(format<=FORMAT_NOSPACES?"%dh":"%dh ",hour);
202         
203         if(format<=FORMAT_FULL || hour || minute)
204                 ret+=strprintf(format<=FORMAT_NOSPACES?"%dm":"%dm ",minute);
205         
206         if(fps)
207         {
208                 int second;
209                 float frame;
210                 second=time;time-=second;
211                 frame=time*fps;
212                 if(format<=FORMAT_FULL || second)
213                         ret+=strprintf(format<=FORMAT_NOSPACES?"%ds":"%ds ",(int)second);
214                 
215                 if(abs(frame-floor(frame)>=epsilon_()))
216                         ret+=strprintf("%0.3ff",frame);
217                 else
218                         ret+=strprintf("%0.0ff",frame);
219         }
220         else
221         {
222                 float second;
223                 second=time;
224                 if(abs(second-floor(second))>=epsilon_())
225                         ret+=strprintf("%0.8fs",second);
226                 else
227                         ret+=strprintf("%0.0fs",second);
228         }
229         
230         return ret;
231 }
232
233 Time
234 Time::round(float fps)const
235 {
236         assert(fps>0);
237
238         value_type time(*this);
239
240         time*=fps;
241
242         if(abs(time-floor(time))<0.5)
243                 return floor(time)/fps;
244         else
245                 return ceil(time)/fps;
246 }
247
248 //! \writeme
249 bool
250 Time::is_valid()const
251 {
252         return !isnan(value_);
253 }