X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Ftrack.cc;h=f279eae3069cbab3dfcedad52c45868b2357c238;hb=873498e196c1671e505631a3e526058a4458b419;hp=6d153e1cbf1068897c1cf74eecbadc817077dc98;hpb=29108187edabb37eed4eec52cbcbcbb736ebb497;p=ardour.git diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index 6d153e1cbf..f279eae306 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -64,12 +64,15 @@ Track::init () boost::shared_ptr rt = boost::dynamic_pointer_cast (rp); _rec_enable_control = boost::shared_ptr (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 */ + track_number_changed.connect_same_thread (*this, boost::bind (&Track::resync_track_name, this)); + _session.config.ParameterChanged.connect_same_thread (*this, boost::bind (&Track::parameter_changed, this, _1)); - return 0; + return 0; } void @@ -98,9 +101,9 @@ Track::state (bool full) 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) @@ -138,7 +141,7 @@ Track::set_state (const XMLNode& node, int version) } } } - + const XMLProperty* prop; if ((prop = node.property (X_("monitoring"))) != 0) { @@ -176,7 +179,11 @@ Track::freeze_state() const } Track::RecEnableControl::RecEnableControl (boost::shared_ptr t) - : AutomationControl (t->session(), RecEnableAutomation, boost::shared_ptr(), X_("recenable")) + : AutomationControl (t->session(), + RecEnableAutomation, + ParameterDescriptor(Evoral::Parameter(RecEnableAutomation)), + boost::shared_ptr(), + X_("recenable")) , track (t) { boost::shared_ptr gl(new AutomationList(Evoral::Parameter(RecEnableAutomation))); @@ -184,14 +191,30 @@ Track::RecEnableControl::RecEnableControl (boost::shared_ptr t) } 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 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 @@ -201,7 +224,7 @@ Track::RecEnableControl::get_value () const if (!t) { return 0; } - + return (t->record_enabled() ? 1.0 : 0.0); } @@ -224,8 +247,12 @@ Track::can_record() } 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; } @@ -234,8 +261,8 @@ Track::prep_record_enabled (bool yn, void *src) 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; } @@ -245,7 +272,7 @@ Track::prep_record_enabled (bool yn, void *src) } bool will_follow; - + if (yn) { will_follow = _diskstream->prep_record_enable (); } else { @@ -264,8 +291,12 @@ Track::prep_record_enabled (bool yn, void *src) } 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; } @@ -274,8 +305,8 @@ Track::set_record_enabled (bool yn, void *src) 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; } @@ -284,6 +315,53 @@ Track::set_record_enabled (bool yn, void *src) _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) +{ + if (p == "track-name-number") { + resync_track_name (); + } + else if (p == "track-name-take") { + resync_track_name (); + } + else if (p == "take-name") { + if (_session.config.get_track_name_take()) { + resync_track_name (); + } + } +} + +void +Track::resync_track_name () +{ + set_name(name()); +} + bool Track::set_name (const string& str) { @@ -294,6 +372,29 @@ Track::set_name (const string& str) return false; } + string diskstream_name = ""; + if (_session.config.get_track_name_take () && !_session.config.get_take_name ().empty()) { + // Note: any text is fine, legalize_for_path() fixes this later + diskstream_name += _session.config.get_take_name (); + diskstream_name += "_"; + } + const int64_t tracknumber = track_number(); + if (tracknumber > 0 && _session.config.get_track_name_number()) { + char num[64], fmt[10]; + snprintf(fmt, sizeof(fmt), "%%0%d" PRId64, _session.track_number_decimals()); + snprintf(num, sizeof(num), fmt, tracknumber); + diskstream_name += num; + diskstream_name += "_"; + } + diskstream_name += str; + + if (diskstream_name == _diskstream_name) { + return true; + } + _diskstream_name = diskstream_name; + + _diskstream->set_write_source_name (diskstream_name); + boost::shared_ptr me = boost::dynamic_pointer_cast (shared_from_this ()); if (_diskstream->playlist()->all_regions_empty () && _session.playlists->playlists_for_track (me).size() == 1) { /* Only rename the diskstream (and therefore the playlist) if @@ -347,6 +448,9 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, if (!_active) { silence (nframes); + if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) { + _meter->reset(); + } return 0; } @@ -369,33 +473,28 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool be_silent; - if (_have_internal_generator) { - /* since the instrument has no input streams, - there is no reason to send any signal - into the route. - */ + MonitorState const s = monitoring_state (); + /* we are not rolling, so be silent even if we are monitoring disk, as there + will be no disk data coming in. + */ + switch (s) { + case MonitoringSilence: be_silent = true; + break; + case MonitoringDisk: + be_silent = true; + break; + case MonitoringInput: + be_silent = false; + break; + default: + be_silent = false; + break; + } - } else { - - MonitorState const s = monitoring_state (); - /* we are not rolling, so be silent even if we are monitoring disk, as there - will be no disk data coming in. - */ - switch (s) { - case MonitoringSilence: - /* if there is an instrument, be_silent should always - be false - */ - be_silent = (the_instrument_unlocked() == 0); - break; - case MonitoringDisk: - be_silent = true; - break; - case MonitoringInput: - 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); @@ -405,16 +504,48 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, if (be_silent) { if (_meter_point == MeterInput) { - /* still need input monitoring */ - _input->process_input (_meter, start_frame, end_frame, nframes); + /* still need input monitoring and metering */ + + bool const track_rec = _diskstream->record_enabled (); + 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 no_meter = false; + + /* this needs a proper K-map + * and should be separated into a function similar to monitoring_state() + * that also handles roll() states in audio_track.cc, midi_track.cc and route.cc + * + * see http://www.oofus.co.uk/ardour/Ardour3MonitorModesV3.pdf + */ + if (!auto_input && !track_rec) { + no_meter=true; + } + else if (tape_machine_mode && !track_rec && auto_input) { + no_meter=true; + } + else if (!software_monitor && tape_machine_mode && !track_rec) { + no_meter=true; + } + else if (!software_monitor && !tape_machine_mode && !track_rec && !auto_input) { + no_meter=true; + } + + if (no_meter) { + BufferSet& bufs (_session.get_silent_buffers (n_process_buffers())); + _meter->run (bufs, 0, 0, nframes, true); + _input->process_input (boost::shared_ptr(), start_frame, end_frame, nframes); + } else { + _input->process_input (_meter, start_frame, end_frame, nframes); + } } passthru_silence (start_frame, end_frame, nframes, 0); } else { - BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers()); - + BufferSet& bufs = _session.get_route_buffers (n_process_buffers()); + fill_buffers_with_input (bufs, _input, nframes); if (_meter_point == MeterInput) { @@ -439,6 +570,10 @@ Track::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /* { Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK); if (!lm.locked()) { + framecnt_t playback_distance = _diskstream->calculate_playback_distance(nframes); + if (can_internal_playback_seek(playback_distance)) { + internal_playback_seek(playback_distance); + } return 0; } @@ -458,7 +593,7 @@ Track::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /* framecnt_t playback_distance; - BufferSet& bufs (_session.get_silent_buffers (n_process_buffers())); + BufferSet& bufs (_session.get_route_buffers (n_process_buffers(), true)); int const dret = _diskstream->process (bufs, _session.transport_frame(), nframes, playback_distance, false); need_butler = _diskstream->commit (playback_distance); @@ -473,6 +608,7 @@ Track::set_diskstream (boost::shared_ptr ds) 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)); } @@ -489,6 +625,12 @@ Track::diskstream_record_enable_changed () RecordEnableChanged (); /* EMIT SIGNAL */ } +void +Track::diskstream_record_safe_changed () +{ + RecordSafeChanged (); /* EMIT SIGNAL */ +} + void Track::diskstream_speed_changed () { @@ -508,15 +650,15 @@ Track::playlist () } void -Track::request_jack_monitors_input (bool m) +Track::request_input_monitoring (bool m) { - _diskstream->request_jack_monitors_input (m); + _diskstream->request_input_monitoring (m); } void -Track::ensure_jack_monitors_input (bool m) +Track::ensure_input_monitoring (bool m) { - _diskstream->ensure_jack_monitors_input (m); + _diskstream->ensure_input_monitoring (m); } bool @@ -537,10 +679,10 @@ Track::set_capture_offset () _diskstream->set_capture_offset (); } -list > -Track::steal_write_sources() +std::string +Track::steal_write_source_name() { - return _diskstream->steal_write_sources (); + return _diskstream->steal_write_source_name (); } void @@ -677,9 +819,9 @@ Track::speed () const } void -Track::prepare_to_stop (framepos_t p) +Track::prepare_to_stop (framepos_t t, framepos_t a) { - _diskstream->prepare_to_stop (p); + _diskstream->prepare_to_stop (t, a); } void @@ -805,15 +947,74 @@ Track::adjust_capture_buffering () } } +#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; } @@ -862,14 +1063,16 @@ Track::monitoring_state () const } else { return MonitoringDisk; } - + } } - /* NOTREACHED */ + abort(); /* NOTREACHED */ return MonitoringSilence; } +#endif + void Track::maybe_declick (BufferSet& bufs, framecnt_t nframes, int declick) { @@ -925,12 +1128,17 @@ Track::check_initial_delay (framecnt_t nframes, framepos_t& transport_frame) } - 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; @@ -939,12 +1147,74 @@ Track::set_monitoring (MonitorChoice mc) } MonitoringChanged (); /* EMIT SIGNAL */ + _monitoring_control->Changed (); /* EMIT SIGNAL */ } } MeterState Track::metering_state () const { - return (_diskstream->record_enabled() || _meter_point == MeterInput) ? MeteringInput : MeteringRoute; + bool rv; + if (_session.transport_rolling ()) { + // audio_track.cc || midi_track.cc roll() runs meter IFF: + rv = _meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled()); + } else { + // track no_roll() always metering if + rv = _meter_point == MeterInput; + } + return rv ? MeteringInput : MeteringRoute; } +Track::MonitoringControllable::MonitoringControllable (std::string name, boost::shared_ptr r) + : RouteAutomationControl (name, MonitoringAutomation, boost::shared_ptr(), r) +{ + boost::shared_ptr 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 r = _route.lock(); + if (!r) { + return; + } + + boost::shared_ptr t = boost::dynamic_pointer_cast (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 r = _route.lock(); + if (!r) { + return 0.0; + } + + boost::shared_ptr t = boost::dynamic_pointer_cast (r); + if (!t) { + return 0.0; + } + + return t->monitoring_choice(); +}