From 99aa8c6338e47b41143f799fdcb35d1699548076 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 16 May 2011 20:16:57 +0000 Subject: [PATCH] rename join regions op as combine regions; save and restore nested playlists, sources, regions; add undo/redo for combine; fixup peakfile use/discovery git-svn-id: svn://localhost/ardour2/branches/3.0@9528 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/ardour.menus.in | 2 +- gtk2_ardour/editor.h | 3 +- gtk2_ardour/editor_actions.cc | 2 +- gtk2_ardour/editor_ops.cc | 12 ++++- gtk2_ardour/editor_selection.cc | 3 +- gtk2_ardour/route_time_axis.cc | 13 +++-- gtk2_ardour/route_time_axis.h | 2 +- libs/ardour/ardour/playlist.h | 1 + libs/ardour/audio_playlist_source.cc | 29 ++-------- libs/ardour/playlist.cc | 60 ++++++++++++++++++++- libs/ardour/playlist_source.cc | 21 ++++++-- libs/ardour/session_state.cc | 11 ++-- libs/ardour/source_factory.cc | 80 +++++++++++++++++----------- 13 files changed, 165 insertions(+), 74 deletions(-) diff --git a/gtk2_ardour/ardour.menus.in b/gtk2_ardour/ardour.menus.in index 62d637058b..d59fcc8f38 100644 --- a/gtk2_ardour/ardour.menus.in +++ b/gtk2_ardour/ardour.menus.in @@ -228,7 +228,7 @@ - + diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 83d8b394c3..140235e890 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -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); diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index 0081a806aa..a45279b6bb 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -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)); diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 07e68faf3d..a6bba7d76c 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -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 RTVS; RTVS tracks; + if (selection->regions.empty()) { + return; + } + for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { RouteTimeAxisView* rtv = dynamic_cast(&(*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 (); } diff --git a/gtk2_ardour/editor_selection.cc b/gtk2_ardour/editor_selection.cc index 7998a4bfa6..3ec11ea410 100644 --- a/gtk2_ardour/editor_selection.cc +++ b/gtk2_ardour/editor_selection.cc @@ -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) { diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 81dbefcd29..119f1814d3 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -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 = 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)); } diff --git a/gtk2_ardour/route_time_axis.h b/gtk2_ardour/route_time_axis.h index d596de3df7..b06b56fc67 100644 --- a/gtk2_ardour/route_time_axis.h +++ b/gtk2_ardour/route_time_axis.h @@ -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 */ diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h index 3234e4c108..72155d9981 100644 --- a/libs/ardour/ardour/playlist.h +++ b/libs/ardour/ardour/playlist.h @@ -376,6 +376,7 @@ public: void timestamp_layer_op (boost::shared_ptr); void _split_region (boost::shared_ptr, framepos_t position); + void load_nested_sources (const XMLNode& node); }; } /* namespace ARDOUR */ diff --git a/libs/ardour/audio_playlist_source.cc b/libs/ardour/audio_playlist_source.cc index 2160b9bd3a..882a1710e7 100644 --- a/libs/ardour/audio_playlist_source.cc +++ b/libs/ardour/audio_playlist_source.cc @@ -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; } diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index fd9af56e80..9ceb11fe51 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -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()); diff --git a/libs/ardour/playlist_source.cc b/libs/ardour/playlist_source.cc index 7ac175959c..a1597a76d2 100644 --- a/libs/ardour/playlist_source.cc +++ b/libs/ardour/playlist_source.cc @@ -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 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 (); } diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 604fc4bc52..82c2d5a31c 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -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 fs; + if ((fs = boost::dynamic_pointer_cast (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()); } } diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc index 4d3f02b1dc..57f0fdc1ec 100644 --- a/libs/ardour/source_factory.cc +++ b/libs/ardour/source_factory.cc @@ -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 ret (src); - if (setup_peakfile (ret, defer_peaks)) { - return boost::shared_ptr(); - } - 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 ap (new AudioPlaylistSource (s, node)); + + if (setup_peakfile (ap, true)) { + return boost::shared_ptr(); + } - /* 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 ret (src); - - if (setup_peakfile (ret, defer_peaks)) { - return boost::shared_ptr(); + boost::shared_ptr ret (src); + if (setup_peakfile (ret, defer_peaks)) { + return boost::shared_ptr(); + } + 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 ret (src); + + if (setup_peakfile (ret, defer_peaks)) { + return boost::shared_ptr(); + } + + 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 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; } } -- 2.30.2