13
0

Linear interpolation for MIDI CC (bar controller, line, and actual MIDI output all now obey linear/discrete mode).

git-svn-id: svn://localhost/ardour2/trunk@2125 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard 2007-07-07 07:54:51 +00:00
parent af8acbcc88
commit 01c84bcbba
3 changed files with 132 additions and 19 deletions

View File

@ -238,12 +238,17 @@ class AutomationList : public PBD::StatefulDestructible
InterpolationStyle interpolation() const { return _interpolation; }
void set_interpolation(InterpolationStyle style) { _interpolation = style; }
protected:
private:
/** Called by unlocked_eval() to handle cases of 3 or more control points.
*/
double multipoint_eval (double x) const;
void build_search_cache_if_necessary(double start, double end) const;
bool rt_safe_earliest_event_discrete (double start, double end, double& x, double& y) const;
bool rt_safe_earliest_event_linear (double start, double end, double& x, double& y) const;
AutomationList* cut_copy_clear (double, double, int op);
int deserialize_events (const XMLNode&);

View File

@ -1031,25 +1031,14 @@ AutomationList::multipoint_eval (double x) const
return (*range.first)->value;
}
/** Get the earliest event between \a start and \a end.
*
* If an event is found, \a x and \a y are set to its coordinates.
* \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
void
AutomationList::build_search_cache_if_necessary(double start, double end) const
{
// FIXME: It would be nice if this was unnecessary..
Glib::Mutex::Lock lm(_lock, Glib::TRY_LOCK);
if (!lm.locked()) {
return false;
}
/* Only do the range lookup if x is in a different range than last time
* this was called (or if the search cache has been marked "dirty" (left<0) */
if ((_search_cache.left < 0) ||
((_search_cache.left > start) ||
(_search_cache.right < end))) {
((_search_cache.left > start) ||
(_search_cache.right < end))) {
const ControlEvent start_point (start, 0);
const ControlEvent end_point (end, 0);
@ -1064,7 +1053,38 @@ AutomationList::rt_safe_earliest_event (double start, double end, double& x, dou
_search_cache.left = start;
_search_cache.right = end;
}
}
/** 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.
* \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
{
if (_interpolation == Discrete)
return rt_safe_earliest_event_discrete(start, end, x, y);
else
return rt_safe_earliest_event_linear(start, end, x, y);
}
/** 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.
* \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
{
// 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);
pair<const_iterator,const_iterator> range = _search_cache.range;
if (range.first != _events.end()) {
@ -1096,6 +1116,96 @@ AutomationList::rt_safe_earliest_event (double start, double end, double& x, dou
}
}
/** 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.
* \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
{
// FIXME: It would be nice if this was unnecessary..
Glib::Mutex::Lock lm(_lock, Glib::TRY_LOCK);
if (!lm.locked()) {
return false;
}
if (_events.size() < 2)
return false;
build_search_cache_if_necessary(start, end);
pair<const_iterator,const_iterator> range = _search_cache.range;
if (range.first != _events.end()) {
const ControlEvent* first = NULL;
const ControlEvent* next = NULL;
/* Step is after first */
if (range.first == _events.begin() || (*range.first)->when == start) {
first = *range.first;
next = *(++range.first);
/* Step is before first */
} else {
const_iterator prev = range.first;
--prev;
first = *prev;
next = *range.first;
}
if (first->when == start) {
x = start;
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;
return true;
}
/*cerr << first->value << " @ " << first->when << " ---> "
<< next->value << " @ " << next->when << endl;*/
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);
}
if (x >= start && x < end) {
//cerr << y << " @ " << x << endl;
x = floor(x);
/* 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;
}
/* No points in the future, so no steps (towards them) in the future */
} else {
return false;
}
}
AutomationList*
AutomationList::cut (iterator start, iterator end)
{

View File

@ -166,9 +166,7 @@ MidiTrack::_set_state (const XMLNode& node, bool call_base)
if ((prop = node.property (X_("note-mode"))) != 0) {
_note_mode = NoteMode (string_2_enum (prop->value(), _note_mode));
cerr << "NOTE MODE: " << prop->value() << " -> " << _note_mode << endl;
} else {
cerr << "NO NOTE MODE" << endl;
_note_mode = Note;
}
@ -620,7 +618,7 @@ MidiTrack::write_controller_messages(MidiBuffer& output_buf, nframes_t start_fra
cc_buf.push_back(ev);
start = x;
start = x + 1; // FIXME? maybe?
}
}
}