fix crash recovery: add new constructors to SndFileSource, AudioFileSource, add a...
authorPaul Davis <paul@linuxaudiosystems.com>
Tue, 10 Jun 2014 14:07:04 +0000 (10:07 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 10 Jun 2014 14:09:26 +0000 (10:09 -0400)
AudioDiskstream::use_pending_capture_data() to create both the required whole-file and the in-playlist regions

libs/ardour/ardour/audiofilesource.h
libs/ardour/ardour/sndfilesource.h
libs/ardour/ardour/source_factory.h
libs/ardour/audio_diskstream.cc
libs/ardour/audiofilesource.cc
libs/ardour/file_source.cc
libs/ardour/sndfilesource.cc
libs/ardour/source_factory.cc

index 9be8d6ce45cd39bf09914ca1999839f0ee9bff48..7f4b18e404234c7e68784be26340c6e450932148 100644 (file)
@@ -93,6 +93,12 @@ protected:
        /** Constructor to be called for existing in-session files */
        AudioFileSource (Session&, const XMLNode&, bool must_exist = true);
 
+       /** Constructor to be called for crash recovery. Final argument is not
+        * used but exists to differentiate from the external-to-session
+        * constructor above.
+        */
+       AudioFileSource (Session&, const std::string& path, Source::Flag flags, bool);
+
        int init (const std::string& idstr, bool must_exist);
 
        virtual void set_header_timeline_position () = 0;
index 3f63f1c59898b5f4c568a824938db1eef01f057d..9604d3f232270f27e9097830858228a28ecc3a52 100644 (file)
@@ -38,7 +38,16 @@ class SndFileSource : public AudioFileSource {
                       SampleFormat samp_format, HeaderFormat hdr_format, framecnt_t rate,
                       Flag flags = SndFileSource::default_writable_flags);
 
-       /** Constructor to be called for existing in-session files */
+       /* Constructor to be called for recovering files being used for
+        * capture. They are in-session, they already exist, they should not
+        * be writable. They are an odd hybrid (from a constructor point of
+        * view) of the previous two constructors.
+        */
+       SndFileSource (Session&, const std::string& path, int chn);
+
+       /** Constructor to be called for existing in-session files during
+        * session loading 
+        */
        SndFileSource (Session&, const XMLNode&);
 
        ~SndFileSource ();
index c94f783b445f51fba4b9fa1505459e3e42bb1f9b..ce0f86bb6bd59a63e6d1cf44cff954ee4efb0b00 100644 (file)
@@ -57,6 +57,9 @@ class SourceFactory {
                 bool destructive, framecnt_t rate, bool announce = true, bool async = false);
 
 
+       static boost::shared_ptr<Source> createForRecovery
+               (DataType type, Session&, const std::string& path, int chn);
+
        static boost::shared_ptr<Source> createFromPlaylist
                (DataType type, Session& s, boost::shared_ptr<Playlist> p, const PBD::ID& orig, const std::string& name,
                 uint32_t chn, frameoffset_t start, framecnt_t len, bool copy, bool defer_peaks);
index 010e1da21f9092db29dbe2337ff495a48524398d..7785284dac8fdaa796e2c2fa2b0f16f903ba42b8 100644 (file)
@@ -2181,11 +2181,16 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
                                continue;
                        }
 
+                       /* XXX as of June 2014, we always record to mono
+                          files. Since this Source is being created as part of
+                          crash recovery, we know that we need the first
+                          channel (the final argument to the SourceFactory
+                          call below). If we ever support non-mono files for
+                          capture, this will need rethinking.
+                       */
+
                        try {
-                               fs = boost::dynamic_pointer_cast<AudioFileSource> (
-                                       SourceFactory::createWritable (
-                                               DataType::AUDIO, _session,
-                                               prop->value(), false, _session.frame_rate()));
+                               fs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createForRecovery (DataType::AUDIO, _session, prop->value(), 0));
                        }
 
                        catch (failed_constructor& err) {
@@ -2216,21 +2221,31 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
                return -1;
        }
 
-       boost::shared_ptr<AudioRegion> region;
-
        try {
 
-               PropertyList plist;
+               boost::shared_ptr<AudioRegion> wf_region;
+               boost::shared_ptr<AudioRegion> region;
+               
+               /* First create the whole file region */
 
+               PropertyList plist;
+               
                plist.add (Properties::start, 0);
                plist.add (Properties::length, first_fs->length (first_fs->timeline_position()));
                plist.add (Properties::name, region_name_from_path (first_fs->name(), true));
 
-               region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (pending_sources, plist));
+               wf_region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (pending_sources, plist));
+
+               wf_region->set_automatic (true);
+               wf_region->set_whole_file (true);
+               wf_region->special_set_position (position);
 
-               region->set_automatic (true);
-               region->set_whole_file (true);
-               region->special_set_position (0);
+               /* Now create a region that isn't the whole file for adding to
+                * the playlist */
+
+               region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (pending_sources, plist));
+               
+               _playlist->add_region (region, position);
        }
 
        catch (failed_constructor& err) {
@@ -2241,7 +2256,6 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
                return -1;
        }
 
-       _playlist->add_region (region, position);
 
        return 0;
 }
index 37bf502177a9245f4631f8cb55b06d63c68c59ed..8c3bf0017659cfcfb9561d48c130a9ff81e4ba13 100644 (file)
@@ -115,6 +115,22 @@ AudioFileSource::AudioFileSource (Session& s, const string& path, const string&
        }
 }
 
+/** Constructor used for existing internal-to-session files during crash
+ * recovery. File must exist
+ */
+AudioFileSource::AudioFileSource (Session& s, const string& path, Source::Flag flags, bool /* ignored-exists-for-prototype differentiation */)
+       : Source (s, DataType::AUDIO, path, flags)
+       , AudioSource (s, path)
+       , FileSource (s, DataType::AUDIO, path, string(), flags)
+{
+        /* note that origin remains empty */
+
+       if (init (_path, true)) {
+               throw failed_constructor ();
+       }
+}
+
+
 /** Constructor used for existing internal-to-session files via XML.  File must exist. */
 AudioFileSource::AudioFileSource (Session& s, const XMLNode& node, bool must_exist)
        : Source (s, node)
index d579d119651cf0f56d81565634a748e773c8d4d9..30ae2178fe40b2b33a47100b914c63c7a50264a0 100644 (file)
@@ -56,7 +56,7 @@ PBD::Signal3<int,std::string,std::string,std::vector<std::string> > FileSource::
 FileSource::FileSource (Session& session, DataType type, const string& path, const string& origin, Source::Flag flag)
        : Source(session, type, path, flag)
        , _path (path)
-       , _file_is_new (!origin.empty()) // origin empty => new file VS. origin !empty => new file
+       , _file_is_new (!origin.empty()) // if origin is left unspecified (empty string) then file must exist
        , _channel (0)
         , _origin (origin)
         , _open (false)
index 6b019f6fd04925970ffef209b9425f81590d13eb..5465c5e4a4654311c02c15b8f0eb003f86f4acf4 100644 (file)
@@ -183,6 +183,34 @@ SndFileSource::SndFileSource (Session& s, const string& path, const string& orig
        }
 }
 
+/** Constructor to be called for recovering files being used for
+ * capture. They are in-session, they already exist, they should not
+ * be writable. They are an odd hybrid (from a constructor point of
+ * view) of the previous two constructors.
+ */
+SndFileSource::SndFileSource (Session& s, const string& path, int chn)
+       : Source (s, DataType::AUDIO, path, Flag (0))
+         /* the final boolean argument is not used, its value is irrelevant. see audiofilesource.h for explanation */
+       , AudioFileSource (s, path, Flag (0))
+       , _descriptor (0)
+       , _broadcast_info (0)
+       , _capture_start (false)
+       , _capture_end (false)
+       , file_pos (0)
+       , xfade_buf (0)
+{
+       _channel = chn;
+
+       init_sndfile ();
+
+        assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
+       existence_check ();
+
+       if (open()) {
+               throw failed_constructor ();
+       }
+}
+
 void
 SndFileSource::init_sndfile ()
 {
@@ -256,6 +284,14 @@ SndFileSource::open ()
                delete _broadcast_info;
                _broadcast_info = 0;
                _flags = Flag (_flags & ~Broadcast);
+       } 
+
+       /* Set the broadcast flag if the BWF info is already there. We need
+        * this when recovering or using existing files.
+        */
+       
+       if (bwf_info_exists) {
+               _flags = Flag (_flags | Broadcast);
        }
 
        if (writable()) {
index 391b205a94e88182f93b23ca20a0e58304f6969a..6d2bb80b30be8859716bb09fea2a3d17b6e27c07 100644 (file)
@@ -341,6 +341,39 @@ SourceFactory::createWritable (DataType type, Session& s, const std::string& pat
        return boost::shared_ptr<Source> ();
 }
 
+boost::shared_ptr<Source>
+SourceFactory::createForRecovery (DataType type, Session& s, const std::string& path, int chn)
+{
+       /* this might throw failed_constructor(), which is OK */
+
+       if (type == DataType::AUDIO) {
+               Source* src = new SndFileSource (s, path, chn);
+
+#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
+               // boost_debug_shared_ptr_mark_interesting (src, "Source");
+#endif
+               boost::shared_ptr<Source> ret (src);
+
+               if (setup_peakfile (ret, false)) {
+                       return boost::shared_ptr<Source>();
+               }
+
+               // no analysis data - this is still basically a new file (we
+               // crashed while recording.
+
+               // always announce these files
+
+               SourceCreated (ret);
+
+               return ret;
+
+       } else if (type == DataType::MIDI) {
+               error << _("Recovery attempted on a MIDI file - not implemented") << endmsg;
+       }
+
+       return boost::shared_ptr<Source> ();
+}
+
 boost::shared_ptr<Source>
 SourceFactory::createFromPlaylist (DataType type, Session& s, boost::shared_ptr<Playlist> p, const PBD::ID& orig, const std::string& name,
                                   uint32_t chn, frameoffset_t start, framecnt_t len, bool copy, bool defer_peaks)