mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 23:05:04 +01:00
changes to compile against libtemporal and use of timepos_t/timecnt_t
This commit is contained in:
parent
e111123b54
commit
6b09642406
13 changed files with 460 additions and 722 deletions
|
|
@ -41,10 +41,10 @@ Control::Control(const Parameter& parameter,
|
||||||
/** Get the currently effective value (ie the one that corresponds to current output)
|
/** Get the currently effective value (ie the one that corresponds to current output)
|
||||||
*/
|
*/
|
||||||
double
|
double
|
||||||
Control::get_double (bool from_list, double frame) const
|
Control::get_double (bool from_list, Temporal::timepos_t when) const
|
||||||
{
|
{
|
||||||
if (from_list) {
|
if (from_list) {
|
||||||
return _list->eval(frame);
|
return _list->eval (when);
|
||||||
} else {
|
} else {
|
||||||
return _user_value;
|
return _user_value;
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +52,7 @@ Control::get_double (bool from_list, double frame) const
|
||||||
|
|
||||||
|
|
||||||
void
|
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;
|
_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)) {
|
if (to_list && (!_list->in_write_pass() || _list->descriptor().toggled)) {
|
||||||
_list->add (frame, value, false);
|
_list->add (when, value, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
#define isnan_local std::isnan
|
#define isnan_local std::isnan
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define GUARD_POINT_DELTA 64
|
#define GUARD_POINT_DELTA Temporal::timecnt_t::from_samples (64)
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
@ -48,6 +48,8 @@
|
||||||
|
|
||||||
#include "pbd/control_math.h"
|
#include "pbd/control_math.h"
|
||||||
#include "pbd/compose.h"
|
#include "pbd/compose.h"
|
||||||
|
#include "pbd/error.h"
|
||||||
|
#include "pbd/i18n.h"
|
||||||
#include "pbd/debug.h"
|
#include "pbd/debug.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
@ -60,10 +62,11 @@ inline bool event_time_less_than (ControlEvent* a, ControlEvent* b)
|
||||||
return a->when < b->when;
|
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)
|
: _parameter(id)
|
||||||
, _desc(desc)
|
, _desc(desc)
|
||||||
, _interpolation (default_interpolation ())
|
, _interpolation (default_interpolation ())
|
||||||
|
, _time_style (ts)
|
||||||
, _curve(0)
|
, _curve(0)
|
||||||
{
|
{
|
||||||
_frozen = 0;
|
_frozen = 0;
|
||||||
|
|
@ -85,6 +88,7 @@ ControlList::ControlList (const ControlList& other)
|
||||||
: _parameter(other._parameter)
|
: _parameter(other._parameter)
|
||||||
, _desc(other._desc)
|
, _desc(other._desc)
|
||||||
, _interpolation(other._interpolation)
|
, _interpolation(other._interpolation)
|
||||||
|
, _time_style (other._time_style)
|
||||||
, _curve(0)
|
, _curve(0)
|
||||||
{
|
{
|
||||||
_frozen = 0;
|
_frozen = 0;
|
||||||
|
|
@ -103,10 +107,11 @@ ControlList::ControlList (const ControlList& other)
|
||||||
copy_events (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)
|
: _parameter(other._parameter)
|
||||||
, _desc(other._desc)
|
, _desc(other._desc)
|
||||||
, _interpolation(other._interpolation)
|
, _interpolation(other._interpolation)
|
||||||
|
, _time_style (other._time_style)
|
||||||
, _curve(0)
|
, _curve(0)
|
||||||
{
|
{
|
||||||
_frozen = 0;
|
_frozen = 0;
|
||||||
|
|
@ -145,9 +150,9 @@ ControlList::~ControlList()
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<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
|
bool
|
||||||
|
|
@ -251,21 +256,24 @@ ControlList::clear ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ControlList::x_scale (double factor)
|
ControlList::x_scale (Temporal::ratio_t const & factor)
|
||||||
{
|
{
|
||||||
Glib::Threads::RWLock::WriterLock lm (_lock);
|
Glib::Threads::RWLock::WriterLock lm (_lock);
|
||||||
_x_scale (factor);
|
_x_scale (factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ControlList::extend_to (double when)
|
ControlList::extend_to (Temporal::timepos_t const & end)
|
||||||
{
|
{
|
||||||
Glib::Threads::RWLock::WriterLock lm (_lock);
|
Glib::Threads::RWLock::WriterLock lm (_lock);
|
||||||
if (_events.empty() || _events.back()->when == when) {
|
|
||||||
|
if (_events.empty() || _events.back()->when == end) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
double factor = when / _events.back()->when;
|
|
||||||
|
Temporal::ratio_t factor (end.val(), _events.back()->when.val());
|
||||||
_x_scale (factor);
|
_x_scale (factor);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -330,10 +338,10 @@ ControlList::list_merge (ControlList const& other, boost::function<double(double
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ControlList::_x_scale (double factor)
|
ControlList::_x_scale (Temporal::ratio_t const & factor)
|
||||||
{
|
{
|
||||||
for (iterator i = _events.begin(); i != _events.end(); ++i) {
|
for (iterator i = _events.begin(); i != _events.end(); ++i) {
|
||||||
(*i)->when *= factor;
|
(*i)->when = (*i)->when.operator* (factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_dirty ();
|
mark_dirty ();
|
||||||
|
|
@ -377,9 +385,13 @@ ControlList::thin (double thinning_factor)
|
||||||
/* compute the area of the triangle formed by 3 points
|
/* compute the area of the triangle formed by 3 points
|
||||||
*/
|
*/
|
||||||
|
|
||||||
double area = fabs ((prevprev->when * (prev->value - cur->value)) +
|
const double ppw = prevprev->when.val();
|
||||||
(prev->when * (cur->value - prevprev->value)) +
|
const double pw = prev->when.val();
|
||||||
(cur->when * (prevprev->value - prev->value)));
|
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) {
|
if (area < thinning_factor) {
|
||||||
iterator tmp = pprev;
|
iterator tmp = pprev;
|
||||||
|
|
@ -415,11 +427,11 @@ ControlList::thin (double thinning_factor)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
Glib::Threads::RWLock::WriterLock lm (_lock);
|
||||||
/* to be used only for loading pre-sorted data from saved state */
|
/* 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 ();
|
mark_dirty ();
|
||||||
if (_frozen) {
|
if (_frozen) {
|
||||||
|
|
@ -459,9 +471,10 @@ ControlList::unlocked_remove_duplicates ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ControlList::start_write_pass (double when)
|
ControlList::start_write_pass (Temporal::timepos_t const & time)
|
||||||
{
|
{
|
||||||
Glib::Threads::RWLock::WriterLock lm (_lock);
|
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));
|
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 (_in_write_pass && !new_write_pass) {
|
||||||
#if 1
|
#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
|
#else
|
||||||
const ControlEvent cp (when, 0.0);
|
const ControlEvent cp (when, 0.0);
|
||||||
most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
|
most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
|
||||||
|
|
@ -490,7 +503,7 @@ ControlList::start_write_pass (double when)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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");
|
DEBUG_TRACE (DEBUG::ControlList, "write pass finished\n");
|
||||||
|
|
||||||
|
|
@ -503,7 +516,7 @@ ControlList::write_pass_finished (double /*when*/, double thinning_factor)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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));
|
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) {
|
if (yn && add_point) {
|
||||||
Glib::Threads::RWLock::WriterLock lm (_lock);
|
Glib::Threads::RWLock::WriterLock lm (_lock);
|
||||||
add_guard_point (when, 0);
|
add_guard_point (when, std::numeric_limits<Temporal::timecnt_t>::min());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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
|
// caller needs to hold writer-lock
|
||||||
if (offset < 0 && when < offset) {
|
|
||||||
|
if (offset.negative() && when < offset) {
|
||||||
return;
|
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 */
|
/* check if there are points between when + offset .. when */
|
||||||
ControlEvent cp (when + offset, 0.0);
|
ControlEvent cp (when + offset, 0.0);
|
||||||
iterator s;
|
iterator s;
|
||||||
|
|
@ -533,7 +551,7 @@ ControlList::add_guard_point (double when, double offset)
|
||||||
cp.when = when;
|
cp.when = when;
|
||||||
e = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
|
e = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
|
||||||
if (s != e) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -601,11 +619,12 @@ ControlList::in_write_pass () const
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
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 */
|
/* this is for making changes from a graphical line editor */
|
||||||
{
|
{
|
||||||
Glib::Threads::RWLock::WriterLock lm (_lock);
|
Glib::Threads::RWLock::WriterLock lm (_lock);
|
||||||
|
Temporal::timepos_t when = time;
|
||||||
|
|
||||||
ControlEvent cp (when, 0.0f);
|
ControlEvent cp (when, 0.0f);
|
||||||
iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
|
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) {
|
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));
|
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
|
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
|
// caller needs to hold writer-lock
|
||||||
if (most_recent_insert_iterator != _events.end()) {
|
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
|
/* 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
|
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
|
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. */
|
/** If we would just be adding to a straight line, move the previous point instead. */
|
||||||
bool
|
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
|
// caller needs to hold writer-lock
|
||||||
if (_events.empty()) {
|
if (_events.empty()) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -702,8 +724,10 @@ ControlList::maybe_insert_straight_line (double when, double value)
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlList::iterator
|
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
|
// caller needs to hold writer-lock
|
||||||
while (iter != _events.end()) {
|
while (iter != _events.end()) {
|
||||||
if ((*iter)->when < when) {
|
if ((*iter)->when < when) {
|
||||||
|
|
@ -723,8 +747,10 @@ ControlList::erase_from_iterator_to (iterator iter, double when)
|
||||||
* control surface (GUI, MIDI, OSC etc)
|
* control surface (GUI, MIDI, OSC etc)
|
||||||
*/
|
*/
|
||||||
void
|
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 */
|
/* clamp new value to allowed range */
|
||||||
value = std::min ((double)_desc.upper, std::max ((double)_desc.lower, value));
|
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 (when >= 1) {
|
||||||
if (_desc.toggled) {
|
if (_desc.toggled) {
|
||||||
const double opp_val = ((value >= 0.5) ? 1.0 : 0.0);
|
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));
|
DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added toggled value %2 at zero\n", this, opp_val));
|
||||||
|
|
||||||
} else {
|
} 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));
|
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 */
|
/* first write in a write pass: add guard point if requested */
|
||||||
|
|
||||||
if (with_guards) {
|
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;
|
did_write_during_pass = true;
|
||||||
} else {
|
} else {
|
||||||
/* not adding a guard, but we need to set iterator appropriately */
|
/* 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 */
|
/** Erase the first event which matches the given time and value */
|
||||||
void
|
void
|
||||||
ControlList::erase (double when, double value)
|
ControlList::erase (Temporal::timepos_t const & time, double value)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
Glib::Threads::RWLock::WriterLock lm (_lock);
|
Glib::Threads::RWLock::WriterLock lm (_lock);
|
||||||
|
Temporal::timepos_t when = time;
|
||||||
|
|
||||||
iterator i = begin ();
|
iterator i = begin ();
|
||||||
while (i != end() && ((*i)->when != when || (*i)->value != value)) {
|
while (i != end() && ((*i)->when != when || (*i)->value != value)) {
|
||||||
|
|
@ -928,12 +955,13 @@ ControlList::erase (double when, double value)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ControlList::erase_range (double start, double endt)
|
ControlList::erase_range (Temporal::timepos_t const & start, Temporal::timepos_t const & endt)
|
||||||
{
|
{
|
||||||
bool erased = false;
|
bool erased = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
Glib::Threads::RWLock::WriterLock lm (_lock);
|
Glib::Threads::RWLock::WriterLock lm (_lock);
|
||||||
|
|
||||||
erased = erase_range_internal (start, endt, _events);
|
erased = erase_range_internal (start, endt, _events);
|
||||||
|
|
||||||
if (erased) {
|
if (erased) {
|
||||||
|
|
@ -947,14 +975,32 @@ ControlList::erase_range (double start, double endt)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
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;
|
bool erased = false;
|
||||||
ControlEvent cp (start, 0.0f);
|
|
||||||
iterator s;
|
iterator s;
|
||||||
iterator e;
|
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()) {
|
if ((s = lower_bound (events.begin(), events.end(), &cp, time_comparator)) != events.end()) {
|
||||||
|
|
||||||
cp.when = endt;
|
cp.when = endt;
|
||||||
e = upper_bound (events.begin(), events.end(), &cp, time_comparator);
|
e = upper_bound (events.begin(), events.end(), &cp, time_comparator);
|
||||||
events.erase (s, e);
|
events.erase (s, e);
|
||||||
|
|
@ -968,7 +1014,7 @@ ControlList::erase_range_internal (double start, double endt, EventList & events
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ControlList::slide (iterator before, double distance)
|
ControlList::slide (iterator before, Temporal::timecnt_t const & distance)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
Glib::Threads::RWLock::WriterLock lm (_lock);
|
Glib::Threads::RWLock::WriterLock lm (_lock);
|
||||||
|
|
@ -977,8 +1023,10 @@ ControlList::slide (iterator before, double distance)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Temporal::timecnt_t wd = distance;
|
||||||
|
|
||||||
while (before != _events.end()) {
|
while (before != _events.end()) {
|
||||||
(*before)->when += distance;
|
(*before)->when += wd;
|
||||||
++before;
|
++before;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -988,19 +1036,22 @@ ControlList::slide (iterator before, double distance)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
Glib::Threads::RWLock::WriterLock lm (_lock);
|
||||||
double v0, v1;
|
double v0, v1;
|
||||||
if (frames < 0) {
|
|
||||||
|
if (distance.negative()) {
|
||||||
/* Route::shift () with negative shift is used
|
/* Route::shift () with negative shift is used
|
||||||
* for "remove time". The time [pos.. pos-frames] is removed.
|
* for "remove time". The time [pos.. pos-frames] is removed.
|
||||||
* and everyhing after, moved backwards.
|
* and everyhing after, moved backwards.
|
||||||
*/
|
*/
|
||||||
v0 = unlocked_eval (pos);
|
v0 = unlocked_eval (pos);
|
||||||
v1 = unlocked_eval (pos - frames);
|
v1 = unlocked_eval (pos.earlier (distance));
|
||||||
erase_range_internal (pos, pos - frames, _events);
|
erase_range_internal (pos, pos.earlier (distance), _events);
|
||||||
} else {
|
} else {
|
||||||
v0 = v1 = unlocked_eval (pos);
|
v0 = v1 = unlocked_eval (pos);
|
||||||
}
|
}
|
||||||
|
|
@ -1012,23 +1063,23 @@ ControlList::shift (double pos, double frames)
|
||||||
dst_guard_exists = true;
|
dst_guard_exists = true;
|
||||||
}
|
}
|
||||||
if ((*i)->when >= pos) {
|
if ((*i)->when >= pos) {
|
||||||
(*i)->when += frames;
|
(*i)->when += distance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add guard-points to retain shape, if needed */
|
/* add guard-points to retain shape, if needed */
|
||||||
if (frames > 0) {
|
if (distance.positive()) {
|
||||||
ControlEvent cp (pos, 0.0);
|
ControlEvent cp (pos, 0.0);
|
||||||
iterator s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
|
iterator s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
|
||||||
if (s != _events.end ()) {
|
if (s != _events.end ()) {
|
||||||
_events.insert (s, new ControlEvent (pos, v0));
|
_events.insert (s, new ControlEvent (pos, v0));
|
||||||
}
|
}
|
||||||
pos += frames;
|
pos += distance;
|
||||||
} else if (frames < 0 && pos > 0) {
|
} else if (distance.negative() && pos > 0) {
|
||||||
ControlEvent cp (pos - 1, 0.0);
|
ControlEvent cp (pos.decrement(), 0.0);
|
||||||
iterator s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
|
iterator s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
|
||||||
if (s != _events.end ()) {
|
if (s != _events.end ()) {
|
||||||
_events.insert (s, new ControlEvent (pos - 1, v0));
|
_events.insert (s, new ControlEvent (pos.decrement(), v0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!dst_guard_exists) {
|
if (!dst_guard_exists) {
|
||||||
|
|
@ -1044,7 +1095,7 @@ ControlList::shift (double pos, double frames)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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
|
/* note: we assume higher level logic is in place to avoid this
|
||||||
* reordering the time-order of control events in the list. ie. all
|
* 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);
|
Glib::Threads::RWLock::WriterLock lm (_lock);
|
||||||
|
Temporal::timepos_t when = time;
|
||||||
|
|
||||||
(*iter)->when = when;
|
(*iter)->when = when;
|
||||||
(*iter)->value = val;
|
(*iter)->value = val;
|
||||||
|
|
@ -1077,10 +1129,11 @@ ControlList::modify (iterator iter, double when, double val)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<ControlList::iterator,ControlList::iterator>
|
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);
|
Glib::Threads::RWLock::ReaderLock lm (_lock);
|
||||||
iterator i;
|
iterator i;
|
||||||
|
Temporal::timepos_t xval = xtime;
|
||||||
ControlEvent cp (xval, 0.0f);
|
ControlEvent cp (xval, 0.0f);
|
||||||
std::pair<iterator,iterator> ret;
|
std::pair<iterator,iterator> ret;
|
||||||
|
|
||||||
|
|
@ -1140,10 +1193,10 @@ ControlList::thaw ()
|
||||||
void
|
void
|
||||||
ControlList::mark_dirty () const
|
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.first = _events.end();
|
||||||
_lookup_cache.range.second = _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();
|
_search_cache.first = _events.end();
|
||||||
|
|
||||||
if (_curve) {
|
if (_curve) {
|
||||||
|
|
@ -1152,10 +1205,11 @@ ControlList::mark_dirty () const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ControlList::truncate_end (double last_coordinate)
|
ControlList::truncate_end (Temporal::timepos_t const & last_time)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
Glib::Threads::RWLock::WriterLock lm (_lock);
|
Glib::Threads::RWLock::WriterLock lm (_lock);
|
||||||
|
Temporal::timepos_t last_coordinate = last_time;
|
||||||
ControlEvent cp (last_coordinate, 0);
|
ControlEvent cp (last_coordinate, 0);
|
||||||
ControlList::reverse_iterator i;
|
ControlList::reverse_iterator i;
|
||||||
double last_val;
|
double last_val;
|
||||||
|
|
@ -1254,13 +1308,14 @@ ControlList::truncate_end (double last_coordinate)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ControlList::truncate_start (double overall_length)
|
ControlList::truncate_start (Temporal::timecnt_t const & overall)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
Glib::Threads::RWLock::WriterLock lm (_lock);
|
Glib::Threads::RWLock::WriterLock lm (_lock);
|
||||||
iterator i;
|
iterator i;
|
||||||
double first_legal_value;
|
double first_legal_value;
|
||||||
double first_legal_coordinate;
|
Temporal::timepos_t first_legal_coordinate;
|
||||||
|
Temporal::timepos_t overall_length (overall);
|
||||||
|
|
||||||
if (_events.empty()) {
|
if (_events.empty()) {
|
||||||
/* nothing to truncate */
|
/* nothing to truncate */
|
||||||
|
|
@ -1274,7 +1329,7 @@ ControlList::truncate_start (double overall_length)
|
||||||
|
|
||||||
/* growing at front: duplicate first point. shift all others */
|
/* 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;
|
uint32_t np;
|
||||||
|
|
||||||
for (np = 0, i = _events.begin(); i != _events.end(); ++i, ++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) {
|
if (np < 2) {
|
||||||
|
|
||||||
/* less than 2 points: add a new point */
|
/* 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 {
|
} else {
|
||||||
|
|
||||||
|
|
@ -1301,7 +1356,7 @@ ControlList::truncate_start (double overall_length)
|
||||||
_events.front()->when = 0;
|
_events.front()->when = 0;
|
||||||
} else {
|
} else {
|
||||||
/* leave non-flat segment in place, add a new leading point. */
|
/* 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 */
|
/* 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 = unlocked_eval (first_legal_coordinate);
|
||||||
first_legal_value = max ((double)_desc.lower, first_legal_value);
|
first_legal_value = max ((double)_desc.lower, first_legal_value);
|
||||||
first_legal_value = min ((double)_desc.upper, 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) {
|
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 */
|
/* 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 ();
|
unlocked_invalidate_insert_iterator ();
|
||||||
|
|
@ -1354,13 +1409,15 @@ ControlList::truncate_start (double overall_length)
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
ControlList::unlocked_eval (double x) const
|
ControlList::unlocked_eval (Temporal::timepos_t const & xtime) const
|
||||||
{
|
{
|
||||||
pair<EventList::iterator,EventList::iterator> range;
|
pair<EventList::iterator,EventList::iterator> range;
|
||||||
int32_t npoints;
|
int32_t npoints;
|
||||||
double lpos, upos;
|
Temporal::timepos_t lpos, upos;
|
||||||
double lval, uval;
|
double lval, uval;
|
||||||
double fraction;
|
double fraction;
|
||||||
|
double xx;
|
||||||
|
double ll;
|
||||||
|
|
||||||
const_iterator length_check_iter = _events.begin();
|
const_iterator length_check_iter = _events.begin();
|
||||||
for (npoints = 0; npoints < 4; ++npoints, ++length_check_iter) {
|
for (npoints = 0; npoints < 4; ++npoints, ++length_check_iter) {
|
||||||
|
|
@ -1377,9 +1434,9 @@ ControlList::unlocked_eval (double x) const
|
||||||
return _events.front()->value;
|
return _events.front()->value;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
if (x >= _events.back()->when) {
|
if (xtime >= _events.back()->when) {
|
||||||
return _events.back()->value;
|
return _events.back()->value;
|
||||||
} else if (x <= _events.front()->when) {
|
} else if (xtime <= _events.front()->when) {
|
||||||
return _events.front()->value;
|
return _events.front()->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1388,7 +1445,10 @@ ControlList::unlocked_eval (double x) const
|
||||||
upos = _events.back()->when;
|
upos = _events.back()->when;
|
||||||
uval = _events.back()->value;
|
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) {
|
switch (_interpolation) {
|
||||||
case Discrete:
|
case Discrete:
|
||||||
|
|
@ -1405,13 +1465,13 @@ ControlList::unlocked_eval (double x) const
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (x >= _events.back()->when) {
|
if (xtime >= _events.back()->when) {
|
||||||
return _events.back()->value;
|
return _events.back()->value;
|
||||||
} else if (x <= _events.front()->when) {
|
} else if (xtime <= _events.front()->when) {
|
||||||
return _events.front()->value;
|
return _events.front()->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return multipoint_eval (x);
|
return multipoint_eval (xtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
abort(); /*NOTREACHED*/ /* stupid gcc */
|
abort(); /*NOTREACHED*/ /* stupid gcc */
|
||||||
|
|
@ -1419,35 +1479,35 @@ ControlList::unlocked_eval (double x) const
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
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 uval, lval;
|
||||||
double fraction;
|
double fraction;
|
||||||
|
|
||||||
/* "Stepped" lookup (no interpolation) */
|
/* "Stepped" lookup (no interpolation) */
|
||||||
/* FIXME: no cache. significant? */
|
/* FIXME: no cache. significant? */
|
||||||
if (_interpolation == Discrete) {
|
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);
|
EventList::const_iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
|
||||||
|
|
||||||
// shouldn't have made it to multipoint_eval
|
// shouldn't have made it to multipoint_eval
|
||||||
assert(i != _events.end());
|
assert(i != _events.end());
|
||||||
|
|
||||||
if (i == _events.begin() || (*i)->when == x)
|
if (i == _events.begin() || (*i)->when == xtime)
|
||||||
return (*i)->value;
|
return (*i)->value;
|
||||||
else
|
else
|
||||||
return (*(--i))->value;
|
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) */
|
* this was called (or if the lookup cache has been marked "dirty" (left<0) */
|
||||||
if ((_lookup_cache.left < 0) ||
|
if ((_lookup_cache.left == std::numeric_limits<Temporal::timepos_t>::max()) ||
|
||||||
((_lookup_cache.left > x) ||
|
((_lookup_cache.left > xtime) ||
|
||||||
(_lookup_cache.range.first == _events.end()) ||
|
(_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);
|
_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 */
|
/* x does not exist within the list as a control point */
|
||||||
|
|
||||||
_lookup_cache.left = x;
|
_lookup_cache.left = xtime;
|
||||||
|
|
||||||
if (range.first != _events.begin()) {
|
if (range.first != _events.begin()) {
|
||||||
--range.first;
|
--range.first;
|
||||||
|
|
@ -1478,7 +1538,7 @@ ControlList::multipoint_eval (double x) const
|
||||||
upos = (*range.second)->when;
|
upos = (*range.second)->when;
|
||||||
uval = (*range.second)->value;
|
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) {
|
switch (_interpolation) {
|
||||||
case Logarithmic:
|
case Logarithmic:
|
||||||
|
|
@ -1499,20 +1559,22 @@ ControlList::multipoint_eval (double x) const
|
||||||
}
|
}
|
||||||
|
|
||||||
/* x is a control point in the data */
|
/* 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;
|
return (*range.first)->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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()) {
|
if (_events.empty()) {
|
||||||
/* Empty, nothing to cache, move to end. */
|
/* Empty, nothing to cache, move to end. */
|
||||||
_search_cache.first = _events.end();
|
_search_cache.first = _events.end();
|
||||||
_search_cache.left = 0;
|
_search_cache.left = Temporal::timepos_t();
|
||||||
return;
|
return;
|
||||||
} else if ((_search_cache.left < 0) || (_search_cache.left > start)) {
|
} else if ((_search_cache.left == std::numeric_limits<Temporal::timepos_t>::max()) || (_search_cache.left > start)) {
|
||||||
/* Marked dirty (left < 0), or we're too far forward, re-search. */
|
/* Marked dirty (left == max), or we're too far forward, re-search. */
|
||||||
|
|
||||||
const ControlEvent start_point (start, 0);
|
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).
|
* \return true if event is found (and \a x and \a y are valid).
|
||||||
*/
|
*/
|
||||||
bool
|
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);
|
build_search_cache_if_necessary (start);
|
||||||
|
|
||||||
if (_search_cache.first != _events.end()) {
|
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
|
/* Move left of cache to this point
|
||||||
* (Optimize for immediate call this cycle within range) */
|
* (Optimize for immediate call this cycle within range) */
|
||||||
_search_cache.left = x;
|
_search_cache.left = first->when;
|
||||||
++_search_cache.first;
|
++_search_cache.first;
|
||||||
|
|
||||||
assert(x >= start);
|
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).
|
* \return true if event is found (and \a x and \a y are valid).
|
||||||
*/
|
*/
|
||||||
bool
|
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;
|
// 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);
|
return rt_safe_earliest_event_discrete_unlocked (start + min_x_delta, x, y, inclusive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (min_x_delta > 0) {
|
if (min_x_delta > 0) {
|
||||||
/* if there is an event between [start and start + min_x_delta], use it,
|
/* if there is an event between [start and start + min_x_delta], use it,
|
||||||
* otherwise interpolate at start + min_x_delta
|
* 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;
|
y = first->value;
|
||||||
/* Move left of cache to this point
|
/* Move left of cache to this point
|
||||||
* (Optimize for immediate call this cycle within range) */
|
* (Optimize for immediate call this cycle within range) */
|
||||||
_search_cache.left = x;
|
_search_cache.left = first->when;
|
||||||
return true;
|
return true;
|
||||||
} else if (next->when < start || (!inclusive && next->when == start)) {
|
} else if (next->when < start || (!inclusive && next->when == start)) {
|
||||||
/* "Next" is before the start, no points left. */
|
/* "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;
|
y = next->value;
|
||||||
/* Move left of cache to this point
|
/* Move left of cache to this point
|
||||||
* (Optimize for immediate call this cycle within range) */
|
* (Optimize for immediate call this cycle within range) */
|
||||||
_search_cache.left = x;
|
_search_cache.left = next->when;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
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;
|
//cerr << "start y: " << start_y << endl;
|
||||||
|
|
||||||
//y = first->value + (slope * fabs(start - first->when));
|
//y = first->value + (slope * fabs(start - first->when));
|
||||||
y = first->value;
|
y = first->value;
|
||||||
|
|
||||||
if (first->value < next->value) // ramping up
|
if (first->value < next->value) { // ramping up
|
||||||
y = ceil(y);
|
y = ceil(y);
|
||||||
else // ramping down
|
} else { // ramping down
|
||||||
y = floor(y);
|
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;
|
y += 1.0;
|
||||||
else // ramping down
|
} else { // ramping down
|
||||||
y -= 1.0;
|
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
|
#if 0
|
||||||
|
|
@ -1695,20 +1768,21 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, do
|
||||||
|| (y <= first->value && y >= next->value) );
|
|| (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) {
|
if (past_start) {
|
||||||
/* Move left of cache to this point
|
/* Move left of cache to this point
|
||||||
* (Optimize for immediate call this cycle within range) */
|
* (Optimize for immediate call this cycle within range) */
|
||||||
_search_cache.left = x;
|
_search_cache.left = x;
|
||||||
assert(inclusive ? x >= start : x > start);
|
assert(inclusive ? x >= start_time : x > start_time);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (inclusive) {
|
if (inclusive) {
|
||||||
x = next->when;
|
x = next->when;
|
||||||
|
_search_cache.left = next->when;
|
||||||
} else {
|
} else {
|
||||||
x = start;
|
x = start;
|
||||||
|
_search_cache.left = x;
|
||||||
}
|
}
|
||||||
_search_cache.left = x;
|
|
||||||
return true;
|
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.
|
* @param op 0 = cut, 1 = copy, 2 = clear.
|
||||||
*/
|
*/
|
||||||
boost::shared_ptr<ControlList>
|
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;
|
iterator s, e;
|
||||||
|
Temporal::timepos_t start = start_time;
|
||||||
|
Temporal::timepos_t end = end_time;
|
||||||
ControlEvent cp (start, 0.0);
|
ControlEvent cp (start, 0.0);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -1773,7 +1849,7 @@ ControlList::cut_copy_clear (double start, double end, int op)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op != 2) { // ! clear
|
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) {
|
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) {
|
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
|
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>
|
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);
|
return cut_copy_clear (start, end, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<ControlList>
|
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);
|
return cut_copy_clear (start, end, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
cut_copy_clear (start, end, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param pos Position in model coordinates */
|
/** @param pos Position in model coordinates */
|
||||||
bool
|
bool
|
||||||
ControlList::paste (const ControlList& alist, double pos)
|
ControlList::paste (const ControlList& alist, Temporal::timepos_t const & time)
|
||||||
{
|
{
|
||||||
if (alist._events.empty()) {
|
if (alist._events.empty()) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1850,7 +1926,8 @@ ControlList::paste (const ControlList& alist, double pos)
|
||||||
Glib::Threads::RWLock::WriterLock lm (_lock);
|
Glib::Threads::RWLock::WriterLock lm (_lock);
|
||||||
iterator where;
|
iterator where;
|
||||||
iterator prev;
|
iterator prev;
|
||||||
double end = 0;
|
Temporal::timepos_t end;
|
||||||
|
Temporal::timepos_t pos = time;
|
||||||
ControlEvent cp (pos, 0.0);
|
ControlEvent cp (pos, 0.0);
|
||||||
|
|
||||||
where = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
|
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)
|
* @param return true if anything was changed, otherwise false (ie nothing needed changing)
|
||||||
*/
|
*/
|
||||||
bool
|
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);
|
Glib::Threads::RWLock::WriterLock lm (_lock);
|
||||||
|
|
@ -1923,11 +2000,17 @@ ControlList::move_ranges (const list< RangeMove<double> >& movements)
|
||||||
bool things_erased = false;
|
bool things_erased = false;
|
||||||
for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
|
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;
|
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;
|
things_erased = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1940,14 +2023,48 @@ ControlList::move_ranges (const list< RangeMove<double> >& movements)
|
||||||
/* copy the events into the new list */
|
/* copy the events into the new list */
|
||||||
for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
|
for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
|
||||||
iterator j = old_events.begin ();
|
iterator j = old_events.begin ();
|
||||||
const double limit = i->from + i->length;
|
|
||||||
const double dx = i->to - i->from;
|
const Temporal::timepos_t limit = i->from + i->length;
|
||||||
while (j != old_events.end () && (*j)->when <= limit) {
|
const Temporal::timecnt_t dx = i->from.distance (i->to);
|
||||||
if ((*j)->when >= i->from) {
|
|
||||||
|
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);
|
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);
|
_events.push_back (ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
++j;
|
++j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2044,9 +2161,8 @@ ControlList::dump (ostream& o)
|
||||||
/* NOT LOCKED ... for debugging only */
|
/* NOT LOCKED ... for debugging only */
|
||||||
|
|
||||||
for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
|
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
|
} // namespace Evoral
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,20 +62,23 @@ Curve::solve () const
|
||||||
(www.korf.co.uk/spline.pdf) for more details.
|
(www.korf.co.uk/spline.pdf) for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
vector<double> x(npoints);
|
vector<Temporal::timepos_t> x (npoints);
|
||||||
vector<double> y(npoints);
|
vector<double> y(npoints);
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
ControlList::EventList::const_iterator xx;
|
ControlList::EventList::const_iterator xx;
|
||||||
|
|
||||||
for (i = 0, xx = _list.events().begin(); xx != _list.events().end(); ++xx, ++i) {
|
for (i = 0, xx = _list.events().begin(); xx != _list.events().end(); ++xx, ++i) {
|
||||||
x[i] = (double) (*xx)->when;
|
x[i] = (*xx)->when;
|
||||||
y[i] = (double) (*xx)->value;
|
y[i] = (*xx)->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
double lp0, lp1, fpone;
|
double lp0, lp1, fpone;
|
||||||
|
double xd;
|
||||||
|
|
||||||
lp0 = (x[1] - x[0])/(y[1] - y[0]);
|
xd = x[0].distance (x[1]).magnitude();
|
||||||
lp1 = (x[2] - x[1])/(y[2] - y[1]);
|
lp0 = xd/(y[1] - y[0]);
|
||||||
|
xd = x[1].distance (x[2]).magnitude();
|
||||||
|
lp1 = xd/(y[2] - y[1]);
|
||||||
|
|
||||||
if (lp0*lp1 < 0) {
|
if (lp0*lp1 < 0) {
|
||||||
fpone = 0;
|
fpone = 0;
|
||||||
|
|
@ -92,9 +95,12 @@ Curve::solve () const
|
||||||
double ydelta; /* ditto */
|
double ydelta; /* ditto */
|
||||||
double fppL, fppR;
|
double fppL, fppR;
|
||||||
double fpi;
|
double fpi;
|
||||||
|
double xi = x[i].val();
|
||||||
|
double xim1;
|
||||||
|
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
xdelta = x[i] - x[i-1];
|
xim1 = x[i-1].val();
|
||||||
|
xdelta = xi - xim1;
|
||||||
xdelta2 = xdelta * xdelta;
|
xdelta2 = xdelta * xdelta;
|
||||||
ydelta = y[i] - y[i-1];
|
ydelta = y[i] - y[i-1];
|
||||||
}
|
}
|
||||||
|
|
@ -105,7 +111,7 @@ Curve::solve () const
|
||||||
|
|
||||||
/* first segment */
|
/* 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 */
|
/* we don't store coefficients for i = 0 */
|
||||||
|
|
||||||
|
|
@ -121,7 +127,9 @@ Curve::solve () const
|
||||||
|
|
||||||
/* all other segments */
|
/* 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);
|
double slope_after = (xdelta / ydelta);
|
||||||
|
|
||||||
if (slope_after * slope_before < 0.0) {
|
if (slope_after * slope_before < 0.0) {
|
||||||
|
|
@ -145,22 +153,22 @@ Curve::solve () const
|
||||||
double b, c, d;
|
double b, c, d;
|
||||||
|
|
||||||
d = (fppR - fppL) / (6 * xdelta);
|
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 xim12, xim13;
|
||||||
double xi2, xi3;
|
double xi2, xi3;
|
||||||
|
|
||||||
xim12 = x[i-1] * x[i-1]; /* "x[i-1] squared" */
|
xim12 = xim1 * xim1; /* "x[i-1] squared" */
|
||||||
xim13 = xim12 * x[i-1]; /* "x[i-1] cubed" */
|
xim13 = xim12 * xim1; /* "x[i-1] cubed" */
|
||||||
xi2 = x[i] * x[i]; /* "x[i] squared" */
|
xi2 = xi * xi; /* "x[i] squared" */
|
||||||
xi3 = xi2 * x[i]; /* "x[i] cubed" */
|
xi3 = xi2 * xi; /* "x[i] cubed" */
|
||||||
|
|
||||||
b = (ydelta - (c * (xi2 - xim12)) - (d * (xi3 - xim13))) / xdelta;
|
b = (ydelta - (c * (xi2 - xim12)) - (d * (xi3 - xim13))) / xdelta;
|
||||||
|
|
||||||
/* store */
|
/* store */
|
||||||
|
|
||||||
(*xx)->create_coeffs();
|
(*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[1] = b;
|
||||||
(*xx)->coeff[2] = c;
|
(*xx)->coeff[2] = c;
|
||||||
(*xx)->coeff[3] = d;
|
(*xx)->coeff[3] = d;
|
||||||
|
|
@ -174,7 +182,7 @@ Curve::solve () const
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
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);
|
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
|
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());
|
Glib::Threads::RWLock::ReaderLock lm(_list.lock());
|
||||||
_get_vector (x0, x1, vec, veclen);
|
_get_vector (x0, x1, vec, veclen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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 i;
|
||||||
int32_t original_veclen;
|
int32_t original_veclen;
|
||||||
int32_t npoints;
|
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 */
|
/* events is now known not to be empty */
|
||||||
|
|
||||||
max_x = _list.events().back()->when;
|
max_x = _list.events().back()->when.val();
|
||||||
min_x = _list.events().front()->when;
|
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 */
|
/* totally past the end - just fill the entire array with the final value */
|
||||||
for (int32_t i = 0; i < veclen; ++i) {
|
for (int32_t i = 0; i < veclen; ++i) {
|
||||||
vec[i] = _list.events().back()->value;
|
vec[i] = _list.events().back()->value;
|
||||||
|
|
@ -233,7 +245,7 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) const
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x1 < min_x) {
|
if (end < min_x) {
|
||||||
/* totally before the first event - fill the entire array with
|
/* totally before the first event - fill the entire array with
|
||||||
* the initial value.
|
* the initial value.
|
||||||
*/
|
*/
|
||||||
|
|
@ -245,13 +257,13 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) const
|
||||||
|
|
||||||
original_veclen = veclen;
|
original_veclen = veclen;
|
||||||
|
|
||||||
if (x0 < min_x) {
|
if (start < min_x) {
|
||||||
|
|
||||||
/* fill some beginning section of the array with the
|
/* fill some beginning section of the array with the
|
||||||
initial (used to be default) value
|
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);
|
int64_t fill_len = (int64_t) floor (veclen * frac);
|
||||||
|
|
||||||
fill_len = min (fill_len, (int64_t)veclen);
|
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;
|
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 */
|
/* 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);
|
int64_t fill_len = (int64_t) floor (original_veclen * frac);
|
||||||
float val;
|
float val;
|
||||||
|
|
||||||
|
|
@ -282,14 +294,14 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) const
|
||||||
veclen -= fill_len;
|
veclen -= fill_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
lx = max (min_x, x0);
|
lx = max (min_x, start);
|
||||||
hx = min (max_x, x1);
|
hx = min (max_x, end);
|
||||||
|
|
||||||
if (npoints == 2) {
|
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 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;
|
const double uval = _list.events().back()->value;
|
||||||
|
|
||||||
/* dx that we are using */
|
/* dx that we are using */
|
||||||
|
|
@ -360,18 +372,19 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen) const
|
||||||
|
|
||||||
rx = lx;
|
rx = lx;
|
||||||
|
|
||||||
double dx = 0;
|
double dx = 0.;
|
||||||
|
|
||||||
if (veclen > 1) {
|
if (veclen > 1) {
|
||||||
dx = (hx - lx) / (veclen - 1);
|
dx = (hx - lx) / (veclen - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < veclen; ++i, rx += dx) {
|
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
|
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;
|
pair<ControlList::EventList::const_iterator,ControlList::EventList::const_iterator> range;
|
||||||
|
|
||||||
|
|
@ -427,8 +440,11 @@ Curve::multipoint_eval (double x) const
|
||||||
return before->value;
|
return before->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
double tdelta = x - before->when;
|
double aw = after->when.val();
|
||||||
double trange = after->when - before->when;
|
double bw = before->when.val();
|
||||||
|
|
||||||
|
double tdelta = x.val() - bw;
|
||||||
|
double trange = aw - bw;
|
||||||
|
|
||||||
switch (_list.interpolation()) {
|
switch (_list.interpolation()) {
|
||||||
case ControlList::Discrete:
|
case ControlList::Discrete:
|
||||||
|
|
@ -440,8 +456,9 @@ Curve::multipoint_eval (double x) const
|
||||||
case ControlList::Curved:
|
case ControlList::Curved:
|
||||||
if (after->coeff) {
|
if (after->coeff) {
|
||||||
ControlEvent* ev = after;
|
ControlEvent* ev = after;
|
||||||
double x2 = x * x;
|
#warning NUTEMPO fixme possible overflow ... multiplyng two position types .. also, units?
|
||||||
return ev->coeff[0] + (ev->coeff[1] * x) + (ev->coeff[2] * x2) + (ev->coeff[3] * x2 * x);
|
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 */
|
/* fallthrough */
|
||||||
case ControlList::Linear:
|
case ControlList::Linear:
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ using namespace PBD;
|
||||||
XXX: This is a hack. The time should probably be expressed in
|
XXX: This is a hack. The time should probably be expressed in
|
||||||
seconds rather than beats, and should be configurable etc. etc.
|
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 {
|
namespace Evoral {
|
||||||
|
|
||||||
|
|
@ -78,11 +78,11 @@ Sequence<Time>::const_iterator::const_iterator()
|
||||||
|
|
||||||
/** @param force_discrete true to force ControlLists to use discrete evaluation, otherwise false to get them to use their configured mode */
|
/** @param force_discrete true to force ControlLists to use discrete evaluation, otherwise false to get them to use their configured mode */
|
||||||
template<typename Time>
|
template<typename Time>
|
||||||
Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>& seq,
|
Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>& seq,
|
||||||
Time t,
|
Time t,
|
||||||
bool force_discrete,
|
bool force_discrete,
|
||||||
const std::set<Evoral::Parameter>& filtered,
|
const std::set<Evoral::Parameter>& filtered,
|
||||||
const std::set<WeakNotePtr>* active_notes)
|
std::set<WeakNotePtr> const * active_notes)
|
||||||
: _seq(&seq)
|
: _seq(&seq)
|
||||||
, _active_patch_change_message (0)
|
, _active_patch_change_message (0)
|
||||||
, _type(NIL)
|
, _type(NIL)
|
||||||
|
|
@ -103,8 +103,7 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>&
|
||||||
|
|
||||||
// Add currently active notes, if given
|
// Add currently active notes, if given
|
||||||
if (active_notes) {
|
if (active_notes) {
|
||||||
for (typename std::set<WeakNotePtr>::const_iterator i = active_notes->begin();
|
for (typename std::set<WeakNotePtr>::const_iterator i = active_notes->begin(); i != active_notes->end(); ++i) {
|
||||||
i != active_notes->end(); ++i) {
|
|
||||||
NotePtr note = i->lock();
|
NotePtr note = i->lock();
|
||||||
if (note && note->time() <= t && note->end_time() > t) {
|
if (note && note->time() <= t && note->end_time() > t) {
|
||||||
_active_notes.push(note);
|
_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
|
// Find first note which begins at or after t
|
||||||
_note_iter = seq.note_lower_bound(t);
|
_note_iter = seq.note_lower_bound(t);
|
||||||
|
|
||||||
// Find first sysex event at or after t
|
// Find first sysex event at or after t
|
||||||
for (typename Sequence<Time>::SysExes::const_iterator i = seq.sysexes().begin();
|
for (typename Sequence<Time>::SysExes::const_iterator i = seq.sysexes().begin();
|
||||||
i != seq.sysexes().end(); ++i) {
|
i != seq.sysexes().end(); ++i) {
|
||||||
|
|
@ -138,7 +136,8 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>&
|
||||||
_control_iters.reserve(seq._controls.size());
|
_control_iters.reserve(seq._controls.size());
|
||||||
bool found = false;
|
bool found = false;
|
||||||
size_t earliest_control_index = 0;
|
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) {
|
for (Controls::const_iterator i = seq._controls.begin(); i != seq._controls.end(); ++i) {
|
||||||
|
|
||||||
if (filtered.find (i->first) != filtered.end()) {
|
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)));
|
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;
|
bool ret;
|
||||||
if (_force_discrete || i->second->list()->interpolation() == ControlList::Discrete) {
|
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 {
|
} 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) {
|
if (!ret) {
|
||||||
DEBUG_TRACE (DEBUG::Sequence, string_compose ("Iterator: CC %1 (size %2) has no events past %3\n",
|
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));
|
i->first.id(), i->second->list()->size(), t));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(x >= 0);
|
|
||||||
|
|
||||||
const ParameterDescriptor& desc = seq.type_map().descriptor(i->first);
|
const ParameterDescriptor& desc = seq.type_map().descriptor(i->first);
|
||||||
if (y < desc.lower || y > desc.upper) {
|
if (y < desc.lower || y > desc.upper) {
|
||||||
cerr << "ERROR: Controller value " << y
|
cerr << "ERROR: Controller value " << y
|
||||||
|
|
@ -170,14 +169,14 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>&
|
||||||
continue;
|
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);
|
_control_iters.push_back(new_iter);
|
||||||
|
|
||||||
// Found a new earliest_control
|
// Found a new earliest_control
|
||||||
if (x < earliest_control_x) {
|
if (xtime < earliest_control_x) {
|
||||||
earliest_control_x = x;
|
earliest_control_x = xtime;
|
||||||
earliest_control_index = _control_iters.size() - 1;
|
earliest_control_index = _control_iters.size() - 1;
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
|
|
@ -215,13 +214,22 @@ Sequence<Time>::const_iterator::const_iterator(const Sequence<Time>&
|
||||||
|
|
||||||
template<typename Time>
|
template<typename Time>
|
||||||
void
|
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()) {
|
/* can't iterate over a std::priority_queue<> such as ActiveNotes */
|
||||||
if (notes) {
|
ActiveNotes copy (_active_notes);
|
||||||
notes->insert(_active_notes.top());
|
while (!copy.empty()) {
|
||||||
}
|
active_notes.insert (copy.top());
|
||||||
_active_notes.pop();
|
copy.pop ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Time>
|
||||||
|
void
|
||||||
|
Sequence<Time>::const_iterator::invalidate(bool preserve_active_notes)
|
||||||
|
{
|
||||||
|
if (!preserve_active_notes) {
|
||||||
|
_active_notes = ActiveNotes();
|
||||||
}
|
}
|
||||||
_type = NIL;
|
_type = NIL;
|
||||||
_is_end = true;
|
_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
|
/* 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. */
|
* or patch-change. Bank-select (CC0, CC32) needs to be sent before the PGM. */
|
||||||
if (_control_iter != _control_iters.end() &&
|
if (_control_iter != _control_iters.end() &&
|
||||||
_control_iter->list && _control_iter->x != DBL_MAX) {
|
_control_iter->list && _control_iter->x != std::numeric_limits<Temporal::timepos_t>::max()) {
|
||||||
if (_type == NIL || _control_iter->x <= earliest_t.to_double()) {
|
if (_type == NIL || _control_iter->x <= earliest_t) {
|
||||||
_type = CONTROL;
|
_type = CONTROL;
|
||||||
earliest_t = Time(_control_iter->x);
|
earliest_t = _control_iter->x.beats();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* .. but prefer to send any Note-off first */
|
/* .. but prefer to send any Note-off first */
|
||||||
if ((!_active_notes.empty())) {
|
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;
|
_type = NOTE_OFF;
|
||||||
earliest_t = _active_notes.top()->end_time();
|
earliest_t = _active_notes.top()->end_time();
|
||||||
}
|
}
|
||||||
|
|
@ -351,9 +359,10 @@ Sequence<Time>::const_iterator::operator++()
|
||||||
<< int(ev.buffer()[0]) << int(ev.buffer()[1]) << int(ev.buffer()[2]) << endl;
|
<< int(ev.buffer()[0]) << int(ev.buffer()[1]) << int(ev.buffer()[2]) << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
double x = 0.0;
|
Temporal::timepos_t x;
|
||||||
double y = 0.0;
|
Temporal::timepos_t xtime;
|
||||||
bool ret = false;
|
double y = 0.0;
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
// Increment past current event
|
// Increment past current event
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
|
|
@ -366,19 +375,18 @@ Sequence<Time>::const_iterator::operator++()
|
||||||
case CONTROL:
|
case CONTROL:
|
||||||
// Increment current controller iterator
|
// Increment current controller iterator
|
||||||
if (_force_discrete || _control_iter->list->interpolation() == ControlList::Discrete) {
|
if (_force_discrete || _control_iter->list->interpolation() == ControlList::Discrete) {
|
||||||
ret = _control_iter->list->rt_safe_earliest_event_discrete_unlocked (
|
ret = _control_iter->list->rt_safe_earliest_event_discrete_unlocked (_control_iter->x, xtime, y, false);
|
||||||
_control_iter->x, x, y, false);
|
|
||||||
} else {
|
} else {
|
||||||
ret = _control_iter->list->rt_safe_earliest_event_linear_unlocked (
|
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);
|
assert(!ret || x > _control_iter->x);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
_control_iter->x = x;
|
_control_iter->x = xtime;
|
||||||
_control_iter->y = y;
|
_control_iter->y = y;
|
||||||
} else {
|
} else {
|
||||||
_control_iter->list.reset();
|
_control_iter->list.reset();
|
||||||
_control_iter->x = DBL_MAX;
|
_control_iter->x = std::numeric_limits<Time>::max();
|
||||||
_control_iter->y = DBL_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.list->parameter().id() <= INT8_MAX);
|
||||||
assert(iter.y <= INT8_MAX);
|
assert(iter.y <= INT8_MAX);
|
||||||
|
|
||||||
ev->set_time(Time(iter.x));
|
ev->set_time(iter.x.beats());
|
||||||
ev->realloc(3);
|
ev->realloc(3);
|
||||||
ev->buffer()[0] = MIDI_CMD_CONTROL + iter.list->parameter().channel();
|
ev->buffer()[0] = MIDI_CMD_CONTROL + iter.list->parameter().channel();
|
||||||
ev->buffer()[1] = (uint8_t)iter.list->parameter().id();
|
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.list->parameter().channel() < 16);
|
||||||
assert(iter.y <= INT8_MAX);
|
assert(iter.y <= INT8_MAX);
|
||||||
|
|
||||||
ev->set_time(Time(iter.x));
|
ev->set_time(iter.x.beats());
|
||||||
ev->realloc(2);
|
ev->realloc(2);
|
||||||
ev->buffer()[0] = MIDI_CMD_PGM_CHANGE + iter.list->parameter().channel();
|
ev->buffer()[0] = MIDI_CMD_PGM_CHANGE + iter.list->parameter().channel();
|
||||||
ev->buffer()[1] = (uint8_t)iter.y;
|
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.list->parameter().channel() < 16);
|
||||||
assert(iter.y < (1<<14));
|
assert(iter.y < (1<<14));
|
||||||
|
|
||||||
ev->set_time(Time(iter.x));
|
ev->set_time(iter.x.beats());
|
||||||
ev->realloc(3);
|
ev->realloc(3);
|
||||||
ev->buffer()[0] = MIDI_CMD_BENDER + iter.list->parameter().channel();
|
ev->buffer()[0] = MIDI_CMD_BENDER + iter.list->parameter().channel();
|
||||||
ev->buffer()[1] = uint16_t(iter.y) & 0x7F; // LSB
|
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.list->parameter().id() <= INT8_MAX);
|
||||||
assert(iter.y <= INT8_MAX);
|
assert(iter.y <= INT8_MAX);
|
||||||
|
|
||||||
ev->set_time(Time(iter.x));
|
ev->set_time(iter.x.beats());
|
||||||
ev->realloc(3);
|
ev->realloc(3);
|
||||||
ev->buffer()[0] = MIDI_CMD_NOTE_PRESSURE + iter.list->parameter().channel();
|
ev->buffer()[0] = MIDI_CMD_NOTE_PRESSURE + iter.list->parameter().channel();
|
||||||
ev->buffer()[1] = (uint8_t)iter.list->parameter().id();
|
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.list->parameter().channel() < 16);
|
||||||
assert(iter.y <= INT8_MAX);
|
assert(iter.y <= INT8_MAX);
|
||||||
|
|
||||||
ev->set_time(Time(iter.x));
|
ev->set_time(iter.x.beats());
|
||||||
ev->realloc(2);
|
ev->realloc(2);
|
||||||
ev->buffer()[0] = MIDI_CMD_CHANNEL_PRESSURE + iter.list->parameter().channel();
|
ev->buffer()[0] = MIDI_CMD_CHANNEL_PRESSURE + iter.list->parameter().channel();
|
||||||
ev->buffer()[1] = (uint8_t)iter.y;
|
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",
|
DEBUG_TRACE (DEBUG::Sequence, string_compose ("%1 %2 @ %3 = %4 # controls: %5\n",
|
||||||
this, _type_map.to_symbol(param), time, value, _controls.size()));
|
this, _type_map.to_symbol(param), time, value, _controls.size()));
|
||||||
boost::shared_ptr<Control> c = control(param, true);
|
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 */
|
/* XXX control events should use IDs */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1411,12 +1419,26 @@ Sequence<Time>::control_list_marked_dirty ()
|
||||||
|
|
||||||
template<typename Time>
|
template<typename Time>
|
||||||
void
|
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;
|
typename Sequence<Time>::const_iterator i = begin();
|
||||||
str << "+++ dump\n";
|
|
||||||
for (i = begin(); i != end(); ++i) {
|
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;
|
str << *i << endl;
|
||||||
|
if (limit) {
|
||||||
|
if (--limit == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
str << "--- dump\n";
|
str << "--- dump\n";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include "pbd/signals.h"
|
#include "pbd/signals.h"
|
||||||
|
|
||||||
|
#include "temporal/timeline.h"
|
||||||
|
|
||||||
#include "evoral/visibility.h"
|
#include "evoral/visibility.h"
|
||||||
#include "evoral/Parameter.h"
|
#include "evoral/Parameter.h"
|
||||||
#include "evoral/ParameterDescriptor.h"
|
#include "evoral/ParameterDescriptor.h"
|
||||||
|
|
@ -52,8 +54,8 @@ public:
|
||||||
|
|
||||||
virtual ~Control() {}
|
virtual ~Control() {}
|
||||||
|
|
||||||
virtual void set_double (double val, double frame=0, bool to_list=false);
|
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, double frame=0) const;
|
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
|
/** Get the latest user-set value
|
||||||
* (which may not equal get_value() when automation is playing back).
|
* (which may not equal get_value() when automation is playing back).
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,12 @@
|
||||||
|
|
||||||
#include "pbd/signals.h"
|
#include "pbd/signals.h"
|
||||||
|
|
||||||
|
#include "temporal/timeline.h"
|
||||||
|
#include "temporal/types.h"
|
||||||
|
#include "temporal/range.h"
|
||||||
|
|
||||||
#include "evoral/visibility.h"
|
#include "evoral/visibility.h"
|
||||||
#include "evoral/Range.h"
|
|
||||||
#include "evoral/Parameter.h"
|
#include "evoral/Parameter.h"
|
||||||
#include "evoral/ParameterDescriptor.h"
|
#include "evoral/ParameterDescriptor.h"
|
||||||
|
|
||||||
|
|
@ -48,7 +52,8 @@ class TypeMap;
|
||||||
*/
|
*/
|
||||||
class LIBEVORAL_API ControlEvent {
|
class LIBEVORAL_API ControlEvent {
|
||||||
public:
|
public:
|
||||||
ControlEvent (double w, double v)
|
|
||||||
|
ControlEvent (Temporal::timepos_t const & w, double v)
|
||||||
: when (w), value (v), coeff (0)
|
: when (w), value (v), coeff (0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
@ -71,11 +76,12 @@ public:
|
||||||
coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
|
coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
double when;
|
Temporal::timepos_t when;
|
||||||
double value;
|
double value;
|
||||||
double* coeff; ///< double[4] allocated by Curve as needed
|
double* coeff; ///< double[4] allocated by Curve as needed
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/** A list (sequence) of time-stamped values for a control
|
/** A list (sequence) of time-stamped values for a control
|
||||||
*/
|
*/
|
||||||
class LIBEVORAL_API ControlList
|
class LIBEVORAL_API ControlList
|
||||||
|
|
@ -87,12 +93,14 @@ public:
|
||||||
typedef EventList::const_iterator const_iterator;
|
typedef EventList::const_iterator const_iterator;
|
||||||
typedef EventList::const_reverse_iterator const_reverse_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&);
|
||||||
ControlList (const ControlList&, double start, double end);
|
|
||||||
virtual ~ControlList();
|
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&);
|
void dump (std::ostream&);
|
||||||
|
|
||||||
|
|
@ -113,26 +121,26 @@ public:
|
||||||
EventList::size_type size() const { return _events.size(); }
|
EventList::size_type size() const { return _events.size(); }
|
||||||
|
|
||||||
/** @return time-stamp of first or last event in the list */
|
/** @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);
|
Glib::Threads::RWLock::ReaderLock lm (_lock);
|
||||||
if (_events.empty()) {
|
if (_events.empty()) {
|
||||||
return 0.0;
|
return std::numeric_limits<Temporal::timepos_t>::min();
|
||||||
}
|
}
|
||||||
return at_start ? _events.front()->when : _events.back()->when;
|
return at_start ? _events.front()->when : _events.back()->when;
|
||||||
}
|
}
|
||||||
|
|
||||||
double length() const {
|
Temporal::timecnt_t length() const {
|
||||||
Glib::Threads::RWLock::ReaderLock lm (_lock);
|
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(); }
|
bool empty() const { return _events.empty(); }
|
||||||
|
|
||||||
/** Remove all events from this list. */
|
/** Remove all events from this list. */
|
||||||
void clear ();
|
void clear ();
|
||||||
void x_scale (double factor);
|
void x_scale (Temporal::ratio_t const &);
|
||||||
bool extend_to (double);
|
bool extend_to (Temporal::timepos_t const & );
|
||||||
void slide (iterator before, double distance);
|
void slide (iterator before, Temporal::timecnt_t const & distance);
|
||||||
void shift (double before, double distance);
|
void shift (Temporal::timepos_t const & before, Temporal::timecnt_t const & distance);
|
||||||
|
|
||||||
void y_transform (boost::function<double(double)> callback);
|
void y_transform (boost::function<double(double)> callback);
|
||||||
void list_merge (ControlList const& other, boost::function<double(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_guards if true, add guard-points
|
||||||
* @param with_initial if true, add an initial point if the list is empty
|
* @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.
|
/** Add an event to this list.
|
||||||
*
|
*
|
||||||
|
|
@ -160,17 +168,17 @@ public:
|
||||||
*
|
*
|
||||||
* @return true if an event was added.
|
* @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 */
|
/* 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);
|
||||||
void erase (iterator, iterator);
|
void erase (iterator, iterator);
|
||||||
void erase (double, double);
|
void erase (Temporal::timepos_t const &, double);
|
||||||
bool move_ranges (std::list< RangeMove<double> > const &);
|
bool move_ranges (std::list<Temporal::RangeMove> const &);
|
||||||
void modify (iterator, double, double);
|
void modify (iterator, Temporal::timepos_t const &, double);
|
||||||
|
|
||||||
/** Thin the number of events in this list.
|
/** Thin the number of events in this list.
|
||||||
*
|
*
|
||||||
|
|
@ -192,29 +200,29 @@ public:
|
||||||
*/
|
*/
|
||||||
void thin (double thinning_factor);
|
void thin (double thinning_factor);
|
||||||
|
|
||||||
boost::shared_ptr<ControlList> cut (double, double);
|
boost::shared_ptr<ControlList> cut (Temporal::timepos_t const &, Temporal::timepos_t const &);
|
||||||
boost::shared_ptr<ControlList> copy (double, double);
|
boost::shared_ptr<ControlList> copy (Temporal::timepos_t const &, Temporal::timepos_t const &);
|
||||||
|
|
||||||
/** Remove all events in the given time range from this list.
|
/** Remove all events in the given time range from this list.
|
||||||
*
|
*
|
||||||
* @param start start of range (inclusive) in audio samples
|
* @param start start of range (inclusive) in audio samples
|
||||||
* @param end end 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.
|
/** Remove all events after the given time from this list.
|
||||||
*
|
*
|
||||||
* @param last_coordinate time in audio samples of the last event to keep
|
* @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.
|
/** 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(); }
|
iterator begin() { return _events.begin(); }
|
||||||
const_iterator begin() const { return _events.begin(); }
|
const_iterator begin() const { return _events.begin(); }
|
||||||
|
|
@ -229,7 +237,7 @@ public:
|
||||||
ControlEvent* front() { return _events.front(); }
|
ControlEvent* front() { return _events.front(); }
|
||||||
const ControlEvent* front() const { 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&)) {
|
template<class T> void apply_to_points (T& obj, void (T::*method)(const ControlList&)) {
|
||||||
Glib::Threads::RWLock::WriterLock lm (_lock);
|
Glib::Threads::RWLock::WriterLock lm (_lock);
|
||||||
|
|
@ -242,7 +250,7 @@ public:
|
||||||
* @param where absolute time in samples
|
* @param where absolute time in samples
|
||||||
* @returns parameter value
|
* @returns parameter value
|
||||||
*/
|
*/
|
||||||
double eval (double where) const {
|
double eval (Temporal::timepos_t const & where) const {
|
||||||
Glib::Threads::RWLock::ReaderLock lm (_lock);
|
Glib::Threads::RWLock::ReaderLock lm (_lock);
|
||||||
return unlocked_eval (where);
|
return unlocked_eval (where);
|
||||||
}
|
}
|
||||||
|
|
@ -254,7 +262,7 @@ public:
|
||||||
* @param ok boolean reference if returned value is valid
|
* @param ok boolean reference if returned value is valid
|
||||||
* @returns parameter value
|
* @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);
|
Glib::Threads::RWLock::ReaderLock lm (_lock, Glib::Threads::TRY_LOCK);
|
||||||
|
|
||||||
|
|
@ -271,15 +279,15 @@ public:
|
||||||
|
|
||||||
/** Lookup cache for eval functions, range contains equivalent values */
|
/** Lookup cache for eval functions, range contains equivalent values */
|
||||||
struct LookupCache {
|
struct LookupCache {
|
||||||
LookupCache() : left(-1) {}
|
LookupCache() : left (std::numeric_limits<Temporal::timepos_t>::max()) {}
|
||||||
double left; /* leftmost x coordinate used when finding "range" */
|
Temporal::timepos_t left; /* leftmost x coordinate used when finding "range" */
|
||||||
std::pair<ControlList::const_iterator,ControlList::const_iterator> range;
|
std::pair<ControlList::const_iterator,ControlList::const_iterator> range;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Lookup cache for point finding, range contains points after left */
|
/** Lookup cache for point finding, range contains points after left */
|
||||||
struct SearchCache {
|
struct SearchCache {
|
||||||
SearchCache () : left(-1) {}
|
SearchCache () : left (std::numeric_limits<Temporal::timepos_t>::max()) {}
|
||||||
double left; /* leftmost x coordinate used when finding "first" */
|
Temporal::timepos_t left; /* leftmost x coordinate used when finding "first" */
|
||||||
ControlList::const_iterator first;
|
ControlList::const_iterator first;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -296,10 +304,10 @@ public:
|
||||||
*
|
*
|
||||||
* FIXME: Should this be private? Curve needs it..
|
* 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_discrete_unlocked (Temporal::timepos_t const & start, Temporal::timepos_t & 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_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 create_curve();
|
||||||
void destroy_curve();
|
void destroy_curve();
|
||||||
|
|
@ -338,9 +346,9 @@ public:
|
||||||
virtual bool touching() const { return false; }
|
virtual bool touching() const { return false; }
|
||||||
virtual bool writing() const { return false; }
|
virtual bool writing() const { return false; }
|
||||||
virtual bool touch_enabled() const { return false; }
|
virtual bool touch_enabled() const { return false; }
|
||||||
void start_write_pass (double when);
|
void start_write_pass (Temporal::timepos_t const &);
|
||||||
void write_pass_finished (double when, double thinning_factor=0.0);
|
void write_pass_finished (Temporal::timepos_t const &, double thinning_factor=0.0);
|
||||||
void set_in_write_pass (bool, bool add_point = false, double when = 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 */
|
/** @return true if transport is running and this list is in write mode */
|
||||||
bool in_write_pass () const;
|
bool in_write_pass () const;
|
||||||
bool in_new_write_pass () { return new_write_pass; }
|
bool in_new_write_pass () { return new_write_pass; }
|
||||||
|
|
@ -355,23 +363,23 @@ public:
|
||||||
|
|
||||||
void invalidate_insert_iterator ();
|
void invalidate_insert_iterator ();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/** Called by unlocked_eval() to handle cases of 3 or more control points. */
|
/** 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);
|
boost::shared_ptr<ControlList> cut_copy_clear (Temporal::timepos_t const &, Temporal::timepos_t const &, int op);
|
||||||
bool erase_range_internal (double start, double end, EventList &);
|
bool erase_range_internal (Temporal::timepos_t const & start, Temporal::timepos_t const & end, EventList &);
|
||||||
|
|
||||||
void maybe_add_insert_guard (double when);
|
void maybe_add_insert_guard (Temporal::timepos_t const & when);
|
||||||
iterator erase_from_iterator_to (iterator iter, double when);
|
iterator erase_from_iterator_to (iterator iter, Temporal::timepos_t const & when);
|
||||||
bool maybe_insert_straight_line (double when, double value);
|
bool maybe_insert_straight_line (Temporal::timepos_t const & when, double value);
|
||||||
|
|
||||||
virtual void maybe_signal_changed ();
|
virtual void maybe_signal_changed ();
|
||||||
|
|
||||||
void _x_scale (double factor);
|
void _x_scale (Temporal::ratio_t const &);
|
||||||
|
|
||||||
mutable LookupCache _lookup_cache;
|
mutable LookupCache _lookup_cache;
|
||||||
mutable SearchCache _search_cache;
|
mutable SearchCache _search_cache;
|
||||||
|
|
@ -385,24 +393,25 @@ protected:
|
||||||
int8_t _frozen;
|
int8_t _frozen;
|
||||||
bool _changed_when_thawed;
|
bool _changed_when_thawed;
|
||||||
bool _sort_pending;
|
bool _sort_pending;
|
||||||
|
Temporal::TimeDomain _time_style;
|
||||||
|
|
||||||
Curve* _curve;
|
Curve* _curve;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
iterator most_recent_insert_iterator;
|
iterator most_recent_insert_iterator;
|
||||||
double insert_position;
|
Temporal::timepos_t insert_position;
|
||||||
bool new_write_pass;
|
bool new_write_pass;
|
||||||
bool did_write_during_pass;
|
bool did_write_during_pass;
|
||||||
bool _in_write_pass;
|
bool _in_write_pass;
|
||||||
|
|
||||||
void unlocked_remove_duplicates ();
|
void unlocked_remove_duplicates ();
|
||||||
void unlocked_invalidate_insert_iterator ();
|
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;
|
bool is_sorted () const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Evoral
|
} // namespace Evoral
|
||||||
|
|
||||||
#endif // EVORAL_CONTROL_LIST_HPP
|
#endif // EVORAL_CONTROL_LIST_HPP
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
|
|
||||||
|
#include "temporal/timeline.h"
|
||||||
|
|
||||||
#include "evoral/visibility.h"
|
#include "evoral/visibility.h"
|
||||||
|
|
||||||
namespace Evoral {
|
namespace Evoral {
|
||||||
|
|
@ -33,17 +35,17 @@ class LIBEVORAL_API Curve : public boost::noncopyable
|
||||||
public:
|
public:
|
||||||
Curve (const ControlList& cl);
|
Curve (const ControlList& cl);
|
||||||
|
|
||||||
bool rt_safe_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 (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;
|
||||||
|
|
||||||
void solve () const;
|
void solve () const;
|
||||||
|
|
||||||
void mark_dirty() const { _dirty = true; }
|
void mark_dirty() const { _dirty = true; }
|
||||||
|
|
||||||
private:
|
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;
|
mutable bool _dirty;
|
||||||
const ControlList& _list;
|
const ControlList& _list;
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -49,14 +49,14 @@ template<typename Time> class Event;
|
||||||
*/
|
*/
|
||||||
class /*LIBEVORAL_API*/ ControlIterator {
|
class /*LIBEVORAL_API*/ ControlIterator {
|
||||||
public:
|
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)
|
: list(al)
|
||||||
, x(ax)
|
, x(ax)
|
||||||
, y(ay)
|
, y(ay)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
boost::shared_ptr<const ControlList> list;
|
boost::shared_ptr<const ControlList> list;
|
||||||
double x;
|
Temporal::timepos_t x;
|
||||||
double y;
|
double y;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -151,7 +151,7 @@ public:
|
||||||
typedef const Note<Time>* value_type;
|
typedef const Note<Time>* value_type;
|
||||||
inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
|
inline bool operator()(const boost::shared_ptr< const Note<Time> > a,
|
||||||
const boost::shared_ptr< const Note<Time> > b) const {
|
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 PatchChanges& patch_changes () { return _patch_changes; }
|
||||||
inline const PatchChanges& patch_changes () const { return _patch_changes; }
|
inline const PatchChanges& patch_changes () const { return _patch_changes; }
|
||||||
|
|
||||||
void dump (std::ostream&) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::priority_queue<NotePtr, std::deque<NotePtr>, LaterNoteEndComparator> ActiveNotes;
|
typedef std::priority_queue<NotePtr, std::deque<NotePtr>, LaterNoteEndComparator> ActiveNotes;
|
||||||
public:
|
public:
|
||||||
|
|
@ -226,15 +224,15 @@ public:
|
||||||
class LIBEVORAL_API const_iterator {
|
class LIBEVORAL_API const_iterator {
|
||||||
public:
|
public:
|
||||||
const_iterator();
|
const_iterator();
|
||||||
const_iterator(const Sequence<Time>& seq,
|
const_iterator(const Sequence<Time>& seq,
|
||||||
Time t,
|
Time t,
|
||||||
bool force_discrete,
|
bool force_discrete,
|
||||||
const std::set<Evoral::Parameter>& filtered,
|
std::set<Evoral::Parameter> const & filtered,
|
||||||
const std::set<WeakNotePtr>* active_notes=NULL);
|
std::set<WeakNotePtr> const* active_notes = 0);
|
||||||
|
|
||||||
inline bool valid() const { return !_is_end && _event; }
|
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 Event<Time>& operator*() const { return *_event; }
|
||||||
const boost::shared_ptr< 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);
|
const_iterator& operator=(const const_iterator& other);
|
||||||
|
|
||||||
|
void get_active_notes (std::set<WeakNotePtr>&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Sequence<Time>;
|
friend class Sequence<Time>;
|
||||||
|
|
||||||
|
|
@ -277,12 +277,14 @@ public:
|
||||||
Time t = Time(),
|
Time t = Time(),
|
||||||
bool force_discrete = false,
|
bool force_discrete = false,
|
||||||
const std::set<Evoral::Parameter>& f = std::set<Evoral::Parameter>(),
|
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);
|
return const_iterator (*this, t, force_discrete, f, active_notes);
|
||||||
}
|
}
|
||||||
|
|
||||||
const const_iterator& end() const { return _end_iter; }
|
const const_iterator& end() const { return _end_iter; }
|
||||||
|
|
||||||
|
void dump (std::ostream&, const_iterator x, uint32_t limit = 0) const;
|
||||||
|
|
||||||
// CONST iterator implementations (x3)
|
// CONST iterator implementations (x3)
|
||||||
typename Notes::const_iterator note_lower_bound (Time t) const;
|
typename Notes::const_iterator note_lower_bound (Time t) const;
|
||||||
typename PatchChanges::const_iterator patch_change_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
|
#endif // EVORAL_SEQUENCE_HPP
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#include "RangeTest.h"
|
#include "RangeTest.h"
|
||||||
#include "evoral/Range.h"
|
#include "temporal/range.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
CPPUNIT_TEST_SUITE_REGISTRATION (RangeTest);
|
CPPUNIT_TEST_SUITE_REGISTRATION (RangeTest);
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,6 @@ def build(bld):
|
||||||
Note.cc
|
Note.cc
|
||||||
SMF.cc
|
SMF.cc
|
||||||
Sequence.cc
|
Sequence.cc
|
||||||
TimeConverter.cc
|
|
||||||
debug.cc
|
debug.cc
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue