1 /*
2  * Copyright (C) 2005-2007 Doug McLain <doug@nostar.net>
3  * Copyright (C) 2005-2017 Tim Mayberry <mojofunk@gmail.com>
4  * Copyright (C) 2005-2019 Paul Davis <paul@linuxaudiosystems.com>
5  * Copyright (C) 2005 Karsten Wiese <fzuuzf@googlemail.com>
6  * Copyright (C) 2005 Taybin Rutkin <taybin@taybin.com>
7  * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
8  * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
9  * Copyright (C) 2008-2010 Sakari Bergen <sakari.bergen@beatwaves.net>
10  * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
11  * Copyright (C) 2013-2015 Colin Fletcher <colin.m.fletcher@googlemail.com>
12  * Copyright (C) 2013-2016 John Emmas <john@creativepost.co.uk>
13  * Copyright (C) 2013-2016 Nick Mainsbridge <mainsbridge@gmail.com>
14  * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
15  * Copyright (C) 2015 André Nusser <andre.nusser@googlemail.com>
16  * Copyright (C) 2016-2018 Len Ovens <len@ovenwerks.net>
17  * Copyright (C) 2017 Johannes Mueller <github@johannes-mueller.org>
18  *
19  * This program is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 2 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License along
30  * with this program; if not, write to the Free Software Foundation, Inc.,
31  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32  */
33 
34 #ifdef WAF_BUILD
35 #include "gtk2ardour-config.h"
36 #include "gtk2ardour-version.h"
37 #endif
38 
39 #include <gtkmm/progressbar.h>
40 #include <gtkmm/stock.h>
41 
42 #include "pbd/basename.h"
43 #include "pbd/localtime_r.h"
44 #include "pbd/unwind.h"
45 
46 #include "gtkmm2ext/application.h"
47 #include "gtkmm2ext/doi.h"
48 
49 #include "widgets/prompter.h"
50 
51 #include "ardour/audioengine.h"
52 #include "ardour/filename_extensions.h"
53 #include "ardour/profile.h"
54 #include "ardour/session.h"
55 #include "ardour/session_utils.h"
56 #include "ardour/session_state_utils.h"
57 #include "ardour/session_directory.h"
58 
59 #include "ardour_message.h"
60 #include "ardour_ui.h"
61 #include "engine_dialog.h"
62 #include "missing_filesource_dialog.h"
63 #include "missing_plugin_dialog.h"
64 #include "opts.h"
65 #include "public_editor.h"
66 #include "save_as_dialog.h"
67 #include "session_dialog.h"
68 #include "session_archive_dialog.h"
69 #include "timers.h"
70 #include "utils.h"
71 
72 #ifdef WINDOWS_VST_SUPPORT
73 #include <fst.h>
74 #endif
75 
76 #include "pbd/i18n.h"
77 
78 using namespace ARDOUR;
79 using namespace ARDOUR_UI_UTILS;
80 using namespace PBD;
81 using namespace Gtk;
82 using namespace std;
83 using namespace ArdourWidgets;
84 
85 bool
ask_about_loading_existing_session(const std::string & session_path)86 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
87 {
88 	std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
89 
90 	ArdourMessageDialog msg (str,
91 	                         false,
92 	                         Gtk::MESSAGE_WARNING,
93 	                         Gtk::BUTTONS_YES_NO,
94 	                         true);
95 
96 	msg.set_name (X_("OpenExistingDialog"));
97 	msg.set_title (_("Open Existing Session"));
98 	msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
99 	msg.set_position (Gtk::WIN_POS_CENTER);
100 
101 	switch (msg.run()) {
102 	case RESPONSE_YES:
103 		return true;
104 		break;
105 	}
106 	return false;
107 }
108 
109 void
build_session_from_dialog(SessionDialog & sd,const std::string & session_path,const std::string & session_name,std::string const & session_template)110 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name, std::string const& session_template)
111 {
112 	BusProfile bus_profile;
113 
114 	if (nsm) {
115 		bus_profile.master_out_channels = 2;
116 	} else if ( Profile->get_mixbus()) {
117 		bus_profile.master_out_channels = 2;
118 	} else {
119 		/* get settings from advanced section of NSD */
120 		bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
121 	}
122 
123 	build_session (session_path, session_name, session_template, bus_profile, false, !sd.was_new_name_edited());
124 }
125 
126 /** This is only ever used once Ardour is already running with a session
127  * loaded. The startup case is handled by StartupFSM
128  */
129 void
start_session_load(bool create_new)130 ARDOUR_UI::start_session_load (bool create_new)
131 {
132 	/* deal with any existing DIRTY session now, rather than later. don't
133 	 * treat a non-dirty session this way, so that it stays visible
134 	 * as we bring up the new session dialog.
135 	 */
136 
137 	if (_session && ARDOUR_UI::instance()->video_timeline) {
138 		ARDOUR_UI::instance()->video_timeline->sync_session_state();
139 	}
140 
141 	if (_session && _session->dirty()) {
142 		if (unload_session (false)) {
143 			/* unload cancelled by user */
144 			return;
145 		}
146 	}
147 
148 	SessionDialog* session_dialog = new SessionDialog (create_new, string(), Config->get_default_session_parent_dir(), string(), true);
149 	session_dialog->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::session_dialog_response_handler), session_dialog));
150 	session_dialog->present ();
151 }
152 
153 void
session_dialog_response_handler(int response,SessionDialog * session_dialog)154 ARDOUR_UI::session_dialog_response_handler (int response, SessionDialog* session_dialog)
155 {
156 	string session_name;
157 	string session_path;
158 	string template_name;
159 	bool likely_new = false;
160 
161 	session_path = "";
162 	session_name = "";
163 
164 	switch (response) {
165 	case RESPONSE_ACCEPT:
166 		break;
167 	default:
168 		return; /* back to main event loop */
169 	}
170 
171 	session_name = session_dialog->session_name (likely_new);
172 	session_path = session_dialog->session_folder ();
173 
174 	if (nsm) {
175 		likely_new = true;
176 	}
177 
178 	/* could be an archived session, so test for that and use the
179 	 * result if it was
180 	 */
181 
182 	if (!likely_new) {
183 		int rv = ARDOUR::inflate_session (session_name, Config->get_default_session_parent_dir(), session_path, session_name);
184 
185 		if (rv < 0) {
186 			ArdourMessageDialog msg (*session_dialog, string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
187 			msg.run ();
188 			return; /* back to main event loop */
189 		} else if (rv == 0) {
190 			session_dialog->set_provided_session (session_name, session_path);
191 		}
192 	}
193 
194 	string::size_type suffix = session_name.find (statefile_suffix);
195 
196 	if (suffix != string::npos) {
197 		session_name = session_name.substr (0, suffix);
198 	}
199 
200 	/* this shouldn't happen, but we catch it just in case it does */
201 
202 	if (session_name.empty()) {
203 		return; /* back to main event loop */
204 	}
205 
206 	if (session_dialog->use_session_template()) {
207 		template_name = session_dialog->session_template_name();
208 		_session_is_new = true;
209 	}
210 
211 	if (session_name[0] == G_DIR_SEPARATOR ||
212 #ifdef PLATFORM_WINDOWS
213 	    (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
214 #else
215 	    (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
216 	    (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
217 #endif
218 		)
219 	{
220 
221 		/* absolute path or cwd-relative path specified for session name: infer session folder
222 		   from what was given.
223 		*/
224 
225 		session_path = Glib::path_get_dirname (session_name);
226 		session_name = Glib::path_get_basename (session_name);
227 
228 	} else {
229 
230 		session_path = session_dialog->session_folder();
231 
232 		std::string const& illegal = Session::session_name_is_legal (session_name);
233 
234 		if (!illegal.empty()) {
235 			ArdourMessageDialog msg (*session_dialog,
236 			                         string_compose (_("To ensure compatibility with various systems\n"
237 			                                           "session names may not contain a '%1' character"),
238 			                                         illegal));
239 			msg.run ();
240 			return; /* back to main event loop */
241 		}
242 	}
243 
244 	if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
245 
246 
247 		if (likely_new && !nsm) {
248 
249 			std::string existing = Glib::build_filename (session_path, session_name);
250 
251 			if (!ask_about_loading_existing_session (existing)) {
252 				return; /* back to main event loop */
253 			}
254 		}
255 
256 		_session_is_new = false;
257 
258 	} else {
259 
260 		if (!likely_new) {
261 			ArdourMessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
262 			msg.run ();
263 			return; /* back to main event loop */
264 		}
265 
266 		std::string const& illegal = Session::session_name_is_legal (session_name);
267 
268 		if (!illegal.empty()) {
269 			ArdourMessageDialog msg (*session_dialog, string_compose(_("To ensure compatibility with various systems\n"
270 			                                                           "session names may not contain a '%1' character"), illegal));
271 			msg.run ();
272 			return; /* back to main event loop */
273 
274 		}
275 
276 		_session_is_new = true;
277 	}
278 
279 
280 	/* OK, parameters provided ... good to go. */
281 
282 	session_dialog->hide ();
283 	delete_when_idle (session_dialog);
284 
285 	if (!template_name.empty() || likely_new) {
286 
287 		build_session_from_dialog (*session_dialog, session_path, session_name, template_name);
288 
289 	} else {
290 
291 		load_session (session_path, session_name, template_name);
292 	}
293 }
294 
295 void
close_session()296 ARDOUR_UI::close_session()
297 {
298 	if (unload_session (true)) {
299 		return;
300 	}
301 
302 	start_session_load (false);
303 }
304 
305 
306 /** @param snap_name Snapshot name (without .ardour suffix).
307  *  @return -2 if the load failed because we are not connected to the AudioEngine.
308  */
309 int
load_session(const std::string & path,const std::string & snap_name,std::string mix_template)310 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
311 {
312 	/* load_session calls flush_pending() which allows
313 	 * GUI interaction and potentially loading another session
314 	 * (that was easy via snapshot sidebar).
315 	 * Recursing into load_session() from load_session() and recusive
316 	 * event loops causes all kind of crashes.
317 	 */
318 	assert (!session_load_in_progress);
319 	if (session_load_in_progress) {
320 		return -1;
321 	}
322 	PBD::Unwinder<bool> lsu (session_load_in_progress, true);
323 
324 	int unload_status;
325 	bool had_session = false;
326 
327 	if (_session) {
328 		had_session = true;
329 
330 		unload_status = unload_session ();
331 
332 		if (unload_status != 0) {
333 			hide_splash ();
334 			return -1;
335 		}
336 	}
337 
338 	if (had_session) {
339 		float sr;
340 		SampleFormat sf;
341 		string pv;
342 
343 		Session::get_info_from_path (Glib::build_filename (path, snap_name + statefile_suffix), sr, sf, pv);
344 
345 		/* this will stop the engine if the SR is different */
346 
347 		audio_midi_setup->set_desired_sample_rate (sr);
348 
349 		if (!AudioEngine::instance()->running()) {
350 			audio_midi_setup->set_position (WIN_POS_CENTER);
351 			audio_midi_setup->present ();
352 			_engine_dialog_connection = audio_midi_setup->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::audio_midi_setup_reconfigure_done), path, snap_name, mix_template));
353 			/* not done yet, but we're avoiding modal dialogs */
354 			return 0;
355 		}
356 	}
357 
358 	return load_session_stage_two (path, snap_name, mix_template);
359 }
360 
361 void
audio_midi_setup_reconfigure_done(int response,std::string path,std::string snap_name,std::string mix_template)362 ARDOUR_UI::audio_midi_setup_reconfigure_done (int response, std::string path, std::string snap_name, std::string mix_template)
363 {
364 	_engine_dialog_connection.disconnect ();
365 
366 	switch (response) {
367 	case Gtk::RESPONSE_DELETE_EVENT:
368 		break;
369 	default:
370 		if (!AudioEngine::instance()->running()) {
371 			return; // keep dialog visible, maybe try again
372 		}
373 	}
374 
375 	audio_midi_setup->hide();
376 
377 	(void) load_session_stage_two (path, snap_name, mix_template);
378 }
379 
380 int
load_session_stage_two(const std::string & path,const std::string & snap_name,std::string mix_template)381 ARDOUR_UI::load_session_stage_two (const std::string& path, const std::string& snap_name, std::string mix_template)
382 {
383 	Session *new_session;
384 	int retval = -1;
385 
386 	BootMessage (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
387 
388 	try {
389 		new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
390 	}
391 
392 	/* this one is special */
393 
394 	catch (AudioEngine::PortRegistrationFailure const& err) {
395 
396 		ArdourMessageDialog msg (err.what(),
397 		                         true,
398 		                         Gtk::MESSAGE_INFO,
399 		                         Gtk::BUTTONS_CLOSE);
400 
401 		msg.set_title (_("Port Registration Error"));
402 		msg.set_secondary_text (_("Click the Close button to try again."));
403 		msg.set_position (Gtk::WIN_POS_CENTER);
404 
405 		int response = msg.run ();
406 		msg.hide ();
407 
408 		switch (response) {
409 		case RESPONSE_CANCEL:
410 			exit (EXIT_FAILURE);
411 		default:
412 			break;
413 		}
414 		goto out;
415 	}
416 	catch (SessionException const& e) {
417 		stringstream ss;
418 		dump_errors (ss, 6);
419 		dump_errors (cerr);
420 		clear_errors ();
421 		ArdourMessageDialog msg (string_compose(
422 			                         _("Session \"%1 (snapshot %2)\" did not load successfully:\n%3%4%5"),
423 			                         path, snap_name, e.what(), ss.str().empty() ? "" : "\n\n---", ss.str()),
424 		                         false,
425 		                         Gtk::MESSAGE_INFO,
426 		                         BUTTONS_OK);
427 
428 		msg.set_title (_("Loading Error"));
429 		msg.set_position (Gtk::WIN_POS_CENTER);
430 
431 		(void) msg.run ();
432 		msg.hide ();
433 
434 		goto out;
435 	}
436 	catch (...) {
437 		stringstream ss;
438 		dump_errors (ss, 6);
439 		dump_errors (cerr);
440 		clear_errors ();
441 
442 		ArdourMessageDialog msg (string_compose(
443 		                           _("Session \"%1 (snapshot %2)\" did not load successfully.%3%4"),
444 		                           path, snap_name, ss.str().empty() ? "" : "\n\n---", ss.str()),
445 		                         true,
446 		                         Gtk::MESSAGE_INFO,
447 		                         BUTTONS_OK);
448 
449 		msg.set_title (_("Loading Error"));
450 		msg.set_position (Gtk::WIN_POS_CENTER);
451 
452 		(void) msg.run ();
453 		msg.hide ();
454 
455 		goto out;
456 	}
457 
458 	if (new_session->had_destructive_tracks()) {
459 		ArdourMessageDialog msg (string_compose (_("This session (from an older version of %1) used at least\none \"tape track\" (aka \"destructive recording\".\n\n"
460 		                                           "This is no longer supported by the program. The tape track(s) have been setup as normal tracks.\n\n"
461 		                                           "If you need to continue using tape tracks/destructive recording\n"
462 		                                           "please use an older version of %1 to work on this session"), PROGRAM_NAME),
463 
464 		                         true,
465 		                         Gtk::MESSAGE_INFO,
466 		                         BUTTONS_OK);
467 
468 		msg.set_title (_("Tape Tracks No Longer Supported"));
469 		msg.set_position (Gtk::WIN_POS_CENTER);
470 		(void) msg.run ();
471 		msg.hide ();
472 	}
473 
474 	{
475 		list<string> const u = new_session->missing_filesources (DataType::MIDI);
476 		if (!u.empty()) {
477 			MissingFileSourceDialog d (_session, u, DataType::MIDI);
478 			d.run ();
479 		}
480 	}
481 	{
482 		list<string> const u = new_session->unknown_processors ();
483 		if (!u.empty()) {
484 			MissingPluginDialog d (_session, u);
485 			d.run ();
486 		}
487 	}
488 
489 	if (!new_session->writable()) {
490 		ArdourMessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
491 		                         true,
492 		                         Gtk::MESSAGE_INFO,
493 		                         BUTTONS_OK);
494 
495 		msg.set_title (_("Read-only Session"));
496 		msg.set_position (Gtk::WIN_POS_CENTER);
497 		(void) msg.run ();
498 		msg.hide ();
499 	}
500 
501 
502 	/* Now the session been created, add the transport controls */
503 	new_session->add_controllable(roll_controllable);
504 	new_session->add_controllable(stop_controllable);
505 	new_session->add_controllable(goto_start_controllable);
506 	new_session->add_controllable(goto_end_controllable);
507 	new_session->add_controllable(auto_loop_controllable);
508 	new_session->add_controllable(play_selection_controllable);
509 	new_session->add_controllable(rec_controllable);
510 
511 	set_session (new_session);
512 
513 	if (_session) {
514 		_session->set_clean ();
515 	}
516 
517 #ifdef WINDOWS_VST_SUPPORT
518 	fst_stop_threading();
519 #endif
520 
521 	{
522 		Timers::TimerSuspender t;
523 		flush_pending (10);
524 	}
525 
526 #ifdef WINDOWS_VST_SUPPORT
527 	fst_start_threading();
528 #endif
529 	retval = 0;
530 
531 	if (!mix_template.empty ()) {
532 		/* if mix_template is given, assume this is a new session */
533 		string metascript = Glib::build_filename (mix_template, "template.lua");
534 		meta_session_setup (metascript);
535 	}
536 
537 
538   out:
539 	/* For successful session load the splash is hidden by ARDOUR_UI::first_idle,
540 	 * which is queued by set_session().
541 	 * If session-loading fails we hide it explicitly.
542 	 * This covers both cases in a central place.
543 	 */
544 	if (retval) {
545 		hide_splash ();
546 	}
547 	return retval;
548 }
549 
550 int
build_session(const std::string & path,const std::string & snap_name,const std::string & session_template,BusProfile const & bus_profile,bool from_startup_fsm,bool unnamed)551 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, const std::string& session_template, BusProfile const& bus_profile, bool from_startup_fsm, bool unnamed)
552 {
553 	int x;
554 
555 	x = unload_session ();
556 
557 	if (x < 0) {
558 		return -1;
559 	} else if (x > 0) {
560 		return 0;
561 	}
562 
563 	_session_is_new = true;
564 
565 	/* when running from startup FSM all is fine,
566 	 * engine should be running and the FSM will also have
567 	 * asked for the SR (even if try-autostart-engine is set)
568 	 */
569 	if (from_startup_fsm && AudioEngine::instance()->running ()) {
570 		return build_session_stage_two (path, snap_name, session_template, bus_profile, unnamed);
571 	}
572 	/* Sample-rate cannot be changed when JACK is running */
573 	if (!ARDOUR::AudioEngine::instance()->setup_required () && AudioEngine::instance()->running ()) {
574 		return build_session_stage_two (path, snap_name, session_template, bus_profile, unnamed);
575 	}
576 
577 	/* Work-around missing "OK" button:
578 	 * When the engine is running. The way to proceed w/o engine re-start
579 	 * is to simply close the dialog. This is not obvious.
580 	 *
581 	 * Ideally an engine restart should be avoided since it can invalidate
582 	 * latency-calibration.
583 	 */
584 	ARDOUR::AudioEngine::instance()->stop();
585 
586 	/* Ask for the Sample-rate to use with the new session */
587 	audio_midi_setup->set_position (WIN_POS_CENTER);
588 	audio_midi_setup->set_modal ();
589 	audio_midi_setup->present ();
590 	_engine_dialog_connection = audio_midi_setup->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::audio_midi_setup_for_new_session_done), path, snap_name, session_template, bus_profile, unnamed));
591 
592 	/* not done yet, but we're avoiding modal dialogs */
593 	return 0;
594 }
595 
596 
597 void
audio_midi_setup_for_new_session_done(int response,std::string path,std::string snap_name,std::string template_name,BusProfile const & bus_profile,bool unnamed)598 ARDOUR_UI::audio_midi_setup_for_new_session_done (int response, std::string path, std::string snap_name, std::string template_name, BusProfile const& bus_profile, bool unnamed)
599 {
600 	_engine_dialog_connection.disconnect ();
601 
602 	switch (response) {
603 		case Gtk::RESPONSE_DELETE_EVENT:
604 			audio_midi_setup->set_modal (false);
605 			break;
606 		default:
607 			break;
608 	}
609 
610 	if (!AudioEngine::instance()->running()) {
611 		return; // keep dialog visible, maybe try again
612 	}
613 	audio_midi_setup->set_modal (false);
614 	audio_midi_setup->hide();
615 
616 	build_session_stage_two (path, snap_name, template_name, bus_profile, unnamed);
617 }
618 
619 int
build_session_stage_two(std::string const & path,std::string const & snap_name,std::string const & session_template,BusProfile const & bus_profile,bool unnamed)620 ARDOUR_UI::build_session_stage_two (std::string const& path, std::string const& snap_name, std::string const& session_template, BusProfile const& bus_profile, bool unnamed)
621 {
622 	Session* new_session;
623 
624 	bool meta_session = !session_template.empty() && session_template.substr (0, 11) == "urn:ardour:";
625 
626 	try {
627 		new_session = new Session (*AudioEngine::instance(), path, snap_name, bus_profile.master_out_channels > 0 ? &bus_profile : NULL, meta_session ? "" : session_template, unnamed);
628 	}
629 	catch (SessionException const& e) {
630 		stringstream ss;
631 		dump_errors (ss, 6);
632 		cerr << "Here are the errors associated with this failed session:\n";
633 		dump_errors (cerr);
634 		cerr << "---------\n";
635 		clear_errors ();
636 		ArdourMessageDialog msg (string_compose(_("Could not create session in \"%1\": %2%3%4"), path, e.what(), ss.str().empty() ? "" : "\n\n---", ss.str()));
637 		msg.set_title (_("Loading Error"));
638 		msg.set_position (Gtk::WIN_POS_CENTER);
639 		msg.run ();
640 		return -1;
641 	}
642 	catch (...) {
643 		stringstream ss;
644 		dump_errors (ss, 6);
645 		cerr << "Here are the errors associated with this failed session:\n";
646 		dump_errors (cerr);
647 		cerr << "---------\n";
648 		clear_errors ();
649 		ArdourMessageDialog msg (string_compose(_("Could not create session in \"%1\"%2%3"), path, ss.str().empty() ? "" : "\n\n---", ss.str()));
650 		msg.set_title (_("Loading Error"));
651 		msg.set_position (Gtk::WIN_POS_CENTER);
652 		msg.run ();
653 		return -1;
654 	}
655 
656 	/* Give the new session the default GUI state, if such things exist */
657 
658 	XMLNode* n;
659 	n = Config->instant_xml (X_("Editor"));
660 	if (n) {
661 		n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
662 		new_session->add_instant_xml (*n, false);
663 	}
664 	n = Config->instant_xml (X_("Mixer"));
665 	if (n) {
666 		new_session->add_instant_xml (*n, false);
667 	}
668 
669 	n = Config->instant_xml (X_("Preferences"));
670 	if (n) {
671 		new_session->add_instant_xml (*n, false);
672 	}
673 
674 	/* Put the playhead at 0 and scroll fully left */
675 	n = new_session->instant_xml (X_("Editor"));
676 	if (n) {
677 		n->set_property (X_("playhead"), X_("0"));
678 		n->set_property (X_("left-frame"), X_("0"));
679 	}
680 
681 	set_session (new_session);
682 
683 	new_session->save_state(new_session->name());
684 
685 	if (meta_session) {
686 		meta_session_setup (session_template.substr (11));
687 	}
688 
689 	return 0;
690 }
691 
692 /** Ask the user for the name of a new snapshot and then take it.
693  */
694 
695 void
snapshot_session(bool switch_to_it)696 ARDOUR_UI::snapshot_session (bool switch_to_it)
697 {
698 	if (switch_to_it && _session->dirty()) {
699 		vector<string> actions;
700 		actions.push_back (_("Abort saving snapshot"));
701 		actions.push_back (_("Don't save now, just snapshot"));
702 		actions.push_back (_("Save it first"));
703 		switch (ask_about_saving_session(actions)) {
704 			case -1:
705 				return;
706 				break;
707 			case 1:
708 				if (save_state_canfail ("")) {
709 					ArdourMessageDialog msg (_main_window,
710 							string_compose (_("\
711 %1 was unable to save your session.\n\n\
712 If you still wish to proceed, please use the\n\n\
713 \"Don't save now\" option."), PROGRAM_NAME));
714 					msg.run ();
715 					return;
716 				}
717 				/* fallthrough */
718 			case 0:
719 				_session->remove_pending_capture_state ();
720 				break;
721 		}
722 	}
723 
724 	Prompter prompter (true);
725 	prompter.set_name ("Prompter");
726 	prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
727 	if (switch_to_it) {
728 		prompter.set_title (_("Snapshot and switch"));
729 		prompter.set_prompt (_("New session name"));
730 	} else {
731 		prompter.set_title (_("Take Snapshot"));
732 		prompter.set_prompt (_("Name of new snapshot"));
733 	}
734 
735 	if (switch_to_it) {
736 		prompter.set_initial_text (_session->snap_name());
737 	} else {
738 		Glib::DateTime tm (g_date_time_new_now_local ());
739 		prompter.set_initial_text (tm.format ("%FT%H.%M.%S"));
740 	}
741 
742 	bool finished = false;
743 	while (!finished) {
744 		switch (prompter.run()) {
745 		case RESPONSE_ACCEPT:
746 		{
747 			finished = process_snapshot_session_prompter (prompter, switch_to_it);
748 			break;
749 		}
750 
751 		default:
752 			finished = true;
753 			break;
754 		}
755 	}
756 }
757 
758 /** Ask the user for a new session name and then rename the session to it.
759  */
760 
761 void
rename_session(bool for_unnamed)762 ARDOUR_UI::rename_session (bool for_unnamed)
763 {
764 	if (!_session) {
765 		return;
766 	}
767 
768 	Prompter prompter (true, false);
769 	string name;
770 
771 	prompter.set_name ("Prompter");
772 
773 	prompter.add_button (Gtk::Stock::DISCARD, Gtk::RESPONSE_CANCEL);
774 	prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
775 
776 	if (for_unnamed) {
777 		prompter.set_title (_("Name Session"));
778 		prompter.set_prompt (_("Session name"));
779 	} else {
780 		prompter.set_title (_("Rename Session"));
781 		prompter.set_prompt (_("New session name"));
782 	}
783 
784   again:
785 	switch (prompter.run()) {
786 	case RESPONSE_ACCEPT:
787 	{
788 		prompter.get_result (name);
789 
790 		bool do_rename = (name.length() != 0);
791 
792 		if (do_rename) {
793 			std::string const& illegal = Session::session_name_is_legal (name);
794 
795 			if (!illegal.empty()) {
796 				ArdourMessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
797 				                                     "session names may not contain a '%1' character"), illegal));
798 				msg.run ();
799 				goto again;
800 			}
801 
802 			switch (_session->rename (name)) {
803 			case -1: {
804 				ArdourMessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
805 				msg.run ();
806 				goto again;
807 				break;
808 			}
809 			case 0:
810 				break;
811 			default: {
812 				ArdourMessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
813 				msg.run ();
814 				break;
815 			}
816 			}
817 		}
818 
819 		break;
820 	}
821 
822 	default:
823 		break;
824 	}
825 }
826 
827 bool
save_as_progress_update(float fraction,int64_t cnt,int64_t total,Gtk::Label * label,Gtk::ProgressBar * bar)828 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
829 {
830 	char buf[256];
831 
832 	snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
833 
834 	label->set_text (buf);
835 	bar->set_fraction (fraction);
836 
837 	/* process events, redraws, etc. */
838 
839 	while (gtk_events_pending()) {
840 		gtk_main_iteration ();
841 	}
842 
843 	return true; /* continue with save-as */
844 }
845 
846 void
save_session_as()847 ARDOUR_UI::save_session_as ()
848 {
849 	if (!_session) {
850 		return;
851 	}
852 
853 	if (_session->unnamed()) {
854 		save_state ("", false);
855 		return;
856 	}
857 
858 	if (_session->dirty()) {
859 		vector<string> actions;
860 		actions.push_back (_("Abort save-as"));
861 		actions.push_back (_("Don't save now, just save-as"));
862 		actions.push_back (_("Save it first"));
863 		switch (ask_about_saving_session(actions)) {
864 			case -1:
865 				return;
866 				break;
867 			case 1:
868 				if (save_state_canfail ("")) {
869 					ArdourMessageDialog msg (_main_window,
870 							string_compose (_("\
871 %1 was unable to save your session.\n\n\
872 If you still wish to proceed, please use the\n\n\
873 \"Don't save now\" option."), PROGRAM_NAME));
874 					msg.run ();
875 					return;
876 				}
877 				/* fallthrough */
878 			case 0:
879 				_session->remove_pending_capture_state ();
880 				break;
881 		}
882 	}
883 
884 	if (!save_as_dialog) {
885 		save_as_dialog = new SaveAsDialog;
886 	}
887 
888 	save_as_dialog->set_name (_session->name());
889 
890 	int response = save_as_dialog->run ();
891 
892 	save_as_dialog->hide ();
893 
894 	switch (response) {
895 		case Gtk::RESPONSE_OK:
896 			break;
897 		default:
898 			return;
899 	}
900 
901 
902 	Session::SaveAs sa;
903 
904 	sa.new_parent_folder = save_as_dialog->new_parent_folder ();
905 	sa.new_name = save_as_dialog->new_name ();
906 	sa.switch_to = save_as_dialog->switch_to();
907 	sa.copy_media = save_as_dialog->copy_media();
908 	sa.copy_external = save_as_dialog->copy_external();
909 	sa.include_media = save_as_dialog->include_media ();
910 
911 	/* Only bother with a progress dialog if we're going to copy
912 	   media into the save-as target. Without that choice, this
913 	   will be very fast because we're only talking about a few kB's to
914 	   perhaps a couple of MB's of data.
915 	*/
916 
917 	ArdourDialog progress_dialog (_("Save As"), true);
918 	ScopedConnection c;
919 
920 	if (sa.include_media && sa.copy_media) {
921 
922 		Gtk::Label* label = manage (new Gtk::Label());
923 		Gtk::ProgressBar* progress_bar = manage (new Gtk::ProgressBar ());
924 
925 		progress_dialog.get_vbox()->pack_start (*label);
926 		progress_dialog.get_vbox()->pack_start (*progress_bar);
927 		label->show ();
928 		progress_bar->show ();
929 
930 		/* this signal will be emitted from within this, the calling thread,
931 		 * after every file is copied. It provides information on percentage
932 		 * complete (in terms of total data to copy), the number of files
933 		 * copied so far, and the total number to copy.
934 		 */
935 
936 		sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, label, progress_bar));
937 
938 		progress_dialog.show_all ();
939 		progress_dialog.present ();
940 	}
941 
942 	if (_session->save_as (sa)) {
943 		/* ERROR MESSAGE */
944 		ArdourMessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
945 		msg.run ();
946 	}
947 
948 	/* the logic here may seem odd: why isn't the condition sa.switch_to ?
949 	 * the trick is this: if the new session was copy with media included,
950 	 * then Session::save_as() will have already done a neat trick to avoid
951 	 * us having to unload and load the new state. But if the media was not
952 	 * included, then this is required (it avoids us having to otherwise
953 	 * drop all references to media (sources).
954 	 */
955 
956 	if (!sa.include_media && sa.switch_to) {
957 		unload_session (false);
958 		load_session (sa.final_session_folder_name, sa.new_name);
959 	}
960 }
961 
962 void
archive_session()963 ARDOUR_UI::archive_session ()
964 {
965 	if (!_session) {
966 		return;
967 	}
968 
969 	Glib::DateTime gdt (Glib::DateTime::create_now_local ());
970 
971 	SessionArchiveDialog sad;
972 	sad.set_name (_session->name() + gdt.format ("_%F_%H%M%S"));
973 	int response = sad.run ();
974 
975 	if (response != Gtk::RESPONSE_OK) {
976 		sad.hide ();
977 		return;
978 	}
979 
980 	if (_session->archive_session (sad.target_folder(), sad.name(), sad.encode_option (), sad.compression_level (), sad.only_used_sources (), &sad)) {
981 		ArdourMessageDialog msg (_("Session Archiving failed."));
982 		msg.run ();
983 	}
984 }
985 
986 void
quick_snapshot_session(bool switch_to_it)987 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
988 {
989 	if (switch_to_it && _session->dirty ()) {
990 		save_state_canfail ("");
991 	}
992 
993 	save_state (Glib::DateTime::create_now_local().format ("%FT%H.%M.%S"), switch_to_it);
994 }
995 
996 
997 bool
process_snapshot_session_prompter(Prompter & prompter,bool switch_to_it)998 ARDOUR_UI::process_snapshot_session_prompter (Prompter& prompter, bool switch_to_it)
999 {
1000 	string snapname;
1001 
1002 	prompter.get_result (snapname);
1003 
1004 	bool do_save = (snapname.length() != 0);
1005 
1006 	if (do_save) {
1007 		std::string const& illegal = Session::session_name_is_legal (snapname);
1008 		if (!illegal.empty()) {
1009 			ArdourMessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
1010 			                                           "snapshot names may not contain a '%1' character"), illegal));
1011 			msg.run ();
1012 			return false;
1013 		}
1014 	}
1015 
1016 	vector<std::string> p;
1017 	get_state_files_in_directory (_session->session_directory().root_path(), p);
1018 	vector<string> n = get_file_names_no_extension (p);
1019 
1020 	if (find (n.begin(), n.end(), snapname) != n.end()) {
1021 
1022 		do_save = overwrite_file_dialog (prompter,
1023 						 _("Confirm Snapshot Overwrite"),
1024 						 _("A snapshot already exists with that name. Do you want to overwrite it?"));
1025 	}
1026 
1027 	if (do_save) {
1028 		save_state (snapname, switch_to_it);
1029 	}
1030 	else {
1031 		return false;
1032 	}
1033 
1034 	return true;
1035 }
1036 
1037 
1038 void
open_session()1039 ARDOUR_UI::open_session ()
1040 {
1041 	if (!check_audioengine (_main_window)) {
1042 		return;
1043 	}
1044 
1045 	/* ardour sessions are folders */
1046 	Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1047 	open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1048 	open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1049 	open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1050 
1051 	if (_session) {
1052 		string session_parent_dir = Glib::path_get_dirname(_session->path());
1053 		open_session_selector.set_current_folder(session_parent_dir);
1054 	} else {
1055 		open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1056 	}
1057 
1058 	Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1059 	try {
1060 		/* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1061 		string default_session_folder = Config->get_default_session_parent_dir();
1062 		open_session_selector.add_shortcut_folder (default_session_folder);
1063 	}
1064 	catch (Glib::Error const& e) {
1065 		std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1066 	}
1067 
1068 	FileFilter session_filter;
1069 	session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1070 	session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1071 	open_session_selector.add_filter (session_filter);
1072 
1073 	FileFilter archive_filter;
1074 	archive_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::session_archive_suffix));
1075 	archive_filter.set_name (_("Session Archives"));
1076 
1077 	open_session_selector.add_filter (archive_filter);
1078 
1079 	open_session_selector.set_filter (session_filter);
1080 
1081 	int response = open_session_selector.run();
1082 	open_session_selector.hide ();
1083 
1084 	switch (response) {
1085 		case Gtk::RESPONSE_ACCEPT:
1086 			break;
1087 		default:
1088 			return;
1089 	}
1090 
1091 	string session_path = open_session_selector.get_filename();
1092 	string path, name;
1093 	bool isnew;
1094 
1095 	if (session_path.length() > 0) {
1096 		int rv = ARDOUR::inflate_session (session_path,
1097 				Config->get_default_session_parent_dir(), path, name);
1098 		if (rv == 0) {
1099 			_session_is_new = false;
1100 			load_session (path, name);
1101 		}
1102 		else if (rv < 0) {
1103 			ArdourMessageDialog msg (_main_window,
1104 			                         string_compose (_("Extracting session-archive failed: %1"), inflate_error (rv)));
1105 			msg.run ();
1106 		}
1107 		else if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1108 			_session_is_new = isnew;
1109 			load_session (path, name);
1110 		}
1111 	}
1112 }
1113 
1114 void
open_recent_session()1115 ARDOUR_UI::open_recent_session ()
1116 {
1117 	bool can_return = (_session != 0);
1118 
1119 	SessionDialog recent_session_dialog;
1120 
1121 	while (true) {
1122 
1123 		ResponseType r = (ResponseType) recent_session_dialog.run ();
1124 
1125 		switch (r) {
1126 		case RESPONSE_ACCEPT:
1127 			break;
1128 		default:
1129 			if (can_return) {
1130 				recent_session_dialog.hide();
1131 				return;
1132 			} else {
1133 				exit (EXIT_FAILURE);
1134 			}
1135 		}
1136 
1137 		recent_session_dialog.hide();
1138 
1139 		bool should_be_new;
1140 
1141 		std::string path = recent_session_dialog.session_folder();
1142 		std::string state = recent_session_dialog.session_name (should_be_new);
1143 
1144 		if (should_be_new == true) {
1145 			continue;
1146 		}
1147 
1148 		_session_is_new = false;
1149 
1150 		if (load_session (path, state) == 0) {
1151 			break;
1152 		}
1153 
1154 		can_return = false;
1155 	}
1156 }
1157 
1158 int
ask_about_saving_session(const vector<string> & actions)1159 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1160 {
1161 	ArdourDialog window (_("Unsaved Session"));
1162 	Gtk::HBox dhbox;  // the hbox for the image and text
1163 	Gtk::Label  prompt_label;
1164 	Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING,  Gtk::ICON_SIZE_DIALOG));
1165 
1166 	string msg;
1167 
1168 	assert (actions.size() >= 3);
1169 
1170 	window.add_button (actions[0], RESPONSE_REJECT);
1171 	window.add_button (actions[1], RESPONSE_APPLY);
1172 	window.add_button (actions[2], RESPONSE_ACCEPT);
1173 
1174 	window.set_default_response (RESPONSE_ACCEPT);
1175 
1176 	Gtk::Button noquit_button (msg);
1177 	noquit_button.set_name ("EditorGTKButton");
1178 
1179 	string prompt;
1180 
1181 	if (_session->snap_name() == _session->name()) {
1182 		prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1183 					_session->snap_name());
1184 	} else {
1185 		prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1186 					_session->snap_name());
1187 	}
1188 
1189 	prompt_label.set_text (prompt);
1190 	prompt_label.set_name (X_("PrompterLabel"));
1191 	prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1192 
1193 	dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1194 	dhbox.set_homogeneous (false);
1195 	dhbox.pack_start (*dimage, false, false, 5);
1196 	dhbox.pack_start (prompt_label, true, false, 5);
1197 	window.get_vbox()->pack_start (dhbox);
1198 
1199 	window.set_name (_("Prompter"));
1200 	window.set_modal (true);
1201 	window.set_resizable (false);
1202 
1203 	dhbox.show();
1204 	prompt_label.show();
1205 	dimage->show();
1206 	window.show();
1207 	window.present ();
1208 
1209 	ResponseType r = (ResponseType) window.run();
1210 
1211 	window.hide ();
1212 
1213 	switch (r) {
1214 	case RESPONSE_ACCEPT: // save and get out of here
1215 		return 1;
1216 	case RESPONSE_APPLY:  // get out of here
1217 		return 0;
1218 	default:
1219 		break;
1220 	}
1221 
1222 	return -1;
1223 }
1224 
1225 
1226 void
save_session_at_its_request(std::string snapshot_name)1227 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
1228 {
1229 	if (_session) {
1230 		_session->save_state (snapshot_name);
1231 	}
1232 }
1233 
1234 gint
autosave_session()1235 ARDOUR_UI::autosave_session ()
1236 {
1237 	if (g_main_depth() > 1) {
1238 		/* inside a recursive main loop,
1239 		   give up because we may not be able to
1240 		   take a lock.
1241 		*/
1242 		return 1;
1243 	}
1244 
1245 	if (!Config->get_periodic_safety_backups()) {
1246 		return 1;
1247 	}
1248 
1249 	if (_session) {
1250 		_session->maybe_write_autosave();
1251 	}
1252 
1253 	return 1;
1254 }
1255