fix boot message always sticking on the last loaded route; it looked like an error
[ardour.git] / libs / ardour / session_state.cc
index cfd6b9c1e01348671f86f285b0c1713fda0ea187..b12a89480edefe3d219ce244a7318903b838900a 100644 (file)
@@ -96,6 +96,7 @@
 #include "ardour/midi_track.h"
 #include "ardour/pannable.h"
 #include "ardour/playlist_factory.h"
+#include "ardour/playlist_source.h"
 #include "ardour/port.h"
 #include "ardour/processor.h"
 #include "ardour/proxy_controllable.h"
@@ -315,10 +316,9 @@ Session::post_engine_init ()
                
                initialize_latencies ();
                
+               _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
+               _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
                _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
-               _locations->added.connect_same_thread (*this, boost::bind (&Session::locations_added, this, _1));
-               
-               
                
        } catch (AudioEngine::PortRegistrationFailure& err) {
                /* handle this one in a different way than all others, so that its clear what happened */
@@ -333,8 +333,8 @@ Session::post_engine_init ()
        // send_full_time_code (0);
        _engine.transport_locate (0);
 
-       _mmc->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
-       _mmc->send (MIDI::MachineControlCommand (Timecode::Time ()));
+       send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
+       send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
 
        MIDI::Name::MidiPatchManager::instance().set_session (this);
 
@@ -512,7 +512,7 @@ Session::create (const string& session_template, BusProfile* bus_profile)
 
                                /* Copy plugin state files from template to new session */
                                std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
-                               copy_files (template_plugins, plugins_dir ());
+                               copy_recurse (template_plugins, plugins_dir ());
                                
                                return 0;
 
@@ -698,7 +698,7 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot
                }
        }
 
-       SaveSession (); /* EMIT SIGNAL */
+       SessionSaveUnderway (); /* EMIT SIGNAL */
 
        tree.set_root (&get_state());
 
@@ -880,7 +880,7 @@ Session::load_state (string snapshot_name)
 int
 Session::load_options (const XMLNode& node)
 {
-       LocaleGuard lg (X_("POSIX"));
+       LocaleGuard lg (X_("C"));
        config.set_variables (node);
        return 0;
 }
@@ -1379,8 +1379,12 @@ Session::load_routes (const XMLNode& node, int version)
                new_routes.push_back (route);
        }
 
+       BootMessage (_("Tracks/busses loaded;  Adding to Session"));
+
        add_routes (new_routes, false, false, false);
 
+       BootMessage (_("Finished adding tracks/busses"));
+
        return 0;
 }
 
@@ -1852,7 +1856,10 @@ Session::load_sources (const XMLNode& node)
 {
        XMLNodeList nlist;
        XMLNodeConstIterator niter;
-       boost::shared_ptr<Source> source;
+       boost::shared_ptr<Source> source; /* don't need this but it stops some
+                                          * versions of gcc complaining about
+                                          * discarded return values.
+                                          */
 
        nlist = node.children();
 
@@ -1869,9 +1876,15 @@ Session::load_sources (const XMLNode& node)
 
                         int user_choice;
 
+                       if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
+                               error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
+                                                        PROGRAM_NAME) << endmsg;
+                               return -1;
+                       }
+
                         if (!no_questions_about_missing_files) {
-                                user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
-                        } else {
+                               user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
+                       } else {
                                 user_choice = -2;
                         }
 
@@ -1899,14 +1912,30 @@ Session::load_sources (const XMLNode& node)
                                switch (err.type) {
 
                                case DataType::AUDIO:
-                                       warning << _("A sound file is missing. It will be replaced by silence.") << endmsg;
                                        source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
                                        break;
 
                                case DataType::MIDI:
-                                       warning << string_compose (_("A MIDI file is missing. %1 cannot currently recover from missing MIDI files"),
-                                                                    PROGRAM_NAME) << endmsg;
-                                       return -1;
+                                       /* The MIDI file is actually missing so
+                                        * just create a new one in the same
+                                        * location. Do not announce its
+                                        */
+                                       string fullpath;
+
+                                       if (!Glib::path_is_absolute (err.path)) {
+                                               fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
+                                       } else {
+                                               /* this should be an unrecoverable error: we would be creating a MIDI file outside
+                                                  the session tree.
+                                               */
+                                               return -1;
+                                       }
+                                       /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
+                                       source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
+                                       /* reset ID to match the missing one */
+                                       source->set_id (**niter);
+                                       /* Now we can announce it */
+                                       SourceFactory::SourceCreated (source);
                                        break;
                                }
                                 break;
@@ -1930,7 +1959,7 @@ Session::XMLSourceFactory (const XMLNode& node)
        }
 
        catch (failed_constructor& err) {
-               error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the progammers."), PROGRAM_NAME) << endmsg;
+               error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
                return boost::shared_ptr<Source>();
        }
 }
@@ -1991,7 +2020,7 @@ Session::save_template (string template_name)
                return -1;
        }
 
-       copy_files (plugins_dir(), template_plugin_state_path);
+       copy_recurse (plugins_dir(), template_plugin_state_path);
 
        return 0;
 }
@@ -2286,7 +2315,7 @@ remove_end(string state)
                statename = statename.substr (start+1);
        }
 
-       if ((end = statename.rfind(".ardour")) == string::npos) {
+       if ((end = statename.rfind(statefile_suffix)) == string::npos) {
                end = statename.length();
        }
 
@@ -2406,6 +2435,17 @@ Session::begin_reversible_command (GQuark q)
        _current_trans_quarks.push_front (q);
 }
 
+void
+Session::abort_reversible_command ()
+{
+       if (_current_trans != 0) {
+               _current_trans->clear();
+               delete _current_trans;
+               _current_trans = 0;
+               _current_trans_quarks.clear();
+       }
+}
+
 void
 Session::commit_reversible_command (Command *cmd)
 {
@@ -2468,11 +2508,16 @@ accept_all_midi_files (const string& path, void* /*arg*/)
 static bool
 accept_all_state_files (const string& path, void* /*arg*/)
 {
-        if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
-                return false;
-        }
+       if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
+               return false;
+       }
 
-       return (path.length() > 7 && path.find (".ardour") == (path.length() - 7));
+       std::string const statefile_ext (statefile_suffix);
+       if (path.length() >= statefile_ext.length()) {
+               return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
+       } else {
+               return false;
+       }
 }
 
 int
@@ -2586,6 +2631,7 @@ Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
 void
 Session::cleanup_regions ()
 {
+       bool removed = false;
        const RegionFactory::RegionMap& regions (RegionFactory::regions());
 
        for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
@@ -2593,10 +2639,24 @@ Session::cleanup_regions ()
                uint32_t used = playlists->region_use_count (i->second);
 
                if (used == 0 && !i->second->automatic ()) {
+                       removed = true;
                        RegionFactory::map_remove (i->second);
                }
        }
 
+       if (removed) {
+               // re-check to remove parent references of compound regions
+               for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
+                       if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
+                               continue;
+                       }
+                       assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
+                       if (0 == playlists->region_use_count (i->second)) {
+                               RegionFactory::map_remove (i->second);
+                       }
+               }
+       }
+
        /* dump the history list */
        _history.clear ();
 
@@ -3457,12 +3517,12 @@ Session::config_changed (std::string p, bool ours)
                listen_position_changed ();
        } else if (p == "solo-control-is-listen-control") {
                solo_control_mode_changed ();
+       } else if (p == "solo-mute-gain") {
+               _solo_cut_control->Changed();
        } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
                last_timecode_valid = false;
        } else if (p == "playback-buffer-seconds") {
                AudioSource::allocate_working_buffers (frame_rate());
-       } else if (p == "automation-thinning-factor") {
-               Evoral::ControlList::set_thinning_factor (Config->get_automation_thinning_factor());
        } else if (p == "ltc-source-port") {
                reconnect_ltc_input ();
        } else if (p == "ltc-sink-port") {