diff options
author | David Robillard <d@drobilla.net> | 2007-07-07 07:54:51 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2007-07-07 07:54:51 +0000 |
commit | 01c84bcbba1c8ca41079d8304234661d17ecb79a (patch) | |
tree | fd26b5c4c87c8f0bf304611a85cc9388b239d8b5 /libs | |
parent | af8acbcc8879e3e3e158a92417578152627faf3b (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.h | 7 | ||||
-rw-r--r-- | libs/ardour/automation_event.cc | 140 | ||||
-rw-r--r-- | libs/ardour/midi_track.cc | 4 |
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? } } } |