don't do system reads beyond the apparent data end of a file; single region for destr...
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 17 Feb 2006 16:03:04 +0000 (16:03 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Fri, 17 Feb 2006 16:03:04 +0000 (16:03 +0000)
git-svn-id: svn://localhost/trunk/ardour2@337 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/ardour/ardour/diskstream.h
libs/ardour/diskstream.cc
libs/ardour/filesource.cc

index 007f5282d082124600668e5cbae9511e06f8e81e..69ade5b170fb76f537578fb9a915a8a3f5dbeccb 100644 (file)
@@ -436,11 +436,9 @@ class DiskStream : public Stateful, public sigc::trackable
        int use_pending_capture_data (XMLNode& node);
 
        void get_input_sources ();
-       
        void check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record);
-
        void set_align_style_from_io();
-
+       void setup_destructive_playlist ();
 };
 
 }; /* namespace ARDOUR */
index 1dc9d74aa4cd681daf8f936c031df5bb9003c69d..2a2ab3aa62983d33e10d08ca97c6b6cbaf284a7f 100644 (file)
@@ -406,7 +406,17 @@ DiskStream::use_new_playlist ()
 
        if ((playlist = new AudioPlaylist (_session, newname, hidden())) != 0) {
                playlist->set_orig_diskstream_id (id());
-               return use_playlist (playlist);
+
+               if (use_playlist (playlist)) {
+                       return -1;
+               }
+
+               if (destructive()) {
+                       setup_destructive_playlist ();
+               }
+
+               return 0;
+
        } else { 
                return -1;
        }
@@ -433,6 +443,25 @@ DiskStream::use_copy_playlist ()
        }
 }
 
+void
+DiskStream::setup_destructive_playlist ()
+{
+       AudioRegion::SourceList srcs;
+
+       /* make sure we have sources for every channel */
+
+       reset_write_sources (true);
+
+       for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
+               srcs.push_back ((*chan).write_source);
+       }
+
+       /* a single full-sized region */
+
+       AudioRegion* region = new AudioRegion (srcs, 0, max_frames, _name);
+       _playlist->add_region (*region, 0);             
+}
+
 void
 DiskStream::set_io (IO& io)
 {
@@ -1719,62 +1748,78 @@ DiskStream::transport_stopped (struct tm& when, time_t twhen, bool abort_capture
                }
        }
 
-       /* Register a new region with the Session that
-          describes the entire source. Do this first
-          so that any sub-regions will obviously be
-          children of this one (later!)
-       */
-
-       try {
-               region = new AudioRegion (srcs, channels[0].write_source->last_capture_start_frame(), total_capture, 
-                                         region_name_from_path (channels[0].write_source->name()), 
-                                         0, AudioRegion::Flag (AudioRegion::DefaultFlags|AudioRegion::Automatic|AudioRegion::WholeFile));
-
-               region->special_set_position (capture_info.front()->start);
-       }
-       
-       catch (failed_constructor& err) {
-               error << string_compose(_("%1: could not create region for complete audio file"), _name) << endmsg;
-               /* XXX what now? */
-       }
-
-       _last_capture_regions.push_back (region);
+       /* destructive tracks have a single, never changing region */
 
-       // cerr << _name << ": there are " << capture_info.size() << " capture_info records\n";
+       if (destructive()) {
 
-       _session.add_undo (_playlist->get_memento());
-       _playlist->freeze ();
+               /* send a signal that any UI can pick up to do the right thing. there is 
+                  a small problem here in that a UI may need the peak data to be ready
+                  for the data that was recorded and this isn't interlocked with that
+                  process. this problem is deferred to the UI.
+                */
                
-       for (buffer_position = channels[0].write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
+               _playlist->Modified();
 
-               string region_name;
-               _session.region_name (region_name, _name, false);
-
-               // cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add a region\n";
+       } else {
 
+               /* Register a new region with the Session that
+                  describes the entire source. Do this first
+                  so that any sub-regions will obviously be
+                  children of this one (later!)
+               */
+               
                try {
-                       region = new AudioRegion (srcs, buffer_position, (*ci)->frames, region_name);
+                       region = new AudioRegion (srcs, channels[0].write_source->last_capture_start_frame(), total_capture, 
+                                                 region_name_from_path (channels[0].write_source->name()), 
+                                                 0, AudioRegion::Flag (AudioRegion::DefaultFlags|AudioRegion::Automatic|AudioRegion::WholeFile));
+                       
+                       region->special_set_position (capture_info.front()->start);
                }
                
+               
                catch (failed_constructor& err) {
-                       error << _("DiskStream: could not create region for captured audio!") << endmsg;
-                       continue; /* XXX is this OK? */
+                       error << string_compose(_("%1: could not create region for complete audio file"), _name) << endmsg;
+                       /* XXX what now? */
                }
-
-               _last_capture_regions.push_back (region);
                
-               // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl;
+               _last_capture_regions.push_back (region);
 
-               i_am_the_modifier++;
-               _playlist->add_region (*region, (*ci)->start);
-               i_am_the_modifier--;
+               // cerr << _name << ": there are " << capture_info.size() << " capture_info records\n";
+               
+               _session.add_undo (_playlist->get_memento());
+               _playlist->freeze ();
+               
+               for (buffer_position = channels[0].write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
+                       
+                       string region_name;
+                       _session.region_name (region_name, _name, false);
+                       
+                       // cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add a region\n";
+                       
+                       try {
+                               region = new AudioRegion (srcs, buffer_position, (*ci)->frames, region_name);
+                       }
+                       
+                       catch (failed_constructor& err) {
+                               error << _("DiskStream: could not create region for captured audio!") << endmsg;
+                               continue; /* XXX is this OK? */
+                       }
+                       
+                       _last_capture_regions.push_back (region);
+                       
+                       // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl;
+                       
+                       i_am_the_modifier++;
+                       _playlist->add_region (*region, (*ci)->start);
+                       i_am_the_modifier--;
+                       
+                       buffer_position += (*ci)->frames;
+               }
 
-               buffer_position += (*ci)->frames;
+               _playlist->thaw ();
+               _session.add_redo_no_execute (_playlist->get_memento());
        }
 
-       _playlist->thaw ();
-       _session.add_redo_no_execute (_playlist->get_memento());
-
        mark_write_completed = true;
 
        reset_write_sources (mark_write_completed);
@@ -1812,7 +1857,7 @@ DiskStream::finish_capture (bool rec_monitors_input)
                        }
                        else {
                                // bad!
-                               cerr << "capture_transition_buf is full when stopping record!  inconceivable!" << endl;
+                               fatal << string_compose (_("programmer error: %1"), X_("capture_transition_buf is full when stopping record!  inconceivable!")) << endmsg;
                        }
                }
        }
@@ -2159,7 +2204,7 @@ DiskStream::reset_write_sources (bool mark_write_complete, bool force)
        capturing_sources.clear ();
        
        for (chan = channels.begin(), n = 0; chan != channels.end(); ++chan, ++n) {
-               if (mark_write_complete) {
+               if ((*chan).write_source && mark_write_complete) {
                        (*chan).write_source->mark_streaming_write_completed ();
                }
                use_new_write_source (n);
index 5c97cd8dee0a2547a8748506c9e682ce528976d6..303113174d3318085168685643a870c30ba0f1f0 100644 (file)
@@ -967,9 +967,36 @@ FileSource::read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char *
 jack_nframes_t
 FileSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const
 {
-       
-       if (file_read(dst, start, cnt, workbuf) != (ssize_t) cnt) {
-               return 0;
+       jack_nframes_t file_cnt;
+
+       if (start > _length) {
+
+               /* read starts beyond end of data, just memset to zero */
+               
+               file_cnt = 0;
+
+       } else if (start + cnt > _length) {
+               
+               /* read ends beyond end of data, read some, memset the rest */
+               
+               file_cnt = _length - start;
+
+       } else {
+               
+               /* read is entirely within data */
+
+               file_cnt = cnt;
+       }
+
+       if (file_cnt) {
+               if (file_read(dst, start, file_cnt, workbuf) != (ssize_t) cnt) {
+                       return 0;
+               }
+       }
+
+       if (file_cnt != cnt) {
+               jack_nframes_t delta = cnt - file_cnt;
+               memset (dst+file_cnt, 0, sizeof (Sample) * delta);
        }
        
        return cnt;