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