diff options
author | David Robillard <d@drobilla.net> | 2015-03-26 00:47:34 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2015-03-26 00:47:34 -0400 |
commit | 7e2c8ace4bf30ce8e27f1089370d63d7ef604cfa (patch) | |
tree | fe6812cf1b5abc337db5a2395fe1945881c32f7c /libs/ardour/midi_track.cc | |
parent | a53bd7269797969bfb182a4caebc9361cac45795 (diff) |
Follow MIDI control values with automation faders.
Fixes bug #6166 (except record).
This attempts to follow the "current" control value somewhat aggressively:
* On locate, slider is set to the value from the top region at the new
transport position.
* Playback or MIDI input is followed "live".
* Whenever the slider is moved (including automatically), that value is emitted
as an immediate event to keep external gear in sync.
General idea is that the Ardour slider should act as a mirror of an external
hardware knob, and both should be synced to whatever the control is at the
current transport position. Since we lack real playback/touch/etc modes for
these for now, we must choose one behaviour, and this seems like the most
reasonable one.
Follow is handled in the audio thread, which is probably not ideal, but since
these controls have no lists and do not record, should be fine. Probably.
Diffstat (limited to 'libs/ardour/midi_track.cc')
-rw-r--r-- | libs/ardour/midi_track.cc | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index 770e4da3fe..b8f53a87d0 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -34,6 +34,7 @@ #include "pbd/convert.h" #include "evoral/midi_util.h" +#include "ardour/beats_frames_converter.h" #include "ardour/buffer_set.h" #include "ardour/debug.h" #include "ardour/delivery.h" @@ -42,6 +43,7 @@ #include "ardour/midi_diskstream.h" #include "ardour/midi_playlist.h" #include "ardour/midi_port.h" +#include "ardour/midi_region.h" #include "ardour/midi_track.h" #include "ardour/parameter_types.h" #include "ardour/port.h" @@ -318,6 +320,20 @@ MidiTrack::set_state_part_two () return; } +void +MidiTrack::update_controls(const BufferSet& bufs) +{ + const MidiBuffer& buf = bufs.get_midi(0); + for (MidiBuffer::const_iterator e = buf.begin(); e != buf.end(); ++e) { + const Evoral::MIDIEvent<framepos_t>& ev = *e; + const Evoral::Parameter param = midi_parameter(ev.buffer(), ev.size()); + const boost::shared_ptr<Evoral::Control> control = this->control(param); + if (control) { + control->set_double(ev.value(), _session.transport_frame(), false); + } + } +} + /** @param need_butler to be set to true if this track now needs the butler, otherwise it can be left alone * or set to false. */ @@ -471,6 +487,42 @@ MidiTrack::realtime_handle_transport_stopped () } void +MidiTrack::non_realtime_locate (framepos_t pos) +{ + Track::non_realtime_locate(pos); + + boost::shared_ptr<MidiPlaylist> playlist = midi_diskstream()->midi_playlist(); + if (!playlist) { + return; + } + + /* Get the top unmuted region at this position. */ + boost::shared_ptr<MidiRegion> region = boost::dynamic_pointer_cast<MidiRegion>( + playlist->top_unmuted_region_at(pos)); + if (!region) { + return; + } + + Glib::Threads::Mutex::Lock lm (_control_lock, Glib::Threads::TRY_LOCK); + if (!lm.locked()) { + return; + } + + /* Update track controllers based on its "automation". */ + const framepos_t origin = region->position() - region->start(); + BeatsFramesConverter bfc(_session.tempo_map(), origin); + for (Controls::const_iterator c = _controls.begin(); c != _controls.end(); ++c) { + boost::shared_ptr<MidiTrack::MidiControl> tcontrol; + boost::shared_ptr<Evoral::Control> rcontrol; + if ((tcontrol = boost::dynamic_pointer_cast<MidiTrack::MidiControl>(c->second)) && + (rcontrol = region->control(tcontrol->parameter()))) { + const Evoral::Beats pos_beats = bfc.from(pos - origin); + tcontrol->set_value(rcontrol->list()->eval(pos_beats.to_double())); + } + } +} + +void MidiTrack::push_midi_input_to_step_edit_ringbuffer (framecnt_t nframes) { PortSet& ports (_input->ports()); @@ -539,6 +591,8 @@ MidiTrack::write_out_of_band_data (BufferSet& bufs, framepos_t /*start*/, framep { MidiBuffer& buf (bufs.get_midi (0)); + update_controls (bufs); + // Append immediate events if (_immediate_events.read_space()) { |