13
0

libtemporal: changes derived from converting libardour

This commit is contained in:
Paul Davis 2020-09-20 16:33:43 -06:00
parent 6b09642406
commit bca8e2e8cc
10 changed files with 226 additions and 41 deletions

62
libs/temporal/enums.cc Normal file
View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 2020 Paul Davis <paul@linuxaudiosystems.com>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <typeinfo>
#include "pbd/enumwriter.h"
#include "temporal/types.h"
using namespace PBD;
using namespace Temporal;
using namespace std;
void
setup_libtemporal_enums ()
{
EnumWriter& enum_writer (EnumWriter::instance());
vector<int> i;
vector<string> s;
Temporal::TimeDomain td;
Temporal::OverlapType _OverlapType;
#define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
#define REGISTER_BITS(e) enum_writer.register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
#define REGISTER_ENUM(e) i.push_back (e); s.push_back (#e)
#define REGISTER_CLASS_ENUM(t,e) i.push_back (t::e); s.push_back (#e)
REGISTER_ENUM (AudioTime);
REGISTER_ENUM (BeatTime);
REGISTER (td);
REGISTER_ENUM (Temporal::OverlapNone);
REGISTER_ENUM (Temporal::OverlapInternal);
REGISTER_ENUM (Temporal::OverlapStart);
REGISTER_ENUM (Temporal::OverlapEnd);
REGISTER_ENUM (Temporal::OverlapExternal);
REGISTER(_OverlapType);
}
void Temporal::init ()
{
setup_libtemporal_enums ();
}

View File

@ -95,3 +95,9 @@ Range::subtract (RangeList & sub) const
return result;
}
template<> OverlapType coverage_exclusive_ends<int64_t> (int64_t sa, int64_t eaE, int64_t sb, int64_t ebE)
{
/* convert end positions to inclusive */
return coverage_inclusive_ends (sa, eaE-1, sb, ebE-1);
}

View File

@ -87,7 +87,7 @@ Point::time() const
/*NOTREACHED*/
abort();
/*NOTREACHED*/
return timepos_t();
return timepos_t (AudioTime);
}
Tempo::Tempo (XMLNode const & node)
@ -2473,7 +2473,7 @@ TempoMap::bbt_duration_at (superclock_t pos, const BBT_Time& bbt, int /* dir_ign
timecnt_t
TempoMap::full_duration_at (timepos_t const & pos, timecnt_t const & duration, TimeDomain return_domain) const
{
timepos_t p;
timepos_t p (return_domain);
Beats b;
superclock_t s;

View File

@ -30,6 +30,7 @@
#include "pbd/compose.h"
#include "pbd/failed_constructor.h"
#include "pbd/integer_division.h"
#include "pbd/string_convert.h"
@ -395,19 +396,12 @@ public:
return b;
}
template<typename Number>
Beats operator*(Number factor) const {
return ticks ((_beats * PPQN + _ticks) * factor);
}
Beats operator*(int32_t factor) const {return ticks (to_ticks() * factor); }
Beats operator/(int32_t factor) const { return ticks (to_ticks() / factor);}
Beats operator*(ratio_t const & factor) const {return ticks (int_div_round (to_ticks() * factor.numerator(), factor.denominator())); }
Beats operator/(ratio_t const & factor) const {return ticks (int_div_round (to_ticks() * factor.denominator(), factor.numerator())); }
template<typename Number>
Beats operator/(Number factor) const {
return ticks ((_beats * PPQN + _ticks) / factor);
}
Beats operator% (Beats const & b) {
return Beats::ticks (to_ticks() % b.to_ticks());
}
Beats operator% (Beats const & b) { return Beats::ticks (to_ticks() % b.to_ticks());}
Beats operator%= (Beats const & b) {
const Beats B (Beats::ticks (to_ticks() % b.to_ticks()));

View File

@ -25,17 +25,10 @@
#include "temporal/visibility.h"
#include "temporal/timeline.h"
#include "temporal/types.h"
namespace Temporal {
enum /*LIBTEMPORAL_API*/ OverlapType {
OverlapNone, // no overlap
OverlapInternal, // the overlap is 100% within the object
OverlapStart, // overlap covers start, but ends within
OverlapEnd, // overlap begins within and covers end
OverlapExternal // overlap extends to (at least) begin+end
};
/** end position arguments are inclusive */
template<typename T>
/*LIBTEMPORAL_API*/ OverlapType coverage_inclusive_ends (T sa, T ea, T sb, T eb) {
@ -137,6 +130,8 @@ template<typename T>
return coverage_inclusive_ends (sa, eaE.decrement(), sb, ebE.decrement());
}
template<> /*LIBTEMPORAL_API*/ OverlapType coverage_exclusive_ends<int64_t> (int64_t sa, int64_t eaE, int64_t sb, int64_t ebE);
class RangeList;
@ -174,9 +169,9 @@ class LIBTEMPORAL_API Range {
* looping). If the argument is earlier than or equal to the end of
* this range, do nothing.
*/
timepos_t squish (timepos_t t) const {
timepos_t squish (timepos_t const & t) const {
if (t >= _end) {
t = _start + (_start.distance (t) % length());
return _start + (_start.distance (t) % length());
}
return t;
}

View File

@ -46,21 +46,35 @@ class timecnt_t;
class LIBTEMPORAL_API timepos_t : public int62_t {
public:
timepos_t () : int62_t (false, 0) {}
timepos_t (TimeDomain d) : int62_t (d != AudioTime, 0) {}
/* for now (Sept2020) do not allow implicit type conversions */
explicit timepos_t (samplepos_t s) : int62_t (false, samples_to_superclock (s, _thread_sample_rate)) {}
explicit timepos_t (timecnt_t const &); /* will throw() if val is negative */
explicit timepos_t (Temporal::Beats const & b) : int62_t (false, b.to_ticks()) {}
/* superclock_t and samplepos_t are the same underlying primitive type,
* which means we cannot use polymorphism to differentiate them.
* which means we cannot use polymorphism to differentiate them. But it
* turns out that we more or less never construct timepos_t from an
* integer representing superclocks. So, there's a normal constructor
* for the samples case above, and ::from_superclock() here.
*/
static timepos_t from_superclock (superclock_t s) { return timepos_t (false, s); }
static timepos_t from_samples (samplepos_t s) { return timepos_t (false, samples_to_superclock (s, _thread_sample_rate)); }
static timepos_t from_ticks (int64_t t) { return timepos_t (true, t); }
static timepos_t zero (bool is_beats) { return timepos_t (is_beats, 0); }
bool is_beats() const { return flagged(); }
bool is_superclock() const { return !flagged(); }
bool positive () const { return val() > 0; }
bool negative () const { return val() < 0; }
bool zero () const { return val() == 0; }
Temporal::TimeDomain time_domain () const { if (flagged()) return Temporal::BeatTime; return Temporal::AudioTime; }
superclock_t superclocks() const { if (is_superclock()) return v; return _superclocks (); }
superclock_t superclocks() const { if (is_superclock()) return val(); return _superclocks (); }
int64_t samples() const { return superclock_to_samples (superclocks(), _thread_sample_rate); }
int64_t ticks() const { if (is_beats()) return val(); return _ticks (); }
Beats beats() const { if (is_beats()) return Beats::ticks (val()); return _beats (); }
@ -69,8 +83,12 @@ class LIBTEMPORAL_API timepos_t : public int62_t {
timepos_t & operator= (superclock_t s) { v = s; return *this; }
timepos_t & operator= (Temporal::Beats const & b) { operator= (build (true, b.to_ticks())); return *this; }
bool operator== (timepos_t const & other) const { return v == other.v; }
bool operator!= (timepos_t const & other) const { return v != other.v; }
timepos_t operator-() const { return timepos_t (int62_t::operator-()); }
/* if both values are zero, the time domain doesn't matter */
bool operator== (timepos_t const & other) const { return (val() == 0 && other.val() == 0) || (v == other.v); }
bool operator!= (timepos_t const & other) const { return (val() != 0 || other.val() != 0) && (v != other.v); }
bool operator< (timecnt_t const & other) const;
bool operator> (timecnt_t const & other) const;
@ -89,8 +107,7 @@ class LIBTEMPORAL_API timepos_t : public int62_t {
/* donn't provide operator+(samplepos_t) or operator+(superclock_t)
* because the compiler can't disambiguate them and neither can we.
* to add such types, use ::from_samples() or ::from_superclock() to
* create a timepo_t and then add that.
* to add such types, create a timepo_t and then add that.
*/
/* operator-() poses severe and thorny problems for a class that represents position on a timeline.
@ -168,6 +185,16 @@ class LIBTEMPORAL_API timepos_t : public int62_t {
timepos_t operator% (timecnt_t const &) const;
timepos_t & operator%=(timecnt_t const &);
/* Although multiplication and division of positions seems unusual,
* these are used in Evoral::Curve when scaling a list of timed events
* along the x (time) axis.
*/
timepos_t operator/(ratio_t const & n) const;
timepos_t operator*(ratio_t const & n) const;
timepos_t & operator/=(ratio_t const & n);
timepos_t & operator*=(ratio_t const & n);
bool operator< (superclock_t s) { return v < s; }
bool operator< (Temporal::Beats const & b) { return beats() < b; }
bool operator<= (superclock_t s) { return v <= s; }
@ -188,16 +215,14 @@ class LIBTEMPORAL_API timepos_t : public int62_t {
bool string_to (std::string const & str);
std::string to_string () const;
static timepos_t const & max() { return _max_timepos; }
static timepos_t max (TimeDomain td) { return timepos_t (td != AudioTime, int62_t::max); }
private:
int64_t v;
/* special private constructor for use when constructing timepos_t as a
return value using arithmetic ops
*/
explicit timepos_t (bool b, int64_t v) : int62_t (b, v) {}
static timepos_t _max_timepos;
explicit timepos_t (int62_t const & v) : int62_t (v) {}
/* these can only be called after verifying that the time domain does
* not match the relevant one i.e. call _beats() to get a Beats value
@ -226,8 +251,10 @@ class LIBTEMPORAL_API timepos_t : public int62_t {
timepos_t expensive_add (Temporal::Beats const &) const;
timepos_t expensive_add (timepos_t const & s) const;
int62_t operator- (int62_t) const { assert (0); }
int62_t operator- (int64_t) const { assert (0); }
using int62_t::operator int64_t;
using int62_t::operator-;
using int62_t::operator-=;
};
@ -257,10 +284,16 @@ class LIBTEMPORAL_API timepos_t : public int62_t {
class LIBTEMPORAL_API timecnt_t {
public:
/* default to zero superclocks @ zero */
timecnt_t () : _distance (int62_t (false, 0)), _position (timepos_t::from_superclock (0)) {}
timecnt_t () : _distance (false, 0), _position (AudioTime) {}
timecnt_t (TimeDomain td) : _distance (td != AudioTime, 0), _position (td) {}
timecnt_t (timecnt_t const &other) : _distance (other.distance()), _position (other.position()) {}
/* construct from sample count (position doesn't matter due to linear nature * of audio time */
explicit timecnt_t (samplepos_t s, timepos_t const & pos) : _distance (int62_t (false, samples_to_superclock (s, _thread_sample_rate))), _position (pos) {}
explicit timecnt_t (samplepos_t s) : _distance (int62_t (false, samples_to_superclock (s, _thread_sample_rate))), _position (AudioTime) {}
/* construct from timeline types */
explicit timecnt_t (timepos_t const & d) : _distance (d), _position (timepos_t::zero (d.flagged())) {}
explicit timecnt_t (timepos_t const & d, timepos_t const & p) : _distance (d), _position (p) { assert (p.is_beats() == d.is_beats()); }
explicit timecnt_t (timecnt_t const &, timepos_t const & pos);
@ -270,19 +303,24 @@ class LIBTEMPORAL_API timecnt_t {
/* construct from beats */
explicit timecnt_t (Temporal::Beats const & b, timepos_t const & pos) : _distance (true, b.to_ticks()), _position (pos) { assert ( _distance.flagged() == _position.is_beats()); }
static timecnt_t zero_at (TimeDomain td, timepos_t const & pos) { return timecnt_t (timepos_t (td), pos); }
/* superclock_t and samplepos_t are the same underlying primitive type,
* which means we cannot use polymorphism to differentiate them.
* See comments in timepos_t above.
*/
static timecnt_t from_superclock (superclock_t s, timepos_t const & pos) { return timecnt_t (int62_t (false, s), pos); }
static timecnt_t from_samples (samplepos_t s, timepos_t const & pos) { return timecnt_t (int62_t (false, samples_to_superclock (s, _thread_sample_rate)), pos); }
static timecnt_t from_ticks (int64_t ticks, timepos_t const & pos) { return timecnt_t (int62_t (true, ticks), pos); }
/* Construct from just a distance value - position is assumed to be zero */
explicit timecnt_t (Temporal::Beats const & b) : _distance (true, b.to_ticks()), _position (Beats()) {}
static timecnt_t from_superclock (superclock_t s) { return timecnt_t (int62_t (false, s), timepos_t::from_superclock (0)); }
static timecnt_t from_samples (samplepos_t s) { return timecnt_t (int62_t (false, samples_to_superclock (s, _thread_sample_rate)), timepos_t::from_superclock (0)); }
static timecnt_t from_ticks (int64_t ticks) { return timecnt_t (int62_t (true, ticks), timepos_t::from_ticks (0)); }
int64_t magnitude() const { return _distance.val(); }
int62_t const & distance() const { return _distance; }
timepos_t const & position() const { return _position; }
timepos_t const & origin() const { return _position; } /* alias */
void set_position (timepos_t const &pos);
bool positive() const { return _distance.val() > 0; }
@ -316,9 +354,14 @@ class LIBTEMPORAL_API timecnt_t {
timecnt_t operator- (timecnt_t const & t) const;
timecnt_t operator+ (timecnt_t const & t) const;
timecnt_t operator- (timepos_t const & t) const;
timecnt_t operator+ (timepos_t const & t) const;
timecnt_t & operator-= (timecnt_t const & t);
timecnt_t & operator+= (timecnt_t const & t);
timecnt_t decrement () const { return timecnt_t (_distance - 1, _position); }
//timecnt_t operator- (timepos_t const & t) const;
//timecnt_t operator+ (timepos_t const & t) const;
//timecnt_t & operator-= (timepos_t);
@ -417,7 +460,9 @@ struct numeric_limits<Temporal::timecnt_t> {
namespace std {
std::ostream& operator<< (std::ostream & o, Temporal::timecnt_t const & tc);
std::ostream& operator>> (std::istream & o, Temporal::timecnt_t const & tc);
std::ostream& operator<< (std::ostream & o, Temporal::timepos_t const & tp);
std::ostream& operator>> (std::istream & o, Temporal::timepos_t const & tp);
}
#if 0

View File

@ -19,11 +19,17 @@
#ifndef __libpbd_position_types_h__
#define __libpbd_position_types_h__
#include <cstdlib>
#include <stdint.h>
#include <boost/rational.hpp>
#include "pbd/integer_division.h"
namespace Temporal {
extern void init ();
/* Any position measured in audio samples.
Assumed to be non-negative but not enforced.
*/
@ -52,7 +58,45 @@ static const samplecnt_t max_samplecnt = INT64_MAX;
static const int32_t ticks_per_beat = 1920;
typedef boost::rational<int64_t> ratio_t;
template<class T>
class _ratio_t {
public:
/* do not allow negative values, this is just a ratio */
_ratio_t (T n, T d) : _numerator (abs (n)), _denominator (abs(d)) { assert (_denominator != 0); }
_ratio_t (T n) : _numerator (abs (n)), _denominator (1) {}
T numerator() const { return _numerator; }
T denominator() const { return _denominator; }
bool is_unity() const { return _numerator == _denominator; }
bool is_zero() const { return _numerator == 0; }
/* provide an easy way to multiply double by ratio_t. Note that this
must be written as ratio_t * double, not the other way around. We
are not trying to duplicate boost::rational here (which also doesn't
allow this without a lot of syntactic fluff.
*/
double operator* (double v) const { return (v * (double) _numerator) / (double) _denominator; }
/* ditto for int64_t */
int64_t operator* (int64_t v) const { return int_div_round (v * _numerator, _denominator); }
private:
T _numerator;
T _denominator;
};
typedef _ratio_t<int64_t> ratio_t;
enum OverlapType {
OverlapNone, // no overlap
OverlapInternal, // the overlap is 100% within the object
OverlapStart, // overlap covers start, but ends within
OverlapEnd, // overlap begins within and covers end
OverlapExternal // overlap extends to (at least) begin+end
};
enum TimeDomain {
/* simple ordinals, since these are mutually exclusive */

View File

@ -23,16 +23,22 @@
#define LIBTEMPORAL_DLL_IMPORT __declspec(dllimport)
#define LIBTEMPORAL_DLL_EXPORT __declspec(dllexport)
#define LIBTEMPORAL_DLL_LOCAL
#define LIBTEMPORAL_TEMPLATE_DLL_IMPORT __declspec(dllimport)
#define LIBTEMPORAL_TEMPLATE_DLL_EXPORT __declspec(dllexport)
#else
#define LIBTEMPORAL_DLL_IMPORT __attribute__ ((visibility ("default")))
#define LIBTEMPORAL_DLL_EXPORT __attribute__ ((visibility ("default")))
#define LIBTEMPORAL_DLL_LOCAL __attribute__ ((visibility ("hidden")))
#define LIBTEMPORAL_TEMPLATE_DLL_IMPORT __attribute__ ((visibility ("default")))
#define LIBTEMPORAL_TEMPLATE_DLL_EXPORT __attribute__ ((visibility ("default")))
#endif
#ifdef LIBTEMPORAL_DLL_EXPORTS // defined if we are building the libtimecode DLL (instead of using it)
#define LIBTEMPORAL_API LIBTEMPORAL_DLL_EXPORT
#define LIBTEMPORAL_TEMPLATE_API LIBTEMPORAL_TEMPLATE_DLL_EXPORT
#else
#define LIBTEMPORAL_API LIBTEMPORAL_DLL_IMPORT
#define LIBTEMPORAL_TEMPLATE_API LIBTEMPORAL_TEMPLATE_DLL_IMPORT
#endif
#define LIBTEMPORAL_LOCAL LIBTEMPORAL_DLL_LOCAL

View File

@ -228,7 +228,7 @@ timepos_t::operator= (timecnt_t const & t)
void
timepos_t::set_superclock (superclock_t s)
{
v = s;
v = build (false, s);
}
void
@ -261,6 +261,38 @@ timepos_t::_ticks () const
return _beats().to_ticks();
}
timepos_t
timepos_t::operator/(ratio_t const & n) const
{
/* this cannot make the value negative, since ratio_t is always positive */
/* note: v / (N/D) = (v * D) / N */
return timepos_t (is_beats(), int_div_round (val() * n.denominator(), n.numerator()));
}
timepos_t
timepos_t::operator*(ratio_t const & n) const
{
/* this cannot make the value negative, since ratio_t is always positive */
return timepos_t (is_beats(), int_div_round (val() * n.numerator(), n.denominator()));
}
timepos_t &
timepos_t::operator/=(ratio_t const & n)
{
/* this cannot make the value negative, since ratio_t is always positive */
v = build (flagged(), int_div_round (val() * n.numerator(), n.denominator()));
return *this;
}
timepos_t &
timepos_t::operator*=(ratio_t const & n)
{
/* this cannot make the value negative, since ratio_t is always positive */
v = build (flagged(), int_div_round (val() * n.denominator(), n.numerator()));
return *this;
}
timepos_t
timepos_t::expensive_add (Beats const & b) const
{

View File

@ -27,6 +27,7 @@ I18N_PACKAGE = 'libtemporal'
temporal_sources = [
'debug.cc',
'bbt_time.cc',
'enums.cc',
'tempo.cc',
'time.cc',
'timeline.cc',