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