summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/ardour/ardour/midi_track.h4
-rw-r--r--libs/ardour/ardour/parameter_types.h21
-rw-r--r--libs/ardour/midi_track.cc54
-rw-r--r--libs/evoral/evoral/MIDIEvent.hpp15
4 files changed, 94 insertions, 0 deletions
diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h
index 2af5b4cf87..a12a0c6087 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -47,6 +47,7 @@ public:
void realtime_handle_transport_stopped ();
void realtime_locate ();
+ void non_realtime_locate (framepos_t);
boost::shared_ptr<Diskstream> create_diskstream ();
void set_diskstream (boost::shared_ptr<Diskstream>);
@@ -183,6 +184,9 @@ private:
void track_input_active (IOChange, void*);
void map_input_active (bool);
+ /** Update automation controls to reflect any changes in buffers. */
+ void update_controls (const BufferSet& bufs);
+
void filter_channels (BufferSet& bufs, ChannelMode mode, uint32_t mask);
/* if mode is ForceChannel, force mask to the lowest set channel or 1 if no
diff --git a/libs/ardour/ardour/parameter_types.h b/libs/ardour/ardour/parameter_types.h
index 8442d1f1bf..240ad2d956 100644
--- a/libs/ardour/ardour/parameter_types.h
+++ b/libs/ardour/ardour/parameter_types.h
@@ -24,6 +24,7 @@
#include <stdint.h>
#include "ardour/types.h"
+#include "evoral/Parameter.hpp"
#include "evoral/midi_events.h"
namespace ARDOUR {
@@ -54,6 +55,26 @@ midi_parameter_type(uint8_t status)
}
}
+inline Evoral::Parameter
+midi_parameter(const uint8_t* buf, const uint32_t len)
+{
+ const uint8_t channel = buf[0] & 0x0F;
+ switch (midi_parameter_type(buf[0])) {
+ case MidiCCAutomation:
+ return Evoral::Parameter(MidiCCAutomation, channel, buf[1]);
+ case MidiPgmChangeAutomation:
+ return Evoral::Parameter(MidiPgmChangeAutomation, channel);
+ case MidiChannelPressureAutomation:
+ return Evoral::Parameter(MidiChannelPressureAutomation, channel);
+ case MidiPitchBenderAutomation:
+ return Evoral::Parameter(MidiPitchBenderAutomation, channel);
+ case MidiSystemExclusiveAutomation:
+ return Evoral::Parameter(MidiSystemExclusiveAutomation, channel);
+ default:
+ return Evoral::Parameter(NullAutomation);
+ }
+}
+
inline bool
parameter_is_midi(AutomationType type)
{
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()) {
diff --git a/libs/evoral/evoral/MIDIEvent.hpp b/libs/evoral/evoral/MIDIEvent.hpp
index 9b1d72c400..f0c9c74589 100644
--- a/libs/evoral/evoral/MIDIEvent.hpp
+++ b/libs/evoral/evoral/MIDIEvent.hpp
@@ -104,6 +104,21 @@ public:
return this->size() == 10 && this->_buf[0] == 0xf0 && this->_buf[1] == 0x7f &&
this->_buf[3] == 0x01 && this->_buf[4] == 0x01;
}
+
+ inline uint16_t value() const {
+ switch (type()) {
+ case MIDI_CMD_CONTROL:
+ return cc_value();
+ case MIDI_CMD_BENDER:
+ return pitch_bender_value();
+ case MIDI_CMD_NOTE_PRESSURE:
+ return aftertouch();
+ case MIDI_CMD_CHANNEL_PRESSURE:
+ return channel_pressure();
+ default:
+ return 0;
+ }
+ }
};
} // namespace Evoral