'libs/evoral' - cast the returned pointers from malloc() / g_ptr_array_index() etc...
[ardour.git] / libs / ardour / session_state.cc
index 51f6f1352c321cc9e83bbaa5b9a07076938d79d6..62edaa39115fe8e5b9b556228c4f283d341cd844 100644 (file)
 #include <unistd.h>
 #include <sys/stat.h>
 #include <climits>
-#include <fcntl.h>
-#include <poll.h>
 #include <signal.h>
-#include <sys/mman.h>
 #include <sys/time.h>
 
 #ifdef HAVE_SYS_VFS_H
 #include <sys/vfs.h>
-#else
-#include <sys/param.h>
-#include <sys/mount.h>
 #endif
 
 #ifdef HAVE_SYS_STATVFS_H
 #include "pbd/enumwriter.h"
 #include "pbd/error.h"
 #include "pbd/file_utils.h"
+#include "pbd/pathexpand.h"
 #include "pbd/pathscanner.h"
 #include "pbd/pthread_utils.h"
 #include "pbd/stacktrace.h"
 #include "pbd/convert.h"
 #include "pbd/clear_dir.h"
+#include "pbd/localtime_r.h"
 
 #include "ardour/amp.h"
 #include "ardour/audio_diskstream.h"
@@ -134,14 +130,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
                throw failed_constructor();
        }
 
-       char buf[PATH_MAX+1];
-       if (!realpath (fullpath.c_str(), buf) && (errno != ENOENT)) {
-               error << string_compose(_("Could not use path %1 (%s)"), buf, strerror(errno)) << endmsg;
-               destroy ();
-               throw failed_constructor();
-       }
-
-       _path = string(buf);
+       _path = canonical_path (fullpath);
 
        if (_path[_path.length()-1] != G_DIR_SEPARATOR) {
                _path += G_DIR_SEPARATOR;
@@ -206,6 +195,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
        _play_range = false;
        _exporting = false;
        pending_abort = false;
+       _adding_routes_in_progress = false;
        destructive_index = 0;
        first_file_data_format_reset = true;
        first_file_header_format_reset = true;
@@ -366,6 +356,7 @@ Session::second_stage_init ()
 
        MIDI::Name::MidiPatchManager::instance().set_session (this);
 
+       ltc_tx_initialize();
        /* initial program change will be delivered later; see ::config_changed() */
 
        _state_of_the_state = Clean;
@@ -683,7 +674,7 @@ Session::remove_state (string snapshot_name)
 
        // and delete it
        if (g_remove (xml_path.c_str()) != 0) {
-               error << string_compose(_("Could not remove state file at path \"%1\" (%2)"),
+               error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
                                xml_path, g_strerror (errno)) << endmsg;
        }
 }
@@ -692,7 +683,7 @@ Session::remove_state (string snapshot_name)
 void
 Session::jack_session_event (jack_session_event_t * event)
 {
-        char timebuf[128];
+        char timebuf[128], *tmp;
         time_t n;
         struct tm local_time;
 
@@ -700,6 +691,8 @@ Session::jack_session_event (jack_session_event_t * event)
         localtime_r (&n, &local_time);
         strftime (timebuf, sizeof(timebuf), "JS_%FT%T", &local_time);
 
+        while ((tmp = strchr(timebuf, ':'))) { *tmp = '.'; }
+
         if (event->type == JackSessionSaveTemplate)
         {
                 if (save_template( timebuf )) {
@@ -770,6 +763,8 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot
                }
        }
 
+       SaveSession (); /* EMIT SIGNAL */
+
        tree.set_root (&get_state());
 
        if (snapshot_name.empty()) {
@@ -805,18 +800,18 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot
        if (!tree.write (tmp_path)) {
                error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
                if (g_remove (tmp_path.c_str()) != 0) {
-                       error << string_compose(_("Could not remove temporary state file at path \"%1\" (%2)"),
+                       error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
                                        tmp_path, g_strerror (errno)) << endmsg;
                }
                return -1;
 
        } else {
 
-               if (::rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
-                       error << string_compose (_("could not rename temporary session file %1 to %2"),
-                                       tmp_path, xml_path) << endmsg;
+               if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
+                       error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
+                                       tmp_path, xml_path, g_strerror(errno)) << endmsg;
                        if (g_remove (tmp_path.c_str()) != 0) {
-                               error << string_compose(_("Could not remove temporary state file at path \"%1\" (%2)"),
+                               error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
                                                tmp_path, g_strerror (errno)) << endmsg;
                        }
                        return -1;
@@ -881,7 +876,7 @@ Session::load_state (string snapshot_name)
        if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
                xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
                if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
-                        error << string_compose(_("%1: session state information file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
+                        error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
                         return 1;
                 }
         }
@@ -893,7 +888,7 @@ Session::load_state (string snapshot_name)
        _writable = exists_and_writable (xmlpath);
 
        if (!state_tree->read (xmlpath)) {
-               error << string_compose(_("Could not understand ardour file %1"), xmlpath) << endmsg;
+               error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
                delete state_tree;
                state_tree = 0;
                return -1;
@@ -936,9 +931,7 @@ Session::load_state (string snapshot_name)
 
                if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
                        
-                       info << string_compose (_("Copying old session file %1 to %2\nUse %2 with %3 versions before 2.0 from now on"),
-                                               xmlpath, backup_path, PROGRAM_NAME)
-                            << endmsg;
+                       VersionMismatch (xmlpath, backup_path);
                        
                        if (!copy_file (xmlpath, backup_path)) {;
                                return -1;
@@ -1076,7 +1069,11 @@ Session::state (bool full_state)
                         boost::shared_ptr<Region> r = i->second;
                         /* only store regions not attached to playlists */
                         if (r->playlist() == 0) {
-                                child->add_child_nocopy (r->state ());
+                               if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
+                                       child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
+                               } else {
+                                       child->add_child_nocopy (r->get_state ());
+                               }
                         }
                 }
 
@@ -1135,7 +1132,7 @@ Session::state (bool full_state)
                 }
 
                for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
-                       if (!(*i)->is_hidden()) {
+                       if (!(*i)->is_auditioner()) {
                                if (full_state) {
                                        child->add_child_nocopy ((*i)->get_state());
                                } else {
@@ -1158,6 +1155,16 @@ Session::state (bool full_state)
                gain_child->add_child_nocopy (_click_gain->state (full_state));
        }
 
+       if (_ltc_input) {
+               XMLNode* ltc_input_child = node->add_child ("LTC-In");
+               ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
+       }
+
+       if (_ltc_input) {
+               XMLNode* ltc_output_child = node->add_child ("LTC-Out");
+               ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
+       }
+
         node->add_child_nocopy (_speakers->get_state());
        node->add_child_nocopy (_tempo_map->get_state());
        node->add_child_nocopy (get_control_protocol_state());
@@ -1647,7 +1654,7 @@ Session::load_nested_sources (const XMLNode& node)
 
                        XMLProperty* prop = (*niter)->property (X_("id"));
                        if (!prop) {
-                               error << _("Nested source has no ID info in session state file! (ignored)") << endmsg;
+                               error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
                                continue;
                        }
 
@@ -2064,7 +2071,7 @@ Session::save_template (string template_name)
 void
 Session::refresh_disk_space ()
 {
-#if HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H
+#if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
        
        Glib::Threads::Mutex::Lock lm (space_lock);
 
@@ -2246,7 +2253,7 @@ Session::load_bundles (XMLNode const & node)
                } else if ((*niter)->name() == "OutputBundle") {
                        add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
                } else {
-                       error << string_compose(_("Unknown node \"%1\" found in Bundles list from state file"), (*niter)->name()) << endmsg;
+                       error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
                        return -1;
                }
        }
@@ -2573,7 +2580,7 @@ Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_th
                ripped = ripped.substr (0, ripped.length() - 1);
        }
 
-       state_files = scanner (ripped, accept_all_state_files, (void *) 0, false, true);
+       state_files = scanner (ripped, accept_all_state_files, (void *) 0, true, true);
 
        if (state_files == 0) {
                /* impossible! */
@@ -2652,6 +2659,8 @@ Session::cleanup_sources (CleanupReport& rep)
        bool used;
        string spath;
        int ret = -1;
+       string tmppath1;
+       string tmppath2;
 
        _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
 
@@ -2776,9 +2785,6 @@ Session::cleanup_sources (CleanupReport& rep)
                 i = tmp;
        }
 
-       char tmppath1[PATH_MAX+1];
-       char tmppath2[PATH_MAX+1];
-
         if (candidates) {
                 for (vector<string*>::iterator x = candidates->begin(); x != candidates->end(); ++x) {
 
@@ -2787,19 +2793,10 @@ Session::cleanup_sources (CleanupReport& rep)
 
                         for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
 
-                                if (realpath(spath.c_str(), tmppath1) == 0) {
-                                        error << string_compose (_("Cannot expand path %1 (%2)"),
-                                                                 spath, strerror (errno)) << endmsg;
-                                        continue;
-                                }
-
-                                if (realpath((*i).c_str(),  tmppath2) == 0) {
-                                        error << string_compose (_("Cannot expand path %1 (%2)"),
-                                                                 (*i), strerror (errno)) << endmsg;
-                                        continue;
-                                }
+                               tmppath1 = canonical_path (spath);
+                               tmppath2 = canonical_path ((*i));
 
-                                if (strcmp(tmppath1, tmppath2) == 0) {
+                               if (tmppath1 == tmppath2) {
                                         used = true;
                                         break;
                                 }
@@ -2903,7 +2900,7 @@ Session::cleanup_sources (CleanupReport& rep)
                string peakpath = peak_path (base);
 
                if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
-                       if (::unlink (peakpath.c_str()) != 0) {
+                       if (::g_unlink (peakpath.c_str()) != 0) {
                                error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
                                                          peakpath, _path, strerror (errno))
                                      << endmsg;
@@ -3548,6 +3545,12 @@ Session::config_changed (std::string p, bool ours)
                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") {
+               reconnect_ltc_output ();
+       } else if (p == "timecode-generator-offset") {
+               ltc_tx_parse_offset();
        }
 
        set_dirty ();