X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Faudio_track.cc;h=878ad1118fdfc6127decdb0bccb6204a536dae61;hb=015fc7b39fab97cee1875231694adce43155ceb5;hp=9154747152816664be06b12d25cbc53ca4336f0a;hpb=d469cc3e3a536fceedbfc41e52ad3d7d178f7b0d;p=ardour.git diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc index 9154747152..878ad1118f 100644 --- a/libs/ardour/audio_track.cc +++ b/libs/ardour/audio_track.cc @@ -21,25 +21,28 @@ #include #include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "pbd/error.h" +#include "pbd/enumwriter.h" + +#include "evoral/Curve.hpp" + +#include "ardour/amp.h" +#include "ardour/audio_buffer.h" +#include "ardour/audio_diskstream.h" +#include "ardour/audio_track.h" +#include "ardour/audioplaylist.h" +#include "ardour/audioregion.h" +#include "ardour/audiosource.h" +#include "ardour/buffer_set.h" +#include "ardour/io_processor.h" +#include "ardour/panner.h" +#include "ardour/playlist_factory.h" +#include "ardour/plugin_insert.h" +#include "ardour/processor.h" +#include "ardour/region_factory.h" +#include "ardour/route_group_specialized.h" +#include "ardour/session.h" +#include "ardour/utils.h" #include "i18n.h" using namespace std; @@ -48,6 +51,22 @@ using namespace PBD; AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode mode) : Track (sess, name, flag, mode) +{ + use_new_diskstream (); +} + +AudioTrack::AudioTrack (Session& sess, const XMLNode& node) + : Track (sess, node) +{ + _set_state (node, false); +} + +AudioTrack::~AudioTrack () +{ +} + +void +AudioTrack::use_new_diskstream () { AudioDiskstream::Flag dflags = AudioDiskstream::Flag (0); @@ -57,27 +76,20 @@ AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode dflags = AudioDiskstream::Flag (dflags | AudioDiskstream::Recordable); } - if (mode == Destructive) { + if (_mode == Destructive) { dflags = AudioDiskstream::Flag (dflags | AudioDiskstream::Destructive); + } else if (_mode == NonLayered){ + dflags = AudioDiskstream::Flag(dflags | AudioDiskstream::NonLayered); } + - boost::shared_ptr ds (new AudioDiskstream (_session, name, dflags)); + boost::shared_ptr ds (new AudioDiskstream (_session, name(), dflags)); _session.add_diskstream (ds); set_diskstream (boost::dynamic_pointer_cast (ds), this); } -AudioTrack::AudioTrack (Session& sess, const XMLNode& node) - : Track (sess, node) -{ - _set_state (node, false); -} - -AudioTrack::~AudioTrack () -{ -} - int AudioTrack::set_mode (TrackMode m) { @@ -86,7 +98,8 @@ AudioTrack::set_mode (TrackMode m) if (_diskstream->set_destructive (m == Destructive)) { return -1; } - + + _diskstream->set_non_layered (m == NonLayered); _mode = m; TrackModeChanged (); /* EMIT SIGNAL */ @@ -99,6 +112,7 @@ bool AudioTrack::can_use_mode (TrackMode m, bool& bounce_required) { switch (m) { + case NonLayered: case Normal: bounce_required = false; return true; @@ -132,7 +146,7 @@ AudioTrack::deprecated_use_diskstream_connections () if ((prop = node.property ("gain")) != 0) { set_gain (atof (prop->value().c_str()), this); - _gain = _desired_gain; + _gain = _gain_control->user_float(); } if ((prop = node.property ("input-connection")) != 0) { @@ -169,6 +183,7 @@ AudioTrack::set_diskstream (boost::shared_ptr ds, void *src) _diskstream = ds; _diskstream->set_io (*this); _diskstream->set_destructive (_mode == Destructive); + _diskstream->set_non_layered (_mode == NonLayered); if (audio_diskstream()->deprecated_io_node) { @@ -263,8 +278,19 @@ AudioTrack::_set_state (const XMLNode& node, bool call_base) } else { PBD::ID id (prop->value()); + PBD::ID zero ("0"); + + /* this wierd hack is used when creating tracks from a template. there isn't + a particularly good time to interpose between setting the first part of + the track state (notably Route::set_state() and the track mode), and the + second part (diskstream stuff). So, we have a special ID for the diskstream + that means "you should create a new diskstream here, not look for + an old one. + */ - if (use_diskstream (id)) { + if (id == zero) { + use_new_diskstream (); + } else if (use_diskstream (id)) { return -1; } } @@ -286,7 +312,11 @@ AudioTrack::_set_state (const XMLNode& node, bool call_base) pending_state = const_cast (&node); - _session.StateReady.connect (mem_fun (*this, &AudioTrack::set_state_part_two)); + if (_session.state_of_the_state() & Session::Loading) { + _session.StateReady.connect (mem_fun (*this, &AudioTrack::set_state_part_two)); + } else { + set_state_part_two (); + } return 0; } @@ -319,7 +349,7 @@ AudioTrack::state(bool full_state) /* Alignment: act as a proxy for the diskstream */ - XMLNode* align_node = new XMLNode (X_("alignment")); + XMLNode* align_node = new XMLNode (X_("Alignment")); AlignStyle as = _diskstream->alignment_style (); align_node->add_property (X_("style"), enum_2_string (as)); root.add_child_nocopy (*align_node); @@ -357,8 +387,6 @@ AudioTrack::set_state_part_two () if ((fnode = find_named_node (*pending_state, X_("freeze-info"))) != 0) { - - _freeze_record.have_mementos = false; _freeze_record.state = Frozen; for (vector::iterator i = _freeze_record.processor_info.begin(); i != _freeze_record.processor_info.end(); ++i) { @@ -402,7 +430,7 @@ AudioTrack::set_state_part_two () /* Alignment: act as a proxy for the diskstream */ - if ((fnode = find_named_node (*pending_state, X_("alignment"))) != 0) { + if ((fnode = find_named_node (*pending_state, X_("Alignment"))) != 0) { if ((prop = fnode->property (X_("style"))) != 0) { @@ -425,93 +453,8 @@ AudioTrack::set_state_part_two () return; } -int -AudioTrack::no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset, - bool session_state_changing, bool can_record, bool rec_monitors_input) -{ - if (n_outputs().n_total() == 0) { - return 0; - } - - if (!_active) { - silence (nframes, offset); - return 0; - } - - if (session_state_changing) { - - /* XXX is this safe to do against transport state changes? */ - - passthru_silence (start_frame, end_frame, nframes, offset, 0, false); - return 0; - } - - audio_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) && (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; - } - } - } - - 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, offset, 0, true); - } else { - if (_meter_point == MeterInput) { - just_meter_input (start_frame, end_frame, nframes, offset); - } - passthru_silence (start_frame, end_frame, nframes, offset, 0, false); - } - - } else { - - /* we're sending signal, but we may still want to meter the input. - */ - - passthru (start_frame, end_frame, nframes, offset, 0, (_meter_point == MeterInput)); - } - - return 0; -} - int -AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset, int declick, +AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick, bool can_record, bool rec_monitors_input) { int dret; @@ -535,45 +478,44 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, } if (!_active) { - silence (nframes, offset); + silence (nframes); return 0; } transport_frame = _session.transport_frame(); - prepare_inputs( nframes, offset ); + prepare_inputs (nframes); + + if ((nframes = check_initial_delay (nframes, transport_frame)) == 0) { - if ((nframes = check_initial_delay (nframes, offset, transport_frame)) == 0) { /* need to do this so that the diskstream sets its playback distance to zero, thus causing diskstream::commit to do nothing. */ - return diskstream->process (transport_frame, 0, 0, can_record, rec_monitors_input); + return diskstream->process (transport_frame, 0, can_record, rec_monitors_input); } _silent = false; - apply_gain_automation = false; - - if ((dret = diskstream->process (transport_frame, nframes, offset, can_record, rec_monitors_input)) != 0) { - - silence (nframes, offset); + _amp->apply_gain_automation(false); + if ((dret = diskstream->process (transport_frame, nframes, can_record, rec_monitors_input)) != 0) { + silence (nframes); return dret; } /* special condition applies */ if (_meter_point == MeterInput) { - just_meter_input (start_frame, end_frame, nframes, offset); + just_meter_input (start_frame, end_frame, nframes); } - if (diskstream->record_enabled() && !can_record && !Config->get_auto_input()) { + if (diskstream->record_enabled() && !can_record && !_session.config.get_auto_input()) { /* not actually recording, but we want to hear the input material anyway, at least potentially (depending on monitoring options) */ - passthru (start_frame, end_frame, nframes, offset, 0, true); + passthru (start_frame, end_frame, nframes, false); } else if ((b = diskstream->playback_buffer(0)) != 0) { @@ -665,50 +607,28 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK); if (am.locked() && gain_control()->automation_playback()) { - apply_gain_automation = gain_control()->list()->curve().rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes); + _amp->apply_gain_automation( + gain_control()->list()->curve().rt_safe_get_vector ( + start_frame, end_frame, _session.gain_automation_buffer(), nframes)); } } - process_output_buffers (bufs, start_frame, end_frame, nframes, offset, (!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick, (_meter_point != MeterInput)); + process_output_buffers (bufs, start_frame, end_frame, nframes, (!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick); } else { /* problem with the diskstream; just be quiet for a bit */ - silence (nframes, offset); + silence (nframes); } return 0; } int -AudioTrack::silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset, - bool can_record, bool rec_monitors_input) -{ - if (n_outputs().n_total() == 0 && _processors.empty()) { - return 0; - } - - if (!_active) { - silence (nframes, offset); - return 0; - } - - _silent = true; - apply_gain_automation = false; - - silence (nframes, offset); - - return audio_diskstream()->process (_session.transport_frame() + offset, nframes, offset, can_record, rec_monitors_input); -} - -int -AudioTrack::export_stuff (BufferSet& buffers, nframes_t start, nframes_t nframes) +AudioTrack::export_stuff (BufferSet& buffers, sframes_t start, nframes_t nframes, bool enable_processing) { - gain_t gain_automation[nframes]; gain_t gain_buffer[nframes]; float mix_buffer[nframes]; ProcessorList::iterator i; - bool post_fader_work = false; - gain_t this_gain = _gain; boost::shared_ptr diskstream = audio_diskstream(); Glib::RWLock::ReaderLock rlock (_processor_lock); @@ -740,6 +660,10 @@ AudioTrack::export_stuff (BufferSet& buffers, nframes_t start, nframes_t nframes } } + // If no processing is required, there's no need to go any further. + if (!enable_processing) { + return 0; + } /* note: only run processors during export. other layers in the machinery will already have checked that there are no external port processors. @@ -747,57 +671,11 @@ AudioTrack::export_stuff (BufferSet& buffers, nframes_t start, nframes_t nframes for (i = _processors.begin(); i != _processors.end(); ++i) { boost::shared_ptr processor; - if ((processor = boost::dynamic_pointer_cast(*i)) != 0) { - switch (processor->placement()) { - case PreFader: - processor->run_in_place (buffers, start, start+nframes, nframes, 0); - break; - case PostFader: - post_fader_work = true; - break; - } + processor->run_in_place (buffers, start, start+nframes, nframes); } } - if (gain_control()->automation_state() == Play) { - - gain_control()->list()->curve().get_vector (start, start + nframes, gain_automation, nframes); - - for (BufferSet::audio_iterator bi = buffers.audio_begin(); bi != buffers.audio_end(); ++bi) { - Sample *b = bi->data(); - for (nframes_t n = 0; n < nframes; ++n) { - b[n] *= gain_automation[n]; - } - } - - } else { - - for (BufferSet::audio_iterator bi = buffers.audio_begin(); bi != buffers.audio_end(); ++bi) { - Sample *b = bi->data(); - for (nframes_t n = 0; n < nframes; ++n) { - b[n] *= this_gain; - } - } - } - - if (post_fader_work) { - - for (i = _processors.begin(); i != _processors.end(); ++i) { - boost::shared_ptr processor; - - if ((processor = boost::dynamic_pointer_cast(*i)) != 0) { - switch ((*i)->placement()) { - case PreFader: - break; - case PostFader: - processor->run_in_place (buffers, start, start+nframes, nframes, 0); - break; - } - } - } - } - return 0; } @@ -809,10 +687,10 @@ AudioTrack::bounce (InterThreadInfo& itt) } boost::shared_ptr -AudioTrack::bounce_range (nframes_t start, nframes_t end, InterThreadInfo& itt) +AudioTrack::bounce_range (nframes_t start, nframes_t end, InterThreadInfo& itt, bool enable_processing) { vector > srcs; - return _session.write_one_track (*this, start, end, false, srcs, itt); + return _session.write_one_track (*this, start, end, false, srcs, itt, enable_processing); } void @@ -860,7 +738,6 @@ AudioTrack::freeze (InterThreadInfo& itt) } _freeze_record.processor_info.clear (); - _freeze_record.have_mementos = true; { Glib::RWLock::ReaderLock lm (_processor_lock); @@ -895,10 +772,11 @@ AudioTrack::freeze (InterThreadInfo& itt) /* create a new region from all filesources, keep it private */ - boost::shared_ptr region (RegionFactory::create (srcs, 0, srcs[0]->length(), - region_name, 0, - (Region::Flag) (Region::WholeFile|Region::DefaultFlags), - false)); + boost::shared_ptr region (RegionFactory::create (srcs, 0, + srcs[0]->length(srcs[0]->timeline_position()), + region_name, 0, + (Region::Flag) (Region::WholeFile|Region::DefaultFlags), + false)); new_playlist->set_orig_diskstream_id (diskstream->id()); new_playlist->add_region (region, _session.current_start_frame()); @@ -924,14 +802,7 @@ AudioTrack::unfreeze () if (_freeze_record.playlist) { audio_diskstream()->use_playlist (_freeze_record.playlist); - if (_freeze_record.have_mementos) { - - for (vector::iterator i = _freeze_record.processor_info.begin(); i != _freeze_record.processor_info.end(); ++i) { - (*i)->memento (); - } - - } else { - + { Glib::RWLock::ReaderLock lm (_processor_lock); // should this be a write lock? jlc for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { for (vector::iterator ii = _freeze_record.processor_info.begin(); ii != _freeze_record.processor_info.end(); ++ii) {