draft how to integrate parsing of timecode formats
This commit is contained in:
parent
3139fb7f1e
commit
6b1b6cb805
7 changed files with 132 additions and 15 deletions
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "lib/query.hpp"
|
||||
#include "lib/util.hpp"
|
||||
#include "lib/symbol.hpp"
|
||||
#include "include/logging.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
|
@ -74,7 +75,7 @@ namespace lumiera {
|
|||
|
||||
map<Symbol, regex> regexTable;
|
||||
|
||||
Symbol matchArgument = "\\(\\s*([\\w_\\.\\-]+)\\s*\\),?\\s*";
|
||||
Literal matchArgument = "\\(\\s*([\\w_\\.\\-]+)\\s*\\),?\\s*";
|
||||
regex findPredicate (string("(\\w+)")+matchArgument);
|
||||
|
||||
inline regex&
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "lib/typed-counter.hpp"
|
||||
|
||||
#include <tr1/memory>
|
||||
#include <string>
|
||||
#include <bitset>
|
||||
|
||||
|
||||
|
|
@ -53,6 +54,9 @@ namespace time {
|
|||
|
||||
namespace format {
|
||||
|
||||
LUMIERA_ERROR_DECLARE (INVALID_TIMECODE); ///< timecode format error, illegal value encountered.
|
||||
|
||||
using std::string;
|
||||
using lib::meta::NoInstance; // the following types are for metaprogramming only...
|
||||
|
||||
|
||||
|
|
@ -67,6 +71,7 @@ namespace time {
|
|||
struct Frames
|
||||
: NoInstance<Frames>
|
||||
{
|
||||
static TimeValue parse (string const&, QuantR);
|
||||
static void rebuild (FrameNr&, QuantR, TimeValue const&);
|
||||
static TimeValue evaluate (FrameNr const&, QuantR);
|
||||
};
|
||||
|
|
@ -81,6 +86,7 @@ namespace time {
|
|||
struct Smpte
|
||||
: NoInstance<Smpte>
|
||||
{
|
||||
static TimeValue parse (string const&, QuantR);
|
||||
static void rebuild (SmpteTC&, QuantR, TimeValue const&);
|
||||
static TimeValue evaluate (SmpteTC const&, QuantR);
|
||||
static uint getFramerate (QuantR, TimeValue const&);
|
||||
|
|
@ -98,6 +104,7 @@ namespace time {
|
|||
struct Hms
|
||||
: NoInstance<Hms>
|
||||
{
|
||||
static TimeValue parse (string const&, QuantR);
|
||||
static void rebuild (HmsTC&, QuantR, TimeValue const&);
|
||||
static TimeValue evaluate (HmsTC const&, QuantR);
|
||||
};
|
||||
|
|
@ -115,6 +122,7 @@ namespace time {
|
|||
struct Seconds
|
||||
: NoInstance<Seconds>
|
||||
{
|
||||
static TimeValue parse (string const&, QuantR);
|
||||
static void rebuild (Secs&, QuantR, TimeValue const&);
|
||||
static TimeValue evaluate (Secs const&, QuantR);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -30,12 +30,19 @@
|
|||
#include "lib/util.hpp"
|
||||
|
||||
#include <tr1/functional>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
using std::string;
|
||||
using util::unConst;
|
||||
using util::isSameObject;
|
||||
using util::floorwrap;
|
||||
using boost::regex;
|
||||
using boost::smatch;
|
||||
using boost::regex_search;
|
||||
using boost::lexical_cast;
|
||||
|
||||
namespace error = lumiera::error;
|
||||
|
||||
namespace lib {
|
||||
namespace time {
|
||||
|
|
@ -43,7 +50,101 @@ namespace time {
|
|||
|
||||
TCode::~TCode() { } // emit VTable here....
|
||||
|
||||
namespace format {
|
||||
|
||||
namespace format { /* ================= Timecode implementation details ======== */
|
||||
|
||||
LUMIERA_ERROR_DEFINE (INVALID_TIMECODE, "timecode format error, illegal value encountered");
|
||||
|
||||
|
||||
/** try to parse a frame number specification
|
||||
* @param frameNumber string containing an integral number with trailing '#'
|
||||
* @param frameGrid coordinate system (and thus framerate) to use for the conversion
|
||||
* @return (opaque internal) lumiera time value of the given frame's start position
|
||||
* @throw error::Invalid in case of parsing failure
|
||||
* @note the string may contain any additional content, as long as a
|
||||
* regular-expression search is able to pick out a suitable value
|
||||
*/
|
||||
TimeValue
|
||||
Frames::parse (string const& frameNumber, QuantR frameGrid)
|
||||
{
|
||||
static regex frameNr_parser ("(-?\\d+)#");
|
||||
smatch match;
|
||||
if (regex_search (frameNumber, match, frameNr_parser))
|
||||
return frameGrid.timeOf (lexical_cast<int64_t> (match[1]));
|
||||
else
|
||||
throw error::Invalid ("unable to parse framecount \""+frameNumber+"\""
|
||||
, LUMIERA_ERROR_INVALID_TIMECODE);
|
||||
}
|
||||
|
||||
|
||||
TimeValue
|
||||
Smpte::parse (string const&, QuantR)
|
||||
{
|
||||
UNIMPLEMENTED("parsing SMPTE timecode");
|
||||
}
|
||||
|
||||
|
||||
TimeValue
|
||||
Hms::parse (string const&, QuantR)
|
||||
{
|
||||
UNIMPLEMENTED("parse a hours:mins:secs time specification");
|
||||
}
|
||||
|
||||
|
||||
/** try to parse a time specification in seconds or fractional seconds.
|
||||
* The value is interpreted relative to the origin of a the given time grid
|
||||
* This parser recognises full seconds, fractional seconds and both together.
|
||||
* In any case, the actual number is required to end with a trailing \c 'sec'
|
||||
* @par Example specifications
|
||||
\verbatim
|
||||
12sec --> 12 * GAVL_TIME_SCALE
|
||||
-4sec --> -4 * GAVL_TIME_SCALE
|
||||
5/4sec --> 1.25 * GAVL_TIME_SCALE
|
||||
-5/25sec --> -0.2 * GAVL_TIME_SCALE
|
||||
1+1/2sec --> 1.5 * GAVL_TIME_SCALE
|
||||
1-1/25sec --> 0.96 * GAVL_TIME_SCALE
|
||||
-12-1/4sec --> -11.75 * GAVL_TIME_SCALE
|
||||
\endverbatim
|
||||
* @param seconds string containing a time spec in seconds
|
||||
* @param grid coordinate system the parsed value is based on
|
||||
* @return the corresponding (opaque internal) lumiera time value
|
||||
* @throw error::Invalid in case of parsing failure
|
||||
* @note the string may contain any additional content, as long as a
|
||||
* regular-expression search is able to pick out a suitable value
|
||||
*/
|
||||
TimeValue
|
||||
Seconds::parse (string const& seconds, QuantR grid)
|
||||
{
|
||||
static regex fracSecs_parser ("(-?\\d+)(?:([\\-\\+]\\d+)?/(\\d+))?sec");
|
||||
|
||||
#define SUB_EXPR(N) lexical_cast<long> (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));
|
||||
return grid.timeOf (fullSeconds + fractionalPart);
|
||||
}
|
||||
else
|
||||
if (match[3].matched)
|
||||
{
|
||||
// only a fractional part was given
|
||||
return grid.timeOf (FSecs (SUB_EXPR(1), SUB_EXPR(3)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// just simple non-fractional seconds
|
||||
return grid.timeOf (FSecs (SUB_EXPR(1)));
|
||||
}
|
||||
else
|
||||
throw error::Invalid ("unable to parse \""+seconds+"\" as (fractional)seconds"
|
||||
, LUMIERA_ERROR_INVALID_TIMECODE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** build up a frame count
|
||||
* by quantising the given time value
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ namespace time {
|
|||
|
||||
/**
|
||||
* Interface: fixed format timecode specification.
|
||||
* @see time::Format
|
||||
* @see time::format
|
||||
* @todo WIP-WIP-WIP
|
||||
*/
|
||||
class TCode
|
||||
|
|
@ -76,18 +76,25 @@ namespace time {
|
|||
|
||||
/**
|
||||
* A frame counting timecode value.
|
||||
* This is an hard-coded representation of
|
||||
* TCode<format::Frames>, with additional convenience
|
||||
* constructors and conversions, which basically make
|
||||
* FrameNr values interchangeable with integral numbers.
|
||||
* This is the hard-coded standard representation of
|
||||
* format::Frames, and is defined such as to make FrameNr
|
||||
* values interchangeable with integral numbers.
|
||||
* Like any concrete TCode subclass, it can be created
|
||||
* based on a QuTime value. This way, not only the (raw) TimeValue
|
||||
* is provided, but also the (frame)-Grid to base the frame count on.
|
||||
* But contrary to a QuTime value, a FrameNr value is \em materialised
|
||||
* (rounded) into a definite integral number, stripping the excess
|
||||
* precision contained in the original (raw) TimeValue.
|
||||
* As framecount values are implemented as single display field for an
|
||||
* integral value (time::Digxel), they allow for simple presentation.
|
||||
*/
|
||||
class FrameNr
|
||||
: public TCode
|
||||
, public CountVal
|
||||
{
|
||||
|
||||
string show() const { return string(CountVal::show())+"fr"; }
|
||||
Literal tcID() const { return "Frame-count"; }
|
||||
string show() const { return string(CountVal::show())+"#"; }
|
||||
Literal tcID() const { return "Framecount"; }
|
||||
TimeValue value() const { return Format::evaluate (*this, *quantiser_); }
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -315,7 +315,7 @@ namespace util {
|
|||
* will start with an alphanumeric character.
|
||||
*
|
||||
* @par Example Conversions
|
||||
\verbatim
|
||||
\verbatim
|
||||
"Word" --> 'Word'
|
||||
"a Sentence" --> 'a_Sentence'
|
||||
"trailing Withespace \t \n" --> 'trailing_Withespace'
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ namespace test{
|
|||
void
|
||||
checkSeconds ()
|
||||
{
|
||||
UNIMPLEMENTED ("verify seconds as timecode format");
|
||||
UNIMPLEMENTED ("verify fractional seconds as timecode format");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6764,7 +6764,7 @@ At the level of individual timecode formats, we're lacking a common denominator;
|
|||
&rarr; Quantiser [[implementation details|QuantiserImpl]]
|
||||
</pre>
|
||||
</div>
|
||||
<div title="TimeUsage" modifier="Ichthyostega" modified="201104260244" created="201012230204" tags="design discuss" changecount="25">
|
||||
<div title="TimeUsage" modifier="Ichthyostega" modified="201105122348" created="201012230204" tags="design discuss" changecount="27">
|
||||
<pre>the following collection of usage situations helps to shape the details of the time values and time quantisation design. &rarr; see also [[time quantisation|TimeQuant]]
|
||||
|
||||
;time position of an object
|
||||
|
|
@ -6808,7 +6808,7 @@ The ''problem with playback position'' is -- that indeed it's an attempt to conc
|
|||
Note that the ''display window might be treated as just an independent instance of quantisation''. This is similar to the approach taken above for modifying quantised time span values. We should provide a special kind of time grid, the display coordinates. The origin of these is always defined to the left (lower) side of the interval to be displayed, and they are gauged in screen units (pixels or similar, as used by the GUI toolkit set). The rest is handled by the general quantisation mechanisms. The problem of aligning the display should be transformed into a general facility to align grids, and solved for the general case. Doing so solves the remaining problems with quantised value changes and with ''specifying relative placements'' as well: If we choose to represent them as quantised values, we might (or might not) also choose to apply this //grid-alignment function.//
|
||||
|
||||
!the complete time value usage cycle
|
||||
The way this time value and quantisation handling is designed in Lumiera creates a typical usage path, which actually is a one-way route. We might start out with a textual representation according to a specific ''timecode'' format. This timecode string may be parsed, and typically it will be ''materialised'', by invoking the {{{value()}}}-function. This brings us (back) to the very origin, which is a raw timevalue (''internal time'' value). Now, this time value might be manipulated, compared to other values, combined into a ''time span'' (time point and duration -- the most basic notion of an //object// to be manipulated in the Session). Anyway, at some point these time values need to be related to some ''time scale'' again, leading to ''quantised'' time values, which -- finally -- can be cast into a timecode format for external representation again, thus closing the circle.
|
||||
The way time value and quantisation handling is designed in Lumiera creates a typical usage path, which actually is a one-way route. We might start out with a textual representation according to a specific ''timecode'' format. Assumed we know the implicit underlying ''time grid'' (coordinate system, framerate), this timecode string may be parsed. This brings us (back) to the very origin, which is a raw ~TimeValue (''internal time'' value). Now, this time value might be manipulated, compared to other values, combined into a ''time span'' (time point and duration -- the most basic notion of an //object// to be manipulated in the Session). Anyway, at some point these time values need to be related to some ''time scale'' again, leading to ''quantised'' time values, which -- finally -- can be cast into a timecode format for external representation again, thus closing the circle.
|
||||
|
||||
!substantial problems to be solved
|
||||
* how to [[align multiple grids|TimeGridAlignment]]
|
||||
|
|
@ -7092,14 +7092,14 @@ For now, as of 6/10, we use specialised QueryResolver instances explicitly and d
|
|||
&rarr; QueryRegistration
|
||||
</pre>
|
||||
</div>
|
||||
<div title="ViewerPlayConnection" modifier="Ichthyostega" modified="201011100202" created="201007110305" tags="Model Player spec draft" changecount="6">
|
||||
<div title="ViewerPlayConnection" modifier="Ichthyostega" modified="201105110009" created="201007110305" tags="Model Player spec draft" changecount="7">
|
||||
<pre>for showing output, three entities are involved
|
||||
* the [[Timeline]] holds the relevant part of the model, which gets rendered for playback
|
||||
* by connecting to a viewer component, an actual output target is established
|
||||
* the playback process itself is coordinated by a PlayController, which in turn creates a PlayProcess
|
||||
|
||||
!the viewer connection
|
||||
A viewer element gets connected to a given timeline either by directly attaching it, or by //allocating an available free viewer.// Anyway, as a model element, the viewer is just like another set of global pipes cascaded behind the global pipes present in the timeline. The number and kind of pipes provided is a configurable property of the viewer element &mdash; more specifically: the viewer's SwitchBoard. Thus, connecting a viewer activates the same internal logic employed when connecting a sequence into a timeline or meta-clip: a default channel association is established, which can be overridden persistently (&rarr; OutputMapping). Each of the viewer's pipes in turn gets connected to a system output through an OutputManager slot &mdash; again an output mapping step.
|
||||
A viewer element gets connected to a given timeline either by directly attaching it, or by //allocating an available free viewer.// Anyway, as a model element, the viewer is just like another set of global pipes chained up after the global pipes present in the timeline. The number and kind of pipes provided is a configurable property of the viewer element &mdash; more specifically: the viewer's SwitchBoard. Thus, connecting a viewer activates the same internal logic employed when connecting a sequence into a timeline or meta-clip: a default channel association is established, which can be overridden persistently (&rarr; OutputMapping). Each of the viewer's pipes in turn gets connected to a system output through an OutputManager slot &mdash; again an output mapping step.
|
||||
</pre>
|
||||
</div>
|
||||
<div title="VirtualClip" modifier="Ichthyostega" modified="201011220152" created="200804110321" tags="def Model" changecount="17">
|
||||
|
|
|
|||
Loading…
Reference in a new issue