X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=libs%2Fardour%2Ftrack.cc;h=1aa917ca9d0830a9e93ba9eb8c5af95aae95d6e6;hb=7d96960b162d25da87c388a3083775e8770bba56;hp=58d8c1b3065692320e1a4ad3230a8458afe8871b;hpb=81b9700c145abfb6f2e32d5a9bd13895e42b04e2;p=ardour.git diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index 58d8c1b306..1aa917ca9d 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2006 Paul Davis + Copyright (C) 2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,23 +15,23 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "pbd/error.h" + +#include "ardour/amp.h" +#include "ardour/audioplaylist.h" +#include "ardour/audioregion.h" +#include "ardour/audiosource.h" +#include "ardour/debug.h" +#include "ardour/delivery.h" +#include "ardour/diskstream.h" +#include "ardour/io_processor.h" +#include "ardour/meter.h" +#include "ardour/port.h" +#include "ardour/processor.h" +#include "ardour/route_group_specialized.h" +#include "ardour/session.h" +#include "ardour/track.h" +#include "ardour/utils.h" #include "i18n.h" @@ -40,9 +40,8 @@ using namespace ARDOUR; using namespace PBD; Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, DataType default_type) - : Route (sess, name, 1, -1, -1, -1, flag, default_type) - , _diskstream (0) - , _rec_enable_control (*this) + : Route (sess, name, flag, default_type) + , _rec_enable_control (new RecEnableControllable(*this)) { _declickable = true; _freeze_record.state = NoFreeze; @@ -51,9 +50,8 @@ Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, Data } Track::Track (Session& sess, const XMLNode& node, DataType default_type) - : Route (sess, "to be renamed", 0, 0, -1, -1, Route::Flag(0), default_type) - , _diskstream (0) - , _rec_enable_control (*this) + : Route (sess, node, default_type) + , _rec_enable_control (new RecEnableControllable(*this)) { _freeze_record.state = NoFreeze; _declickable = true; @@ -62,15 +60,7 @@ Track::Track (Session& sess, const XMLNode& node, DataType default_type) Track::~Track () { - if (_diskstream) { - _diskstream->unref(); - } -} - -void -Track::set_meter_point (MeterPoint p, void *src) -{ - Route::set_meter_point (p, src); + DEBUG_TRACE (DEBUG::Destruction, string_compose ("track %1 destructor\n", _name)); } XMLNode& @@ -88,31 +78,41 @@ Track::get_template () void Track::toggle_monitor_input () { - for (vector::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { - (*i)->request_monitor_input(!(*i)->monitoring_input()); + for (PortSet::iterator i = _input->ports().begin(); i != _input->ports().end(); ++i) { + i->ensure_monitor_input(!i->monitoring_input()); } } -jack_nframes_t +ARDOUR::nframes_t Track::update_total_latency () { - _own_latency = 0; + nframes_t old = _output->effective_latency(); + nframes_t own_latency = _output->user_latency(); - for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) { + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { if ((*i)->active ()) { - _own_latency += (*i)->latency (); + own_latency += (*i)->signal_latency (); } } - set_port_latency (_own_latency); +#undef DEBUG_LATENCY +#ifdef DEBUG_LATENCY + cerr << _name << ": internal redirect (final) latency = " << own_latency << endl; +#endif - return _own_latency; -} + _output->set_port_latency (own_latency); + + if (old != own_latency) { + _output->set_latency_delay (own_latency); + signal_latency_changed (); /* EMIT SIGNAL */ + } + return _output->effective_latency(); +} Track::FreezeRecord::~FreezeRecord () { - for (vector::iterator i = insert_info.begin(); i != insert_info.end(); ++i) { + for (vector::iterator i = processor_info.begin(); i != processor_info.end(); ++i) { delete *i; } } @@ -124,7 +124,7 @@ Track::freeze_state() const } Track::RecEnableControllable::RecEnableControllable (Track& s) - : track (s) + : Controllable (X_("recenable")), track (s) { } @@ -145,36 +145,34 @@ Track::RecEnableControllable::get_value (void) const bool Track::record_enabled () const { - return _diskstream->record_enabled (); + return _diskstream && _diskstream->record_enabled (); } bool Track::can_record() { bool will_record = true; - for (size_t i = 0; i < _inputs.size() && will_record; i++) { - if (!_inputs[i]->connected()) + for (PortSet::iterator i = _input->ports().begin(); i != _input->ports().end() && will_record; ++i) { + if (!i->connected()) will_record = false; } return will_record; } - + void Track::set_record_enable (bool yn, void *src) { - if (_freeze_record.state == Frozen) { + if (!_session.writable()) { return; } - if (_mix_group && src != _mix_group && _mix_group->is_active()) { - _mix_group->apply (&Track::set_record_enable, yn, _mix_group); + if (_freeze_record.state == Frozen) { return; } - // Do not set rec enabled if the track can't record. - if (yn && !can_record()) { - error << string_compose( _("Can not arm track '%1'. Check the input connections"), name() ) << endmsg; + if (_route_group && src != _route_group && _route_group->active_property (RouteGroup::RecEnable)) { + _route_group->apply (&Track::set_record_enable, yn, _route_group); return; } @@ -182,56 +180,171 @@ Track::set_record_enable (bool yn, void *src) if (!_diskstream->record_enabled()) { _saved_meter_point = _meter_point; } - + _diskstream->set_record_enabled (yn); if (_diskstream->record_enabled()) { - set_meter_point (MeterInput, this); + if (_meter_point != MeterCustom) { + set_meter_point (MeterInput, this); + } } else { set_meter_point (_saved_meter_point, this); } - _rec_enable_control.Changed (); + _rec_enable_control->Changed (); } -void -Track::set_mode (TrackMode m) -{ - if (_diskstream) { - if (_mode != m) { - _mode = m; - _diskstream->set_destructive (m == Destructive); - ModeChanged(); - } - } -} -int -Track::set_name (string str, void *src) +bool +Track::set_name (const string& str) { - int ret; + bool ret; if (record_enabled() && _session.actively_recording()) { /* this messes things up if done while recording */ - return -1; + return false; } if (_diskstream->set_name (str)) { - return -1; + return false; } /* save state so that the statefile fully reflects any filename changes */ - if ((ret = IO::set_name (str, src)) == 0) { + if ((ret = Route::set_name (str)) == 0) { _session.save_state (""); } + return ret; } void -Track::set_latency_delay (jack_nframes_t longest_session_latency) +Track::set_latency_delay (nframes_t longest_session_latency) { Route::set_latency_delay (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, sframes_t start_frame, sframes_t end_frame, + bool session_state_changing, bool can_record, bool /*rec_monitors_input*/) +{ + if (n_outputs().n_total() == 0) { + return 0; + } + + if (!_active) { + silence (nframes); + return 0; + } + + if (session_state_changing) { + if (_session.transport_speed() != 0.0f) { + /* we're rolling but some state is changing (e.g. our diskstream contents) + so we cannot use them. Be silent till this is over. Don't declick. + + XXX note the absurdity of ::no_roll() being called when we ARE rolling! + */ + passthru_silence (start_frame, end_frame, nframes, 0); + return 0; + } + /* we're really not rolling, so we're either delivery silence or actually + monitoring, both of which are safe to do while session_state_changing is true. + */ + } + + diskstream()->check_record_status (start_frame, nframes, can_record); + + bool send_silence; + + 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; + } 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; + } + } + } + + _amp->apply_gain_automation(false); + + if (send_silence) { + + /* if we're sending silence, but we want the meters to show levels for the signal, + meter right here. + */ + + if (_have_internal_generator) { + passthru_silence (start_frame, end_frame, nframes, 0); + } else { + if (_meter_point == MeterInput) { + _input->process_input (_meter, start_frame, end_frame, nframes); + } + passthru_silence (start_frame, end_frame, nframes, 0); + } + + } else { + + /* we're sending signal, but we may still want to meter the input. + */ + + passthru (start_frame, end_frame, nframes, false); + } + + _main_outs->flush (nframes, end_frame - start_frame - 1); + + return 0; +} + +int +Track::silent_roll (nframes_t nframes, sframes_t /*start_frame*/, sframes_t /*end_frame*/, + bool can_record, bool rec_monitors_input) +{ + if (n_outputs().n_total() == 0 && _processors.empty()) { + return 0; + } + + if (!_active) { + silence (nframes); + return 0; + } + + _silent = true; + _amp->apply_gain_automation(false); + + silence (nframes); + + return diskstream()->process (_session.transport_frame(), nframes, can_record, rec_monitors_input); +}