summaryrefslogtreecommitdiff
path: root/libs/ardour/automation_event.cc
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-08-31 05:02:45 +0000
committerDavid Robillard <d@drobilla.net>2007-08-31 05:02:45 +0000
commit51c0f6c442e5507754d5bac68550b1659dcf3a04 (patch)
treec3829a5b22fcc9730ab4514ff9b167554348e923 /libs/ardour/automation_event.cc
parent056b2a59d5cb28042926dab61f56e49917c8eec4 (diff)
Reading of MIDI CC from MIDI regions (MidiModel). UI still needs work though..
Various fixes for linear/integer AutomationList interpolation (for CC). git-svn-id: svn://localhost/ardour2/trunk@2359 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour/automation_event.cc')
-rw-r--r--libs/ardour/automation_event.cc124
1 files changed, 83 insertions, 41 deletions
diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc
index 955acf0082..3a80dddc76 100644
--- a/libs/ardour/automation_event.cc
+++ b/libs/ardour/automation_event.cc
@@ -1036,7 +1036,7 @@ AutomationList::build_search_cache_if_necessary(double start, double end) const
const ControlEvent start_point (start, 0);
const ControlEvent end_point (end, 0);
- //cerr << "REBUILD: (" << _search_cache.left << ".." << _search_cache.right << ") -> ("
+ //cerr << "REBUILD: (" << _search_cache.left << ".." << _search_cache.right << ") := ("
// << start << ".." << end << ")" << endl;
_search_cache.range.first = lower_bound (_events.begin(), _events.end(), &start_point, time_comparator);
@@ -1050,31 +1050,50 @@ AutomationList::build_search_cache_if_necessary(double start, double end) const
/** Get the earliest event between \a start and \a end, using the current interpolation style.
*
* If an event is found, \a x and \a y are set to its coordinates.
+ *
+ * \param inclusive Include events with timestamp exactly equal to \a start
+ * \return true if event is found (and \a x and \a y are valid).
+ */
+bool
+AutomationList::rt_safe_earliest_event(double start, double end, double& x, double& y, bool inclusive) const
+{
+ // FIXME: It would be nice if this was unnecessary..
+ Glib::Mutex::Lock lm(_lock, Glib::TRY_LOCK);
+ if (!lm.locked()) {
+ return false;
+ }
+
+ return rt_safe_earliest_event_unlocked(start, end, x, y, inclusive);
+}
+
+
+/** Get the earliest event between \a start and \a end, using the current interpolation style.
+ *
+ * If an event is found, \a x and \a y are set to its coordinates.
+ *
+ * \param inclusive Include events with timestamp exactly equal to \a start
* \return true if event is found (and \a x and \a y are valid).
*/
bool
-AutomationList::rt_safe_earliest_event(double start, double end, double& x, double& y) const
+AutomationList::rt_safe_earliest_event_unlocked(double start, double end, double& x, double& y, bool inclusive) const
{
if (_interpolation == Discrete)
- return rt_safe_earliest_event_discrete(start, end, x, y);
+ return rt_safe_earliest_event_discrete_unlocked(start, end, x, y, inclusive);
else
- return rt_safe_earliest_event_linear(start, end, x, y);
+ return rt_safe_earliest_event_linear_unlocked(start, end, x, y, inclusive);
}
+
/** Get the earliest event between \a start and \a end (Discrete (lack of) interpolation)
*
* If an event is found, \a x and \a y are set to its coordinates.
+ *
+ * \param inclusive Include events with timestamp exactly equal to \a start
* \return true if event is found (and \a x and \a y are valid).
*/
bool
-AutomationList::rt_safe_earliest_event_discrete (double start, double end, double& x, double& y) const
+AutomationList::rt_safe_earliest_event_discrete_unlocked (double start, double end, double& x, double& y, bool inclusive) const
{
- // FIXME: It would be nice if this was unnecessary..
- Glib::Mutex::Lock lm(_lock, Glib::TRY_LOCK);
- if (!lm.locked()) {
- return false;
- }
-
build_search_cache_if_necessary(start, end);
const pair<const_iterator,const_iterator>& range = _search_cache.range;
@@ -1082,8 +1101,10 @@ AutomationList::rt_safe_earliest_event_discrete (double start, double end, doubl
if (range.first != _events.end()) {
const ControlEvent* const first = *range.first;
+ const bool past_start = (inclusive ? first->when >= start : first->when > start);
+
/* Earliest points is in range, return it */
- if (first->when >= start && first->when < end) {
+ if (past_start >= start && first->when < end) {
x = first->when;
y = first->value;
@@ -1098,7 +1119,6 @@ AutomationList::rt_safe_earliest_event_discrete (double start, double end, doubl
return true;
} else {
-
return false;
}
@@ -1111,20 +1131,19 @@ AutomationList::rt_safe_earliest_event_discrete (double start, double end, doubl
/** Get the earliest time the line crosses an integer (Linear interpolation).
*
* If an event is found, \a x and \a y are set to its coordinates.
+ *
+ * \param inclusive Include events with timestamp exactly equal to \a start
* \return true if event is found (and \a x and \a y are valid).
*/
bool
-AutomationList::rt_safe_earliest_event_linear (double start, double end, double& x, double& y) const
+AutomationList::rt_safe_earliest_event_linear_unlocked (double start, double end, double& x, double& y, bool inclusive) const
{
- // FIXME: It would be nice if this was unnecessary..
- Glib::Mutex::Lock lm(_lock, Glib::TRY_LOCK);
- if (!lm.locked()) {
- return false;
- }
+ //cerr << "earliest_event(" << start << ", " << end << ", " << x << ", " << y << ", " << inclusive << endl;
if (_events.size() < 2)
- return false;
+ return rt_safe_earliest_event_discrete_unlocked(start, end, x, y, inclusive);
+ // Hack to avoid infinitely repeating the same event
build_search_cache_if_necessary(start, end);
pair<const_iterator,const_iterator> range = _search_cache.range;
@@ -1138,6 +1157,7 @@ AutomationList::rt_safe_earliest_event_linear (double start, double end, double&
if (range.first == _events.begin() || (*range.first)->when == start) {
first = *range.first;
next = *(++range.first);
+ ++_search_cache.range.first;
/* Step is before first */
} else {
@@ -1147,48 +1167,70 @@ AutomationList::rt_safe_earliest_event_linear (double start, double end, double&
next = *range.first;
}
- if (first->when == start) {
- x = start;
+ if (inclusive && first->when == start) {
+ x = first->when;
y = first->value;
/* Move left of cache to this point
* (Optimize for immediate call this cycle within range) */
_search_cache.left = x;
- ++_search_cache.range.first;
+ //++_search_cache.range.first;
return true;
}
-
- /*cerr << first->value << " @ " << first->when << " ---> "
- << next->value << " @ " << next->when << endl;*/
+
+ if (abs(first->value - next->value) <= 1) {
+ if (next->when <= end && (!inclusive || next->when > start)) {
+ x = next->when;
+ y = next->value;
+ /* Move left of cache to this point
+ * (Optimize for immediate call this cycle within range) */
+ _search_cache.left = x;
+ //++_search_cache.range.first;
+ return true;
+ } else {
+ return false;
+ }
+ }
const double slope = (next->value - first->value) / (double)(next->when - first->when);
-
- const double start_y = first->value + (slope * (start - first->when));
//cerr << "start y: " << start_y << endl;
- if (start_y >= first->value) {
- x = first->when + ((ceil(start_y) - first->value) / (double)slope);
- y = ceil(start_y);
- } else {
- x = first->when + ((floor(start_y) - first->value) / (double)slope);
- y = floor(start_y);
+ //y = first->value + (slope * fabs(start - first->when));
+ y = first->value;
+
+ if (first->value < next->value) // ramping up
+ y = ceil(y);
+ else // ramping down
+ y = floor(y);
+
+ x = first->when + (y - first->value) / (double)slope;
+
+ while ((inclusive && x < start) || x <= start && y != next->value) {
+
+ if (first->value < next->value) // ramping up
+ y += 1.0;
+ else // ramping down
+ y -= 1.0;
+
+ x = first->when + (y - first->value) / (double)slope;
}
- if (x >= start && x < end) {
- //cerr << y << " @ " << x << endl;
+ /*cerr << first->value << " @ " << first->when << " ... "
+ << next->value << " @ " << next->when
+ << " = " << y << " @ " << x << endl;*/
- x = floor(x);
+ assert( (y >= first->value && y <= next->value)
+ || (y <= first->value && y >= next->value) );
+
+ const bool past_start = (inclusive ? x >= start : x > start);
+ if (past_start && x < end) {
/* Move left of cache to this point
* (Optimize for immediate call this cycle within range) */
_search_cache.left = x;
-
- if (x >= next->when)
- ++_search_cache.range.first;
return true;
} else {
- //cerr << "\tNo: " << start_y << ", " << x << endl;
return false;
}