boost::shared_ptr<Track> rt = boost::dynamic_pointer_cast<Track> (rp);
_rec_enable_control = boost::shared_ptr<RecEnableControl> (new RecEnableControl(rt));
_rec_enable_control->set_flags (Controllable::Toggle);
+ _monitoring_control.reset (new MonitoringControllable (X_("monitoring"), rt));
/* don't add rec_enable_control to controls because we don't want it to
* appear as an automatable parameter
root.add_property (X_("saved-meter-point"), enum_2_string (_saved_meter_point));
root.add_child_nocopy (_rec_enable_control->get_state());
root.add_child_nocopy (_diskstream->get_state ());
-
+
return root;
-}
+}
int
Track::set_state (const XMLNode& node, int version)
}
}
}
-
+
const XMLProperty* prop;
if ((prop = node.property (X_("monitoring"))) != 0) {
}
void
-Track::RecEnableControl::set_value (double val)
+Track::RecEnableControl::set_value (double val, Controllable::GroupControlDisposition group_override)
+{
+ if (writable()) {
+ _set_value (val, group_override);
+ }
+}
+
+void
+Track::RecEnableControl::set_value_unchecked (double val)
+{
+ if (writable()) {
+ _set_value (val, Controllable::NoGroup);
+ }
+}
+
+void
+Track::RecEnableControl::_set_value (double val, Controllable::GroupControlDisposition group_override)
{
boost::shared_ptr<Track> t = track.lock ();
if (!t) {
return;
}
-
- t->set_record_enabled (val >= 0.5 ? true : false, this);
+
+ t->set_record_enabled (val >= 0.5 ? true : false, group_override);
}
double
if (!t) {
return 0;
}
-
+
return (t->record_enabled() ? 1.0 : 0.0);
}
}
void
-Track::prep_record_enabled (bool yn, void *src)
+Track::prep_record_enabled (bool yn, Controllable::GroupControlDisposition group_override)
{
+ if (yn && record_safe ()) {
+ return;
+ }
+
if (!_session.writable()) {
return;
}
return;
}
- if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_recenable()) {
- _route_group->apply (&Track::prep_record_enabled, yn, _route_group);
+ if (use_group (group_override, &RouteGroup::is_recenable)) {
+ _route_group->apply (&Track::prep_record_enabled, yn, Controllable::NoGroup);
return;
}
}
bool will_follow;
-
+
if (yn) {
will_follow = _diskstream->prep_record_enable ();
} else {
}
void
-Track::set_record_enabled (bool yn, void *src)
+Track::set_record_enabled (bool yn, Controllable::GroupControlDisposition group_override)
{
+ if (_diskstream->record_safe ()) {
+ return;
+ }
+
if (!_session.writable()) {
return;
}
return;
}
- if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_recenable()) {
- _route_group->apply (&Track::set_record_enabled, yn, _route_group);
+ if (use_group (group_override, &RouteGroup::is_recenable)) {
+ _route_group->apply (&Track::set_record_enabled, yn, Controllable::NoGroup);
return;
}
_rec_enable_control->Changed ();
}
+bool
+Track::record_safe () const
+{
+ return _diskstream && _diskstream->record_safe ();
+}
+
+void
+Track::set_record_safe (bool yn, Controllable::GroupControlDisposition group_override)
+{
+ if (!_session.writable()) {
+ return;
+ }
+
+ if (_freeze_record.state == Frozen) {
+ return;
+ }
+
+ if (use_group (group_override, &RouteGroup::is_recenable)) {
+ _route_group->apply (&Track::set_record_safe, yn, Controllable::NoGroup);
+ return;
+ }
+
+ _diskstream->set_record_safe (yn);
+}
+
void
Track::parameter_changed (string const & p)
{
be_silent = false;
break;
}
-
+
//if we have an internal generator, let it play regardless of monitoring state
if (_have_internal_generator) {
be_silent = false;
}
-
+
_amp->apply_gain_automation (false);
/* if have_internal_generator, or .. */
} else {
BufferSet& bufs = _session.get_route_buffers (n_process_buffers());
-
+
fill_buffers_with_input (bufs, _input, nframes);
if (_meter_point == MeterInput) {
ds->PlaylistChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_playlist_changed, this));
diskstream_playlist_changed ();
ds->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_record_enable_changed, this));
+ ds->RecordSafeChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_record_safe_changed, this));
ds->SpeedChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_speed_changed, this));
ds->AlignmentStyleChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_alignment_style_changed, this));
}
RecordEnableChanged (); /* EMIT SIGNAL */
}
+void
+Track::diskstream_record_safe_changed ()
+{
+ RecordSafeChanged (); /* EMIT SIGNAL */
+}
+
void
Track::diskstream_speed_changed ()
{
}
}
+#ifdef USE_TRACKS_CODE_FEATURES
+
+/* This is the Tracks version of Track::monitoring_state().
+ *
+ * Ardour developers: try to flag or fix issues if parts of the libardour API
+ * change in ways that invalidate this
+ */
+
MonitorState
Track::monitoring_state () const
{
/* Explicit requests */
-
+
if (_monitoring & MonitorInput) {
return MonitoringInput;
}
-
+
+ if (_monitoring & MonitorDisk) {
+ return MonitoringDisk;
+ }
+
+ /* This is an implementation of the truth table in doc/monitor_modes.pdf;
+ I don't think it's ever going to be too pretty too look at.
+ */
+
+ // GZ: NOT USED IN TRACKS
+ //bool const auto_input = _session.config.get_auto_input ();
+ //bool const software_monitor = Config->get_monitoring_model() == SoftwareMonitoring;
+ //bool const tape_machine_mode = Config->get_tape_machine_mode ();
+
+ bool const roll = _session.transport_rolling ();
+ bool const track_rec = _diskstream->record_enabled ();
+ bool session_rec = _session.actively_recording ();
+
+ if (track_rec) {
+
+ if (!session_rec && roll) {
+ return MonitoringDisk;
+ } else {
+ return MonitoringInput;
+ }
+
+ } else {
+
+ if (roll) {
+ return MonitoringDisk;
+ }
+ }
+
+ return MonitoringSilence;
+}
+
+#else
+
+/* This is the Ardour/Mixbus version of Track::monitoring_state().
+ *
+ * Tracks developers: do NOT modify this method under any circumstances.
+ */
+
+MonitorState
+Track::monitoring_state () const
+{
+ /* Explicit requests */
+
+ if (_monitoring & MonitorInput) {
+ return MonitoringInput;
+ }
+
if (_monitoring & MonitorDisk) {
return MonitoringDisk;
}
} else {
return MonitoringDisk;
}
-
+
}
}
- /* NOTREACHED */
+ abort(); /* NOTREACHED */
return MonitoringSilence;
}
+#endif
+
void
Track::maybe_declick (BufferSet& bufs, framecnt_t nframes, int declick)
{
}
- return nframes;
+ return nframes;
}
void
-Track::set_monitoring (MonitorChoice mc)
+Track::set_monitoring (MonitorChoice mc, Controllable::GroupControlDisposition gcd)
{
+ if (use_group (gcd, &RouteGroup::is_monitoring)) {
+ _route_group->apply (&Track::set_monitoring, mc, Controllable::NoGroup);
+ return;
+ }
+
if (mc != _monitoring) {
_monitoring = mc;
}
MonitoringChanged (); /* EMIT SIGNAL */
+ _monitoring_control->Changed (); /* EMIT SIGNAL */
}
}
return rv ? MeteringInput : MeteringRoute;
}
+Track::MonitoringControllable::MonitoringControllable (std::string name, boost::shared_ptr<Track> r)
+ : RouteAutomationControl (name, MonitoringAutomation, boost::shared_ptr<AutomationList>(), r)
+{
+ boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(MonitoringAutomation)));
+ gl->set_interpolation(Evoral::ControlList::Discrete);
+ set_list (gl);
+}
+
+void
+Track::MonitoringControllable::set_value (double val, Controllable::GroupControlDisposition gcd)
+{
+ _set_value (val, gcd);
+}
+
+void
+Track::MonitoringControllable::_set_value (double val, Controllable::GroupControlDisposition gcd)
+{
+ boost::shared_ptr<Route> r = _route.lock();
+ if (!r) {
+ return;
+ }
+
+ boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (r);
+ if (!t) {
+ return;
+ }
+
+ int mc = (int) val;
+
+ if (mc < MonitorAuto || mc > MonitorDisk) {
+ return;
+ }
+
+ /* no group effect at present */
+
+ t->set_monitoring ((MonitorChoice) mc, gcd);
+}
+
+double
+Track::MonitoringControllable::get_value () const
+{
+ boost::shared_ptr<Route> r = _route.lock();
+ if (!r) {
+ return 0.0;
+ }
+
+ boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (r);
+ if (!t) {
+ return 0.0;
+ }
+
+ return t->monitoring_choice();
+}