diff --git a/ardour.rc.in b/ardour.rc.in
index 44738f8062..a1d0d37177 100644
--- a/ardour.rc.in
+++ b/ardour.rc.in
@@ -33,6 +33,8 @@
+
+
diff --git a/gtk2_ardour/ardour.menus b/gtk2_ardour/ardour.menus
index 9b857b5a52..5529b4de0c 100644
--- a/gtk2_ardour/ardour.menus
+++ b/gtk2_ardour/ardour.menus
@@ -348,6 +348,7 @@
+
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc
index 8fa4f283f8..850f29fe0a 100644
--- a/gtk2_ardour/ardour_ui.cc
+++ b/gtk2_ardour/ardour_ui.cc
@@ -428,6 +428,39 @@ ARDOUR_UI::save_ardour_state ()
save_keybindings ();
}
+gint
+ARDOUR_UI::autosave_session ()
+{
+ if (!Config->get_periodic_safety_backups())
+ return 1;
+
+ if (session) {
+ session->maybe_write_autosave();
+ }
+
+ return 1;
+}
+
+void
+ARDOUR_UI::update_autosave ()
+{
+ ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::update_autosave));
+
+ if (session->dirty()) {
+ if (_autosave_connection.connected()) {
+ _autosave_connection.disconnect();
+ }
+
+ _autosave_connection = Glib::signal_timeout().connect (mem_fun (*this, &ARDOUR_UI::autosave_session),
+ Config->get_periodic_safety_backup_interval() * 1000);
+
+ } else {
+ if (_autosave_connection.connected()) {
+ _autosave_connection.disconnect();
+ }
+ }
+}
+
void
ARDOUR_UI::startup ()
{
diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h
index 3cee38372b..1ebb7407af 100644
--- a/gtk2_ardour/ardour_ui.h
+++ b/gtk2_ardour/ardour_ui.h
@@ -291,6 +291,11 @@ class ARDOUR_UI : public Gtkmm2ext::UI
int ask_about_saving_session (const string & why);
int save_the_session;
+ /* periodic safety backup, to be precise */
+ gint autosave_session();
+ void update_autosave();
+ sigc::connection _autosave_connection;
+
void queue_transport_change ();
void map_transport_state ();
int32_t do_engine_start ();
@@ -668,6 +673,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI
void toggle_StopPluginsWithTransport();
void toggle_DoNotRunPluginsWhileRecording();
void toggle_VerifyRemoveLastCapture();
+ void toggle_PeriodicSafetyBackups();
void toggle_StopRecordingOnXrun();
void toggle_StopTransportAtEndOfSession();
void toggle_GainReduceFastTransport();
diff --git a/gtk2_ardour/ardour_ui_dialogs.cc b/gtk2_ardour/ardour_ui_dialogs.cc
index c3b82c74a8..8a50697e85 100644
--- a/gtk2_ardour/ardour_ui_dialogs.cc
+++ b/gtk2_ardour/ardour_ui_dialogs.cc
@@ -126,6 +126,10 @@ ARDOUR_UI::connect_to_session (Session *s)
solo_alert_button.set_active (session->soloing());
+ /* update autochange callback on dirty state changing */
+
+ session->DirtyChanged.connect (mem_fun(*this, &ARDOUR_UI::update_autosave));
+
/* can't be auditioning here */
primary_clock.set_session (s);
diff --git a/gtk2_ardour/ardour_ui_ed.cc b/gtk2_ardour/ardour_ui_ed.cc
index 7ecbb0d01b..1add49af69 100644
--- a/gtk2_ardour/ardour_ui_ed.cc
+++ b/gtk2_ardour/ardour_ui_ed.cc
@@ -402,6 +402,7 @@ ARDOUR_UI::install_actions ()
ActionManager::register_toggle_action (option_actions, X_("StopPluginsWithTransport"), _("Stop plugins with transport"), mem_fun (*this, &ARDOUR_UI::toggle_StopPluginsWithTransport));
ActionManager::register_toggle_action (option_actions, X_("VerifyRemoveLastCapture"), _("Verify remove last capture"), mem_fun (*this, &ARDOUR_UI::toggle_VerifyRemoveLastCapture));
+ ActionManager::register_toggle_action (option_actions, X_("PeriodicSafetyBackups"), _("Make periodic safety backups"), mem_fun (*this, &ARDOUR_UI::toggle_PeriodicSafetyBackups));
ActionManager::register_toggle_action (option_actions, X_("StopRecordingOnXrun"), _("Stop recording on xrun"), mem_fun (*this, &ARDOUR_UI::toggle_StopRecordingOnXrun));
ActionManager::register_toggle_action (option_actions, X_("StopTransportAtEndOfSession"), _("Stop transport at session end"), mem_fun (*this, &ARDOUR_UI::toggle_StopTransportAtEndOfSession));
ActionManager::register_toggle_action (option_actions, X_("GainReduceFastTransport"), _("-12dB gain reduce ffwd/rewind"), mem_fun (*this, &ARDOUR_UI::toggle_GainReduceFastTransport));
diff --git a/gtk2_ardour/ardour_ui_options.cc b/gtk2_ardour/ardour_ui_options.cc
index 9565c46e40..34431aeafb 100644
--- a/gtk2_ardour/ardour_ui_options.cc
+++ b/gtk2_ardour/ardour_ui_options.cc
@@ -398,6 +398,12 @@ ARDOUR_UI::toggle_VerifyRemoveLastCapture()
ActionManager::toggle_config_state ("options", "VerifyRemoveLastCapture", &Configuration::set_verify_remove_last_capture, &Configuration::get_verify_remove_last_capture);
}
+void
+ARDOUR_UI::toggle_PeriodicSafetyBackups()
+{
+ ActionManager::toggle_config_state ("options", "PeriodicSafetyBackups", &Configuration::set_periodic_safety_backups, &Configuration::get_periodic_safety_backups);
+}
+
void
ARDOUR_UI::toggle_StopRecordingOnXrun()
{
@@ -891,6 +897,8 @@ ARDOUR_UI::parameter_changed (const char* parameter_name)
ActionManager::map_some_state ("options", "LatchedRecordEnable", &Configuration::get_latched_record_enable);
} else if (PARAM_IS ("verify-remove-last-capture")) {
ActionManager::map_some_state ("options", "VerifyRemoveLastCapture", &Configuration::get_verify_remove_last_capture);
+ } else if (PARAM_IS ("periodic-safety-backups")) {
+ ActionManager::map_some_state ("options", "PeriodicSafetyBackups", &Configuration::get_periodic_safety_backups);
} else if (PARAM_IS ("stop-recording-on-xrun")) {
ActionManager::map_some_state ("options", "StopRecordingOnXrun", &Configuration::get_stop_recording_on_xrun);
} else if (PARAM_IS ("stop-at-session-end")) {
@@ -944,8 +952,6 @@ ARDOUR_UI::parameter_changed (const char* parameter_name)
map_meter_hold ();
} else if (PARAM_IS ("meter-falloff")) {
map_meter_falloff ();
- } else if (PARAM_IS ("verify-remove-last-capture")) {
- ActionManager::map_some_state ("options", "VerifyRemoveLastCapture", &Configuration::get_verify_remove_last_capture);
} else if (PARAM_IS ("video-pullup") || PARAM_IS ("smpte-format")) {
if (session) {
primary_clock.set (session->audible_frame(), true);
diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h
index 62bf826dc9..395732e727 100644
--- a/libs/ardour/ardour/configuration_vars.h
+++ b/libs/ardour/ardour/configuration_vars.h
@@ -137,6 +137,8 @@ CONFIG_VARIABLE (bool, use_vst, "use-vst", true)
CONFIG_VARIABLE (uint32_t, subframes_per_frame, "subframes-per-frame", 100)
CONFIG_VARIABLE (uint32_t, saved_history_depth, "save-history-depth", 100)
CONFIG_VARIABLE (bool, use_overlap_equivalency, "use-overlap-equivalency", false)
+CONFIG_VARIABLE (bool, periodic_safety_backups, "periodic-safety-backups", true)
+CONFIG_VARIABLE (uint32_t, periodic_safety_backup_interval, "periodic-safety-backup-interval", 120)
/* BWAV */
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 675fa7ca0a..70a9d7c96f 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -323,6 +323,8 @@ class Session : public PBD::StatefulDestructible
void disable_record (bool rt_context, bool force = false);
void step_back_from_record ();
+ void maybe_write_autosave ();
+
/* Proxy signal for region hidden changes */
sigc::signal > RegionHiddenChange;
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index d3bf70a2dd..418709a826 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -574,6 +574,14 @@ Session::load_diskstreams (const XMLNode& node)
return 0;
}
+void
+Session::maybe_write_autosave()
+{
+ if (dirty() && record_status() != Recording) {
+ save_state("", true);
+ }
+}
+
void
Session::remove_pending_capture_state ()
{
@@ -681,7 +689,7 @@ Session::save_state (string snapshot_name, bool pending)
tmp_path += snapshot_name;
tmp_path += ".tmp";
- cerr << "actually writing state\n";
+ cerr << "actually writing state to " << xml_path << endl;
if (!tree.write (tmp_path)) {
error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;