summaryrefslogtreecommitdiff
path: root/libs
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
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')
-rw-r--r--libs/ardour/ardour/automatable.h2
-rw-r--r--libs/ardour/ardour/automation_event.h7
-rw-r--r--libs/ardour/ardour/midi_event.h23
-rw-r--r--libs/ardour/ardour/midi_model.h35
-rw-r--r--libs/ardour/ardour/midi_ring_buffer.h2
-rw-r--r--libs/ardour/automation_event.cc124
-rw-r--r--libs/ardour/midi_buffer.cc6
-rw-r--r--libs/ardour/midi_model.cc180
-rw-r--r--libs/ardour/midi_track.cc6
-rw-r--r--libs/ardour/session.cc2
10 files changed, 300 insertions, 87 deletions
diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h
index 574d7af129..fe47614a1f 100644
--- a/libs/ardour/ardour/automatable.h
+++ b/libs/ardour/ardour/automatable.h
@@ -52,7 +52,7 @@ public:
boost::shared_ptr<AutomationControl> control_factory(boost::shared_ptr<AutomationList> list);
typedef std::map<Parameter,boost::shared_ptr<AutomationControl> > Controls;
- Controls& controls() { return _controls; }
+ Controls& controls() { return _controls; }
const Controls& controls() const { return _controls; }
virtual void add_control(boost::shared_ptr<AutomationControl>);
diff --git a/libs/ardour/ardour/automation_event.h b/libs/ardour/ardour/automation_event.h
index e2a98e50b0..1831f5ca4d 100644
--- a/libs/ardour/ardour/automation_event.h
+++ b/libs/ardour/ardour/automation_event.h
@@ -234,7 +234,8 @@ class AutomationList : public PBD::StatefulDestructible
*/
double unlocked_eval (double x) const;
- bool rt_safe_earliest_event (double start, double end, double& x, double& y) const;
+ bool rt_safe_earliest_event (double start, double end, double& x, double& y, bool start_inclusive=false) const;
+ bool rt_safe_earliest_event_unlocked (double start, double end, double& x, double& y, bool start_inclusive=false) const;
Curve& curve() { return *_curve; }
const Curve& curve() const { return *_curve; }
@@ -256,8 +257,8 @@ class AutomationList : public PBD::StatefulDestructible
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;
+ bool rt_safe_earliest_event_discrete_unlocked (double start, double end, double& x, double& y, bool inclusive) const;
+ bool rt_safe_earliest_event_linear_unlocked (double start, double end, double& x, double& y, bool inclusive) const;
AutomationList* cut_copy_clear (double, double, int op);
diff --git a/libs/ardour/ardour/midi_event.h b/libs/ardour/ardour/midi_event.h
index a04a19cec8..bd16440d05 100644
--- a/libs/ardour/ardour/midi_event.h
+++ b/libs/ardour/ardour/midi_event.h
@@ -96,16 +96,35 @@ struct MidiEvent {
_size = copy._size;
return *this;
}
+
+ inline bool operator==(const MidiEvent& other) const {
+ if (_time != other._time)
+ return false;
+
+ if (_size != other._size)
+ return false;
+
+ if (_buffer == other._buffer)
+ return true;
+
+ for (size_t i=0; i < _size; ++i)
+ if (_buffer[i] != other._buffer[i])
+ return false;
+
+ return true;
+ }
+
+ inline bool operator!=(const MidiEvent& other) const { return ! operator==(other); }
inline bool owns_buffer() const { return _owns_buffer; }
- inline void set_buffer(Byte* buf) {
+ inline void set_buffer(Byte* buf, bool own) {
if (_owns_buffer) {
free(_buffer);
_buffer = NULL;
}
_buffer = buf;
- _owns_buffer = false;
+ _owns_buffer = own;
}
#else
diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h
index 41382b1be3..6337ca8e65 100644
--- a/libs/ardour/ardour/midi_model.h
+++ b/libs/ardour/ardour/midi_model.h
@@ -55,8 +55,8 @@ public:
// This is crap.
void write_lock() { _lock.writer_lock(); _automation_lock.lock(); }
void write_unlock() { _lock.writer_unlock(); _automation_lock.unlock(); }
- void read_lock() const { _lock.reader_lock(); _automation_lock.lock(); }
- void read_unlock() const { _lock.reader_unlock(); _automation_lock.unlock(); }
+ void read_lock() const { _lock.reader_lock(); /*_automation_lock.lock();*/ }
+ void read_unlock() const { _lock.reader_unlock(); /*_automation_lock.unlock();*/ }
void clear() { _notes.clear(); }
@@ -140,33 +140,41 @@ public:
/** Read iterator */
class const_iterator {
public:
- const_iterator(MidiModel& model, double t);
+ const_iterator(const MidiModel& model, double t);
~const_iterator();
- const MidiEvent& operator*() const { return _event; }
+ const MidiEvent& operator*() const { return _event; }
+ const MidiEvent* operator->() const { return &_event; }
const const_iterator& operator++(); // prefix only
+ bool operator==(const const_iterator& other) const;
+ bool operator!=(const const_iterator& other) const { return ! operator==(other); }
private:
- const MidiModel& _model;
+ const MidiModel* _model;
MidiEvent _event;
typedef std::priority_queue<const Note*,std::vector<const Note*>, LaterNoteEndComparator>
ActiveNotes;
mutable ActiveNotes _active_notes;
- Notes::iterator _note_iter;
-
- std::vector<MidiControlIterator> _control_iters;
+ bool _is_end;
+ bool _locked;
+ Notes::const_iterator _note_iter;
+ std::vector<MidiControlIterator> _control_iters;
+ std::vector<MidiControlIterator>::iterator _control_iter;
};
+ const_iterator begin() const { return const_iterator(*this, 0); }
+ const const_iterator& end() const { return _end_iter; }
+
private:
friend class DeltaCommand;
void add_note_unlocked(const Note& note);
void remove_note_unlocked(const Note& note);
friend class const_iterator;
- bool control_to_midi_event(MidiEvent& ev, const MidiControlIterator& iter);
+ bool control_to_midi_event(MidiEvent& ev, const MidiControlIterator& iter) const;
#ifndef NDEBUG
bool is_sorted() const;
@@ -185,14 +193,19 @@ private:
WriteNotes _write_notes;
bool _writing;
bool _edited;
-
+
+ const const_iterator _end_iter;
+
+ mutable nframes_t _next_read;
+ mutable const_iterator _read_iter;
+
// note state for read():
// (TODO: Remove and replace with iterator)
typedef std::priority_queue<const Note*,std::vector<const Note*>,
LaterNoteEndComparator> ActiveNotes;
- mutable ActiveNotes _active_notes;
+ //mutable ActiveNotes _active_notes;
};
} /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h
index 9389f962fc..a0078061ee 100644
--- a/libs/ardour/ardour/midi_ring_buffer.h
+++ b/libs/ardour/ardour/midi_ring_buffer.h
@@ -342,7 +342,7 @@ MidiRingBuffer::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes_t
}
} else {
- printf("MRB - SKIPPING EVENT (with time %f)\n", ev.time());
+ printf("MRB - SKIPPING EVENT AT TIME %f\n", ev.time());
}
}
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;
}
diff --git a/libs/ardour/midi_buffer.cc b/libs/ardour/midi_buffer.cc
index 07ae2abab0..2b47689911 100644
--- a/libs/ardour/midi_buffer.cc
+++ b/libs/ardour/midi_buffer.cc
@@ -119,7 +119,7 @@ MidiBuffer::push_back(const MidiEvent& ev)
memcpy(write_loc, ev.buffer(), ev.size());
_events[_size] = ev;
- _events[_size].set_buffer(write_loc);
+ _events[_size].set_buffer(write_loc, false);
++_size;
//cerr << "MidiBuffer: pushed, size = " << _size << endl;
@@ -148,7 +148,7 @@ MidiBuffer::push_back(const jack_midi_event_t& ev)
memcpy(write_loc, ev.buffer, ev.size);
_events[_size].time() = (double)ev.time;
_events[_size].size() = ev.size;
- _events[_size].set_buffer(write_loc);
+ _events[_size].set_buffer(write_loc, false);
++_size;
//cerr << "MidiBuffer: pushed, size = " << _size << endl;
@@ -178,7 +178,7 @@ MidiBuffer::reserve(double time, size_t size)
_events[_size].time() = time;
_events[_size].size() = size;
- _events[_size].set_buffer(write_loc);
+ _events[_size].set_buffer(write_loc, false);
++_size;
//cerr << "MidiBuffer: reserved, size = " << _size << endl;
diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc
index 4df4cf0b37..765d5f7cad 100644
--- a/libs/ardour/midi_model.cc
+++ b/libs/ardour/midi_model.cc
@@ -22,6 +22,7 @@
#include <iostream>
#include <algorithm>
+#include <stdexcept>
#include <stdint.h>
#include <pbd/enumwriter.h>
#include <ardour/midi_model.h>
@@ -36,50 +37,165 @@ using namespace ARDOUR;
// Read iterator (const_iterator)
-MidiModel::const_iterator::const_iterator(MidiModel& model, double t)
- : _model(model)
+MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
+ : _model(&model)
+ , _is_end( (t == DBL_MAX) || model.empty())
+ , _locked( ! _is_end)
{
- model.read_lock();
+ //cerr << "Created MIDI iterator @ " << t << "(is end: " << _is_end << ")" << endl;
+
+ if (_is_end)
+ return;
+ model.read_lock();
+
_note_iter = model.notes().end();
- for (MidiModel::Notes::iterator i = model.notes().begin(); i != model.notes().end(); ++i) {
+
+ for (MidiModel::Notes::const_iterator i = model.notes().begin(); i != model.notes().end(); ++i) {
if ((*i).time() >= t) {
_note_iter = i;
break;
}
}
-
- MidiControlIterator earliest_control = make_pair(boost::shared_ptr<AutomationList>(), make_pair(DBL_MAX, 0.0));
+
+ MidiControlIterator earliest_control = make_pair(boost::shared_ptr<AutomationList>(),
+ make_pair(DBL_MAX, 0.0));
_control_iters.reserve(model.controls().size());
for (Automatable::Controls::const_iterator i = model.controls().begin();
i != model.controls().end(); ++i) {
+
+ assert(i->first.type() == MidiCCAutomation);
+
double x, y;
- i->second->list()->rt_safe_earliest_event(t, DBL_MAX, x, y);
+ bool ret = i->second->list()->rt_safe_earliest_event_unlocked(t, DBL_MAX, x, y);
+ if (!ret) {
+ cerr << "MIDI Iterator: CC " << i->first.id() << " (size " << i->second->list()->size()
+ << ") has no events past " << t << endl;
+ continue;
+ }
+
+ assert(x >= 0);
+ assert(y >= 0);
+ assert(y <= UINT8_MAX);
const MidiControlIterator new_iter = make_pair(i->second->list(), make_pair(x, y));
+
+ //cerr << "MIDI Iterator: CC " << i->first.id() << " added (" << x << ", " << y << ")" << endl;
+ _control_iters.push_back(new_iter);
- if (x < earliest_control.second.first)
+ if (x < earliest_control.second.first) {
earliest_control = new_iter;
-
- _control_iters.push_back(new_iter);
+ _control_iter = _control_iters.end();
+ --_control_iter;
+ }
}
- if (_note_iter != model.notes().end())
+ if (_note_iter != model.notes().end()) {
_event = MidiEvent(_note_iter->on_event(), false);
+ ++_note_iter;
+ }
- if (earliest_control.first != 0 && earliest_control.second.first < _event.time())
+ if (earliest_control.first && earliest_control.second.first < _event.time())
model.control_to_midi_event(_event, earliest_control);
-
+ else
+ _control_iter = _control_iters.end();
+
+ if (_event.size() == 0) {
+ //cerr << "Created MIDI iterator @ " << t << " is at end." << endl;
+ _is_end = true;
+ _model->read_unlock();
+ _locked = false;
+ //} else {
+ // printf("MIDI Iterator = %X @ %lf\n", _event.type(), _event.time());
+ }
}
MidiModel::const_iterator::~const_iterator()
{
- _model.read_unlock();
+ if (_locked)
+ _model->read_unlock();
+}
+
+
+const MidiModel::const_iterator&
+MidiModel::const_iterator::operator++()
+{
+ if (_is_end)
+ throw std::logic_error("Attempt to iterate past end of MidiModel");
+
+ assert(_event.is_note() || _event.is_cc());
+
+ // Increment past current control event
+ if (_control_iter->first && _event.is_cc()) {
+ double x, y;
+ const bool ret = _control_iter->first->rt_safe_earliest_event_unlocked(
+ _control_iter->second.first, DBL_MAX, x, y, false);
+
+ if (ret) {
+ //cerr << "Incremented " << _control_iter->first->parameter().id() << " to " << x << endl;
+ _control_iter->second.first = x;
+ _control_iter->second.second = y;
+ } else {
+ //cerr << "Hit end of " << _control_iter->first->parameter().id() << endl;
+ _control_iter->first.reset();
+ _control_iter->second.first = DBL_MAX;
+ }
+ }
+
+ // Now find and point at the earliest event
+
+ _control_iter = _control_iters.begin();
+
+ for (std::vector<MidiControlIterator>::iterator i = _control_iters.begin();
+ i != _control_iters.end(); ++i) {
+ if (i->second.first < _control_iter->second.first) {
+ _control_iter = i;
+ }
+ }
+
+ enum Type { NIL, NOTE, CC };
+ Type type = NIL;
+
+ if (_note_iter != _model->notes().end())
+ type = NOTE;
+
+ if (_control_iter != _control_iters.end() && _control_iter->second.first != DBL_MAX)
+ if (_note_iter == _model->notes().end() || _control_iter->second.first < _note_iter->time())
+ type = CC;
+
+ if (type == NOTE) {
+ //cerr << "MIDI Iterator = note" << endl;
+ _event = MidiEvent(_note_iter->on_event(), false);
+ ++_note_iter;
+ } else if (type == CC) {
+ //cerr << "MIDI Iterator = CC" << endl;
+ _model->control_to_midi_event(_event, *_control_iter);
+ } else {
+ //cerr << "MIDI Iterator = NIL" << endl;
+ _is_end = true;
+ _model->read_unlock();
+ _locked = false;
+ }
+
+ return *this;
}
+
+bool
+MidiModel::const_iterator::operator==(const const_iterator& other) const
+{
+ if (_is_end)
+ if (other._is_end)
+ return true;
+ else
+ return false;
+ else
+ return (_event == other._event);
+}
+
// MidiModel
MidiModel::MidiModel(Session& s, size_t size)
@@ -88,7 +204,10 @@ MidiModel::MidiModel(Session& s, size_t size)
, _note_mode(Sustained)
, _writing(false)
, _edited(false)
- , _active_notes(LaterNoteEndComparator())
+ //, _active_notes(LaterNoteEndComparator())
+ , _end_iter(*this, DBL_MAX)
+ , _next_read(UINT32_MAX)
+ , _read_iter(*this, DBL_MAX)
{
}
@@ -98,10 +217,26 @@ MidiModel::MidiModel(Session& s, size_t size)
* \return number of events written to \a dst
*/
size_t
-MidiModel::read (MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes_t stamp_offset) const
+MidiModel::read(MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes_t stamp_offset) const
{
size_t read_events = 0;
+ if (start != _next_read) {
+ _read_iter = const_iterator(*this, (double)start);
+ cerr << "Repositioning iterator from " << _next_read << " to " << start << endl;
+ //} else {
+ // cerr << "Using cached iterator at " << _next_read << endl;
+ }
+
+ _next_read = start + nframes;
+
+ while (_read_iter != end() && _read_iter->time() < start + nframes) {
+ dst.write(_read_iter->time() + stamp_offset, _read_iter->size(), _read_iter->buffer());
+ ++_read_iter;
+ ++read_events;
+ }
+
+#if 0
/* FIXME: cache last lookup value to avoid O(n) search every time */
if (_note_mode == Sustained) {
@@ -161,17 +296,17 @@ MidiModel::read (MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframe
}
}
}
-
+#endif
return read_events;
}
bool
-MidiModel::control_to_midi_event(MidiEvent& ev, const MidiControlIterator& iter)
+MidiModel::control_to_midi_event(MidiEvent& ev, const MidiControlIterator& iter) const
{
if (iter.first->parameter().type() == MidiCCAutomation) {
- if (!ev.owns_buffer() || ev.size() < 3)
- ev = MidiEvent(iter.second.first, 3, (Byte*)malloc(3), true);
+ if (ev.size() < 3)
+ ev.set_buffer((Byte*)malloc(3), true);
assert(iter.first);
assert(iter.first->parameter().id() <= INT8_MAX);
@@ -418,11 +553,10 @@ void
MidiModel::append_cc_unlocked(double time, uint8_t number, uint8_t value)
{
Parameter param(MidiCCAutomation, number);
-
- //cerr << "MidiModel " << this << " add CC " << (int)number << " = " << (int)value
- // << " @ " << time << endl;
boost::shared_ptr<AutomationControl> control = Automatable::control(param, true);
+ //cerr << "MidiModel " << this << "(" << control.get() << ") add CC " << (int)number << " = " << (int)value
+ // << " @ " << time << endl;
control->list()->fast_simple_add(time, (double)value);
}
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index ac40170e72..a6cd964e82 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -589,7 +589,10 @@ MidiTrack::write_controller_messages(MidiBuffer& output_buf, nframes_t start_fra
buf[0] = MIDI_CMD_CONTROL;
MidiEvent ev(0, 3, buf, false);
- // Write controller automation
+ // Write track controller automation
+#if 0
+ // This now lives in MidiModel. Any need for track automation like this?
+ // Relative Velocity?
if (_session.transport_rolling()) {
for (Controls::const_iterator i = _controls.begin(); i != _controls.end(); ++i) {
const boost::shared_ptr<AutomationList> list = (*i).second->list();
@@ -637,6 +640,7 @@ MidiTrack::write_controller_messages(MidiBuffer& output_buf, nframes_t start_fra
output_buf.copy(cc_buf);
}
}
+#endif
// Append immediate events (UI controls)
_immediate_events.read(output_buf, 0, 0, offset + nframes-1); // all stamps = 0
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 3a7e5aeaa8..c638018ab2 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -2151,7 +2151,7 @@ Session::update_route_solo_state ()
shared_ptr<RouteList> r = routes.reader ();
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if ((*i)->soloed()) {
mute = true;
if (dynamic_cast<Track*>((*i).get())) {