diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2011-12-26 17:01:31 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2011-12-26 17:01:31 +0000 |
commit | 5558b3cf06b98060438d1e68c8d5d2f4a9c2f8f6 (patch) | |
tree | f760d3daccb5e4fdafe73c013a1c8bc11684a015 /libs/ardour | |
parent | bda0f938fbf640ad60b6f1d3bc7ed18bcb2a0c2b (diff) |
a grab bag of changes correcting and improving the way MIDI note on/off tracking is done. may/should fix a number of problem with spurious note-offs under a variety of circumstances
git-svn-id: svn://localhost/ardour2/branches/3.0@11074 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour')
-rw-r--r-- | libs/ardour/ardour/midi_diskstream.h | 2 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_ring_buffer.h | 2 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_track.h | 2 | ||||
-rw-r--r-- | libs/ardour/ardour/plugin.h | 4 | ||||
-rw-r--r-- | libs/ardour/ardour/plugin_insert.h | 2 | ||||
-rw-r--r-- | libs/ardour/ardour/processor.h | 7 | ||||
-rw-r--r-- | libs/ardour/midi_diskstream.cc | 26 | ||||
-rw-r--r-- | libs/ardour/midi_playlist.cc | 147 | ||||
-rw-r--r-- | libs/ardour/midi_ring_buffer.cc | 7 | ||||
-rw-r--r-- | libs/ardour/midi_state_tracker.cc | 35 | ||||
-rw-r--r-- | libs/ardour/midi_track.cc | 18 | ||||
-rw-r--r-- | libs/ardour/plugin.cc | 27 | ||||
-rw-r--r-- | libs/ardour/plugin_insert.cc | 16 | ||||
-rw-r--r-- | libs/ardour/track.cc | 5 |
14 files changed, 214 insertions, 86 deletions
diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h index 94eb56d9b5..23ae7addb0 100644 --- a/libs/ardour/ardour/midi_diskstream.h +++ b/libs/ardour/ardour/midi_diskstream.h @@ -65,6 +65,8 @@ class MidiDiskstream : public Diskstream void get_playback (MidiBuffer& dst, framecnt_t); void set_record_enabled (bool yn); + + void reset_tracker (); boost::shared_ptr<MidiPlaylist> midi_playlist () { return boost::dynamic_pointer_cast<MidiPlaylist>(_playlist); } diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h index 14934456e1..4b352b3c4d 100644 --- a/libs/ardour/ardour/midi_ring_buffer.h +++ b/libs/ardour/ardour/midi_ring_buffer.h @@ -75,6 +75,8 @@ public: return g_atomic_int_get(&_channel_mask) & 0x0000FFFF; } + void reset_tracker (); + protected: inline bool is_channel_event(uint8_t event_type_byte) { // mask out channel information diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h index 86eb8fd680..6ca48573d5 100644 --- a/libs/ardour/ardour/midi_track.h +++ b/libs/ardour/ardour/midi_track.h @@ -107,6 +107,8 @@ public: PBD::Signal1<void, boost::weak_ptr<MidiSource> > DataRecorded; boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const; + void set_monitoring (MonitorChoice); + void set_input_active (bool); bool input_active () const; PBD::Signal0<void> InputActiveChanged; diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h index 9c073d4a19..0c2bcbdd93 100644 --- a/libs/ardour/ardour/plugin.h +++ b/libs/ardour/ardour/plugin.h @@ -141,6 +141,8 @@ class Plugin : public PBD::StatefulDestructible, public Latent } void realtime_handle_transport_stopped (); + void realtime_locate (); + void monitoring_changed (); struct PresetRecord { PresetRecord () : user (true) {} @@ -257,6 +259,8 @@ private: bool _have_pending_stop_events; PresetRecord _last_preset; bool _parameter_changed_since_last_preset; + + void resolve_midi (); }; PluginPtr find_plugin(ARDOUR::Session&, std::string unique_id, ARDOUR::PluginType); diff --git a/libs/ardour/ardour/plugin_insert.h b/libs/ardour/ardour/plugin_insert.h index b7a89b663f..48ce925d3f 100644 --- a/libs/ardour/ardour/plugin_insert.h +++ b/libs/ardour/ardour/plugin_insert.h @@ -77,6 +77,8 @@ class PluginInsert : public Processor bool is_midi_instrument() const; void realtime_handle_transport_stopped (); + void realtime_locate (); + void monitoring_changed (); struct PluginControl : public AutomationControl { diff --git a/libs/ardour/ardour/processor.h b/libs/ardour/ardour/processor.h index 08fd3ecd8d..fe23d6fdde 100644 --- a/libs/ardour/ardour/processor.h +++ b/libs/ardour/ardour/processor.h @@ -87,6 +87,13 @@ class Processor : public SessionObject, public Automatable, public Latent virtual void realtime_handle_transport_stopped () {} virtual void realtime_locate () {} + /* most processors won't care about this, but plugins that + receive MIDI or similar data from an input source that + may suddenly go "quiet" because of monitoring changes + need to know about it. + */ + virtual void monitoring_changed() {} + /* note: derived classes should implement state(), NOT get_state(), to allow us to merge C++ inheritance and XML lack-of-inheritance reasonably smoothly. diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index c1d391fa4a..e3d7014457 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -737,16 +737,16 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed) start = loop_start + ((start - loop_start) % loop_length); //cerr << "to " << start << endl; } - //cerr << "start is " << start << " loopstart: " << loop_start << " loopend: " << loop_end << endl; + // cerr << "start is " << start << " loopstart: " << loop_start << " loopend: " << loop_end << endl; } while (dur) { /* take any loop into account. we can't read past the end of the loop. */ - if (loc && (loop_end - start < dur)) { + if (loc && (loop_end - start <= dur)) { this_read = loop_end - start; - //cerr << "reloop true: thisread: " << this_read << " dur: " << dur << endl; + // cerr << "reloop true: thisread: " << this_read << " dur: " << dur << endl; reloop = true; } else { reloop = false; @@ -1102,9 +1102,7 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen no_capture_stuff_to_do: - if (_playlist) { - midi_playlist()->clear_note_trackers (); - } + reset_tracker (); } void @@ -1134,6 +1132,10 @@ MidiDiskstream::transport_looped (framepos_t transport_frame) last_recordable_frame = max_framepos; was_recording = true; } + + if (!Config->get_seamless_loop()) { + reset_tracker (); + } } void @@ -1477,3 +1479,15 @@ MidiDiskstream::get_gui_feed_buffer () const b->copy (_gui_feed_buffer); return b; } + +void +MidiDiskstream::reset_tracker () +{ + _playback_buf->reset_tracker (); + + boost::shared_ptr<MidiPlaylist> mp (midi_playlist()); + + if (mp) { + mp->clear_note_trackers (); + } +} diff --git a/libs/ardour/midi_playlist.cc b/libs/ardour/midi_playlist.cc index edadc225b0..39f603a6e9 100644 --- a/libs/ardour/midi_playlist.cc +++ b/libs/ardour/midi_playlist.cc @@ -83,8 +83,16 @@ MidiPlaylist::~MidiPlaylist () } template<typename Time> -struct EventsSortByTime { +struct EventsSortByTimeAndType { bool operator() (Evoral::Event<Time>* a, Evoral::Event<Time>* b) { + if (a->time() == b->time()) { + if (EventTypeMap::instance().type_is_midi (a->event_type()) && EventTypeMap::instance().type_is_midi (b->event_type())) { + /* negate return value since we must return whether + * or not a should sort before b, not b before a + */ + return !MidiBuffer::second_simultaneous_midi_byte_is_first (a->buffer()[0], b->buffer()[0]); + } + } return a->time() < b->time(); } }; @@ -98,59 +106,50 @@ MidiPlaylist::read (Evoral::EventSink<framepos_t>& dst, framepos_t start, framec */ Glib::RecMutex::Lock rm (region_lock); - DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("++++++ %1 .. %2 +++++++++++++++++++++++++++++++++++++++++++++++\n", start, start + dur)); + DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("++++++ %1 .. %2 +++++++ %3 trackers +++++++++++++++++\n", + start, start + dur, _note_trackers.size())); framepos_t end = start + dur - 1; // relevent regions overlapping start <--> end vector< boost::shared_ptr<Region> > regs; + vector< boost::shared_ptr<Region> > ended; typedef pair<MidiStateTracker*,framepos_t> TrackerInfo; vector<TrackerInfo> tracker_info; - uint32_t note_cnt = 0; + NoteTrackers::iterator t; for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { - if ((*i)->coverage (start, end) != OverlapNone) { - regs.push_back(*i); - } else { - NoteTrackers::iterator t = _note_trackers.find ((*i).get()); - if (t != _note_trackers.end()) { - - /* add it the set of trackers we will do note resolution - on, and remove it from the list we are keeping - around, because we don't need it anymore. - - if the end of the region (where we want to theoretically resolve notes) - is outside the current read range, then just do it at the start - of this read range. - */ - - framepos_t resolve_at = (*i)->last_frame(); - if (resolve_at < start || resolve_at >= end) { - resolve_at = start; - } - - tracker_info.push_back (TrackerInfo (t->second, resolve_at)); - DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("time to resolve & remove tracker for %1 @ %2\n", (*i)->name(), resolve_at)); - note_cnt += (t->second->on()); - _note_trackers.erase (t); - } - } - } - if (note_cnt == 0 && !tracker_info.empty()) { - /* trackers to dispose of, but they have no notes in them */ - DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("Clearing %1 empty trackers\n", tracker_info.size())); - for (vector<TrackerInfo>::iterator t = tracker_info.begin(); t != tracker_info.end(); ++t) { - delete (*t).first; + /* in this call to coverage, the return value indicates the + * overlap status of the read range (start...end) WRT to + * the region. + */ + + switch ((*i)->coverage (start, end)) { + case OverlapStart: + case OverlapInternal: + case OverlapExternal: + regs.push_back (*i); + break; + + case OverlapEnd: + /* this region ends within the read range */ + regs.push_back (*i); + ended.push_back (*i); + break; + default: + /* we don't care */ + break; } - tracker_info.clear (); } - if (regs.size() == 1 && tracker_info.empty()) { + if (regs.size() == 1 && + (ended.empty() || (ended.size() == 1 && ended.front() == regs.front()))) { /* just a single region - read directly into dst */ - DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("Single region (%1) read, no out-of-bound region tracking info\n", regs.front()->name())); + DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("Single region (%1) read, ended during this read %2\n", regs.front()->name(), + ended.size())); boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(regs.front()); @@ -172,12 +171,22 @@ MidiPlaylist::read (Evoral::EventSink<framepos_t>& dst, framepos_t start, framec mr->read_at (dst, start, dur, chan_n, _note_mode, tracker); DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\tAFTER: tracker says there are %1 on notes\n", tracker->on())); - if (new_tracker) { - pair<Region*,MidiStateTracker*> newpair; - newpair.first = mr.get(); - newpair.second = tracker; - _note_trackers.insert (newpair); - DEBUG_TRACE (DEBUG::MidiPlaylistIO, "\tadded tracker to trackers\n"); + if (!ended.empty()) { + DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\t%1 ended in this read, resolve notes and delete (%2) tracker\n", + mr->name(), ((new_tracker) ? "new" : "old"))); + tracker->resolve_notes (dst, mr->last_frame()); + delete tracker; + if (!new_tracker) { + _note_trackers.erase (t); + } + } else { + if (new_tracker) { + pair<Region*,MidiStateTracker*> newpair; + newpair.first = mr.get(); + newpair.second = tracker; + _note_trackers.insert (newpair); + DEBUG_TRACE (DEBUG::MidiPlaylistIO, "\tadded tracker to trackers\n"); + } } } @@ -191,23 +200,12 @@ MidiPlaylist::read (Evoral::EventSink<framepos_t>& dst, framepos_t start, framec Evoral::EventList<framepos_t> evlist; - for (vector<TrackerInfo>::iterator t = tracker_info.begin(); t != tracker_info.end(); ++t) { - DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("Resolve %1 notes\n", (*t).first->on())); - (*t).first->resolve_notes (evlist, (*t).second); - delete (*t).first; - } - -#ifndef NDEBUG - DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("After resolution we now have %1 events\n", evlist.size())); - for (Evoral::EventList<framepos_t>::iterator x = evlist.begin(); x != evlist.end(); ++x) { - DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\t%1\n", **x)); - } -#endif - DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("for %1 .. %2 we have %3 to consider\n", start, start+dur-1, regs.size())); for (vector<boost::shared_ptr<Region> >::iterator i = regs.begin(); i != regs.end(); ++i) { + boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(*i); + if (!mr) { continue; } @@ -216,7 +214,6 @@ MidiPlaylist::read (Evoral::EventSink<framepos_t>& dst, framepos_t start, framec MidiStateTracker* tracker; bool new_tracker = false; - DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("Before %1 (%2 .. %3) we now have %4 events\n", mr->name(), mr->position(), mr->last_frame(), evlist.size())); if (t == _note_trackers.end()) { @@ -238,21 +235,39 @@ MidiPlaylist::read (Evoral::EventSink<framepos_t>& dst, framepos_t start, framec } DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\tAFTER: tracker says there are %1 on notes\n", tracker->on())); #endif + if (find (ended.begin(), ended.end(), *i) != ended.end()) { + + /* the region ended within the read range, so + * resolve any dangling notes (i.e. notes whose + * end is beyond the end of the region). + */ + + DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\t%1 ended in this read, resolve notes and delete (%2) tracker\n", + mr->name(), ((new_tracker) ? "new" : "old"))); + + tracker->resolve_notes (evlist, (*i)->last_frame()); + delete tracker; + if (!new_tracker) { + _note_trackers.erase (t); + } - if (new_tracker) { - pair<Region*,MidiStateTracker*> newpair; - newpair.first = mr.get(); - newpair.second = tracker; - _note_trackers.insert (newpair); - DEBUG_TRACE (DEBUG::MidiPlaylistIO, "\tadded tracker to trackers\n"); + } else { + + if (new_tracker) { + pair<Region*,MidiStateTracker*> newpair; + newpair.first = mr.get(); + newpair.second = tracker; + _note_trackers.insert (newpair).first; + DEBUG_TRACE (DEBUG::MidiPlaylistIO, "\tadded tracker to trackers\n"); + } } } if (!evlist.empty()) { /* sort the event list */ - EventsSortByTime<framepos_t> time_cmp; - evlist.sort (time_cmp); + EventsSortByTimeAndType<framepos_t> cmp; + evlist.sort (cmp); #ifndef NDEBUG DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("Final we now have %1 events\n", evlist.size())); diff --git a/libs/ardour/midi_ring_buffer.cc b/libs/ardour/midi_ring_buffer.cc index 34a1bafc76..4ad563eec9 100644 --- a/libs/ardour/midi_ring_buffer.cc +++ b/libs/ardour/midi_ring_buffer.cc @@ -270,5 +270,12 @@ MidiRingBuffer<T>::dump(ostream& str) delete [] buf; } +template<typename T> +void +MidiRingBuffer<T>::reset_tracker () +{ + _tracker.reset (); +} + template class MidiRingBuffer<framepos_t>; diff --git a/libs/ardour/midi_state_tracker.cc b/libs/ardour/midi_state_tracker.cc index d261115ac1..7537ca04d1 100644 --- a/libs/ardour/midi_state_tracker.cc +++ b/libs/ardour/midi_state_tracker.cc @@ -20,6 +20,7 @@ #include <iostream> #include "pbd/compose.h" +#include "pbd/stacktrace.h" #include "ardour/debug.h" #include "ardour/event_type_map.h" @@ -57,15 +58,23 @@ MidiStateTracker::track_note_onoffs (const Evoral::MIDIEvent<MidiBuffer::TimeTyp void MidiStateTracker::add (uint8_t note, uint8_t chn) { + if (_active_notes[note+128 * chn] == 0) { + ++_on; + } ++_active_notes[note + 128 * chn]; - ++_on; - DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("MST @ %1 ON %2/%3 total on %4\n", - this, (int) note, (int) chn, _on)); + + if (_active_notes[note+128 * chn] > 1) { + cerr << this << " note " << (int) note << '/' << (int) chn << " was already on, now at " << (int) _active_notes[note+128*chn] << endl; + } + + DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1 ON %2/%3 voices %5 total on %4\n", + this, (int) note, (int) chn, _on, + (int) _active_notes[note+128 * chn])); } void MidiStateTracker::remove (uint8_t note, uint8_t chn) -{ +{ switch (_active_notes[note + 128 * chn]) { case 0: break; @@ -75,11 +84,12 @@ MidiStateTracker::remove (uint8_t note, uint8_t chn) break; default: --_active_notes [note + 128 * chn]; - break; + break; } - DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("MST @ %1 OFF %2/%3 total on %4\n", - this, (int) note, (int) chn, _on)); + DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1 OFF %2/%3 current voices = %5 total on %4\n", + this, (int) note, (int) chn, _on, + (int) _active_notes[note+128 * chn])); } void @@ -102,9 +112,10 @@ MidiStateTracker::track (const MidiBuffer::iterator &from, const MidiBuffer::ite if (ev.type() == MIDI_CTL_ALL_NOTES_OFF) { cerr << "State tracker sees ALL_NOTES_OFF, silenceing " << sizeof (_active_notes) << endl; memset (_active_notes, 0, sizeof (_active_notes)); + _on = 0; + } else { + track_note_onoffs (ev); } - - track_note_onoffs (ev); } } @@ -123,6 +134,9 @@ MidiStateTracker::resolve_notes (MidiBuffer &dst, framepos_t time) uint8_t buffer[3] = { MIDI_CMD_NOTE_OFF | channel, note, 0 }; Evoral::MIDIEvent<MidiBuffer::TimeType> noteoff (MIDI_CMD_NOTE_OFF, time, 3, buffer, false); + /* note that we do not care about failure from + push_back() ... should we warn someone ? + */ dst.push_back (noteoff); _active_notes[note + 128 * channel]--; DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1: MB-resolved note %2/%3 at %4\n", @@ -150,6 +164,9 @@ MidiStateTracker::resolve_notes (Evoral::EventSink<framepos_t> &dst, framepos_t buf[0] = MIDI_CMD_NOTE_OFF|channel; buf[1] = note; buf[2] = 0; + /* note that we do not care about failure from + write() ... should we warn someone ? + */ dst.write (time, EventTypeMap::instance().midi_event_type (buf[0]), 3, buf); _active_notes[note + 128 * channel]--; DEBUG_TRACE (PBD::DEBUG::MidiTrackers, string_compose ("%1: EVS-resolved note %2/%3 at %4\n", diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index f5743f4992..1b327ae70d 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -109,11 +109,11 @@ MidiTrack::set_diskstream (boost::shared_ptr<Diskstream> ds) { Track::set_diskstream (ds); + midi_diskstream()->reset_tracker (); + _diskstream->set_track (this); _diskstream->set_destructive (_mode == Destructive); - _diskstream->set_record_enabled (false); - //_diskstream->monitor_input (false); _diskstream_data_recorded_connection.disconnect (); boost::shared_ptr<MidiDiskstream> mds = boost::dynamic_pointer_cast<MidiDiskstream> (ds); @@ -391,6 +391,7 @@ void MidiTrack::realtime_locate () { Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); + if (!lm.locked ()) { return; } @@ -398,6 +399,8 @@ MidiTrack::realtime_locate () for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { (*i)->realtime_locate (); } + + midi_diskstream()->reset_tracker (); } void @@ -734,3 +737,14 @@ MidiTrack::act_on_mute () } } +void +MidiTrack::set_monitoring (MonitorChoice mc) +{ + Track::set_monitoring (mc); + + boost::shared_ptr<MidiDiskstream> md (midi_diskstream()); + + if (md) { + md->reset_tracker (); + } +} diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc index 8c8bf248e0..bac014df38 100644 --- a/libs/ardour/plugin.cc +++ b/libs/ardour/plugin.cc @@ -70,6 +70,7 @@ Plugin::Plugin (AudioEngine& e, Session& s) , _have_pending_stop_events (false) , _parameter_changed_since_last_preset (false) { + _pending_stop_events.ensure_buffers (DataType::MIDI, 1, 4096); } Plugin::Plugin (const Plugin& other) @@ -83,12 +84,11 @@ Plugin::Plugin (const Plugin& other) , _have_pending_stop_events (false) , _parameter_changed_since_last_preset (false) { - + _pending_stop_events.ensure_buffers (DataType::MIDI, 1, 4096); } Plugin::~Plugin () { - } void @@ -242,8 +242,10 @@ Plugin::connect_and_run (BufferSet& bufs, if (bufs.count().n_midi() > 0) { /* Track notes that we are sending to the plugin */ + MidiBuffer& b = bufs.get_midi (0); bool looped; + _tracker.track (b.begin(), b.end(), looped); if (_have_pending_stop_events) { @@ -259,11 +261,28 @@ Plugin::connect_and_run (BufferSet& bufs, void Plugin::realtime_handle_transport_stopped () { + resolve_midi (); +} + +void +Plugin::realtime_locate () +{ + resolve_midi (); +} + +void +Plugin::monitoring_changed () +{ + resolve_midi (); +} + +void +Plugin::resolve_midi () +{ /* Create note-offs for any active notes and put them in _pending_stop_events, to be picked up on the next call to connect_and_run (). */ - _pending_stop_events.ensure_buffers (DataType::MIDI, 1, 4096); _pending_stop_events.get_midi(0).clear (); _tracker.resolve_notes (_pending_stop_events.get_midi (0), 0); _have_pending_stop_events = true; @@ -345,3 +364,5 @@ Plugin::set_info (PluginInfoPtr info) { _info = info; } + + diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc index 1d8581af39..728e6b8645 100644 --- a/libs/ardour/plugin_insert.cc +++ b/libs/ardour/plugin_insert.cc @@ -1282,3 +1282,19 @@ PluginInsert::realtime_handle_transport_stopped () (*i)->realtime_handle_transport_stopped (); } } + +void +PluginInsert::realtime_locate () +{ + for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { + (*i)->realtime_locate (); + } +} + +void +PluginInsert::monitoring_changed () +{ + for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { + (*i)->monitoring_changed (); + } +} diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index 7d1f7930a6..af804cc932 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -890,6 +890,11 @@ Track::set_monitoring (MonitorChoice mc) { if (mc != _monitoring) { _monitoring = mc; + + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + (*i)->monitoring_changed (); + } + MonitoringChanged (); /* EMIT SIGNAL */ } } |