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.
21 #include "gtk2ardour-config.h"
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/bindings.h"
53 #include "gtkmm2ext/gtk_ui.h"
54 #include "gtkmm2ext/utils.h"
55 #include "gtkmm2ext/click_box.h"
56 #include "gtkmm2ext/fastmeter.h"
57 #include "gtkmm2ext/popup.h"
58 #include "gtkmm2ext/window_title.h"
60 #include "midi++/manager.h"
62 #include "ardour/ardour.h"
63 #include "ardour/callback.h"
64 #include "ardour/profile.h"
65 #include "ardour/session_directory.h"
66 #include "ardour/session_route.h"
67 #include "ardour/session_state_utils.h"
68 #include "ardour/session_utils.h"
69 #include "ardour/port.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/playlist.h"
72 #include "ardour/utils.h"
73 #include "ardour/audio_diskstream.h"
74 #include "ardour/audiofilesource.h"
75 #include "ardour/recent_sessions.h"
76 #include "ardour/port.h"
77 #include "ardour/audio_track.h"
78 #include "ardour/midi_track.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/filename_extensions.h"
82 typedef uint64_t microseconds_t;
86 #include "add_route_dialog.h"
87 #include "ambiguous_file_dialog.h"
88 #include "ardour_ui.h"
89 #include "audio_clock.h"
90 #include "bundle_manager.h"
91 #include "engine_dialog.h"
92 #include "gain_meter.h"
93 #include "global_port_matrix.h"
94 #include "gui_thread.h"
96 #include "location_ui.h"
97 #include "missing_file_dialog.h"
98 #include "missing_plugin_dialog.h"
101 #include "processor_box.h"
102 #include "prompter.h"
103 #include "public_editor.h"
104 #include "route_time_axis.h"
105 #include "session_metadata_dialog.h"
106 #include "shuttle_control.h"
107 #include "speaker_dialog.h"
110 #include "theme_manager.h"
111 #include "time_axis_view_item.h"
113 #include "window_proxy.h"
117 using namespace ARDOUR;
119 using namespace Gtkmm2ext;
122 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
123 UIConfiguration *ARDOUR_UI::ui_config = 0;
125 sigc::signal<void,bool> ARDOUR_UI::Blink;
126 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
127 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
128 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
130 bool could_be_a_valid_path (const string& path);
132 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
134 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
136 , primary_clock (new AudioClock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true))
137 , secondary_clock (new AudioClock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true))
138 , preroll_clock (new AudioClock (X_("preroll"), false, X_("PreRollClock"), true, false, true))
139 , postroll_clock (new AudioClock (X_("postroll"), false, X_("PostRollClock"), true, false, true))
143 , preroll_button (_("pre\nroll"))
144 , postroll_button (_("post\nroll"))
148 , big_clock (new AudioClock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false))
152 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
153 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
154 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
155 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
156 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
157 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
158 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
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 , punch_in_button (_("Punch In"))
169 , punch_out_button (_("Punch Out"))
170 , auto_return_button (_("Auto Return"))
171 , auto_play_button (_("Auto Play"))
172 , auto_input_button (_("Auto Input"))
173 , click_button (_("Click"))
174 , time_master_button (_("time\nmaster"))
176 , auditioning_alert_button (_("AUDITION"))
177 , solo_alert_button (_("SOLO"))
179 , error_log_button (_("Errors"))
182 using namespace Gtk::Menu_Helpers;
188 // _auto_display_errors = false;
190 * This was commented out as it wasn't defined
191 * in A3 IIRC. If this is not needed it should
192 * be completely removed.
200 if (theArdourUI == 0) {
204 ui_config = new UIConfiguration();
205 theme_manager = new ThemeManager();
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;
223 rc_option_editor = 0;
224 session_option_editor = 0;
226 open_session_selector = 0;
227 have_configure_timeout = false;
228 have_disk_speed_dialog_displayed = false;
229 session_loaded = false;
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);
242 join_play_range_button.unset_flags (Gtk::CAN_FOCUS);
243 last_configure_time= 0;
246 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
247 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
249 /* handle dialog requests */
251 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
253 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
255 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
257 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
259 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
261 /* handle requests to quit (coming from JACK session) */
263 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
265 /* handle requests to deal with missing files */
267 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
269 /* and ambiguous files */
271 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
273 /* lets get this party started */
276 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
277 throw failed_constructor ();
280 setup_gtk_ardour_enums ();
283 GainMeter::setup_slider_pix ();
284 RouteTimeAxisView::setup_slider_pix ();
285 SendProcessorEntry::setup_slider_pix ();
286 SessionEvent::create_per_thread_pool ("GUI", 512);
288 } catch (failed_constructor& err) {
289 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
294 /* we like keyboards */
296 keyboard = new ArdourKeyboard(*this);
299 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
301 keyboard->set_state (*node, Stateful::loading_state_version);
304 /* we don't like certain modifiers */
305 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
309 TimeAxisViewItem::set_constant_heights ();
311 /* The following must happen after ARDOUR::init() so that Config is set up */
313 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
314 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
315 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
317 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
318 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
319 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
320 Config->extra_xml (X_("UI")),
321 string_compose ("toggle-%1-connection-manager", (*i).to_string())
327 SpeakerDialog* s = new SpeakerDialog ();
328 s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
329 speaker_config_window->set (s);
331 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
332 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
335 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
337 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
340 _startup = new ArdourStartup ();
342 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
344 if (audio_setup && _startup->engine_control()) {
345 _startup->engine_control()->set_state (*audio_setup);
348 _startup->set_new_only (should_be_new);
349 if (!load_template.empty()) {
350 _startup->set_load_template( load_template );
352 _startup->present ();
358 switch (_startup->response()) {
367 ARDOUR_UI::create_engine ()
369 // this gets called every time by new_session()
375 loading_message (_("Starting audio engine"));
378 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
385 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
386 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
387 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
389 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
391 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
399 ARDOUR_UI::post_engine ()
401 /* Things to be done once we create the AudioEngine
404 ARDOUR::init_post_engine ();
406 ActionManager::init ();
409 if (setup_windows ()) {
410 throw failed_constructor ();
413 check_memory_locking();
415 /* this is the first point at which all the keybindings are available */
417 if (ARDOUR_COMMAND_LINE::show_key_actions) {
418 vector<string> names;
419 vector<string> paths;
420 vector<string> tooltips;
422 vector<AccelKey> bindings;
424 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
426 vector<string>::iterator n;
427 vector<string>::iterator k;
428 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
429 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
435 blink_timeout_tag = -1;
437 /* this being a GUI and all, we want peakfiles */
439 AudioFileSource::set_build_peakfiles (true);
440 AudioFileSource::set_build_missing_peakfiles (true);
442 /* set default clock modes */
444 if (Profile->get_sae()) {
445 primary_clock->set_mode (AudioClock::BBT);
446 secondary_clock->set_mode (AudioClock::MinSec);
448 primary_clock->set_mode (AudioClock::Timecode);
449 secondary_clock->set_mode (AudioClock::BBT);
452 /* start the time-of-day-clock */
455 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
456 update_wall_clock ();
457 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
460 update_disk_space ();
462 update_sample_rate (engine->frame_rate());
464 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
465 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
466 Config->map_parameters (pc);
468 /* now start and maybe save state */
470 if (do_engine_start () == 0) {
471 if (_session && _session_is_new) {
472 /* we need to retain initial visual
473 settings for a new session
475 _session->save_state ("");
480 ARDOUR_UI::~ARDOUR_UI ()
485 delete add_route_dialog;
489 ARDOUR_UI::pop_back_splash ()
491 if (Splash::instance()) {
492 // Splash::instance()->pop_back();
493 Splash::instance()->hide ();
498 ARDOUR_UI::configure_timeout ()
500 if (last_configure_time == 0) {
501 /* no configure events yet */
505 /* force a gap of 0.5 seconds since the last configure event
508 if (get_microseconds() - last_configure_time < 500000) {
511 have_configure_timeout = false;
512 cerr << "config event-driven save\n";
513 save_ardour_state ();
519 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
521 if (have_configure_timeout) {
522 last_configure_time = get_microseconds();
524 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
525 have_configure_timeout = true;
532 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
534 const XMLProperty* prop;
536 if ((prop = node.property ("roll")) != 0) {
537 roll_controllable->set_id (prop->value());
539 if ((prop = node.property ("stop")) != 0) {
540 stop_controllable->set_id (prop->value());
542 if ((prop = node.property ("goto-start")) != 0) {
543 goto_start_controllable->set_id (prop->value());
545 if ((prop = node.property ("goto-end")) != 0) {
546 goto_end_controllable->set_id (prop->value());
548 if ((prop = node.property ("auto-loop")) != 0) {
549 auto_loop_controllable->set_id (prop->value());
551 if ((prop = node.property ("play-selection")) != 0) {
552 play_selection_controllable->set_id (prop->value());
554 if ((prop = node.property ("rec")) != 0) {
555 rec_controllable->set_id (prop->value());
557 if ((prop = node.property ("shuttle")) != 0) {
558 shuttle_box->controllable()->set_id (prop->value());
564 ARDOUR_UI::get_transport_controllable_state ()
566 XMLNode* node = new XMLNode(X_("TransportControllables"));
569 roll_controllable->id().print (buf, sizeof (buf));
570 node->add_property (X_("roll"), buf);
571 stop_controllable->id().print (buf, sizeof (buf));
572 node->add_property (X_("stop"), buf);
573 goto_start_controllable->id().print (buf, sizeof (buf));
574 node->add_property (X_("goto_start"), buf);
575 goto_end_controllable->id().print (buf, sizeof (buf));
576 node->add_property (X_("goto_end"), buf);
577 auto_loop_controllable->id().print (buf, sizeof (buf));
578 node->add_property (X_("auto_loop"), buf);
579 play_selection_controllable->id().print (buf, sizeof (buf));
580 node->add_property (X_("play_selection"), buf);
581 rec_controllable->id().print (buf, sizeof (buf));
582 node->add_property (X_("rec"), buf);
583 shuttle_box->controllable()->id().print (buf, sizeof (buf));
584 node->add_property (X_("shuttle"), buf);
591 ARDOUR_UI::autosave_session ()
593 if (g_main_depth() > 1) {
594 /* inside a recursive main loop,
595 give up because we may not be able to
601 if (!Config->get_periodic_safety_backups()) {
606 _session->maybe_write_autosave();
613 ARDOUR_UI::update_autosave ()
615 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
617 if (_session && _session->dirty()) {
618 if (_autosave_connection.connected()) {
619 _autosave_connection.disconnect();
622 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
623 Config->get_periodic_safety_backup_interval() * 1000);
626 if (_autosave_connection.connected()) {
627 _autosave_connection.disconnect();
633 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
637 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
639 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
642 MessageDialog win (title,
648 win.set_secondary_text(_("There are several possible reasons:\n\
650 1) You requested audio parameters that are not supported..\n\
651 2) JACK is running as another user.\n\
653 Please consider the possibilities, and perhaps try different parameters."));
655 win.set_secondary_text(_("There are several possible reasons:\n\
657 1) JACK is not running.\n\
658 2) JACK is running as another user, perhaps root.\n\
659 3) There is already another client called \"ardour\".\n\
661 Please consider the possibilities, and perhaps (re)start JACK."));
665 win.set_transient_for (*toplevel);
669 win.add_button (Stock::OK, RESPONSE_CLOSE);
671 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
674 win.set_default_response (RESPONSE_CLOSE);
677 win.set_position (Gtk::WIN_POS_CENTER);
680 /* we just don't care about the result, but we want to block */
686 ARDOUR_UI::startup ()
688 Application* app = Application::instance ();
690 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
691 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
694 call_the_mothership (VERSIONSTRING);
699 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
705 goto_editor_window ();
707 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
708 to be opened on top of the editor window that goto_editor_window() just opened.
710 add_window_proxy (location_ui);
711 add_window_proxy (big_clock_window);
712 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
713 add_window_proxy (_global_port_matrix[*i]);
716 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
720 ARDOUR_UI::no_memory_warning ()
722 XMLNode node (X_("no-memory-warning"));
723 Config->add_instant_xml (node);
727 ARDOUR_UI::check_memory_locking ()
730 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
734 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
736 if (engine->is_realtime() && memory_warning_node == 0) {
738 struct rlimit limits;
740 long pages, page_size;
742 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
745 ram = (int64_t) pages * (int64_t) page_size;
748 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
752 if (limits.rlim_cur != RLIM_INFINITY) {
754 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
758 _("WARNING: Your system has a limit for maximum amount of locked memory. "
759 "This might cause %1 to run out of memory before your system "
760 "runs out of memory. \n\n"
761 "You can view the memory limit with 'ulimit -l', "
762 "and it is normally controlled by /etc/security/limits.conf"),
763 PROGRAM_NAME).c_str());
765 VBox* vbox = msg.get_vbox();
767 CheckButton cb (_("Do not show this window again"));
769 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
771 hbox.pack_start (cb, true, false);
772 vbox->pack_start (hbox);
779 editor->ensure_float (msg);
789 ARDOUR_UI::queue_finish ()
791 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
795 ARDOUR_UI::idle_finish ()
798 return false; /* do not call again */
807 if (_session->transport_rolling() && (++tries < 8)) {
808 _session->request_stop (false, true);
812 if (_session->dirty()) {
813 vector<string> actions;
814 actions.push_back (_("Don't quit"));
815 actions.push_back (_("Just quit"));
816 actions.push_back (_("Save and quit"));
817 switch (ask_about_saving_session(actions)) {
822 /* use the default name */
823 if (save_state_canfail ("")) {
824 /* failed - don't quit */
825 MessageDialog msg (*editor,
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."));
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
850 save_ardour_state ();
853 // _session->set_deletion_in_progress ();
854 _session->set_clean ();
855 _session->remove_pending_capture_state ();
860 ArdourDialog::close_all_dialogs ();
866 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
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));
875 assert (actions.size() >= 3);
877 window.add_button (actions[0], RESPONSE_REJECT);
878 window.add_button (actions[1], RESPONSE_APPLY);
879 window.add_button (actions[2], RESPONSE_ACCEPT);
881 window.set_default_response (RESPONSE_ACCEPT);
883 Gtk::Button noquit_button (msg);
884 noquit_button.set_name ("EditorGTKButton");
888 if (_session->snap_name() == _session->name()) {
889 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
890 _session->snap_name());
892 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
893 _session->snap_name());
896 prompt_label.set_text (prompt);
897 prompt_label.set_name (X_("PrompterLabel"));
898 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
900 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
901 dhbox.set_homogeneous (false);
902 dhbox.pack_start (*dimage, false, false, 5);
903 dhbox.pack_start (prompt_label, true, false, 5);
904 window.get_vbox()->pack_start (dhbox);
906 window.set_name (_("Prompter"));
907 window.set_position (Gtk::WIN_POS_MOUSE);
908 window.set_modal (true);
909 window.set_resizable (false);
915 window.set_keep_above (true);
918 ResponseType r = (ResponseType) window.run();
923 case RESPONSE_ACCEPT: // save and get out of here
925 case RESPONSE_APPLY: // get out of here
935 ARDOUR_UI::every_second ()
938 update_buffer_load ();
939 update_disk_space ();
944 ARDOUR_UI::every_point_one_seconds ()
946 shuttle_box->update_speed_display ();
947 RapidScreenUpdate(); /* EMIT_SIGNAL */
952 ARDOUR_UI::every_point_zero_one_seconds ()
954 // august 2007: actual update frequency: 40Hz, not 100Hz
956 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
961 ARDOUR_UI::update_sample_rate (framecnt_t)
965 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
967 if (!engine->connected()) {
969 snprintf (buf, sizeof (buf), _("disconnected"));
973 framecnt_t rate = engine->frame_rate();
975 if (fmod (rate, 1000.0) != 0.0) {
976 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
977 (float) rate/1000.0f,
978 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
980 snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"),
982 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
986 sample_rate_label.set_text (buf);
990 ARDOUR_UI::update_cpu_load ()
993 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
994 cpu_load_label.set_text (buf);
998 ARDOUR_UI::update_buffer_load ()
1004 c = _session->capture_load ();
1005 p = _session->playback_load ();
1007 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
1008 _session->playback_load(), _session->capture_load());
1009 buffer_load_label.set_text (buf);
1011 buffer_load_label.set_text ("");
1016 ARDOUR_UI::count_recenabled_streams (Route& route)
1018 Track* track = dynamic_cast<Track*>(&route);
1019 if (track && track->record_enabled()) {
1020 rec_enabled_streams += track->n_inputs().n_total();
1025 ARDOUR_UI::update_disk_space()
1027 if (_session == 0) {
1031 framecnt_t frames = _session->available_capture_duration();
1033 framecnt_t fr = _session->frame_rate();
1035 if (frames == max_framecnt) {
1036 strcpy (buf, _("Disk: 24hrs+"));
1038 rec_enabled_streams = 0;
1039 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1041 if (rec_enabled_streams) {
1042 frames /= rec_enabled_streams;
1049 hrs = frames / (fr * 3600);
1050 frames -= hrs * fr * 3600;
1051 mins = frames / (fr * 60);
1052 frames -= mins * fr * 60;
1055 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1058 disk_space_label.set_text (buf);
1060 // An attempt to make the disk space label flash red when space has run out.
1062 if (frames < fr * 60 * 5) {
1063 /* disk_space_box.style ("disk_space_label_empty"); */
1065 /* disk_space_box.style ("disk_space_label"); */
1071 ARDOUR_UI::update_wall_clock ()
1078 tm_now = localtime (&now);
1080 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1081 wall_clock_label.set_text (buf);
1087 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1089 session_popup_menu->popup (0, 0);
1094 ARDOUR_UI::redisplay_recent_sessions ()
1096 std::vector<sys::path> session_directories;
1097 RecentSessionsSorter cmp;
1099 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1100 recent_session_model->clear ();
1102 ARDOUR::RecentSessions rs;
1103 ARDOUR::read_recent_sessions (rs);
1106 recent_session_display.set_model (recent_session_model);
1110 // sort them alphabetically
1111 sort (rs.begin(), rs.end(), cmp);
1113 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1114 session_directories.push_back ((*i).second);
1117 for (vector<sys::path>::const_iterator i = session_directories.begin();
1118 i != session_directories.end(); ++i)
1120 std::vector<sys::path> state_file_paths;
1122 // now get available states for this session
1124 get_state_files_in_directory (*i, state_file_paths);
1126 vector<string*>* states;
1127 vector<const gchar*> item;
1128 string fullpath = (*i).to_string();
1130 /* remove any trailing / */
1132 if (fullpath[fullpath.length()-1] == '/') {
1133 fullpath = fullpath.substr (0, fullpath.length()-1);
1136 /* check whether session still exists */
1137 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1138 /* session doesn't exist */
1139 cerr << "skipping non-existent session " << fullpath << endl;
1143 /* now get available states for this session */
1145 if ((states = Session::possible_states (fullpath)) == 0) {
1146 /* no state file? */
1150 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1152 Gtk::TreeModel::Row row = *(recent_session_model->append());
1154 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1155 row[recent_session_columns.fullpath] = fullpath;
1157 if (state_file_names.size() > 1) {
1161 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1162 i2 != state_file_names.end(); ++i2)
1165 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1167 child_row[recent_session_columns.visible_name] = *i2;
1168 child_row[recent_session_columns.fullpath] = fullpath;
1173 recent_session_display.set_model (recent_session_model);
1177 ARDOUR_UI::build_session_selector ()
1179 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1181 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1183 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1184 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1185 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1186 recent_session_model = TreeStore::create (recent_session_columns);
1187 recent_session_display.set_model (recent_session_model);
1188 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1189 recent_session_display.set_headers_visible (false);
1190 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1191 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1193 scroller->add (recent_session_display);
1194 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1196 session_selector_window->set_name ("SessionSelectorWindow");
1197 session_selector_window->set_size_request (200, 400);
1198 session_selector_window->get_vbox()->pack_start (*scroller);
1200 recent_session_display.show();
1202 //session_selector_window->get_vbox()->show();
1206 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1208 session_selector_window->response (RESPONSE_ACCEPT);
1212 ARDOUR_UI::open_recent_session ()
1214 bool can_return = (_session != 0);
1216 if (session_selector_window == 0) {
1217 build_session_selector ();
1220 redisplay_recent_sessions ();
1224 session_selector_window->set_position (WIN_POS_MOUSE);
1226 ResponseType r = (ResponseType) session_selector_window->run ();
1229 case RESPONSE_ACCEPT:
1233 session_selector_window->hide();
1240 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1244 session_selector_window->hide();
1246 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1248 if (i == recent_session_model->children().end()) {
1252 std::string path = (*i)[recent_session_columns.fullpath];
1253 std::string state = (*i)[recent_session_columns.visible_name];
1255 _session_is_new = false;
1257 if (load_session (path, state) == 0) {
1266 ARDOUR_UI::check_audioengine ()
1269 if (!engine->connected()) {
1270 MessageDialog msg (string_compose (
1271 _("%1 is not connected to JACK\n"
1272 "You cannot open or close sessions in this condition"),
1285 ARDOUR_UI::open_session ()
1287 if (!check_audioengine()) {
1292 /* popup selector window */
1294 if (open_session_selector == 0) {
1296 /* ardour sessions are folders */
1298 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1299 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1300 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1301 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1303 FileFilter session_filter;
1304 session_filter.add_pattern ("*.ardour");
1305 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1306 open_session_selector->add_filter (session_filter);
1307 open_session_selector->set_filter (session_filter);
1310 int response = open_session_selector->run();
1311 open_session_selector->hide ();
1314 case RESPONSE_ACCEPT:
1317 open_session_selector->hide();
1321 open_session_selector->hide();
1322 string session_path = open_session_selector->get_filename();
1326 if (session_path.length() > 0) {
1327 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1328 _session_is_new = isnew;
1329 load_session (path, name);
1336 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1338 list<boost::shared_ptr<MidiTrack> > tracks;
1340 if (_session == 0) {
1341 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1348 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1350 if (tracks.size() != how_many) {
1351 if (how_many == 1) {
1352 error << _("could not create a new midi track") << endmsg;
1354 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1358 if ((route = _session->new_midi_route ()) == 0) {
1359 error << _("could not create new midi bus") << endmsg;
1365 MessageDialog msg (*editor,
1366 string_compose (_("There are insufficient JACK ports available\n\
1367 to create a new track or bus.\n\
1368 You should save %1, exit and\n\
1369 restart JACK with more ports."), PROGRAM_NAME));
1376 ARDOUR_UI::session_add_audio_route (
1378 int32_t input_channels,
1379 int32_t output_channels,
1380 ARDOUR::TrackMode mode,
1381 RouteGroup* route_group,
1383 string const & name_template
1386 list<boost::shared_ptr<AudioTrack> > tracks;
1389 if (_session == 0) {
1390 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1396 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1398 if (tracks.size() != how_many) {
1399 if (how_many == 1) {
1400 error << _("could not create a new audio track") << endmsg;
1402 error << string_compose (_("could only create %1 of %2 new audio %3"),
1403 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1409 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1411 if (routes.size() != how_many) {
1412 if (how_many == 1) {
1413 error << _("could not create a new audio track") << endmsg;
1415 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1422 MessageDialog msg (*editor,
1423 string_compose (_("There are insufficient JACK ports available\n\
1424 to create a new track or bus.\n\
1425 You should save %1, exit and\n\
1426 restart JACK with more ports."), PROGRAM_NAME));
1433 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1435 framecnt_t _preroll = 0;
1438 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1439 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1441 if (new_position > _preroll) {
1442 new_position -= _preroll;
1447 _session->request_locate (new_position, with_roll);
1452 ARDOUR_UI::transport_goto_start ()
1455 _session->goto_start();
1457 /* force displayed area in editor to start no matter
1458 what "follow playhead" setting is.
1462 editor->center_screen (_session->current_start_frame ());
1468 ARDOUR_UI::transport_goto_zero ()
1471 _session->request_locate (0);
1473 /* force displayed area in editor to start no matter
1474 what "follow playhead" setting is.
1478 editor->reset_x_origin (0);
1484 ARDOUR_UI::transport_goto_wallclock ()
1486 if (_session && editor) {
1493 localtime_r (&now, &tmnow);
1495 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1496 frames += tmnow.tm_min * (60 * _session->frame_rate());
1497 frames += tmnow.tm_sec * _session->frame_rate();
1499 _session->request_locate (frames, _session->transport_rolling ());
1501 /* force displayed area in editor to start no matter
1502 what "follow playhead" setting is.
1506 editor->center_screen (frames);
1512 ARDOUR_UI::transport_goto_end ()
1515 framepos_t const frame = _session->current_end_frame();
1516 _session->request_locate (frame);
1518 /* force displayed area in editor to start no matter
1519 what "follow playhead" setting is.
1523 editor->center_screen (frame);
1529 ARDOUR_UI::transport_stop ()
1535 if (_session->is_auditioning()) {
1536 _session->cancel_audition ();
1540 _session->request_stop (false, true);
1544 ARDOUR_UI::transport_stop_and_forget_capture ()
1547 _session->request_stop (true, true);
1552 ARDOUR_UI::remove_last_capture()
1555 editor->remove_last_capture();
1560 ARDOUR_UI::transport_record (bool roll)
1564 switch (_session->record_status()) {
1565 case Session::Disabled:
1566 if (_session->ntracks() == 0) {
1567 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1571 _session->maybe_enable_record ();
1576 case Session::Recording:
1578 _session->request_stop();
1580 _session->disable_record (false, true);
1584 case Session::Enabled:
1585 _session->disable_record (false, true);
1588 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1592 ARDOUR_UI::transport_roll ()
1598 if (_session->is_auditioning()) {
1603 if (_session->config.get_external_sync()) {
1604 switch (_session->config.get_sync_source()) {
1608 /* transport controlled by the master */
1614 bool rolling = _session->transport_rolling();
1616 if (_session->get_play_loop()) {
1617 /* XXX it is not possible to just leave seamless loop and keep
1618 playing at present (nov 4th 2009)
1620 if (!Config->get_seamless_loop()) {
1621 _session->request_play_loop (false, true);
1623 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1624 /* stop playing a range if we currently are */
1625 _session->request_play_range (0, true);
1628 if (join_play_range_button.get_active()) {
1629 _session->request_play_range (&editor->get_selection().time, true);
1633 _session->request_transport_speed (1.0f);
1638 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1645 if (_session->is_auditioning()) {
1646 _session->cancel_audition ();
1650 if (_session->config.get_external_sync()) {
1651 switch (_session->config.get_sync_source()) {
1655 /* transport controlled by the master */
1660 bool rolling = _session->transport_rolling();
1661 bool affect_transport = true;
1663 if (rolling && roll_out_of_bounded_mode) {
1664 /* drop out of loop/range playback but leave transport rolling */
1665 if (_session->get_play_loop()) {
1666 if (Config->get_seamless_loop()) {
1667 /* the disk buffers contain copies of the loop - we can't
1668 just keep playing, so stop the transport. the user
1669 can restart as they wish.
1671 affect_transport = true;
1673 /* disk buffers are normal, so we can keep playing */
1674 affect_transport = false;
1676 _session->request_play_loop (false, true);
1677 } else if (_session->get_play_range ()) {
1678 affect_transport = false;
1679 _session->request_play_range (0, true);
1683 if (affect_transport) {
1685 _session->request_stop (with_abort, true);
1687 if (join_play_range_button.get_active()) {
1688 _session->request_play_range (&editor->get_selection().time, true);
1691 _session->request_transport_speed (1.0f);
1697 ARDOUR_UI::toggle_session_auto_loop ()
1703 if (_session->get_play_loop()) {
1705 if (_session->transport_rolling()) {
1707 Location * looploc = _session->locations()->auto_loop_location();
1710 _session->request_locate (looploc->start(), true);
1711 _session->request_play_loop (false);
1715 _session->request_play_loop (false);
1719 Location * looploc = _session->locations()->auto_loop_location();
1722 _session->request_play_loop (true);
1728 ARDOUR_UI::transport_play_selection ()
1734 editor->play_selection ();
1738 ARDOUR_UI::transport_rewind (int option)
1740 float current_transport_speed;
1743 current_transport_speed = _session->transport_speed();
1745 if (current_transport_speed >= 0.0f) {
1748 _session->request_transport_speed (-1.0f);
1751 _session->request_transport_speed (-4.0f);
1754 _session->request_transport_speed (-0.5f);
1759 _session->request_transport_speed (current_transport_speed * 1.5f);
1765 ARDOUR_UI::transport_forward (int option)
1767 float current_transport_speed;
1770 current_transport_speed = _session->transport_speed();
1772 if (current_transport_speed <= 0.0f) {
1775 _session->request_transport_speed (1.0f);
1778 _session->request_transport_speed (4.0f);
1781 _session->request_transport_speed (0.5f);
1786 _session->request_transport_speed (current_transport_speed * 1.5f);
1793 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1795 if (_session == 0) {
1799 boost::shared_ptr<Route> r;
1801 if ((r = _session->route_by_remote_id (rid)) != 0) {
1805 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1806 t->set_record_enabled (!t->record_enabled(), this);
1809 if (_session == 0) {
1815 ARDOUR_UI::map_transport_state ()
1818 auto_loop_button.set_visual_state (0);
1819 play_selection_button.set_visual_state (0);
1820 roll_button.set_visual_state (0);
1821 stop_button.set_visual_state (1);
1825 shuttle_box->map_transport_state ();
1827 float sp = _session->transport_speed();
1833 if (_session->get_play_range()) {
1835 play_selection_button.set_visual_state (1);
1836 roll_button.set_visual_state (0);
1837 auto_loop_button.set_visual_state (0);
1839 } else if (_session->get_play_loop ()) {
1841 auto_loop_button.set_visual_state (1);
1842 play_selection_button.set_visual_state (0);
1843 roll_button.set_visual_state (0);
1847 roll_button.set_visual_state (1);
1848 play_selection_button.set_visual_state (0);
1849 auto_loop_button.set_visual_state (0);
1852 if (join_play_range_button.get_active()) {
1853 /* light up both roll and play-selection if they are joined */
1854 roll_button.set_visual_state (1);
1855 play_selection_button.set_visual_state (1);
1858 stop_button.set_visual_state (0);
1862 stop_button.set_visual_state (1);
1863 roll_button.set_visual_state (0);
1864 play_selection_button.set_visual_state (0);
1865 auto_loop_button.set_visual_state (0);
1866 update_disk_space ();
1871 ARDOUR_UI::engine_stopped ()
1873 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1874 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1875 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1879 ARDOUR_UI::engine_running ()
1881 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1882 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1883 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1885 Glib::RefPtr<Action> action;
1886 const char* action_name = 0;
1888 switch (engine->frames_per_cycle()) {
1890 action_name = X_("JACKLatency32");
1893 action_name = X_("JACKLatency64");
1896 action_name = X_("JACKLatency128");
1899 action_name = X_("JACKLatency512");
1902 action_name = X_("JACKLatency1024");
1905 action_name = X_("JACKLatency2048");
1908 action_name = X_("JACKLatency4096");
1911 action_name = X_("JACKLatency8192");
1914 /* XXX can we do anything useful ? */
1920 action = ActionManager::get_action (X_("JACK"), action_name);
1923 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1924 ract->set_active ();
1930 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1932 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1933 /* we can't rely on the original string continuing to exist when we are called
1934 again in the GUI thread, so make a copy and note that we need to
1937 char *copy = strdup (reason);
1938 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1942 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1943 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1945 update_sample_rate (0);
1949 /* if the reason is a non-empty string, it means that the backend was shutdown
1950 rather than just Ardour.
1953 if (strlen (reason)) {
1954 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1956 msgstr = string_compose (_("\
1957 JACK has either been shutdown or it\n\
1958 disconnected %1 because %1\n\
1959 was not fast enough. Try to restart\n\
1960 JACK, reconnect and save the session."), PROGRAM_NAME);
1963 MessageDialog msg (*editor, msgstr);
1968 free ((char*) reason);
1973 ARDOUR_UI::do_engine_start ()
1981 error << _("Unable to start the session running")
1991 ARDOUR_UI::setup_theme ()
1993 theme_manager->setup_theme();
1997 ARDOUR_UI::update_clocks ()
1999 if (!editor || !editor->dragging_playhead()) {
2000 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2005 ARDOUR_UI::start_clocking ()
2007 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2011 ARDOUR_UI::stop_clocking ()
2013 clock_signal_connection.disconnect ();
2017 ARDOUR_UI::toggle_clocking ()
2020 if (clock_button.get_active()) {
2029 ARDOUR_UI::_blink (void *arg)
2032 ((ARDOUR_UI *) arg)->blink ();
2039 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2043 ARDOUR_UI::start_blinking ()
2045 /* Start the blink signal. Everybody with a blinking widget
2046 uses Blink to drive the widget's state.
2049 if (blink_timeout_tag < 0) {
2051 blink_timeout_tag = g_timeout_add (240, _blink, this);
2056 ARDOUR_UI::stop_blinking ()
2058 if (blink_timeout_tag >= 0) {
2059 g_source_remove (blink_timeout_tag);
2060 blink_timeout_tag = -1;
2065 /** Ask the user for the name of a new shapshot and then take it.
2069 ARDOUR_UI::snapshot_session (bool switch_to_it)
2071 ArdourPrompter prompter (true);
2074 prompter.set_name ("Prompter");
2075 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2076 prompter.set_title (_("Take Snapshot"));
2077 prompter.set_title (_("Take Snapshot"));
2078 prompter.set_prompt (_("Name of new snapshot"));
2080 if (!switch_to_it) {
2083 struct tm local_time;
2086 localtime_r (&n, &local_time);
2087 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2088 prompter.set_initial_text (timebuf);
2092 switch (prompter.run()) {
2093 case RESPONSE_ACCEPT:
2095 prompter.get_result (snapname);
2097 bool do_save = (snapname.length() != 0);
2100 if (snapname.find ('/') != string::npos) {
2101 MessageDialog msg (_("To ensure compatibility with various systems\n"
2102 "snapshot names may not contain a '/' character"));
2106 if (snapname.find ('\\') != string::npos) {
2107 MessageDialog msg (_("To ensure compatibility with various systems\n"
2108 "snapshot names may not contain a '\\' character"));
2114 vector<sys::path> p;
2115 get_state_files_in_directory (_session->session_directory().root_path(), p);
2116 vector<string> n = get_file_names_no_extension (p);
2117 if (find (n.begin(), n.end(), snapname) != n.end()) {
2119 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2120 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2121 confirm.get_vbox()->pack_start (m, true, true);
2122 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2123 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2124 confirm.show_all ();
2125 switch (confirm.run()) {
2126 case RESPONSE_CANCEL:
2132 save_state (snapname, switch_to_it);
2143 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2145 XMLNode* node = new XMLNode (X_("UI"));
2147 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2148 if (!(*i)->rc_configured()) {
2149 node->add_child_nocopy (*((*i)->get_state ()));
2153 _session->add_extra_xml (*node);
2155 save_state_canfail (name, switch_to_it);
2159 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2164 if (name.length() == 0) {
2165 name = _session->snap_name();
2168 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2173 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2178 ARDOUR_UI::primary_clock_value_changed ()
2181 _session->request_locate (primary_clock->current_time ());
2186 ARDOUR_UI::big_clock_value_changed ()
2189 _session->request_locate (big_clock->current_time ());
2194 ARDOUR_UI::secondary_clock_value_changed ()
2197 _session->request_locate (secondary_clock->current_time ());
2202 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2204 if (_session == 0) {
2208 if (_session->step_editing()) {
2212 Session::RecordState const r = _session->record_status ();
2213 bool const h = _session->have_rec_enabled_track ();
2215 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2217 rec_button.set_visual_state (2);
2219 rec_button.set_visual_state (0);
2221 } else if (r == Session::Recording && h) {
2222 rec_button.set_visual_state (1);
2224 rec_button.set_visual_state (0);
2229 ARDOUR_UI::save_template ()
2231 ArdourPrompter prompter (true);
2234 if (!check_audioengine()) {
2238 prompter.set_name (X_("Prompter"));
2239 prompter.set_title (_("Save Template"));
2240 prompter.set_prompt (_("Name for template:"));
2241 prompter.set_initial_text(_session->name() + _("-template"));
2242 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2244 switch (prompter.run()) {
2245 case RESPONSE_ACCEPT:
2246 prompter.get_result (name);
2248 if (name.length()) {
2249 _session->save_template (name);
2259 ARDOUR_UI::edit_metadata ()
2261 SessionMetadataEditor dialog;
2262 dialog.set_session (_session);
2263 editor->ensure_float (dialog);
2268 ARDOUR_UI::import_metadata ()
2270 SessionMetadataImporter dialog;
2271 dialog.set_session (_session);
2272 editor->ensure_float (dialog);
2277 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2279 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2281 MessageDialog msg (str,
2283 Gtk::MESSAGE_WARNING,
2284 Gtk::BUTTONS_YES_NO,
2288 msg.set_name (X_("OpenExistingDialog"));
2289 msg.set_title (_("Open Existing Session"));
2290 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2291 msg.set_position (Gtk::WIN_POS_MOUSE);
2294 switch (msg.run()) {
2303 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2305 BusProfile bus_profile;
2307 if (Profile->get_sae()) {
2309 bus_profile.master_out_channels = 2;
2310 bus_profile.input_ac = AutoConnectPhysical;
2311 bus_profile.output_ac = AutoConnectMaster;
2312 bus_profile.requested_physical_in = 0; // use all available
2313 bus_profile.requested_physical_out = 0; // use all available
2317 /* get settings from advanced section of NSD */
2319 if (_startup->create_master_bus()) {
2320 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2322 bus_profile.master_out_channels = 0;
2325 if (_startup->connect_inputs()) {
2326 bus_profile.input_ac = AutoConnectPhysical;
2328 bus_profile.input_ac = AutoConnectOption (0);
2331 /// @todo some minor tweaks.
2333 bus_profile.output_ac = AutoConnectOption (0);
2335 if (_startup->connect_outputs ()) {
2336 if (_startup->connect_outs_to_master()) {
2337 bus_profile.output_ac = AutoConnectMaster;
2338 } else if (_startup->connect_outs_to_physical()) {
2339 bus_profile.output_ac = AutoConnectPhysical;
2343 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2344 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2347 if (build_session (session_path, session_name, bus_profile)) {
2355 ARDOUR_UI::idle_load (const std::string& path)
2358 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2359 /* /path/to/foo => /path/to/foo, foo */
2360 load_session (path, basename_nosuffix (path));
2362 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2363 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2367 ARDOUR_COMMAND_LINE::session_name = path;
2370 * new_session_dialog doens't exist in A3
2371 * Try to remove all references to it to
2372 * see if it will compile. NOTE: this will
2373 * likely cause a runtime issue is my somewhat
2377 //if (new_session_dialog) {
2380 /* make it break out of Dialog::run() and
2384 //new_session_dialog->response (1);
2390 ARDOUR_UI::end_loading_messages ()
2396 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2399 // splash->message (msg);
2403 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2405 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2407 string session_name;
2408 string session_path;
2409 string template_name;
2411 bool likely_new = false;
2413 if (!load_template.empty()) {
2414 should_be_new = true;
2415 template_name = load_template;
2420 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2422 /* if they named a specific statefile, use it, otherwise they are
2423 just giving a session folder, and we want to use it as is
2424 to find the session.
2427 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2429 if (suffix != string::npos) {
2430 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2431 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2432 session_name = Glib::path_get_basename (session_name);
2434 session_path = ARDOUR_COMMAND_LINE::session_name;
2435 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2440 bool const apply = run_startup (should_be_new, load_template);
2443 if (quit_on_cancel) {
2450 /* if we run the startup dialog again, offer more than just "new session" */
2452 should_be_new = false;
2454 session_name = _startup->session_name (likely_new);
2456 /* this shouldn't happen, but we catch it just in case it does */
2458 if (session_name.empty()) {
2462 if (_startup->use_session_template()) {
2463 template_name = _startup->session_template_name();
2464 _session_is_new = true;
2467 if (session_name[0] == G_DIR_SEPARATOR ||
2468 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2469 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2471 /* absolute path or cwd-relative path specified for session name: infer session folder
2472 from what was given.
2475 session_path = Glib::path_get_dirname (session_name);
2476 session_name = Glib::path_get_basename (session_name);
2480 session_path = _startup->session_folder();
2482 if (session_name.find ('/') != string::npos) {
2483 MessageDialog msg (*_startup,
2484 _("To ensure compatibility with various systems\n"
2485 "session names may not contain a '/' character"));
2487 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2491 if (session_name.find ('\\') != string::npos) {
2492 MessageDialog msg (*_startup,
2493 _("To ensure compatibility with various systems\n"
2494 "session names may not contain a '\\' character"));
2496 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2502 if (create_engine ()) {
2506 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2510 std::string existing = Glib::build_filename (session_path, session_name);
2512 if (!ask_about_loading_existing_session (existing)) {
2513 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2518 _session_is_new = false;
2523 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2525 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2529 if (session_name.find ('/') != std::string::npos) {
2530 MessageDialog msg (*_startup,
2531 _("To ensure compatibility with various systems\n"
2532 "session names may not contain a '/' character"));
2534 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2538 if (session_name.find ('\\') != std::string::npos) {
2539 MessageDialog msg (*_startup,
2540 _("To ensure compatibility with various systems\n"
2541 "session names may not contain a '\\' character"));
2543 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2547 _session_is_new = true;
2550 if (likely_new && template_name.empty()) {
2552 ret = build_session_from_nsd (session_path, session_name);
2556 ret = load_session (session_path, session_name, template_name);
2559 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2563 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2564 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2574 ARDOUR_UI::close_session()
2576 if (!check_audioengine()) {
2580 if (unload_session (true)) {
2584 ARDOUR_COMMAND_LINE::session_name = "";
2586 if (get_session_parameters (true, false)) {
2590 goto_editor_window ();
2593 /** @param snap_name Snapshot name (without .ardour suffix).
2594 * @return -2 if the load failed because we are not connected to the AudioEngine.
2597 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2599 Session *new_session;
2603 session_loaded = false;
2605 if (!check_audioengine()) {
2609 unload_status = unload_session ();
2611 if (unload_status < 0) {
2613 } else if (unload_status > 0) {
2618 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2621 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2624 /* this one is special */
2626 catch (AudioEngine::PortRegistrationFailure& err) {
2628 MessageDialog msg (err.what(),
2631 Gtk::BUTTONS_CLOSE);
2633 msg.set_title (_("Port Registration Error"));
2634 msg.set_secondary_text (_("Click the Close button to try again."));
2635 msg.set_position (Gtk::WIN_POS_CENTER);
2639 int response = msg.run ();
2644 case RESPONSE_CANCEL:
2654 MessageDialog msg (string_compose(
2655 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2661 msg.set_title (_("Loading Error"));
2662 msg.set_secondary_text (_("Click the Refresh button to try again."));
2663 msg.add_button (Stock::REFRESH, 1);
2664 msg.set_position (Gtk::WIN_POS_CENTER);
2668 int response = msg.run ();
2683 list<string> const u = new_session->unknown_processors ();
2685 MissingPluginDialog d (_session, u);
2690 /* Now the session been created, add the transport controls */
2691 new_session->add_controllable(roll_controllable);
2692 new_session->add_controllable(stop_controllable);
2693 new_session->add_controllable(goto_start_controllable);
2694 new_session->add_controllable(goto_end_controllable);
2695 new_session->add_controllable(auto_loop_controllable);
2696 new_session->add_controllable(play_selection_controllable);
2697 new_session->add_controllable(rec_controllable);
2699 set_session (new_session);
2701 session_loaded = true;
2703 goto_editor_window ();
2706 _session->set_clean ();
2717 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2719 Session *new_session;
2722 if (!check_audioengine()) {
2726 session_loaded = false;
2728 x = unload_session ();
2736 _session_is_new = true;
2739 new_session = new Session (*engine, path, snap_name, &bus_profile);
2744 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2750 /* Give the new session the default GUI state, if such things exist */
2753 n = Config->instant_xml (X_("Editor"));
2755 new_session->add_instant_xml (*n, false);
2757 n = Config->instant_xml (X_("Mixer"));
2759 new_session->add_instant_xml (*n, false);
2762 /* Put the playhead at 0 and scroll fully left */
2763 n = new_session->instant_xml (X_("Editor"));
2765 n->add_property (X_("playhead"), X_("0"));
2766 n->add_property (X_("left-frame"), X_("0"));
2769 set_session (new_session);
2771 session_loaded = true;
2773 new_session->save_state(new_session->name());
2779 ARDOUR_UI::launch_chat ()
2782 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2784 open_uri("http://webchat.freenode.net/?channels=ardour");
2789 ARDOUR_UI::show_about ()
2793 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2796 about->set_transient_for(*editor);
2801 ARDOUR_UI::launch_manual ()
2803 PBD::open_uri("http://ardour.org/flossmanual");
2807 ARDOUR_UI::launch_reference ()
2809 PBD::open_uri("http://ardour.org/refmanual");
2813 ARDOUR_UI::hide_about ()
2816 about->get_window()->set_cursor ();
2822 ARDOUR_UI::about_signal_response (int /*response*/)
2828 ARDOUR_UI::show_splash ()
2832 splash = new Splash;
2840 splash->queue_draw ();
2841 splash->get_window()->process_updates (true);
2846 ARDOUR_UI::hide_splash ()
2854 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2855 const string& plural_msg, const string& singular_msg)
2859 removed = rep.paths.size();
2862 MessageDialog msgd (*editor,
2863 _("No files were ready for clean-up"),
2866 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2867 msgd.set_title (_("Clean-up"));
2868 msgd.set_secondary_text (_("If this seems suprising, \n\
2869 check for any existing snapshots.\n\
2870 These may still include regions that\n\
2871 require some unused files to continue to exist."));
2877 ArdourDialog results (_("Clean-up"), true, false);
2879 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2880 CleanupResultsModelColumns() {
2884 Gtk::TreeModelColumn<std::string> visible_name;
2885 Gtk::TreeModelColumn<std::string> fullpath;
2889 CleanupResultsModelColumns results_columns;
2890 Glib::RefPtr<Gtk::ListStore> results_model;
2891 Gtk::TreeView results_display;
2893 results_model = ListStore::create (results_columns);
2894 results_display.set_model (results_model);
2895 results_display.append_column (list_title, results_columns.visible_name);
2897 results_display.set_name ("CleanupResultsList");
2898 results_display.set_headers_visible (true);
2899 results_display.set_headers_clickable (false);
2900 results_display.set_reorderable (false);
2902 Gtk::ScrolledWindow list_scroller;
2905 Gtk::HBox dhbox; // the hbox for the image and text
2906 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2907 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2909 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2911 const string dead_directory = _session->session_directory().dead_path().to_string();
2914 %1 - number of files removed
2915 %2 - location of "dead"
2916 %3 - size of files affected
2917 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2920 const char* bprefix;
2921 double space_adjusted = 0;
2923 if (rep.space < 1000) {
2925 space_adjusted = rep.space;
2926 } else if (rep.space < 1000000) {
2927 bprefix = X_("kilo");
2928 space_adjusted = truncf((float)rep.space / 1000.0);
2929 } else if (rep.space < 1000000 * 1000) {
2930 bprefix = X_("mega");
2931 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
2933 bprefix = X_("giga");
2934 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
2938 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
2940 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
2943 dhbox.pack_start (*dimage, true, false, 5);
2944 dhbox.pack_start (txt, true, false, 5);
2946 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2947 TreeModel::Row row = *(results_model->append());
2948 row[results_columns.visible_name] = *i;
2949 row[results_columns.fullpath] = *i;
2952 list_scroller.add (results_display);
2953 list_scroller.set_size_request (-1, 150);
2954 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2956 dvbox.pack_start (dhbox, true, false, 5);
2957 dvbox.pack_start (list_scroller, true, false, 5);
2958 ddhbox.pack_start (dvbox, true, false, 5);
2960 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2961 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2962 results.set_default_response (RESPONSE_CLOSE);
2963 results.set_position (Gtk::WIN_POS_MOUSE);
2965 results_display.show();
2966 list_scroller.show();
2973 //results.get_vbox()->show();
2974 results.set_resizable (false);
2981 ARDOUR_UI::cleanup ()
2983 if (_session == 0) {
2984 /* shouldn't happen: menu item is insensitive */
2989 MessageDialog checker (_("Are you sure you want to clean-up?"),
2991 Gtk::MESSAGE_QUESTION,
2992 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2994 checker.set_title (_("Clean-up"));
2996 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
2997 ALL undo/redo information will be lost if you clean-up.\n\
2998 Clean-up will move all unused files to a \"dead\" location."));
3000 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3001 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3002 checker.set_default_response (RESPONSE_CANCEL);
3004 checker.set_name (_("CleanupDialog"));
3005 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3006 checker.set_position (Gtk::WIN_POS_MOUSE);
3008 switch (checker.run()) {
3009 case RESPONSE_ACCEPT:
3015 ARDOUR::CleanupReport rep;
3017 editor->prepare_for_cleanup ();
3019 /* do not allow flush until a session is reloaded */
3021 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3023 act->set_sensitive (false);
3026 if (_session->cleanup_sources (rep)) {
3027 editor->finish_cleanup ();
3031 editor->finish_cleanup ();
3034 display_cleanup_results (rep,
3037 The following %1 files were not in use and \n\
3038 have been moved to:\n\n\
3040 After a restart of Ardour,\n\n\
3041 Session -> Clean-up -> Flush Wastebasket\n\n\
3042 will release an additional\n\
3043 %3 %4bytes of disk space.\n"),
3045 The following file was not in use and \n\
3046 has been moved to:\n \
3048 After a restart of Ardour,\n\n\
3049 Session -> Clean-up -> Flush Wastebasket\n\n\
3050 will release an additional\n\
3051 %3 %4bytes of disk space.\n"
3057 ARDOUR_UI::flush_trash ()
3059 if (_session == 0) {
3060 /* shouldn't happen: menu item is insensitive */
3064 ARDOUR::CleanupReport rep;
3066 if (_session->cleanup_trash_sources (rep)) {
3070 display_cleanup_results (rep,
3072 _("The following %1 files were deleted from\n\
3074 releasing %3 %4bytes of disk space"),
3075 _("The following file was deleted from\n\
3077 releasing %3 %4bytes of disk space"));
3081 ARDOUR_UI::add_route (Gtk::Window* float_window)
3089 if (add_route_dialog == 0) {
3090 add_route_dialog = new AddRouteDialog (_session);
3092 add_route_dialog->set_transient_for (*float_window);
3096 if (add_route_dialog->is_visible()) {
3097 /* we're already doing this */
3101 ResponseType r = (ResponseType) add_route_dialog->run ();
3103 add_route_dialog->hide();
3106 case RESPONSE_ACCEPT:
3113 if ((count = add_route_dialog->count()) <= 0) {
3117 string template_path = add_route_dialog->track_template();
3119 if (!template_path.empty()) {
3120 _session->new_route_from_template (count, template_path);
3124 uint32_t input_chan = add_route_dialog->channels ();
3125 uint32_t output_chan;
3126 string name_template = add_route_dialog->name_template ();
3127 bool track = add_route_dialog->track ();
3128 RouteGroup* route_group = add_route_dialog->route_group ();
3130 AutoConnectOption oac = Config->get_output_auto_connect();
3132 if (oac & AutoConnectMaster) {
3133 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3135 output_chan = input_chan;
3138 /* XXX do something with name template */
3140 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3142 session_add_midi_track (route_group, count, name_template);
3144 MessageDialog msg (*editor,
3145 _("Sorry, MIDI Busses are not supported at this time."));
3147 //session_add_midi_bus();
3151 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3153 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3159 ARDOUR_UI::mixer_settings () const
3164 node = _session->instant_xml(X_("Mixer"));
3166 node = Config->instant_xml(X_("Mixer"));
3170 node = new XMLNode (X_("Mixer"));
3177 ARDOUR_UI::editor_settings () const
3182 node = _session->instant_xml(X_("Editor"));
3184 node = Config->instant_xml(X_("Editor"));
3188 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3189 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3194 node = new XMLNode (X_("Editor"));
3201 ARDOUR_UI::keyboard_settings () const
3205 node = Config->extra_xml(X_("Keyboard"));
3208 node = new XMLNode (X_("Keyboard"));
3215 ARDOUR_UI::create_xrun_marker (framepos_t where)
3217 editor->mouse_add_new_marker (where, false, true);
3221 ARDOUR_UI::halt_on_xrun_message ()
3223 MessageDialog msg (*editor,
3224 _("Recording was stopped because your system could not keep up."));
3229 ARDOUR_UI::xrun_handler (framepos_t where)
3235 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3237 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3238 create_xrun_marker(where);
3241 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3242 halt_on_xrun_message ();
3247 ARDOUR_UI::disk_overrun_handler ()
3249 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3251 if (!have_disk_speed_dialog_displayed) {
3252 have_disk_speed_dialog_displayed = true;
3253 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3254 The disk system on your computer\n\
3255 was not able to keep up with %1.\n\
3257 Specifically, it failed to write data to disk\n\
3258 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3259 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3265 ARDOUR_UI::disk_underrun_handler ()
3267 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3269 if (!have_disk_speed_dialog_displayed) {
3270 have_disk_speed_dialog_displayed = true;
3271 MessageDialog* msg = new MessageDialog (
3272 *editor, string_compose (_("The disk system on your computer\n\
3273 was not able to keep up with %1.\n\
3275 Specifically, it failed to read data from disk\n\
3276 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3277 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3283 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3285 have_disk_speed_dialog_displayed = false;
3290 ARDOUR_UI::session_dialog (std::string msg)
3292 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3297 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3299 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3308 ARDOUR_UI::pending_state_dialog ()
3310 HBox* hbox = new HBox();
3311 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3312 ArdourDialog dialog (_("Crash Recovery"), true);
3314 This session appears to have been in\n\
3315 middle of recording when ardour or\n\
3316 the computer was shutdown.\n\
3318 Ardour can recover any captured audio for\n\
3319 you, or it can ignore it. Please decide\n\
3320 what you would like to do.\n"));
3321 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3322 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3323 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3324 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3325 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3326 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3327 dialog.set_default_response (RESPONSE_ACCEPT);
3328 dialog.set_position (WIN_POS_CENTER);
3333 switch (dialog.run ()) {
3334 case RESPONSE_ACCEPT:
3342 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3344 HBox* hbox = new HBox();
3345 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3346 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3347 Label message (string_compose (_("\
3348 This session was created with a sample rate of %1 Hz\n\
3350 The audioengine is currently running at %2 Hz\n"), desired, actual));
3352 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3353 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3354 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3355 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3356 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3357 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3358 dialog.set_default_response (RESPONSE_ACCEPT);
3359 dialog.set_position (WIN_POS_CENTER);
3364 switch (dialog.run ()) {
3365 case RESPONSE_ACCEPT:
3374 ARDOUR_UI::disconnect_from_jack ()
3377 if( engine->disconnect_from_jack ()) {
3378 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3382 update_sample_rate (0);
3387 ARDOUR_UI::reconnect_to_jack ()
3390 if (engine->reconnect_to_jack ()) {
3391 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3395 update_sample_rate (0);
3400 ARDOUR_UI::use_config ()
3402 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3404 set_transport_controllable_state (*node);
3409 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3411 if (Config->get_primary_clock_delta_edit_cursor()) {
3412 primary_clock->set (pos, false, editor->get_preferred_edit_position(), 1);
3414 primary_clock->set (pos, 0, true);
3417 if (Config->get_secondary_clock_delta_edit_cursor()) {
3418 secondary_clock->set (pos, false, editor->get_preferred_edit_position(), 2);
3420 secondary_clock->set (pos);
3423 if (big_clock_window->get()) {
3424 big_clock->set (pos);
3430 ARDOUR_UI::step_edit_status_change (bool yn)
3432 // XXX should really store pre-step edit status of things
3433 // we make insensitive
3436 rec_button.set_visual_state (3);
3437 rec_button.set_sensitive (false);
3439 rec_button.set_visual_state (0);
3440 rec_button.set_sensitive (true);
3445 ARDOUR_UI::record_state_changed ()
3447 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3449 if (!_session || !big_clock_window->get()) {
3450 /* why bother - the clock isn't visible */
3454 Session::RecordState const r = _session->record_status ();
3455 bool const h = _session->have_rec_enabled_track ();
3457 if (r == Session::Recording && h) {
3458 big_clock->set_widget_name ("BigClockRecording");
3460 big_clock->set_widget_name ("BigClockNonRecording");
3465 ARDOUR_UI::first_idle ()
3468 _session->allow_auto_play (true);
3472 editor->first_idle();
3475 Keyboard::set_can_save_keybindings (true);
3480 ARDOUR_UI::store_clock_modes ()
3482 XMLNode* node = new XMLNode(X_("ClockModes"));
3484 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3485 XMLNode* child = new XMLNode (X_("Clock"));
3487 child->add_property (X_("name"), (*x)->name());
3488 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3489 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3491 node->add_child_nocopy (*child);
3494 _session->add_extra_xml (*node);
3495 _session->set_dirty ();
3498 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3499 : Controllable (name), ui (u), type(tp)
3505 ARDOUR_UI::TransportControllable::set_value (double val)
3508 /* do nothing: these are radio-style actions */
3512 const char *action = 0;
3516 action = X_("Roll");
3519 action = X_("Stop");
3522 action = X_("Goto Start");
3525 action = X_("Goto End");
3528 action = X_("Loop");
3531 action = X_("Play Selection");
3534 action = X_("Record");
3544 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3552 ARDOUR_UI::TransportControllable::get_value (void) const
3579 ARDOUR_UI::TransportControllable::set_id (const string& str)
3585 ARDOUR_UI::setup_profile ()
3587 if (gdk_screen_width() < 1200) {
3588 Profile->set_small_screen ();
3592 if (getenv ("ARDOUR_SAE")) {
3593 Profile->set_sae ();
3594 Profile->set_single_package ();
3599 ARDOUR_UI::toggle_translations ()
3601 using namespace Glib;
3603 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3605 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3608 string i18n_killer = ARDOUR::translation_kill_path();
3610 bool already_enabled = !ARDOUR::translations_are_disabled ();
3612 if (ract->get_active ()) {
3613 /* we don't care about errors */
3614 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3617 /* we don't care about errors */
3618 unlink (i18n_killer.c_str());
3621 if (already_enabled != ract->get_active()) {
3622 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3624 Gtk::MESSAGE_WARNING,
3626 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3627 win.set_position (Gtk::WIN_POS_CENTER);
3635 /** Add a window proxy to our list, so that its state will be saved.
3636 * This call also causes the window to be created and opened if its
3637 * state was saved as `visible'.
3640 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3642 _window_proxies.push_back (p);
3646 /** Remove a window proxy from our list. Must be called if a WindowProxy
3647 * is deleted, to prevent hanging pointers.
3650 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3652 _window_proxies.remove (p);
3656 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3658 MissingFileDialog dialog (s, str, type);
3663 int result = dialog.run ();
3670 return 1; // quit entire session load
3673 result = dialog.get_action ();
3679 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3681 AmbiguousFileDialog dialog (file, hits);
3687 return dialog.get_which ();