clean-up: relocate frame quantisation operations
The `FixedFrameQuantiser` relied on three functions from the raw-time handling library. Since this (and NTSC drop-frame) are the only usages, these functions can be relocated into the implemntation translation unit `lib/time/quantiser.cpp` On closer inspection, this reveals some room for improvements: Instead of relying on raw-computation functions written in C, we could rather revert the dependency and express these computations in terms of our Time-entities, which are written in C++, are much more systematic and provide consistency checks and protection against numeric overflow, all integrated with linear arithmetic and concise notation. After performing these rearrangements, most of the functions can be collapsed into ''almost nothing''. This was taken as opportunity to re-check and improve the remaining implementation core of the `FixedFrameQuantiser` -- the handling of extreme corner cases can be much improved, now representing the "grid-local time" as `Offset`, which doubles the possible value range. The reworked unit test shows that, with this change, now the limitation happens prior to quantisation, meaning that we always get a grid-aligned result, even in the most extreme corner cases.
This commit is contained in:
parent
255fc82a1b
commit
27089550d2
7 changed files with 401 additions and 291 deletions
|
|
@ -78,15 +78,6 @@ raw_time_64
|
|||
lumiera_framecount_to_time (uint64_t frameCount, lib::time::FrameRate const& fps);
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the duration of one frame in Lumiera time units.
|
||||
* @param framerate underlying framerate as rational number
|
||||
* @throw error::Logic on zero framerate
|
||||
*/
|
||||
raw_time_64
|
||||
lumiera_frame_duration (lib::time::FrameRate const& fps);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -94,42 +85,6 @@ extern "C" { /* ===================== C interface ======================== */
|
|||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Quantise the given time into a fixed grid, relative to the origin.
|
||||
* The time grid used for quantisation is comprised of equally spaced intervals,
|
||||
* rooted at the given origin. The interval starting with the origin is numbered
|
||||
* as zero. Each interval includes its lower bound, but excludes its upper bound.
|
||||
* @param grid spacing of the grid intervals, measured in TimeValue::Scale (µ-ticks)
|
||||
* @return number of the grid interval containing the given time.
|
||||
* @warning the resulting value is limited to (Time::Min, Time::MAX)
|
||||
*/
|
||||
int64_t
|
||||
lumiera_quantise_frames (raw_time_64 time, raw_time_64 origin, raw_time_64 grid);
|
||||
|
||||
int64_t
|
||||
lumiera_quantise_frames_fps (raw_time_64 time, raw_time_64 origin, uint framerate);
|
||||
|
||||
/**
|
||||
* Similar to #lumiera_quantise_frames, but returns a grid aligned _relative time_.
|
||||
* @return time of start of the grid interval containing the given time,
|
||||
* but measured relative to the origin
|
||||
* @warning because the resulting value needs to be limited to fit into a 64bit long,
|
||||
* the addressable time range can be considerably reduced. For example, if
|
||||
* origin = Time::MIN, then all original time values above zero will be
|
||||
* clipped, because the result, relative to origin, needs to be <= Time::MAX
|
||||
*/
|
||||
raw_time_64
|
||||
lumiera_quantise_time (raw_time_64 time, raw_time_64 origin, raw_time_64 grid);
|
||||
|
||||
/**
|
||||
* Calculate time of a grid point (frame start)
|
||||
* @param nr index number of the grid point (0 is at origin)
|
||||
* @param grid spacing of the grid intervals, measured in TimeValue::Scale (µ-ticks)
|
||||
* @return time point (frame start) on the Lumiera internal time scale
|
||||
*/
|
||||
raw_time_64
|
||||
lumiera_time_of_gridpoint (int64_t nr, raw_time_64 origin, raw_time_64 grid);
|
||||
|
||||
/**
|
||||
* Build a time value by summing up the given components.
|
||||
* @param millis number of milliseconds
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ namespace time {
|
|||
|
||||
|
||||
virtual FrameCnt gridPoint (TimeValue const& raw) const =0;
|
||||
virtual TimeValue gridLocal (TimeValue const& raw) const =0;
|
||||
virtual Offset gridLocal (TimeValue const& raw) const =0;
|
||||
virtual TimeValue timeOf (FrameCnt gridPoint) const =0;
|
||||
virtual TimeValue timeOf (FSecs gridTime, int=0) const =0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
Quantiser - aligning time values to a time grid
|
||||
|
||||
Copyright (C)
|
||||
2010, Hermann Vosseler <Ichthyostega@web.de>
|
||||
2010, Stefan Kangas <skangas@skangas.se>
|
||||
2010-2025, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
**Lumiera** is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
|
|
@ -20,11 +21,9 @@
|
|||
#include "lib/time/quantiser.hpp"
|
||||
#include "lib/time/timevalue.hpp"
|
||||
#include "lib/time/timequant.hpp"
|
||||
#include "lib/time.h"
|
||||
#include "lib/util-quant.hpp"
|
||||
#include "lib/rational.hpp"
|
||||
|
||||
#include <boost/rational.hpp>
|
||||
|
||||
using boost::rational_cast;
|
||||
using std::string;
|
||||
|
||||
|
||||
|
|
@ -33,6 +32,63 @@ namespace error = lumiera::error;
|
|||
namespace lib {
|
||||
namespace time {
|
||||
|
||||
namespace { // implementation: basic frame quantisation....
|
||||
|
||||
/**
|
||||
* Grid-align the raw time to a frame grid, which can be fractional.
|
||||
* @note for extreme values of framerate and framerate_divisor, the
|
||||
* computation is approximative and will be µs-aligned.
|
||||
*/
|
||||
inline int64_t
|
||||
calculate_quantisation (raw_time_64 time, uint64_t framerate, uint64_t framerate_divisor=1)
|
||||
{
|
||||
REQUIRE (framerate);
|
||||
REQUIRE (framerate_divisor);
|
||||
|
||||
const uint64_t MAXRANGE = std::numeric_limits<raw_time_64>::max();
|
||||
const int64_t limit_num = MAXRANGE / framerate;
|
||||
const int64_t limit_den = MAXRANGE / framerate_divisor;
|
||||
const int64_t microScale {lib::time::TimeValue::SCALE};
|
||||
|
||||
// protect against numeric overflow
|
||||
if (abs(time) < limit_num and microScale < limit_den)
|
||||
{
|
||||
// safe to calculate "time * framerate"
|
||||
return util::floordiv (time*int64_t(framerate), microScale*int64_t(framerate_divisor));
|
||||
}
|
||||
else
|
||||
{
|
||||
// direct calculation will overflow;
|
||||
// thus approximate the grid spacing by re-quantisation into µ-tick scale
|
||||
// (since in the end we will alias to the microScale anyway)...
|
||||
const uint64_t LIM{MAXRANGE/microScale};
|
||||
if (framerate > LIM or framerate_divisor > LIM)
|
||||
{
|
||||
framerate = util::reQuant (framerate,framerate_divisor, LIM);
|
||||
framerate_divisor = LIM;
|
||||
}
|
||||
// Note : frameDuration ≡ microScale / (framerate/framerate_divisor)
|
||||
raw_time_64 frameDuration = util::reQuant (framerate_divisor,framerate, microScale);
|
||||
return util::floordiv (time,frameDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Quantise the given time into a fixed grid, relative to the origin.
|
||||
* The time grid used for quantisation is comprised of equally spaced intervals,
|
||||
* rooted at the given origin. The interval starting with the origin is numbered
|
||||
* as zero. Each interval includes its lower bound, but excludes its upper bound.
|
||||
* @param grid spacing of the grid intervals, measured in TimeValue::Scale (µ-ticks)
|
||||
* @return number of the grid interval containing the given time.
|
||||
*/
|
||||
int64_t
|
||||
FixedFrameQuantiser::grid_aligned (TimeValue const& time, TimeValue const& grid)
|
||||
{
|
||||
return util::floordiv (_raw(time), _raw(grid));
|
||||
}
|
||||
|
||||
|
||||
|
||||
PQuant
|
||||
getDefaultGridFallback()
|
||||
|
|
@ -51,7 +107,7 @@ namespace time {
|
|||
/* Note: the ctor QuTime(TimeValue, Symbol) and the static function
|
||||
* PQuant Quantiser::retrieve (Symbol) are defined in common-services.cpp
|
||||
* To use this special convenience shortcuts, you need to link against liblumieracore.so
|
||||
* This allows to use the Advice-system to retrieve grid definitions directly from the session
|
||||
* This allows to use the Advice-system to retrieve grid definitions directly from the session
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -86,7 +142,7 @@ namespace time {
|
|||
|
||||
|
||||
/** convenience shortcut: \em materialise a raw time value
|
||||
* based on this grid or time axis, but returning a raw time value.
|
||||
* based on this grid or time axis, but returning a raw time value.
|
||||
* Implemented as combination of the #gridPoint and #timeOf operations,
|
||||
* i.e. we quantise into this scale, but transform the result back onto
|
||||
* the global raw time value scale.
|
||||
|
|
@ -111,50 +167,52 @@ namespace time {
|
|||
* origin and framerate stored within this quantiser.
|
||||
* @warning returned frame count might exceed the valid
|
||||
* range when converting back into a TimeValue.
|
||||
* @see #lumiera_quantise_frames
|
||||
* @see FixedFrameQuantiser::grid_aligned
|
||||
*/
|
||||
FrameCnt
|
||||
FixedFrameQuantiser::gridPoint (TimeValue const& rawTime) const
|
||||
{
|
||||
return lumiera_quantise_frames (_raw(rawTime), _raw(origin_), _raw(raster_));
|
||||
return grid_aligned (Offset{origin_, rawTime}, raster_);
|
||||
}
|
||||
|
||||
|
||||
/** transform into the local time scale grid aligned.
|
||||
* The actual calculation first determines the number
|
||||
* of the grid interval containing the given rawTime,
|
||||
* then followed by multiplying this interval number
|
||||
* The actual calculation first determines the number of the grid interval
|
||||
* containing the given rawTime, followed by multiplying this interval number
|
||||
* with the grid spacing.
|
||||
* @return time of the start point of the grid interval
|
||||
* containing the rawTime, _relative to the origin_
|
||||
* of the time scale used by this quantiser.
|
||||
* @warning returned time values are limited by the
|
||||
* valid range of lumiera::Time
|
||||
* @see #lumiera_quantise_time
|
||||
* @return time of the start point of the grid interval containing the rawTime,
|
||||
* _relative to the origin_ of the time scale used by this quantiser.
|
||||
* @warning because the resulting value needs to be limited to fit into a 64bit long,
|
||||
* the addressable time range can be considerably reduced. For example, if
|
||||
* origin = Time::MIN, then all original time values above zero will be
|
||||
* clipped, because the result, relative to origin, needs to be <= Time::MAX
|
||||
* @see FixedFrameQuantiser::grid_aligned
|
||||
*/
|
||||
TimeValue
|
||||
Offset
|
||||
FixedFrameQuantiser::gridLocal (TimeValue const& rawTime) const
|
||||
{
|
||||
return TimeValue (lumiera_quantise_time (_raw(rawTime), _raw(origin_), _raw(raster_)));
|
||||
return raster_ * grid_aligned (Offset{origin_, rawTime}
|
||||
,raster_);
|
||||
}
|
||||
|
||||
|
||||
/** calculate time value of a grid interval (frame) start point
|
||||
* @return time point measured in Lumiera internal time
|
||||
* @param gridPoint index number of the grid point (0 is at origin)
|
||||
* @return time point measured in Lumiera internal time
|
||||
* @warning returned time values are limited by the
|
||||
* valid range of lumiera::Time
|
||||
*/
|
||||
TimeValue
|
||||
FixedFrameQuantiser::timeOf (FrameCnt gridPoint) const
|
||||
{
|
||||
return TimeValue (lumiera_time_of_gridpoint (gridPoint, _raw(origin_), _raw(raster_)));
|
||||
return origin_ + gridPoint * raster_;
|
||||
}
|
||||
|
||||
|
||||
/** calculate time coordinates of a time spec relative to this quantised time scale
|
||||
* @param gridTime seconds relative to the origin of this scale
|
||||
* @param gridOffset additional offset in grid intervals (frames)
|
||||
* @return time point measured in Lumiera internal time
|
||||
* @return time point measured in Lumiera internal time
|
||||
* @warning returned time values are limited by the
|
||||
* valid range of lumiera::Time
|
||||
*/
|
||||
|
|
@ -174,5 +232,66 @@ namespace time {
|
|||
|
||||
|
||||
|
||||
}} // lib::time
|
||||
|
||||
|
||||
|
||||
/* ===== NTSC drop-frame conversions ===== */
|
||||
|
||||
namespace { // conversion parameters
|
||||
|
||||
const uint FRAMES_PER_10min = 10*60 * 30000/1001;
|
||||
const uint FRAMES_PER_1min = 1*60 * 30000/1001;
|
||||
const uint DISCREPANCY = (1*60 * 30) - FRAMES_PER_1min;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @remark This function reverses building the drop-frame timecode,
|
||||
* and thus maps a time into consecutive frame numbers
|
||||
* at NTSC framerate (i.e. without gaps)
|
||||
* @param timecode represented as time value in µ-ticks
|
||||
* @return the absolute frame number as addressed by NTSC drop-frame
|
||||
* @todo 2011 I doubt this works correct for negative times!!
|
||||
*/
|
||||
int64_t
|
||||
calculate_ntsc_drop_frame_number (raw_time_64 time)
|
||||
{
|
||||
int64_t frameNr = calculate_quantisation (time, 30000, 1001);
|
||||
|
||||
// partition into 10 minute segments
|
||||
lldiv_t tenMinFrames = lldiv (frameNr, FRAMES_PER_10min);
|
||||
|
||||
// ensure the drop-frame incidents happen at full minutes;
|
||||
// at start of each 10-minute segment *no* drop incident happens,
|
||||
// thus we need to correct discrepancy between nominal/real framerate once:
|
||||
int64_t remainingMinutes = (tenMinFrames.rem - DISCREPANCY) / FRAMES_PER_1min;
|
||||
|
||||
int64_t dropIncidents = (10-1) * tenMinFrames.quot + remainingMinutes;
|
||||
return frameNr + 2*dropIncidents;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @remark This is the mapping function to translate NTSC drop frame
|
||||
* timecode specification into an actual time, with the necessary
|
||||
* skip events every 1.-9. minute, thereby allocating 108 frames
|
||||
* less per hour, than would be required for full 30 fps.
|
||||
* @return raw time value on a µ-tick scale
|
||||
*/
|
||||
raw_time_64
|
||||
build_time_from_ntsc_drop_frame (uint frames, uint secs, uint mins, uint hours)
|
||||
{
|
||||
int64_t total_mins = 60 * hours + mins;
|
||||
int64_t total_frames = 30*60*60 * hours
|
||||
+ 30*60 * mins
|
||||
+ 30 * secs
|
||||
+ frames
|
||||
- 2 * (total_mins - total_mins / 10);
|
||||
raw_time_64 result = _raw (Offset{total_frames, FrameRate::NTSC});
|
||||
|
||||
if (0 != result) // compensate for truncating down on conversion
|
||||
result += 1; // without this adjustment the frame number
|
||||
return result; // would turn out off by -1 on back conversion
|
||||
}
|
||||
|
||||
}} // lib::time
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ namespace time {
|
|||
|
||||
//------Grid-API----------------------------------------------
|
||||
virtual FrameCnt gridPoint (TimeValue const& raw) const =0;
|
||||
virtual TimeValue gridLocal (TimeValue const& raw) const =0;
|
||||
virtual Offset gridLocal (TimeValue const& raw) const =0;
|
||||
virtual TimeValue timeOf (FrameCnt gridPoint) const =0;
|
||||
virtual TimeValue timeOf (FSecs, int =0) const =0;
|
||||
};
|
||||
|
|
@ -142,11 +142,13 @@ namespace time {
|
|||
FixedFrameQuantiser (FrameRate const& frames_per_second, TimeValue referencePoint =TimeValue(0));
|
||||
FixedFrameQuantiser (Duration const& frame_duration, TimeValue referencePoint =TimeValue(0));
|
||||
|
||||
FrameCnt gridPoint (TimeValue const&) const;
|
||||
TimeValue gridLocal (TimeValue const&) const;
|
||||
TimeValue timeOf (FrameCnt gridPoint) const;
|
||||
TimeValue timeOf (FSecs, int =0) const;
|
||||
FrameCnt gridPoint (TimeValue const&) const override;
|
||||
Offset gridLocal (TimeValue const&) const override;
|
||||
TimeValue timeOf (FrameCnt gridPoint) const override;
|
||||
TimeValue timeOf (FSecs, int =0) const override;
|
||||
|
||||
private:
|
||||
static int64_t grid_aligned (TimeValue const&, TimeValue const&);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -402,81 +402,8 @@ lumiera_framecount_to_time (uint64_t frameCount, FrameRate const& fps)
|
|||
return rational_cast<raw_time_64> (lib::time::TimeValue::SCALE * frameCount / framerate);
|
||||
}
|
||||
|
||||
raw_time_64
|
||||
lumiera_frame_duration (FrameRate const& fps)
|
||||
{
|
||||
if (!fps)
|
||||
throw error::Logic ("Impossible to quantise to an zero spaced frame grid"
|
||||
, error::LUMIERA_ERROR_BOTTOM_VALUE);
|
||||
|
||||
FSecs duration = 1 / fps;
|
||||
return lumiera_rational_to_time (duration);
|
||||
}
|
||||
|
||||
|
||||
namespace { // implementation: basic frame quantisation....
|
||||
|
||||
inline int64_t
|
||||
calculate_quantisation (raw_time_64 time, raw_time_64 origin, raw_time_64 grid)
|
||||
{
|
||||
time -= origin;
|
||||
return floordiv (time,grid);
|
||||
}
|
||||
|
||||
inline int64_t
|
||||
calculate_quantisation (raw_time_64 time, raw_time_64 origin, uint framerate, uint framerate_divisor=1)
|
||||
{
|
||||
REQUIRE (framerate);
|
||||
REQUIRE (framerate_divisor);
|
||||
|
||||
const int64_t limit_num = std::numeric_limits<raw_time_64>::max() / framerate;
|
||||
const int64_t limit_den = std::numeric_limits<raw_time_64>::max() / framerate_divisor;
|
||||
const int64_t microScale {lib::time::TimeValue::SCALE};
|
||||
|
||||
// protect against numeric overflow
|
||||
if (abs(time) < limit_num and microScale < limit_den)
|
||||
{
|
||||
// safe to calculate "time * framerate"
|
||||
time -= origin;
|
||||
return floordiv (time*framerate, microScale*framerate_divisor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// direct calculation will overflow.
|
||||
// use the less precise method instead...
|
||||
raw_time_64 frameDuration = microScale / framerate; // truncated to µs
|
||||
return calculate_quantisation (time,origin, frameDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int64_t
|
||||
lumiera_quantise_frames (raw_time_64 time, raw_time_64 origin, raw_time_64 grid)
|
||||
{
|
||||
return calculate_quantisation (time, origin, grid);
|
||||
}
|
||||
|
||||
int64_t
|
||||
lumiera_quantise_frames_fps (raw_time_64 time, raw_time_64 origin, uint framerate)
|
||||
{
|
||||
return calculate_quantisation (time, origin, framerate);
|
||||
}
|
||||
|
||||
raw_time_64
|
||||
lumiera_quantise_time (raw_time_64 time, raw_time_64 origin, raw_time_64 grid)
|
||||
{
|
||||
int64_t count = calculate_quantisation (time, origin, grid);
|
||||
raw_time_64 alignedTime = count * grid;
|
||||
return alignedTime;
|
||||
}
|
||||
|
||||
raw_time_64
|
||||
lumiera_time_of_gridpoint (int64_t nr, raw_time_64 origin, raw_time_64 grid)
|
||||
{
|
||||
raw_time_64 offset = nr * grid;
|
||||
return origin + offset;
|
||||
}
|
||||
|
||||
|
||||
raw_time_64
|
||||
|
|
@ -536,66 +463,6 @@ lumiera_time_frames (raw_time_64 time, uint fps)
|
|||
|
||||
namespace lib {
|
||||
namespace time { ////////////////////////////////////////////////////////////////////////////////////////////TICKET #1259 : move all calculation functions into a C++ namespace
|
||||
|
||||
|
||||
/* ===== NTSC drop-frame conversions ===== */
|
||||
|
||||
namespace { // conversion parameters
|
||||
|
||||
const uint FRAMES_PER_10min = 10*60 * 30000/1001;
|
||||
const uint FRAMES_PER_1min = 1*60 * 30000/1001;
|
||||
const uint DISCREPANCY = (1*60 * 30) - FRAMES_PER_1min;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @remark This function reverses building the drop-frame timecode,
|
||||
* and thus maps a time into consecutive frame numbers
|
||||
* at NTSC framerate (i.e. without gaps)
|
||||
* @param timecode represented as time value in µ-ticks
|
||||
* @return the absolute frame number as addressed by NTSC drop-frame
|
||||
* @todo 2011 I doubt this works correct for negative times!!
|
||||
*/
|
||||
int64_t
|
||||
calculate_ntsc_drop_frame_number (raw_time_64 time)
|
||||
{
|
||||
int64_t frameNr = calculate_quantisation (time, 0, 30000, 1001);
|
||||
|
||||
// partition into 10 minute segments
|
||||
lldiv_t tenMinFrames = lldiv (frameNr, FRAMES_PER_10min);
|
||||
|
||||
// ensure the drop-frame incidents happen at full minutes;
|
||||
// at start of each 10-minute segment *no* drop incident happens,
|
||||
// thus we need to correct discrepancy between nominal/real framerate once:
|
||||
int64_t remainingMinutes = (tenMinFrames.rem - DISCREPANCY) / FRAMES_PER_1min;
|
||||
|
||||
int64_t dropIncidents = (10-1) * tenMinFrames.quot + remainingMinutes;
|
||||
return frameNr + 2*dropIncidents;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @remark This is the mapping function to translate NTSC drop frame
|
||||
* timecode specification into an actual time, with the necessary
|
||||
* skip events every 1.-9. minute, thereby allocating 108 frames
|
||||
* less per hour, than would be required for full 30 fps.
|
||||
* @return raw time value on a µ-tick scale
|
||||
*/
|
||||
raw_time_64
|
||||
build_time_from_ntsc_drop_frame (uint frames, uint secs, uint mins, uint hours)
|
||||
{
|
||||
uint64_t total_mins = 60 * hours + mins;
|
||||
uint64_t total_frames = 30*60*60 * hours
|
||||
+ 30*60 * mins
|
||||
+ 30 * secs
|
||||
+ frames
|
||||
- 2 * (total_mins - total_mins / 10);
|
||||
raw_time_64 result = lumiera_framecount_to_time (total_frames, FrameRate::NTSC);
|
||||
|
||||
if (0 != result) // compensate for truncating down on conversion
|
||||
result += 1; // without this adjustment the frame number
|
||||
return result; // would turn out off by -1 on back conversion
|
||||
}
|
||||
|
||||
|
||||
}} // lib::time
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "lib/time/quantiser.hpp"
|
||||
#include "lib/random.hpp"
|
||||
#include "lib/util.hpp"
|
||||
#include "lib/test/diagnostic-output.hpp"
|
||||
|
||||
using lumiera::error::LUMIERA_ERROR_BOTTOM_VALUE;
|
||||
using util::isnil;
|
||||
|
|
@ -152,91 +153,80 @@ namespace test{
|
|||
void
|
||||
coverQuantisationCornerCases()
|
||||
{
|
||||
// For this test we exploit the limits of the time system
|
||||
Time SUB_MIN{-Duration::MAX};
|
||||
Time SUP_MAX{ Duration::MAX};
|
||||
|
||||
// origin at lower end of the time range
|
||||
FixedFrameQuantiser case1 (1, Time::MIN);
|
||||
CHECK (secs(0) == case1.gridLocal(Time::MIN ));
|
||||
CHECK (secs(0) == case1.gridLocal(Time::MIN +TimeValue(1) ));
|
||||
CHECK (secs(1) == case1.gridLocal(Time::MIN +secs(1) ));
|
||||
CHECK (Time::MAX -secs(1) > case1.gridLocal( secs(-1) ));
|
||||
CHECK (Time::MAX -secs(1) <= case1.gridLocal( secs (0) ));
|
||||
CHECK (Time::MAX > case1.gridLocal( secs (0) ));
|
||||
CHECK (Time::MAX == case1.gridLocal( secs(+1) ));
|
||||
CHECK (Time::MAX == case1.gridLocal( secs(+2) ));
|
||||
FixedFrameQuantiser case1 (1, SUB_MIN);
|
||||
CHECK (secs(0) == case1.gridLocal(SUB_MIN ));
|
||||
CHECK (secs(0) == case1.gridLocal(SUB_MIN +TimeValue(1) ));
|
||||
CHECK (secs(1) == case1.gridLocal(SUB_MIN +secs(1) ));
|
||||
CHECK (SUP_MAX -secs(1) > case1.gridLocal( secs(-1) ));
|
||||
CHECK (SUP_MAX -secs(1) <= case1.gridLocal( secs (0) ));
|
||||
CHECK (SUP_MAX > case1.gridLocal( secs (0) ));
|
||||
CHECK (SUP_MAX > case1.gridLocal( secs(+1) ));
|
||||
CHECK (SUP_MAX > case1.gridLocal( secs(+2) ));
|
||||
|
||||
TimeValue largestPoint = case1.gridLocal(secs (0));
|
||||
CHECK (largestPoint == case1.gridLocal( secs(+1) ));
|
||||
CHECK (largestPoint == case1.gridLocal( secs(+2) ));
|
||||
CHECK (largestPoint < SUP_MAX);
|
||||
CHECK (largestPoint == Offset{secs(1)} * case1.gridPoint(secs(0)));
|
||||
|
||||
// origin at upper end of the time range
|
||||
FixedFrameQuantiser case2 (1, Time::MAX);
|
||||
CHECK (secs( 0) == case2.gridLocal(Time::MAX ));
|
||||
CHECK (secs(-1) == case2.gridLocal(Time::MAX -TimeValue(1) )); // note: next lower frame
|
||||
CHECK (secs(-1) == case2.gridLocal(Time::MAX -secs(1) )); // i.e. the same as a whole frame down
|
||||
CHECK (Time::MIN +secs(1) < case2.gridLocal( secs(+2) ));
|
||||
CHECK (Time::MIN +secs(1) >= case2.gridLocal( secs(+1) ));
|
||||
CHECK (Time::MIN < case2.gridLocal( secs(+1) ));
|
||||
CHECK (Time::MIN == case2.gridLocal( secs( 0) )); // note: because of downward truncating,
|
||||
CHECK (Time::MIN == case2.gridLocal( secs(-1) )); // resulting values will already exceed
|
||||
CHECK (Time::MIN == case2.gridLocal( secs(-2) )); // allowed range and thus will be clipped
|
||||
FixedFrameQuantiser case2 (1, SUP_MAX);
|
||||
CHECK (secs( 0) == case2.gridLocal(SUP_MAX ));
|
||||
CHECK (secs(-1) == case2.gridLocal(SUP_MAX -TimeValue(1) )); // note: next lower frame
|
||||
CHECK (secs(-1) == case2.gridLocal(SUP_MAX -secs(1) )); // i.e. the same as a whole frame down
|
||||
CHECK (SUB_MIN +secs(1) < case2.gridLocal( secs(+2) ));
|
||||
CHECK (SUB_MIN +secs(1) >= case2.gridLocal( secs(+1) ));
|
||||
CHECK (SUB_MIN < case2.gridLocal( secs(+1) ));
|
||||
CHECK (SUB_MIN == case2.gridLocal( secs( 0) )); // note: because of downward truncating,
|
||||
CHECK (SUB_MIN == case2.gridLocal( secs(-1) )); // resulting values will already exceed
|
||||
CHECK (SUB_MIN == case2.gridLocal( secs(-2) )); // allowed range and thus will be clipped
|
||||
|
||||
// use very large frame with size of half the time range
|
||||
Duration hugeFrame(Time::MAX);
|
||||
Duration hugeFrame(SUP_MAX);
|
||||
FixedFrameQuantiser case3 (hugeFrame);
|
||||
CHECK (Time::MIN == case3.gridLocal(Time::MIN ));
|
||||
CHECK (Time::MIN == case3.gridLocal(Time::MIN +TimeValue(1) ));
|
||||
CHECK (Time::MIN == case3.gridLocal( secs(-1) ));
|
||||
CHECK (TimeValue(0) == case3.gridLocal( secs( 0) ));
|
||||
CHECK (TimeValue(0) == case3.gridLocal( secs(+1) ));
|
||||
CHECK (TimeValue(0) == case3.gridLocal(Time::MAX -TimeValue(1) ));
|
||||
CHECK (Time::MAX == case3.gridLocal(Time::MAX ));
|
||||
CHECK (SUB_MIN == case3.gridLocal(SUB_MIN ));
|
||||
CHECK (SUB_MIN == case3.gridLocal(SUB_MIN +TimeValue(1) ));
|
||||
CHECK (SUB_MIN == case3.gridLocal( secs(-1) ));
|
||||
CHECK (TimeValue(0) == case3.gridLocal( secs( 0) ));
|
||||
CHECK (TimeValue(0) == case3.gridLocal( secs(+1) ));
|
||||
CHECK (TimeValue(0) == case3.gridLocal(SUP_MAX -TimeValue(1) ));
|
||||
CHECK (SUP_MAX == case3.gridLocal(SUP_MAX ));
|
||||
|
||||
// now displacing this grid by +1sec....
|
||||
FixedFrameQuantiser case4 (hugeFrame, secs(1));
|
||||
CHECK (Time::MIN == case4.gridLocal(Time::MIN ));
|
||||
CHECK (Time::MIN == case4.gridLocal(Time::MIN +TimeValue(1) )); // clipped...
|
||||
CHECK (Time::MIN == case4.gridLocal(Time::MIN +secs(1) )); // but now exact (unclipped)
|
||||
CHECK (Time::MIN == case4.gridLocal( secs(-1) ));
|
||||
CHECK (Time::MIN == case4.gridLocal( secs( 0) ));
|
||||
CHECK (TimeValue(0) == case4.gridLocal( secs(+1) )); //.....now exactly the frame number zero
|
||||
CHECK (TimeValue(0) == case4.gridLocal(Time::MAX -TimeValue(1) ));
|
||||
CHECK (TimeValue(0) == case4.gridLocal(Time::MAX )); //.......still truncated down to frame #0
|
||||
CHECK (SUB_MIN == case4.gridLocal(SUB_MIN ));
|
||||
CHECK (SUB_MIN == case4.gridLocal(SUB_MIN +TimeValue(1) )); // clipped...
|
||||
CHECK (SUB_MIN == case4.gridLocal(SUB_MIN +secs(1) )); // but now exact (unclipped)
|
||||
CHECK (SUB_MIN == case4.gridLocal( secs(-1) ));
|
||||
CHECK (SUB_MIN == case4.gridLocal( secs( 0) ));
|
||||
CHECK (TimeValue(0) == case4.gridLocal( secs(+1) )); //.....now exactly the frame number zero
|
||||
CHECK (TimeValue(0) == case4.gridLocal(SUP_MAX -TimeValue(1) ));
|
||||
|
||||
|
||||
// think big...
|
||||
Duration superHuge{secs(12345) + hugeFrame};
|
||||
Duration extraHuge{2*hugeFrame};
|
||||
CHECK (extraHuge == Duration::MAX);
|
||||
TimeVar excess{SUP_MAX +secs(1)}; // this is a *loophole* to slide by the limitation of Time values
|
||||
CHECK (SUP_MAX < excess);
|
||||
CHECK (Duration{excess} < excess); // ...yet as soon as we construct another entity, the limitation applies
|
||||
CHECK (Duration{excess} == SUP_MAX);
|
||||
|
||||
// Time::MAX < superHuge < Duration::Max is possible, but we can accommodate only one
|
||||
FixedFrameQuantiser case5 (superHuge);
|
||||
CHECK (TimeValue(0) == case5.gridLocal(Time::MAX ));
|
||||
CHECK (TimeValue(0) == case5.gridLocal(Time::MAX -TimeValue(1) ));
|
||||
CHECK (TimeValue(0) == case5.gridLocal( secs( 1) ));
|
||||
CHECK (TimeValue(0) == case5.gridLocal( secs( 0) ));
|
||||
CHECK (Time::MIN == case5.gridLocal( secs(-1) ));
|
||||
CHECK (Time::MIN == case5.gridLocal(Time::MIN +TimeValue(1) ));
|
||||
CHECK (Time::MIN == case5.gridLocal(Time::MIN ));
|
||||
|
||||
// now with offset
|
||||
FixedFrameQuantiser case6 (superHuge, Time::MAX-secs(1));
|
||||
CHECK (TimeValue(0) == case6.gridLocal(Time::MAX ));
|
||||
CHECK (TimeValue(0) == case6.gridLocal(Time::MAX -TimeValue(1) ));
|
||||
CHECK (TimeValue(0) == case6.gridLocal(Time::MAX -secs(1) ));
|
||||
CHECK (Time::MIN == case6.gridLocal(Time::MAX -secs(2) ));
|
||||
CHECK (Time::MIN == case6.gridLocal( secs( 1) ));
|
||||
CHECK (Time::MIN == case6.gridLocal( secs(-12345) ));
|
||||
CHECK (Time::MIN == case6.gridLocal( secs(-12345-1) ));
|
||||
CHECK (Time::MIN == case6.gridLocal( secs(-12345-2) )); // this would be one frame lower, but is clipped
|
||||
CHECK (Time::MIN == case6.gridLocal(Time::MIN +TimeValue(1) ));
|
||||
CHECK (Time::MIN == case6.gridLocal(Time::MIN )); // same... unable to represent time points before Time::MIN
|
||||
CHECK (SUP_MAX == case4.gridLocal(excess )); // Thus, more by accident, the next higher grid point can be computed
|
||||
|
||||
// maximum frame size is spanning the full time range
|
||||
FixedFrameQuantiser case7 (extraHuge, Time::MIN+secs(1));
|
||||
CHECK (TimeValue(0) == case7.gridLocal(Time::MAX )); // rounded down one frame, i.e. to origin
|
||||
CHECK (TimeValue(0) == case7.gridLocal( secs( 0) ));
|
||||
CHECK (TimeValue(0) == case7.gridLocal(Time::MIN+secs(2) ));
|
||||
CHECK (TimeValue(0) == case7.gridLocal(Time::MIN+secs(1) )); // exactly at origin
|
||||
CHECK (Time::MIN == case7.gridLocal(Time::MIN )); // one frame further down, but clipped to Time::MIN
|
||||
|
||||
// even larger frames aren't possible
|
||||
Duration not_really_larger(secs(10000) + extraHuge);
|
||||
CHECK (extraHuge == not_really_larger);
|
||||
CHECK (secs(1) == case4.timeOf(0));
|
||||
CHECK (excess == case4.timeOf(1)); // The same loophole also allows to generate this next higher grid point
|
||||
CHECK (excess == case4.timeOf(2)); // ...while the next after next will limited in computation
|
||||
|
||||
FixedFrameQuantiser broken (Duration::MAX, SUP_MAX); // Can drive this loophole to the extreme...
|
||||
CHECK (secs(0) == broken.timeOf(-1)); // since there is leeway by one order of magnitude
|
||||
CHECK (SUP_MAX == broken.timeOf(0));
|
||||
CHECK (SUP_MAX+SUP_MAX > Duration::MAX);
|
||||
CHECK (SUP_MAX+SUP_MAX == broken.timeOf(1));
|
||||
CHECK (SUP_MAX+SUP_MAX == broken.timeOf(2));
|
||||
|
||||
// frame sizes below the time micro grid get trapped
|
||||
long subAtomic = 2*TimeValue::SCALE; // too small for this universe...
|
||||
VERIFY_ERROR (BOTTOM_VALUE, FixedFrameQuantiser quark(subAtomic) );
|
||||
|
|
|
|||
|
|
@ -162938,7 +162938,8 @@ Since then others have made contributions, see the log for the history.</font></
|
|||
<node CREATED="1748351475601" ID="ID_828981584" MODIFIED="1748351475601" TEXT="lumiera_time_seconds"/>
|
||||
<node CREATED="1748351482281" ID="ID_76044701" MODIFIED="1748351482281" TEXT="lumiera_time_millis"/>
|
||||
</node>
|
||||
<node CREATED="1748351146392" ID="ID_1900378289" MODIFIED="1748351155511" TEXT="nur C-Test">
|
||||
<node CREATED="1748351146392" ID="ID_1900378289" MODIFIED="1748389490642" TEXT="nur C-Test">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1748351152077" MODIFIED="1748351152077" TEXT="lumiera_quantise_frames_fps"/>
|
||||
<node CREATED="1748351210265" ID="ID_980580438" MODIFIED="1748351210265" TEXT="lumiera_build_time_fps"/>
|
||||
<node CREATED="1748351564782" ID="ID_1914445290" MODIFIED="1748351569194" TEXT="lumiera_time_frames"/>
|
||||
|
|
@ -162966,8 +162967,8 @@ Since then others have made contributions, see the log for the history.</font></
|
|||
<node CREATED="1748351911358" MODIFIED="1748351911358" TEXT="lumiera_time_ntsc_drop_hours"/>
|
||||
<node CREATED="1748351925746" MODIFIED="1748351925746" TEXT="lumiera_tmpbuf_print_time"/>
|
||||
</node>
|
||||
<node CREATED="1748351446052" ID="ID_620111210" MODIFIED="1748351456006" TEXT="nur Timecode-Widget (+ C-Test)"/>
|
||||
<node CREATED="1748350835257" ID="ID_337045682" MODIFIED="1748351145534" TEXT="keine Verwendung">
|
||||
<node CREATED="1748350835257" ID="ID_337045682" MODIFIED="1748389483435" TEXT="keine Verwendung">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1748350857513" ID="ID_1512877366" MODIFIED="1748350857513" TEXT="lumiera_frame_duration"/>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -162980,7 +162981,9 @@ Since then others have made contributions, see the log for the history.</font></
|
|||
</node>
|
||||
<node CREATED="1748350997721" ID="ID_266616127" MODIFIED="1748351028774" TEXT="und außerdem...">
|
||||
<node CREATED="1748351029770" ID="ID_324213134" MODIFIED="1748351034557" TEXT="im Timecode-Widget"/>
|
||||
<node CREATED="1748351035274" ID="ID_1640433443" MODIFIED="1748351046306" TEXT="im C-Test für die Time-Library"/>
|
||||
<node CREATED="1748351035274" ID="ID_1640433443" MODIFIED="1748389509129" TEXT="im C-Test für die Time-Library">
|
||||
<icon BUILTIN="back"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1748352902464" ID="ID_790522662" MODIFIED="1748352905396" TEXT="Probleme">
|
||||
<node CREATED="1748352906772" ID="ID_1144464670" MODIFIED="1748354044614" TEXT="die Dezimator-Funktionen">
|
||||
|
|
@ -163100,15 +163103,27 @@ Since then others have made contributions, see the log for the history.</font></
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1748358751369" ID="ID_920187834" MODIFIED="1748358756276" TEXT="Weg zur Auflösung">
|
||||
<node CREATED="1748358771454" ID="ID_810358375" MODIFIED="1748358805918" TEXT="alle Verwendungen der Komponenten-Accessoren beseitigen"/>
|
||||
<node CREATED="1748358858563" ID="ID_567453270" MODIFIED="1748358892312" TEXT="den Basis-Test neu schreiben, mit einer Literal-Expectation"/>
|
||||
<node CREATED="1748358817067" ID="ID_557771496" MODIFIED="1748358830620" TEXT="Dezimation in Komponenten stets direkt berechnen"/>
|
||||
<node CREATED="1748358907068" ID="ID_918217691" MODIFIED="1748358919181" TEXT="die restlichen Funktionen zur Implementierung"/>
|
||||
<node CREATED="1748358931317" ID="ID_1847347457" MODIFIED="1748358944202" TEXT="Drop-Frame-Algo separat dokumentieren"/>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1748358751369" ID="ID_920187834" MODIFIED="1748389559916" TEXT="Weg zur Auflösung">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node COLOR="#338800" CREATED="1748358771454" ID="ID_810358375" MODIFIED="1748389566617" TEXT="alle Verwendungen der Komponenten-Accessoren beseitigen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1748358858563" ID="ID_567453270" MODIFIED="1748389568085" TEXT="den Basis-Test neu schreiben, mit einer Literal-Expectation">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1748358817067" ID="ID_557771496" MODIFIED="1748389571906" TEXT="Dezimation in Komponenten stets direkt berechnen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1748358907068" ID="ID_918217691" MODIFIED="1748389575707" TEXT="die restlichen Funktionen zur Implementierung">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1748358931317" ID="ID_1847347457" MODIFIED="1748389574283" TEXT="Drop-Frame-Algo separat dokumentieren">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1748350717103" ID="ID_1477694076" MODIFIED="1748350722786" TEXT="Aufräumen">
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1748350717103" ID="ID_1477694076" MODIFIED="1748479104036" TEXT="Aufräumen">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#5b280f" CREATED="1748362636897" ID="ID_793532606" MODIFIED="1748362658768" TEXT="man könnte versuchen, H:M:S fertig zu implementieren">
|
||||
<icon BUILTIN="stop-sign"/>
|
||||
<node CREATED="1748362660474" ID="ID_1457327168" MODIFIED="1748362804911" TEXT="das wäre aber »premature«">
|
||||
|
|
@ -163199,7 +163214,10 @@ Since then others have made contributions, see the log for the history.</font></
|
|||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1748383746542" ID="ID_1117132995" MODIFIED="1748383761481" TEXT="umziehen in Namespace lib::time"/>
|
||||
<node CREATED="1748383717910" ID="ID_6099644" MODIFIED="1748383730804" TEXT="umziehen in Header lib/time/dropframe.hpp"/>
|
||||
<node CREATED="1748383731428" ID="ID_1472070007" MODIFIED="1748383743307" TEXT="Implementierung verbleibt in lib/time/time.cpp"/>
|
||||
<node COLOR="#5b280f" CREATED="1748383731428" ID="ID_1472070007" MODIFIED="1748442507691" TEXT="Implementierung verbleibt in lib/time/time.cpp">
|
||||
<arrowlink COLOR="#6361b7" DESTINATION="ID_1724729549" ENDARROW="Default" ENDINCLINATION="1281;74;" ID="Arrow_ID_444441914" STARTARROW="None" STARTINCLINATION="771;44;"/>
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
</node>
|
||||
<node CREATED="1748383780122" ID="ID_170667006" MODIFIED="1748383790175" TEXT="nur die eigentliche Berechnungslogik erhalten">
|
||||
<node CREATED="1748383816257" ID="ID_1470396784" MODIFIED="1748384512960" TEXT="int64_t calculate_ntsc_drop_frame_number (raw_time_64 timecode)"/>
|
||||
<node CREATED="1748383835599" ID="ID_328152526" MODIFIED="1748385988435" TEXT="raw_time_64 build_time_from_ntsc_drop_frame (frames, secs, mins, hours)"/>
|
||||
|
|
@ -163231,6 +163249,165 @@ Since then others have made contributions, see the log for the history.</font></
|
|||
<node COLOR="#435e98" CREATED="1748388278014" ID="ID_275417741" MODIFIED="1748388508019" TEXT="lumiera_tmpbuf_print_time (raw_time_64 time)"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1748436006749" ID="ID_439524098" MODIFIED="1748479104035" TEXT="verbleibende Funktionen verteilen">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1748436021050" ID="ID_1426888385" MODIFIED="1748436030803" TEXT="generische HIlfsfunktionen">
|
||||
<node CREATED="1748436257559" ID="ID_1140529126" MODIFIED="1748436260804" TEXT="lumiera_rational_to_time">
|
||||
<node CREATED="1748436293884" ID="ID_534358506" MODIFIED="1748436301463" TEXT="technisch kniffelig">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1748436263298" ID="ID_1571065618" MODIFIED="1748436277061" TEXT="könnte Basis für eine RSec-Klasse werden">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1748436280279" ID="ID_1020376151" MODIFIED="1748436289210" TEXT="bisher nur intern von den Time-Entitäten verwendet"/>
|
||||
</node>
|
||||
<node CREATED="1748436314956" ID="ID_135965943" MODIFIED="1748436317043" TEXT="lumiera_framecount_to_time">
|
||||
<node CREATED="1748436317043" ID="ID_1149266151" MODIFIED="1748436333277" TEXT="eigentlich einfach — aber tricky"/>
|
||||
<node CREATED="1748436335001" ID="ID_21451369" MODIFIED="1748436352201" TEXT="auch verwendet von NTSC Drop-frame">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1748436444348" ID="ID_37784063" MODIFIED="1748436473941" TEXT="verwendet eine FrameRate als Argument ⟹ gehört in Klasse FrameRate"/>
|
||||
<node CREATED="1748436579524" ID="ID_47238779" MODIFIED="1748436664963" TEXT="ist bereits Baiss-Implementierung des Konstrukturs Offset{cnt, rate}">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1748436604184" ID="ID_1226697297" MODIFIED="1748436673076" TEXT="FrameCount::duration()">
|
||||
<icon BUILTIN="back"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1748437205734" ID="ID_1510698290" MODIFIED="1748437216165" TEXT="lumiera_build_time">
|
||||
<node CREATED="1748437218033" ID="ID_1983858379" MODIFIED="1748437242305" TEXT="effektiv ist das der Konstrutor Time(ms,s,min,h)"/>
|
||||
<node CREATED="1748437245750" ID="ID_1962316549" MODIFIED="1748437254099" TEXT="sonst jetzt keine Verwendung mehr">
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1748436687122" ID="ID_498539691" MODIFIED="1748436742026" STYLE="bubble" TEXT="können »wegdiskutiert werden« ⟶ Time-Entitäten">
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1748436052160" ID="ID_332930192" MODIFIED="1748479008869" TEXT="Zeit-Quantisierung">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1748436068486" ID="ID_236415016" MODIFIED="1748451420529" TEXT="lumiera_quantise_frames">
|
||||
<arrowlink COLOR="#4e8ead" DESTINATION="ID_830480651" ENDARROW="Default" ENDINCLINATION="153;-10;" ID="Arrow_ID_875820569" STARTARROW="None" STARTINCLINATION="503;54;"/>
|
||||
</node>
|
||||
<node CREATED="1748436074681" ID="ID_867414214" MODIFIED="1748436074681" TEXT="lumiera_quantise_time"/>
|
||||
<node CREATED="1748436080004" ID="ID_308010594" MODIFIED="1748436080004" TEXT="lumiera_time_of_gridpoint"/>
|
||||
<node BACKGROUND_COLOR="#b6c8ba" COLOR="#435e98" CREATED="1748436089328" HGAP="24" ID="ID_1017613960" MODIFIED="1748478999996" STYLE="bubble" TEXT="reine Implementierung ⟶ quantiser.cpp" VSHIFT="13">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1748441710788" ID="ID_929357775" MODIFIED="1748441736850" STYLE="fork" TEXT="sogar umformulieren in Time-Entities">
|
||||
<font NAME="SansSerif" SIZE="10"/>
|
||||
</node>
|
||||
<node CREATED="1748441710788" ID="ID_1159666529" MODIFIED="1748441755465" STYLE="fork" TEXT="als private static in FixedFrameQuantiser">
|
||||
<font NAME="SansSerif" SIZE="10"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1748441710788" ID="ID_830480651" MODIFIED="1748451436980" STYLE="fork" TEXT="grid_aligned() wird sogar zum Implementierungs-Kern">
|
||||
<arrowlink COLOR="#7aabe4" DESTINATION="ID_762146581" ENDARROW="Default" ENDINCLINATION="-166;9;" ID="Arrow_ID_160880569" STARTARROW="None" STARTINCLINATION="53;127;"/>
|
||||
<linktarget COLOR="#4e8ead" DESTINATION="ID_830480651" ENDARROW="Default" ENDINCLINATION="153;-10;" ID="Arrow_ID_875820569" SOURCE="ID_236415016" STARTARROW="None" STARTINCLINATION="503;54;"/>
|
||||
<font NAME="SansSerif" SIZE="10"/>
|
||||
<node COLOR="#434698" CREATED="1748451451319" HGAP="25" ID="ID_439737233" MODIFIED="1748451501391" TEXT="viel besser ⟸ klarer ∧ mit limit-check" VSHIFT="10">
|
||||
<font NAME="SansSerif" SIZE="11"/>
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1748442444116" ID="ID_1724729549" MODIFIED="1748442507692" TEXT="Drop-Frame-Implementierung ebenfalls umziehen">
|
||||
<linktarget COLOR="#6361b7" DESTINATION="ID_1724729549" ENDARROW="Default" ENDINCLINATION="1281;74;" ID="Arrow_ID_444441914" SOURCE="ID_1472070007" STARTARROW="None" STARTINCLINATION="771;44;"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1748443770239" HGAP="27" ID="ID_900416096" MODIFIED="1748443794005" TEXT="verwendet erweiterte Variante von grid_aligned" VSHIFT="37">
|
||||
<icon BUILTIN="info"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1748443795974" ID="ID_1475460893" MODIFIED="1748443808643" TEXT="AUA: in den wenigen Zeilen stecken zwei Bugs">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
</node>
|
||||
<node CREATED="1748443855397" ID="ID_1688939667" MODIFIED="1748443866719" TEXT="ziehe erst mal den Origin-Offset raus"/>
|
||||
<node COLOR="#5b280f" CREATED="1748444585733" ID="ID_1996155038" MODIFIED="1748468854134" TEXT="könnte stets die erweiterte Variante verwenden">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1748468860305" ID="ID_1750630451" MODIFIED="1748468870864" TEXT="ist nicht sinnvoll"/>
|
||||
<node CREATED="1748468871585" ID="ID_1915828426" MODIFIED="1748468899785" TEXT="der einfache Standardfall braucht keine Framerate"/>
|
||||
<node CREATED="1748468900420" ID="ID_1493748826" MODIFIED="1748468930405" TEXT="und ist auch nicht von Overflows bedroht">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Zeiten sind bereits µ-Tick-quantisiert, d.h. eine einfache Division über ein Grid ist stets im Integer-Value range und ohne Fehler ausführbar
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1748449969608" ID="ID_762146581" MODIFIED="1748468816509" TEXT="diese aber neu schreiben ⟵ util::reQuant nutzen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
und zwar wegen der Gefahr numerischer Overflows; die eingebaute Limitierung der Lumiera-Time ist <i>nicht ausreichend:</i> denn die Quantisierung muß die Framerate durch das µ-Grid dividieren, also den Zähler mal 10^6 nehmen
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<linktarget COLOR="#7aabe4" DESTINATION="ID_762146581" ENDARROW="Default" ENDINCLINATION="-166;9;" ID="Arrow_ID_160880569" SOURCE="ID_830480651" STARTARROW="None" STARTINCLINATION="53;127;"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1748452649267" FOLDED="true" ID="ID_1766809889" MODIFIED="1748478967926" TEXT="test Failures">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1748452670184" ID="ID_124809807" MODIFIED="1748452679547" TEXT="QuantiserBasics_test (und diverse andere)"/>
|
||||
<node CREATED="1748454238651" ID="ID_433970184" MODIFIED="1748454264048" TEXT="habe beim Umbau Framerate und Grid-Duration verwechselt"/>
|
||||
<node CREATED="1748454328068" ID="ID_555997242" MODIFIED="1748468961571" TEXT="QuantiserBasics_test : Grenzfall-Bedingung nicht mehr erfüllt">
|
||||
<node CREATED="1748470251934" ID="ID_1257197599" MODIFIED="1748470264939" TEXT="Limitierungen sind nun signifikant anders"/>
|
||||
<node CREATED="1748470265887" ID="ID_1915675840" MODIFIED="1748471065332" TEXT="wir geben nun effektiv einen Offset heraus">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...und das macht durchaus Sinn, grade wegen der starken Limitierung, die ich bisher in diesem Fall demonstriert habe; außerdem ist diese grid-local-Time ohnehin etwas sonderbar, und auch daher ist es sinnvoll, diese als Offset (gegenüber dem Origin) zu modellieren. Sofern der Benutzer in eine normale Lumiera-Time speichert, sind wir wieder zurück bei den alten Limitierungen, aber man kann eben mit diesem Offset auch weiterrechnen, und ihn z.B. zum Origin dazuaddieren (und würde dann im Beispiel wieder bei ganz kleinen Zeiten ankommen)
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1748470276454" ID="ID_1578018466" MODIFIED="1748470869371" TEXT="und dieser ist limitiert auf ± Duration::MAX"/>
|
||||
<node CREATED="1748470870415" ID="ID_1224045565" MODIFIED="1748470884416" TEXT="⟹ Grid-API entspreichend anpassen"/>
|
||||
<node CREATED="1748472727015" ID="ID_762218159" MODIFIED="1748472735878" TEXT="muß dann den Test umschreiben">
|
||||
<node CREATED="1748472736947" ID="ID_1167982787" MODIFIED="1748472745825" TEXT="möchte aber das Prinzip der Demonstration beibehalten"/>
|
||||
<node CREATED="1748472746714" ID="ID_1982316622" MODIFIED="1748472860999" TEXT="muß dafür Hilfskonstanten einführen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...und die Grenzen ausreizen, die das Zeit-Framework (bewußt) erlaubt, wenn man die Typisierung geschickt ausnutzt: denn ein TimeValue wird aus einer anderen Zeit-Enität (absichtlich) ohne weiteren Bounds-Check übernommen. Es sind mithin durchaus TimeValue möglich, die größer sind als Time::MAX
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1748478811956" ID="ID_1509469989" MODIFIED="1748478819810" TEXT="Time SUB_MIN{-Duration::MAX};"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1748478811956" ID="ID_315980503" MODIFIED="1748478819809" TEXT="Time SUP_MAX{ Duration::MAX};"/>
|
||||
</node>
|
||||
<node CREATED="1748472909503" ID="ID_1458117682" MODIFIED="1748472936823" TEXT="die Limitierung passiert nun bereits beim Berchnen des Offset zum Origin"/>
|
||||
<node CREATED="1748472937481" ID="ID_1805019467" MODIFIED="1748472956687" TEXT="das ist viel besser so ⟹ denn damit liegt jedes Ergebnis stets auf dem Grid">
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e9d3ae" COLOR="#a50125" CREATED="1748478829786" ID="ID_1611930745" MODIFIED="1748478859145" TEXT="es gibt hier eine Art Lücke im Sicherheitsnetz">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1748478862377" ID="ID_591567262" MODIFIED="1748478874096" TEXT="TimeVar übernimmt eine andere Zeit-Entität"/>
|
||||
<node CREATED="1748478874828" ID="ID_1454599373" MODIFIED="1748478883719" TEXT="und macht direkte Integer-Arithmetik"/>
|
||||
<node CREATED="1748478884351" ID="ID_1695859043" MODIFIED="1748478892386" TEXT="erst im nächsten Konstruktur wird wieder gelimited"/>
|
||||
<node CREATED="1748478896305" ID="ID_381040546" MODIFIED="1748478930393" TEXT="⟹ das führt dazu, daß die Berechnungen Duration::MAX * 2 erreichen können"/>
|
||||
<node CREATED="1748478931881" ID="ID_1630974569" MODIFIED="1748478955275" TEXT="(aber nicht zuletzt deshalb bin ich um den Faktor 10 unter die tatsächlichen Grenzen gegangen"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue