Use PBD::copy_file in Session::create() to copy the template file.
[ardour.git] / libs / ardour / diskstream.cc
index 8b7edae6b43d336e606c5d9ba316c58df2b55d63..18aeb329310bd7b739fb9e0862e7811b12fb2c5b 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2000-2003 Paul Davis 
+    Copyright (C) 2000-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
     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>
+#include <cassert>
 #include <cstdio>
 #include <unistd.h>
 #include <cmath>
@@ -31,6 +31,8 @@
 #include <sys/stat.h>
 #include <sys/mman.h>
 
+#include <sigc++/bind.h>
+
 #include <pbd/error.h>
 #include <pbd/basename.h>
 #include <glibmm/thread.h>
@@ -42,7 +44,6 @@
 #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>
@@ -55,25 +56,25 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-jack_nframes_t Diskstream::disk_io_chunk_frames;
+/* XXX This goes uninitialized when there is no ~/.ardour2 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..
+ */
+ARDOUR::nframes_t Diskstream::disk_io_chunk_frames = 1024 * 256;
 
-sigc::signal<void,Diskstream*>    Diskstream::DiskstreamCreated;
-//sigc::signal<void,list<AudioFileSource*>*> Diskstream::DeleteSources;
 sigc::signal<void>                Diskstream::DiskOverrun;
 sigc::signal<void>                Diskstream::DiskUnderrun;
 
 Diskstream::Diskstream (Session &sess, const string &name, Flag flag)
-       : deprecated_io_node(NULL)
-       , _name (name)
+       : _name (name)
        , _session (sess)
 {
        init (flag);
 }
        
 Diskstream::Diskstream (Session& sess, const XMLNode& node)
-       : deprecated_io_node(NULL)
-       , _session (sess)
-       
+       : _session (sess)
 {
        init (Recordable);
 }
@@ -81,7 +82,6 @@ Diskstream::Diskstream (Session& sess, const XMLNode& node)
 void
 Diskstream::init (Flag f)
 {
-       _refcnt = 0;
        _flags = f;
        _io = 0;
        _alignment_style = ExistingMaterial;
@@ -114,39 +114,25 @@ Diskstream::init (Flag f)
        playback_distance = 0;
        _read_data_count = 0;
        _write_data_count = 0;
-       deprecated_io_node = 0;
-
-       /* there are no channels at this point, so these
-          two calls just get speed_buffer_size and wrap_buffer
-          size setup without duplicating their code.
-       */
-
-       //set_block_size (_session.get_block_size());
-       //allocate_temporary_buffers ();
+       commit_should_unlock = false;
 
        pending_overwrite = false;
        overwrite_frame = 0;
        overwrite_queued = false;
        input_change_pending = NoChange;
-
-       //add_channel ();
-       _n_channels = 0;//1;
 }
 
 Diskstream::~Diskstream ()
 {
-       // Taken by child.. assure lock?
-       //Glib::Mutex::Lock lm (state_lock);
-
-       //if (_playlist) {
-       //      _playlist->unref ();
-       //}
+       if (_playlist)
+               _playlist->release ();
+}
 
-       //for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
-       //      destroy_channel((*chan));
-       //}
-       
-       //channels.clear();
+void
+Diskstream::set_io (IO& io)
+{
+       _io = &io;
+       set_align_style_from_io ();
 }
 
 void
@@ -160,6 +146,29 @@ Diskstream::handle_input_change (IOChange change, void *src)
        }
 }
 
+void
+Diskstream::non_realtime_set_speed ()
+{
+       if (_buffer_reallocation_required)
+       {
+               Glib::Mutex::Lock lm (state_lock);
+               allocate_temporary_buffers ();
+
+               _buffer_reallocation_required = false;
+       }
+
+       if (_seek_required) {
+               if (speed() != 1.0f || speed() != -1.0f) {
+                       seek ((nframes_t) (_session.transport_frame() * (double) speed()), true);
+               }
+               else {
+                       seek (_session.transport_frame(), true);
+               }
+
+               _seek_required = false;
+       }
+}
+
 bool
 Diskstream::realtime_set_speed (double sp, bool global)
 {
@@ -173,7 +182,7 @@ Diskstream::realtime_set_speed (double sp, bool global)
        
        if (new_speed != _actual_speed) {
                
-               jack_nframes_t required_wrap_size = (jack_nframes_t) floor (_session.get_block_size() * 
+               nframes_t required_wrap_size = (nframes_t) floor (_session.get_block_size() * 
                                                                            fabs (new_speed)) + 1;
                
                if (required_wrap_size > wrap_buffer_size) {
@@ -188,7 +197,7 @@ Diskstream::realtime_set_speed (double sp, bool global)
                if (!global) {
                        _seek_required = true;
                }
-                speed_changed (); /* EMIT SIGNAL */
+               SpeedChanged (); /* EMIT SIGNAL */
        }
 
        return _buffer_reallocation_required || _seek_required;
@@ -204,7 +213,9 @@ Diskstream::prepare ()
 void
 Diskstream::recover ()
 {
-       state_lock.unlock();
+       if (commit_should_unlock) {
+               state_lock.unlock();
+       }
        _processed = false;
 }
 
@@ -226,7 +237,6 @@ Diskstream::set_align_style (AlignStyle a)
                return;
        }
 
-
        if (a != _alignment_style) {
                _alignment_style = a;
                AlignmentStyleChanged ();
@@ -249,7 +259,7 @@ Diskstream::set_loop (Location *location)
        return 0;
 }
 
-jack_nframes_t
+ARDOUR::nframes_t
 Diskstream::get_capture_start_frame (uint32_t n)
 {
        Glib::Mutex::Lock lm (capture_info_lock);
@@ -262,7 +272,7 @@ Diskstream::get_capture_start_frame (uint32_t n)
        }
 }
 
-jack_nframes_t
+ARDOUR::nframes_t
 Diskstream::get_captured_frames (uint32_t n)
 {
        Glib::Mutex::Lock lm (capture_info_lock);
@@ -276,7 +286,7 @@ Diskstream::get_captured_frames (uint32_t n)
 }
 
 void
-Diskstream::set_roll_delay (jack_nframes_t nframes)
+Diskstream::set_roll_delay (ARDOUR::nframes_t nframes)
 {
        _roll_delay = nframes;
 }
@@ -290,6 +300,50 @@ Diskstream::set_speed (double sp)
        playlist_modified();
 }
 
+int
+Diskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
+{
+       {
+               Glib::Mutex::Lock lm (state_lock);
+
+               if (playlist == _playlist) {
+                       return 0;
+               }
+
+               plmod_connection.disconnect ();
+               plgone_connection.disconnect ();
+
+               if (_playlist) {
+                       _playlist->release();
+               }
+                       
+               _playlist = playlist;
+               _playlist->use();
+
+               if (!in_set_state && recordable()) {
+                       reset_write_sources (false);
+               }
+               
+               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)));
+       }
+
+       /* 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;
+       }
+       
+       PlaylistChanged (); /* EMIT SIGNAL */
+       _session.set_dirty ();
+
+       return 0;
+}
+
 void
 Diskstream::playlist_changed (Change ignored)
 {
@@ -305,8 +359,26 @@ Diskstream::playlist_modified ()
        } 
 }
 
+void
+Diskstream::playlist_deleted (boost::weak_ptr<Playlist> wpl)
+{
+       boost::shared_ptr<Playlist> pl (wpl.lock());
+
+       if (pl == _playlist) {
+
+               /* this catches an ordering issue with session destruction. playlists 
+                  are destroyed before diskstreams. we have to invalidate any handles
+                  we have to the playlist.
+               */
+               
+               if (_playlist) {
+                       _playlist.reset ();
+               } 
+       }
+}
+
 int
-Diskstream::set_name (string str, void *src)
+Diskstream::set_name (string str)
 {
        if (str != _name) {
                assert(playlist());
@@ -325,14 +397,14 @@ Diskstream::set_name (string str, void *src)
 }
 
 void
-Diskstream::set_destructive (bool yn)
+Diskstream::remove_region_from_last_capture (boost::weak_ptr<Region> wregion)
 {
-       if (yn != destructive()) {
-               reset_write_sources (true, true);
-               if (yn) {
-                       _flags |= Destructive;
-               } else {
-                       _flags &= ~Destructive;
-               }
+       boost::shared_ptr<Region> region (wregion.lock());
+
+       if (!region) {
+               return;
        }
+       
+       _last_capture_regions.remove (region);
 }
+