Lumiera  0.pre.03
»edit your freedom«
quantiser-basics-test.cpp
Go to the documentation of this file.
1 /*
2  QuantiserBasics(Test) - a demo quantiser to cover the basic quantiser API
3 
4  Copyright (C) Lumiera.org
5  2011, 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"
30 #include "lib/time/quantiser.hpp"
31 #include "lib/util.hpp"
32 #include <cstdlib>
33 
34 using lumiera::error::LUMIERA_ERROR_BOTTOM_VALUE;
35 using util::isnil;
36 using std::rand;
37 
38 
39 
40 namespace lib {
41 namespace time{
42 namespace test{
43 
44  namespace {
45 
46  const int MAX_FRAMES = 25*500;
47  const int DIRT_GRAIN = 50;
48 
49  const FSecs F25(1,25); // duration of one PAL frame
50 
51  inline Time
52  secs (int seconds)
53  {
54  return Time(FSecs(seconds));
55  }
56  }
57 
58 
59 
60 
61  /****************************************************/
77  class QuantiserBasics_test : public Test
78  {
79 
80  virtual void
81  run (Arg)
82  {
83  checkSimpleQuantisation ();
84  coverQuantisationStandardCases();
85  coverQuantisationCornerCases();
86  }
87 
88 
89  void
90  checkSimpleQuantisation ()
91  {
92  FixedFrameQuantiser fixQ(25);
93 
94  int frames = (rand() % MAX_FRAMES);
95  FSecs dirt = (F25 / (2 + rand() % DIRT_GRAIN));
96 
97  Time rawTime = Time(frames*F25) + Duration(dirt);
98 
99  CHECK (Time( frames *F25) <= rawTime);
100  CHECK (Time((frames+1)*F25) > rawTime);
101 
102  Time quantTime (fixQ.gridLocal (rawTime));
103 
104  CHECK (Time(frames*F25) == quantTime);
105  }
106 
107 
111  struct TestQuant
113  {
114  TestQuant (int origin=0)
116  { }
117 
118  int
119  quant (int testPoint)
120  {
121  TimeVar quantised = this->gridLocal(TimeValue(testPoint));
122  return int(quantised);
123  }
124  };
125 
126  void
127  coverQuantisationStandardCases()
128  {
129  TestQuant q0;
130  TestQuant q1(1);
131 
132  CHECK ( 6 == q0.quant(7) );
133  CHECK ( 6 == q0.quant(6) );
134  CHECK ( 3 == q0.quant(5) );
135  CHECK ( 3 == q0.quant(4) );
136  CHECK ( 3 == q0.quant(3) );
137  CHECK ( 0 == q0.quant(2) );
138  CHECK ( 0 == q0.quant(1) );
139  CHECK ( 0 == q0.quant(0) );
140  CHECK (-3 == q0.quant(-1));
141  CHECK (-3 == q0.quant(-2));
142  CHECK (-3 == q0.quant(-3));
143  CHECK (-6 == q0.quant(-4));
144 
145  CHECK ( 6 == q1.quant(7) );
146  CHECK ( 3 == q1.quant(6) );
147  CHECK ( 3 == q1.quant(5) );
148  CHECK ( 3 == q1.quant(4) );
149  CHECK ( 0 == q1.quant(3) );
150  CHECK ( 0 == q1.quant(2) );
151  CHECK ( 0 == q1.quant(1) );
152  CHECK (-3 == q1.quant(0) );
153  CHECK (-3 == q1.quant(-1));
154  CHECK (-3 == q1.quant(-2));
155  CHECK (-6 == q1.quant(-3));
156  CHECK (-6 == q1.quant(-4));
157  }
158 
159 
160  void
161  coverQuantisationCornerCases()
162  {
163  // origin at lower end of the time range
164  FixedFrameQuantiser case1 (1, Time::MIN);
165  CHECK (secs(0) == case1.gridLocal(Time::MIN ));
166  CHECK (secs(0) == case1.gridLocal(Time::MIN +TimeValue(1) ));
167  CHECK (secs(1) == case1.gridLocal(Time::MIN +secs(1) ));
168  CHECK (Time::MAX -secs(1) > case1.gridLocal( secs(-1) ));
169  CHECK (Time::MAX -secs(1) <= case1.gridLocal( secs (0) ));
170  CHECK (Time::MAX > case1.gridLocal( secs (0) ));
171  CHECK (Time::MAX == case1.gridLocal( secs(+1) ));
172  CHECK (Time::MAX == case1.gridLocal( secs(+2) ));
173 
174  // origin at upper end of the time range
175  FixedFrameQuantiser case2 (1, Time::MAX);
176  CHECK (secs( 0) == case2.gridLocal(Time::MAX ));
177  CHECK (secs(-1) == case2.gridLocal(Time::MAX -TimeValue(1) )); // note: next lower frame
178  CHECK (secs(-1) == case2.gridLocal(Time::MAX -secs(1) )); // i.e. the same as a whole frame down
179  CHECK (Time::MIN +secs(1) < case2.gridLocal( secs(+2) ));
180  CHECK (Time::MIN +secs(1) >= case2.gridLocal( secs(+1) ));
181  CHECK (Time::MIN < case2.gridLocal( secs(+1) ));
182  CHECK (Time::MIN == case2.gridLocal( secs( 0) )); // note: because of downward truncating,
183  CHECK (Time::MIN == case2.gridLocal( secs(-1) )); // resulting values will already exceed
184  CHECK (Time::MIN == case2.gridLocal( secs(-2) )); // allowed range and thus will be clipped
185 
186  // use very large frame with size of half the time range
187  Duration hugeFrame(Time::MAX);
188  FixedFrameQuantiser case3 (hugeFrame);
189  CHECK (Time::MIN == case3.gridLocal(Time::MIN ));
190  CHECK (Time::MIN == case3.gridLocal(Time::MIN +TimeValue(1) ));
191  CHECK (Time::MIN == case3.gridLocal( secs(-1) ));
192  CHECK (TimeValue(0) == case3.gridLocal( secs( 0) ));
193  CHECK (TimeValue(0) == case3.gridLocal( secs(+1) ));
194  CHECK (TimeValue(0) == case3.gridLocal(Time::MAX -TimeValue(1) ));
195  CHECK (Time::MAX == case3.gridLocal(Time::MAX ));
196 
197  // now displacing this grid by +1sec....
198  FixedFrameQuantiser case4 (hugeFrame, secs(1));
199  CHECK (Time::MIN == case4.gridLocal(Time::MIN ));
200  CHECK (Time::MIN == case4.gridLocal(Time::MIN +TimeValue(1) )); // clipped...
201  CHECK (Time::MIN == case4.gridLocal(Time::MIN +secs(1) )); // but now exact (unclipped)
202  CHECK (Time::MIN == case4.gridLocal( secs(-1) ));
203  CHECK (Time::MIN == case4.gridLocal( secs( 0) ));
204  CHECK (TimeValue(0) == case4.gridLocal( secs(+1) )); //.....now exactly the frame number zero
205  CHECK (TimeValue(0) == case4.gridLocal(Time::MAX -TimeValue(1) ));
206  CHECK (TimeValue(0) == case4.gridLocal(Time::MAX )); //.......still truncated down to frame #0
207 
208  // think big...
209  Duration superHuge{secs(12345) + hugeFrame};
210  Duration extraHuge{2*hugeFrame};
211  CHECK (extraHuge == Duration::MAX);
212 
213  // Time::MAX < superHuge < Duration::Max is possible, but we can accommodate only one
214  FixedFrameQuantiser case5 (superHuge);
215  CHECK (TimeValue(0) == case5.gridLocal(Time::MAX ));
216  CHECK (TimeValue(0) == case5.gridLocal(Time::MAX -TimeValue(1) ));
217  CHECK (TimeValue(0) == case5.gridLocal( secs( 1) ));
218  CHECK (TimeValue(0) == case5.gridLocal( secs( 0) ));
219  CHECK (Time::MIN == case5.gridLocal( secs(-1) ));
220  CHECK (Time::MIN == case5.gridLocal(Time::MIN +TimeValue(1) ));
221  CHECK (Time::MIN == case5.gridLocal(Time::MIN ));
222 
223  // now with offset
224  FixedFrameQuantiser case6 (superHuge, Time::MAX-secs(1));
225  CHECK (TimeValue(0) == case6.gridLocal(Time::MAX ));
226  CHECK (TimeValue(0) == case6.gridLocal(Time::MAX -TimeValue(1) ));
227  CHECK (TimeValue(0) == case6.gridLocal(Time::MAX -secs(1) ));
228  CHECK (Time::MIN == case6.gridLocal(Time::MAX -secs(2) ));
229  CHECK (Time::MIN == case6.gridLocal( secs( 1) ));
230  CHECK (Time::MIN == case6.gridLocal( secs(-12345) ));
231  CHECK (Time::MIN == case6.gridLocal( secs(-12345-1) ));
232  CHECK (Time::MIN == case6.gridLocal( secs(-12345-2) )); // this would be one frame lower, but is clipped
233  CHECK (Time::MIN == case6.gridLocal(Time::MIN +TimeValue(1) ));
234  CHECK (Time::MIN == case6.gridLocal(Time::MIN )); // same... unable to represent time points before Time::MIN
235 
236  // maximum frame size is spanning the full time range
237  FixedFrameQuantiser case7 (extraHuge, Time::MIN+secs(1));
238  CHECK (TimeValue(0) == case7.gridLocal(Time::MAX )); // rounded down one frame, i.e. to origin
239  CHECK (TimeValue(0) == case7.gridLocal( secs( 0) ));
240  CHECK (TimeValue(0) == case7.gridLocal(Time::MIN+secs(2) ));
241  CHECK (TimeValue(0) == case7.gridLocal(Time::MIN+secs(1) )); // exactly at origin
242  CHECK (Time::MIN == case7.gridLocal(Time::MIN )); // one frame further down, but clipped to Time::MIN
243 
244  // even larger frames aren't possible
245  Duration not_really_larger(secs(10000) + extraHuge);
246  CHECK (extraHuge == not_really_larger);
247 
248  // frame sizes below the time micro grid get trapped
249  long subAtomic = 2*TimeValue::SCALE; // too small for this universe...
250  VERIFY_ERROR (BOTTOM_VALUE, FixedFrameQuantiser quark(subAtomic) );
251  VERIFY_ERROR (BOTTOM_VALUE, FixedFrameQuantiser quark(Duration (FSecs (1,subAtomic))) );
252  }
253  };
254 
255 
257  LAUNCHER (QuantiserBasics_test, "unit common");
258 
259 
260 
261 }}} // namespace lib::time::test
a mutable time value, behaving like a plain number, allowing copy and re-accessing ...
Definition: timevalue.hpp:238
static const Duration MAX
maximum possible temporal extension
Definition: timevalue.hpp:513
FixedFrameQuantiser(FrameRate const &frames_per_second, TimeValue referencePoint=TimeValue(0))
Create a quantiser based on a fixed constant spaced grid, rooted at the reference point as origin of ...
Definition: quantiser.cpp:84
Definition: run.hpp:49
Framerate specified as frames per second.
Definition: timevalue.hpp:661
static const gavl_time_t SCALE
Number of micro ticks (µs) per second as basic time scale.
Definition: timevalue.hpp:176
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify a statement indeed raises an exception.
Implementation namespace for support and library code.
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:305
Simple test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
TimeValue gridLocal(TimeValue const &) const
transform into the local time scale grid aligned.
Definition: quantiser.cpp:145
boost::rational< int64_t > FSecs
rational representation of fractional seconds
Definition: timevalue.hpp:226
A collection of frequently used helper functions to support unit testing.
Library functions to support the formation of grid-aligned time values.
Duration is the internal Lumiera time metric.
Definition: timevalue.hpp:474
Test Quantiser allowing to use plain numbers.
basic constant internal time value.
Definition: timevalue.hpp:142
static const Time MAX
Definition: timevalue.hpp:315
Simple stand-alone Quantiser implementation based on a constant sized gird.
Definition: quantiser.hpp:144