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/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;
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"
95 #include "location_ui.h"
96 #include "missing_file_dialog.h"
97 #include "missing_plugin_dialog.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"
108 #include "theme_manager.h"
109 #include "time_axis_view_item.h"
111 #include "window_proxy.h"
115 using namespace ARDOUR;
117 using namespace Gtkmm2ext;
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),
141 preroll_button (_("pre\nroll")),
142 postroll_button (_("post\nroll")),
146 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
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;
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.
202 if (theArdourUI == 0) {
206 ui_config = new UIConfiguration();
207 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;
222 rc_option_editor = 0;
223 session_option_editor = 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;
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 */
286 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
287 throw failed_constructor ();
290 setup_gtk_ardour_enums ();
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;
304 /* we like keyboards */
306 keyboard = new ArdourKeyboard(*this);
308 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
310 keyboard->set_state (*node, Stateful::loading_state_version);
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())
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));
340 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
342 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
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 ();
363 switch (_startup->response()) {
372 ARDOUR_UI::create_engine ()
374 // this gets called every time by new_session()
380 loading_message (_("Starting audio engine"));
383 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
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);
404 ARDOUR_UI::post_engine ()
406 /* Things to be done once we create the AudioEngine
409 ARDOUR::init_post_engine ();
411 ActionManager::init ();
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;
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;
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);
453 primary_clock.set_mode (AudioClock::Timecode);
454 secondary_clock.set_mode (AudioClock::BBT);
457 /* start the time-of-day-clock */
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);
465 update_disk_space ();
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 ()
490 delete add_route_dialog;
494 ARDOUR_UI::pop_back_splash ()
496 if (Splash::instance()) {
497 // Splash::instance()->pop_back();
498 Splash::instance()->hide ();
503 ARDOUR_UI::configure_timeout ()
505 if (last_configure_time == 0) {
506 /* no configure events yet */
510 /* force a gap of 0.5 seconds since the last configure event
513 if (get_microseconds() - last_configure_time < 500000) {
516 have_configure_timeout = false;
517 cerr << "config event-driven save\n";
518 save_ardour_state ();
524 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
526 if (have_configure_timeout) {
527 last_configure_time = get_microseconds();
529 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
530 have_configure_timeout = true;
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());
568 ARDOUR_UI::get_transport_controllable_state ()
570 XMLNode* node = new XMLNode(X_("TransportControllables"));
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);
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
605 if (!Config->get_periodic_safety_backups()) {
610 _session->maybe_write_autosave();
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);
630 if (_autosave_connection.connected()) {
631 _autosave_connection.disconnect();
637 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
641 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
643 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
646 MessageDialog win (title,
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."));
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."));
669 win.set_transient_for (*toplevel);
673 win.add_button (Stock::OK, RESPONSE_CLOSE);
675 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
678 win.set_default_response (RESPONSE_CLOSE);
681 win.set_position (Gtk::WIN_POS_CENTER);
684 /* we just don't care about the result, but we want to block */
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));
698 call_the_mothership (VERSIONSTRING);
703 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
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));
724 ARDOUR_UI::no_memory_warning ()
726 XMLNode node (X_("no-memory-warning"));
727 Config->add_instant_xml (node);
731 ARDOUR_UI::check_memory_locking ()
734 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
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;
744 long pages, page_size;
746 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
749 ram = (int64_t) pages * (int64_t) page_size;
752 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
756 if (limits.rlim_cur != RLIM_INFINITY) {
758 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
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();
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);
783 editor->ensure_float (msg);
793 ARDOUR_UI::queue_finish ()
795 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
799 ARDOUR_UI::idle_finish ()
802 return false; /* do not call again */
811 if (_session->transport_rolling() && (++tries < 8)) {
812 _session->request_stop (false, true);
816 if (_session->dirty()) {
817 switch (ask_about_saving_session(_("quit"))) {
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 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));
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");
890 if (_session->snap_name() == _session->name()) {
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);
917 window.set_keep_above (true);
920 ResponseType r = (ResponseType) window.run();
925 case RESPONSE_ACCEPT: // save and get out of here
927 case RESPONSE_APPLY: // get out of here
937 ARDOUR_UI::every_second ()
940 update_buffer_load ();
941 update_disk_space ();
946 ARDOUR_UI::every_point_one_seconds ()
948 update_speed_display ();
949 RapidScreenUpdate(); /* EMIT_SIGNAL */
954 ARDOUR_UI::every_point_zero_one_seconds ()
956 // august 2007: actual update frequency: 40Hz, not 100Hz
958 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
963 ARDOUR_UI::update_sample_rate (framecnt_t)
967 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
969 if (!engine->connected()) {
971 snprintf (buf, sizeof (buf), _("disconnected"));
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);
982 snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"),
984 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
988 sample_rate_label.set_text (buf);
992 ARDOUR_UI::update_cpu_load ()
995 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
996 cpu_load_label.set_text (buf);
1000 ARDOUR_UI::update_buffer_load ()
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);
1013 buffer_load_label.set_text ("");
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();
1027 ARDOUR_UI::update_disk_space()
1029 if (_session == 0) {
1033 framecnt_t frames = _session->available_capture_duration();
1035 framecnt_t fr = _session->frame_rate();
1037 if (frames == max_framecnt) {
1038 strcpy (buf, _("Disk: 24hrs+"));
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;
1051 hrs = frames / (fr * 3600);
1052 frames -= hrs * fr * 3600;
1053 mins = frames / (fr * 60);
1054 frames -= mins * fr * 60;
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"); */
1067 /* disk_space_box.style ("disk_space_label"); */
1073 ARDOUR_UI::update_wall_clock ()
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);
1089 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1091 session_popup_menu->popup (0, 0);
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);
1108 recent_session_display.set_model (recent_session_model);
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;
1145 /* now get available states for this session */
1147 if ((states = Session::possible_states (fullpath)) == 0) {
1148 /* no state file? */
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) {
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);
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();
1204 //session_selector_window->get_vbox()->show();
1208 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1210 session_selector_window->response (RESPONSE_ACCEPT);
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 ();
1226 session_selector_window->set_position (WIN_POS_MOUSE);
1228 ResponseType r = (ResponseType) session_selector_window->run ();
1231 case RESPONSE_ACCEPT:
1235 session_selector_window->hide();
1242 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
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()) {
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) {
1268 ARDOUR_UI::check_audioengine ()
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"),
1286 ARDOUR_UI::open_session ()
1288 if (!check_audioengine()) {
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 ();
1315 case RESPONSE_ACCEPT:
1318 open_session_selector->hide();
1322 open_session_selector->hide();
1323 string session_path = open_session_selector->get_filename();
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);
1337 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1339 list<boost::shared_ptr<MidiTrack> > tracks;
1341 if (_session == 0) {
1342 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1349 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1351 if (tracks.size() != how_many) {
1352 if (how_many == 1) {
1353 error << _("could not create a new midi track") << endmsg;
1355 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1359 if ((route = _session->new_midi_route ()) == 0) {
1360 error << _("could not create new midi bus") << endmsg;
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));
1377 ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, RouteGroup* route_group, uint32_t how_many)
1379 list<boost::shared_ptr<AudioTrack> > tracks;
1382 if (_session == 0) {
1383 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1389 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1391 if (tracks.size() != how_many) {
1392 if (how_many == 1) {
1393 error << _("could not create a new audio track") << endmsg;
1395 error << string_compose (_("could only create %1 of %2 new audio %3"),
1396 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1402 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many);
1404 if (routes.size() != how_many) {
1405 if (how_many == 1) {
1406 error << _("could not create a new audio track") << endmsg;
1408 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1415 MessageDialog msg (*editor,
1416 string_compose (_("There are insufficient JACK ports available\n\
1417 to create a new track or bus.\n\
1418 You should save %1, exit and\n\
1419 restart JACK with more ports."), PROGRAM_NAME));
1426 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1428 framecnt_t _preroll = 0;
1431 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1432 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1434 if (new_position > _preroll) {
1435 new_position -= _preroll;
1440 _session->request_locate (new_position, with_roll);
1445 ARDOUR_UI::transport_goto_start ()
1448 _session->goto_start();
1450 /* force displayed area in editor to start no matter
1451 what "follow playhead" setting is.
1455 editor->center_screen (_session->current_start_frame ());
1461 ARDOUR_UI::transport_goto_zero ()
1464 _session->request_locate (0);
1466 /* force displayed area in editor to start no matter
1467 what "follow playhead" setting is.
1471 editor->reset_x_origin (0);
1477 ARDOUR_UI::transport_goto_wallclock ()
1479 if (_session && editor) {
1486 localtime_r (&now, &tmnow);
1488 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1489 frames += tmnow.tm_min * (60 * _session->frame_rate());
1490 frames += tmnow.tm_sec * _session->frame_rate();
1492 _session->request_locate (frames, _session->transport_rolling ());
1494 /* force displayed area in editor to start no matter
1495 what "follow playhead" setting is.
1499 editor->center_screen (frames);
1505 ARDOUR_UI::transport_goto_end ()
1508 framepos_t const frame = _session->current_end_frame();
1509 _session->request_locate (frame);
1511 /* force displayed area in editor to start no matter
1512 what "follow playhead" setting is.
1516 editor->center_screen (frame);
1522 ARDOUR_UI::transport_stop ()
1528 if (_session->is_auditioning()) {
1529 _session->cancel_audition ();
1533 _session->request_stop (false, true);
1537 ARDOUR_UI::transport_stop_and_forget_capture ()
1540 _session->request_stop (true, true);
1545 ARDOUR_UI::remove_last_capture()
1548 editor->remove_last_capture();
1553 ARDOUR_UI::transport_record (bool roll)
1557 switch (_session->record_status()) {
1558 case Session::Disabled:
1559 if (_session->ntracks() == 0) {
1560 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1564 _session->maybe_enable_record ();
1569 case Session::Recording:
1571 _session->request_stop();
1573 _session->disable_record (false, true);
1577 case Session::Enabled:
1578 _session->disable_record (false, true);
1581 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1585 ARDOUR_UI::transport_roll ()
1591 if (_session->is_auditioning()) {
1596 if (_session->config.get_external_sync()) {
1597 switch (_session->config.get_sync_source()) {
1601 /* transport controlled by the master */
1607 bool rolling = _session->transport_rolling();
1609 if (_session->get_play_loop()) {
1610 /* XXX it is not possible to just leave seamless loop and keep
1611 playing at present (nov 4th 2009)
1613 if (!Config->get_seamless_loop()) {
1614 _session->request_play_loop (false, true);
1616 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1617 /* stop playing a range if we currently are */
1618 _session->request_play_range (0, true);
1621 if (join_play_range_button.get_active()) {
1622 _session->request_play_range (&editor->get_selection().time, true);
1626 _session->request_transport_speed (1.0f);
1631 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1638 if (_session->is_auditioning()) {
1639 _session->cancel_audition ();
1644 if (_session->config.get_external_sync()) {
1645 switch (_session->config.get_sync_source()) {
1649 /* transport controlled by the master */
1655 bool rolling = _session->transport_rolling();
1656 bool affect_transport = true;
1658 if (rolling && roll_out_of_bounded_mode) {
1659 /* drop out of loop/range playback but leave transport rolling */
1660 if (_session->get_play_loop()) {
1661 if (Config->get_seamless_loop()) {
1662 /* the disk buffers contain copies of the loop - we can't
1663 just keep playing, so stop the transport. the user
1664 can restart as they wish.
1666 affect_transport = true;
1668 /* disk buffers are normal, so we can keep playing */
1669 affect_transport = false;
1671 _session->request_play_loop (false, true);
1672 } else if (_session->get_play_range ()) {
1673 affect_transport = false;
1674 _session->request_play_range (0, true);
1678 if (affect_transport) {
1680 _session->request_stop (with_abort, true);
1682 if (join_play_range_button.get_active()) {
1683 _session->request_play_range (&editor->get_selection().time, true);
1686 _session->request_transport_speed (1.0f);
1692 ARDOUR_UI::toggle_session_auto_loop ()
1698 if (_session->get_play_loop()) {
1700 if (_session->transport_rolling()) {
1702 Location * looploc = _session->locations()->auto_loop_location();
1705 _session->request_locate (looploc->start(), true);
1706 _session->request_play_loop (false);
1710 _session->request_play_loop (false);
1714 Location * looploc = _session->locations()->auto_loop_location();
1717 _session->request_play_loop (true);
1723 ARDOUR_UI::transport_play_selection ()
1729 editor->play_selection ();
1733 ARDOUR_UI::transport_rewind (int option)
1735 float current_transport_speed;
1738 current_transport_speed = _session->transport_speed();
1740 if (current_transport_speed >= 0.0f) {
1743 _session->request_transport_speed (-1.0f);
1746 _session->request_transport_speed (-4.0f);
1749 _session->request_transport_speed (-0.5f);
1754 _session->request_transport_speed (current_transport_speed * 1.5f);
1760 ARDOUR_UI::transport_forward (int option)
1762 float current_transport_speed;
1765 current_transport_speed = _session->transport_speed();
1767 if (current_transport_speed <= 0.0f) {
1770 _session->request_transport_speed (1.0f);
1773 _session->request_transport_speed (4.0f);
1776 _session->request_transport_speed (0.5f);
1781 _session->request_transport_speed (current_transport_speed * 1.5f);
1788 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1790 if (_session == 0) {
1794 boost::shared_ptr<Route> r;
1796 if ((r = _session->route_by_remote_id (rid)) != 0) {
1800 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1801 t->set_record_enabled (!t->record_enabled(), this);
1804 if (_session == 0) {
1810 ARDOUR_UI::map_transport_state ()
1812 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1815 auto_loop_button.set_visual_state (0);
1816 play_selection_button.set_visual_state (0);
1817 roll_button.set_visual_state (0);
1818 stop_button.set_visual_state (1);
1822 float sp = _session->transport_speed();
1825 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1826 shuttle_box.queue_draw ();
1827 } else if (sp == 0.0f) {
1829 shuttle_box.queue_draw ();
1830 update_disk_space ();
1837 if (_session->get_play_range()) {
1839 play_selection_button.set_visual_state (1);
1840 roll_button.set_visual_state (0);
1841 auto_loop_button.set_visual_state (0);
1843 } else if (_session->get_play_loop ()) {
1845 auto_loop_button.set_visual_state (1);
1846 play_selection_button.set_visual_state (0);
1847 roll_button.set_visual_state (0);
1851 roll_button.set_visual_state (1);
1852 play_selection_button.set_visual_state (0);
1853 auto_loop_button.set_visual_state (0);
1856 if (join_play_range_button.get_active()) {
1857 /* light up both roll and play-selection if they are joined */
1858 roll_button.set_visual_state (1);
1859 play_selection_button.set_visual_state (1);
1862 stop_button.set_visual_state (0);
1866 stop_button.set_visual_state (1);
1867 roll_button.set_visual_state (0);
1868 play_selection_button.set_visual_state (0);
1869 auto_loop_button.set_visual_state (0);
1874 ARDOUR_UI::engine_stopped ()
1876 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1877 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1878 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1882 ARDOUR_UI::engine_running ()
1884 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1885 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1886 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1888 Glib::RefPtr<Action> action;
1889 const char* action_name = 0;
1891 switch (engine->frames_per_cycle()) {
1893 action_name = X_("JACKLatency32");
1896 action_name = X_("JACKLatency64");
1899 action_name = X_("JACKLatency128");
1902 action_name = X_("JACKLatency512");
1905 action_name = X_("JACKLatency1024");
1908 action_name = X_("JACKLatency2048");
1911 action_name = X_("JACKLatency4096");
1914 action_name = X_("JACKLatency8192");
1917 /* XXX can we do anything useful ? */
1923 action = ActionManager::get_action (X_("JACK"), action_name);
1926 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1927 ract->set_active ();
1933 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1935 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1936 /* we can't rely on the original string continuing to exist when we are called
1937 again in the GUI thread, so make a copy and note that we need to
1940 char *copy = strdup (reason);
1941 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1945 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1946 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1948 update_sample_rate (0);
1952 /* if the reason is a non-empty string, it means that the backend was shutdown
1953 rather than just Ardour.
1956 if (strlen (reason)) {
1957 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1959 msgstr = string_compose (_("\
1960 JACK has either been shutdown or it\n\
1961 disconnected %1 because %1\n\
1962 was not fast enough. Try to restart\n\
1963 JACK, reconnect and save the session."), PROGRAM_NAME);
1966 MessageDialog msg (*editor, msgstr);
1971 free ((char*) reason);
1976 ARDOUR_UI::do_engine_start ()
1984 error << _("Unable to start the session running")
1994 ARDOUR_UI::setup_theme ()
1996 theme_manager->setup_theme();
2000 ARDOUR_UI::update_clocks ()
2002 if (!editor || !editor->dragging_playhead()) {
2003 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2008 ARDOUR_UI::start_clocking ()
2010 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2014 ARDOUR_UI::stop_clocking ()
2016 clock_signal_connection.disconnect ();
2020 ARDOUR_UI::toggle_clocking ()
2023 if (clock_button.get_active()) {
2032 ARDOUR_UI::_blink (void *arg)
2035 ((ARDOUR_UI *) arg)->blink ();
2042 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2046 ARDOUR_UI::start_blinking ()
2048 /* Start the blink signal. Everybody with a blinking widget
2049 uses Blink to drive the widget's state.
2052 if (blink_timeout_tag < 0) {
2054 blink_timeout_tag = g_timeout_add (240, _blink, this);
2059 ARDOUR_UI::stop_blinking ()
2061 if (blink_timeout_tag >= 0) {
2062 g_source_remove (blink_timeout_tag);
2063 blink_timeout_tag = -1;
2068 /** Ask the user for the name of a new shapshot and then take it.
2072 ARDOUR_UI::snapshot_session (bool switch_to_it)
2074 ArdourPrompter prompter (true);
2077 prompter.set_name ("Prompter");
2078 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2079 prompter.set_title (_("Take Snapshot"));
2080 prompter.set_title (_("Take Snapshot"));
2081 prompter.set_prompt (_("Name of new snapshot"));
2083 if (!switch_to_it) {
2086 struct tm local_time;
2089 localtime_r (&n, &local_time);
2090 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2091 prompter.set_initial_text (timebuf);
2095 switch (prompter.run()) {
2096 case RESPONSE_ACCEPT:
2098 prompter.get_result (snapname);
2100 bool do_save = (snapname.length() != 0);
2103 if (snapname.find ('/') != string::npos) {
2104 MessageDialog msg (_("To ensure compatibility with various systems\n"
2105 "snapshot names may not contain a '/' character"));
2109 if (snapname.find ('\\') != string::npos) {
2110 MessageDialog msg (_("To ensure compatibility with various systems\n"
2111 "snapshot names may not contain a '\\' character"));
2117 vector<sys::path> p;
2118 get_state_files_in_directory (_session->session_directory().root_path(), p);
2119 vector<string> n = get_file_names_no_extension (p);
2120 if (find (n.begin(), n.end(), snapname) != n.end()) {
2122 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2123 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2124 confirm.get_vbox()->pack_start (m, true, true);
2125 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2126 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2127 confirm.show_all ();
2128 switch (confirm.run()) {
2129 case RESPONSE_CANCEL:
2135 save_state (snapname, switch_to_it);
2146 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2148 XMLNode* node = new XMLNode (X_("UI"));
2150 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2151 if (!(*i)->rc_configured()) {
2152 node->add_child_nocopy (*((*i)->get_state ()));
2156 _session->add_extra_xml (*node);
2158 save_state_canfail (name, switch_to_it);
2162 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2167 if (name.length() == 0) {
2168 name = _session->snap_name();
2171 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2175 cerr << "SS canfail\n";
2176 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2181 ARDOUR_UI::primary_clock_value_changed ()
2184 _session->request_locate (primary_clock.current_time ());
2189 ARDOUR_UI::big_clock_value_changed ()
2192 _session->request_locate (big_clock.current_time ());
2197 ARDOUR_UI::secondary_clock_value_changed ()
2200 _session->request_locate (secondary_clock.current_time ());
2205 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2207 if (_session == 0) {
2211 if (_session->step_editing()) {
2215 Session::RecordState const r = _session->record_status ();
2216 bool const h = _session->have_rec_enabled_track ();
2218 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2220 rec_button.set_visual_state (2);
2222 rec_button.set_visual_state (0);
2224 } else if (r == Session::Recording && h) {
2225 rec_button.set_visual_state (1);
2227 rec_button.set_visual_state (0);
2232 ARDOUR_UI::save_template ()
2234 ArdourPrompter prompter (true);
2237 if (!check_audioengine()) {
2241 prompter.set_name (X_("Prompter"));
2242 prompter.set_title (_("Save Template"));
2243 prompter.set_prompt (_("Name for template:"));
2244 prompter.set_initial_text(_session->name() + _("-template"));
2245 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2247 switch (prompter.run()) {
2248 case RESPONSE_ACCEPT:
2249 prompter.get_result (name);
2251 if (name.length()) {
2252 _session->save_template (name);
2262 ARDOUR_UI::edit_metadata ()
2264 SessionMetadataEditor dialog;
2265 dialog.set_session (_session);
2266 editor->ensure_float (dialog);
2271 ARDOUR_UI::import_metadata ()
2273 SessionMetadataImporter dialog;
2274 dialog.set_session (_session);
2275 editor->ensure_float (dialog);
2280 ARDOUR_UI::fontconfig_dialog ()
2283 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2284 may not and it can take a while to build it. Warn them.
2287 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2289 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2290 MessageDialog msg (*_startup,
2291 string_compose (_("Welcome to %1.\n\n"
2292 "The program will take a bit longer to start up\n"
2293 "while the system fonts are checked.\n\n"
2294 "This will only be done once, and you will\n"
2295 "not see this message again\n"), PROGRAM_NAME),
2308 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2310 existing_session = false;
2312 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2313 session_path = cmdline_path;
2314 existing_session = true;
2315 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2316 session_path = Glib::path_get_dirname (string (cmdline_path));
2317 existing_session = true;
2319 /* it doesn't exist, assume the best */
2320 session_path = Glib::path_get_dirname (string (cmdline_path));
2323 session_name = basename_nosuffix (string (cmdline_path));
2327 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2329 /* when this is called, the backend audio system must be running */
2331 /* the main idea here is to deal with the fact that a cmdline argument for the session
2332 can be interpreted in different ways - it could be a directory or a file, and before
2333 we load, we need to know both the session directory and the snapshot (statefile) within it
2334 that we are supposed to use.
2337 if (session_name.length() == 0 || session_path.length() == 0) {
2341 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2343 std::string predicted_session_file;
2345 predicted_session_file = session_path;
2346 predicted_session_file += '/';
2347 predicted_session_file += session_name;
2348 predicted_session_file += ARDOUR::statefile_suffix;
2350 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2351 existing_session = true;
2354 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2356 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2357 /* existing .ardour file */
2358 existing_session = true;
2362 existing_session = false;
2365 /* lets just try to load it */
2367 if (create_engine ()) {
2368 backend_audio_error (false, _startup);
2372 return load_session (session_path, session_name);
2376 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2378 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2380 MessageDialog msg (str,
2382 Gtk::MESSAGE_WARNING,
2383 Gtk::BUTTONS_YES_NO,
2387 msg.set_name (X_("OpenExistingDialog"));
2388 msg.set_title (_("Open Existing Session"));
2389 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2390 msg.set_position (Gtk::WIN_POS_MOUSE);
2393 switch (msg.run()) {
2402 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2404 BusProfile bus_profile;
2406 if (Profile->get_sae()) {
2408 bus_profile.master_out_channels = 2;
2409 bus_profile.input_ac = AutoConnectPhysical;
2410 bus_profile.output_ac = AutoConnectMaster;
2411 bus_profile.requested_physical_in = 0; // use all available
2412 bus_profile.requested_physical_out = 0; // use all available
2416 /* get settings from advanced section of NSD */
2418 if (_startup->create_master_bus()) {
2419 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2421 bus_profile.master_out_channels = 0;
2424 if (_startup->connect_inputs()) {
2425 bus_profile.input_ac = AutoConnectPhysical;
2427 bus_profile.input_ac = AutoConnectOption (0);
2430 /// @todo some minor tweaks.
2432 bus_profile.output_ac = AutoConnectOption (0);
2434 if (_startup->connect_outputs ()) {
2435 if (_startup->connect_outs_to_master()) {
2436 bus_profile.output_ac = AutoConnectMaster;
2437 } else if (_startup->connect_outs_to_physical()) {
2438 bus_profile.output_ac = AutoConnectPhysical;
2442 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2443 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2446 if (build_session (session_path, session_name, bus_profile)) {
2454 ARDOUR_UI::idle_load (const std::string& path)
2457 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2458 /* /path/to/foo => /path/to/foo, foo */
2459 load_session (path, basename_nosuffix (path));
2461 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2462 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2466 ARDOUR_COMMAND_LINE::session_name = path;
2469 * new_session_dialog doens't exist in A3
2470 * Try to remove all references to it to
2471 * see if it will compile. NOTE: this will
2472 * likely cause a runtime issue is my somewhat
2476 //if (new_session_dialog) {
2479 /* make it break out of Dialog::run() and
2483 //new_session_dialog->response (1);
2489 ARDOUR_UI::end_loading_messages ()
2495 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2498 // splash->message (msg);
2502 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2504 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2506 string session_name;
2507 string session_path;
2508 string template_name;
2510 bool likely_new = false;
2512 if (! load_template.empty()) {
2513 should_be_new = true;
2514 template_name = load_template;
2519 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2521 /* if they named a specific statefile, use it, otherwise they are
2522 just giving a session folder, and we want to use it as is
2523 to find the session.
2526 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2527 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2529 session_path = ARDOUR_COMMAND_LINE::session_name;
2532 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2536 bool const apply = run_startup (should_be_new, load_template);
2539 if (quit_on_cancel) {
2546 /* if we run the startup dialog again, offer more than just "new session" */
2548 should_be_new = false;
2550 session_name = _startup->session_name (likely_new);
2552 /* this shouldn't happen, but we catch it just in case it does */
2554 if (session_name.empty()) {
2558 if (_startup->use_session_template()) {
2559 template_name = _startup->session_template_name();
2560 _session_is_new = true;
2563 if (session_name[0] == G_DIR_SEPARATOR ||
2564 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2565 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2567 /* absolute path or cwd-relative path specified for session name: infer session folder
2568 from what was given.
2571 session_path = Glib::path_get_dirname (session_name);
2572 session_name = Glib::path_get_basename (session_name);
2576 session_path = _startup->session_folder();
2578 if (session_name.find ('/') != string::npos) {
2579 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2580 "session names may not contain a '/' character"));
2582 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
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"));
2590 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2596 if (create_engine ()) {
2600 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2604 std::string existing = Glib::build_filename (session_path, session_name);
2606 if (!ask_about_loading_existing_session (existing)) {
2607 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2612 _session_is_new = false;
2617 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2619 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2623 if (session_name.find ('/') != std::string::npos) {
2624 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2625 "session names may not contain a '/' character"));
2627 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
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"));
2635 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2639 _session_is_new = true;
2642 if (likely_new && template_name.empty()) {
2644 ret = build_session_from_nsd (session_path, session_name);
2648 ret = load_session (session_path, session_name, template_name);
2651 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2655 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2656 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2666 ARDOUR_UI::close_session()
2668 if (!check_audioengine()) {
2672 if (unload_session (true)) {
2676 ARDOUR_COMMAND_LINE::session_name = "";
2678 if (get_session_parameters (true, false)) {
2682 goto_editor_window ();
2685 /** @return -2 if the load failed because we are not connected to the AudioEngine */
2687 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2689 Session *new_session;
2693 session_loaded = false;
2695 if (!check_audioengine()) {
2699 unload_status = unload_session ();
2701 if (unload_status < 0) {
2703 } else if (unload_status > 0) {
2708 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2711 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2714 /* this one is special */
2716 catch (AudioEngine::PortRegistrationFailure& err) {
2718 MessageDialog msg (err.what(),
2721 Gtk::BUTTONS_CLOSE);
2723 msg.set_title (_("Port Registration Error"));
2724 msg.set_secondary_text (_("Click the Close button to try again."));
2725 msg.set_position (Gtk::WIN_POS_CENTER);
2729 int response = msg.run ();
2734 case RESPONSE_CANCEL:
2744 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"),path, snap_name),
2749 msg.set_title (_("Loading Error"));
2750 msg.set_secondary_text (_("Click the Refresh button to try again."));
2751 msg.add_button (Stock::REFRESH, 1);
2752 msg.set_position (Gtk::WIN_POS_CENTER);
2756 int response = msg.run ();
2771 list<string> const u = new_session->unknown_processors ();
2773 MissingPluginDialog d (_session, u);
2778 /* Now the session been created, add the transport controls */
2779 new_session->add_controllable(roll_controllable);
2780 new_session->add_controllable(stop_controllable);
2781 new_session->add_controllable(goto_start_controllable);
2782 new_session->add_controllable(goto_end_controllable);
2783 new_session->add_controllable(auto_loop_controllable);
2784 new_session->add_controllable(play_selection_controllable);
2785 new_session->add_controllable(rec_controllable);
2787 set_session (new_session);
2789 session_loaded = true;
2791 goto_editor_window ();
2794 _session->set_clean ();
2805 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2807 Session *new_session;
2810 if (!check_audioengine()) {
2814 session_loaded = false;
2816 x = unload_session ();
2824 _session_is_new = true;
2827 new_session = new Session (*engine, path, snap_name, &bus_profile);
2832 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2838 /* Give the new session the default GUI state, if such things exist */
2841 n = Config->instant_xml (X_("Editor"));
2843 new_session->add_instant_xml (*n, false);
2845 n = Config->instant_xml (X_("Mixer"));
2847 new_session->add_instant_xml (*n, false);
2850 /* Put the playhead at 0 and scroll fully left */
2851 n = new_session->instant_xml (X_("Editor"));
2853 n->add_property (X_("playhead"), X_("0"));
2854 n->add_property (X_("left-frame"), X_("0"));
2857 set_session (new_session);
2859 session_loaded = true;
2861 new_session->save_state(new_session->name());
2867 ARDOUR_UI::launch_chat ()
2870 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2872 open_uri("http://webchat.freenode.net/?channels=ardour");
2877 ARDOUR_UI::show_about ()
2881 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2884 about->set_transient_for(*editor);
2889 ARDOUR_UI::launch_manual ()
2891 PBD::open_uri("http://ardour.org/flossmanual");
2895 ARDOUR_UI::launch_reference ()
2897 PBD::open_uri("http://ardour.org/refmanual");
2901 ARDOUR_UI::hide_about ()
2904 about->get_window()->set_cursor ();
2910 ARDOUR_UI::about_signal_response (int /*response*/)
2916 ARDOUR_UI::show_splash ()
2920 splash = new Splash;
2928 splash->queue_draw ();
2929 splash->get_window()->process_updates (true);
2934 ARDOUR_UI::hide_splash ()
2942 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2943 const string& plural_msg, const string& singular_msg)
2947 removed = rep.paths.size();
2950 MessageDialog msgd (*editor,
2951 _("No audio files were ready for cleanup"),
2954 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2955 msgd.set_secondary_text (_("If this seems suprising, \n\
2956 check for any existing snapshots.\n\
2957 These may still include regions that\n\
2958 require some unused files to continue to exist."));
2964 ArdourDialog results (_("Clean-up"), true, false);
2966 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2967 CleanupResultsModelColumns() {
2971 Gtk::TreeModelColumn<std::string> visible_name;
2972 Gtk::TreeModelColumn<std::string> fullpath;
2976 CleanupResultsModelColumns results_columns;
2977 Glib::RefPtr<Gtk::ListStore> results_model;
2978 Gtk::TreeView results_display;
2980 results_model = ListStore::create (results_columns);
2981 results_display.set_model (results_model);
2982 results_display.append_column (list_title, results_columns.visible_name);
2984 results_display.set_name ("CleanupResultsList");
2985 results_display.set_headers_visible (true);
2986 results_display.set_headers_clickable (false);
2987 results_display.set_reorderable (false);
2989 Gtk::ScrolledWindow list_scroller;
2992 Gtk::HBox dhbox; // the hbox for the image and text
2993 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2994 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2996 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2998 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
3001 %1 - number of files removed
3002 %2 - location of "dead_sounds"
3003 %3 - size of files affected
3004 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3007 const char* bprefix;
3008 double space_adjusted = 0;
3010 if (rep.space < 100000.0f) {
3011 bprefix = X_("kilo");
3012 } else if (rep.space < 1000000.0f * 1000) {
3013 bprefix = X_("mega");
3014 space_adjusted = truncf((float)rep.space / 1000.0);
3016 bprefix = X_("giga");
3017 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
3021 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
3023 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
3026 dhbox.pack_start (*dimage, true, false, 5);
3027 dhbox.pack_start (txt, true, false, 5);
3029 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3030 TreeModel::Row row = *(results_model->append());
3031 row[results_columns.visible_name] = *i;
3032 row[results_columns.fullpath] = *i;
3035 list_scroller.add (results_display);
3036 list_scroller.set_size_request (-1, 150);
3037 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3039 dvbox.pack_start (dhbox, true, false, 5);
3040 dvbox.pack_start (list_scroller, true, false, 5);
3041 ddhbox.pack_start (dvbox, true, false, 5);
3043 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3044 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3045 results.set_default_response (RESPONSE_CLOSE);
3046 results.set_position (Gtk::WIN_POS_MOUSE);
3048 results_display.show();
3049 list_scroller.show();
3056 //results.get_vbox()->show();
3057 results.set_resizable (false);
3064 ARDOUR_UI::cleanup ()
3066 if (_session == 0) {
3067 /* shouldn't happen: menu item is insensitive */
3072 MessageDialog checker (_("Are you sure you want to cleanup?"),
3074 Gtk::MESSAGE_QUESTION,
3075 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3077 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3078 ALL undo/redo information will be lost if you cleanup.\n\
3079 After cleanup, unused audio files will be moved to a \
3080 \"dead sounds\" location."));
3082 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3083 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3084 checker.set_default_response (RESPONSE_CANCEL);
3086 checker.set_name (_("CleanupDialog"));
3087 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3088 checker.set_position (Gtk::WIN_POS_MOUSE);
3090 switch (checker.run()) {
3091 case RESPONSE_ACCEPT:
3097 ARDOUR::CleanupReport rep;
3099 editor->prepare_for_cleanup ();
3101 /* do not allow flush until a session is reloaded */
3103 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3105 act->set_sensitive (false);
3108 if (_session->cleanup_sources (rep)) {
3109 editor->finish_cleanup ();
3113 editor->finish_cleanup ();
3116 display_cleanup_results (rep,
3119 The following %1 files were not in use and \n\
3120 have been moved to:\n\
3122 Flushing the wastebasket will \n\
3123 release an additional\n\
3124 %3 %4bytes of disk space.\n"),
3126 The following file was not in use and \n \
3127 has been moved to:\n \
3129 Flushing the wastebasket will \n\
3130 release an additional\n\
3131 %3 %4bytes of disk space.\n"
3137 ARDOUR_UI::flush_trash ()
3139 if (_session == 0) {
3140 /* shouldn't happen: menu item is insensitive */
3144 ARDOUR::CleanupReport rep;
3146 if (_session->cleanup_trash_sources (rep)) {
3150 display_cleanup_results (rep,
3152 _("The following %1 files were deleted from\n\
3154 releasing %3 %4bytes of disk space"),
3155 _("The following file was deleted from\n\
3157 releasing %3 %4bytes of disk space"));
3161 ARDOUR_UI::add_route (Gtk::Window* float_window)
3169 if (add_route_dialog == 0) {
3170 add_route_dialog = new AddRouteDialog (_session);
3172 add_route_dialog->set_transient_for (*float_window);
3176 if (add_route_dialog->is_visible()) {
3177 /* we're already doing this */
3181 ResponseType r = (ResponseType) add_route_dialog->run ();
3183 add_route_dialog->hide();
3186 case RESPONSE_ACCEPT:
3193 if ((count = add_route_dialog->count()) <= 0) {
3197 string template_path = add_route_dialog->track_template();
3199 if (!template_path.empty()) {
3200 _session->new_route_from_template (count, template_path);
3204 uint32_t input_chan = add_route_dialog->channels ();
3205 uint32_t output_chan;
3206 string name_template = add_route_dialog->name_template ();
3207 bool track = add_route_dialog->track ();
3208 RouteGroup* route_group = add_route_dialog->route_group ();
3210 AutoConnectOption oac = Config->get_output_auto_connect();
3212 if (oac & AutoConnectMaster) {
3213 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3215 output_chan = input_chan;
3218 /* XXX do something with name template */
3220 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3222 session_add_midi_track (route_group, count);
3224 MessageDialog msg (*editor,
3225 _("Sorry, MIDI Busses are not supported at this time."));
3227 //session_add_midi_bus();
3231 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3233 session_add_audio_bus (input_chan, output_chan, route_group, count);
3239 ARDOUR_UI::mixer_settings () const
3244 node = _session->instant_xml(X_("Mixer"));
3246 node = Config->instant_xml(X_("Mixer"));
3250 node = new XMLNode (X_("Mixer"));
3257 ARDOUR_UI::editor_settings () const
3262 node = _session->instant_xml(X_("Editor"));
3264 node = Config->instant_xml(X_("Editor"));
3268 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3269 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3274 node = new XMLNode (X_("Editor"));
3281 ARDOUR_UI::keyboard_settings () const
3285 node = Config->extra_xml(X_("Keyboard"));
3288 node = new XMLNode (X_("Keyboard"));
3294 ARDOUR_UI::create_xrun_marker (framepos_t where)
3296 editor->mouse_add_new_marker (where, false, true);
3300 ARDOUR_UI::halt_on_xrun_message ()
3302 MessageDialog msg (*editor,
3303 _("Recording was stopped because your system could not keep up."));
3308 ARDOUR_UI::xrun_handler (framepos_t where)
3314 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3316 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3317 create_xrun_marker(where);
3320 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3321 halt_on_xrun_message ();
3326 ARDOUR_UI::disk_overrun_handler ()
3328 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3330 if (!have_disk_speed_dialog_displayed) {
3331 have_disk_speed_dialog_displayed = true;
3332 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3333 The disk system on your computer\n\
3334 was not able to keep up with %1.\n\
3336 Specifically, it failed to write data to disk\n\
3337 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3338 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3344 ARDOUR_UI::disk_underrun_handler ()
3346 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3348 if (!have_disk_speed_dialog_displayed) {
3349 have_disk_speed_dialog_displayed = true;
3350 MessageDialog* msg = new MessageDialog (*editor,
3351 string_compose (_("The disk system on your computer\n\
3352 was not able to keep up with %1.\n\
3354 Specifically, it failed to read data from disk\n\
3355 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3356 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3362 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3364 have_disk_speed_dialog_displayed = false;
3369 ARDOUR_UI::session_dialog (std::string msg)
3371 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3376 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3378 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3387 ARDOUR_UI::pending_state_dialog ()
3389 HBox* hbox = new HBox();
3390 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3391 ArdourDialog dialog (_("Crash Recovery"), true);
3393 This session appears to have been in\n\
3394 middle of recording when ardour or\n\
3395 the computer was shutdown.\n\
3397 Ardour can recover any captured audio for\n\
3398 you, or it can ignore it. Please decide\n\
3399 what you would like to do.\n"));
3400 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3401 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3402 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3403 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3404 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3405 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3406 dialog.set_default_response (RESPONSE_ACCEPT);
3407 dialog.set_position (WIN_POS_CENTER);
3412 switch (dialog.run ()) {
3413 case RESPONSE_ACCEPT:
3421 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3423 HBox* hbox = new HBox();
3424 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3425 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3426 Label message (string_compose (_("\
3427 This session was created with a sample rate of %1 Hz\n\
3429 The audioengine is currently running at %2 Hz\n"), desired, actual));
3431 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3432 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3433 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3434 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3435 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3436 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3437 dialog.set_default_response (RESPONSE_ACCEPT);
3438 dialog.set_position (WIN_POS_CENTER);
3443 switch (dialog.run ()) {
3444 case RESPONSE_ACCEPT:
3453 ARDOUR_UI::disconnect_from_jack ()
3456 if( engine->disconnect_from_jack ()) {
3457 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3461 update_sample_rate (0);
3466 ARDOUR_UI::reconnect_to_jack ()
3469 if (engine->reconnect_to_jack ()) {
3470 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3474 update_sample_rate (0);
3479 ARDOUR_UI::use_config ()
3481 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3483 set_transport_controllable_state (*node);
3488 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3490 if (Config->get_primary_clock_delta_edit_cursor()) {
3491 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3493 primary_clock.set (pos, 0, true);
3496 if (Config->get_secondary_clock_delta_edit_cursor()) {
3497 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3499 secondary_clock.set (pos);
3502 if (big_clock_window->get()) {
3503 big_clock.set (pos);
3509 ARDOUR_UI::step_edit_status_change (bool yn)
3511 // XXX should really store pre-step edit status of things
3512 // we make insensitive
3515 rec_button.set_visual_state (3);
3516 rec_button.set_sensitive (false);
3518 rec_button.set_visual_state (0);
3519 rec_button.set_sensitive (true);
3524 ARDOUR_UI::record_state_changed ()
3526 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3528 if (!_session || !big_clock_window->get()) {
3529 /* why bother - the clock isn't visible */
3533 Session::RecordState const r = _session->record_status ();
3534 bool const h = _session->have_rec_enabled_track ();
3536 if (r == Session::Recording && h) {
3537 big_clock.set_widget_name ("BigClockRecording");
3539 big_clock.set_widget_name ("BigClockNonRecording");
3544 ARDOUR_UI::first_idle ()
3547 _session->allow_auto_play (true);
3551 editor->first_idle();
3554 Keyboard::set_can_save_keybindings (true);
3559 ARDOUR_UI::store_clock_modes ()
3561 XMLNode* node = new XMLNode(X_("ClockModes"));
3563 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3564 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3567 _session->add_extra_xml (*node);
3568 _session->set_dirty ();
3573 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3574 : Controllable (name), ui (u), type(tp)
3580 ARDOUR_UI::TransportControllable::set_value (double val)
3582 if (type == ShuttleControl) {
3589 fract = -((0.5 - val)/0.5);
3591 fract = ((val - 0.5)/0.5);
3595 ui.set_shuttle_fract (fract);
3600 /* do nothing: these are radio-style actions */
3604 const char *action = 0;
3608 action = X_("Roll");
3611 action = X_("Stop");
3614 action = X_("Goto Start");
3617 action = X_("Goto End");
3620 action = X_("Loop");
3623 action = X_("Play Selection");
3626 action = X_("Record");
3636 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3644 ARDOUR_UI::TransportControllable::get_value (void) const
3663 case ShuttleControl:
3673 ARDOUR_UI::TransportControllable::set_id (const string& str)
3679 ARDOUR_UI::setup_profile ()
3681 if (gdk_screen_width() < 1200) {
3682 Profile->set_small_screen ();
3686 if (getenv ("ARDOUR_SAE")) {
3687 Profile->set_sae ();
3688 Profile->set_single_package ();
3693 ARDOUR_UI::toggle_translations ()
3695 using namespace Glib;
3697 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3699 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3702 string i18n_killer = ARDOUR::translation_kill_path();
3704 bool already_enabled = !ARDOUR::translations_are_disabled ();
3706 if (ract->get_active ()) {
3707 /* we don't care about errors */
3708 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3711 /* we don't care about errors */
3712 unlink (i18n_killer.c_str());
3715 if (already_enabled != ract->get_active()) {
3716 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3718 Gtk::MESSAGE_WARNING,
3720 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3721 win.set_position (Gtk::WIN_POS_CENTER);
3729 /** Add a window proxy to our list, so that its state will be saved.
3730 * This call also causes the window to be created and opened if its
3731 * state was saved as `visible'.
3734 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3736 _window_proxies.push_back (p);
3740 /** Remove a window proxy from our list. Must be called if a WindowProxy
3741 * is deleted, to prevent hanging pointers.
3744 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3746 _window_proxies.remove (p);
3750 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3752 MissingFileDialog dialog (s, str, type);
3757 int result = dialog.run ();
3764 return 1; // quit entire session load
3767 result = dialog.get_action ();
3773 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3775 AmbiguousFileDialog dialog (file, hits);
3781 return dialog.get_which ();