X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Ftrack.cc;h=fa19c3ddcc6fc6cb9c338144c96b87a23850d5b5;hb=d8a9f64bbc21e4d5dac66474bcad754f4fa9d1e7;hp=ad4c7658677ab017c6c694a85d7fdac30003f8e0;hpb=14004b75a6d18a74fa59ac06c203af693164b774;p=ardour.git diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index ad4c765867..fa19c3ddcc 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -43,10 +43,13 @@ Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, Data : Route (sess, name, flag, default_type) , _saved_meter_point (_meter_point) , _mode (mode) + , _monitoring (MonitorAuto) , _rec_enable_control (new RecEnableControllable(*this)) { _freeze_record.state = NoFreeze; _declickable = true; + + Config->ParameterChanged.connect_same_thread (*this, boost::bind (&Track::parameter_changed, this, _1)); } Track::~Track () @@ -63,6 +66,19 @@ Track::init () return 0; } + +void +Track::use_new_diskstream () +{ + boost::shared_ptr ds = create_diskstream (); + + ds->do_refill_with_alloc (); + ds->set_block_size (_session.get_block_size ()); + ds->playlist()->set_orig_track_id (id()); + + set_diskstream (ds); +} + XMLNode& Track::get_state () { @@ -70,44 +86,100 @@ Track::get_state () } XMLNode& -Track::get_template () -{ - return state (false); -} +Track::state (bool full) +{ + XMLNode& root (Route::state (full)); + root.add_property (X_("monitoring"), enum_2_string (_monitoring)); + 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 ()); + + if (!_deactivated_processors.empty ()) { + XMLNode* node = new XMLNode (X_("DeactivatedProcessors")); + for (list >::iterator i = _deactivated_processors.begin(); i != _deactivated_processors.end(); ++i) { + boost::shared_ptr p = i->lock (); + if (p) { + XMLNode* c = new XMLNode (X_("Processor")); + c->add_property (X_("id"), p->id().to_s()); + node->add_child_nocopy (*c); + } + } + root.add_child_nocopy (*node); + } + + return root; +} -void -Track::toggle_monitor_input () +int +Track::set_state (const XMLNode& node, int version) { - for (PortSet::iterator i = _input->ports().begin(); i != _input->ports().end(); ++i) { - i->ensure_monitor_input(!i->monitoring_input()); + if (Route::set_state (node, version)) { + return -1; } -} -ARDOUR::nframes_t -Track::update_total_latency () -{ - nframes_t old = _output->effective_latency(); - nframes_t own_latency = _output->user_latency(); + XMLNode* child; - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - if ((*i)->active ()) { - own_latency += (*i)->signal_latency (); + if (version >= 3000) { + if ((child = find_named_node (node, X_("Diskstream"))) != 0) { + boost::shared_ptr ds = diskstream_factory (*child); + ds->do_refill_with_alloc (); + set_diskstream (ds); } } -#undef DEBUG_LATENCY -#ifdef DEBUG_LATENCY - cerr << _name << ": internal redirect (final) latency = " << own_latency << endl; -#endif + if (_diskstream) { + _diskstream->playlist()->set_orig_track_id (id()); + } + + /* set rec-enable control *AFTER* setting up diskstream, because it may + want to operate on the diskstream as it sets its own state + */ - _output->set_port_latency (own_latency); + XMLNodeList nlist = node.children(); + for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) { + child = *niter; - if (old != own_latency) { - _output->set_latency_delay (own_latency); - signal_latency_changed (); /* EMIT SIGNAL */ + XMLProperty* prop; + if (child->name() == Controllable::xml_node_name && (prop = child->property ("name")) != 0) { + if (prop->value() == X_("recenable")) { + _rec_enable_control->set_state (*child, version); + } + } + + if (child->name() == X_("DeactivatedProcessors")) { + XMLNodeList dp = child->children (); + for (XMLNodeConstIterator i = dp.begin(); i != dp.end(); ++i) { + assert ((*i)->name() == X_("Processor")); + XMLProperty* prop = (*i)->property (X_("id")); + boost::shared_ptr p = processor_by_id (PBD::ID (prop->value ())); + if (p) { + _deactivated_processors.push_back (p); + } + } + } + } + + const XMLProperty* prop; + + if ((prop = node.property (X_("monitoring"))) != 0) { + _monitoring = MonitorChoice (string_2_enum (prop->value(), _monitoring)); + } else { + _monitoring = MonitorAuto; + } + + if ((prop = node.property (X_("saved-meter-point"))) != 0) { + _saved_meter_point = MeterPoint (string_2_enum (prop->value(), _saved_meter_point)); + } else { + _saved_meter_point = _meter_point; } - return _output->effective_latency(); + return 0; +} + +XMLNode& +Track::get_template () +{ + return state (false); } Track::FreezeRecord::~FreezeRecord () @@ -129,17 +201,17 @@ Track::RecEnableControllable::RecEnableControllable (Track& s) } void -Track::RecEnableControllable::set_value (float val) +Track::RecEnableControllable::set_value (double val) { - bool bval = ((val >= 0.5f) ? true: false); - track.set_record_enable (bval, this); + bool bval = ((val >= 0.5) ? true: false); + track.set_record_enabled (bval, this); } -float +double Track::RecEnableControllable::get_value (void) const { - if (track.record_enabled()) { return 1.0f; } - return 0.0f; + if (track.record_enabled()) { return 1.0; } + return 0.0; } bool @@ -160,8 +232,35 @@ Track::can_record() return will_record; } +/* Turn off visible processors (except Fader), keeping track of the old states */ void -Track::set_record_enable (bool yn, void *src) +Track::deactivate_visible_processors () +{ + _deactivated_processors.clear (); + Glib::RWLock::ReaderLock lm (_processor_lock); + + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + if ((*i)->active() && (*i)->display_to_user() && boost::dynamic_pointer_cast (*i) == 0) { + (*i)->deactivate (); + _deactivated_processors.push_back (*i); + } + } +} + +/* Turn deactivated processors back on again */ +void +Track::activate_deactivated_processors () +{ + for (list >::iterator i = _deactivated_processors.begin(); i != _deactivated_processors.end(); ++i) { + boost::shared_ptr p = i->lock (); + if (p) { + p->activate (); + } + } +} + +void +Track::set_record_enabled (bool yn, void *src) { if (!_session.writable()) { return; @@ -172,7 +271,7 @@ Track::set_record_enable (bool yn, void *src) } if (_route_group && src != _route_group && _route_group->is_active() && _route_group->is_recenable()) { - _route_group->apply (&Track::set_record_enable, yn, _route_group); + _route_group->apply (&Track::set_record_enabled, yn, _route_group); return; } @@ -181,6 +280,14 @@ Track::set_record_enable (bool yn, void *src) _saved_meter_point = _meter_point; } + if (Config->get_do_not_record_plugins ()) { + if (yn) { + deactivate_visible_processors (); + } else { + activate_deactivated_processors (); + } + } + _diskstream->set_record_enabled (yn); if (_diskstream->record_enabled()) { @@ -205,9 +312,7 @@ Track::set_name (const string& str) return false; } - if (_diskstream->set_name (str)) { - return false; - } + _diskstream->set_name (str); /* save state so that the statefile fully reflects any filename changes */ @@ -219,29 +324,22 @@ Track::set_name (const string& str) } void -Track::set_latency_delay (nframes_t longest_session_latency) +Track::set_latency_compensation (framecnt_t longest_session_latency) { - Route::set_latency_delay (longest_session_latency); + Route::set_latency_compensation (longest_session_latency); _diskstream->set_roll_delay (_roll_delay); } -void -Track::zero_diskstream_id_in_xml (XMLNode& node) -{ - if (node.property ("diskstream-id")) { - node.add_property ("diskstream-id", "0"); - } -} - int -Track::no_roll (nframes_t nframes, framepos_t start_frame, framepos_t end_frame, - bool session_state_changing, bool can_record, bool /*rec_monitors_input*/) +Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing) { Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); if (!lm.locked()) { return 0; } + bool can_record = _session.actively_recording (); + if (n_outputs().n_total() == 0) { return 0; } @@ -266,46 +364,23 @@ Track::no_roll (nframes_t nframes, framepos_t start_frame, framepos_t end_frame, */ } - _diskstream->check_record_status (start_frame, nframes, can_record); + _diskstream->check_record_status (start_frame, can_record); - bool send_silence; + 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. */ - send_silence = true; + be_silent = true; } else { - if (!Config->get_tape_machine_mode()) { - /* - ADATs work in a strange way.. - they monitor input always when stopped.and auto-input is engaged. - */ - if ((Config->get_monitoring_model() == SoftwareMonitoring) - && (_session.config.get_auto_input () || _diskstream->record_enabled())) { - send_silence = false; - } else { - send_silence = true; - } - } else { - /* - Other machines switch to input on stop if the track is record enabled, - regardless of the auto input setting (auto input only changes the - monitoring state when the transport is rolling) - */ - if ((Config->get_monitoring_model() == SoftwareMonitoring) - && _diskstream->record_enabled()) { - send_silence = false; - } else { - send_silence = true; - } - } + be_silent = send_silence (); } _amp->apply_gain_automation(false); - if (send_silence) { + if (be_silent) { /* if we're sending silence, but we want the meters to show levels for the signal, meter right here. @@ -328,14 +403,18 @@ Track::no_roll (nframes_t nframes, framepos_t start_frame, framepos_t end_frame, passthru (start_frame, end_frame, nframes, false); } - _main_outs->flush (nframes, end_frame - start_frame - 1); + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + boost::shared_ptr d = boost::dynamic_pointer_cast (*i); + if (d) { + d->flush_buffers (nframes, end_frame - start_frame - 1); + } + } return 0; } int -Track::silent_roll (nframes_t nframes, framepos_t /*start_frame*/, framepos_t /*end_frame*/, - bool can_record, bool rec_monitors_input, bool& need_butler) +Track::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /*end_frame*/, bool& need_butler) { Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); if (!lm.locked()) { @@ -356,26 +435,17 @@ Track::silent_roll (nframes_t nframes, framepos_t /*start_frame*/, framepos_t /* silence (nframes); - return _diskstream->process (_session.transport_frame(), nframes, can_record, rec_monitors_input, need_butler); -} - -ChanCount -Track::input_streams () const -{ - ChanCount cc = _input->n_ports (); - - if (cc.n_total() == 0 && _diskstream) { - return cc = _diskstream->n_channels(); - } - - return cc; + framecnt_t playback_distance; + int const dret = _diskstream->process (_session.transport_frame(), nframes, playback_distance); + need_butler = _diskstream->commit (playback_distance); + return dret; } void Track::set_diskstream (boost::shared_ptr ds) { _diskstream = 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)); @@ -414,9 +484,15 @@ Track::playlist () } void -Track::monitor_input (bool m) +Track::request_jack_monitors_input (bool m) { - _diskstream->monitor_input (m); + _diskstream->request_jack_monitors_input (m); +} + +void +Track::ensure_jack_monitors_input (bool m) +{ + _diskstream->ensure_jack_monitors_input (m); } bool @@ -425,10 +501,10 @@ Track::destructive () const return _diskstream->destructive (); } -list > & -Track::last_capture_regions () +list > & +Track::last_capture_sources () { - return _diskstream->last_capture_regions (); + return _diskstream->last_capture_sources (); } void @@ -437,6 +513,12 @@ Track::set_capture_offset () _diskstream->set_capture_offset (); } +list > +Track::steal_write_sources() +{ + return _diskstream->steal_write_sources (); +} + void Track::reset_write_sources (bool r, bool force) { @@ -474,9 +556,9 @@ Track::set_pending_overwrite (bool o) } int -Track::seek (nframes_t s, bool complete_refill) +Track::seek (framepos_t p, bool complete_refill) { - return _diskstream->seek (s, complete_refill); + return _diskstream->seek (p, complete_refill); } bool @@ -486,15 +568,15 @@ Track::hidden () const } int -Track::can_internal_playback_seek (nframes_t d) +Track::can_internal_playback_seek (framepos_t p) { - return _diskstream->can_internal_playback_seek (d); + return _diskstream->can_internal_playback_seek (p); } int -Track::internal_playback_seek (nframes_t d) +Track::internal_playback_seek (framepos_t p) { - return _diskstream->internal_playback_seek (d); + return _diskstream->internal_playback_seek (p); } void @@ -504,7 +586,7 @@ Track::non_realtime_input_change () } void -Track::non_realtime_locate (nframes_t p) +Track::non_realtime_locate (framepos_t p) { _diskstream->non_realtime_locate (p); } @@ -521,8 +603,8 @@ Track::overwrite_existing_buffers () return _diskstream->overwrite_existing_buffers (); } -nframes_t -Track::get_captured_frames (uint32_t n) +framecnt_t +Track::get_captured_frames (uint32_t n) const { return _diskstream->get_captured_frames (n); } @@ -534,9 +616,9 @@ Track::set_loop (Location* l) } void -Track::transport_looped (nframes_t f) +Track::transport_looped (framepos_t p) { - _diskstream->transport_looped (f); + _diskstream->transport_looped (p); } bool @@ -581,8 +663,8 @@ Track::n_channels () return _diskstream->n_channels (); } -nframes_t -Track::get_capture_start_frame (uint32_t n) +framepos_t +Track::get_capture_start_frame (uint32_t n) const { return _diskstream->get_capture_start_frame (n); } @@ -593,19 +675,19 @@ Track::alignment_style () const return _diskstream->alignment_style (); } -void -Track::set_record_enabled (bool r) +AlignChoice +Track::alignment_choice () const { - _diskstream->set_record_enabled (r); + return _diskstream->alignment_choice (); } -nframes_t +framepos_t Track::current_capture_start () const { return _diskstream->current_capture_start (); } -nframes_t +framepos_t Track::current_capture_end () const { return _diskstream->current_capture_end (); @@ -620,53 +702,63 @@ Track::playlist_modified () int Track::use_playlist (boost::shared_ptr p) { - return _diskstream->use_playlist (p); + int ret = _diskstream->use_playlist (p); + if (ret == 0) { + p->set_orig_track_id (id()); + } + return ret; } int Track::use_copy_playlist () { - return _diskstream->use_copy_playlist (); + int ret = _diskstream->use_copy_playlist (); + + if (ret == 0) { + _diskstream->playlist()->set_orig_track_id (id()); + } + + return ret; } int Track::use_new_playlist () { - return _diskstream->use_new_playlist (); -} + int ret = _diskstream->use_new_playlist (); -uint32_t -Track::read_data_count () const -{ - return _diskstream->read_data_count (); + if (ret == 0) { + _diskstream->playlist()->set_orig_track_id (id()); + } + + return ret; } void -Track::set_align_style (AlignStyle s) +Track::set_align_style (AlignStyle s, bool force) { - _diskstream->set_align_style (s); + _diskstream->set_align_style (s, force); } -uint32_t -Track::write_data_count () const +void +Track::set_align_choice (AlignChoice s, bool force) { - return _diskstream->write_data_count (); + _diskstream->set_align_choice (s, force); } -PBD::ID const & -Track::diskstream_id () const +bool +Track::using_diskstream_id (PBD::ID id) const { - return _diskstream->id (); + return (id == _diskstream->id ()); } void -Track::set_block_size (nframes_t n) +Track::set_block_size (pframes_t n) { Route::set_block_size (n); _diskstream->set_block_size (n); } -void +void Track::adjust_playback_buffering () { if (_diskstream) { @@ -674,10 +766,192 @@ Track::adjust_playback_buffering () } } -void +void Track::adjust_capture_buffering () { if (_diskstream) { _diskstream->adjust_capture_buffering (); } } + +bool +Track::send_silence () const +{ + bool send_silence; + + if (Config->get_tape_machine_mode()) { + + /* ADATs work in a strange way.. + they monitor input always when stopped.and auto-input is engaged. + */ + + if ((Config->get_monitoring_model() == SoftwareMonitoring) + && ((_monitoring & MonitorInput) || (_diskstream->record_enabled()))) { + send_silence = false; + } else { + send_silence = true; + } + + + } else { + + /* Other machines switch to input on stop if the track is record enabled, + regardless of the auto input setting (auto input only changes the + monitoring state when the transport is rolling) + */ + + if ((Config->get_monitoring_model() == SoftwareMonitoring) + && ((_monitoring & MonitorInput) || + (!(_monitoring & MonitorDisk) && (_session.config.get_auto_input () || _diskstream->record_enabled())))){ + + DEBUG_TRACE (DEBUG::Monitor, + string_compose ("%1: no roll, use silence = FALSE, monitoring choice %2 recenable %3 sRA %4 autoinput %5\n", + name(), enum_2_string (_monitoring), + _diskstream->record_enabled(), _session.actively_recording(), + _session.config.get_auto_input())); + + send_silence = false; + } else { + DEBUG_TRACE (DEBUG::Monitor, + string_compose ("%1: no roll, use silence = TRUE, monitoring choice %2 recenable %3 sRA %4 autoinput %5\n", + name(), enum_2_string (_monitoring), + _diskstream->record_enabled(), _session.actively_recording(), + _session.config.get_auto_input())); + send_silence = true; + } + } + + return send_silence; +} + +MonitorState +Track::monitoring_state () +{ + MonitorState ms = MonitoringSilence; + + if (_session.transport_rolling()) { + + /* roll case */ + + if (_monitoring & MonitorInput) { // explicitly requested input monitoring + + ms = MonitoringInput; + + } else if (_monitoring & MonitorDisk) { // explicitly requested disk monitoring + + ms = MonitoringDisk; + + } else if (_diskstream->record_enabled() && _session.actively_recording()) { // Track actually recording + + ms = MonitoringInput; + + } else if (_diskstream->record_enabled() && !_session.actively_recording() && _session.config.get_auto_input()) { // Track armed but not recording, with auto input enabled + + ms = MonitoringInput; + + } else { // Every other state + + ms = MonitoringDisk; + + } + + } else { + + /* no-roll case */ + + if (send_silence()) { + + ms = MonitoringSilence; + } else { + + ms = MonitoringInput; + } + } + + return ms; +} + +void +Track::maybe_declick (BufferSet& bufs, framecnt_t nframes, int declick) +{ + /* never declick if there is an internal generator - we just want it to + keep generating sound without interruption. + + ditto if we are monitoring inputs. + */ + + if (_have_internal_generator || monitoring_choice() == MonitorInput) { + return; + } + + if (!declick) { + declick = _pending_declick; + } + + if (declick != 0) { + Amp::declick (bufs, nframes, declick); + } +} + +framecnt_t +Track::check_initial_delay (framecnt_t nframes, framecnt_t& transport_frame) +{ + if (_roll_delay > nframes) { + + _roll_delay -= nframes; + silence_unlocked (nframes); + /* transport frame is not legal for caller to use */ + return 0; + + } else if (_roll_delay > 0) { + + nframes -= _roll_delay; + silence_unlocked (_roll_delay); + transport_frame += _roll_delay; + + /* shuffle all the port buffers for things that lead "out" of this Route + to reflect that we just wrote _roll_delay frames of silence. + */ + + Glib::RWLock::ReaderLock lm (_processor_lock); + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + boost::shared_ptr iop = boost::dynamic_pointer_cast (*i); + if (iop) { + iop->increment_port_buffer_offset (_roll_delay); + } + } + _output->increment_port_buffer_offset (_roll_delay); + + _roll_delay = 0; + + } + + return nframes; +} + +void +Track::set_monitoring (MonitorChoice mc) +{ + if (mc != _monitoring) { + _monitoring = mc; + MonitoringChanged (); /* EMIT SIGNAL */ + } +} + +void +Track::parameter_changed (string p) +{ + if (p != "do-not-record-plugins") { + return; + } + + if (record_enabled ()) { + if (Config->get_do_not_record_plugins ()) { + deactivate_visible_processors (); + } else { + activate_deactivated_processors (); + } + } +} + +