Lumiera  0.pre.03
»edit your freedom«
time-formats-test.cpp
Go to the documentation of this file.
1 /*
2  TimeFormats(Test) - timecode handling and formatting
3 
4  Copyright (C) Lumiera.org
5  2010, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
28 #include "lib/test/run.hpp"
29 //#include "lib/test/test-helper.hpp"
31 #include "lib/time/timequant.hpp"
32 #include "lib/time/timecode.hpp"
33 #include "lib/time/mutation.hpp"
34 #include "lib/format-cout.hpp"
35 #include "lib/util.hpp"
36 
37 #include <string>
38 #include <cstdlib>
39 
40 using boost::lexical_cast;
41 using util::isnil;
42 using std::rand;
43 using std::string;
44 
45 
46 namespace lib {
47 namespace time{
48 namespace test{
49 
51  using util::toString;
52  using format::Frames;
53  using format::Smpte;
54 
55  namespace{
56  const FrameCnt MAX_FRAME = 265*24*60*60*25;
57 
58  string
59  generateRandomFrameNr()
60  {
61  FrameCnt frameNr(0);
62  while (!frameNr)
63  frameNr = rand() % (2*MAX_FRAME) - MAX_FRAME;
64 
65  return toString(frameNr)+"#";
66  }
67  }
68 
69 
70 
71  /****************************************************/
78  class TimeFormats_test : public Test
79  {
80  virtual void
81  run (Arg)
82  {
84 
86 // checkFrames ();
87 // checkSeconds ();
88 // checkHms ();
89  checkSmpte();
90 // checkDropFrame();
91 // checkCopyAssignments();
92  }
93 
94 
105  void
107  {
108  string srcCode = generateRandomFrameNr();
109  PQuant refScale = Quantiser::retrieve("pal0");
110 
111  // get internal (raw) time value
112  TimeValue t1 = format::Frames::parse (srcCode, *refScale);
113  ENSURE (0 != t1);
114 
115  // manipulating
116  TimeVar v1(t1);
117  v1 += Time(FSecs(6,5));
118  CHECK (t1 < v1);
119 
120  // quantising into an external grid
121  QuTime q1 (t1, "pal0");
122  CHECK (q1 == t1);
123 
124  // further mutations (here nudge by +5 grid steps)
125  QuTime q2 = q1;
126  q2.accept (Mutation::nudge(+5));
127  CHECK (q1 < q2);
128 
129  // converting (back) into a timecode format
130  FrameNr frames1(q1);
131  FrameNr frames2(q2);
132  CHECK (5 == frames2 - frames1);
133 
134  q2.accept (Mutation::changeTime(v1));
135  CHECK (30 == q2.formatAs<Frames>() - frames1); // q2 == v1 == t1 + (6*5)/(5*5)sec
136 
137  CHECK (srcCode == string(frames1));
138  CHECK (srcCode != string(frames2));
139 
140  showTimeCode (frames1);
141  showTimeCode (frames2);
142  showTimeCode (q2.formatAs<Smpte>());
143  }
144 
145 
146  template<class TC>
147  void
148  showTimeCode (TC timecode)
149  {
150  cout << timecode.describe()<<"=\""<<timecode<<"\" time = "<< timecode.getTime() << endl;
151  }
152 
153  void
154  checkFrames ()
155  {
156  UNIMPLEMENTED ("verify frame count time format");
157  }
158 
159 
160  void
161  checkSeconds ()
162  {
163  UNIMPLEMENTED ("verify fractional seconds as timecode format");
164  }
165 
166 
167  void
168  checkHms ()
169  {
170  UNIMPLEMENTED ("verify hour-minutes-seconds-millis timecode");
171  }
172 
173 
184  void
186  {
187  Time raw(555,23,42,5);
188  QuTime t1 (raw, "pal0");
189  SmpteTC smpte(t1);
190 
191  cout << "----SMPTE-----" << endl;
192  showTimeCode(smpte);
193  CHECK (" 5:42:23:13" == string(smpte));
194  CHECK (raw - Time(35,0) == smpte.getTime()); // timecode value got quantised towards next lower frame
195  CHECK (13 == smpte.frames);
196  CHECK (23 == smpte.secs);
197  CHECK (42 == smpte.mins);
198  CHECK ( 5 == smpte.hours);
199  CHECK ( 1 == smpte.sgn);
200  CHECK ("SMPTE" == smpte.describe());
201 
202  ++smpte;
203  CHECK (" 5:42:23:14" == string(smpte));
204  smpte.frames += 12;
205  CHECK (" 5:42:24:01" == string(smpte));
206  smpte.secs = -120;
207  CHECK (" 5:40:00:01" == string(smpte));
208  CHECK (smpte.mins-- == 40);
209  CHECK (--smpte.mins == 38);
210  CHECK (" 5:38:00:01" == string(smpte));
211 
212  TimeVar tx = smpte.getTime();
213  CHECK (tx == Time(0,0,38,5) + Time(FSecs(1,25)));
214 
215  // Extended SMPTE: extension of the axis beyond origin towards negative values
216  smpte.hours -= 6;
217  CHECK ("- 0:21:59:24"== string(smpte)); // representation is symmetrical to origin
218  CHECK (tx - Time(0,0,0,6) == smpte.getTime()); // Continuous time axis
219 
220  CHECK (-1 == smpte.sgn); // Note: for these negative (extended) SMPTE...
221  CHECK (smpte.mins > 0); // ...the representation is really flipped around zero
222  CHECK (smpte.secs > 0);
223  CHECK (smpte.frames > 0);
224  tx = smpte.getTime();
225  ++smpte.frames; // now *increasing* the frame value
226  CHECK ("- 0:22:00:00"== string(smpte)); // means decreasing the resulting time
227  CHECK (smpte.getTime() == tx - Time(1000/25,0,0,0));
228  ++smpte; // but the orientation of the increment on the *whole* TC values is unaltered
229  CHECK ("- 0:21:59:24"== string(smpte)); // so this actually *advanced* time by one frame
230  CHECK (tx == smpte.getTime());
231  CHECK (tx < TimeValue(0));
232 
233  smpte.mins -= 2*60; // now lets flip the representation again...
234  CHECK (" 1:38:00:01"== string(smpte));
235  CHECK (+1 == smpte.sgn);
236  CHECK (smpte.getTime() > 0);
237  CHECK (tx + Time(0,0,0,2) == smpte.getTime());
238  smpte.secs -= 2*60*60; // and again...
239  CHECK (tx == smpte.getTime());
240  CHECK ("- 0:21:59:24"== string(smpte));
241 
242  smpte.sgn += 123; // just flip the sign
243  CHECK (" 0:21:59:24"== string(smpte));
244  CHECK (tx == -smpte.getTime());
245  CHECK (+1 == smpte.sgn); // sign value is limited to +1 / -1
246 
247  smpte.secs.setValueRaw(61); // set "wrong" value, bypassing normalisation
248  CHECK (smpte.secs == 61);
249  CHECK (smpte.getTime() == Time(1000*24/25, 01, 22));
250  CHECK (smpte.secs == 61); // calculated value is correct, but doesn't change state
251  CHECK (" 0:21:61:24"== string(smpte));
252  smpte.rebuild(); // but rebuilding the value includes normalisation
253  CHECK (smpte.secs == 1);
254  CHECK (smpte.mins == 22);
255  CHECK (" 0:22:01:24"== string(smpte));
256 
257  smpte.frames.setValueRaw (25);
258  CHECK (" 0:22:01:25"== string(smpte));
259  smpte.hours = -1; // flipped representation handles denormalised values properly
260  CHECK ("- 0:37:58:00"== string(smpte));
261 
262  smpte.mins.setValueRaw (59);
263  smpte.secs.setValueRaw (61);
264  smpte.frames.setValueRaw(-26); // provoke multiple over/underflows...
265  smpte.hours.setValueRaw (-2);
266  CHECK ("--2:59:61:-26"==string(smpte));
267  tx = smpte.getTime();
268  CHECK (tx == -1*(Time(0,61,59) - Time(0,0,0,2) - Time(FSecs(26,25))));
269  smpte.invertOrientation();
270  CHECK (" 1:00:00:01"== string(smpte));
271  CHECK (tx == smpte.getTime()); // applying invertOrientation() doesn't change the value
272 
273  smpte.frames.setValueRaw(-1);
274  tx -= Time(FSecs(2,25));
275  CHECK (tx == smpte.getTime());
276  CHECK (" 1:00:00:-1"== string(smpte));
277  smpte.invertOrientation(); // invoking on positive should create double negated representation
278  CHECK ("--1:00:00:01"== string(smpte)); // and here especially also causes a series of overflows
279  CHECK (tx == smpte.getTime()); // but without affecting the overall value
280  }
281 
282 
283  void
284  checkDropFrame ()
285  {
286  UNIMPLEMENTED ("verify especially SMPTE-drop-frame timecode");
287  }
288 
289 
290  void
291  checkCopyAssignments ()
292  {
293  UNIMPLEMENTED ("verify Timecode values can be copied and assigned properly");
294  }
295  };
296 
297 
299  LAUNCHER (TimeFormats_test, "unit common");
300 
301 
302 
303 }}} // namespace lib::time::test
static TimeValue parse(string const &, QuantR)
try to parse a frame number specification
Definition: timecode.cpp:74
a mutable time value, behaving like a plain number, allowing copy and re-accessing ...
Definition: timevalue.hpp:241
Interface: a grid and scale definition for time quantisation.
Definition: time-grid.hpp:86
Frame count as timecode format.
Definition: formats.hpp:84
Automatically use custom string conversion in C++ stream output.
Classical Timecode value reminiscent to SMPTE format.
Definition: timecode.hpp:150
Modifying time and timecode values.
static PQuant retrieve(Symbol gridID)
Access an existing grid definition or quantiser, known by the given symbolic ID.
static EncapsulatedMutation changeTime(Time)
Convenience factory to yield a simple Mutation changing the absolute start time.
Definition: mutation.cpp:294
Definition: run.hpp:49
Widely used standard media timecode format.
Definition: formats.hpp:99
static PGrid build(FrameRate frames_per_second)
Definition: time-grid.cpp:167
void accept(Mutation const &)
receive change message, which might cause re-quantisation
Implementation namespace for support and library code.
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:308
format::Traits< FMT >::TimeCode formatAs() const
create new time code instance, then castInto
Definition: timequant.hpp:147
Timecode handling library This header defines the foundation interface TCode to represent a grid alig...
Simple test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
std::string toString(TY const &val) noexcept
get some string representation of any object, reliably.
Definition: format-obj.hpp:200
boost::rational< int64_t > FSecs
rational representation of fractional seconds
Definition: timevalue.hpp:229
Support library to represent grid-aligned time specifications This is part of Lumiera&#39;s time and time...
To establish a reference scale for quantised time values.
static EncapsulatedMutation nudge(int adjustment)
build a time mutation to nudge the target time value by an offset, defined as number of steps on an i...
Definition: mutation.cpp:345
int64_t FrameCnt
relative framecount or frame number.
Definition: digxel.hpp:321
A frame counting timecode value.
Definition: timecode.hpp:105
basic constant internal time value.
Definition: timevalue.hpp:142
static const FrameRate PAL
predefined constant for PAL framerate
Definition: timevalue.hpp:680
grid aligned time specification, referring to a specific scale.
Definition: timequant.hpp:99