Fix crash when copying MIDI regions with midi-copy-is-fork is on (#6002).
authorDavid Robillard <d@drobilla.net>
Sat, 15 Nov 2014 04:53:59 +0000 (23:53 -0500)
committerDavid Robillard <d@drobilla.net>
Sat, 15 Nov 2014 04:53:59 +0000 (23:53 -0500)
libs/ardour/ardour/source.h
libs/ardour/midi_region.cc
libs/ardour/region_factory.cc
libs/ardour/session.cc

index afb6430242b7404ce33755d388c0fd4da75dff77..e009e0ef51e49c5dff84e159870b3f6c18535665 100644 (file)
@@ -109,6 +109,9 @@ class LIBARDOUR_API Source : public SessionObject
        bool used() const { return use_count() > 0; }
        uint32_t level() const { return _level; }
 
+       std::string ancestor_name() { return _ancestor_name.empty() ? name() : _ancestor_name; }
+       void set_ancestor_name(const std::string& name) { _ancestor_name = name; }
+
   protected:
        DataType            _type;
        Flag                _flags;
@@ -119,6 +122,7 @@ class LIBARDOUR_API Source : public SessionObject
         mutable Glib::Threads::Mutex _analysis_lock;
        gint                _use_count; /* atomic */
        uint32_t            _level; /* how deeply nested is this source w.r.t a disk file */
+       std::string         _ancestor_name;
 
   private:
        void fix_writable_flags ();
index e7298e752623423c4a7c8e472001a44a9077c5ef..03db3eaaa76d7d59ed45152f9db5f17db474ce16 100644 (file)
@@ -133,6 +133,7 @@ MidiRegion::clone (string path) const
        boost::shared_ptr<MidiSource> newsrc;
 
        /* caller must check for pre-existing file */
+       assert (!path.empty());
        assert (!Glib::file_test (path, Glib::FILE_TEST_EXISTS));
        newsrc = boost::dynamic_pointer_cast<MidiSource>(
                SourceFactory::createWritable(DataType::MIDI, _session,
index 9654a4b3de530a6f78926aa066e826d983e1275f..7c9f4fd228200ebb4d7f3e6dc169f4b180872f0c 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <inttypes.h>
 
+#include "pbd/basename.h"
 #include "pbd/error.h"
 
 #include "ardour/audioregion.h"
@@ -58,7 +59,17 @@ RegionFactory::create (boost::shared_ptr<const Region> region, bool announce)
        } else if ((mr = boost::dynamic_pointer_cast<const MidiRegion>(region)) != 0) {
 
                if (mr->session().config.get_midi_copy_is_fork()) {
-                       ret = mr->clone ();
+                       /* What we really want to do here is what Editor::fork_region()
+                          does via Session::create_midi_source_by_stealing_name(), but we
+                          don't have a Track.  We'll just live with the skipped number,
+                          and store the ancestral name of sources so multiple clones
+                          generates reasonable names that don't have too many suffixes. */
+                       const std::string ancestor_name = mr->sources().front()->ancestor_name();
+                       const std::string base          = PBD::basename_nosuffix(ancestor_name);
+
+                       boost::shared_ptr<MidiSource> source = mr->session().create_midi_source_for_session(base);
+                       source->set_ancestor_name(mr->sources().front()->name());
+                       ret = mr->clone(source);
                } else {
                        ret = boost::shared_ptr<Region> (new MidiRegion (mr, 0));
                }
index 2878bb8014cff7580e93cc52249a5526c1246c35..9c5b6fdccf242b0861f6e3f0ba54fd9770d4d689 100644 (file)
@@ -3734,7 +3734,7 @@ Session::new_audio_source_path (const string& base, uint32_t nchan, uint32_t cha
        return s;
 }
 
-/** Return a unique name based on \a owner_name for a new internal MIDI source */
+/** Return a unique name based on `base` for a new internal MIDI source */
 string
 Session::new_midi_source_path (const string& base)
 {