diff --git a/src/lib/time/grid.hpp b/src/lib/time/grid.hpp index 50854ea30..f87dc0793 100644 --- a/src/lib/time/grid.hpp +++ b/src/lib/time/grid.hpp @@ -24,7 +24,7 @@ /** @file grid.hpp ** definition of a time grid abstraction for time and timecode handling. ** This interface is the foundation to deal with _quantised_ (grid aligned) - ** time values, as is essential for handling of timecode data. + ** time values, which is essential for handling of timecode data. */ @@ -43,12 +43,13 @@ namespace time { /** * Abstraction of a value alignment grid. * Such a grid has an underlying scale (origin and measurement) - * and is comprised of distinct grid intervals, which can be addressed - * by a ordering number, centred at origin with interval number zero. - * The typical example is a 25fps time frame grid, but indeed the - * spacing of the intervals is not necessarily constant. An entity - * defining such a grid provides functions to calculate the - * grid coordinates and to convert back to plain values. + * and is comprised of consecutive grid intervals, joined at the + * _grid points._ These can be addressed by an ordering number, + * centred at origin with grid point number zero. + * The classical example is a 25fps time frame grid, but in fact + * the length of the intervals is not necessarily constant. An + * entity defining such a grid provides functions to calculate + * the grid coordinates and to convert back to plain values. * This includes a way of rounding to the next lower * grid point, usable for grid aligning values. * diff --git a/src/lib/time/time.cpp b/src/lib/time/time.cpp index 76a988e5d..ce05c2cb6 100644 --- a/src/lib/time/time.cpp +++ b/src/lib/time/time.cpp @@ -55,6 +55,7 @@ extern "C" { #include #include #include +#include #include #include @@ -73,6 +74,9 @@ namespace error = lumiera::error; namespace lib { +namespace meta { + extern const std::string FAILURE_INDICATOR; +} namespace time { @@ -175,17 +179,30 @@ namespace time { } + namespace { + template + string + renderFraction (INT const& frac, Literal postfx) noexcept + try { + std::ostringstream buffer; + if (1 == frac.denominator() or 0 == frac.numerator()) + buffer << frac.numerator() << postfx; + else + buffer << frac < (numerator())+"FPS" - : lexical_cast (numerator()) - + "/" - + lexical_cast (denominator()) - + "FPS"; + return renderFraction (*this, "FPS"); } + /** @internal backdoor to sneak in a raw time value * bypassing any normalisation and limiting */ TimeValue @@ -247,6 +264,13 @@ namespace time { }} // namespace lib::Time +namespace util { + string + StringConv::invoke (lib::time::FSecs val) noexcept + { + return lib::time::renderFraction (val, "sec"); + } +} // namespace util @@ -285,7 +309,7 @@ lumiera_tmpbuf_print_time (gavl_time_t time) gavl_time_t lumiera_rational_to_time (FSecs const& fractionalSeconds) { - return rational_cast (lib::time::TimeValue::SCALE * fractionalSeconds); + return rational_cast (fractionalSeconds * int{lib::time::TimeValue::SCALE}); } gavl_time_t @@ -304,7 +328,7 @@ lumiera_frame_duration (FrameRate const& fps) throw error::Logic ("Impossible to quantise to an zero spaced frame grid" , error::LUMIERA_ERROR_BOTTOM_VALUE); - FSecs duration = rational_cast (1/fps); + FSecs duration = 1 / fps; return lumiera_rational_to_time (duration); } diff --git a/src/lib/time/timecode.cpp b/src/lib/time/timecode.cpp index 2e30a9e79..a1f4ebee6 100644 --- a/src/lib/time/timecode.cpp +++ b/src/lib/time/timecode.cpp @@ -122,14 +122,14 @@ namespace time { static regex fracSecs_parser ("(?:^|[^\\./\\d\\-])(\\-?\\d+)(?:([\\-\\+]\\d+)?/(\\d+))?sec"); //__no leading[./-\d] number [+-] number '/' number 'sec' - #define SUB_EXPR(N) lexical_cast (match[N]) + #define SUB_EXPR(N) lexical_cast (match[N]) smatch match; if (regex_search (seconds, match, fracSecs_parser)) if (match[2].matched) { // complete spec with all parts FSecs fractionalPart (SUB_EXPR(2), SUB_EXPR(3)); - long fullSeconds (SUB_EXPR(1)); + int fullSeconds (SUB_EXPR(1)); return grid.timeOf (fullSeconds + fractionalPart); } else diff --git a/src/lib/time/timevalue.hpp b/src/lib/time/timevalue.hpp index 0755e4969..36c50c515 100644 --- a/src/lib/time/timevalue.hpp +++ b/src/lib/time/timevalue.hpp @@ -205,7 +205,7 @@ namespace time { /** rational representation of fractional seconds * @warning do not mix up gavl_time_t and FSecs */ - typedef boost::rational FSecs; + typedef boost::rational FSecs; /** @@ -550,12 +550,10 @@ namespace time { class FrameRate : public boost::rational { - typedef boost::rational IFrac; - public: FrameRate (uint fps) ; FrameRate (uint num, uint denom); - FrameRate (IFrac const& fractionalRate); + FrameRate (boost::rational const& fractionalRate); // standard copy acceptable; @@ -576,7 +574,7 @@ namespace time { inline FSecs operator/ (int n, FrameRate rate) { - return n / boost::rational_cast (rate); + return FSecs{ n*rate.denominator(), rate.numerator()}; } @@ -621,17 +619,17 @@ namespace time { inline FrameRate::FrameRate (uint fps) - : IFrac (__ensure_nonzero(fps)) + : boost::rational (__ensure_nonzero(fps)) { } inline FrameRate::FrameRate (uint num, uint denom) - : IFrac (__ensure_nonzero(num), denom) + : boost::rational (__ensure_nonzero(num), denom) { } inline - FrameRate::FrameRate (IFrac const& fractionalRate) - : IFrac (__ensure_nonzero(fractionalRate)) + FrameRate::FrameRate (boost::rational const& fractionalRate) + : boost::rational (__ensure_nonzero(fractionalRate)) { } inline double @@ -654,5 +652,16 @@ namespace util { return 0 == dur; } + // repeated or forward declaration, see meta/util.hpp + template + struct StringConv; + + /** specialisation: render fractional seconds (for diagnostics) */ + template<> + struct StringConv + { + static std::string + invoke (lib::time::FSecs) noexcept; + }; } -#endif +#endif /*LIB_TIME_TIMEVALUE_H*/ diff --git a/tests/basics/time/quantiser-basics-test.cpp b/tests/basics/time/quantiser-basics-test.cpp index e37445409..b1eb73b35 100644 --- a/tests/basics/time/quantiser-basics-test.cpp +++ b/tests/basics/time/quantiser-basics-test.cpp @@ -43,8 +43,8 @@ namespace test{ namespace { - const uint MAX_FRAMES = 25*500; - const uint DIRT_GRAIN = 50; + const int MAX_FRAMES = 25*500; + const int DIRT_GRAIN = 50; const FSecs F25(1,25); // duration of one PAL frame @@ -91,10 +91,10 @@ namespace test{ { FixedFrameQuantiser fixQ(25); - uint frames = (rand() % MAX_FRAMES); + int frames = (rand() % MAX_FRAMES); FSecs dirt = (F25 / (2 + rand() % DIRT_GRAIN)); - Time rawTime = Time(frames*F25) + Duration(dirt); ////////////////TICKET #939 : should better use 64bit base type for FSecs ?? + Time rawTime = Time(frames*F25) + Duration(dirt); CHECK (Time( frames *F25) <= rawTime); CHECK (Time((frames+1)*F25) > rawTime); diff --git a/tests/core/steam/asset/meta/time-grid-basics-test.cpp b/tests/core/steam/asset/meta/time-grid-basics-test.cpp index 54f77303e..70578ebdc 100644 --- a/tests/core/steam/asset/meta/time-grid-basics-test.cpp +++ b/tests/core/steam/asset/meta/time-grid-basics-test.cpp @@ -52,8 +52,8 @@ namespace test { namespace { // Test definitions... - const Time testOrigin (12,34); - const FrameRate testFps (5,6); + const Time TEST_ORIGIN (12,34); + const FrameRate TEST_FPS (5,6); const uint MAX_FRAMES = 1000; const uint DIRT_GRAIN = 50; @@ -89,8 +89,8 @@ namespace test { CHECK ( spec.origin == TimeValue(0)); CHECK (!spec.predecessor); - spec.fps = testFps; - spec.origin = testOrigin; + spec.fps = TEST_FPS; + spec.origin = TEST_ORIGIN; PGrid myGrid = spec.commit(); CHECK (myGrid); @@ -101,15 +101,15 @@ namespace test { int randomFrame = (rand() % MAX_FRAMES); Time point (myGrid->timeOf (randomFrame)); - CHECK (point == testOrigin + randomFrame * testFps.duration()); + CHECK (point == TEST_ORIGIN + randomFrame * TEST_FPS.duration()); - uint fract = 2 + rand() % DIRT_GRAIN; - FSecs dirt = rational_cast (1 / testFps / fract); - ASSERT (Time(dirt) < testFps.duration()); + int fract = 2 + rand() % DIRT_GRAIN; + FSecs dirt = (1/TEST_FPS) / fract; + ASSERT (Time(dirt) < TEST_FPS.duration()); ASSERT (0 < dirt); Time dirty(point + Time(dirt)); - CHECK (point == testOrigin + myGrid->gridAlign(dirty)); + CHECK (point == TEST_ORIGIN + myGrid->gridAlign(dirty)); } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index fa8b7458e..2509c69fc 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -44967,8 +44967,7 @@ früher war das so eine typische "nörgel"-Warnung, die man unter den Teppich kehren konnte: 'ey, der Compiler bekommt es ja trotzdem richtig hin.

- - + @@ -44989,8 +44988,7 @@ - - + @@ -45363,9 +45361,144 @@ - - - + + + + + + + + +

+ als "workaround" hatte ich boost::rational<long> genommen +

+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ und wir brauchen die definitiv zum sinnvollen Rechenen mit Zeiten auf micro-Scala +

+ + +
+ + + + + +

+ Der kritsche Fall ist nämlich, wenn wir mit FSecs anfangen, und dann irgendwo in der Rechnung mal Time::SCALE multiplizieren, um auf die µ-Skala zu wechseln. Am Ende der Rechnung würde dann typischerweise ein rational_cast stehen. Damit das funktioniert, muß vor allem der Zähler des Bruches die volle Zeitskala unterstützen. Daher sind 64bit zwingend +

+ + +
+ + +
+
+ + + + + + + + +

+ weil 64bit -> 32bit eine narrowing conversion ist, die zumindest eine Warnung erzeugt +

+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -45406,8 +45539,7 @@ WICHTIG: keine vorgreifende Infos publizieren!!!!!

- - +