Implementation: building a simple time grid

This commit is contained in:
Fischlurch 2010-12-31 05:59:53 +01:00
parent 640d061de6
commit 04db5655f1
11 changed files with 285 additions and 60 deletions

View file

@ -125,7 +125,8 @@ namespace lumiera {
LUMIERA_ERROR_DECLARE (WRONG_TYPE); ///< runtime type mismatch
LUMIERA_ERROR_DECLARE (ITER_EXHAUST); ///< end of sequence reached
LUMIERA_ERROR_DECLARE (BOTTOM_VALUE); ///< invalid or NIL value
LUMIERA_ERROR_DECLARE (UNCONNECTED); ///< missing connection
LUMIERA_ERROR_DECLARE (UNCONNECTED); ///< missing connection
LUMIERA_ERROR_DECLARE (UNIMPLEMENTED);///< unimplemented feature

View file

@ -82,7 +82,9 @@ namespace lumiera {
LUMIERA_ERROR_DEFINE (WRONG_TYPE, "runtime type mismatch");
LUMIERA_ERROR_DEFINE (ITER_EXHAUST, "end of sequence reached");
LUMIERA_ERROR_DEFINE (BOTTOM_VALUE, "invalid or NIL value");
LUMIERA_ERROR_DEFINE (UNCONNECTED, "missing connection");
LUMIERA_ERROR_DEFINE (UNCONNECTED, "missing connection");
LUMIERA_ERROR_DEFINE (UNIMPLEMENTED, "using a feature not yet implemented....");
} // namespace error

49
src/lib/time/display.hpp Normal file
View file

@ -0,0 +1,49 @@
/*
DISPLAY.hpp - formatting of time values for display
Copyright (C) Lumiera.org
2010, Hermann Vosseler <Ichthyostega@web.de>
This program 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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LIB_TIME_DISPLAY_H
#define LIB_TIME_DISPLAY_H
#include "lib/time/timecode.hpp"
#include <iostream>
#include <string>
namespace lib {
namespace time {
/** writes time value, formatted as HH:MM:SS:mmm
* @see lumiera_tmpbuf_print_time */
inline std::ostream&
operator<< (std::ostream& os, Time const& t)
{
return os << std::string(t);
}
}} // lib::time
#endif

View file

@ -30,6 +30,7 @@ extern "C" {
#include <limits>
#include <string>
#include <boost/rational.hpp>
using std::string;
@ -37,6 +38,18 @@ using std::string;
namespace lib {
namespace time {
namespace {
/** implementation detail: convert a rational number denoting fractionalSeconds
* into the internal time scale used by GAVL and Lumiera internal time values.
*/
inline gavl_time_t
rational2time (TimeFract const& fractionalSeconds)
{
return boost::rational_cast<gavl_time_t> (GAVL_TIME_SCALE * fractionalSeconds);
}
}
const Time Time::MAX ( TimeValue (+std::numeric_limits<gavl_time_t>::max()) );
const Time Time::MIN ( TimeValue (-std::numeric_limits<gavl_time_t>::max()) );
@ -60,6 +73,15 @@ namespace time {
{ }
/** convenience constructor to build an Time value
* from a fraction of seconds, given as rational number.
* An example would be to the time unit of a framerate.
*/
Time::Time (TimeFract const& fractionalSeconds)
: TimeValue(rational2time (fractionalSeconds))
{ }
/** displaying an internal Lumiera Time value
* for diagnostic purposes or internal reporting.
* @warning internal Lumiera time values refer to an

View file

@ -25,6 +25,7 @@
#define LIB_TIME_TIMEVALUE_H
#include <boost/operators.hpp>
#include <boost/rational.hpp>
#include <cstdlib>
#include <string>
@ -182,6 +183,9 @@ namespace time {
/* ======= specific Time entities ==================== */
/** rational representation of fractional seconds */
typedef boost::rational<gavl_time_t> TimeFract;
/**
* Lumiera's internal time value datatype.
* This is a TimeValue, but now more specifically denoting
@ -219,6 +223,8 @@ namespace time {
: TimeValue(calcResult)
{ }
Time (TimeFract const& fractionalSeconds);
Time ( long millis
, uint secs
, uint mins =0

View file

@ -38,7 +38,7 @@ namespace asset {
namespace meta {
Descriptor::~Descriptor() { } // emit vtable here...
Descriptor::~Descriptor() { } // emit VTable here...
}
@ -54,8 +54,8 @@ namespace asset {
* created as a side effect of calling the concrete Meta subclass ctor.
*/
template<class MA>
P<MA>
MetaFactory::operator() (EntryID<MA> elementIdentity)
meta::Builder<MA>
MetaFactory::operator () (EntryID<MA> elementIdentity)
{
UNIMPLEMENTED ("Meta-Factory");
}
@ -70,7 +70,7 @@ namespace asset {
* created as a side effect of calling the concrete Meta subclass ctor.
*/
template<class MA>
P<MA>
meta::Builder<MA>
MetaFactory::operator() (Descriptor const& prototype, EntryID<MA> elementIdentity)
{
UNIMPLEMENTED ("Meta-Factory");
@ -96,10 +96,11 @@ namespace asset {
namespace asset {
using meta::Descriptor;
using meta::Builder;
using meta::TimeGrid;
template P<TimeGrid> MetaFactory::operator() (EntryID<TimeGrid>);
template Builder<TimeGrid> MetaFactory::operator() (EntryID<TimeGrid>);
template P<TimeGrid> MetaFactory::operator() (Descriptor const&, EntryID<TimeGrid>);
template Builder<TimeGrid> MetaFactory::operator() (Descriptor const&, EntryID<TimeGrid>);
} // namespace asset

View file

@ -22,14 +22,34 @@
/** @file meta.hpp
** Internal and organisational metadata. Some internally created data elements,
** like automation data sets, inventory of session contents, can be exposed and
** treated as specific Kind of Asset.
** Internal and organisational metadata. Some internally created data elements
** rather serve the purpose of controlling the way the application behaves, as
** opposed to organising the \link struct.hpp structure \endlink of the data the
** user works with. Lumiera exposes this self-referential control and customisation
** aspects as a special kind of Asset. Examples being types, scales and quantisation
** grids, decision rules, control data stores (automation data), annotations attached
** to labels, inventory entities etc.
**
** For the different <i>Kinds</i> of Assets, we use sub-interfaces inheriting
** from the general Asset interface. To be able to get asset::Meta instances
** directly from the AssetManager, we define a specialisation of the Asset ID.
**
** \par using meta assets
** The usage pattern of asset::Meta entities differs from the other assets,
** insofar they aren't created as individual entries, rather added as part
** of a larger scale configuration activity, or they are derived from category.
** The latter fits in with a prototype-like approach; initially, the individual
** entry just serves to keep track of a categorisation, while at some point,
** such a link into a describing category may evolve into a local
** differentiation of some settings (copy on modification).
**
** To cope with this special usage, the meta assets are defined to be immutable.
** They are created from a descriptor, which stands for a category or sub-category
** and can be another already existing asset::Meta (inheriting from meta::Descriptor)
** Generally this yields a Builder object, which can be used for outfitting the new
** or changed metadata entry, finally \em committing this builder to yield a new
** asset::Meta (which, in case of a mutation, might superseede an existin one).
**
** @see asset.hpp explanation of assets in general
** @see MetaFactory creating concrete asset::Meta instances
**
@ -71,6 +91,21 @@ namespace asset {
public:
virtual ~Descriptor(); ///< this is an ABC
};
/**
* Building and configuring a meta asset.
* The finished elements are defined to be immutable,
* thus, on creation or when changing / superseding a
* meta asset, the client gets a special builder instance,
* which is a value object for configuring the specific details
* to set. When done, the client invokes a \c commit() function,
* which yields a smart-ptr to the new meta asset.
* Individual meta asset subclasses are bound to define a
* specialisation of this Builder template, which will then be
* instantiated and provided by the MetaFactory.
*/
template<class MA>
struct Builder;
}
@ -116,10 +151,10 @@ namespace asset {
typedef P<asset::Meta> PType;
template<class MA>
P<MA> operator() (EntryID<MA> elementIdentity);
meta::Builder<MA> operator() (EntryID<MA> elementIdentity);
template<class MA>
P<MA> operator() (meta::Descriptor const& prototype, EntryID<MA> elementIdentity);
meta::Builder<MA> operator() (meta::Descriptor const& prototype, EntryID<MA> elementIdentity);
};

View file

@ -23,29 +23,94 @@
#include "proc/asset/meta/time-grid.hpp"
#include "proc/asset/entry-id.hpp"
#include "proc/assetmanager.hpp"
//#include "lib/time/quantiser.hpp"
#include "lib/time/timevalue.hpp"
#include "lib/time/display.hpp"
//#include "lib/util.hpp"
//#include "include/logging.h"
#include <boost/format.hpp>
#include <string>
using boost::format;
using boost::str;
using std::string;
namespace asset {
namespace meta {
namespace error = lumiera::error;
namespace {
typedef TimeGrid::Builder Builder;
Asset::Ident
deriveAssetIdentity (Builder const& setup)
{
EntryID<TimeGrid> wtf("wtf**ck"); //////////////////////TODO some real meat here
return wtf.getIdent();
}
// Implementation details (still required???)
}
/** */
TimeGrid::TimeGrid (Builder const& setup)
: Meta (deriveAssetIdentity (setup))
TimeGrid::TimeGrid (EntryID<TimeGrid> const& nameID)
: Meta (nameID.getIdent())
{ }
using lib::time::Time;
using lib::time::TimeValue;
using lib::time::TimeSpan;
using lib::time::Duration;
using lib::time::Offset;
/**
* TimeGrid implementation: a trivial time grid,
* starting at a given point in time and using a
* constant grid spacing
*/
class SimpleTimeGrid
: public TimeGrid
{
TimeSpan timeBase_;
// TODO implement the TimeGrid API here
public:
SimpleTimeGrid (Time start, Duration gridSpacing, EntryID<TimeGrid> const& name)
: TimeGrid (name)
, timeBase_(start,gridSpacing)
{ }
};
/** Setup of a TimeGrid: validate the settings configured into this builder instance,
* then decide on the implementation strategy for the time grid. Convert the given
* frames per second into an appropriate gridSpacing time and build a suitable
* name-ID to denote the TimeGrid-meta-Asset to be built.
* @return shared_ptr holding onto the new asset::Meta, which has already been
* registered with the AssetManager.
* @throw error::Config in case of invalid frames-per-second. The AssetManager
* might raise further exception when asset registration fails.
* @todo currently (12/2010) the AssetManager is unable to detect duplicate assets.
* Later on the intention is that in such cases, instead of creating a new grid
* we'll silently return the already registered exisiting and equivalent grid.
*/
P<TimeGrid>
Builder<TimeGrid>::commit()
{
if (predecessor_)
throw error::Invalid("compound and variable time grids are a planned feature"
, error::LUMIERA_ERROR_UNIMPLEMENTED);
if (!fps_)
throw error::Config ("attempt to build a TimeGrid with 0 frames per second");
Time spacing = 1 / fps_; // seconds per frame
format gridIdFormat("grid_%f_%s");
string name = str(gridIdFormat % fps_ % origin_);
EntryID<TimeGrid> nameID (name);
TimeGrid& newGrid (*new SimpleTimeGrid(origin_, Offset(spacing), nameID));
return AssetManager::instance().wrap (newGrid);
}
}} // namespace asset::meta

View file

@ -34,6 +34,11 @@
** Time grid specifications are integrated into Lumiera's framework
** for meta assets, automation, configuration and similar metadata.
**
** \par using time grids
** TimeGrid is an interface (ABC), but provides some actual factory
** functions, which can be used as a convenience shortcut to fabricate
** the kind of simple time grid used most often.
**
** @see MetaFactory creating concrete asset::Meta instances
** @see time::Quantiser
**
@ -43,14 +48,14 @@
#define ASSET_META_TIME_GRID_H
#include "proc/asset/meta.hpp"
#include "lib/time/quantiser.hpp"
#include "lib/time/timevalue.hpp"
namespace asset {
namespace meta {
/**
* Interface: a grid and scale for time quantisation.
* This meta-Asset describes a coordinate system or
@ -61,17 +66,52 @@ namespace meta {
{
public:
struct Builder
{
};
// TODO define the TimeGrid API here
protected:
friend class Builder;
TimeGrid (Builder const& setup); //////////////TODO
TimeGrid (EntryID<TimeGrid> const&);
};
using lib::time::Time;
using lib::time::TimeValue;
using lib::time::TimeFract;
template<>
struct Builder<TimeGrid>
{
TimeFract fps_;
Time origin_;
/** when building a compound or variable grid,
* the predecessor is the grid active \em before
* the origin of this (local) grid.
* @todo currently not supported (as of 12/2010)
*/
P<TimeGrid> predecessor_;
/**
* initialise to blank (zero).
* You need at least to set the framerate,
* in order to create a usable TimeGrid
*/
Builder()
: fps_(0)
, origin_(TimeValue(0))
, predecessor_()
{ }
/** create a time grid
* based on settings within this builder
*/
P<TimeGrid> commit();
};
}} // namespace asset::meta
#endif

View file

@ -52,7 +52,7 @@ namespace asset {
IDErr (const char* eID, format fmt)
: lumiera::error::Invalid(fmt.str(),eID) {}
};
// ------pre-defined-common-error-cases---------------
//
@ -88,8 +88,8 @@ namespace asset {
AssetManager::AssetManager ()
: registry (Singleton<asset::DB>() ())
{ }
/** provide the unique ID for given Asset::Ident tuple */
ID<Asset>
@ -117,7 +117,7 @@ namespace asset {
DB::Lock guard(&registry);
TODO ("handle duplicate Registrations");
P<KIND> smart_ptr (obj, &destroy);
registry.put (asset_id, smart_ptr);
return asset_id;
}
@ -155,9 +155,9 @@ namespace asset {
return static_pointer_cast<KIND,Asset>
(instance().registry.get (asset.id));
}
/**
* @return true if the given id is registered in the internal asset DB
*/
@ -167,10 +167,10 @@ namespace asset {
return ( registry.get (ID<Asset>(id)) );
} // query most general Asset ID-kind and use implicit
// conversion from smart-ptr to bool (test if empty)
/**
* @return true if the given id is registered with the given Category
* @return true if the given id is registered with the given Category
*/
bool
AssetManager::known (IDA id, const Category& cat)
@ -178,23 +178,23 @@ namespace asset {
PAsset pA = registry.get (id);
return ( pA && pA->ident.category.isWithin(cat));
}
namespace { // details implementing AssetManager::remove
void
recursive_call (AssetManager* instance, PAsset& pA)
{
instance->remove (pA->getID());
}
function<void(PAsset&)>
detach_child_recursively () ///< @return a functor recursively invoking remove(child)
detach_child_recursively () ///< @return a functor recursively invoking remove(child)
{
return bind( &recursive_call, &AssetManager::instance(), _1 );
}
}
/**
* remove the given asset from the internal DB
* <i>together with all its dependents</i>
@ -203,11 +203,11 @@ namespace asset {
AssetManager::remove (IDA id)
{
PAsset asset = getAsset (id);
for_each (asset->dependants, detach_child_recursively()); /////
for_each (asset->dependants, detach_child_recursively());
asset->unlink();
registry.del(id);
}
list<PcAsset>
@ -218,7 +218,7 @@ namespace asset {
res.sort();
return res;
}
} // namespace asset
@ -229,15 +229,16 @@ namespace asset {
/* explicit template instantiations for various Asset Kinds */
/************************************************************/
#include "proc/asset/media.hpp"
#include "proc/asset/clip.hpp"
#include "proc/asset/proc.hpp"
#include "proc/asset/struct.hpp"
#include "proc/asset/pipe.hpp"
#include "proc/asset/meta.hpp"
#include "proc/asset/procpatt.hpp"
#include "proc/asset/timeline.hpp"
#include "proc/asset/sequence.hpp"
#include "proc/asset/media.hpp"
#include "proc/asset/clip.hpp"
#include "proc/asset/proc.hpp"
#include "proc/asset/struct.hpp"
#include "proc/asset/pipe.hpp"
#include "proc/asset/meta.hpp"
#include "proc/asset/procpatt.hpp"
#include "proc/asset/timeline.hpp"
#include "proc/asset/sequence.hpp"
#include "proc/asset/meta/time-grid.hpp"
namespace asset {
@ -260,5 +261,8 @@ namespace asset {
template P<Timeline> AssetManager::wrap (const Timeline& asset);
template P<Sequence> AssetManager::wrap (const Sequence& asset);
using meta::TimeGrid;
template P<TimeGrid> AssetManager::wrap (const TimeGrid& asset);
} // namespace asset

View file

@ -201,7 +201,7 @@ namespace test{
TimeValue zero;
TimeValue five(5);
TimeSpan interval (Time(org), Duration(Offset (org,five)));
TimeSpan interval (Time(org), Duration(Offset (org,five))); /////////////TODO need more convenient constructors
// the time span behaves like a time
CHECK (org == interval);