changes to compile against libtemporal and use of timepos_t/timecnt_t

This commit is contained in:
Paul Davis 2020-08-24 14:40:03 -06:00
parent e111123b54
commit 6b09642406
13 changed files with 460 additions and 722 deletions

View file

@ -41,10 +41,10 @@ Control::Control(const Parameter& parameter,
/** Get the currently effective value (ie the one that corresponds to current output)
*/
double
Control::get_double (bool from_list, double frame) const
Control::get_double (bool from_list, Temporal::timepos_t when) const
{
if (from_list) {
return _list->eval(frame);
return _list->eval (when);
} else {
return _user_value;
}
@ -52,7 +52,7 @@ Control::get_double (bool from_list, double frame) const
void
Control::set_double (double value, double frame, bool to_list)
Control::set_double (double value, Temporal::timepos_t when, bool to_list)
{
_user_value = value;
@ -61,7 +61,7 @@ Control::set_double (double value, double frame, bool to_list)
*/
if (to_list && (!_list->in_write_pass() || _list->descriptor().toggled)) {
_list->add (frame, value, false);
_list->add (when, value, false);
}
}

View file

@ -33,7 +33,7 @@
#define isnan_local std::isnan
#endif
#define GUARD_POINT_DELTA 64
#define GUARD_POINT_DELTA Temporal::timecnt_t::from_samples (64)
#include <cassert>
#include <cmath>
@ -48,6 +48,8 @@
#include "pbd/control_math.h"
#include "pbd/compose.h"
#include "pbd/error.h"
#include "pbd/i18n.h"
#include "pbd/debug.h"
using namespace std;
@ -60,10 +62,11 @@ inline bool event_time_less_than (ControlEvent* a, ControlEvent* b)
return a->when < b->when;
}
ControlList::ControlList (const Parameter& id, const ParameterDescriptor& desc)
ControlList::ControlList (const Parameter& id, const ParameterDescriptor& desc, Temporal::TimeDomain ts)
: _parameter(id)
, _desc(desc)
, _interpolation (default_interpolation ())
, _time_style (ts)
, _curve(0)
{
_frozen = 0;
@ -85,6 +88,7 @@ ControlList::ControlList (const ControlList& other)
: _parameter(other._parameter)
, _desc(other._desc)
, _interpolation(other._interpolation)
, _time_style (other._time_style)
, _curve(0)
{
_frozen = 0;
@ -103,10 +107,11 @@ ControlList::ControlList (const ControlList& other)
copy_events (other);
}
ControlList::ControlList (const ControlList& other, double start, double end)
ControlList::ControlList (const ControlList& other, Temporal::timepos_t const & start, Temporal::timepos_t const & end)
: _parameter(other._parameter)
, _desc(other._desc)
, _interpolation(other._interpolation)
, _time_style (other._time_style)
, _curve(0)
{
_frozen = 0;
@ -145,9 +150,9 @@ ControlList::~ControlList()
}
boost::shared_ptr<ControlList>
ControlList::create(const Parameter& id, const ParameterDescriptor& desc)
ControlList::create(const Parameter& id, const ParameterDescriptor& desc, Temporal::TimeDomain time_style)
{
return boost::shared_ptr<ControlList>(new ControlList(id, desc));
return boost::shared_ptr<ControlList>(new ControlList(id, desc, time_style));
}
bool
@ -251,21 +256,24 @@ ControlList::clear ()
}
void
ControlList::x_scale (double factor)
ControlList::x_scale (Temporal::ratio_t const & factor)
{
Glib::Threads::RWLock::WriterLock lm (_lock);
_x_scale (factor);
}
bool
ControlList::extend_to (double when)
ControlList::extend_to (Temporal::timepos_t const & end)
{
Glib::Threads::RWLock::WriterLock lm (_lock);
if (_events.empty() || _events.back()->when == when) {
if (_events.empty() || _events.back()->when == end) {
return false;
}
double factor = when / _events.back()->when;
Temporal::ratio_t factor (end.val(), _events.back()->when.val());
_x_scale (factor);
return true;
}
@ -330,10 +338,10 @@ ControlList::list_merge (ControlList const& other, boost::function<double(double
}
void
ControlList::_x_scale (double factor)
ControlList::_x_scale (Temporal::ratio_t const & factor)
{
for (iterator i = _events.begin(); i != _events.end(); ++i) {
(*i)->when *= factor;
(*i)->when = (*i)->when.operator* (factor);
}
mark_dirty ();
@ -377,9 +385,13 @@ ControlList::thin (double thinning_factor)
/* compute the area of the triangle formed by 3 points
*/
double area = fabs ((prevprev->when * (prev->value - cur->value)) +
(prev->when * (cur->value - prevprev->value)) +
(cur->when * (prevprev->value - prev->value)));
const double ppw = prevprev->when.val();
const double pw = prev->when.val();
const double cw = cur->when.val();
double area = fabs ((ppw * (prev->value - cur->value)) +
(pw * (cur->value - prevprev->value)) +
(cw * (prevprev->value - prev->value)));
if (area < thinning_factor) {
iterator tmp = pprev;
@ -415,11 +427,11 @@ ControlList::thin (double thinning_factor)
}
void
ControlList::fast_simple_add (double when, double value)
ControlList::fast_simple_add (Temporal::timepos_t const & time, double value)
{
Glib::Threads::RWLock::WriterLock lm (_lock);
/* to be used only for loading pre-sorted data from saved state */
_events.insert (_events.end(), new ControlEvent (when, value));
_events.insert (_events.end(), new ControlEvent (time, value));
mark_dirty ();
if (_frozen) {
@ -459,9 +471,10 @@ ControlList::unlocked_remove_duplicates ()
}
void
ControlList::start_write_pass (double when)
ControlList::start_write_pass (Temporal::timepos_t const & time)
{
Glib::Threads::RWLock::WriterLock lm (_lock);
Temporal::timepos_t when = time;
DEBUG_TRACE (DEBUG::ControlList, string_compose ("%1: setup write pass @ %2\n", this, when));
@ -481,7 +494,7 @@ ControlList::start_write_pass (double when)
*/
if (_in_write_pass && !new_write_pass) {
#if 1
add_guard_point (when, 0); // also sets most_recent_insert_iterator
add_guard_point (when, std::numeric_limits<Temporal::timecnt_t>::min()); // also sets most_recent_insert_iterator
#else
const ControlEvent cp (when, 0.0);
most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
@ -490,7 +503,7 @@ ControlList::start_write_pass (double when)
}
void
ControlList::write_pass_finished (double /*when*/, double thinning_factor)
ControlList::write_pass_finished (Temporal::timepos_t const & /*when*/, double thinning_factor)
{
DEBUG_TRACE (DEBUG::ControlList, "write pass finished\n");
@ -503,7 +516,7 @@ ControlList::write_pass_finished (double /*when*/, double thinning_factor)
}
void
ControlList::set_in_write_pass (bool yn, bool add_point, double when)
ControlList::set_in_write_pass (bool yn, bool add_point, Temporal::timepos_t when)
{
DEBUG_TRACE (DEBUG::ControlList, string_compose ("set_in_write_pass: in-write: %1 @ %2 add point? %3\n", yn, when, add_point));
@ -511,20 +524,25 @@ ControlList::set_in_write_pass (bool yn, bool add_point, double when)
if (yn && add_point) {
Glib::Threads::RWLock::WriterLock lm (_lock);
add_guard_point (when, 0);
add_guard_point (when, std::numeric_limits<Temporal::timecnt_t>::min());
}
}
void
ControlList::add_guard_point (double when, double offset)
ControlList::add_guard_point (Temporal::timepos_t const & time, Temporal::timecnt_t const & offset)
{
Temporal::timepos_t when = time;
// caller needs to hold writer-lock
if (offset < 0 && when < offset) {
if (offset.negative() && when < offset) {
return;
}
assert (offset <= 0);
if (offset != 0) {
#warning NUTEMPO FIXME this assertion should be possible to write
// assert (offset <= 0);
if (!offset.zero()) {
/* check if there are points between when + offset .. when */
ControlEvent cp (when + offset, 0.0);
iterator s;
@ -533,7 +551,7 @@ ControlList::add_guard_point (double when, double offset)
cp.when = when;
e = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
if (s != e) {
DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 add_guard_point, none added, found event between %2 and %3\n", this, when - offset, when));
DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 add_guard_point, none added, found event between %2 and %3\n", this, when.earlier (offset), when));
return;
}
}
@ -601,11 +619,12 @@ ControlList::in_write_pass () const
}
bool
ControlList::editor_add (double when, double value, bool with_guard)
ControlList::editor_add (Temporal::timepos_t const & time, double value, bool with_guard)
{
/* this is for making changes from a graphical line editor */
{
Glib::Threads::RWLock::WriterLock lm (_lock);
Temporal::timepos_t when = time;
ControlEvent cp (when, 0.0f);
iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
@ -624,7 +643,7 @@ ControlList::editor_add (double when, double value, bool with_guard)
*/
if (when >= 1) {
_events.insert (_events.end(), new ControlEvent (0, value));
_events.insert (_events.end(), new ControlEvent (std::numeric_limits<Temporal::timepos_t>::min(), value));
DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added value %2 at zero\n", this, value));
}
}
@ -652,11 +671,12 @@ ControlList::editor_add (double when, double value, bool with_guard)
}
void
ControlList::maybe_add_insert_guard (double when)
ControlList::maybe_add_insert_guard (Temporal::timepos_t const & time)
{
Temporal::timepos_t when = time;
// caller needs to hold writer-lock
if (most_recent_insert_iterator != _events.end()) {
if ((*most_recent_insert_iterator)->when - when > GUARD_POINT_DELTA) {
if ((*most_recent_insert_iterator)->when.earlier (when) > GUARD_POINT_DELTA) {
/* Next control point is some distance from where our new point is
going to go, so add a new point to avoid changing the shape of
the line too much. The insert iterator needs to point to the
@ -673,8 +693,10 @@ ControlList::maybe_add_insert_guard (double when)
/** If we would just be adding to a straight line, move the previous point instead. */
bool
ControlList::maybe_insert_straight_line (double when, double value)
ControlList::maybe_insert_straight_line (Temporal::timepos_t const & time, double value)
{
Temporal::timepos_t when = time;
// caller needs to hold writer-lock
if (_events.empty()) {
return false;
@ -702,8 +724,10 @@ ControlList::maybe_insert_straight_line (double when, double value)
}
ControlList::iterator
ControlList::erase_from_iterator_to (iterator iter, double when)
ControlList::erase_from_iterator_to (iterator iter, Temporal::timepos_t const & time)
{
Temporal::timepos_t when = time;
// caller needs to hold writer-lock
while (iter != _events.end()) {
if ((*iter)->when < when) {
@ -723,8 +747,10 @@ ControlList::erase_from_iterator_to (iterator iter, double when)
* control surface (GUI, MIDI, OSC etc)
*/
void
ControlList::add (double when, double value, bool with_guards, bool with_initial)
ControlList::add (Temporal::timepos_t const & time, double value, bool with_guards, bool with_initial)
{
Temporal::timepos_t when = time;
/* clamp new value to allowed range */
value = std::min ((double)_desc.upper, std::max ((double)_desc.lower, value));
@ -744,11 +770,11 @@ ControlList::add (double when, double value, bool with_guards, bool with_initial
if (when >= 1) {
if (_desc.toggled) {
const double opp_val = ((value >= 0.5) ? 1.0 : 0.0);
_events.insert (_events.end(), new ControlEvent (0, opp_val));
_events.insert (_events.end(), new ControlEvent (std::numeric_limits<Temporal::timepos_t>::min(), opp_val));
DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added toggled value %2 at zero\n", this, opp_val));
} else {
_events.insert (_events.end(), new ControlEvent (0, value));
_events.insert (_events.end(), new ControlEvent (std::numeric_limits<Temporal::timepos_t>::min(), value));
DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _desc.normal));
}
}
@ -759,7 +785,7 @@ ControlList::add (double when, double value, bool with_guards, bool with_initial
/* first write in a write pass: add guard point if requested */
if (with_guards) {
add_guard_point (insert_position, 0);
add_guard_point (insert_position, std::numeric_limits<Temporal::timecnt_t>::min());
did_write_during_pass = true;
} else {
/* not adding a guard, but we need to set iterator appropriately */
@ -905,10 +931,11 @@ ControlList::erase (iterator start, iterator end)
/** Erase the first event which matches the given time and value */
void
ControlList::erase (double when, double value)
ControlList::erase (Temporal::timepos_t const & time, double value)
{
{
Glib::Threads::RWLock::WriterLock lm (_lock);
Temporal::timepos_t when = time;
iterator i = begin ();
while (i != end() && ((*i)->when != when || (*i)->value != value)) {
@ -928,12 +955,13 @@ ControlList::erase (double when, double value)
}
void
ControlList::erase_range (double start, double endt)
ControlList::erase_range (Temporal::timepos_t const & start, Temporal::timepos_t const & endt)
{
bool erased = false;
{
Glib::Threads::RWLock::WriterLock lm (_lock);
erased = erase_range_internal (start, endt, _events);
if (erased) {
@ -947,14 +975,32 @@ ControlList::erase_range (double start, double endt)
}
bool
ControlList::erase_range_internal (double start, double endt, EventList & events)
ControlList::erase_range_internal (Temporal::timepos_t const & start, Temporal::timepos_t const & endt, EventList & events)
{
bool erased = false;
ControlEvent cp (start, 0.0f);
iterator s;
iterator e;
/* This is where we have to pick the time domain to be used when
* defining the control points.
*
* start/endt retain their values no matter what the time domain is,
* but the location of the control point is specified as a single
* integer value that represents either samples or beats. The sample
* position and beat position, while representing the same position on
* the timeline, will be numerically different anywhere (except perhaps
* zero).
*
* eg. start = 1000000 samples == 12.34 beats
* cp.when = 100000 if ControlList uses AudioTime
* cp.when = 23074 if ControlList uses BeatTime (see Temporal::Beats::to_ticks())
*
*/
ControlEvent cp (start, 0.0f);
if ((s = lower_bound (events.begin(), events.end(), &cp, time_comparator)) != events.end()) {
cp.when = endt;
e = upper_bound (events.begin(), events.end(), &cp, time_comparator);
events.erase (s, e);
@ -968,7 +1014,7 @@ ControlList::erase_range_internal (double start, double endt, EventList & events
}
void
ControlList::slide (iterator before, double distance)
ControlList::slide (iterator before, Temporal::timecnt_t const & distance)
{
{
Glib::Threads::RWLock::WriterLock lm (_lock);
@ -977,8 +1023,10 @@ ControlList::slide (iterator before, double distance)
return;
}
Temporal::timecnt_t wd = distance;
while (before != _events.end()) {
(*before)->when += distance;
(*before)->when += wd;
++before;
}
@ -988,19 +1036,22 @@ ControlList::slide (iterator before, double distance)
}
void
ControlList::shift (double pos, double frames)
ControlList::shift (Temporal::timepos_t const & time, Temporal::timecnt_t const & distance)
{
Temporal::timepos_t pos = time;
{
Glib::Threads::RWLock::WriterLock lm (_lock);
double v0, v1;
if (frames < 0) {
if (distance.negative()) {
/* Route::shift () with negative shift is used
* for "remove time". The time [pos.. pos-frames] is removed.
* and everyhing after, moved backwards.
*/
v0 = unlocked_eval (pos);
v1 = unlocked_eval (pos - frames);
erase_range_internal (pos, pos - frames, _events);
v1 = unlocked_eval (pos.earlier (distance));
erase_range_internal (pos, pos.earlier (distance), _events);
} else {
v0 = v1 = unlocked_eval (pos);
}
@ -1012,23 +1063,23 @@ ControlList::shift (double pos, double frames)
dst_guard_exists = true;
}
if ((*i)->when >= pos) {
(*i)->when += frames;
(*i)->when += distance;
}
}
/* add guard-points to retain shape, if needed */
if (frames > 0) {
if (distance.positive()) {
ControlEvent cp (pos, 0.0);
iterator s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
if (s != _events.end ()) {
_events.insert (s, new ControlEvent (pos, v0));
}
pos += frames;
} else if (frames < 0 && pos > 0) {
ControlEvent cp (pos - 1, 0.0);
pos += distance;
} else if (distance.negative() && pos > 0) {
ControlEvent cp (pos.decrement(), 0.0);
iterator s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
if (s != _events.end ()) {
_events.insert (s, new ControlEvent (pos - 1, v0));
_events.insert (s, new ControlEvent (pos.decrement(), v0));
}
}
if (!dst_guard_exists) {
@ -1044,7 +1095,7 @@ ControlList::shift (double pos, double frames)
}
void
ControlList::modify (iterator iter, double when, double val)
ControlList::modify (iterator iter, Temporal::timepos_t const & time, double val)
{
/* note: we assume higher level logic is in place to avoid this
* reordering the time-order of control events in the list. ie. all
@ -1056,6 +1107,7 @@ ControlList::modify (iterator iter, double when, double val)
{
Glib::Threads::RWLock::WriterLock lm (_lock);
Temporal::timepos_t when = time;
(*iter)->when = when;
(*iter)->value = val;
@ -1077,10 +1129,11 @@ ControlList::modify (iterator iter, double when, double val)
}
std::pair<ControlList::iterator,ControlList::iterator>
ControlList::control_points_adjacent (double xval)
ControlList::control_points_adjacent (Temporal::timepos_t const & xtime)
{
Glib::Threads::RWLock::ReaderLock lm (_lock);
iterator i;
Temporal::timepos_t xval = xtime;
ControlEvent cp (xval, 0.0f);
std::pair<iterator,iterator> ret;
@ -1140,10 +1193,10 @@ ControlList::thaw ()
void
ControlList::mark_dirty () const
{
_lookup_cache.left = -1;
_lookup_cache.left = std::numeric_limits<Temporal::timepos_t>::max();
_lookup_cache.range.first = _events.end();
_lookup_cache.range.second = _events.end();
_search_cache.left = -1;
_search_cache.left = std::numeric_limits<Temporal::timepos_t>::max();
_search_cache.first = _events.end();
if (_curve) {
@ -1152,10 +1205,11 @@ ControlList::mark_dirty () const
}
void
ControlList::truncate_end (double last_coordinate)
ControlList::truncate_end (Temporal::timepos_t const & last_time)
{
{
Glib::Threads::RWLock::WriterLock lm (_lock);
Temporal::timepos_t last_coordinate = last_time;
ControlEvent cp (last_coordinate, 0);
ControlList::reverse_iterator i;
double last_val;
@ -1254,13 +1308,14 @@ ControlList::truncate_end (double last_coordinate)
}
void
ControlList::truncate_start (double overall_length)
ControlList::truncate_start (Temporal::timecnt_t const & overall)
{
{
Glib::Threads::RWLock::WriterLock lm (_lock);
iterator i;
double first_legal_value;
double first_legal_coordinate;
Temporal::timepos_t first_legal_coordinate;
Temporal::timepos_t overall_length (overall);
if (_events.empty()) {
/* nothing to truncate */
@ -1274,7 +1329,7 @@ ControlList::truncate_start (double overall_length)
/* growing at front: duplicate first point. shift all others */
double shift = overall_length - _events.back()->when;
Temporal::timepos_t shift (_events.back()->when.distance (overall_length));
uint32_t np;
for (np = 0, i = _events.begin(); i != _events.end(); ++i, ++np) {
@ -1284,7 +1339,7 @@ ControlList::truncate_start (double overall_length)
if (np < 2) {
/* less than 2 points: add a new point */
_events.push_front (new ControlEvent (0, _events.front()->value));
_events.push_front (new ControlEvent (std::numeric_limits<Temporal::timepos_t>::min(), _events.front()->value));
} else {
@ -1301,7 +1356,7 @@ ControlList::truncate_start (double overall_length)
_events.front()->when = 0;
} else {
/* leave non-flat segment in place, add a new leading point. */
_events.push_front (new ControlEvent (0, _events.front()->value));
_events.push_front (new ControlEvent (std::numeric_limits<Temporal::timepos_t>::min(), _events.front()->value));
}
}
@ -1309,7 +1364,7 @@ ControlList::truncate_start (double overall_length)
/* shrinking at front */
first_legal_coordinate = _events.back()->when - overall_length;
first_legal_coordinate = _events.back()->when.distance (overall_length);
first_legal_value = unlocked_eval (first_legal_coordinate);
first_legal_value = max ((double)_desc.lower, first_legal_value);
first_legal_value = min ((double)_desc.upper, first_legal_value);
@ -1339,12 +1394,12 @@ ControlList::truncate_start (double overall_length)
*/
for (i = _events.begin(); i != _events.end(); ++i) {
(*i)->when -= first_legal_coordinate;
(*i)->when.shift_earlier (Temporal::timecnt_t (first_legal_coordinate, Temporal::timepos_t()));
}
/* add a new point for the interpolated new value */
_events.push_front (new ControlEvent (0, first_legal_value));
_events.push_front (new ControlEvent (std::numeric_limits<Temporal::timepos_t>::min(), first_legal_value));
}
unlocked_invalidate_insert_iterator ();
@ -1354,13 +1409,15 @@ ControlList::truncate_start (double overall_length)
}
double
ControlList::unlocked_eval (double x) const
ControlList::unlocked_eval (Temporal::timepos_t const & xtime) const
{
pair<EventList::iterator,EventList::iterator> range;
int32_t npoints;
double lpos, upos;
Temporal::timepos_t lpos, upos;
double lval, uval;
double fraction;
double xx;
double ll;
const_iterator length_check_iter = _events.begin();
for (npoints = 0; npoints < 4; ++npoints, ++length_check_iter) {
@ -1377,9 +1434,9 @@ ControlList::unlocked_eval (double x) const
return _events.front()->value;
case 2:
if (x >= _events.back()->when) {
if (xtime >= _events.back()->when) {
return _events.back()->value;
} else if (x <= _events.front()->when) {
} else if (xtime <= _events.front()->when) {
return _events.front()->value;
}
@ -1388,7 +1445,10 @@ ControlList::unlocked_eval (double x) const
upos = _events.back()->when;
uval = _events.back()->value;
fraction = (double) (x - lpos) / (double) (upos - lpos);
xx = lpos.distance (xtime).distance().val();
ll = lpos.distance (upos).distance().val();
fraction = xx / ll;
switch (_interpolation) {
case Discrete:
@ -1405,13 +1465,13 @@ ControlList::unlocked_eval (double x) const
}
default:
if (x >= _events.back()->when) {
if (xtime >= _events.back()->when) {
return _events.back()->value;
} else if (x <= _events.front()->when) {
} else if (xtime <= _events.front()->when) {
return _events.front()->value;
}
return multipoint_eval (x);
return multipoint_eval (xtime);
}
abort(); /*NOTREACHED*/ /* stupid gcc */
@ -1419,35 +1479,35 @@ ControlList::unlocked_eval (double x) const
}
double
ControlList::multipoint_eval (double x) const
ControlList::multipoint_eval (Temporal::timepos_t const & xtime) const
{
double upos, lpos;
Temporal::timepos_t upos, lpos;
double uval, lval;
double fraction;
/* "Stepped" lookup (no interpolation) */
/* FIXME: no cache. significant? */
if (_interpolation == Discrete) {
const ControlEvent cp (x, 0);
const ControlEvent cp (xtime, 0);
EventList::const_iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
// shouldn't have made it to multipoint_eval
assert(i != _events.end());
if (i == _events.begin() || (*i)->when == x)
if (i == _events.begin() || (*i)->when == xtime)
return (*i)->value;
else
return (*(--i))->value;
}
/* Only do the range lookup if x is in a different range than last time
/* Only do the range lookup if xtime is in a different range than last time
* this was called (or if the lookup cache has been marked "dirty" (left<0) */
if ((_lookup_cache.left < 0) ||
((_lookup_cache.left > x) ||
if ((_lookup_cache.left == std::numeric_limits<Temporal::timepos_t>::max()) ||
((_lookup_cache.left > xtime) ||
(_lookup_cache.range.first == _events.end()) ||
((*_lookup_cache.range.second)->when < x))) {
((*_lookup_cache.range.second)->when < xtime))) {
const ControlEvent cp (x, 0);
const ControlEvent cp (xtime, 0);
_lookup_cache.range = equal_range (_events.begin(), _events.end(), &cp, time_comparator);
}
@ -1458,7 +1518,7 @@ ControlList::multipoint_eval (double x) const
/* x does not exist within the list as a control point */
_lookup_cache.left = x;
_lookup_cache.left = xtime;
if (range.first != _events.begin()) {
--range.first;
@ -1478,7 +1538,7 @@ ControlList::multipoint_eval (double x) const
upos = (*range.second)->when;
uval = (*range.second)->value;
fraction = (double) (x - lpos) / (double) (upos - lpos);
fraction = (double) lpos.distance (xtime).distance().val() / (double) lpos.distance (upos).distance().val();
switch (_interpolation) {
case Logarithmic:
@ -1499,20 +1559,22 @@ ControlList::multipoint_eval (double x) const
}
/* x is a control point in the data */
_lookup_cache.left = -1;
_lookup_cache.left = std::numeric_limits<Temporal::timepos_t>::max();
return (*range.first)->value;
}
void
ControlList::build_search_cache_if_necessary (double start) const
ControlList::build_search_cache_if_necessary (Temporal::timepos_t const & start_time) const
{
Temporal::timepos_t start = start_time;
if (_events.empty()) {
/* Empty, nothing to cache, move to end. */
_search_cache.first = _events.end();
_search_cache.left = 0;
_search_cache.left = Temporal::timepos_t();
return;
} else if ((_search_cache.left < 0) || (_search_cache.left > start)) {
/* Marked dirty (left < 0), or we're too far forward, re-search. */
} else if ((_search_cache.left == std::numeric_limits<Temporal::timepos_t>::max()) || (_search_cache.left > start)) {
/* Marked dirty (left == max), or we're too far forward, re-search. */
const ControlEvent start_point (start, 0);
@ -1537,8 +1599,10 @@ ControlList::build_search_cache_if_necessary (double start) const
* \return true if event is found (and \a x and \a y are valid).
*/
bool
ControlList::rt_safe_earliest_event_discrete_unlocked (double start, double& x, double& y, bool inclusive) const
ControlList::rt_safe_earliest_event_discrete_unlocked (Temporal::timepos_t const & start_time, Temporal::timepos_t & x, double& y, bool inclusive) const
{
Temporal::timepos_t start = start_time;
build_search_cache_if_necessary (start);
if (_search_cache.first != _events.end()) {
@ -1554,7 +1618,7 @@ ControlList::rt_safe_earliest_event_discrete_unlocked (double start, double& x,
/* Move left of cache to this point
* (Optimize for immediate call this cycle within range) */
_search_cache.left = x;
_search_cache.left = first->when;
++_search_cache.first;
assert(x >= start);
@ -1578,9 +1642,9 @@ ControlList::rt_safe_earliest_event_discrete_unlocked (double start, double& x,
* \return true if event is found (and \a x and \a y are valid).
*/
bool
ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, double& y, bool inclusive, double min_x_delta) const
ControlList::rt_safe_earliest_event_linear_unlocked (Temporal::timepos_t const & start_time, Temporal::timepos_t & x, double& y, bool inclusive, timepos_t const & min_x_delta) const
{
Glib::Threads::RWLock::ReaderLock lm (_lock); // XXX
Temporal::timepos_t start = start_time;
// cout << "earliest_event(start: " << start << ", x: " << x << ", y: " << y << ", inclusive: " << inclusive << ")" << endl;
@ -1591,7 +1655,6 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, do
return rt_safe_earliest_event_discrete_unlocked (start + min_x_delta, x, y, inclusive);
}
if (min_x_delta > 0) {
/* if there is an event between [start and start + min_x_delta], use it,
* otherwise interpolate at start + min_x_delta
@ -1642,7 +1705,7 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, do
y = first->value;
/* Move left of cache to this point
* (Optimize for immediate call this cycle within range) */
_search_cache.left = x;
_search_cache.left = first->when;
return true;
} else if (next->when < start || (!inclusive && next->when == start)) {
/* "Next" is before the start, no points left. */
@ -1655,34 +1718,44 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, do
y = next->value;
/* Move left of cache to this point
* (Optimize for immediate call this cycle within range) */
_search_cache.left = x;
_search_cache.left = next->when;
return true;
} else {
return false;
}
}
const double slope = (next->value - first->value) / (double)(next->when - first->when);
const double slope = (next->value - first->value) / (double) first->when.distance (next->when).distance().val();
//cerr << "start y: " << start_y << endl;
//y = first->value + (slope * fabs(start - first->when));
y = first->value;
if (first->value < next->value) // ramping up
if (first->value < next->value) { // ramping up
y = ceil(y);
else // ramping down
} else { // ramping down
y = floor(y);
}
x = first->when + (y - first->value) / (double)slope;
if (_time_style == Temporal::AudioTime) {
x = first->when + Temporal::timepos_t::from_samples ((y - first->value) / (double)slope);
} else {
x = first->when + Temporal::timepos_t::from_ticks ((y - first->value) / (double)slope);
}
while ((inclusive && x < start) || (x <= start && y != next->value)) {
while ((inclusive && x < start_time) || (x <= start_time && y != next->value)) {
if (first->value < next->value) // ramping up
if (first->value < next->value) { // ramping up
y += 1.0;
else // ramping down
} else { // ramping down
y -= 1.0;
}
x = first->when + (y - first->value) / (double)slope;
if (_time_style == Temporal::AudioTime) {
x = first->when + Temporal::timepos_t::from_samples ((y - first->value) / (double)slope);
} else {
x = first->when + Temporal::timepos_t::from_ticks ((y - first->value) / (double)slope);
}
}
#if 0
@ -1695,20 +1768,21 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, do
|| (y <= first->value && y >= next->value) );
const bool past_start = (inclusive ? x >= start : x > start);
const bool past_start = (inclusive ? x >= start_time : x > start_time);
if (past_start) {
/* Move left of cache to this point
* (Optimize for immediate call this cycle within range) */
_search_cache.left = x;
assert(inclusive ? x >= start : x > start);
assert(inclusive ? x >= start_time : x > start_time);
return true;
} else {
if (inclusive) {
x = next->when;
_search_cache.left = next->when;
} else {
x = start;
}
_search_cache.left = x;
}
return true;
}
@ -1724,10 +1798,12 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, do
* @param op 0 = cut, 1 = copy, 2 = clear.
*/
boost::shared_ptr<ControlList>
ControlList::cut_copy_clear (double start, double end, int op)
ControlList::cut_copy_clear (Temporal::timepos_t const & start_time, Temporal::timepos_t const & end_time, int op)
{
boost::shared_ptr<ControlList> nal = create (_parameter, _desc);
boost::shared_ptr<ControlList> nal = create (_parameter, _desc, _time_style);
iterator s, e;
Temporal::timepos_t start = start_time;
Temporal::timepos_t end = end_time;
ControlEvent cp (start, 0.0);
{
@ -1773,7 +1849,7 @@ ControlList::cut_copy_clear (double start, double end, int op)
}
if (op != 2) { // ! clear
nal->_events.push_back (new ControlEvent (0, val));
nal->_events.push_back (new ControlEvent (std::numeric_limits<Temporal::timepos_t>::min(), val));
}
}
@ -1784,7 +1860,7 @@ ControlList::cut_copy_clear (double start, double end, int op)
*/
if (op != 2) {
nal->_events.push_back (new ControlEvent ((*x)->when - start, (*x)->value));
nal->_events.push_back (new ControlEvent (Temporal::timepos_t (start.distance ((*x)->when)), (*x)->value));
}
if (op != 1) {
@ -1804,7 +1880,7 @@ ControlList::cut_copy_clear (double start, double end, int op)
}
if (op != 2 && (e != _events.end() && end < (*e)->when)) { // cut/copy
nal->_events.push_back (new ControlEvent (end - start, end_value));
nal->_events.push_back (new ControlEvent (Temporal::timepos_t (start.distance (start)), end_value));
}
}
@ -1821,26 +1897,26 @@ ControlList::cut_copy_clear (double start, double end, int op)
boost::shared_ptr<ControlList>
ControlList::cut (double start, double end)
ControlList::cut (Temporal::timepos_t const & start, Temporal::timepos_t const & end)
{
return cut_copy_clear (start, end, 0);
}
boost::shared_ptr<ControlList>
ControlList::copy (double start, double end)
ControlList::copy (Temporal::timepos_t const & start, Temporal::timepos_t const & end)
{
return cut_copy_clear (start, end, 1);
}
void
ControlList::clear (double start, double end)
ControlList::clear (Temporal::timepos_t const & start, Temporal::timepos_t const & end)
{
cut_copy_clear (start, end, 2);
}
/** @param pos Position in model coordinates */
bool
ControlList::paste (const ControlList& alist, double pos)
ControlList::paste (const ControlList& alist, Temporal::timepos_t const & time)
{
if (alist._events.empty()) {
return false;
@ -1850,7 +1926,8 @@ ControlList::paste (const ControlList& alist, double pos)
Glib::Threads::RWLock::WriterLock lm (_lock);
iterator where;
iterator prev;
double end = 0;
Temporal::timepos_t end;
Temporal::timepos_t pos = time;
ControlEvent cp (pos, 0.0);
where = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
@ -1909,9 +1986,9 @@ ControlList::paste (const ControlList& alist, double pos)
* @param return true if anything was changed, otherwise false (ie nothing needed changing)
*/
bool
ControlList::move_ranges (const list< RangeMove<double> >& movements)
ControlList::move_ranges (const list< Temporal::RangeMove> & movements)
{
typedef list< RangeMove<double> > RangeMoveList;
typedef list<Temporal::RangeMove> RangeMoveList;
{
Glib::Threads::RWLock::WriterLock lm (_lock);
@ -1923,11 +2000,17 @@ ControlList::move_ranges (const list< RangeMove<double> >& movements)
bool things_erased = false;
for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
if (erase_range_internal (i->from, i->from + i->length, _events)) {
Temporal::timepos_t start = i->from;
Temporal::timepos_t end = i->from + i->length;
if (erase_range_internal (start, end, _events)) {
things_erased = true;
}
if (erase_range_internal (i->to, i->to + i->length, _events)) {
start = i->to;
end = i->to + i->length;
if (erase_range_internal (start, end, _events)) {
things_erased = true;
}
}
@ -1940,14 +2023,48 @@ ControlList::move_ranges (const list< RangeMove<double> >& movements)
/* copy the events into the new list */
for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
iterator j = old_events.begin ();
const double limit = i->from + i->length;
const double dx = i->to - i->from;
while (j != old_events.end () && (*j)->when <= limit) {
if ((*j)->when >= i->from) {
const Temporal::timepos_t limit = i->from + i->length;
const Temporal::timecnt_t dx = i->from.distance (i->to);
while (j != old_events.end ()) {
Temporal::timepos_t jtime;
switch (_time_style) {
case Temporal::AudioTime:
jtime = (*j)->when;
break;
case Temporal::BeatTime:
jtime = (*j)->when;
break;
default:
/*NOTREACHED*/
return false;
}
if (jtime > limit) {
break;
}
if (jtime >= i->from) {
ControlEvent* ev = new ControlEvent (**j);
ev->when += dx;
switch (_time_style) {
case Temporal::AudioTime:
ev->when += dx.samples();
break;
case Temporal::BeatTime:
ev->when += dx.beats().to_ticks();
break;
default:
/*NOTREACHED*/
return false;
}
_events.push_back (ev);
}
++j;
}
}
@ -2044,9 +2161,8 @@ ControlList::dump (ostream& o)
/* NOT LOCKED ... for debugging only */
for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
o << (*x)->value << " @ " << (uint64_t) (*x)->when << endl;
o << (*x)->value << " @ " << (*x)->when << endl;
}
}
} // namespace Evoral

View file

@ -62,20 +62,23 @@ Curve::solve () const
(www.korf.co.uk/spline.pdf) for more details.
*/
vector<double> x(npoints);
vector<Temporal::timepos_t> x (npoints);
vector<double> y(npoints);
uint32_t i;
ControlList::EventList::const_iterator xx;
for (i = 0, xx = _list.events().begin(); xx != _list.events().end(); ++xx, ++i) {
x[i] = (double) (*xx)->when;
y[i] = (double) (*xx)->value;
x[i] = (*xx)->when;
y[i] = (*xx)->value;
}
double lp0, lp1, fpone;
double xd;
lp0 = (x[1] - x[0])/(y[1] - y[0]);
lp1 = (x[2] - x[1])/(y[2] - y[1]);
xd = x[0].distance (x[1]).magnitude();
lp0 = xd/(y[1] - y[0]);
xd = x[1].distance (x[2]).magnitude();
lp1 = xd/(y[2] - y[1]);
if (lp0*lp1 < 0) {
fpone = 0;
@ -92,9 +95,12 @@ Curve::solve () const
double ydelta; /* ditto */
double fppL, fppR;
double fpi;
double xi = x[i].val();
double xim1;
if (i > 0) {
xdelta = x[i] - x[i-1];
xim1 = x[i-1].val();
xdelta = xi - xim1;
xdelta2 = xdelta * xdelta;
ydelta = y[i] - y[i-1];
}
@ -105,7 +111,7 @@ Curve::solve () const
/* first segment */
fplast = ((3 * (y[1] - y[0]) / (2 * (x[1] - x[0]))) - (fpone * 0.5));
fplast = ((3 * (y[1] - y[0]) / (2 * (xi - xim1))) - (fpone * 0.5));
/* we don't store coefficients for i = 0 */
@ -121,7 +127,9 @@ Curve::solve () const
/* all other segments */
double slope_before = ((x[i+1] - x[i]) / (y[i+1] - y[i]));
double xip1 = x[i+1].val();
double slope_before = (xip1 - xi) / (y[i+1] - y[i]);
double slope_after = (xdelta / ydelta);
if (slope_after * slope_before < 0.0) {
@ -145,22 +153,22 @@ Curve::solve () const
double b, c, d;
d = (fppR - fppL) / (6 * xdelta);
c = ((x[i] * fppL) - (x[i-1] * fppR))/(2 * xdelta);
c = ((xi * fppL) - (xim1 * fppR))/(2 * xdelta);
double xim12, xim13;
double xi2, xi3;
xim12 = x[i-1] * x[i-1]; /* "x[i-1] squared" */
xim13 = xim12 * x[i-1]; /* "x[i-1] cubed" */
xi2 = x[i] * x[i]; /* "x[i] squared" */
xi3 = xi2 * x[i]; /* "x[i] cubed" */
xim12 = xim1 * xim1; /* "x[i-1] squared" */
xim13 = xim12 * xim1; /* "x[i-1] cubed" */
xi2 = xi * xi; /* "x[i] squared" */
xi3 = xi2 * xi; /* "x[i] cubed" */
b = (ydelta - (c * (xi2 - xim12)) - (d * (xi3 - xim13))) / xdelta;
/* store */
(*xx)->create_coeffs();
(*xx)->coeff[0] = y[i-1] - (b * x[i-1]) - (c * xim12) - (d * xim13);
(*xx)->coeff[0] = y[i-1] - (b * xim1) - (c * xim12) - (d * xim13);
(*xx)->coeff[1] = b;
(*xx)->coeff[2] = c;
(*xx)->coeff[3] = d;
@ -174,7 +182,7 @@ Curve::solve () const
}
bool
Curve::rt_safe_get_vector (double x0, double x1, float *vec, int32_t veclen) const
Curve::rt_safe_get_vector (Temporal::timepos_t const & x0, Temporal::timepos_t const & x1, float *vec, int32_t veclen) const
{
Glib::Threads::RWLock::ReaderLock lm(_list.lock(), Glib::Threads::TRY_LOCK);
@ -187,16 +195,20 @@ Curve::rt_safe_get_vector (double x0, double x1, float *vec, int32_t veclen) con
}
void
Curve::get_vector (double x0, double x1, float *vec, int32_t veclen) const
Curve::get_vector (Temporal::timepos_t const & x0, Temporal::timepos_t const & x1, float *vec, int32_t veclen) const
{
Glib::Threads::RWLock::ReaderLock lm(_list.lock());
_get_vector (x0, x1, vec, veclen);
}
void
Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) const
Curve::_get_vector (Temporal::timepos_t const & x0, Temporal::timepos_t const & x1, float *vec, int32_t veclen) const
{
double rx, lx, hx, max_x, min_x;
double rx, lx, hx;
const double start = x0.val();
const double end = x1.val();
double max_x;
double min_x;
int32_t i;
int32_t original_veclen;
int32_t npoints;
@ -222,10 +234,10 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) const
/* events is now known not to be empty */
max_x = _list.events().back()->when;
min_x = _list.events().front()->when;
max_x = _list.events().back()->when.val();
min_x = _list.events().front()->when.val();
if (x0 > max_x) {
if (start > max_x) {
/* totally past the end - just fill the entire array with the final value */
for (int32_t i = 0; i < veclen; ++i) {
vec[i] = _list.events().back()->value;
@ -233,7 +245,7 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) const
return;
}
if (x1 < min_x) {
if (end < min_x) {
/* totally before the first event - fill the entire array with
* the initial value.
*/
@ -245,13 +257,13 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) const
original_veclen = veclen;
if (x0 < min_x) {
if (start < min_x) {
/* fill some beginning section of the array with the
initial (used to be default) value
*/
double frac = (min_x - x0) / (x1 - x0);
double frac = (min_x - start) / (end - start);
int64_t fill_len = (int64_t) floor (veclen * frac);
fill_len = min (fill_len, (int64_t)veclen);
@ -264,11 +276,11 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) const
vec += fill_len;
}
if (veclen && x1 > max_x) {
if (veclen && end > max_x) {
/* fill some end section of the array with the default or final value */
double frac = (x1 - max_x) / (x1 - x0);
double frac = (end - max_x) / (end - start);
int64_t fill_len = (int64_t) floor (original_veclen * frac);
float val;
@ -282,14 +294,14 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) const
veclen -= fill_len;
}
lx = max (min_x, x0);
hx = min (max_x, x1);
lx = max (min_x, start);
hx = min (max_x, end);
if (npoints == 2) {
const double lpos = _list.events().front()->when;
const double lpos = _list.events().front()->when.val();
const double lval = _list.events().front()->value;
const double upos = _list.events().back()->when;
const double upos = _list.events().back()->when.val();
const double uval = _list.events().back()->value;
/* dx that we are using */
@ -360,18 +372,19 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) const
rx = lx;
double dx = 0;
double dx = 0.;
if (veclen > 1) {
dx = (hx - lx) / (veclen - 1);
}
for (i = 0; i < veclen; ++i, rx += dx) {
vec[i] = multipoint_eval (rx);
vec[i] = multipoint_eval (x0.is_beats() ? Temporal::timepos_t::from_ticks (rx) : Temporal::timepos_t::from_superclock (rx));
}
}
double
Curve::multipoint_eval (double x) const
Curve::multipoint_eval (Temporal::timepos_t const & x) const
{
pair<ControlList::EventList::const_iterator,ControlList::EventList::const_iterator> range;
@ -427,8 +440,11 @@ Curve::multipoint_eval (double x) const
return before->value;
}
double tdelta = x - before->when;
double trange = after->when - before->when;
double aw = after->when.val();
double bw = before->when.val();
double tdelta = x.val() - bw;
double trange = aw - bw;
switch (_list.interpolation()) {
case ControlList::Discrete:
@ -440,8 +456,9 @@ Curve::multipoint_eval (double x) const
case ControlList::Curved:
if (after->coeff) {
ControlEvent* ev = after;
double x2 = x * x;
return ev->coeff[0] + (ev->coeff[1] * x) + (ev->coeff[2] * x2) + (ev->coeff[3] * x2 * x);
#warning NUTEMPO fixme possible overflow ... multiplyng two position types .. also, units?
double x2 = x.val() * x.val();
return ev->coeff[0] + (ev->coeff[1] * x.val()) + (ev->coeff[2] * x2) + (ev->coeff[3] * x2 * x.val());
}
/* fallthrough */
case ControlList::Linear:

View file

@ -58,7 +58,7 @@ using namespace PBD;
XXX: This is a hack. The time should probably be expressed in
seconds rather than beats, and should be configurable etc. etc.
*/
static double const time_between_interpolated_controller_outputs = 1.0 / 256;
static Temporal::Beats const time_between_interpolated_controller_outputs = Temporal::Beats::ticks (256);
namespace Evoral {
@ -82,7 +82,7 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>&
Time t,
bool force_discrete,
const std::set<Evoral::Parameter>& filtered,
const std::set<WeakNotePtr>* active_notes)
std::set<WeakNotePtr> const * active_notes)
: _seq(&seq)
, _active_patch_change_message (0)
, _type(NIL)
@ -103,8 +103,7 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>&
// Add currently active notes, if given
if (active_notes) {
for (typename std::set<WeakNotePtr>::const_iterator i = active_notes->begin();
i != active_notes->end(); ++i) {
for (typename std::set<WeakNotePtr>::const_iterator i = active_notes->begin(); i != active_notes->end(); ++i) {
NotePtr note = i->lock();
if (note && note->time() <= t && note->end_time() > t) {
_active_notes.push(note);
@ -114,7 +113,6 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>&
// Find first note which begins at or after t
_note_iter = seq.note_lower_bound(t);
// Find first sysex event at or after t
for (typename Sequence<Time>::SysExes::const_iterator i = seq.sysexes().begin();
i != seq.sysexes().end(); ++i) {
@ -138,7 +136,8 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>&
_control_iters.reserve(seq._controls.size());
bool found = false;
size_t earliest_control_index = 0;
double earliest_control_x = DBL_MAX;
Temporal::timepos_t earliest_control_x = std::numeric_limits<Temporal::timepos_t>::max();
for (Controls::const_iterator i = seq._controls.begin(); i != seq._controls.end(); ++i) {
if (filtered.find (i->first) != filtered.end()) {
@ -147,21 +146,21 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>&
}
DEBUG_TRACE (DEBUG::Sequence, string_compose ("Iterator: control: %1\n", seq._type_map.to_symbol(i->first)));
double x, y;
Temporal::timepos_t xtime;
double y;
bool ret;
if (_force_discrete || i->second->list()->interpolation() == ControlList::Discrete) {
ret = i->second->list()->rt_safe_earliest_event_discrete_unlocked (t.to_double(), x, y, true);
ret = i->second->list()->rt_safe_earliest_event_discrete_unlocked (Temporal::timepos_t (t), xtime, y, true);
} else {
ret = i->second->list()->rt_safe_earliest_event_linear_unlocked(t.to_double(), x, y, true);
ret = i->second->list()->rt_safe_earliest_event_linear_unlocked(Temporal::timepos_t (t), xtime, y, true);
}
if (!ret) {
DEBUG_TRACE (DEBUG::Sequence, string_compose ("Iterator: CC %1 (size %2) has no events past %3\n",
i->first.id(), i->second->list()->size(), t));
continue;
}
assert(x >= 0);
const ParameterDescriptor& desc = seq.type_map().descriptor(i->first);
if (y < desc.lower || y > desc.upper) {
cerr << "ERROR: Controller value " << y
@ -170,14 +169,14 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>&
continue;
}
DEBUG_TRACE (DEBUG::Sequence, string_compose ("Iterator: CC %1 added (%2, %3)\n", i->first.id(), x, y));
DEBUG_TRACE (DEBUG::Sequence, string_compose ("Iterator: CC %1 added (%2, %3)\n", i->first.id(), xtime, y));
const ControlIterator new_iter(i->second->list(), x, y);
const ControlIterator new_iter(i->second->list(), xtime, y);
_control_iters.push_back(new_iter);
// Found a new earliest_control
if (x < earliest_control_x) {
earliest_control_x = x;
if (xtime < earliest_control_x) {
earliest_control_x = xtime;
earliest_control_index = _control_iters.size() - 1;
found = true;
}
@ -215,13 +214,22 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>&
template<typename Time>
void
Sequence<Time>::const_iterator::invalidate(std::set< boost::weak_ptr< Note<Time> > >* notes)
Sequence<Time>::const_iterator::get_active_notes (std::set<WeakNotePtr>& active_notes) const
{
while (!_active_notes.empty()) {
if (notes) {
notes->insert(_active_notes.top());
/* can't iterate over a std::priority_queue<> such as ActiveNotes */
ActiveNotes copy (_active_notes);
while (!copy.empty()) {
active_notes.insert (copy.top());
copy.pop ();
}
_active_notes.pop();
}
template<typename Time>
void
Sequence<Time>::const_iterator::invalidate(bool preserve_active_notes)
{
if (!preserve_active_notes) {
_active_notes = ActiveNotes();
}
_type = NIL;
_is_end = true;
@ -260,16 +268,16 @@ Sequence<Time>::const_iterator::choose_next(Time earliest_t)
/* Use the next earliest controller iff it's earlier or coincident with the note-on
* or patch-change. Bank-select (CC0, CC32) needs to be sent before the PGM. */
if (_control_iter != _control_iters.end() &&
_control_iter->list && _control_iter->x != DBL_MAX) {
if (_type == NIL || _control_iter->x <= earliest_t.to_double()) {
_control_iter->list && _control_iter->x != std::numeric_limits<Temporal::timepos_t>::max()) {
if (_type == NIL || _control_iter->x <= earliest_t) {
_type = CONTROL;
earliest_t = Time(_control_iter->x);
earliest_t = _control_iter->x.beats();
}
}
/* .. but prefer to send any Note-off first */
if ((!_active_notes.empty())) {
if (_type == NIL || _active_notes.top()->end_time().to_double() <= earliest_t.to_double()) {
if (_type == NIL || _active_notes.top()->end_time() <= earliest_t) {
_type = NOTE_OFF;
earliest_t = _active_notes.top()->end_time();
}
@ -351,7 +359,8 @@ Sequence<Time>::const_iterator::operator++()
<< int(ev.buffer()[0]) << int(ev.buffer()[1]) << int(ev.buffer()[2]) << endl;
}
double x = 0.0;
Temporal::timepos_t x;
Temporal::timepos_t xtime;
double y = 0.0;
bool ret = false;
@ -366,19 +375,18 @@ Sequence<Time>::const_iterator::operator++()
case CONTROL:
// Increment current controller iterator
if (_force_discrete || _control_iter->list->interpolation() == ControlList::Discrete) {
ret = _control_iter->list->rt_safe_earliest_event_discrete_unlocked (
_control_iter->x, x, y, false);
ret = _control_iter->list->rt_safe_earliest_event_discrete_unlocked (_control_iter->x, xtime, y, false);
} else {
ret = _control_iter->list->rt_safe_earliest_event_linear_unlocked (
_control_iter->x, x, y, false, time_between_interpolated_controller_outputs);
_control_iter->x, xtime, y, false, Temporal::timecnt_t::from_ticks (time_between_interpolated_controller_outputs));
}
assert(!ret || x > _control_iter->x);
if (ret) {
_control_iter->x = x;
_control_iter->x = xtime;
_control_iter->y = y;
} else {
_control_iter->list.reset();
_control_iter->x = DBL_MAX;
_control_iter->x = std::numeric_limits<Time>::max();
_control_iter->y = DBL_MAX;
}
@ -550,7 +558,7 @@ Sequence<Time>::control_to_midi_event(
assert(iter.list->parameter().id() <= INT8_MAX);
assert(iter.y <= INT8_MAX);
ev->set_time(Time(iter.x));
ev->set_time(iter.x.beats());
ev->realloc(3);
ev->buffer()[0] = MIDI_CMD_CONTROL + iter.list->parameter().channel();
ev->buffer()[1] = (uint8_t)iter.list->parameter().id();
@ -562,7 +570,7 @@ Sequence<Time>::control_to_midi_event(
assert(iter.list->parameter().channel() < 16);
assert(iter.y <= INT8_MAX);
ev->set_time(Time(iter.x));
ev->set_time(iter.x.beats());
ev->realloc(2);
ev->buffer()[0] = MIDI_CMD_PGM_CHANGE + iter.list->parameter().channel();
ev->buffer()[1] = (uint8_t)iter.y;
@ -573,7 +581,7 @@ Sequence<Time>::control_to_midi_event(
assert(iter.list->parameter().channel() < 16);
assert(iter.y < (1<<14));
ev->set_time(Time(iter.x));
ev->set_time(iter.x.beats());
ev->realloc(3);
ev->buffer()[0] = MIDI_CMD_BENDER + iter.list->parameter().channel();
ev->buffer()[1] = uint16_t(iter.y) & 0x7F; // LSB
@ -586,7 +594,7 @@ Sequence<Time>::control_to_midi_event(
assert(iter.list->parameter().id() <= INT8_MAX);
assert(iter.y <= INT8_MAX);
ev->set_time(Time(iter.x));
ev->set_time(iter.x.beats());
ev->realloc(3);
ev->buffer()[0] = MIDI_CMD_NOTE_PRESSURE + iter.list->parameter().channel();
ev->buffer()[1] = (uint8_t)iter.list->parameter().id();
@ -598,7 +606,7 @@ Sequence<Time>::control_to_midi_event(
assert(iter.list->parameter().channel() < 16);
assert(iter.y <= INT8_MAX);
ev->set_time(Time(iter.x));
ev->set_time(iter.x.beats());
ev->realloc(2);
ev->buffer()[0] = MIDI_CMD_CHANNEL_PRESSURE + iter.list->parameter().channel();
ev->buffer()[1] = (uint8_t)iter.y;
@ -1075,7 +1083,7 @@ Sequence<Time>::append_control_unlocked(const Parameter& param, Time time, doubl
DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 %2 @ %3 = %4 # controls: %5\n",
this, _type_map.to_symbol(param), time, value, _controls.size()));
boost::shared_ptr<Control> c = control(param, true);
c->list()->add (time.to_double(), value, true, false);
c->list()->add (Temporal::timepos_t (time), value, true, false);
/* XXX control events should use IDs */
}
@ -1411,12 +1419,26 @@ Sequence<Time>::control_list_marked_dirty ()
template<typename Time>
void
Sequence<Time>::dump (ostream& str) const
Sequence<Time>::dump (ostream& str, typename Sequence<Time>::const_iterator x, uint32_t limit) const
{
typename Sequence<Time>::const_iterator i;
str << "+++ dump\n";
for (i = begin(); i != end(); ++i) {
typename Sequence<Time>::const_iterator i = begin();
if (x != end()) {
i = x;
}
str << "+++ dump";
if (i != end()) {
str << " from " << i->time();
}
str << endl;
for (; i != end() && (limit >= 0); ++i) {
str << *i << endl;
if (limit) {
if (--limit == 0) {
break;
}
}
}
str << "--- dump\n";
}

View file

@ -1,51 +0,0 @@
/*
* Copyright (C) 2014-2015 David Robillard <d@drobilla.net>
*
* 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 <stdint.h>
#include "temporal/beats.h"
#include "temporal/types.h"
#include "evoral/TimeConverter.h"
#include "evoral/types.h"
namespace Evoral {
template<typename A, typename B>
TimeConverter<A,B>::~TimeConverter()
{}
template<typename A, typename B>
B
IdentityConverter<A,B>::to(A a) const
{
return static_cast<B>(a);
}
template<typename A, typename B>
A
IdentityConverter<A,B>::from(B b) const
{
return static_cast<A>(b);
}
template class IdentityConverter<double, Temporal::samplepos_t>;
template class TimeConverter<double, Temporal::samplepos_t>;
template class TimeConverter<Temporal::Beats, Temporal::samplepos_t>;
} // namespace Evoral

View file

@ -26,6 +26,8 @@
#include <boost/shared_ptr.hpp>
#include "pbd/signals.h"
#include "temporal/timeline.h"
#include "evoral/visibility.h"
#include "evoral/Parameter.h"
#include "evoral/ParameterDescriptor.h"
@ -52,8 +54,8 @@ public:
virtual ~Control() {}
virtual void set_double (double val, double frame=0, bool to_list=false);
virtual double get_double (bool from_list=false, double frame=0) const;
virtual void set_double (double val, Temporal::timepos_t when = std::numeric_limits<Temporal::timepos_t>::min(), bool to_list=false);
virtual double get_double (bool from_list=false, Temporal::timepos_t frame = std::numeric_limits<Temporal::timepos_t>::min()) const;
/** Get the latest user-set value
* (which may not equal get_value() when automation is playing back).

View file

@ -34,8 +34,12 @@
#include "pbd/signals.h"
#include "temporal/timeline.h"
#include "temporal/types.h"
#include "temporal/range.h"
#include "evoral/visibility.h"
#include "evoral/Range.h"
#include "evoral/Parameter.h"
#include "evoral/ParameterDescriptor.h"
@ -48,7 +52,8 @@ class TypeMap;
*/
class LIBEVORAL_API ControlEvent {
public:
ControlEvent (double w, double v)
ControlEvent (Temporal::timepos_t const & w, double v)
: when (w), value (v), coeff (0)
{}
@ -71,11 +76,12 @@ public:
coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
}
double when;
Temporal::timepos_t when;
double value;
double* coeff; ///< double[4] allocated by Curve as needed
};
/** A list (sequence) of time-stamped values for a control
*/
class LIBEVORAL_API ControlList
@ -87,12 +93,14 @@ public:
typedef EventList::const_iterator const_iterator;
typedef EventList::const_reverse_iterator const_reverse_iterator;
ControlList (const Parameter& id, const ParameterDescriptor& desc);
ControlList (const Parameter& id, const ParameterDescriptor& desc, Temporal::TimeDomain);
ControlList (const ControlList&, Temporal::timepos_t const & start, Temporal::timepos_t const & end);
ControlList (const ControlList&);
ControlList (const ControlList&, double start, double end);
virtual ~ControlList();
virtual boost::shared_ptr<ControlList> create(const Parameter& id, const ParameterDescriptor& desc);
Temporal::TimeDomain time_style() const { return _time_style; }
virtual boost::shared_ptr<ControlList> create(const Parameter& id, const ParameterDescriptor& desc, Temporal::TimeDomain);
void dump (std::ostream&);
@ -113,26 +121,26 @@ public:
EventList::size_type size() const { return _events.size(); }
/** @return time-stamp of first or last event in the list */
double when (bool at_start) const {
Temporal::timepos_t when (bool at_start) const {
Glib::Threads::RWLock::ReaderLock lm (_lock);
if (_events.empty()) {
return 0.0;
return std::numeric_limits<Temporal::timepos_t>::min();
}
return at_start ? _events.front()->when : _events.back()->when;
}
double length() const {
Temporal::timecnt_t length() const {
Glib::Threads::RWLock::ReaderLock lm (_lock);
return _events.empty() ? 0.0 : _events.back()->when;
return _events.empty() ? std::numeric_limits<Temporal::timecnt_t>::min() : Temporal::timecnt_t (_events.back()->when, Temporal::timepos_t());
}
bool empty() const { return _events.empty(); }
/** Remove all events from this list. */
void clear ();
void x_scale (double factor);
bool extend_to (double);
void slide (iterator before, double distance);
void shift (double before, double distance);
void x_scale (Temporal::ratio_t const &);
bool extend_to (Temporal::timepos_t const & );
void slide (iterator before, Temporal::timecnt_t const & distance);
void shift (Temporal::timepos_t const & before, Temporal::timecnt_t const & distance);
void y_transform (boost::function<double(double)> callback);
void list_merge (ControlList const& other, boost::function<double(double, double)> callback);
@ -147,7 +155,7 @@ public:
* @param with_guards if true, add guard-points
* @param with_initial if true, add an initial point if the list is empty
*/
virtual void add (double when, double value, bool with_guards=true, bool with_initial=true);
virtual void add (Temporal::timepos_t const & when, double value, bool with_guards=true, bool with_initial=true);
/** Add an event to this list.
*
@ -160,17 +168,17 @@ public:
*
* @return true if an event was added.
*/
virtual bool editor_add (double when, double value, bool with_guard);
virtual bool editor_add (Temporal::timepos_t const & when, double value, bool with_guard);
/* to be used only for loading pre-sorted data from saved state */
void fast_simple_add (double when, double value);
void fast_simple_add (Temporal::timepos_t const & when, double value);
void erase_range (double start, double end);
void erase_range (Temporal::timepos_t const & start , Temporal::timepos_t const & end);
void erase (iterator);
void erase (iterator, iterator);
void erase (double, double);
bool move_ranges (std::list< RangeMove<double> > const &);
void modify (iterator, double, double);
void erase (Temporal::timepos_t const &, double);
bool move_ranges (std::list<Temporal::RangeMove> const &);
void modify (iterator, Temporal::timepos_t const &, double);
/** Thin the number of events in this list.
*
@ -192,29 +200,29 @@ public:
*/
void thin (double thinning_factor);
boost::shared_ptr<ControlList> cut (double, double);
boost::shared_ptr<ControlList> copy (double, double);
boost::shared_ptr<ControlList> cut (Temporal::timepos_t const &, Temporal::timepos_t const &);
boost::shared_ptr<ControlList> copy (Temporal::timepos_t const &, Temporal::timepos_t const &);
/** Remove all events in the given time range from this list.
*
* @param start start of range (inclusive) in audio samples
* @param end end of range (inclusive) in audio samples
*/
void clear (double start, double end);
void clear (Temporal::timepos_t const &, Temporal::timepos_t const &);
bool paste (const ControlList&, double position);
bool paste (const ControlList&, Temporal::timepos_t const &);
/** Remove all events after the given time from this list.
*
* @param last_coordinate time in audio samples of the last event to keep
*/
void truncate_end (double last_coordinate);
void truncate_end (Temporal::timepos_t const & last_coordinate);
/** Remove all events up to to the given time from this list.
*
* @param overall_length overall length in audio samples
* @param overall_length overall length
*/
void truncate_start (double overall_length);
void truncate_start (Temporal::timecnt_t const & overall_length);
iterator begin() { return _events.begin(); }
const_iterator begin() const { return _events.begin(); }
@ -229,7 +237,7 @@ public:
ControlEvent* front() { return _events.front(); }
const ControlEvent* front() const { return _events.front(); }
std::pair<ControlList::iterator,ControlList::iterator> control_points_adjacent (double when);
std::pair<ControlList::iterator,ControlList::iterator> control_points_adjacent (Temporal::timepos_t const & when);
template<class T> void apply_to_points (T& obj, void (T::*method)(const ControlList&)) {
Glib::Threads::RWLock::WriterLock lm (_lock);
@ -242,7 +250,7 @@ public:
* @param where absolute time in samples
* @returns parameter value
*/
double eval (double where) const {
double eval (Temporal::timepos_t const & where) const {
Glib::Threads::RWLock::ReaderLock lm (_lock);
return unlocked_eval (where);
}
@ -254,7 +262,7 @@ public:
* @param ok boolean reference if returned value is valid
* @returns parameter value
*/
double rt_safe_eval (double where, bool& ok) const {
double rt_safe_eval (Temporal::timepos_t const & where, bool& ok) const {
Glib::Threads::RWLock::ReaderLock lm (_lock, Glib::Threads::TRY_LOCK);
@ -271,15 +279,15 @@ public:
/** Lookup cache for eval functions, range contains equivalent values */
struct LookupCache {
LookupCache() : left(-1) {}
double left; /* leftmost x coordinate used when finding "range" */
LookupCache() : left (std::numeric_limits<Temporal::timepos_t>::max()) {}
Temporal::timepos_t left; /* leftmost x coordinate used when finding "range" */
std::pair<ControlList::const_iterator,ControlList::const_iterator> range;
};
/** Lookup cache for point finding, range contains points after left */
struct SearchCache {
SearchCache () : left(-1) {}
double left; /* leftmost x coordinate used when finding "first" */
SearchCache () : left (std::numeric_limits<Temporal::timepos_t>::max()) {}
Temporal::timepos_t left; /* leftmost x coordinate used when finding "first" */
ControlList::const_iterator first;
};
@ -296,10 +304,10 @@ public:
*
* FIXME: Should this be private? Curve needs it..
*/
double unlocked_eval (double x) const;
double unlocked_eval (Temporal::timepos_t const & x) const;
bool rt_safe_earliest_event_discrete_unlocked (double start, double& x, double& y, bool inclusive) const;
bool rt_safe_earliest_event_linear_unlocked (double start, double& x, double& y, bool inclusive, double min_d_delta = 0) const;
bool rt_safe_earliest_event_discrete_unlocked (Temporal::timepos_t const & start, Temporal::timepos_t & x, double& y, bool inclusive) const;
bool rt_safe_earliest_event_linear_unlocked (Temporal::timepos_t const & start, Temporal::timepos_t & x, double& y, bool inclusive, Temporal::timepos_t min_x_delta = Temporal::timepos_t ()) const;
void create_curve();
void destroy_curve();
@ -338,9 +346,9 @@ public:
virtual bool touching() const { return false; }
virtual bool writing() const { return false; }
virtual bool touch_enabled() const { return false; }
void start_write_pass (double when);
void write_pass_finished (double when, double thinning_factor=0.0);
void set_in_write_pass (bool, bool add_point = false, double when = 0.0);
void start_write_pass (Temporal::timepos_t const &);
void write_pass_finished (Temporal::timepos_t const &, double thinning_factor=0.0);
void set_in_write_pass (bool, bool add_point = false, Temporal::timepos_t = std::numeric_limits<Temporal::timepos_t>::min());
/** @return true if transport is running and this list is in write mode */
bool in_write_pass () const;
bool in_new_write_pass () { return new_write_pass; }
@ -355,23 +363,23 @@ public:
void invalidate_insert_iterator ();
protected:
protected:
/** Called by unlocked_eval() to handle cases of 3 or more control points. */
double multipoint_eval (double x) const;
double multipoint_eval (Temporal::timepos_t const & x) const;
void build_search_cache_if_necessary (double start) const;
void build_search_cache_if_necessary (Temporal::timepos_t const & start) const;
boost::shared_ptr<ControlList> cut_copy_clear (double, double, int op);
bool erase_range_internal (double start, double end, EventList &);
boost::shared_ptr<ControlList> cut_copy_clear (Temporal::timepos_t const &, Temporal::timepos_t const &, int op);
bool erase_range_internal (Temporal::timepos_t const & start, Temporal::timepos_t const & end, EventList &);
void maybe_add_insert_guard (double when);
iterator erase_from_iterator_to (iterator iter, double when);
bool maybe_insert_straight_line (double when, double value);
void maybe_add_insert_guard (Temporal::timepos_t const & when);
iterator erase_from_iterator_to (iterator iter, Temporal::timepos_t const & when);
bool maybe_insert_straight_line (Temporal::timepos_t const & when, double value);
virtual void maybe_signal_changed ();
void _x_scale (double factor);
void _x_scale (Temporal::ratio_t const &);
mutable LookupCache _lookup_cache;
mutable SearchCache _search_cache;
@ -385,24 +393,25 @@ protected:
int8_t _frozen;
bool _changed_when_thawed;
bool _sort_pending;
Temporal::TimeDomain _time_style;
Curve* _curve;
private:
private:
iterator most_recent_insert_iterator;
double insert_position;
Temporal::timepos_t insert_position;
bool new_write_pass;
bool did_write_during_pass;
bool _in_write_pass;
void unlocked_remove_duplicates ();
void unlocked_invalidate_insert_iterator ();
void add_guard_point (double when, double offset);
void add_guard_point (Temporal::timepos_t const & when, Temporal::timecnt_t const & offset);
bool is_sorted () const;
};
} // namespace Evoral
#endif // EVORAL_CONTROL_LIST_HPP

View file

@ -22,6 +22,8 @@
#include <inttypes.h>
#include <boost/utility.hpp>
#include "temporal/timeline.h"
#include "evoral/visibility.h"
namespace Evoral {
@ -33,17 +35,17 @@ class LIBEVORAL_API Curve : public boost::noncopyable
public:
Curve (const ControlList& cl);
bool rt_safe_get_vector (double x0, double x1, float *arg, int32_t veclen) const;
void get_vector (double x0, double x1, float *arg, int32_t veclen) const;
bool rt_safe_get_vector (Temporal::timepos_t const & x0, Temporal::timepos_t const & x1, float *arg, int32_t veclen) const;
void get_vector (Temporal::timepos_t const & x0, Temporal::timepos_t const & x1, float *arg, int32_t veclen) const;
void solve () const;
void mark_dirty() const { _dirty = true; }
private:
double multipoint_eval (double x) const;
double multipoint_eval (Temporal::timepos_t const & x) const;
void _get_vector (double x0, double x1, float *arg, int32_t veclen) const;
void _get_vector (Temporal::timepos_t const & x0, Temporal::timepos_t const & x1, float *arg, int32_t veclen) const;
mutable bool _dirty;
const ControlList& _list;

View file

@ -1,298 +0,0 @@
/*
* Copyright (C) 2012 Carl Hetherington <carl@carlh.net>
* Copyright (C) 2013-2016 Paul Davis <paul@linuxaudiosystems.com>
* Copyright (C) 2014 Colin Fletcher <colin.m.fletcher@googlemail.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.
*/
#ifndef EVORAL_RANGE_HPP
#define EVORAL_RANGE_HPP
#include <list>
#include <assert.h>
#include <iostream>
#include "evoral/visibility.h"
namespace Evoral {
enum /*LIBEVORAL_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
};
template<typename T>
/*LIBEVORAL_API*/ OverlapType coverage (T sa, T ea, T sb, T eb) {
/* OverlapType returned reflects how the second (B)
* range overlaps the first (A).
*
* The diagram shows the OverlapType of each possible relative
* placement of A and B.
*
* Notes:
* Internal: the start and end points cannot coincide
* External: the start and end points can coincide
* Start: end points can coincide
* End: start points can coincide
*
* Internal disallows start and end point equality, and thus implies
* that there are two disjoint portions of A which do not overlap B.
*
* A: |---|
* B starts before A
* B: |-| None
* B: |--| Start
* B: |----| Start
* B: |------| External
* B: |--------| External
* B starts equal to A
* B: |-| Start
* B: |---| External
* B: |----| External
* B starts inside A
* B: |-| Internal
* B: |--| End
* B: |---| End
* B starts at end of A
* B: |--| End
* B starts after A
* B: |-| None
* A: |---|
*/
if (sa > ea) {
// seems we are sometimes called with negative length ranges
return OverlapNone;
}
if (sb > eb) {
// seems we are sometimes called with negative length ranges
return OverlapNone;
}
if (sb < sa) { // B starts before A
if (eb < sa) {
return OverlapNone;
} else if (eb == sa) {
return OverlapStart;
} else { // eb > sa
if (eb < ea) {
return OverlapStart;
} else if (eb == ea) {
return OverlapExternal;
} else {
return OverlapExternal;
}
}
} else if (sb == sa) { // B starts equal to A
if (eb < ea) {
return OverlapStart;
} else if (eb == ea) {
return OverlapExternal;
} else { // eb > ea
return OverlapExternal;
}
} else { // sb > sa
if (eb < ea) {
return OverlapInternal;
} else if (eb == ea) {
return OverlapEnd;
} else { // eb > ea
if (sb < ea) { // B starts inside A
return OverlapEnd;
} else if (sb == ea) { // B starts at end of A
return OverlapEnd;
} else { // sb > ea, B starts after A
return OverlapNone;
}
}
}
std::cerr << "unknown overlap type!" << sa << ", " << ea << "; " << sb << ", " << eb << std::endl;
assert(!"unknown overlap type!");
return OverlapNone;
}
/** Type to describe a time range */
template<typename T>
struct /*LIBEVORAL_API*/ Range {
Range (T f, T t) : from (f), to (t) {}
T from; ///< start of the range
T to; ///< end of the range (inclusive: to lies inside the range)
bool empty() const { return from == to; }
T length() const { return to - from + 1; }
/** for a T, return a mapping of it into the range (used for
* looping). If the argument is earlier than or equal to the end of
* this range, do nothing.
*/
T squish (T t) const {
if (t > to) {
t = (from + ((t - from) % length()));
}
return t;
}
};
template<typename T>
bool operator== (Range<T> a, Range<T> b) {
return a.from == b.from && a.to == b.to;
}
template<typename T>
class /*LIBEVORAL_API*/ RangeList {
public:
RangeList () : _dirty (false) {}
typedef std::list<Range<T> > List;
List const & get () {
coalesce ();
return _list;
}
void add (Range<T> const & range) {
_dirty = true;
_list.push_back (range);
}
bool empty () const {
return _list.empty ();
}
void coalesce () {
if (!_dirty) {
return;
}
restart:
for (typename List::iterator i = _list.begin(); i != _list.end(); ++i) {
for (typename List::iterator j = _list.begin(); j != _list.end(); ++j) {
if (i == j) {
continue;
}
if (coverage (i->from, i->to, j->from, j->to) != OverlapNone) {
i->from = std::min (i->from, j->from);
i->to = std::max (i->to, j->to);
_list.erase (j);
goto restart;
}
}
}
_dirty = false;
}
private:
List _list;
bool _dirty;
};
/** Type to describe the movement of a time range */
template<typename T>
struct /*LIBEVORAL_API*/ RangeMove {
RangeMove (T f, double l, T t) : from (f), length (l), to (t) {}
T from; ///< start of the range
double length; ///< length of the range
T to; ///< new start of the range
};
/** Subtract the ranges in `sub' from that in `range',
* returning the result.
*/
template<typename T>
RangeList<T> subtract (Range<T> range, RangeList<T> sub)
{
/* Start with the input range */
RangeList<T> result;
result.add (range);
if (sub.empty () || range.empty()) {
return result;
}
typename RangeList<T>::List s = sub.get ();
/* The basic idea here is to keep a list of the result ranges, and subtract
the bits of `sub' from them one by one.
*/
for (typename RangeList<T>::List::const_iterator i = s.begin(); i != s.end(); ++i) {
/* Here's where we'll put the new current result after subtracting *i from it */
RangeList<T> new_result;
typename RangeList<T>::List r = result.get ();
/* Work on all parts of the current result using this range *i */
for (typename RangeList<T>::List::const_iterator j = r.begin(); j != r.end(); ++j) {
switch (coverage (j->from, j->to, i->from, i->to)) {
case OverlapNone:
/* The thing we're subtracting (*i) does not overlap this bit of the result (*j),
so pass it through.
*/
new_result.add (*j);
break;
case OverlapInternal:
/* Internal overlap of the thing we're subtracting (*i) from this bit of the result,
so we should end up with two bits of (*j) left over, from the start of (*j) to
the start of (*i), and from the end of (*i) to the end of (*j).
*/
assert (j->from < i->from);
assert (j->to > i->to);
new_result.add (Range<T> (j->from, i->from - 1));
new_result.add (Range<T> (i->to + 1, j->to));
break;
case OverlapStart:
/* The bit we're subtracting (*i) overlaps the start of the bit of the result (*j),
* so we keep only the part of of (*j) from after the end of (*i)
*/
assert (i->to < j->to);
new_result.add (Range<T> (i->to + 1, j->to));
break;
case OverlapEnd:
/* The bit we're subtracting (*i) overlaps the end of the bit of the result (*j),
* so we keep only the part of of (*j) from before the start of (*i)
*/
assert (j->from < i->from);
new_result.add (Range<T> (j->from, i->from - 1));
break;
case OverlapExternal:
/* total overlap of the bit we're subtracting with the result bit, so the
result bit is completely removed; do nothing */
break;
}
}
new_result.coalesce ();
result = new_result;
}
return result;
}
}
#endif

View file

@ -49,14 +49,14 @@ template<typename Time> class Event;
*/
class /*LIBEVORAL_API*/ ControlIterator {
public:
ControlIterator(boost::shared_ptr<const ControlList> al, double ax, double ay)
ControlIterator(boost::shared_ptr<const ControlList> al, Temporal::timepos_t const & ax, double ay)
: list(al)
, x(ax)
, y(ay)
{}
boost::shared_ptr<const ControlList> list;
double x;
Temporal::timepos_t x;
double y;
};
@ -151,7 +151,7 @@ public:
typedef const Note<Time>* value_type;
inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
const boost::shared_ptr< const Note<Time> > b) const {
return a->end_time().to_double() > b->end_time().to_double();
return a->end_time() > b->end_time();
}
};
@ -216,8 +216,6 @@ public:
inline PatchChanges& patch_changes () { return _patch_changes; }
inline const PatchChanges& patch_changes () const { return _patch_changes; }
void dump (std::ostream&) const;
private:
typedef std::priority_queue<NotePtr, std::deque<NotePtr>, LaterNoteEndComparator> ActiveNotes;
public:
@ -229,12 +227,12 @@ public:
const_iterator(const Sequence<Time>& seq,
Time t,
bool force_discrete,
const std::set<Evoral::Parameter>& filtered,
const std::set<WeakNotePtr>* active_notes=NULL);
std::set<Evoral::Parameter> const & filtered,
std::set<WeakNotePtr> const* active_notes = 0);
inline bool valid() const { return !_is_end && _event; }
void invalidate(std::set<WeakNotePtr>* notes);
void invalidate (bool preserve_notes);
const Event<Time>& operator*() const { return *_event; }
const boost::shared_ptr< const Event<Time> > operator->() const { return _event; }
@ -246,6 +244,8 @@ public:
const_iterator& operator=(const const_iterator& other);
void get_active_notes (std::set<WeakNotePtr>&) const;
private:
friend class Sequence<Time>;
@ -277,12 +277,14 @@ public:
Time t = Time(),
bool force_discrete = false,
const std::set<Evoral::Parameter>& f = std::set<Evoral::Parameter>(),
const std::set<WeakNotePtr>* active_notes = NULL) const {
std::set<WeakNotePtr> const * active_notes = 0) const {
return const_iterator (*this, t, force_discrete, f, active_notes);
}
const const_iterator& end() const { return _end_iter; }
void dump (std::ostream&, const_iterator x, uint32_t limit = 0) const;
// CONST iterator implementations (x3)
typename Notes::const_iterator note_lower_bound (Time t) const;
typename PatchChanges::const_iterator patch_change_lower_bound (Time t) const;
@ -378,4 +380,3 @@ template<typename Time> /*LIBEVORAL_API*/ std::ostream& operator<<(std::ostream&
#endif // EVORAL_SEQUENCE_HPP

View file

@ -1,81 +0,0 @@
/*
* Copyright (C) 2009-2014 David Robillard <d@drobilla.net>
* Copyright (C) 2010-2012 Carl Hetherington <carl@carlh.net>
* Copyright (C) 2011-2014 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.
*/
#ifndef EVORAL_TIME_CONVERTER_HPP
#define EVORAL_TIME_CONVERTER_HPP
#include "evoral/visibility.h"
namespace Evoral {
/** A bidirectional converter between two different time units.
*
* Think of the conversion method names as if they are written in-between
* the two template parameters (i.e. "A <name> B").
*
* _origin_b should be the origin for conversion in the units of B.
* That is, there is some point in time _origin_b, such that:
*
* to() converts a time _origin_b + a into an offset from _origin_b in units of B.
* from() converts a time _origin_b + b into an offset from _origin_b in units of A.
*/
template<typename A, typename B>
class LIBEVORAL_TEMPLATE_API TimeConverter {
public:
TimeConverter () : _origin_b (0) {}
TimeConverter (B ob) : _origin_b (ob) {}
virtual ~TimeConverter();
/** Convert A time to B time (A to B) */
virtual B to(A a) const = 0;
/** Convert B time to A time (A from B) */
virtual A from(B b) const = 0;
B origin_b () const {
return _origin_b;
}
void set_origin_b (B o) {
_origin_b = o;
}
protected:
B _origin_b;
};
/** A stub TimeConverter that simple statically casts between types.
* _origin_b has no bearing here, as there is no time conversion
* going on.
*/
template<typename A, typename B>
class LIBEVORAL_TEMPLATE_API IdentityConverter : public TimeConverter<A,B> {
public:
IdentityConverter() {}
B to(A a) const;
A from(B b) const;
};
} // namespace Evoral
#endif // EVORAL_TIME_CONVERTER_HPP

View file

@ -1,5 +1,5 @@
#include "RangeTest.h"
#include "evoral/Range.h"
#include "temporal/range.h"
#include <stdlib.h>
CPPUNIT_TEST_SUITE_REGISTRATION (RangeTest);

View file

@ -95,7 +95,6 @@ def build(bld):
Note.cc
SMF.cc
Sequence.cc
TimeConverter.cc
debug.cc
'''