summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-07-07 07:54:51 +0000
committerDavid Robillard <d@drobilla.net>2007-07-07 07:54:51 +0000
commit01c84bcbba1c8ca41079d8304234661d17ecb79a (patch)
treefd26b5c4c87c8f0bf304611a85cc9388b239d8b5 /libs
parentaf8acbcc8879e3e3e158a92417578152627faf3b (diff)
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
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/automation_event.h7
-rw-r--r--libs/ardour/automation_event.cc140
-rw-r--r--libs/ardour/midi_track.cc4
3 files changed, 132 insertions, 19 deletions
diff --git a/libs/ardour/ardour/automation_event.h b/libs/ardour/ardour/automation_event.h
index ac8ce70ff1..6d04d4319a 100644
--- a/libs/ardour/ardour/automation_event.h
+++ b/libs/ardour/ardour/automation_event.h
@@ -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&);
diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc
index a024391980..d5b122cb53 100644
--- a/libs/ardour/automation_event.cc
+++ b/libs/ardour/automation_event.cc
@@ -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)
{
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index f714bf47f9..3d7c429075 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -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?
}
}
}