rename join regions op as combine regions; save and restore nested playlists, sources...
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 16 May 2011 20:16:57 +0000 (20:16 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 16 May 2011 20:16:57 +0000 (20:16 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@9528 d708f5d6-7413-0410-9779-e7cbd77b26cf

13 files changed:
gtk2_ardour/ardour.menus.in
gtk2_ardour/editor.h
gtk2_ardour/editor_actions.cc
gtk2_ardour/editor_ops.cc
gtk2_ardour/editor_selection.cc
gtk2_ardour/route_time_axis.cc
gtk2_ardour/route_time_axis.h
libs/ardour/ardour/playlist.h
libs/ardour/audio_playlist_source.cc
libs/ardour/playlist.cc
libs/ardour/playlist_source.cc
libs/ardour/session_state.cc
libs/ardour/source_factory.cc

index 62d637058b447b818a9bd3842d59c10ce25ae7d5..d59fcc8f385217f068e8fadcc510828548c734ad 100644 (file)
       <menuitem action='play-selected-regions'/>
       <menuitem action='export-region'/>
       <menuitem action='bounce-region'/>
-      <menuitem action='join-regions'/>
+      <menuitem action='combine-regions'/>
       <menuitem action='analyze-region'/>
       <menuitem action='toggle-region-lock'/>
       <menuitem action='toggle-region-lock-style'/>
index 83d8b394c30364f06cd5f5e6f78bcb53345e973a..140235e890b9254474188ee3891c06dae1022080 100644 (file)
@@ -1099,7 +1099,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
        void duplicate_some_regions (RegionSelection&, float times);
        void duplicate_selection (float times);
        void region_fill_selection ();
-       void join_regions ();
+       void combine_regions ();
+       void uncombine_regions ();
 
        void region_fill_track ();
        void audition_playlist_region_standalone (boost::shared_ptr<ARDOUR::Region>);
index 0081a806aa68e9af2427867327d959c50fefe293..a45279b6bb605d6775862a8fa45b0b460093f2a2 100644 (file)
@@ -1372,7 +1372,7 @@ Editor::register_region_actions ()
        reg_sens (_region_actions, "play-selected-regions", _("Play"), sigc::mem_fun(*this, &Editor::play_selected_region));
 
        reg_sens (_region_actions, "bounce-region", _("Bounce"), sigc::mem_fun (*this, &Editor::bounce_region_selection));
-       reg_sens (_region_actions, "join-regions", _("Join"), sigc::mem_fun (*this, &Editor::join_regions));
+       reg_sens (_region_actions, "combine-regions", _("Combine"), sigc::mem_fun (*this, &Editor::combine_regions));
 
        reg_sens (_region_actions, "analyze-region", _("Spectral Analysis..."), sigc::mem_fun (*this, &Editor::analyze_region_selection));
 
index 07e68faf3def511fb1838d982cabe0608b1051c8..a6bba7d76c4a70990bc4e7680dada114923d2761 100644 (file)
@@ -6403,7 +6403,7 @@ Editor::toggle_region_mute ()
 }
 
 void
-Editor::join_regions ()
+Editor::combine_regions ()
 {
        /* foreach track with selected regions, take all selected regions
           and join them into a new region containing the subregions (as a
@@ -6413,6 +6413,10 @@ Editor::join_regions ()
        typedef set<RouteTimeAxisView*> RTVS;
        RTVS tracks;
 
+       if (selection->regions.empty()) {
+               return;
+       }
+
        for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
                RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
 
@@ -6421,8 +6425,12 @@ Editor::join_regions ()
                }
        }
 
+       begin_reversible_command (_("combine regions"));
+
        for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
-               (*i)->join_regions ();
+               (*i)->combine_regions ();
        }
+
+       commit_reversible_command ();
 }
 
index 7998a4bfa6adaa627efb8e383fae354ef4e71b88..3ec11ea41097d65edd1d5d6cd96e68bdf28da85f 100644 (file)
@@ -957,7 +957,6 @@ Editor::sensitize_the_right_region_actions ()
                if (!selection->time.empty()) {
                        _region_actions->get_action("split-region")->set_sensitive (true);
                }
-               
                return;
 
        } else if (mouse_mode != MouseObject) {
@@ -1063,9 +1062,11 @@ Editor::sensitize_the_right_region_actions ()
                _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
                _region_actions->get_action("show-region-properties")->set_sensitive (false);
                _region_actions->get_action("rename-region")->set_sensitive (false);
+               _region_actions->get_action("combine-regions")->set_sensitive (true);
        } else if (rs.size() == 1) {
                _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
                _region_actions->get_action("close-region-gaps")->set_sensitive (false);
+               _region_actions->get_action("combine-regions")->set_sensitive (false);
        } 
 
        if (!have_midi) {
index 81dbefcd2994a3619de875bbaa9715ba36b27640..119f1814d3b127886394649d71f8d238082a25ab 100644 (file)
@@ -2486,7 +2486,7 @@ void add_region_to_list (RegionView* rv, Playlist::RegionList* l, uint32_t* max_
 }
 
 void
-RouteTimeAxisView::join_regions ()
+RouteTimeAxisView::combine_regions ()
 {
        assert (is_track());
 
@@ -2495,11 +2495,16 @@ RouteTimeAxisView::join_regions ()
        }
 
        Playlist::RegionList selected_regions;
+       boost::shared_ptr<Playlist> playlist = track()->playlist();
        uint32_t max_level = 0;
 
        _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions, &max_level));
        
-       uint32_t num_joined_regions = track()->playlist()->count_joined_regions();
-       string name = string_compose (_("%1 combine-%2 (%3)"), track()->playlist()->name(), num_joined_regions+1, max_level+1);
-       track()->playlist()->join (selected_regions, name);
+       uint32_t num_joined_regions = playlist->count_joined_regions();
+       string name = string_compose (_("%1 compound-%2 (%3)"), playlist->name(), num_joined_regions+1, max_level+1);
+
+
+       playlist->clear_changes ();
+       playlist->join (selected_regions, name);
+       _session->add_command (new StatefulDiffCommand (playlist));
 }
index d596de3df70f0ee65bd9e4e3aaa3a39f4b52f25a..b06b56fc67618559feb0e40b3e4fd4cb9f909574 100644 (file)
@@ -94,7 +94,7 @@ public:
        /* Editing operations */
        void cut_copy_clear (Selection&, Editing::CutCopyOp);
        bool paste (ARDOUR::framepos_t, float times, Selection&, size_t nth);
-       void join_regions ();
+       void combine_regions ();
        void toggle_automation_track (const Evoral::Parameter& param);
 
        /* The editor calls these when mapping an operation across multiple tracks */
index 3234e4c10829f85f875b4a56fb484f3ab1b992d2..72155d99810be3a2421913ac6474377333e77ef9 100644 (file)
@@ -376,6 +376,7 @@ public:
        void timestamp_layer_op (boost::shared_ptr<Region>);
 
        void _split_region (boost::shared_ptr<Region>, framepos_t position);
+       void load_nested_sources (const XMLNode& node);
 };
 
 } /* namespace ARDOUR */
index 2160b9bd3aa482f9f2d38490fd5ca9c16f03b316..882a1710e77badbab4923627139e83eacf1ccfff 100644 (file)
@@ -34,6 +34,7 @@
 #include "ardour/audio_playlist_source.h"
 #include "ardour/audioregion.h"
 #include "ardour/debug.h"
+#include "ardour/filename_extensions.h"
 #include "ardour/session.h"
 #include "ardour/session_directory.h"
 #include "ardour/session_playlists.h"
@@ -52,14 +53,12 @@ AudioPlaylistSource::AudioPlaylistSource (Session& s, const std::string& name, b
        , PlaylistSource (s, name, p, DataType::AUDIO, begin, len, flags)
        , _playlist_channel (chn)
 {
-       _peak_path = Glib::build_filename (_session.session_directory().peak_path().to_string(), name);
-
        AudioSource::_length = len;
        ensure_buffers_for_level (_level);
 }
 
 AudioPlaylistSource::AudioPlaylistSource (Session& s, const XMLNode& node)
-       : Source (s, DataType::AUDIO, "toBeRenamed")
+       : Source (s, node)
        , AudioSource (s, node)
        , PlaylistSource (s, node)
 {
@@ -91,7 +90,6 @@ AudioPlaylistSource::get_state ()
 
        snprintf (buf, sizeof (buf), "%" PRIu32, _playlist_channel);
        node.add_property ("channel", buf);
-       node.add_property ("peak-path", _peak_path);
 
        return node;
 }
@@ -124,12 +122,6 @@ AudioPlaylistSource::set_state (const XMLNode& node, int version, bool with_desc
 
        sscanf (prop->value().c_str(), "%" PRIu32, &_playlist_channel);
 
-       if ((prop = node.property (X_("peak-path"))) == 0) {
-               throw failed_constructor ();
-       }
-
-       _peak_path = prop->value ();
-
        ensure_buffers_for_level (_level);
 
        return 0;
@@ -224,23 +216,12 @@ AudioPlaylistSource::sample_rate () const
 int
 AudioPlaylistSource::setup_peakfile ()
 {
-       /* the peak data is setup once and once only 
-        */
-       
-       if (!Glib::file_test (_peak_path, Glib::FILE_TEST_EXISTS)) {
-               /* the 2nd argument here will be passed
-                  in to ::peak_path, and is irrelevant
-                  since our peak file path is fixed and
-                  not dependent on anything.
-               */
-               return initialize_peakfile (false, string());
-       }
-
-       return 0;
+       _peak_path = Glib::build_filename (_session.session_directory().peak_path().to_string(), name() + ARDOUR::peakfile_suffix);
+       return initialize_peakfile (false, string());
 }
 
 string
-AudioPlaylistSource::peak_path (string /*audio_path*/)
+AudioPlaylistSource::peak_path (string /*audio_path_IGNORED*/)
 {
        return _peak_path;
 }
index fd9af56e80c1865e26a02b8a6b0b4960bb7272dc..9ceb11fe51efa64bc7185b14dc40657633ebaac8 100644 (file)
@@ -2221,6 +2221,26 @@ Playlist::update (const RegionListProperty::ChangeRecord& change)
        thaw ();
 }
 
+void
+Playlist::load_nested_sources (const XMLNode& node)
+{
+       XMLNodeList nlist;
+       XMLNodeConstIterator niter;
+
+       nlist = node.children();
+
+       for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+               if ((*niter)->name() == "Source") {
+                       try {
+                               SourceFactory::create (_session, **niter, true);
+                       } 
+                       catch (failed_constructor& err) {
+                               error << string_compose (_("Cannot reconstruct nested source for playlist %1"), name()) << endmsg;
+                       }
+               }
+       }
+}
+
 int
 Playlist::set_state (const XMLNode& node, int version)
 {
@@ -2264,6 +2284,19 @@ Playlist::set_state (const XMLNode& node, int version)
 
        nlist = node.children();
 
+       /* find the "Nested" node, if any, and recreate the PlaylistSources
+          listed there
+       */
+
+       for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+               child = *niter;
+
+               if (child->name() == "Nested") {
+                       load_nested_sources (*child);
+                       break;
+               }
+       }
+
        for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
 
                child = *niter;
@@ -2292,7 +2325,7 @@ Playlist::set_state (const XMLNode& node, int version)
                                error << _("Playlist: cannot create region from XML") << endmsg;
                                continue;
                        }
-
+                       
 
                        add_region (region, region->position(), 1.0);
 
@@ -2348,6 +2381,31 @@ Playlist::state (bool full_state)
 
        if (full_state) {
                RegionLock rlock (this, false);
+               XMLNode* nested_node = 0;
+
+               for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+                       if ((*i)->max_source_level() > 0) {
+
+                               if (!nested_node) {
+                                       nested_node = new XMLNode (X_("Nested"));
+                               }
+
+                               /* region is compound - get its playlist and
+                                  store that before we list the region that
+                                  needs it ...
+                               */
+
+                               const SourceList& sl ((*i)->sources());
+
+                               for (SourceList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
+                                       nested_node->add_child_nocopy ((*s)->get_state ());
+                               }
+                       }
+               }
+
+               if (nested_node) {
+                       node->add_child_nocopy (*nested_node);
+               }
 
                for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
                        node->add_child_nocopy ((*i)->get_state());
index 7ac175959ca3ad1bb17af779f882af6a8d830f37..a1597a76d2335d4d53c83afdc4e103796d4ee439 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "ardour/playlist.h"
 #include "ardour/playlist_source.h"
+#include "ardour/playlist_factory.h"
 #include "ardour/session.h"
 #include "ardour/session_playlists.h"
 #include "ardour/source_factory.h"
@@ -84,26 +85,38 @@ PlaylistSource::add_state (XMLNode& node)
        node.add_property ("offset", buf);
        snprintf (buf, sizeof (buf), "%" PRIu64, _playlist_length);
        node.add_property ("length", buf);
+       
+       node.add_child_nocopy (_playlist->get_state());
 }
 
 int
 PlaylistSource::set_state (const XMLNode& node, int version) 
 {
-       /* get playlist ID */
+       /* check that we have a playlist ID */
 
        const XMLProperty *prop = node.property (X_("playlist"));
 
        if (!prop) {
+               error << _("No playlist ID in PlaylistSource XML!") << endmsg;
                throw failed_constructor ();
        }
 
-       PBD::ID id (prop->value());
+       /* create playlist from child node */
+
+       XMLNodeList nlist;
+       XMLNodeConstIterator niter;
 
-       /* get playlist */
+       nlist = node.children();
 
-       boost::shared_ptr<Playlist> p = _session.playlists->by_id (id);
+       for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+               if ((*niter)->name() == "Playlist") {
+                       _playlist = PlaylistFactory::create (_session, **niter, true, false);
+                       break;
+               }
+       }
 
        if (!_playlist) {
+               error << _("No playlist node in PlaylistSource XML!") << endmsg;
                throw failed_constructor ();
        }
 
index 604fc4bc52b07804ca9645a6bf7c168537ecc590..82c2d5a31c313681fad7cb9518bb8451cd82582d 100644 (file)
@@ -1056,20 +1056,23 @@ Session::state(bool full_state)
 
                for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
 
-                       /* Don't save information about non-destructive file sources that are empty
-                           and unused by any regions.
+                       /* Don't save information about non-file Sources, or
+                        * about non-destructive file sources that are empty
+                        * and unused by any regions.
                         */
 
                        boost::shared_ptr<FileSource> fs;
+
                        if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
+
                                if (!fs->destructive()) {
                                        if (fs->empty() && !fs->used()) {
                                                continue;
                                        }
                                }
+                               
+                               child->add_child_nocopy (siter->second->get_state());
                        }
-
-                       child->add_child_nocopy (siter->second->get_state());
                }
        }
 
index 4d3f02b1dc68bad81516a0a40b77f624436f23bf..57f0fdc1ec03e894ad10562096c372b406125842 100644 (file)
@@ -147,44 +147,66 @@ SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
 
        if (type == DataType::AUDIO) {
 
-               try {
-                       Source* src = new SndFileSource (s, node);
-#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, defer_peaks)) {
-                               return boost::shared_ptr<Source>();
-                       }
-                       ret->check_for_analysis_data_on_disk ();
-                       SourceCreated (ret);
-                       return ret;
-               }
+               /* it could be nested */
 
-               catch (failed_constructor& err) {
+               if (node.property ("playlist") != 0) {
 
-#ifdef USE_COREAUDIO_FOR_FILES
+                       try {
+                               boost::shared_ptr<AudioPlaylistSource> ap (new AudioPlaylistSource (s, node));
+
+                               if (setup_peakfile (ap, true)) {
+                                       return boost::shared_ptr<Source>();
+                               }
 
-                       /* this is allowed to throw */
+                               ap->check_for_analysis_data_on_disk ();
+                               SourceCreated (ap);
+                               return ap;
 
-                       Source *src = new CoreAudioSource (s, node);
+                       } catch (failed_constructor&) {
+                               /* oh well, so much for that then ... */
+                       }
+                       
+               } else {
+
+
+                       try {
+                               Source* src = new SndFileSource (s, node);
 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
-                       // boost_debug_shared_ptr_mark_interesting (src, "Source");
+                               // boost_debug_shared_ptr_mark_interesting (src, "Source");
 #endif
-                       boost::shared_ptr<Source> ret (src);
-
-                       if (setup_peakfile (ret, defer_peaks)) {
-                               return boost::shared_ptr<Source>();
+                               boost::shared_ptr<Source> ret (src);
+                               if (setup_peakfile (ret, defer_peaks)) {
+                                       return boost::shared_ptr<Source>();
+                               }
+                               ret->check_for_analysis_data_on_disk ();
+                               SourceCreated (ret);
+                               return ret;
                        }
 
-                       ret->check_for_analysis_data_on_disk ();
-                       SourceCreated (ret);
-                       return ret;
+                       catch (failed_constructor& err) {
+                               
+#ifdef USE_COREAUDIO_FOR_FILES
+                               
+                               /* this is allowed to throw */
+                               
+                               Source *src = new CoreAudioSource (s, node);
+#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, defer_peaks)) {
+                                       return boost::shared_ptr<Source>();
+                               }
+                               
+                               ret->check_for_analysis_data_on_disk ();
+                               SourceCreated (ret);
+                               return ret;
 #else
-                       throw; // rethrow
+                               throw; // rethrow
 #endif
+                       }
                }
-
        } else if (type == DataType::MIDI) {
                boost::shared_ptr<SMFSource> src (new SMFSource (s, node));
                src->load_model (true, true);
@@ -348,9 +370,7 @@ SourceFactory::createFromPlaylist (DataType type, Session& s, boost::shared_ptr<
                                }
                                
                                ret->check_for_analysis_data_on_disk ();
-                               
-                               /* we never announce these sources */
-                               
+                               SourceCreated (ret);
                                return ret;
                        }
                }