Time values and Time quantisation ================================= :Author: Hermann Voßeler :Email: :Date: Spring 2011 //Menu: label Time Quantisation .Definitions The term »Time« spans a variety of vastly different entities. + Within a NLE we get to deal with various _flavours of time values._ continuous time:: without any additional assumptions, *points in time* can be specified with arbitrary precision. The time values are just numbers; the point of reference and the meaning is implicit. Within Lumiera, time is encoded as integral number of _micro ticks,_ practically continuous time distance:: a range of time, a *distance* on the time axis, measured with the same arbitrary precision as time points. Distances can be determined by _subtracting_ two time points, consequently they are _signed numbers._ offset:: a distance can be used to adjust (offset) a time or a duration: this means applying a relative change. The _target_ of an offset operation is a time or duration, while it's _argument_ is a distance (synonymous to offset). duration:: the length of a time range yields a *time metric*. + the duration can be defined as the _absolute value_ of the offset between start and endpoint of the time range. A duration always abstracts from the time _when_ this duration or distance happens, the relation to any time scale remains implicit time span:: contrary to a mere duration, a *time interval* or time span is actually _anchored_ at a specific point in time. It can be seen as a _special kind of duration,_ which explicitly states the information _when_ this time span takes place. changing time:: Time values are _immutable,_ like numbers. + Only a *time variable* can be changed -- yet some of the special time entities can recieve link:TimeMutation[mutation messages], allowing e.g. for adjustments to a time interval selection from the GUI '''' internal time:: While the basic continuous time values don't imply any commitment regarding the time scale and origin to be used, actually, within the implementation of the application, the meaning of time values is uniform and free of contradictions. Thus effectively there is an *implementation time scale* -- but its scope of validity is _strictly limited to the implementation level of a single application instance._ It is never exposed and never persisted. It might not be reproducible over multiple instantiations of the application. The implementation reserves the right to recalibrate this internal scale. Later, when Lumiera gains the capability to run within a network of render nodes, these instance connections will include a negotiation about the internal time scale, which remains completely opaque to the outer world. This explains, why `lumiera::Time` instances lack the ability to show their time value beyond debugging purposes. This is to avoid confusion and to stress their opaque nature. wall clock and system time:: The core property of any external real world time is that it is _running_ -- we have to synchronise to an external time source. This implies the presence of a _running synchronisation process,_ with the authority to adjust the time base; + contrast this to the internal time, which is static and unconnected -- quantised time:: The *act of quantisation* transforms a continuous property into a *discrete* structure. Prominent examples can be found in the domain of micro physics and with digital information processing. In a broader sense, any measurement or _quantification_ also encompasses a quantisation. Regarding time and time measurement, quantisation means alignment to a predefined *time grid*. Quantisation necessarily is an _irreversible process_ -- possible additional information is discarded. + Note that quantisation introduces a *time origin* and a *reference scale* frame count:: within the context of film and media editing, the specification of a *frame number* is an especially important instance of quantisation. + all the properties of quantisation apply indeed to this special case: it is a time measurement or specification, where the values are aligned to a grid, and there is a reference time point where the counting starts (origin) and a reference scale (frames per second). Handling of quantised time values in Lumiera is defined such as to ensure the presence of all those bits of information. Without such precautions, operating with bare frame numbers leads itself to all kinds of confusions, mismatches, quantisation errors and unnecessary limitations of functionality. timecode:: Quantisation also is the foundation of all kinds of formalised time specifications actually even a frame count is some kind of (informal) timecode -- other timecodes employ a standardised format. //Every// presentation of time values and every persistent storage and exchange of such values is based on time codes. Yet quantisation and time code aren't identical: a given quantised time value typically can be cast into multiple timecode formats. Patterns for handling quantised time ------------------------------------ When it comes to actually handling quantised time values, several patterns are conceivable for dealing with the quantisation operation and representing quantised data. As guideline for judging these patterns, the general properties of time quantisation, as detailed above, should be taken into account. Quantising a time value means both _discarding information,_ while at the same time _adding explicit information_ pertaining the assumptions of the context. .casual handling this is rather an frequently encountered *anti pattern*. When reading such code, the most striking observation is the sense of general unawareness of the problem, which is then ``discovered'' on a per case base, which leads to numerous repetitions of the same basic undertakings, but done with individual treatment of each instance (not so much copy-n-paste). + Typical code smells: * the rounding, modulo and subtract-base operations pertinent with scale handling are seemingly inserted as bugfix * local code path forks to circumvent or compensate for otherwise hard wired calculations based on specific ways to invoke a function * playing strikingly clever tricks or employing heuristics to "figure out" the missing scale information from accessible context after the fact * advertising support for some of the conceivable cases as special feature, or adding it as plugin or extension module with limited scope * linking parts of the necessary additional information to completely unrelated other structures, thus causing code tangling and scattering * result or behaviour of calculations depends on the way things are set up in a seemingly contingent way, forcing users to stick to very specific procedures and ordered steps. .static typing an analysis of the cases to be expected establishes common patterns and some base cases, which are then represented by distinct types with well established conversions. This can be combined with generic programming for the common parts. Close to the data input, a factory establishes these statically typed values. .Summary **************************************************************************** Lumiera uses (fixed) static typing for the plain _time values_, with a class wrapping a simple 64bit integer as common denominator. The strict typing is used to enforce a sane conversion path to quantised time values. For these grid alinged values, and especially for the common time codes, the principle of _delayed quantisation_ is preferred; the implementation relies on runtime typing with type erasure, but provides conversion to statically tagged values for the most important special formats image:{imgd}/uml.time-entities.png["Time and Time Quantisation in Lumiera"] **************************************************************************** .tagged values quantised values are explicitly created out of continuous values by a quantiser entity. These quantised data values contain a copy of the original data, adjusted to be exactly aligned with respect to the underlying time grid. In addition, they carry a tag or ID to denote the respective scale, grid or timecode system. This tag can be used later on to assess compatibility or to recast values into another timecode system. .delayed quantisation with this approach, the information loss is delayed as long as possible. Quantised time values are rather treated as promise for quantisation, while the actual time data remains unaltered. Additionally, they carry a tag, or even a direct link to the responsible quantiser instance. Effectively, these are specialised time values, instances of a sub-concept, able to stand-in for general time values, but exposing additional accessors to get a quantised value. discussion ~~~~~~~~~~ For Lumiera, the static typing approach is of limited value -- it excels when values belonging to different scales are actually treated differently. There are such cases, but rather on the data handling level, e.g. sound samples are always handled block wise. But regarding time values, the unifying aspect is more important, which leads to prefering a dynamic (run time typed) approach, while _erasing_ the special differences most of the time. Yet the dynamic and open nature of the Lumiera high-level model favours the delayed quantisation pattern; the same values may require different quantisation depending on the larger model context an object is encountered in. This solution might be too general and heavy weight at times though. Thus, for important special cases, the accessors should return tagged values, preferably even with differing static type. Time codes can be integrated this way, but most notably the *frame numbers* used for addressing throughout the vault, can be implemented as such specifically typed tagged values; the tag here denotes the quantiser and thus the underlying grid -- it should be implemented as hash-ID for smooth integration with code written in plain C. At the level of individual timecode formats, we're lacking a common denominator; thus it is preferrable to work with different concrete timecode classes through _generic programming._ This way, each timecode format can expose operations specific only to the given format. Especially, different timecode formats expose different _component fields,_ modelled by the generic *Digxel* concept. There is a common baseclass `TCode` though, which can be used as marker or for _type erasure._ -> more on link:TimeUsage.html[usage situations] //// // TODO integrate those cross links + -> Timecode link:TimecodeFormat[format and quantisation] + -> Quantiser link:QuantiserImpl[implementation details] ////