lincoln's patch to use QM onset detection in RFerret, and other tweaks
[ardour2.git] / gtk2_ardour / ardour_ui.cc
blob5588e2e5a9cb616305f4b948fa32abb28811b65a
1 /*
2 Copyright (C) 1999-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
24 #include <stdint.h>
26 #include <algorithm>
27 #include <cmath>
28 #include <fcntl.h>
29 #include <signal.h>
30 #include <unistd.h>
31 #include <time.h>
32 #include <cerrno>
33 #include <fstream>
35 #include <iostream>
37 #include <sys/resource.h>
39 #include <gtkmm/messagedialog.h>
40 #include <gtkmm/accelmap.h>
42 #include "pbd/error.h"
43 #include "pbd/basename.h"
44 #include "pbd/compose.h"
45 #include "pbd/failed_constructor.h"
46 #include "pbd/enumwriter.h"
47 #include "pbd/memento_command.h"
48 #include "pbd/openuri.h"
49 #include "pbd/file_utils.h"
51 #include "gtkmm2ext/application.h"
52 #include "gtkmm2ext/gtk_ui.h"
53 #include "gtkmm2ext/utils.h"
54 #include "gtkmm2ext/click_box.h"
55 #include "gtkmm2ext/fastmeter.h"
56 #include "gtkmm2ext/popup.h"
57 #include "gtkmm2ext/window_title.h"
59 #include "midi++/manager.h"
61 #include "ardour/ardour.h"
62 #include "ardour/callback.h"
63 #include "ardour/profile.h"
64 #include "ardour/session_directory.h"
65 #include "ardour/session_route.h"
66 #include "ardour/session_state_utils.h"
67 #include "ardour/session_utils.h"
68 #include "ardour/port.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/playlist.h"
71 #include "ardour/utils.h"
72 #include "ardour/audio_diskstream.h"
73 #include "ardour/audiofilesource.h"
74 #include "ardour/recent_sessions.h"
75 #include "ardour/port.h"
76 #include "ardour/audio_track.h"
77 #include "ardour/midi_track.h"
78 #include "ardour/filesystem_paths.h"
79 #include "ardour/filename_extensions.h"
81 typedef uint64_t microseconds_t;
83 #include "about.h"
84 #include "actions.h"
85 #include "add_route_dialog.h"
86 #include "ambiguous_file_dialog.h"
87 #include "ardour_ui.h"
88 #include "audio_clock.h"
89 #include "bundle_manager.h"
90 #include "engine_dialog.h"
91 #include "gain_meter.h"
92 #include "global_port_matrix.h"
93 #include "gui_thread.h"
94 #include "keyboard.h"
95 #include "location_ui.h"
96 #include "missing_file_dialog.h"
97 #include "missing_plugin_dialog.h"
98 #include "mixer_ui.h"
99 #include "opts.h"
100 #include "processor_box.h"
101 #include "prompter.h"
102 #include "public_editor.h"
103 #include "route_time_axis.h"
104 #include "session_metadata_dialog.h"
105 #include "speaker_dialog.h"
106 #include "splash.h"
107 #include "startup.h"
108 #include "theme_manager.h"
109 #include "time_axis_view_item.h"
110 #include "utils.h"
111 #include "window_proxy.h"
113 #include "i18n.h"
115 using namespace ARDOUR;
116 using namespace PBD;
117 using namespace Gtkmm2ext;
118 using namespace Gtk;
120 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
121 UIConfiguration *ARDOUR_UI::ui_config = 0;
123 sigc::signal<void,bool> ARDOUR_UI::Blink;
124 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
125 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
126 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
128 bool could_be_a_valid_path (const string& path);
130 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
132 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
134 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
135 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
136 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
137 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
139 /* preroll stuff */
141 preroll_button (_("pre\nroll")),
142 postroll_button (_("post\nroll")),
144 /* big clock */
146 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
148 /* transport */
150 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
151 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
152 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
153 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
154 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
155 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
156 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
157 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
158 shuttle_controller_binding_proxy (shuttle_controllable),
160 roll_button (roll_controllable),
161 stop_button (stop_controllable),
162 goto_start_button (goto_start_controllable),
163 goto_end_button (goto_end_controllable),
164 auto_loop_button (auto_loop_controllable),
165 play_selection_button (play_selection_controllable),
166 rec_button (rec_controllable),
168 shuttle_units_button (_("% ")),
170 punch_in_button (_("Punch In")),
171 punch_out_button (_("Punch Out")),
172 auto_return_button (_("Auto Return")),
173 auto_play_button (_("Auto Play")),
174 auto_input_button (_("Auto Input")),
175 click_button (_("Click")),
176 time_master_button (_("time\nmaster")),
178 auditioning_alert_button (_("AUDITION")),
179 solo_alert_button (_("SOLO")),
181 error_log_button (_("Errors"))
184 using namespace Gtk::Menu_Helpers;
186 Gtkmm2ext::init();
189 #ifdef TOP_MENUBAR
190 // _auto_display_errors = false;
192 * This was commented out as it wasn't defined
193 * in A3 IIRC. If this is not needed it should
194 * be completely removed.
196 #endif
198 about = 0;
199 splash = 0;
200 _startup = 0;
202 if (theArdourUI == 0) {
203 theArdourUI = this;
206 ui_config = new UIConfiguration();
207 theme_manager = new ThemeManager();
209 editor = 0;
210 mixer = 0;
211 editor = 0;
212 engine = 0;
213 _session_is_new = false;
214 big_clock_window = 0;
215 big_clock_height = 0;
216 big_clock_resize_in_progress = false;
217 session_selector_window = 0;
218 last_key_press_time = 0;
219 _will_create_new_session_automatically = false;
220 add_route_dialog = 0;
221 route_params = 0;
222 rc_option_editor = 0;
223 session_option_editor = 0;
224 location_ui = 0;
225 open_session_selector = 0;
226 have_configure_timeout = false;
227 have_disk_speed_dialog_displayed = false;
228 session_loaded = false;
229 last_speed_displayed = -1.0f;
230 ignore_dual_punch = false;
231 original_big_clock_width = -1;
232 original_big_clock_height = -1;
233 original_big_clock_font_size = 0;
235 roll_button.unset_flags (Gtk::CAN_FOCUS);
236 stop_button.unset_flags (Gtk::CAN_FOCUS);
237 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
238 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
239 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
240 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
241 rec_button.unset_flags (Gtk::CAN_FOCUS);
243 last_configure_time= 0;
245 shuttle_grabbed = false;
246 shuttle_fract = 0.0;
247 shuttle_max_speed = 8.0f;
249 shuttle_style_menu = 0;
250 shuttle_unit_menu = 0;
252 // We do not have jack linked in yet so;
254 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
256 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
257 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
259 /* handle dialog requests */
261 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
263 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
265 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
267 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
269 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
271 /* handle requests to quit (coming from JACK session) */
273 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
275 /* handle requests to deal with missing files */
277 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
279 /* and ambiguous files */
281 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
283 /* lets get this party started */
285 try {
286 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
287 throw failed_constructor ();
290 setup_gtk_ardour_enums ();
291 setup_profile ();
293 GainMeter::setup_slider_pix ();
294 RouteTimeAxisView::setup_slider_pix ();
295 SendProcessorEntry::setup_slider_pix ();
296 SessionEvent::create_per_thread_pool ("GUI", 512);
298 } catch (failed_constructor& err) {
299 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
300 // pass it on up
301 throw;
304 /* we like keyboards */
306 keyboard = new ArdourKeyboard(*this);
308 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
309 if (node) {
310 keyboard->set_state (*node, Stateful::loading_state_version);
313 reset_dpi();
315 TimeAxisViewItem::set_constant_heights ();
317 /* The following must happen after ARDOUR::init() so that Config is set up */
319 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
320 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
321 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
323 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
324 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
325 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
326 Config->extra_xml (X_("UI")),
327 string_compose ("toggle-%1-connection-manager", (*i).to_string())
331 setup_clock ();
332 speaker_config_window->set (new SpeakerDialog);
334 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
335 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
337 platform_setup ();
340 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
341 bool
342 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
344 delete _startup;
345 _startup = new ArdourStartup ();
347 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
349 if (audio_setup && _startup->engine_control()) {
350 _startup->engine_control()->set_state (*audio_setup);
353 _startup->set_new_only (should_be_new);
354 if (!load_template.empty()) {
355 _startup->set_load_template( load_template );
357 _startup->present ();
359 main().run();
361 _startup->hide ();
363 switch (_startup->response()) {
364 case RESPONSE_OK:
365 return true;
366 default:
367 return false;
372 ARDOUR_UI::create_engine ()
374 // this gets called every time by new_session()
376 if (engine) {
377 return 0;
380 loading_message (_("Starting audio engine"));
382 try {
383 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
385 } catch (...) {
387 return -1;
390 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
391 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
392 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
394 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
396 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
398 post_engine ();
400 return 0;
403 void
404 ARDOUR_UI::post_engine ()
406 /* Things to be done once we create the AudioEngine
409 ARDOUR::init_post_engine ();
411 ActionManager::init ();
412 _tooltips.enable();
414 if (setup_windows ()) {
415 throw failed_constructor ();
418 check_memory_locking();
420 /* this is the first point at which all the keybindings are available */
422 if (ARDOUR_COMMAND_LINE::show_key_actions) {
423 vector<string> names;
424 vector<string> paths;
425 vector<string> tooltips;
426 vector<string> keys;
427 vector<AccelKey> bindings;
429 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
431 vector<string>::iterator n;
432 vector<string>::iterator k;
433 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
434 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
437 exit (0);
440 blink_timeout_tag = -1;
442 /* this being a GUI and all, we want peakfiles */
444 AudioFileSource::set_build_peakfiles (true);
445 AudioFileSource::set_build_missing_peakfiles (true);
447 /* set default clock modes */
449 if (Profile->get_sae()) {
450 primary_clock.set_mode (AudioClock::BBT);
451 secondary_clock.set_mode (AudioClock::MinSec);
452 } else {
453 primary_clock.set_mode (AudioClock::Timecode);
454 secondary_clock.set_mode (AudioClock::BBT);
457 /* start the time-of-day-clock */
459 #ifndef GTKOSX
460 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
461 update_wall_clock ();
462 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
463 #endif
465 update_disk_space ();
466 update_cpu_load ();
467 update_sample_rate (engine->frame_rate());
469 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
470 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
471 Config->map_parameters (pc);
473 /* now start and maybe save state */
475 if (do_engine_start () == 0) {
476 if (_session && _session_is_new) {
477 /* we need to retain initial visual
478 settings for a new session
480 _session->save_state ("");
485 ARDOUR_UI::~ARDOUR_UI ()
487 delete keyboard;
488 delete editor;
489 delete mixer;
490 delete add_route_dialog;
493 void
494 ARDOUR_UI::pop_back_splash ()
496 if (Splash::instance()) {
497 // Splash::instance()->pop_back();
498 Splash::instance()->hide ();
502 gint
503 ARDOUR_UI::configure_timeout ()
505 if (last_configure_time == 0) {
506 /* no configure events yet */
507 return true;
510 /* force a gap of 0.5 seconds since the last configure event
513 if (get_microseconds() - last_configure_time < 500000) {
514 return true;
515 } else {
516 have_configure_timeout = false;
517 cerr << "config event-driven save\n";
518 save_ardour_state ();
519 return false;
523 gboolean
524 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
526 if (have_configure_timeout) {
527 last_configure_time = get_microseconds();
528 } else {
529 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
530 have_configure_timeout = true;
533 return FALSE;
536 void
537 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
539 const XMLProperty* prop;
541 if ((prop = node.property ("roll")) != 0) {
542 roll_controllable->set_id (prop->value());
544 if ((prop = node.property ("stop")) != 0) {
545 stop_controllable->set_id (prop->value());
547 if ((prop = node.property ("goto-start")) != 0) {
548 goto_start_controllable->set_id (prop->value());
550 if ((prop = node.property ("goto-end")) != 0) {
551 goto_end_controllable->set_id (prop->value());
553 if ((prop = node.property ("auto-loop")) != 0) {
554 auto_loop_controllable->set_id (prop->value());
556 if ((prop = node.property ("play-selection")) != 0) {
557 play_selection_controllable->set_id (prop->value());
559 if ((prop = node.property ("rec")) != 0) {
560 rec_controllable->set_id (prop->value());
562 if ((prop = node.property ("shuttle")) != 0) {
563 shuttle_controllable->set_id (prop->value());
567 XMLNode&
568 ARDOUR_UI::get_transport_controllable_state ()
570 XMLNode* node = new XMLNode(X_("TransportControllables"));
571 char buf[64];
573 roll_controllable->id().print (buf, sizeof (buf));
574 node->add_property (X_("roll"), buf);
575 stop_controllable->id().print (buf, sizeof (buf));
576 node->add_property (X_("stop"), buf);
577 goto_start_controllable->id().print (buf, sizeof (buf));
578 node->add_property (X_("goto_start"), buf);
579 goto_end_controllable->id().print (buf, sizeof (buf));
580 node->add_property (X_("goto_end"), buf);
581 auto_loop_controllable->id().print (buf, sizeof (buf));
582 node->add_property (X_("auto_loop"), buf);
583 play_selection_controllable->id().print (buf, sizeof (buf));
584 node->add_property (X_("play_selection"), buf);
585 rec_controllable->id().print (buf, sizeof (buf));
586 node->add_property (X_("rec"), buf);
587 shuttle_controllable->id().print (buf, sizeof (buf));
588 node->add_property (X_("shuttle"), buf);
590 return *node;
594 gint
595 ARDOUR_UI::autosave_session ()
597 if (g_main_depth() > 1) {
598 /* inside a recursive main loop,
599 give up because we may not be able to
600 take a lock.
602 return 1;
605 if (!Config->get_periodic_safety_backups()) {
606 return 1;
609 if (_session) {
610 _session->maybe_write_autosave();
613 return 1;
616 void
617 ARDOUR_UI::update_autosave ()
619 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
621 if (_session && _session->dirty()) {
622 if (_autosave_connection.connected()) {
623 _autosave_connection.disconnect();
626 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
627 Config->get_periodic_safety_backup_interval() * 1000);
629 } else {
630 if (_autosave_connection.connected()) {
631 _autosave_connection.disconnect();
636 void
637 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
639 string title;
640 if (we_set_params) {
641 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
642 } else {
643 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
646 MessageDialog win (title,
647 false,
648 Gtk::MESSAGE_INFO,
649 Gtk::BUTTONS_NONE);
651 if (we_set_params) {
652 win.set_secondary_text(_("There are several possible reasons:\n\
654 1) You requested audio parameters that are not supported..\n\
655 2) JACK is running as another user.\n\
657 Please consider the possibilities, and perhaps try different parameters."));
658 } else {
659 win.set_secondary_text(_("There are several possible reasons:\n\
661 1) JACK is not running.\n\
662 2) JACK is running as another user, perhaps root.\n\
663 3) There is already another client called \"ardour\".\n\
665 Please consider the possibilities, and perhaps (re)start JACK."));
668 if (toplevel) {
669 win.set_transient_for (*toplevel);
672 if (we_set_params) {
673 win.add_button (Stock::OK, RESPONSE_CLOSE);
674 } else {
675 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
678 win.set_default_response (RESPONSE_CLOSE);
680 win.show_all ();
681 win.set_position (Gtk::WIN_POS_CENTER);
682 pop_back_splash ();
684 /* we just don't care about the result, but we want to block */
686 win.run ();
689 void
690 ARDOUR_UI::startup ()
692 Application* app = Application::instance ();
694 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
695 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
697 #ifdef PHONE_HOME
698 call_the_mothership (VERSIONSTRING);
699 #endif
701 app->ready ();
703 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
704 exit (1);
707 use_config ();
709 goto_editor_window ();
711 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
712 to be opened on top of the editor window that goto_editor_window() just opened.
714 add_window_proxy (location_ui);
715 add_window_proxy (big_clock_window);
716 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
717 add_window_proxy (_global_port_matrix[*i]);
720 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
723 void
724 ARDOUR_UI::no_memory_warning ()
726 XMLNode node (X_("no-memory-warning"));
727 Config->add_instant_xml (node);
730 void
731 ARDOUR_UI::check_memory_locking ()
733 #ifdef __APPLE__
734 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
735 return;
736 #else // !__APPLE__
738 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
740 if (engine->is_realtime() && memory_warning_node == 0) {
742 struct rlimit limits;
743 int64_t ram;
744 long pages, page_size;
746 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
747 ram = 0;
748 } else {
749 ram = (int64_t) pages * (int64_t) page_size;
752 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
753 return;
756 if (limits.rlim_cur != RLIM_INFINITY) {
758 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
761 MessageDialog msg (
762 string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
763 "This might cause %1 to run out of memory before your system "
764 "runs out of memory. \n\n"
765 "You can view the memory limit with 'ulimit -l', "
766 "and it is normally controlled by /etc/security/limits.conf"),
767 PROGRAM_NAME).c_str());
769 VBox* vbox = msg.get_vbox();
770 HBox hbox;
771 CheckButton cb (_("Do not show this window again"));
773 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
775 hbox.pack_start (cb, true, false);
776 vbox->pack_start (hbox);
777 cb.show();
778 vbox->show();
779 hbox.show ();
781 pop_back_splash ();
783 editor->ensure_float (msg);
784 msg.run ();
788 #endif // !__APPLE__
792 void
793 ARDOUR_UI::queue_finish ()
795 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
798 bool
799 ARDOUR_UI::idle_finish ()
801 finish ();
802 return false; /* do not call again */
805 void
806 ARDOUR_UI::finish()
808 if (_session) {
809 int tries = 0;
811 if (_session->transport_rolling() && (++tries < 8)) {
812 _session->request_stop (false, true);
813 usleep (10000);
816 if (_session->dirty()) {
817 switch (ask_about_saving_session(_("quit"))) {
818 case -1:
819 return;
820 break;
821 case 1:
822 /* use the default name */
823 if (save_state_canfail ("")) {
824 /* failed - don't quit */
825 MessageDialog msg (*editor,
826 _("\
827 Ardour was unable to save your session.\n\n\
828 If you still wish to quit, please use the\n\n\
829 \"Just quit\" option."));
830 pop_back_splash();
831 msg.run ();
832 return;
834 break;
835 case 0:
836 break;
840 second_connection.disconnect ();
841 point_one_second_connection.disconnect ();
842 point_oh_five_second_connection.disconnect ();
843 point_zero_one_second_connection.disconnect();
846 /* Save state before deleting the session, as that causes some
847 windows to be destroyed before their visible state can be
848 saved.
850 save_ardour_state ();
852 if (_session) {
853 // _session->set_deletion_in_progress ();
854 _session->set_clean ();
855 _session->remove_pending_capture_state ();
856 delete _session;
857 _session = 0;
860 ArdourDialog::close_all_dialogs ();
861 engine->stop (true);
862 quit ();
866 ARDOUR_UI::ask_about_saving_session (const string & what)
868 ArdourDialog window (_("Unsaved Session"));
869 Gtk::HBox dhbox; // the hbox for the image and text
870 Gtk::Label prompt_label;
871 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
873 string msg;
875 msg = string_compose(_("Don't %1"), what);
876 window.add_button (msg, RESPONSE_REJECT);
877 msg = string_compose(_("Just %1"), what);
878 window.add_button (msg, RESPONSE_APPLY);
879 msg = string_compose(_("Save and %1"), what);
880 window.add_button (msg, RESPONSE_ACCEPT);
882 window.set_default_response (RESPONSE_ACCEPT);
884 Gtk::Button noquit_button (msg);
885 noquit_button.set_name ("EditorGTKButton");
887 string prompt;
888 string type;
890 if (_session->snap_name() == _session->name()) {
891 type = _("session");
892 } else {
893 type = _("snapshot");
895 prompt = string_compose(_("The %1 \"%2\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
896 type, _session->snap_name());
898 prompt_label.set_text (prompt);
899 prompt_label.set_name (X_("PrompterLabel"));
900 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
902 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
903 dhbox.set_homogeneous (false);
904 dhbox.pack_start (*dimage, false, false, 5);
905 dhbox.pack_start (prompt_label, true, false, 5);
906 window.get_vbox()->pack_start (dhbox);
908 window.set_name (_("Prompter"));
909 window.set_position (Gtk::WIN_POS_MOUSE);
910 window.set_modal (true);
911 window.set_resizable (false);
913 dhbox.show();
914 prompt_label.show();
915 dimage->show();
916 window.show();
917 window.set_keep_above (true);
918 window.present ();
920 ResponseType r = (ResponseType) window.run();
922 window.hide ();
924 switch (r) {
925 case RESPONSE_ACCEPT: // save and get out of here
926 return 1;
927 case RESPONSE_APPLY: // get out of here
928 return 0;
929 default:
930 break;
933 return -1;
936 gint
937 ARDOUR_UI::every_second ()
939 update_cpu_load ();
940 update_buffer_load ();
941 update_disk_space ();
942 return TRUE;
945 gint
946 ARDOUR_UI::every_point_one_seconds ()
948 update_speed_display ();
949 RapidScreenUpdate(); /* EMIT_SIGNAL */
950 return TRUE;
953 gint
954 ARDOUR_UI::every_point_zero_one_seconds ()
956 // august 2007: actual update frequency: 40Hz, not 100Hz
958 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
959 return TRUE;
962 void
963 ARDOUR_UI::update_sample_rate (framecnt_t)
965 char buf[32];
967 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
969 if (!engine->connected()) {
971 snprintf (buf, sizeof (buf), _("disconnected"));
973 } else {
975 framecnt_t rate = engine->frame_rate();
977 if (fmod (rate, 1000.0) != 0.0) {
978 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
979 (float) rate/1000.0f,
980 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
981 } else {
982 snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"),
983 rate/1000,
984 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
988 sample_rate_label.set_text (buf);
991 void
992 ARDOUR_UI::update_cpu_load ()
994 char buf[32];
995 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
996 cpu_load_label.set_text (buf);
999 void
1000 ARDOUR_UI::update_buffer_load ()
1002 char buf[64];
1003 uint32_t c, p;
1005 if (_session) {
1006 c = _session->capture_load ();
1007 p = _session->playback_load ();
1009 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
1010 _session->playback_load(), _session->capture_load());
1011 buffer_load_label.set_text (buf);
1012 } else {
1013 buffer_load_label.set_text ("");
1017 void
1018 ARDOUR_UI::count_recenabled_streams (Route& route)
1020 Track* track = dynamic_cast<Track*>(&route);
1021 if (track && track->record_enabled()) {
1022 rec_enabled_streams += track->n_inputs().n_total();
1026 void
1027 ARDOUR_UI::update_disk_space()
1029 if (_session == 0) {
1030 return;
1033 framecnt_t frames = _session->available_capture_duration();
1034 char buf[64];
1035 framecnt_t fr = _session->frame_rate();
1037 if (frames == max_framecnt) {
1038 strcpy (buf, _("Disk: 24hrs+"));
1039 } else {
1040 rec_enabled_streams = 0;
1041 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1043 if (rec_enabled_streams) {
1044 frames /= rec_enabled_streams;
1047 int hrs;
1048 int mins;
1049 int secs;
1051 hrs = frames / (fr * 3600);
1052 frames -= hrs * fr * 3600;
1053 mins = frames / (fr * 60);
1054 frames -= mins * fr * 60;
1055 secs = frames / fr;
1057 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1060 disk_space_label.set_text (buf);
1062 // An attempt to make the disk space label flash red when space has run out.
1064 if (frames < fr * 60 * 5) {
1065 /* disk_space_box.style ("disk_space_label_empty"); */
1066 } else {
1067 /* disk_space_box.style ("disk_space_label"); */
1072 gint
1073 ARDOUR_UI::update_wall_clock ()
1075 time_t now;
1076 struct tm *tm_now;
1077 char buf[16];
1079 time (&now);
1080 tm_now = localtime (&now);
1082 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1083 wall_clock_label.set_text (buf);
1085 return TRUE;
1088 gint
1089 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1091 session_popup_menu->popup (0, 0);
1092 return TRUE;
1095 void
1096 ARDOUR_UI::redisplay_recent_sessions ()
1098 std::vector<sys::path> session_directories;
1099 RecentSessionsSorter cmp;
1101 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1102 recent_session_model->clear ();
1104 ARDOUR::RecentSessions rs;
1105 ARDOUR::read_recent_sessions (rs);
1107 if (rs.empty()) {
1108 recent_session_display.set_model (recent_session_model);
1109 return;
1112 // sort them alphabetically
1113 sort (rs.begin(), rs.end(), cmp);
1115 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1116 session_directories.push_back ((*i).second);
1119 for (vector<sys::path>::const_iterator i = session_directories.begin();
1120 i != session_directories.end(); ++i)
1122 std::vector<sys::path> state_file_paths;
1124 // now get available states for this session
1126 get_state_files_in_directory (*i, state_file_paths);
1128 vector<string*>* states;
1129 vector<const gchar*> item;
1130 string fullpath = (*i).to_string();
1132 /* remove any trailing / */
1134 if (fullpath[fullpath.length()-1] == '/') {
1135 fullpath = fullpath.substr (0, fullpath.length()-1);
1138 /* check whether session still exists */
1139 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1140 /* session doesn't exist */
1141 cerr << "skipping non-existent session " << fullpath << endl;
1142 continue;
1145 /* now get available states for this session */
1147 if ((states = Session::possible_states (fullpath)) == 0) {
1148 /* no state file? */
1149 continue;
1152 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1154 Gtk::TreeModel::Row row = *(recent_session_model->append());
1156 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1157 row[recent_session_columns.fullpath] = fullpath;
1159 if (state_file_names.size() > 1) {
1161 // add the children
1163 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1164 i2 != state_file_names.end(); ++i2)
1167 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1169 child_row[recent_session_columns.visible_name] = *i2;
1170 child_row[recent_session_columns.fullpath] = fullpath;
1175 recent_session_display.set_model (recent_session_model);
1178 void
1179 ARDOUR_UI::build_session_selector ()
1181 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1183 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1185 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1186 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1187 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1188 recent_session_model = TreeStore::create (recent_session_columns);
1189 recent_session_display.set_model (recent_session_model);
1190 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1191 recent_session_display.set_headers_visible (false);
1192 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1193 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1195 scroller->add (recent_session_display);
1196 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1198 session_selector_window->set_name ("SessionSelectorWindow");
1199 session_selector_window->set_size_request (200, 400);
1200 session_selector_window->get_vbox()->pack_start (*scroller);
1202 recent_session_display.show();
1203 scroller->show();
1204 //session_selector_window->get_vbox()->show();
1207 void
1208 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1210 session_selector_window->response (RESPONSE_ACCEPT);
1213 void
1214 ARDOUR_UI::open_recent_session ()
1216 bool can_return = (_session != 0);
1218 if (session_selector_window == 0) {
1219 build_session_selector ();
1222 redisplay_recent_sessions ();
1224 while (true) {
1226 session_selector_window->set_position (WIN_POS_MOUSE);
1228 ResponseType r = (ResponseType) session_selector_window->run ();
1230 switch (r) {
1231 case RESPONSE_ACCEPT:
1232 break;
1233 default:
1234 if (can_return) {
1235 session_selector_window->hide();
1236 return;
1237 } else {
1238 exit (1);
1242 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1243 continue;
1246 session_selector_window->hide();
1248 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1250 if (i == recent_session_model->children().end()) {
1251 return;
1254 std::string path = (*i)[recent_session_columns.fullpath];
1255 std::string state = (*i)[recent_session_columns.visible_name];
1257 _session_is_new = false;
1259 if (load_session (path, state) == 0) {
1260 break;
1263 can_return = false;
1267 bool
1268 ARDOUR_UI::check_audioengine ()
1270 if (engine) {
1271 if (!engine->connected()) {
1272 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1273 "You cannot open or close sessions in this condition"),
1274 PROGRAM_NAME));
1275 pop_back_splash ();
1276 msg.run ();
1277 return false;
1279 return true;
1280 } else {
1281 return false;
1285 void
1286 ARDOUR_UI::open_session ()
1288 if (!check_audioengine()) {
1289 return;
1293 /* popup selector window */
1295 if (open_session_selector == 0) {
1297 /* ardour sessions are folders */
1299 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1300 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1301 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1302 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1304 FileFilter session_filter;
1305 session_filter.add_pattern ("*.ardour");
1306 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1307 open_session_selector->add_filter (session_filter);
1308 open_session_selector->set_filter (session_filter);
1311 int response = open_session_selector->run();
1312 open_session_selector->hide ();
1314 switch (response) {
1315 case RESPONSE_ACCEPT:
1316 break;
1317 default:
1318 open_session_selector->hide();
1319 return;
1322 open_session_selector->hide();
1323 string session_path = open_session_selector->get_filename();
1324 string path, name;
1325 bool isnew;
1327 if (session_path.length() > 0) {
1328 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1329 _session_is_new = isnew;
1330 load_session (path, name);
1336 void
1337 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1339 list<boost::shared_ptr<MidiTrack> > tracks;
1341 if (_session == 0) {
1342 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1343 return;
1346 try {
1347 if (disk) {
1349 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1351 if (tracks.size() != how_many) {
1352 if (how_many == 1) {
1353 error << _("could not create a new midi track") << endmsg;
1354 } else {
1355 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1358 } /*else {
1359 if ((route = _session->new_midi_route ()) == 0) {
1360 error << _("could not create new midi bus") << endmsg;
1365 catch (...) {
1366 MessageDialog msg (*editor,
1367 string_compose (_("There are insufficient JACK ports available\n\
1368 to create a new track or bus.\n\
1369 You should save %1, exit and\n\
1370 restart JACK with more ports."), PROGRAM_NAME));
1371 msg.run ();
1376 void
1377 ARDOUR_UI::session_add_audio_route (
1378 bool track,
1379 int32_t input_channels,
1380 int32_t output_channels,
1381 ARDOUR::TrackMode mode,
1382 RouteGroup* route_group,
1383 uint32_t how_many,
1384 string const & name_template
1387 list<boost::shared_ptr<AudioTrack> > tracks;
1388 RouteList routes;
1390 if (_session == 0) {
1391 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1392 return;
1395 try {
1396 if (track) {
1397 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1399 if (tracks.size() != how_many) {
1400 if (how_many == 1) {
1401 error << _("could not create a new audio track") << endmsg;
1402 } else {
1403 error << string_compose (_("could only create %1 of %2 new audio %3"),
1404 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1408 } else {
1410 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1412 if (routes.size() != how_many) {
1413 if (how_many == 1) {
1414 error << _("could not create a new audio track") << endmsg;
1415 } else {
1416 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1422 catch (...) {
1423 MessageDialog msg (*editor,
1424 string_compose (_("There are insufficient JACK ports available\n\
1425 to create a new track or bus.\n\
1426 You should save %1, exit and\n\
1427 restart JACK with more ports."), PROGRAM_NAME));
1428 pop_back_splash ();
1429 msg.run ();
1433 void
1434 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1436 framecnt_t _preroll = 0;
1438 if (_session) {
1439 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1440 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1442 if (new_position > _preroll) {
1443 new_position -= _preroll;
1444 } else {
1445 new_position = 0;
1448 _session->request_locate (new_position, with_roll);
1452 void
1453 ARDOUR_UI::transport_goto_start ()
1455 if (_session) {
1456 _session->goto_start();
1458 /* force displayed area in editor to start no matter
1459 what "follow playhead" setting is.
1462 if (editor) {
1463 editor->center_screen (_session->current_start_frame ());
1468 void
1469 ARDOUR_UI::transport_goto_zero ()
1471 if (_session) {
1472 _session->request_locate (0);
1474 /* force displayed area in editor to start no matter
1475 what "follow playhead" setting is.
1478 if (editor) {
1479 editor->reset_x_origin (0);
1484 void
1485 ARDOUR_UI::transport_goto_wallclock ()
1487 if (_session && editor) {
1489 time_t now;
1490 struct tm tmnow;
1491 framepos_t frames;
1493 time (&now);
1494 localtime_r (&now, &tmnow);
1496 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1497 frames += tmnow.tm_min * (60 * _session->frame_rate());
1498 frames += tmnow.tm_sec * _session->frame_rate();
1500 _session->request_locate (frames, _session->transport_rolling ());
1502 /* force displayed area in editor to start no matter
1503 what "follow playhead" setting is.
1506 if (editor) {
1507 editor->center_screen (frames);
1512 void
1513 ARDOUR_UI::transport_goto_end ()
1515 if (_session) {
1516 framepos_t const frame = _session->current_end_frame();
1517 _session->request_locate (frame);
1519 /* force displayed area in editor to start no matter
1520 what "follow playhead" setting is.
1523 if (editor) {
1524 editor->center_screen (frame);
1529 void
1530 ARDOUR_UI::transport_stop ()
1532 if (!_session) {
1533 return;
1536 if (_session->is_auditioning()) {
1537 _session->cancel_audition ();
1538 return;
1541 _session->request_stop (false, true);
1544 void
1545 ARDOUR_UI::transport_stop_and_forget_capture ()
1547 if (_session) {
1548 _session->request_stop (true, true);
1552 void
1553 ARDOUR_UI::remove_last_capture()
1555 if (editor) {
1556 editor->remove_last_capture();
1560 void
1561 ARDOUR_UI::transport_record (bool roll)
1564 if (_session) {
1565 switch (_session->record_status()) {
1566 case Session::Disabled:
1567 if (_session->ntracks() == 0) {
1568 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1569 msg.run ();
1570 return;
1572 _session->maybe_enable_record ();
1573 if (roll) {
1574 transport_roll ();
1576 break;
1577 case Session::Recording:
1578 if (roll) {
1579 _session->request_stop();
1580 } else {
1581 _session->disable_record (false, true);
1583 break;
1585 case Session::Enabled:
1586 _session->disable_record (false, true);
1589 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1592 void
1593 ARDOUR_UI::transport_roll ()
1595 if (!_session) {
1596 return;
1599 if (_session->is_auditioning()) {
1600 return;
1603 #if 0
1604 if (_session->config.get_external_sync()) {
1605 switch (_session->config.get_sync_source()) {
1606 case JACK:
1607 break;
1608 default:
1609 /* transport controlled by the master */
1610 return;
1613 #endif
1615 bool rolling = _session->transport_rolling();
1617 if (_session->get_play_loop()) {
1618 /* XXX it is not possible to just leave seamless loop and keep
1619 playing at present (nov 4th 2009)
1621 if (!Config->get_seamless_loop()) {
1622 _session->request_play_loop (false, true);
1624 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1625 /* stop playing a range if we currently are */
1626 _session->request_play_range (0, true);
1629 if (join_play_range_button.get_active()) {
1630 _session->request_play_range (&editor->get_selection().time, true);
1633 if (!rolling) {
1634 _session->request_transport_speed (1.0f);
1638 void
1639 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1642 if (!_session) {
1643 return;
1646 if (_session->is_auditioning()) {
1647 _session->cancel_audition ();
1648 return;
1651 #if 0
1652 if (_session->config.get_external_sync()) {
1653 switch (_session->config.get_sync_source()) {
1654 case JACK:
1655 break;
1656 default:
1657 /* transport controlled by the master */
1658 return;
1661 #endif
1663 bool rolling = _session->transport_rolling();
1664 bool affect_transport = true;
1666 if (rolling && roll_out_of_bounded_mode) {
1667 /* drop out of loop/range playback but leave transport rolling */
1668 if (_session->get_play_loop()) {
1669 if (Config->get_seamless_loop()) {
1670 /* the disk buffers contain copies of the loop - we can't
1671 just keep playing, so stop the transport. the user
1672 can restart as they wish.
1674 affect_transport = true;
1675 } else {
1676 /* disk buffers are normal, so we can keep playing */
1677 affect_transport = false;
1679 _session->request_play_loop (false, true);
1680 } else if (_session->get_play_range ()) {
1681 affect_transport = false;
1682 _session->request_play_range (0, true);
1686 if (affect_transport) {
1687 if (rolling) {
1688 _session->request_stop (with_abort, true);
1689 } else {
1690 if (join_play_range_button.get_active()) {
1691 _session->request_play_range (&editor->get_selection().time, true);
1694 _session->request_transport_speed (1.0f);
1699 void
1700 ARDOUR_UI::toggle_session_auto_loop ()
1702 if (!_session) {
1703 return;
1706 if (_session->get_play_loop()) {
1708 if (_session->transport_rolling()) {
1710 Location * looploc = _session->locations()->auto_loop_location();
1712 if (looploc) {
1713 _session->request_locate (looploc->start(), true);
1714 _session->request_play_loop (false);
1717 } else {
1718 _session->request_play_loop (false);
1720 } else {
1722 Location * looploc = _session->locations()->auto_loop_location();
1724 if (looploc) {
1725 _session->request_play_loop (true);
1730 void
1731 ARDOUR_UI::transport_play_selection ()
1733 if (!_session) {
1734 return;
1737 editor->play_selection ();
1740 void
1741 ARDOUR_UI::transport_rewind (int option)
1743 float current_transport_speed;
1745 if (_session) {
1746 current_transport_speed = _session->transport_speed();
1748 if (current_transport_speed >= 0.0f) {
1749 switch (option) {
1750 case 0:
1751 _session->request_transport_speed (-1.0f);
1752 break;
1753 case 1:
1754 _session->request_transport_speed (-4.0f);
1755 break;
1756 case -1:
1757 _session->request_transport_speed (-0.5f);
1758 break;
1760 } else {
1761 /* speed up */
1762 _session->request_transport_speed (current_transport_speed * 1.5f);
1767 void
1768 ARDOUR_UI::transport_forward (int option)
1770 float current_transport_speed;
1772 if (_session) {
1773 current_transport_speed = _session->transport_speed();
1775 if (current_transport_speed <= 0.0f) {
1776 switch (option) {
1777 case 0:
1778 _session->request_transport_speed (1.0f);
1779 break;
1780 case 1:
1781 _session->request_transport_speed (4.0f);
1782 break;
1783 case -1:
1784 _session->request_transport_speed (0.5f);
1785 break;
1787 } else {
1788 /* speed up */
1789 _session->request_transport_speed (current_transport_speed * 1.5f);
1795 void
1796 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1798 if (_session == 0) {
1799 return;
1802 boost::shared_ptr<Route> r;
1804 if ((r = _session->route_by_remote_id (rid)) != 0) {
1806 Track* t;
1808 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1809 t->set_record_enabled (!t->record_enabled(), this);
1812 if (_session == 0) {
1813 return;
1817 void
1818 ARDOUR_UI::map_transport_state ()
1820 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1822 if (!_session) {
1823 auto_loop_button.set_visual_state (0);
1824 play_selection_button.set_visual_state (0);
1825 roll_button.set_visual_state (0);
1826 stop_button.set_visual_state (1);
1827 return;
1830 float sp = _session->transport_speed();
1832 if (sp == 1.0f) {
1833 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1834 shuttle_box.queue_draw ();
1835 } else if (sp == 0.0f) {
1836 shuttle_fract = 0;
1837 shuttle_box.queue_draw ();
1838 update_disk_space ();
1841 if (sp != 0.0) {
1843 /* we're rolling */
1845 if (_session->get_play_range()) {
1847 play_selection_button.set_visual_state (1);
1848 roll_button.set_visual_state (0);
1849 auto_loop_button.set_visual_state (0);
1851 } else if (_session->get_play_loop ()) {
1853 auto_loop_button.set_visual_state (1);
1854 play_selection_button.set_visual_state (0);
1855 roll_button.set_visual_state (0);
1857 } else {
1859 roll_button.set_visual_state (1);
1860 play_selection_button.set_visual_state (0);
1861 auto_loop_button.set_visual_state (0);
1864 if (join_play_range_button.get_active()) {
1865 /* light up both roll and play-selection if they are joined */
1866 roll_button.set_visual_state (1);
1867 play_selection_button.set_visual_state (1);
1870 stop_button.set_visual_state (0);
1872 } else {
1874 stop_button.set_visual_state (1);
1875 roll_button.set_visual_state (0);
1876 play_selection_button.set_visual_state (0);
1877 auto_loop_button.set_visual_state (0);
1881 void
1882 ARDOUR_UI::engine_stopped ()
1884 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1885 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1886 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1889 void
1890 ARDOUR_UI::engine_running ()
1892 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1893 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1894 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1896 Glib::RefPtr<Action> action;
1897 const char* action_name = 0;
1899 switch (engine->frames_per_cycle()) {
1900 case 32:
1901 action_name = X_("JACKLatency32");
1902 break;
1903 case 64:
1904 action_name = X_("JACKLatency64");
1905 break;
1906 case 128:
1907 action_name = X_("JACKLatency128");
1908 break;
1909 case 512:
1910 action_name = X_("JACKLatency512");
1911 break;
1912 case 1024:
1913 action_name = X_("JACKLatency1024");
1914 break;
1915 case 2048:
1916 action_name = X_("JACKLatency2048");
1917 break;
1918 case 4096:
1919 action_name = X_("JACKLatency4096");
1920 break;
1921 case 8192:
1922 action_name = X_("JACKLatency8192");
1923 break;
1924 default:
1925 /* XXX can we do anything useful ? */
1926 break;
1929 if (action_name) {
1931 action = ActionManager::get_action (X_("JACK"), action_name);
1933 if (action) {
1934 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1935 ract->set_active ();
1940 void
1941 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1943 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1944 /* we can't rely on the original string continuing to exist when we are called
1945 again in the GUI thread, so make a copy and note that we need to
1946 free it later.
1948 char *copy = strdup (reason);
1949 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1950 return;
1953 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1954 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1956 update_sample_rate (0);
1958 string msgstr;
1960 /* if the reason is a non-empty string, it means that the backend was shutdown
1961 rather than just Ardour.
1964 if (strlen (reason)) {
1965 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1966 } else {
1967 msgstr = string_compose (_("\
1968 JACK has either been shutdown or it\n\
1969 disconnected %1 because %1\n\
1970 was not fast enough. Try to restart\n\
1971 JACK, reconnect and save the session."), PROGRAM_NAME);
1974 MessageDialog msg (*editor, msgstr);
1975 pop_back_splash ();
1976 msg.run ();
1978 if (free_reason) {
1979 free ((char*) reason);
1983 int32_t
1984 ARDOUR_UI::do_engine_start ()
1986 try {
1987 engine->start();
1990 catch (...) {
1991 engine->stop ();
1992 error << _("Unable to start the session running")
1993 << endmsg;
1994 unload_session ();
1995 return -2;
1998 return 0;
2001 void
2002 ARDOUR_UI::setup_theme ()
2004 theme_manager->setup_theme();
2007 void
2008 ARDOUR_UI::update_clocks ()
2010 if (!editor || !editor->dragging_playhead()) {
2011 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2015 void
2016 ARDOUR_UI::start_clocking ()
2018 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2021 void
2022 ARDOUR_UI::stop_clocking ()
2024 clock_signal_connection.disconnect ();
2027 void
2028 ARDOUR_UI::toggle_clocking ()
2030 #if 0
2031 if (clock_button.get_active()) {
2032 start_clocking ();
2033 } else {
2034 stop_clocking ();
2036 #endif
2039 gint
2040 ARDOUR_UI::_blink (void *arg)
2043 ((ARDOUR_UI *) arg)->blink ();
2044 return TRUE;
2047 void
2048 ARDOUR_UI::blink ()
2050 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2053 void
2054 ARDOUR_UI::start_blinking ()
2056 /* Start the blink signal. Everybody with a blinking widget
2057 uses Blink to drive the widget's state.
2060 if (blink_timeout_tag < 0) {
2061 blink_on = false;
2062 blink_timeout_tag = g_timeout_add (240, _blink, this);
2066 void
2067 ARDOUR_UI::stop_blinking ()
2069 if (blink_timeout_tag >= 0) {
2070 g_source_remove (blink_timeout_tag);
2071 blink_timeout_tag = -1;
2076 /** Ask the user for the name of a new shapshot and then take it.
2079 void
2080 ARDOUR_UI::snapshot_session (bool switch_to_it)
2082 ArdourPrompter prompter (true);
2083 string snapname;
2085 prompter.set_name ("Prompter");
2086 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2087 prompter.set_title (_("Take Snapshot"));
2088 prompter.set_title (_("Take Snapshot"));
2089 prompter.set_prompt (_("Name of new snapshot"));
2091 if (!switch_to_it) {
2092 char timebuf[128];
2093 time_t n;
2094 struct tm local_time;
2096 time (&n);
2097 localtime_r (&n, &local_time);
2098 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2099 prompter.set_initial_text (timebuf);
2102 again:
2103 switch (prompter.run()) {
2104 case RESPONSE_ACCEPT:
2106 prompter.get_result (snapname);
2108 bool do_save = (snapname.length() != 0);
2110 if (do_save) {
2111 if (snapname.find ('/') != string::npos) {
2112 MessageDialog msg (_("To ensure compatibility with various systems\n"
2113 "snapshot names may not contain a '/' character"));
2114 msg.run ();
2115 goto again;
2117 if (snapname.find ('\\') != string::npos) {
2118 MessageDialog msg (_("To ensure compatibility with various systems\n"
2119 "snapshot names may not contain a '\\' character"));
2120 msg.run ();
2121 goto again;
2125 vector<sys::path> p;
2126 get_state_files_in_directory (_session->session_directory().root_path(), p);
2127 vector<string> n = get_file_names_no_extension (p);
2128 if (find (n.begin(), n.end(), snapname) != n.end()) {
2130 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2131 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2132 confirm.get_vbox()->pack_start (m, true, true);
2133 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2134 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2135 confirm.show_all ();
2136 switch (confirm.run()) {
2137 case RESPONSE_CANCEL:
2138 do_save = false;
2142 if (do_save) {
2143 save_state (snapname, switch_to_it);
2145 break;
2148 default:
2149 break;
2153 void
2154 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2156 XMLNode* node = new XMLNode (X_("UI"));
2158 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2159 if (!(*i)->rc_configured()) {
2160 node->add_child_nocopy (*((*i)->get_state ()));
2164 _session->add_extra_xml (*node);
2166 save_state_canfail (name, switch_to_it);
2170 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2172 if (_session) {
2173 int ret;
2175 if (name.length() == 0) {
2176 name = _session->snap_name();
2179 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2180 return ret;
2183 cerr << "SS canfail\n";
2184 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2185 return 0;
2188 void
2189 ARDOUR_UI::primary_clock_value_changed ()
2191 if (_session) {
2192 _session->request_locate (primary_clock.current_time ());
2196 void
2197 ARDOUR_UI::big_clock_value_changed ()
2199 if (_session) {
2200 _session->request_locate (big_clock.current_time ());
2204 void
2205 ARDOUR_UI::secondary_clock_value_changed ()
2207 if (_session) {
2208 _session->request_locate (secondary_clock.current_time ());
2212 void
2213 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2215 if (_session == 0) {
2216 return;
2219 if (_session->step_editing()) {
2220 return;
2223 Session::RecordState const r = _session->record_status ();
2224 bool const h = _session->have_rec_enabled_track ();
2226 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2227 if (onoff) {
2228 rec_button.set_visual_state (2);
2229 } else {
2230 rec_button.set_visual_state (0);
2232 } else if (r == Session::Recording && h) {
2233 rec_button.set_visual_state (1);
2234 } else {
2235 rec_button.set_visual_state (0);
2239 void
2240 ARDOUR_UI::save_template ()
2242 ArdourPrompter prompter (true);
2243 string name;
2245 if (!check_audioengine()) {
2246 return;
2249 prompter.set_name (X_("Prompter"));
2250 prompter.set_title (_("Save Template"));
2251 prompter.set_prompt (_("Name for template:"));
2252 prompter.set_initial_text(_session->name() + _("-template"));
2253 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2255 switch (prompter.run()) {
2256 case RESPONSE_ACCEPT:
2257 prompter.get_result (name);
2259 if (name.length()) {
2260 _session->save_template (name);
2262 break;
2264 default:
2265 break;
2269 void
2270 ARDOUR_UI::edit_metadata ()
2272 SessionMetadataEditor dialog;
2273 dialog.set_session (_session);
2274 editor->ensure_float (dialog);
2275 dialog.run ();
2278 void
2279 ARDOUR_UI::import_metadata ()
2281 SessionMetadataImporter dialog;
2282 dialog.set_session (_session);
2283 editor->ensure_float (dialog);
2284 dialog.run ();
2287 void
2288 ARDOUR_UI::fontconfig_dialog ()
2290 #ifdef GTKOSX
2291 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2292 may not and it can take a while to build it. Warn them.
2295 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2297 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2298 MessageDialog msg (*_startup,
2299 string_compose (_("Welcome to %1.\n\n"
2300 "The program will take a bit longer to start up\n"
2301 "while the system fonts are checked.\n\n"
2302 "This will only be done once, and you will\n"
2303 "not see this message again\n"), PROGRAM_NAME),
2304 true,
2305 Gtk::MESSAGE_INFO,
2306 Gtk::BUTTONS_OK);
2307 pop_back_splash ();
2308 msg.show_all ();
2309 msg.present ();
2310 msg.run ();
2312 #endif
2315 void
2316 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2318 existing_session = false;
2320 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2321 session_path = cmdline_path;
2322 existing_session = true;
2323 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2324 session_path = Glib::path_get_dirname (string (cmdline_path));
2325 existing_session = true;
2326 } else {
2327 /* it doesn't exist, assume the best */
2328 session_path = Glib::path_get_dirname (string (cmdline_path));
2331 session_name = basename_nosuffix (string (cmdline_path));
2335 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2337 /* when this is called, the backend audio system must be running */
2339 /* the main idea here is to deal with the fact that a cmdline argument for the session
2340 can be interpreted in different ways - it could be a directory or a file, and before
2341 we load, we need to know both the session directory and the snapshot (statefile) within it
2342 that we are supposed to use.
2345 if (session_name.length() == 0 || session_path.length() == 0) {
2346 return false;
2349 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2351 std::string predicted_session_file;
2353 predicted_session_file = session_path;
2354 predicted_session_file += '/';
2355 predicted_session_file += session_name;
2356 predicted_session_file += ARDOUR::statefile_suffix;
2358 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2359 existing_session = true;
2362 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2364 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2365 /* existing .ardour file */
2366 existing_session = true;
2369 } else {
2370 existing_session = false;
2373 /* lets just try to load it */
2375 if (create_engine ()) {
2376 backend_audio_error (false, _startup);
2377 return -1;
2380 return load_session (session_path, session_name);
2383 bool
2384 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2386 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2388 MessageDialog msg (str,
2389 false,
2390 Gtk::MESSAGE_WARNING,
2391 Gtk::BUTTONS_YES_NO,
2392 true);
2395 msg.set_name (X_("OpenExistingDialog"));
2396 msg.set_title (_("Open Existing Session"));
2397 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2398 msg.set_position (Gtk::WIN_POS_MOUSE);
2399 pop_back_splash ();
2401 switch (msg.run()) {
2402 case RESPONSE_YES:
2403 return true;
2404 break;
2406 return false;
2410 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2412 BusProfile bus_profile;
2414 if (Profile->get_sae()) {
2416 bus_profile.master_out_channels = 2;
2417 bus_profile.input_ac = AutoConnectPhysical;
2418 bus_profile.output_ac = AutoConnectMaster;
2419 bus_profile.requested_physical_in = 0; // use all available
2420 bus_profile.requested_physical_out = 0; // use all available
2422 } else {
2424 /* get settings from advanced section of NSD */
2426 if (_startup->create_master_bus()) {
2427 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2428 } else {
2429 bus_profile.master_out_channels = 0;
2432 if (_startup->connect_inputs()) {
2433 bus_profile.input_ac = AutoConnectPhysical;
2434 } else {
2435 bus_profile.input_ac = AutoConnectOption (0);
2438 /// @todo some minor tweaks.
2440 bus_profile.output_ac = AutoConnectOption (0);
2442 if (_startup->connect_outputs ()) {
2443 if (_startup->connect_outs_to_master()) {
2444 bus_profile.output_ac = AutoConnectMaster;
2445 } else if (_startup->connect_outs_to_physical()) {
2446 bus_profile.output_ac = AutoConnectPhysical;
2450 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2451 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2454 if (build_session (session_path, session_name, bus_profile)) {
2455 return -1;
2458 return 0;
2461 void
2462 ARDOUR_UI::idle_load (const std::string& path)
2464 if (_session) {
2465 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2466 /* /path/to/foo => /path/to/foo, foo */
2467 load_session (path, basename_nosuffix (path));
2468 } else {
2469 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2470 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2472 } else {
2474 ARDOUR_COMMAND_LINE::session_name = path;
2477 * new_session_dialog doens't exist in A3
2478 * Try to remove all references to it to
2479 * see if it will compile. NOTE: this will
2480 * likely cause a runtime issue is my somewhat
2481 * uneducated guess.
2484 //if (new_session_dialog) {
2487 /* make it break out of Dialog::run() and
2488 start again.
2491 //new_session_dialog->response (1);
2496 void
2497 ARDOUR_UI::end_loading_messages ()
2499 // hide_splash ();
2502 void
2503 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2505 // show_splash ();
2506 // splash->message (msg);
2507 flush_pending ();
2510 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2512 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2514 string session_name;
2515 string session_path;
2516 string template_name;
2517 int ret = -1;
2518 bool likely_new = false;
2520 if (! load_template.empty()) {
2521 should_be_new = true;
2522 template_name = load_template;
2525 while (ret != 0) {
2527 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2529 /* if they named a specific statefile, use it, otherwise they are
2530 just giving a session folder, and we want to use it as is
2531 to find the session.
2534 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2535 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2536 } else {
2537 session_path = ARDOUR_COMMAND_LINE::session_name;
2540 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2542 } else {
2544 bool const apply = run_startup (should_be_new, load_template);
2546 if (!apply) {
2547 if (quit_on_cancel) {
2548 exit (1);
2549 } else {
2550 return ret;
2554 /* if we run the startup dialog again, offer more than just "new session" */
2556 should_be_new = false;
2558 session_name = _startup->session_name (likely_new);
2560 /* this shouldn't happen, but we catch it just in case it does */
2562 if (session_name.empty()) {
2563 continue;
2566 if (_startup->use_session_template()) {
2567 template_name = _startup->session_template_name();
2568 _session_is_new = true;
2571 if (session_name[0] == G_DIR_SEPARATOR ||
2572 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2573 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2575 /* absolute path or cwd-relative path specified for session name: infer session folder
2576 from what was given.
2579 session_path = Glib::path_get_dirname (session_name);
2580 session_name = Glib::path_get_basename (session_name);
2582 } else {
2584 session_path = _startup->session_folder();
2586 if (session_name.find ('/') != string::npos) {
2587 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2588 "session names may not contain a '/' character"));
2589 msg.run ();
2590 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2591 continue;
2594 if (session_name.find ('\\') != string::npos) {
2595 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2596 "session names may not contain a '\\' character"));
2597 msg.run ();
2598 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2599 continue;
2604 if (create_engine ()) {
2605 break;
2608 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2610 if (likely_new) {
2612 std::string existing = Glib::build_filename (session_path, session_name);
2614 if (!ask_about_loading_existing_session (existing)) {
2615 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2616 continue;
2620 _session_is_new = false;
2622 } else {
2624 if (!likely_new) {
2625 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2626 msg.run ();
2627 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2628 continue;
2631 if (session_name.find ('/') != std::string::npos) {
2632 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2633 "session names may not contain a '/' character"));
2634 msg.run ();
2635 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2636 continue;
2639 if (session_name.find ('\\') != std::string::npos) {
2640 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2641 "session names may not contain a '\\' character"));
2642 msg.run ();
2643 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2644 continue;
2647 _session_is_new = true;
2650 if (likely_new && template_name.empty()) {
2652 ret = build_session_from_nsd (session_path, session_name);
2654 } else {
2656 ret = load_session (session_path, session_name, template_name);
2658 if (ret == -2) {
2659 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2660 exit (1);
2663 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2664 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2665 exit (1);
2670 return ret;
2673 void
2674 ARDOUR_UI::close_session()
2676 if (!check_audioengine()) {
2677 return;
2680 if (unload_session (true)) {
2681 return;
2684 ARDOUR_COMMAND_LINE::session_name = "";
2686 if (get_session_parameters (true, false)) {
2687 exit (1);
2690 goto_editor_window ();
2693 /** @return -2 if the load failed because we are not connected to the AudioEngine */
2695 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2697 Session *new_session;
2698 int unload_status;
2699 int retval = -1;
2701 session_loaded = false;
2703 if (!check_audioengine()) {
2704 return -2;
2707 unload_status = unload_session ();
2709 if (unload_status < 0) {
2710 goto out;
2711 } else if (unload_status > 0) {
2712 retval = 0;
2713 goto out;
2716 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2718 try {
2719 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2722 /* this one is special */
2724 catch (AudioEngine::PortRegistrationFailure& err) {
2726 MessageDialog msg (err.what(),
2727 true,
2728 Gtk::MESSAGE_INFO,
2729 Gtk::BUTTONS_CLOSE);
2731 msg.set_title (_("Port Registration Error"));
2732 msg.set_secondary_text (_("Click the Close button to try again."));
2733 msg.set_position (Gtk::WIN_POS_CENTER);
2734 pop_back_splash ();
2735 msg.present ();
2737 int response = msg.run ();
2739 msg.hide ();
2741 switch (response) {
2742 case RESPONSE_CANCEL:
2743 exit (1);
2744 default:
2745 break;
2747 goto out;
2750 catch (...) {
2752 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"),path, snap_name),
2753 true,
2754 Gtk::MESSAGE_INFO,
2755 BUTTONS_OK);
2757 msg.set_title (_("Loading Error"));
2758 msg.set_secondary_text (_("Click the Refresh button to try again."));
2759 msg.add_button (Stock::REFRESH, 1);
2760 msg.set_position (Gtk::WIN_POS_CENTER);
2761 pop_back_splash ();
2762 msg.present ();
2764 int response = msg.run ();
2766 switch (response) {
2767 case 1:
2768 break;
2769 default:
2770 exit (1);
2773 msg.hide ();
2775 goto out;
2779 list<string> const u = new_session->unknown_processors ();
2780 if (!u.empty()) {
2781 MissingPluginDialog d (_session, u);
2782 d.run ();
2786 /* Now the session been created, add the transport controls */
2787 new_session->add_controllable(roll_controllable);
2788 new_session->add_controllable(stop_controllable);
2789 new_session->add_controllable(goto_start_controllable);
2790 new_session->add_controllable(goto_end_controllable);
2791 new_session->add_controllable(auto_loop_controllable);
2792 new_session->add_controllable(play_selection_controllable);
2793 new_session->add_controllable(rec_controllable);
2795 set_session (new_session);
2797 session_loaded = true;
2799 goto_editor_window ();
2801 if (_session) {
2802 _session->set_clean ();
2805 flush_pending ();
2806 retval = 0;
2808 out:
2809 return retval;
2813 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2815 Session *new_session;
2816 int x;
2818 if (!check_audioengine()) {
2819 return -1;
2822 session_loaded = false;
2824 x = unload_session ();
2826 if (x < 0) {
2827 return -1;
2828 } else if (x > 0) {
2829 return 0;
2832 _session_is_new = true;
2834 try {
2835 new_session = new Session (*engine, path, snap_name, &bus_profile);
2838 catch (...) {
2840 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2841 pop_back_splash ();
2842 msg.run ();
2843 return -1;
2846 /* Give the new session the default GUI state, if such things exist */
2848 XMLNode* n;
2849 n = Config->instant_xml (X_("Editor"));
2850 if (n) {
2851 new_session->add_instant_xml (*n, false);
2853 n = Config->instant_xml (X_("Mixer"));
2854 if (n) {
2855 new_session->add_instant_xml (*n, false);
2858 /* Put the playhead at 0 and scroll fully left */
2859 n = new_session->instant_xml (X_("Editor"));
2860 if (n) {
2861 n->add_property (X_("playhead"), X_("0"));
2862 n->add_property (X_("left-frame"), X_("0"));
2865 set_session (new_session);
2867 session_loaded = true;
2869 new_session->save_state(new_session->name());
2871 return 0;
2874 void
2875 ARDOUR_UI::launch_chat ()
2877 #ifdef __APPLE__
2878 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2879 #else
2880 open_uri("http://webchat.freenode.net/?channels=ardour");
2881 #endif
2884 void
2885 ARDOUR_UI::show_about ()
2887 if (about == 0) {
2888 about = new About;
2889 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2892 about->set_transient_for(*editor);
2893 about->show_all ();
2896 void
2897 ARDOUR_UI::launch_manual ()
2899 PBD::open_uri("http://ardour.org/flossmanual");
2902 void
2903 ARDOUR_UI::launch_reference ()
2905 PBD::open_uri("http://ardour.org/refmanual");
2908 void
2909 ARDOUR_UI::hide_about ()
2911 if (about) {
2912 about->get_window()->set_cursor ();
2913 about->hide ();
2917 void
2918 ARDOUR_UI::about_signal_response (int /*response*/)
2920 hide_about();
2923 void
2924 ARDOUR_UI::show_splash ()
2926 if (splash == 0) {
2927 try {
2928 splash = new Splash;
2929 } catch (...) {
2930 return;
2934 splash->show ();
2935 splash->present ();
2936 splash->queue_draw ();
2937 splash->get_window()->process_updates (true);
2938 flush_pending ();
2941 void
2942 ARDOUR_UI::hide_splash ()
2944 if (splash) {
2945 splash->hide();
2949 void
2950 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2951 const string& plural_msg, const string& singular_msg)
2953 size_t removed;
2955 removed = rep.paths.size();
2957 if (removed == 0) {
2958 MessageDialog msgd (*editor,
2959 _("No files were ready for cleanup"),
2960 true,
2961 Gtk::MESSAGE_INFO,
2962 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2963 msgd.set_secondary_text (_("If this seems suprising, \n\
2964 check for any existing snapshots.\n\
2965 These may still include regions that\n\
2966 require some unused files to continue to exist."));
2968 msgd.run ();
2969 return;
2972 ArdourDialog results (_("Clean-up"), true, false);
2974 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2975 CleanupResultsModelColumns() {
2976 add (visible_name);
2977 add (fullpath);
2979 Gtk::TreeModelColumn<std::string> visible_name;
2980 Gtk::TreeModelColumn<std::string> fullpath;
2984 CleanupResultsModelColumns results_columns;
2985 Glib::RefPtr<Gtk::ListStore> results_model;
2986 Gtk::TreeView results_display;
2988 results_model = ListStore::create (results_columns);
2989 results_display.set_model (results_model);
2990 results_display.append_column (list_title, results_columns.visible_name);
2992 results_display.set_name ("CleanupResultsList");
2993 results_display.set_headers_visible (true);
2994 results_display.set_headers_clickable (false);
2995 results_display.set_reorderable (false);
2997 Gtk::ScrolledWindow list_scroller;
2998 Gtk::Label txt;
2999 Gtk::VBox dvbox;
3000 Gtk::HBox dhbox; // the hbox for the image and text
3001 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3002 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3004 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3006 const string dead_directory = _session->session_directory().dead_path().to_string();
3008 /* subst:
3009 %1 - number of files removed
3010 %2 - location of "dead"
3011 %3 - size of files affected
3012 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3015 const char* bprefix;
3016 double space_adjusted = 0;
3018 if (rep.space < 1000) {
3019 bprefix = X_("");
3020 space_adjusted = rep.space;
3021 } else if (rep.space < 1000000) {
3022 bprefix = X_("kilo");
3023 space_adjusted = truncf((float)rep.space / 1000.0);
3024 } else if (rep.space < 1000000 * 1000) {
3025 bprefix = X_("mega");
3026 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3027 } else {
3028 bprefix = X_("giga");
3029 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3032 if (removed > 1) {
3033 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3034 } else {
3035 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3038 dhbox.pack_start (*dimage, true, false, 5);
3039 dhbox.pack_start (txt, true, false, 5);
3041 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3042 TreeModel::Row row = *(results_model->append());
3043 row[results_columns.visible_name] = *i;
3044 row[results_columns.fullpath] = *i;
3047 list_scroller.add (results_display);
3048 list_scroller.set_size_request (-1, 150);
3049 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3051 dvbox.pack_start (dhbox, true, false, 5);
3052 dvbox.pack_start (list_scroller, true, false, 5);
3053 ddhbox.pack_start (dvbox, true, false, 5);
3055 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3056 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3057 results.set_default_response (RESPONSE_CLOSE);
3058 results.set_position (Gtk::WIN_POS_MOUSE);
3060 results_display.show();
3061 list_scroller.show();
3062 txt.show();
3063 dvbox.show();
3064 dhbox.show();
3065 ddhbox.show();
3066 dimage->show();
3068 //results.get_vbox()->show();
3069 results.set_resizable (false);
3071 results.run ();
3075 void
3076 ARDOUR_UI::cleanup ()
3078 if (_session == 0) {
3079 /* shouldn't happen: menu item is insensitive */
3080 return;
3084 MessageDialog checker (_("Are you sure you want to cleanup?"),
3085 true,
3086 Gtk::MESSAGE_QUESTION,
3087 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3089 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3090 ALL undo/redo information will be lost if you cleanup.\n\
3091 Cleanup will move all unused files to a \"dead\" location."));
3093 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3094 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3095 checker.set_default_response (RESPONSE_CANCEL);
3097 checker.set_name (_("CleanupDialog"));
3098 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3099 checker.set_position (Gtk::WIN_POS_MOUSE);
3101 switch (checker.run()) {
3102 case RESPONSE_ACCEPT:
3103 break;
3104 default:
3105 return;
3108 ARDOUR::CleanupReport rep;
3110 editor->prepare_for_cleanup ();
3112 /* do not allow flush until a session is reloaded */
3114 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3115 if (act) {
3116 act->set_sensitive (false);
3119 if (_session->cleanup_sources (rep)) {
3120 editor->finish_cleanup ();
3121 return;
3124 editor->finish_cleanup ();
3126 checker.hide();
3127 display_cleanup_results (rep,
3128 _("cleaned files"),
3129 _("\
3130 The following %1 files were not in use and \n\
3131 have been moved to:\n\n\
3132 %2\n\n\
3133 After a restart of Ardour,\n\n\
3134 Session -> Cleanup -> Flush Wastebasket\n\n\
3135 will release an additional\n\
3136 %3 %4bytes of disk space.\n"),
3137 _("\
3138 The following file was not in use and \n \
3139 has been moved to:\n \
3140 %2\n\n\
3141 After a restart of Ardour,\n\n\
3142 Session -> Cleanup -> Flush Wastebasket\n\n\
3143 will release an additional\n\
3144 %3 %4bytes of disk space.\n"
3149 void
3150 ARDOUR_UI::flush_trash ()
3152 if (_session == 0) {
3153 /* shouldn't happen: menu item is insensitive */
3154 return;
3157 ARDOUR::CleanupReport rep;
3159 if (_session->cleanup_trash_sources (rep)) {
3160 return;
3163 display_cleanup_results (rep,
3164 _("deleted file"),
3165 _("The following %1 files were deleted from\n\
3166 %2,\n\
3167 releasing %3 %4bytes of disk space"),
3168 _("The following file was deleted from\n\
3169 %2,\n\
3170 releasing %3 %4bytes of disk space"));
3173 void
3174 ARDOUR_UI::add_route (Gtk::Window* float_window)
3176 int count;
3178 if (!_session) {
3179 return;
3182 if (add_route_dialog == 0) {
3183 add_route_dialog = new AddRouteDialog (_session);
3184 if (float_window) {
3185 add_route_dialog->set_transient_for (*float_window);
3189 if (add_route_dialog->is_visible()) {
3190 /* we're already doing this */
3191 return;
3194 ResponseType r = (ResponseType) add_route_dialog->run ();
3196 add_route_dialog->hide();
3198 switch (r) {
3199 case RESPONSE_ACCEPT:
3200 break;
3201 default:
3202 return;
3203 break;
3206 if ((count = add_route_dialog->count()) <= 0) {
3207 return;
3210 string template_path = add_route_dialog->track_template();
3212 if (!template_path.empty()) {
3213 _session->new_route_from_template (count, template_path);
3214 return;
3217 uint32_t input_chan = add_route_dialog->channels ();
3218 uint32_t output_chan;
3219 string name_template = add_route_dialog->name_template ();
3220 bool track = add_route_dialog->track ();
3221 RouteGroup* route_group = add_route_dialog->route_group ();
3223 AutoConnectOption oac = Config->get_output_auto_connect();
3225 if (oac & AutoConnectMaster) {
3226 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3227 } else {
3228 output_chan = input_chan;
3231 /* XXX do something with name template */
3233 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3234 if (track) {
3235 session_add_midi_track (route_group, count, name_template);
3236 } else {
3237 MessageDialog msg (*editor,
3238 _("Sorry, MIDI Busses are not supported at this time."));
3239 msg.run ();
3240 //session_add_midi_bus();
3242 } else {
3243 if (track) {
3244 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3245 } else {
3246 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3251 XMLNode*
3252 ARDOUR_UI::mixer_settings () const
3254 XMLNode* node = 0;
3256 if (_session) {
3257 node = _session->instant_xml(X_("Mixer"));
3258 } else {
3259 node = Config->instant_xml(X_("Mixer"));
3262 if (!node) {
3263 node = new XMLNode (X_("Mixer"));
3266 return node;
3269 XMLNode*
3270 ARDOUR_UI::editor_settings () const
3272 XMLNode* node = 0;
3274 if (_session) {
3275 node = _session->instant_xml(X_("Editor"));
3276 } else {
3277 node = Config->instant_xml(X_("Editor"));
3280 if (!node) {
3281 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3282 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3286 if (!node) {
3287 node = new XMLNode (X_("Editor"));
3290 return node;
3293 XMLNode*
3294 ARDOUR_UI::keyboard_settings () const
3296 XMLNode* node = 0;
3298 node = Config->extra_xml(X_("Keyboard"));
3300 if (!node) {
3301 node = new XMLNode (X_("Keyboard"));
3303 return node;
3306 void
3307 ARDOUR_UI::create_xrun_marker (framepos_t where)
3309 editor->mouse_add_new_marker (where, false, true);
3312 void
3313 ARDOUR_UI::halt_on_xrun_message ()
3315 MessageDialog msg (*editor,
3316 _("Recording was stopped because your system could not keep up."));
3317 msg.run ();
3320 void
3321 ARDOUR_UI::xrun_handler (framepos_t where)
3323 if (!_session) {
3324 return;
3327 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3329 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3330 create_xrun_marker(where);
3333 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3334 halt_on_xrun_message ();
3338 void
3339 ARDOUR_UI::disk_overrun_handler ()
3341 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3343 if (!have_disk_speed_dialog_displayed) {
3344 have_disk_speed_dialog_displayed = true;
3345 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3346 The disk system on your computer\n\
3347 was not able to keep up with %1.\n\
3349 Specifically, it failed to write data to disk\n\
3350 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3351 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3352 msg->show ();
3356 void
3357 ARDOUR_UI::disk_underrun_handler ()
3359 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3361 if (!have_disk_speed_dialog_displayed) {
3362 have_disk_speed_dialog_displayed = true;
3363 MessageDialog* msg = new MessageDialog (*editor,
3364 string_compose (_("The disk system on your computer\n\
3365 was not able to keep up with %1.\n\
3367 Specifically, it failed to read data from disk\n\
3368 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3369 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3370 msg->show ();
3374 void
3375 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3377 have_disk_speed_dialog_displayed = false;
3378 delete msg;
3381 void
3382 ARDOUR_UI::session_dialog (std::string msg)
3384 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3386 MessageDialog* d;
3388 if (editor) {
3389 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3390 } else {
3391 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3394 d->show_all ();
3395 d->run ();
3396 delete d;
3400 ARDOUR_UI::pending_state_dialog ()
3402 HBox* hbox = new HBox();
3403 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3404 ArdourDialog dialog (_("Crash Recovery"), true);
3405 Label message (_("\
3406 This session appears to have been in\n\
3407 middle of recording when ardour or\n\
3408 the computer was shutdown.\n\
3410 Ardour can recover any captured audio for\n\
3411 you, or it can ignore it. Please decide\n\
3412 what you would like to do.\n"));
3413 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3414 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3415 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3416 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3417 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3418 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3419 dialog.set_default_response (RESPONSE_ACCEPT);
3420 dialog.set_position (WIN_POS_CENTER);
3421 message.show();
3422 image->show();
3423 hbox->show();
3425 switch (dialog.run ()) {
3426 case RESPONSE_ACCEPT:
3427 return 1;
3428 default:
3429 return 0;
3434 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3436 HBox* hbox = new HBox();
3437 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3438 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3439 Label message (string_compose (_("\
3440 This session was created with a sample rate of %1 Hz\n\
3442 The audioengine is currently running at %2 Hz\n"), desired, actual));
3444 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3445 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3446 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3447 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3448 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3449 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3450 dialog.set_default_response (RESPONSE_ACCEPT);
3451 dialog.set_position (WIN_POS_CENTER);
3452 message.show();
3453 image->show();
3454 hbox->show();
3456 switch (dialog.run ()) {
3457 case RESPONSE_ACCEPT:
3458 return 0;
3459 default:
3460 return 1;
3465 void
3466 ARDOUR_UI::disconnect_from_jack ()
3468 if (engine) {
3469 if( engine->disconnect_from_jack ()) {
3470 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3471 msg.run ();
3474 update_sample_rate (0);
3478 void
3479 ARDOUR_UI::reconnect_to_jack ()
3481 if (engine) {
3482 if (engine->reconnect_to_jack ()) {
3483 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3484 msg.run ();
3487 update_sample_rate (0);
3491 void
3492 ARDOUR_UI::use_config ()
3494 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3495 if (node) {
3496 set_transport_controllable_state (*node);
3500 void
3501 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3503 if (Config->get_primary_clock_delta_edit_cursor()) {
3504 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3505 } else {
3506 primary_clock.set (pos, 0, true);
3509 if (Config->get_secondary_clock_delta_edit_cursor()) {
3510 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3511 } else {
3512 secondary_clock.set (pos);
3515 if (big_clock_window->get()) {
3516 big_clock.set (pos);
3521 void
3522 ARDOUR_UI::step_edit_status_change (bool yn)
3524 // XXX should really store pre-step edit status of things
3525 // we make insensitive
3527 if (yn) {
3528 rec_button.set_visual_state (3);
3529 rec_button.set_sensitive (false);
3530 } else {
3531 rec_button.set_visual_state (0);
3532 rec_button.set_sensitive (true);
3536 void
3537 ARDOUR_UI::record_state_changed ()
3539 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3541 if (!_session || !big_clock_window->get()) {
3542 /* why bother - the clock isn't visible */
3543 return;
3546 Session::RecordState const r = _session->record_status ();
3547 bool const h = _session->have_rec_enabled_track ();
3549 if (r == Session::Recording && h) {
3550 big_clock.set_widget_name ("BigClockRecording");
3551 } else {
3552 big_clock.set_widget_name ("BigClockNonRecording");
3556 bool
3557 ARDOUR_UI::first_idle ()
3559 if (_session) {
3560 _session->allow_auto_play (true);
3563 if (editor) {
3564 editor->first_idle();
3567 Keyboard::set_can_save_keybindings (true);
3568 return false;
3571 void
3572 ARDOUR_UI::store_clock_modes ()
3574 XMLNode* node = new XMLNode(X_("ClockModes"));
3576 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3577 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3580 _session->add_extra_xml (*node);
3581 _session->set_dirty ();
3586 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3587 : Controllable (name), ui (u), type(tp)
3592 void
3593 ARDOUR_UI::TransportControllable::set_value (double val)
3595 if (type == ShuttleControl) {
3596 double fract;
3598 if (val == 0.5) {
3599 fract = 0.0;
3600 } else {
3601 if (val < 0.5) {
3602 fract = -((0.5 - val)/0.5);
3603 } else {
3604 fract = ((val - 0.5)/0.5);
3608 ui.set_shuttle_fract (fract);
3609 return;
3612 if (val < 0.5) {
3613 /* do nothing: these are radio-style actions */
3614 return;
3617 const char *action = 0;
3619 switch (type) {
3620 case Roll:
3621 action = X_("Roll");
3622 break;
3623 case Stop:
3624 action = X_("Stop");
3625 break;
3626 case GotoStart:
3627 action = X_("Goto Start");
3628 break;
3629 case GotoEnd:
3630 action = X_("Goto End");
3631 break;
3632 case AutoLoop:
3633 action = X_("Loop");
3634 break;
3635 case PlaySelection:
3636 action = X_("Play Selection");
3637 break;
3638 case RecordEnable:
3639 action = X_("Record");
3640 break;
3641 default:
3642 break;
3645 if (action == 0) {
3646 return;
3649 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3651 if (act) {
3652 act->activate ();
3656 double
3657 ARDOUR_UI::TransportControllable::get_value (void) const
3659 float val = 0.0;
3661 switch (type) {
3662 case Roll:
3663 break;
3664 case Stop:
3665 break;
3666 case GotoStart:
3667 break;
3668 case GotoEnd:
3669 break;
3670 case AutoLoop:
3671 break;
3672 case PlaySelection:
3673 break;
3674 case RecordEnable:
3675 break;
3676 case ShuttleControl:
3677 break;
3678 default:
3679 break;
3682 return val;
3685 void
3686 ARDOUR_UI::TransportControllable::set_id (const string& str)
3688 _id = str;
3691 void
3692 ARDOUR_UI::setup_profile ()
3694 if (gdk_screen_width() < 1200) {
3695 Profile->set_small_screen ();
3699 if (getenv ("ARDOUR_SAE")) {
3700 Profile->set_sae ();
3701 Profile->set_single_package ();
3705 void
3706 ARDOUR_UI::toggle_translations ()
3708 using namespace Glib;
3710 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3711 if (act) {
3712 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3713 if (ract) {
3715 string i18n_killer = ARDOUR::translation_kill_path();
3717 bool already_enabled = !ARDOUR::translations_are_disabled ();
3719 if (ract->get_active ()) {
3720 /* we don't care about errors */
3721 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3722 close (fd);
3723 } else {
3724 /* we don't care about errors */
3725 unlink (i18n_killer.c_str());
3728 if (already_enabled != ract->get_active()) {
3729 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3730 false,
3731 Gtk::MESSAGE_WARNING,
3732 Gtk::BUTTONS_OK);
3733 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3734 win.set_position (Gtk::WIN_POS_CENTER);
3735 win.present ();
3736 win.run ();
3742 /** Add a window proxy to our list, so that its state will be saved.
3743 * This call also causes the window to be created and opened if its
3744 * state was saved as `visible'.
3746 void
3747 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3749 _window_proxies.push_back (p);
3750 p->maybe_show ();
3753 /** Remove a window proxy from our list. Must be called if a WindowProxy
3754 * is deleted, to prevent hanging pointers.
3756 void
3757 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3759 _window_proxies.remove (p);
3763 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3765 MissingFileDialog dialog (s, str, type);
3767 dialog.show ();
3768 dialog.present ();
3770 int result = dialog.run ();
3771 dialog.hide ();
3773 switch (result) {
3774 case RESPONSE_OK:
3775 break;
3776 default:
3777 return 1; // quit entire session load
3780 result = dialog.get_action ();
3782 return result;
3786 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3788 AmbiguousFileDialog dialog (file, hits);
3790 dialog.show ();
3791 dialog.present ();
3793 dialog.run ();
3794 return dialog.get_which ();