* refactor Session::follow_slave to be easier to read and understand
[ardour.git] / libs / ardour / diskstream.cc
index 62c3fffeb6c01ba23c5aeef7b3a4197c24f368cb..334e4336af821478b0ed76f31e97e0348513ee97 100644 (file)
@@ -15,7 +15,6 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id: diskstream.cc 567 2006-06-07 14:54:12Z trutkin $
 */
 
 #include <fstream>
@@ -38,6 +37,7 @@
 #include <pbd/basename.h>
 #include <glibmm/thread.h>
 #include <pbd/xml++.h>
+#include <pbd/memento_command.h>
 
 #include <ardour/ardour.h>
 #include <ardour/audioengine.h>
 #include <ardour/utils.h>
 #include <ardour/configuration.h>
 #include <ardour/audiofilesource.h>
-#include <ardour/destructive_filesource.h>
 #include <ardour/send.h>
 #include <ardour/playlist.h>
 #include <ardour/cycle_timer.h>
 #include <ardour/region.h>
+#include <ardour/panner.h>
 
 #include "i18n.h"
 #include <locale.h>
@@ -58,25 +58,24 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-/* XXX This goes uninitialized when there is no ~/.ardour2 directory.
+/* XXX This goes uninitialized when there is no ~/.ardour3 directory.
  * I can't figure out why, so this will do for now (just stole the
  * default from configuration_vars.h).  0 is not a good value for
  * allocating buffer sizes..
  */
-nframes_t Diskstream::disk_io_chunk_frames = 1024 * 256;
+ARDOUR::nframes_t Diskstream::disk_io_chunk_frames = 1024 * 256;
 
 sigc::signal<void>                Diskstream::DiskOverrun;
 sigc::signal<void>                Diskstream::DiskUnderrun;
 
 Diskstream::Diskstream (Session &sess, const string &name, Flag flag)
-       : _name (name)
-       , _session (sess)
+       : SessionObject(sess, name)
 {
        init (flag);
 }
        
 Diskstream::Diskstream (Session& sess, const XMLNode& node)
-       : _session (sess)
+       : SessionObject(sess, "unnamed diskstream")
 {
        init (Recordable);
 }
@@ -111,25 +110,22 @@ Diskstream::init (Flag f)
        speed_buffer_size = 0;
        last_phase = 0;
        phi = (uint64_t) (0x1000000);
+       target_phi = phi;
        file_frame = 0;
        playback_sample = 0;
        playback_distance = 0;
        _read_data_count = 0;
        _write_data_count = 0;
+       commit_should_unlock = false;
 
        pending_overwrite = false;
        overwrite_frame = 0;
        overwrite_queued = false;
        input_change_pending = NoChange;
-
-       _n_channels = 0;
 }
 
 Diskstream::~Diskstream ()
 {
-       // Taken by derived class destrctors.. should assure locked here somehow?
-       //Glib::Mutex::Lock lm (state_lock);
-
        if (_playlist)
                _playlist->release ();
 }
@@ -196,7 +192,7 @@ Diskstream::realtime_set_speed (double sp, bool global)
                }
                
                _actual_speed = new_speed;
-               phi = (uint64_t) (0x1000000 * fabs(_actual_speed));
+               target_phi = (uint64_t) (0x1000000 * fabs(_actual_speed));
        }
 
        if (changed) {
@@ -219,7 +215,9 @@ Diskstream::prepare ()
 void
 Diskstream::recover ()
 {
-       state_lock.unlock();
+       if (commit_should_unlock) {
+               state_lock.unlock();
+       }
        _processed = false;
 }
 
@@ -263,7 +261,7 @@ Diskstream::set_loop (Location *location)
        return 0;
 }
 
-nframes_t
+ARDOUR::nframes_t
 Diskstream::get_capture_start_frame (uint32_t n)
 {
        Glib::Mutex::Lock lm (capture_info_lock);
@@ -276,7 +274,7 @@ Diskstream::get_capture_start_frame (uint32_t n)
        }
 }
 
-nframes_t
+ARDOUR::nframes_t
 Diskstream::get_captured_frames (uint32_t n)
 {
        Glib::Mutex::Lock lm (capture_info_lock);
@@ -290,7 +288,7 @@ Diskstream::get_captured_frames (uint32_t n)
 }
 
 void
-Diskstream::set_roll_delay (nframes_t nframes)
+Diskstream::set_roll_delay (ARDOUR::nframes_t nframes)
 {
        _roll_delay = nframes;
 }
@@ -316,6 +314,7 @@ Diskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
 
                plmod_connection.disconnect ();
                plgone_connection.disconnect ();
+               plregion_connection.disconnect ();
 
                if (_playlist) {
                        _playlist->release();
@@ -330,9 +329,15 @@ Diskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
                
                plmod_connection = _playlist->Modified.connect (mem_fun (*this, &Diskstream::playlist_modified));
                plgone_connection = _playlist->GoingAway.connect (bind (mem_fun (*this, &Diskstream::playlist_deleted), boost::weak_ptr<Playlist>(_playlist)));
+               plregion_connection = _playlist->RangesMoved.connect (mem_fun (*this, &Diskstream::playlist_ranges_moved));
        }
 
-       if (!overwrite_queued) {
+       /* don't do this if we've already asked for it *or* if we are setting up
+          the diskstream for the very first time - the input changed handling will
+          take care of the buffer refill.
+       */
+
+       if (!overwrite_queued && !(_session.state_of_the_state() & Session::CannotSave)) {
                _session.request_overwrite_buffer (this);
                overwrite_queued = true;
        }
@@ -376,23 +381,24 @@ Diskstream::playlist_deleted (boost::weak_ptr<Playlist> wpl)
        }
 }
 
-int
-Diskstream::set_name (string str)
+bool
+Diskstream::set_name (const string& str)
 {
        if (str != _name) {
                assert(playlist());
                playlist()->set_name (str);
-               _name = str;
+               
+               SessionObject::set_name(str);
                
                if (!in_set_state && recordable()) {
                        /* rename existing capture files so that they have the correct name */
                        return rename_write_sources ();
                } else {
-                       return -1;
+                       return false;
                }
        }
 
-       return 0;
+       return true;
 }
 
 void
@@ -407,3 +413,64 @@ Diskstream::remove_region_from_last_capture (boost::weak_ptr<Region> wregion)
        _last_capture_regions.remove (region);
 }
 
+void
+Diskstream::playlist_ranges_moved (Evoral::RangeMoveList const & movements)
+{
+       if (Config->get_automation_follows_regions () == false) {
+               return;
+       }
+       
+       /* move gain automation */
+       boost::shared_ptr<AutomationList> gain_alist = _io->gain_control()->alist();
+       XMLNode & before = gain_alist->get_state ();
+       gain_alist->move_ranges (movements);
+       _session.add_command (
+               new MementoCommand<AutomationList> (
+                       *gain_alist.get(), &before, &gain_alist->get_state ()
+                       )
+               );
+       
+       /* move panner automation */
+       Panner & p = _io->panner ();
+       for (uint32_t i = 0; i < p.npanners (); ++i) {
+
+               boost::shared_ptr<AutomationList> pan_alist = p.streampanner(i).pan_control()->alist();
+               XMLNode & before = pan_alist->get_state ();
+               pan_alist->move_ranges (movements);
+               _session.add_command (
+                       new MementoCommand<AutomationList> (
+                               *pan_alist.get(), &before, &pan_alist->get_state ()
+                               )
+                       );
+       }
+
+       /* move processor automation */
+       /* XXX: ewww */
+       Route * route = dynamic_cast<Route*> (_io);
+       if (route) {
+               route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &Diskstream::move_processor_automation), movements));
+       }
+}
+
+void
+Diskstream::move_processor_automation (boost::weak_ptr<Processor> p, Evoral::RangeMoveList const & movements)
+{
+       boost::shared_ptr<Processor> processor (p.lock ());
+       if (!processor) {
+               return;
+       }
+       
+       set<Evoral::Parameter> const a = processor->what_can_be_automated ();
+
+       for (set<Evoral::Parameter>::iterator i = a.begin (); i != a.end (); ++i) {
+               boost::shared_ptr<AutomationList> al = processor->automation_control(*i)->alist();
+               XMLNode & before = al->get_state ();
+               al->move_ranges (movements);
+               _session.add_command (
+                       new MementoCommand<AutomationList> (
+                               *al.get(), &before, &al->get_state ()
+                               )
+                       );
+       }
+}
+