diff options
author | David Robillard <d@drobilla.net> | 2007-08-31 05:02:45 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2007-08-31 05:02:45 +0000 |
commit | 51c0f6c442e5507754d5bac68550b1659dcf3a04 (patch) | |
tree | c3829a5b22fcc9730ab4514ff9b167554348e923 /libs | |
parent | 056b2a59d5cb28042926dab61f56e49917c8eec4 (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.h | 2 | ||||
-rw-r--r-- | libs/ardour/ardour/automation_event.h | 7 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_event.h | 23 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_model.h | 35 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_ring_buffer.h | 2 | ||||
-rw-r--r-- | libs/ardour/automation_event.cc | 124 | ||||
-rw-r--r-- | libs/ardour/midi_buffer.cc | 6 | ||||
-rw-r--r-- | libs/ardour/midi_model.cc | 180 | ||||
-rw-r--r-- | libs/ardour/midi_track.cc | 6 | ||||
-rw-r--r-- | libs/ardour/session.cc | 2 |
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())) { |