provide support for playhead-to-next/previous-region-boundary actions, and bindings...
[ardour.git] / libs / ardour / diskstream.cc
index a9a5c6ce075ec9825d2655fd0fd001fa0a21d655..2a307b1f31eec914132f33232b2bb221b3d63d3c 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>
@@ -32,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>
@@ -43,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>
@@ -56,24 +56,25 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-jack_nframes_t Diskstream::disk_io_chunk_frames = 0;
+/* 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..
+ */
+nframes_t Diskstream::disk_io_chunk_frames = 1024 * 256;
 
-sigc::signal<void,Diskstream*>    Diskstream::DiskstreamCreated;
-sigc::signal<void,list<Source*>*> Diskstream::DeleteSources;
 sigc::signal<void>                Diskstream::DiskOverrun;
 sigc::signal<void>                Diskstream::DiskUnderrun;
 
 Diskstream::Diskstream (Session &sess, const string &name, Flag flag)
        : _name (name)
        , _session (sess)
-       , _playlist(NULL)
 {
        init (flag);
 }
        
 Diskstream::Diskstream (Session& sess, const XMLNode& node)
        : _session (sess)
-       , _playlist(NULL)
 {
        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;
@@ -109,11 +109,13 @@ 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;
@@ -125,11 +127,8 @@ Diskstream::init (Flag f)
 
 Diskstream::~Diskstream ()
 {
-       // Taken by derived class destrctors.. should assure locked here somehow?
-       //Glib::Mutex::Lock lm (state_lock);
-
        if (_playlist)
-               _playlist->unref ();
+               _playlist->release ();
 }
 
 void
@@ -153,8 +152,7 @@ Diskstream::handle_input_change (IOChange change, void *src)
 void
 Diskstream::non_realtime_set_speed ()
 {
-       if (_buffer_reallocation_required)
-       {
+       if (_buffer_reallocation_required) {
                Glib::Mutex::Lock lm (state_lock);
                allocate_temporary_buffers ();
 
@@ -163,7 +161,7 @@ Diskstream::non_realtime_set_speed ()
 
        if (_seek_required) {
                if (speed() != 1.0f || speed() != -1.0f) {
-                       seek ((jack_nframes_t) (_session.transport_frame() * (double) speed()), true);
+                       seek ((nframes_t) (_session.transport_frame() * (double) speed()), true);
                }
                else {
                        seek (_session.transport_frame(), true);
@@ -186,7 +184,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) {
@@ -194,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) {
@@ -217,7 +215,9 @@ Diskstream::prepare ()
 void
 Diskstream::recover ()
 {
-       state_lock.unlock();
+       if (commit_should_unlock) {
+               state_lock.unlock();
+       }
        _processed = false;
 }
 
@@ -261,7 +261,7 @@ Diskstream::set_loop (Location *location)
        return 0;
 }
 
-jack_nframes_t
+nframes_t
 Diskstream::get_capture_start_frame (uint32_t n)
 {
        Glib::Mutex::Lock lm (capture_info_lock);
@@ -274,7 +274,7 @@ Diskstream::get_capture_start_frame (uint32_t n)
        }
 }
 
-jack_nframes_t
+nframes_t
 Diskstream::get_captured_frames (uint32_t n)
 {
        Glib::Mutex::Lock lm (capture_info_lock);
@@ -288,7 +288,7 @@ Diskstream::get_captured_frames (uint32_t n)
 }
 
 void
-Diskstream::set_roll_delay (jack_nframes_t nframes)
+Diskstream::set_roll_delay (nframes_t nframes)
 {
        _roll_delay = nframes;
 }
@@ -303,7 +303,7 @@ Diskstream::set_speed (double sp)
 }
 
 int
-Diskstream::use_playlist (Playlist* playlist)
+Diskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
 {
        {
                Glib::Mutex::Lock lm (state_lock);
@@ -312,27 +312,30 @@ Diskstream::use_playlist (Playlist* playlist)
                        return 0;
                }
 
-               plstate_connection.disconnect();
                plmod_connection.disconnect ();
                plgone_connection.disconnect ();
 
                if (_playlist) {
-                       _playlist->unref();
+                       _playlist->release();
                }
                        
                _playlist = playlist;
-               _playlist->ref();
+               _playlist->use();
 
                if (!in_set_state && recordable()) {
                        reset_write_sources (false);
                }
                
-               plstate_connection = _playlist->StateChanged.connect (mem_fun (*this, &Diskstream::playlist_changed));
                plmod_connection = _playlist->Modified.connect (mem_fun (*this, &Diskstream::playlist_modified));
-               plgone_connection = _playlist->GoingAway.connect (mem_fun (*this, &Diskstream::playlist_deleted));
+               plgone_connection = _playlist->GoingAway.connect (bind (mem_fun (*this, &Diskstream::playlist_deleted), boost::weak_ptr<Playlist>(_playlist)));
        }
 
-       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;
        }
@@ -359,14 +362,21 @@ Diskstream::playlist_modified ()
 }
 
 void
-Diskstream::playlist_deleted (Playlist* pl)
+Diskstream::playlist_deleted (boost::weak_ptr<Playlist> wpl)
 {
-       /* this catches an ordering issue with session destruction. playlists 
-          are destroyed before diskstreams. we have to invalidate any handles
-          we have to the playlist.
-       */
+       boost::shared_ptr<Playlist> pl (wpl.lock());
 
-       _playlist = 0;
+       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
@@ -389,14 +399,14 @@ Diskstream::set_name (string str)
 }
 
 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);
 }
+