diff --git a/src/lib/time/quantiser.cpp b/src/lib/time/quantiser.cpp index 567a7d6de..e6d33da42 100644 --- a/src/lib/time/quantiser.cpp +++ b/src/lib/time/quantiser.cpp @@ -40,15 +40,7 @@ namespace time { namespace { // implementation helpers... - template - inline NUM - __ensure_notZero (NUM n) - { - if (!n) - throw error::Logic ("Impossible to quantise to an zero spaced grid" - , error::LUMIERA_ERROR_BOTTOM_VALUE); - return n; - } + ///////////TODO superfluous?? }//(End) implementation helpers @@ -76,7 +68,12 @@ namespace time { * each interval includes its lower bound and excludes its upper bound.*/ FixedFrameQuantiser::FixedFrameQuantiser (FrameRate const& frames_per_second, TimeValue referencePoint) : origin_(referencePoint) - , raster_(frames_per_second.duration()) + , raster_(__ensure_nonzero(frames_per_second.duration())) + { } + + FixedFrameQuantiser::FixedFrameQuantiser (Duration const& frame_duration, TimeValue referencePoint) + : origin_(referencePoint) + , raster_(__ensure_nonzero(frame_duration)) { } diff --git a/src/lib/time/quantiser.hpp b/src/lib/time/quantiser.hpp index 8d79f381e..4f4a38bac 100644 --- a/src/lib/time/quantiser.hpp +++ b/src/lib/time/quantiser.hpp @@ -107,6 +107,7 @@ namespace time { public: FixedFrameQuantiser (FrameRate const& frames_per_second, TimeValue referencePoint =TimeValue(0)); + FixedFrameQuantiser (Duration const& frame_duration, TimeValue referencePoint =TimeValue(0)); TimeValue gridAlign (TimeValue const&); diff --git a/src/lib/time/timevalue.hpp b/src/lib/time/timevalue.hpp index 1a230f605..8a0b1f5fe 100644 --- a/src/lib/time/timevalue.hpp +++ b/src/lib/time/timevalue.hpp @@ -366,7 +366,7 @@ namespace time { inline NUM __ensure_nonzero (NUM n) { - if (!n) + if (n == 0) throw error::Logic ("Zero spaced grid not allowed" , error::LUMIERA_ERROR_BOTTOM_VALUE); return n; @@ -415,7 +415,7 @@ namespace time { { return boost::rational_cast (*this); } - + diff --git a/tests/lib/time/quantiser-basics-test.cpp b/tests/lib/time/quantiser-basics-test.cpp index c719f404b..bd8c11c72 100644 --- a/tests/lib/time/quantiser-basics-test.cpp +++ b/tests/lib/time/quantiser-basics-test.cpp @@ -22,25 +22,15 @@ #include "lib/test/run.hpp" -//#include "lib/test/test-helper.hpp" -//#include "lib/time/timequant.hpp" +#include "lib/test/test-helper.hpp" #include "lib/time/quantiser.hpp" -//#include "lib/time/display.hpp" #include "lib/util.hpp" +#include -#include -//#include -#include -//#include - -using boost::lexical_cast; +using lumiera::error::LUMIERA_ERROR_BOTTOM_VALUE; using util::isnil; -//using util::contains; -//using std::rand; -using std::cout; -using std::endl; +using std::rand; -//using boost::algorithm::join; namespace lib { @@ -52,17 +42,27 @@ namespace test{ const uint MAX_FRAMES = 25*500; const uint MAX_DIRT = 50; - const FSecs F25(1,25); - + const FSecs F25(1,25); // duration of one PAL frame } + /******************************************************** * @test cover the basic Quantiser API. - * This test uses a special quantiser implementation - * with hard coded behaviour to demonstrate and verify - * the usage of a quantiser entity in isolation. + * This test uses a standalone quantiser implementation + * to demonstrate and verify the basic behaviour + * and the usage corner cases of a quantiser. + * + * In this most simple form, a quantiser is defined + * by the time reference point (origin) to use, and + * the frame rate (grid spacing). For each raw time + * value, the quantiser yields a time value aligned + * at the next lower frame bound. Besides that, + * time values are confined to be within + * the interval (Time::MIN, Time::Max) + * + * @see TimeQuantisation_test */ class QuantiserBasics_test : public Test { @@ -84,8 +84,9 @@ namespace test{ uint frames = (rand() % MAX_FRAMES); FSecs dirt = (F25 / (rand() % MAX_DIRT)); - Time rawTime = FSecs(frames, 25) + dirt; - CHECK (Time( frames*F25) <= rawTime); + Time rawTime = dirt + frames*F25; + + CHECK (Time( frames *F25) <= rawTime); CHECK (Time((frames+1)*F25) > rawTime); Time quantTime (fixQ.gridAlign (rawTime)); @@ -149,15 +150,59 @@ namespace test{ void coverQuantisationCornerCases() { + // origin at lower end of the time range FixedFrameQuantiser case1 (1, Time::MIN); - CHECK (Time(0) == case1.gridAlign(Time::MIN)); - CHECK (Time(0) == case1.gridAlign(Time::MIN + TimeValue(1) )); - CHECK (Time(1) == case1.gridAlign(Time::MIN + Time(1) )); - CHECK (Time::MAX - Time(1) > case1.gridAlign( Time(-1) )); - CHECK (Time::MAX - Time(1) <= case1.gridAlign( Time (0) )); - CHECK (Time::MAX > case1.gridAlign( Time (0) )); - CHECK (Time::MAX == case1.gridAlign( Time(+1) )); - CHECK (Time::MAX == case1.gridAlign( Time(+2) )); + CHECK (Time(0) == case1.gridAlign(Time::MIN )); + CHECK (Time(0) == case1.gridAlign(Time::MIN +TimeValue(1) )); + CHECK (Time(1) == case1.gridAlign(Time::MIN +Time(1) )); + CHECK (Time::MAX -Time(1) > case1.gridAlign( Time(-1) )); + CHECK (Time::MAX -Time(1) <= case1.gridAlign( Time (0) )); + CHECK (Time::MAX > case1.gridAlign( Time (0) )); + CHECK (Time::MAX == case1.gridAlign( Time(+1) )); + CHECK (Time::MAX == case1.gridAlign( Time(+2) )); + + // origin at upper end of the time range + FixedFrameQuantiser case2 (1, Time::MAX); + CHECK (Time( 0) == case2.gridAlign(Time::MAX )); + CHECK (Time(-1) == case2.gridAlign(Time::MAX -TimeValue(1) )); // note: next lower frame + CHECK (Time(-1) == case2.gridAlign(Time::MAX -Time(1) )); // i.e. the same as a whole frame down + CHECK (Time::MIN +Time(1) < case2.gridAlign( Time(+2) )); + CHECK (Time::MIN +Time(1) >= case2.gridAlign( Time(+1) )); + CHECK (Time::MIN < case2.gridAlign( Time(+1) )); + CHECK (Time::MIN == case2.gridAlign( Time( 0) )); // note: because of downward truncating, + CHECK (Time::MIN == case2.gridAlign( Time(-1) )); // resulting values will already exceed + CHECK (Time::MIN == case2.gridAlign( Time(-2) )); // allowed range and thus will be clipped + + // maximum frame size is half the time range + Duration hugeFrame(Offset(Time::MAX)); + FixedFrameQuantiser case3 (hugeFrame); + CHECK (Time::MIN == case3.gridAlign(Time::MIN )); + CHECK (Time::MIN == case3.gridAlign(Time::MIN +TimeValue(1) )); + CHECK (Time::MIN == case3.gridAlign( Time(-1) )); + CHECK (Time(0) == case3.gridAlign( Time( 0) )); + CHECK (Time(0) == case3.gridAlign( Time(+1) )); + CHECK (Time(0) == case3.gridAlign(Time::MAX -TimeValue(1) )); + CHECK (Time::MAX == case3.gridAlign(Time::MAX )); + + // now displacing this grid by +1sec.... + FixedFrameQuantiser case4 (hugeFrame, Time(1)); + CHECK (Time::MIN == case4.gridAlign(Time::MIN )); + CHECK (Time::MIN == case4.gridAlign(Time::MIN +TimeValue(1) )); // clipped... + CHECK (Time::MIN == case4.gridAlign(Time::MIN +Time(1) )); // but now exact (unclipped) + CHECK (Time::MIN == case4.gridAlign( Time(-1) )); + CHECK (Time::MIN == case4.gridAlign( Time( 0) )); + CHECK (Time(0) == case4.gridAlign( Time(+1) )); //.....now exactly the frame number zero + CHECK (Time(0) == case4.gridAlign(Time::MAX -TimeValue(1) )); + CHECK (Time(0) == case4.gridAlign(Time::MAX )); //.......still truncated down to frame #0 + + // larger frames aren't possible + Duration not_really_larger(Time(10000) + hugeFrame); + CHECK (hugeFrame == not_really_larger); + + // frame sizes below the time micro grid get trapped + long subAtomic = 2*GAVL_TIME_SCALE; // too small for this universe... + VERIFY_ERROR (BOTTOM_VALUE, FixedFrameQuantiser quark(subAtomic) ); + VERIFY_ERROR (BOTTOM_VALUE, FixedFrameQuantiser quark(Duration (FSecs (1,subAtomic))) ); } };