first compiling, mostly working version of group controls changes
[ardour.git] / libs / ardour / midi_track.cc
index 3f154644812345e4bf56d641c1f3d07621c805b9..d3653dc929d279422422bde635660f9d6ce2b7af 100644 (file)
@@ -47,6 +47,7 @@
 #include "ardour/parameter_types.h"
 #include "ardour/port.h"
 #include "ardour/processor.h"
+#include "ardour/profile.h"
 #include "ardour/session.h"
 #include "ardour/session_playlists.h"
 #include "ardour/utils.h"
@@ -102,13 +103,23 @@ MidiTrack::create_diskstream ()
 
 
 void
-MidiTrack::set_record_enabled (bool yn, void *src)
+MidiTrack::set_record_enabled (bool yn, Controllable::GroupControlDisposition group_override)
 {
        if (_step_editing) {
                return;
        }
 
-       Track::set_record_enabled (yn, src);
+       Track::set_record_enabled (yn, group_override);
+}
+
+void
+MidiTrack::set_record_safe (bool yn, Controllable::GroupControlDisposition group_override)
+{
+       if (_step_editing) { /* REQUIRES REVIEW */
+               return;
+       }
+
+       Track::set_record_safe (yn, group_override);
 }
 
 void
@@ -119,13 +130,17 @@ MidiTrack::set_diskstream (boost::shared_ptr<Diskstream> ds)
        */
        boost::shared_ptr<MidiDiskstream> mds = boost::dynamic_pointer_cast<MidiDiskstream> (ds);
        mds->set_note_mode (_note_mode);
-       
+
        Track::set_diskstream (ds);
 
-       mds->reset_tracker ();  
+       mds->reset_tracker ();
 
        _diskstream->set_track (this);
-       _diskstream->set_destructive (_mode == Destructive);
+       if (Profile->get_trx()) {
+               _diskstream->set_destructive (false);
+       } else {
+               _diskstream->set_destructive (_mode == Destructive);
+       }
        _diskstream->set_record_enabled (false);
 
        _diskstream_data_recorded_connection.disconnect ();
@@ -341,7 +356,7 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
        if (!lm.locked()) {
                boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
                framecnt_t playback_distance = diskstream->calculate_playback_distance(nframes);
-               if (can_internal_playback_seek(llabs(playback_distance))) {
+               if (can_internal_playback_seek(::llabs(playback_distance))) {
                        /* TODO should declick, and/or note-off */
                        internal_playback_seek(playback_distance);
                }
@@ -379,6 +394,16 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
                return dret;
        }
 
+       if (_mute_control->list() && _mute_control->automation_playback()) {
+               bool        valid = false;
+               const float mute  = _mute_control->list()->rt_safe_eval(transport_frame, valid);
+               if (mute >= 0.5 && !muted()) {
+                       _mute_control->set_value_unchecked(1.0);  // mute
+               } else if (mute < 0.5 && muted()) {
+                       _mute_control->set_value_unchecked(0.0);  // unmute
+               }
+       }
+
        BufferSet& bufs = _session.get_route_buffers (n_process_buffers());
 
        fill_buffers_with_input (bufs, _input, nframes);
@@ -415,15 +440,15 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
 
                diskstream->flush_playback (start_frame, end_frame);
 
-       } 
+       }
+
 
-       
        /* append immediate messages to the first MIDI buffer (thus sending it to the first output port) */
-       
+
        write_out_of_band_data (bufs, start_frame, end_frame, nframes);
-       
+
        /* final argument: don't waste time with automation if we're not recording or rolling */
-       
+
        process_output_buffers (bufs, start_frame, end_frame, nframes,
                                declick, (!diskstream->record_enabled() && !_session.transport_stopped()));
 
@@ -435,7 +460,7 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
        }
 
        need_butler = diskstream->commit (playback_distance);
-       
+
        return 0;
 }
 
@@ -498,6 +523,11 @@ MidiTrack::non_realtime_locate (framepos_t pos)
                return;
        }
 
+       /* the source may be missing, but the control still referenced in the GUI */
+       if (!region->midi_source() || !region->model()) {
+               return;
+       }
+
        Glib::Threads::Mutex::Lock lm (_control_lock, Glib::Threads::TRY_LOCK);
        if (!lm.locked()) {
                return;
@@ -512,7 +542,9 @@ MidiTrack::non_realtime_locate (framepos_t pos)
                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()));
+                       if (rcontrol->list()->size() > 0) {
+                               tcontrol->set_value(rcontrol->list()->eval(pos_beats.to_double()), Controllable::NoGroup);
+                       }
                }
        }
 }
@@ -693,7 +725,22 @@ MidiTrack::set_parameter_automation_state (Evoral::Parameter param, AutoState st
 }
 
 void
-MidiTrack::MidiControl::set_value(double val)
+MidiTrack::MidiControl::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
+{
+       if (writable()) {
+               _set_value (val, group_override);
+       }
+}
+
+void
+MidiTrack::MidiControl::set_value_unchecked (double val)
+{
+       /* used only by automation playback */
+       _set_value (val, Controllable::NoGroup);
+}
+
+void
+MidiTrack::MidiControl::_set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
 {
        const Evoral::Parameter &parameter = _list ? _list->parameter() : Control::parameter();
        const Evoral::ParameterDescriptor &desc = EventTypeMap::instance().descriptor(parameter);
@@ -750,7 +797,7 @@ MidiTrack::MidiControl::set_value(double val)
                _route->write_immediate_event(size,  ev);
        }
 
-       AutomationControl::set_value(val);
+       AutomationControl::set_value(val, group_override);
 }
 
 void
@@ -905,23 +952,23 @@ MidiTrack::act_on_mute ()
                }
 
                /* Resolve active notes. */
-               midi_diskstream()->resolve_tracker(_immediate_events, 0);
+               midi_diskstream()->resolve_tracker(_immediate_events, Port::port_offset());
        }
 }
-       
+
 void
 MidiTrack::set_monitoring (MonitorChoice mc)
 {
        if (mc != _monitoring) {
 
                Track::set_monitoring (mc);
-               
+
                /* monitoring state changed, so flush out any on notes at the
                 * port level.
                 */
 
                PortSet& ports (_output->ports());
-               
+
                for (PortSet::iterator p = ports.begin(); p != ports.end(); ++p) {
                        boost::shared_ptr<MidiPort> mp = boost::dynamic_pointer_cast<MidiPort> (*p);
                        if (mp) {
@@ -930,7 +977,7 @@ MidiTrack::set_monitoring (MonitorChoice mc)
                }
 
                boost::shared_ptr<MidiDiskstream> md (midi_diskstream());
-               
+
                if (md) {
                        md->reset_tracker ();
                }
@@ -943,7 +990,7 @@ MidiTrack::monitoring_state () const
        MonitorState ms = Track::monitoring_state();
        if (ms == MonitoringSilence) {
                return MonitoringInput;
-       } 
+       }
        return ms;
 }