lumiera_/src/lib/time/formats.hpp
Ichthyostega 20f3252892 Upgrade: down with typename!!
Yet another chainsaw massacre.

One of the most obnoxious annoyances with C++ metaprogramming
is the need to insert `typename` and `template` qualifiers into
most definitions, to help the compiler to cope with the syntax,
which is not context-free.

The recent standards adds several clarifications, so that most
of these qualifiers are redundant now, at least at places where
it is unambiguously clear that only a type can be given.

GCC already supports most of these relaxing rules
(Clang unfortunately lags way behind with support of newer language features...)
2025-07-06 01:19:08 +02:00

247 lines
7 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
FORMATS.hpp - formats for displaying and specifying time
Copyright (C)
2010, 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
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version. See the file COPYING for further details.
*/
/** @file formats.hpp
** Definition of time code formats
** This header is part of the Lumiera time and timecode handling library
** and defines the interfaces and types to deal with the common set of
** time code formats encountered in video editing. The generic handling
** of _quantised time_ can be parametrised to support and comply to these
** specific time code formats.
*/
#ifndef LIB_TIME_FORMATS_H
#define LIB_TIME_FORMATS_H
#include "lib/time/timevalue.hpp"
#include "lib/meta/no-instance.hpp"
#include "lib/meta/typelist.hpp"
#include "lib/meta/generator.hpp"
#include "lib/typed-counter.hpp"
#include <memory>
#include <string>
#include <bitset>
namespace lumiera {
namespace error {
LUMIERA_ERROR_DECLARE (INVALID_TIMECODE); ///< timecode format error, illegal value encountered.
}}
namespace lib {
namespace time {
// ====== forward declarations of concrete Timecode types
class FrameNr;
class SmpteTC;
class HmsTC;
class Secs;
class Quantiser; // API for grid aligning
using QuantR = Quantiser const&;
using PQuant = std::shared_ptr<const Quantiser>;
namespace format {
using std::string;
using lib::meta::NoInstance; // the following types are for metaprogramming only...
/**
* Frame count as timecode format.
* An integral number used to count frames
* can be used as a simple from of time code.
* Indeed the Lumiera vault layer mostly relies
* on these frame counts. As with any timecode, the
* underlying framerate/quantisation remains implicit.
*/
struct Frames
: NoInstance<Frames>
{
static TimeValue parse (string const&, QuantR);
static void rebuild (FrameNr&, QuantR, TimeValue const&);
static TimeValue evaluate (FrameNr const&, QuantR);
};
/**
* Widely used standard media timecode format.
* A SMPTE timestamp addresses individual frames,
* by specifying time as hour-minute-second plus the
* frame number within the actual second.
*/
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&);
static void applyRangeLimitStrategy (SmpteTC&);
};
/**
* The informal hours-minutes-seconds-millisecond timecode.
* As such, this timecode is quantisation agnostic, but usually
* it is used to address some frame or block or otherwise quantised
* entity in time. HMS-Timecode is similar to SMPTE, but uses a
* floating point milliseconds value instead of the frame count
*/
struct Hms
: NoInstance<Hms>
{
static TimeValue parse (string const&, QuantR);
static void rebuild (HmsTC&, QuantR, TimeValue const&);
static TimeValue evaluate (HmsTC const&, QuantR);
};
/**
* Simple timecode specification as fractional seconds.
* Similar to HMS, a specification of seconds is quantisation agnostic,
* but usually some implicit quantisation is used anyway, be it on actual
* data frames, audio frames, or just on some smaller time interval, e.g.
* full milliseconds.
* @note Seconds is implemented as rational number and thus uses
* decimal format, not the usual sexagesimal time format
*/
struct Seconds
: NoInstance<Seconds>
{
static TimeValue parse (string const&, QuantR);
static void rebuild (Secs&, QuantR, TimeValue const&);
static TimeValue evaluate (Secs const&, QuantR);
};
template<class FMT>
struct Traits;
template<>
struct Traits<Frames>
{
using TimeCode = FrameNr;
};
template<>
struct Traits<Smpte>
{
using TimeCode = SmpteTC;
};
template<>
struct Traits<Hms>
{
using TimeCode = HmsTC;
};
template<>
struct Traits<Seconds>
{
using TimeCode = Secs;
};
/* == Descriptor to define Support for specific formats == */
using lib::meta::Types;
using lib::meta::Node;
using lib::meta::Nil;
/**
* Descriptor to denote support for a specific (timecode) format.
* This helper can be used to configure a selection of specific
* timecode formats to be or not to be supported by some facility.
* Formats are described by the format descriptor types defined in
* this header (or elsewhere for additional formats). This helper
* establishes an numeric ID at runtime and uses a bitset to keep
* track of the support for a given format.
*
* @note preconfigured limit #MAXID on the absolute number of
* different Format types; maybe needs to be increased accordingly.
* @warning the actual numeric IDs might vary on each run
* @see TypedContext
*/
class Supported
{
enum { MAXID = 8 };
std::bitset<MAXID> flags_;
template<class F>
IxID
typeID() const
{
return TypedContext<Supported>::ID<F>::get();
}
template<class F, class FS>
Supported
define(Node<F,FS>) ///< @internal set the flag for one Format in the typelist
{
flags_.set (typeID<F>());
return define(FS());
}
Supported define(Nil) { return *this;} ///< @internal recursion end
Supported() { } ///< @note use #formats to set up a new descriptor
public:
/** build a new Descriptor to denote support for all the Formats,
* @param TY typelist holding all the Format types to support
*/
template<typename TY>
static Supported
formats()
{
using SupportedFormats = TY::List;
return Supported().define(SupportedFormats());
}
/** check if a specific Format is supported */
template<class F>
bool
check() const
{
return flags_[typeID<F>()];
}
};
/**
* predefined standard configuration:
* Descriptor for supporting all the classical timecode formats
*/
struct SupportStandardTimecode
: Supported
{
SupportStandardTimecode()
: Supported(formats< Types<Hms,Smpte,Frames,Seconds> >())
{ }
};
}}} // lib::time::format
#endif