First stage of options rework.
[ardour.git] / libs / ardour / audio_track.cc
index 9154747152816664be06b12d25cbc53ca4336f0a..878ad1118fdfc6127decdb0bccb6204a536dae61 100644 (file)
 #include <sigc++/retype_return.h>
 #include <sigc++/bind.h>
 
-#include <pbd/error.h>
-#include <pbd/enumwriter.h>
-
-#include <ardour/audio_track.h>
-#include <ardour/audio_diskstream.h>
-#include <ardour/session.h>
-#include <ardour/io_processor.h>
-#include <ardour/audioregion.h>
-#include <ardour/audiosource.h>
-#include <ardour/region_factory.h>
-#include <ardour/route_group_specialized.h>
-#include <ardour/processor.h>
-#include <ardour/plugin_insert.h>
-#include <ardour/audioplaylist.h>
-#include <ardour/playlist_factory.h>
-#include <ardour/panner.h>
-#include <ardour/utils.h>
-#include <ardour/buffer_set.h>
-#include <ardour/audio_buffer.h>
+#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<AudioDiskstream> ds (new AudioDiskstream (_session, name, dflags));
+       boost::shared_ptr<AudioDiskstream> ds (new AudioDiskstream (_session, name(), dflags));
        
        _session.add_diskstream (ds);
 
        set_diskstream (boost::dynamic_pointer_cast<AudioDiskstream> (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<AudioDiskstream> 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<XMLNode*> (&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<FreezeRecordProcessorInfo*>::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<AudioDiskstream> 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> processor;
-               
                if ((processor = boost::dynamic_pointer_cast<Processor>(*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<PluginInsert> processor;
-                       
-                       if ((processor = boost::dynamic_pointer_cast<PluginInsert>(*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<Region>
-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<boost::shared_ptr<Source> > 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> region (RegionFactory::create (srcs, 0, srcs[0]->length(), 
-                                                                region_name, 0, 
-                                                                (Region::Flag) (Region::WholeFile|Region::DefaultFlags),
-                                                                false));
+       boost::shared_ptr<Region> 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<FreezeRecordProcessorInfo*>::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<FreezeRecordProcessorInfo*>::iterator ii = _freeze_record.processor_info.begin(); ii != _freeze_record.processor_info.end(); ++ii) {