2 Copyright (C) 1999-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #define __STDC_FORMAT_MACROS 1
34 #include <sys/resource.h>
36 #include <gtkmm/messagedialog.h>
37 #include <gtkmm/accelmap.h>
39 #include "pbd/error.h"
40 #include "pbd/basename.h"
41 #include "pbd/compose.h"
42 #include "pbd/failed_constructor.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/openuri.h"
46 #include "pbd/file_utils.h"
48 #include "gtkmm2ext/application.h"
49 #include "gtkmm2ext/gtk_ui.h"
50 #include "gtkmm2ext/utils.h"
51 #include "gtkmm2ext/click_box.h"
52 #include "gtkmm2ext/fastmeter.h"
53 #include "gtkmm2ext/popup.h"
54 #include "gtkmm2ext/window_title.h"
56 #include "midi++/manager.h"
58 #include "ardour/ardour.h"
59 #include "ardour/callback.h"
60 #include "ardour/profile.h"
61 #include "ardour/session_directory.h"
62 #include "ardour/session_route.h"
63 #include "ardour/session_state_utils.h"
64 #include "ardour/session_utils.h"
65 #include "ardour/port.h"
66 #include "ardour/audioengine.h"
67 #include "ardour/playlist.h"
68 #include "ardour/utils.h"
69 #include "ardour/audio_diskstream.h"
70 #include "ardour/audiofilesource.h"
71 #include "ardour/recent_sessions.h"
72 #include "ardour/port.h"
73 #include "ardour/audio_track.h"
74 #include "ardour/midi_track.h"
75 #include "ardour/filesystem_paths.h"
76 #include "ardour/filename_extensions.h"
78 typedef uint64_t microseconds_t;
81 #include "ardour_ui.h"
82 #include "public_editor.h"
83 #include "audio_clock.h"
88 #include "add_route_dialog.h"
92 #include "gui_thread.h"
93 #include "theme_manager.h"
94 #include "bundle_manager.h"
95 #include "session_metadata_dialog.h"
96 #include "gain_meter.h"
97 #include "route_time_axis.h"
99 #include "engine_dialog.h"
100 #include "processor_box.h"
101 #include "time_axis_view_item.h"
102 #include "window_proxy.h"
103 #include "global_port_matrix.h"
104 #include "location_ui.h"
105 #include "missing_file_dialog.h"
109 using namespace ARDOUR;
111 using namespace Gtkmm2ext;
114 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
115 UIConfiguration *ARDOUR_UI::ui_config = 0;
117 sigc::signal<void,bool> ARDOUR_UI::Blink;
118 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
119 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
120 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
122 bool could_be_a_valid_path (const string& path);
124 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
126 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
128 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
129 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
130 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
131 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
135 preroll_button (_("pre\nroll")),
136 postroll_button (_("post\nroll")),
140 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
144 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
145 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
146 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
147 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
148 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
149 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
150 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
151 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
152 shuttle_controller_binding_proxy (shuttle_controllable),
154 roll_button (roll_controllable),
155 stop_button (stop_controllable),
156 goto_start_button (goto_start_controllable),
157 goto_end_button (goto_end_controllable),
158 auto_loop_button (auto_loop_controllable),
159 play_selection_button (play_selection_controllable),
160 rec_button (rec_controllable),
162 shuttle_units_button (_("% ")),
164 punch_in_button (_("Punch In")),
165 punch_out_button (_("Punch Out")),
166 auto_return_button (_("Auto Return")),
167 auto_play_button (_("Auto Play")),
168 auto_input_button (_("Auto Input")),
169 click_button (_("Click")),
170 time_master_button (_("time\nmaster")),
172 auditioning_alert_button (_("AUDITION")),
173 solo_alert_button (_("SOLO")),
174 error_log_button (_("Errors"))
177 using namespace Gtk::Menu_Helpers;
183 // _auto_display_errors = false;
185 * This was commented out as it wasn't defined
186 * in A3 IIRC. If this is not needed it should
187 * be completely removed.
195 if (theArdourUI == 0) {
199 ui_config = new UIConfiguration();
200 theme_manager = new ThemeManager();
206 _session_is_new = false;
207 big_clock_window = 0;
208 big_clock_height = 0;
209 big_clock_resize_in_progress = false;
210 session_selector_window = 0;
211 last_key_press_time = 0;
212 _will_create_new_session_automatically = false;
213 add_route_dialog = 0;
215 rc_option_editor = 0;
216 session_option_editor = 0;
218 open_session_selector = 0;
219 have_configure_timeout = false;
220 have_disk_speed_dialog_displayed = false;
221 session_loaded = false;
222 last_speed_displayed = -1.0f;
223 ignore_dual_punch = false;
224 original_big_clock_width = -1;
225 original_big_clock_height = -1;
226 original_big_clock_font_size = 0;
228 roll_button.unset_flags (Gtk::CAN_FOCUS);
229 stop_button.unset_flags (Gtk::CAN_FOCUS);
230 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
231 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
232 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
233 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
234 rec_button.unset_flags (Gtk::CAN_FOCUS);
236 last_configure_time= 0;
238 shuttle_grabbed = false;
240 shuttle_max_speed = 8.0f;
242 shuttle_style_menu = 0;
243 shuttle_unit_menu = 0;
245 // We do not have jack linked in yet so;
247 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
249 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
250 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
252 /* handle dialog requests */
254 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
256 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
258 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
260 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
262 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
264 /* handle requests to quit (coming from JACK session) */
266 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
268 /* handle requests to deal with missing files */
270 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
272 /* lets get this party started */
275 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
276 throw failed_constructor ();
279 setup_gtk_ardour_enums ();
282 GainMeter::setup_slider_pix ();
283 RouteTimeAxisView::setup_slider_pix ();
284 SendProcessorEntry::setup_slider_pix ();
285 SessionEvent::create_per_thread_pool ("GUI", 512);
287 } catch (failed_constructor& err) {
288 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
293 /* we like keyboards */
295 keyboard = new ArdourKeyboard(*this);
297 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
299 keyboard->set_state (*node, Stateful::loading_state_version);
304 TimeAxisViewItem::set_constant_heights ();
306 /* The following must happen after ARDOUR::init() so that Config is set up */
308 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
309 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
311 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
312 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
313 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
314 Config->extra_xml (X_("UI")),
315 string_compose ("toggle-%1-connection-manager", (*i).to_string())
321 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
322 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
327 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
329 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
332 _startup = new ArdourStartup ();
334 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
336 if (audio_setup && _startup->engine_control()) {
337 _startup->engine_control()->set_state (*audio_setup);
340 _startup->set_new_only (should_be_new);
341 if (!load_template.empty()) {
342 _startup->set_load_template( load_template );
344 _startup->present ();
350 switch (_startup->response()) {
359 ARDOUR_UI::create_engine ()
361 // this gets called every time by new_session()
367 loading_message (_("Starting audio engine"));
370 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
377 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
378 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
379 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
381 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
383 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
391 ARDOUR_UI::post_engine ()
393 /* Things to be done once we create the AudioEngine
396 ARDOUR::init_post_engine ();
398 ActionManager::init ();
401 if (setup_windows ()) {
402 throw failed_constructor ();
405 check_memory_locking();
407 /* this is the first point at which all the keybindings are available */
409 if (ARDOUR_COMMAND_LINE::show_key_actions) {
410 vector<string> names;
411 vector<string> paths;
413 vector<AccelKey> bindings;
415 ActionManager::get_all_actions (names, paths, keys, bindings);
417 vector<string>::iterator n;
418 vector<string>::iterator k;
419 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
420 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
426 blink_timeout_tag = -1;
428 /* this being a GUI and all, we want peakfiles */
430 AudioFileSource::set_build_peakfiles (true);
431 AudioFileSource::set_build_missing_peakfiles (true);
433 /* set default clock modes */
435 if (Profile->get_sae()) {
436 primary_clock.set_mode (AudioClock::BBT);
437 secondary_clock.set_mode (AudioClock::MinSec);
439 primary_clock.set_mode (AudioClock::Timecode);
440 secondary_clock.set_mode (AudioClock::BBT);
443 /* start the time-of-day-clock */
446 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
447 update_wall_clock ();
448 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
451 update_disk_space ();
453 update_sample_rate (engine->frame_rate());
455 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
456 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
457 Config->map_parameters (pc);
459 /* now start and maybe save state */
461 if (do_engine_start () == 0) {
462 if (_session && _session_is_new) {
463 /* we need to retain initial visual
464 settings for a new session
466 _session->save_state ("");
471 ARDOUR_UI::~ARDOUR_UI ()
476 delete add_route_dialog;
480 ARDOUR_UI::pop_back_splash ()
482 if (Splash::instance()) {
483 // Splash::instance()->pop_back();
484 Splash::instance()->hide ();
489 ARDOUR_UI::configure_timeout ()
491 if (last_configure_time == 0) {
492 /* no configure events yet */
496 /* force a gap of 0.5 seconds since the last configure event
499 if (get_microseconds() - last_configure_time < 500000) {
502 have_configure_timeout = false;
503 cerr << "config event-driven save\n";
504 save_ardour_state ();
510 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
512 if (have_configure_timeout) {
513 last_configure_time = get_microseconds();
515 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
516 have_configure_timeout = true;
523 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
525 const XMLProperty* prop;
527 if ((prop = node.property ("roll")) != 0) {
528 roll_controllable->set_id (prop->value());
530 if ((prop = node.property ("stop")) != 0) {
531 stop_controllable->set_id (prop->value());
533 if ((prop = node.property ("goto-start")) != 0) {
534 goto_start_controllable->set_id (prop->value());
536 if ((prop = node.property ("goto-end")) != 0) {
537 goto_end_controllable->set_id (prop->value());
539 if ((prop = node.property ("auto-loop")) != 0) {
540 auto_loop_controllable->set_id (prop->value());
542 if ((prop = node.property ("play-selection")) != 0) {
543 play_selection_controllable->set_id (prop->value());
545 if ((prop = node.property ("rec")) != 0) {
546 rec_controllable->set_id (prop->value());
548 if ((prop = node.property ("shuttle")) != 0) {
549 shuttle_controllable->set_id (prop->value());
554 ARDOUR_UI::get_transport_controllable_state ()
556 XMLNode* node = new XMLNode(X_("TransportControllables"));
559 roll_controllable->id().print (buf, sizeof (buf));
560 node->add_property (X_("roll"), buf);
561 stop_controllable->id().print (buf, sizeof (buf));
562 node->add_property (X_("stop"), buf);
563 goto_start_controllable->id().print (buf, sizeof (buf));
564 node->add_property (X_("goto_start"), buf);
565 goto_end_controllable->id().print (buf, sizeof (buf));
566 node->add_property (X_("goto_end"), buf);
567 auto_loop_controllable->id().print (buf, sizeof (buf));
568 node->add_property (X_("auto_loop"), buf);
569 play_selection_controllable->id().print (buf, sizeof (buf));
570 node->add_property (X_("play_selection"), buf);
571 rec_controllable->id().print (buf, sizeof (buf));
572 node->add_property (X_("rec"), buf);
573 shuttle_controllable->id().print (buf, sizeof (buf));
574 node->add_property (X_("shuttle"), buf);
581 ARDOUR_UI::autosave_session ()
583 if (g_main_depth() > 1) {
584 /* inside a recursive main loop,
585 give up because we may not be able to
591 if (!Config->get_periodic_safety_backups()) {
596 _session->maybe_write_autosave();
603 ARDOUR_UI::update_autosave ()
605 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
607 if (_session && _session->dirty()) {
608 if (_autosave_connection.connected()) {
609 _autosave_connection.disconnect();
612 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
613 Config->get_periodic_safety_backup_interval() * 1000);
616 if (_autosave_connection.connected()) {
617 _autosave_connection.disconnect();
623 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
627 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
629 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
632 MessageDialog win (title,
638 win.set_secondary_text(_("There are several possible reasons:\n\
640 1) You requested audio parameters that are not supported..\n\
641 2) JACK is running as another user.\n\
643 Please consider the possibilities, and perhaps try different parameters."));
645 win.set_secondary_text(_("There are several possible reasons:\n\
647 1) JACK is not running.\n\
648 2) JACK is running as another user, perhaps root.\n\
649 3) There is already another client called \"ardour\".\n\
651 Please consider the possibilities, and perhaps (re)start JACK."));
655 win.set_transient_for (*toplevel);
659 win.add_button (Stock::OK, RESPONSE_CLOSE);
661 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
664 win.set_default_response (RESPONSE_CLOSE);
667 win.set_position (Gtk::WIN_POS_CENTER);
670 /* we just don't care about the result, but we want to block */
676 ARDOUR_UI::startup ()
678 Application* app = Application::instance ();
680 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
681 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
684 call_the_mothership (VERSIONSTRING);
689 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
695 goto_editor_window ();
697 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
698 to be opened on top of the editor window that goto_editor_window() just opened.
700 add_window_proxy (location_ui);
701 add_window_proxy (big_clock_window);
702 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
703 add_window_proxy (_global_port_matrix[*i]);
706 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
710 ARDOUR_UI::no_memory_warning ()
712 XMLNode node (X_("no-memory-warning"));
713 Config->add_instant_xml (node);
717 ARDOUR_UI::check_memory_locking ()
720 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
724 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
726 if (engine->is_realtime() && memory_warning_node == 0) {
728 struct rlimit limits;
730 long pages, page_size;
732 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
735 ram = (int64_t) pages * (int64_t) page_size;
738 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
742 if (limits.rlim_cur != RLIM_INFINITY) {
744 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
747 MessageDialog msg (string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
748 "This might cause %1 to run out of memory before your system "
749 "runs out of memory. \n\n"
750 "You can view the memory limit with 'ulimit -l', "
751 "and it is normally controlled by /etc/security/limits.conf"),
752 PROGRAM_NAME).c_str());
754 VBox* vbox = msg.get_vbox();
756 CheckButton cb (_("Do not show this window again"));
758 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
760 hbox.pack_start (cb, true, false);
761 vbox->pack_start (hbox);
768 editor->ensure_float (msg);
778 ARDOUR_UI::queue_finish ()
780 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
784 ARDOUR_UI::idle_finish ()
787 return false; /* do not call again */
796 if (_session->transport_rolling() && (++tries < 8)) {
797 _session->request_stop (false, true);
801 if (_session->dirty()) {
802 switch (ask_about_saving_session(_("quit"))) {
807 /* use the default name */
808 if (save_state_canfail ("")) {
809 /* failed - don't quit */
810 MessageDialog msg (*editor,
812 Ardour was unable to save your session.\n\n\
813 If you still wish to quit, please use the\n\n\
814 \"Just quit\" option."));
825 second_connection.disconnect ();
826 point_one_second_connection.disconnect ();
827 point_oh_five_second_connection.disconnect ();
828 point_zero_one_second_connection.disconnect();
831 /* Save state before deleting the session, as that causes some
832 windows to be destroyed before their visible state can be
835 save_ardour_state ();
838 // _session->set_deletion_in_progress ();
839 _session->set_clean ();
840 _session->remove_pending_capture_state ();
845 ArdourDialog::close_all_dialogs ();
851 ARDOUR_UI::ask_about_saving_session (const string & what)
853 ArdourDialog window (_("Unsaved Session"));
854 Gtk::HBox dhbox; // the hbox for the image and text
855 Gtk::Label prompt_label;
856 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
860 msg = string_compose(_("Don't %1"), what);
861 window.add_button (msg, RESPONSE_REJECT);
862 msg = string_compose(_("Just %1"), what);
863 window.add_button (msg, RESPONSE_APPLY);
864 msg = string_compose(_("Save and %1"), what);
865 window.add_button (msg, RESPONSE_ACCEPT);
867 window.set_default_response (RESPONSE_ACCEPT);
869 Gtk::Button noquit_button (msg);
870 noquit_button.set_name ("EditorGTKButton");
875 if (_session->snap_name() == _session->name()) {
878 type = _("snapshot");
880 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?"),
881 type, _session->snap_name());
883 prompt_label.set_text (prompt);
884 prompt_label.set_name (X_("PrompterLabel"));
885 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
887 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
888 dhbox.set_homogeneous (false);
889 dhbox.pack_start (*dimage, false, false, 5);
890 dhbox.pack_start (prompt_label, true, false, 5);
891 window.get_vbox()->pack_start (dhbox);
893 window.set_name (_("Prompter"));
894 window.set_position (Gtk::WIN_POS_MOUSE);
895 window.set_modal (true);
896 window.set_resizable (false);
902 window.set_keep_above (true);
905 ResponseType r = (ResponseType) window.run();
910 case RESPONSE_ACCEPT: // save and get out of here
912 case RESPONSE_APPLY: // get out of here
922 ARDOUR_UI::every_second ()
925 update_buffer_load ();
926 update_disk_space ();
931 ARDOUR_UI::every_point_one_seconds ()
933 update_speed_display ();
934 RapidScreenUpdate(); /* EMIT_SIGNAL */
939 ARDOUR_UI::every_point_zero_one_seconds ()
941 // august 2007: actual update frequency: 40Hz, not 100Hz
943 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
948 ARDOUR_UI::update_sample_rate (nframes_t)
952 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
954 if (!engine->connected()) {
956 snprintf (buf, sizeof (buf), _("disconnected"));
960 nframes_t rate = engine->frame_rate();
962 if (fmod (rate, 1000.0) != 0.0) {
963 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
964 (float) rate/1000.0f,
965 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
967 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
969 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
973 sample_rate_label.set_text (buf);
977 ARDOUR_UI::update_cpu_load ()
980 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
981 cpu_load_label.set_text (buf);
985 ARDOUR_UI::update_buffer_load ()
991 c = _session->capture_load ();
992 p = _session->playback_load ();
994 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
995 _session->playback_load(), _session->capture_load());
996 buffer_load_label.set_text (buf);
998 buffer_load_label.set_text ("");
1003 ARDOUR_UI::count_recenabled_streams (Route& route)
1005 Track* track = dynamic_cast<Track*>(&route);
1006 if (track && track->record_enabled()) {
1007 rec_enabled_streams += track->n_inputs().n_total();
1012 ARDOUR_UI::update_disk_space()
1014 if (_session == 0) {
1018 framecnt_t frames = _session->available_capture_duration();
1020 nframes_t fr = _session->frame_rate();
1022 if (frames == max_framecnt) {
1023 strcpy (buf, _("Disk: 24hrs+"));
1025 rec_enabled_streams = 0;
1026 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1028 if (rec_enabled_streams) {
1029 frames /= rec_enabled_streams;
1036 hrs = frames / (fr * 3600);
1037 frames -= hrs * fr * 3600;
1038 mins = frames / (fr * 60);
1039 frames -= mins * fr * 60;
1042 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1045 disk_space_label.set_text (buf);
1047 // An attempt to make the disk space label flash red when space has run out.
1049 if (frames < fr * 60 * 5) {
1050 /* disk_space_box.style ("disk_space_label_empty"); */
1052 /* disk_space_box.style ("disk_space_label"); */
1058 ARDOUR_UI::update_wall_clock ()
1065 tm_now = localtime (&now);
1067 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1068 wall_clock_label.set_text (buf);
1074 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1076 session_popup_menu->popup (0, 0);
1081 ARDOUR_UI::redisplay_recent_sessions ()
1083 std::vector<sys::path> session_directories;
1084 RecentSessionsSorter cmp;
1086 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1087 recent_session_model->clear ();
1089 ARDOUR::RecentSessions rs;
1090 ARDOUR::read_recent_sessions (rs);
1093 recent_session_display.set_model (recent_session_model);
1097 // sort them alphabetically
1098 sort (rs.begin(), rs.end(), cmp);
1100 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1101 session_directories.push_back ((*i).second);
1104 for (vector<sys::path>::const_iterator i = session_directories.begin();
1105 i != session_directories.end(); ++i)
1107 std::vector<sys::path> state_file_paths;
1109 // now get available states for this session
1111 get_state_files_in_directory (*i, state_file_paths);
1113 vector<string*>* states;
1114 vector<const gchar*> item;
1115 string fullpath = (*i).to_string();
1117 /* remove any trailing / */
1119 if (fullpath[fullpath.length()-1] == '/') {
1120 fullpath = fullpath.substr (0, fullpath.length()-1);
1123 /* check whether session still exists */
1124 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1125 /* session doesn't exist */
1126 cerr << "skipping non-existent session " << fullpath << endl;
1130 /* now get available states for this session */
1132 if ((states = Session::possible_states (fullpath)) == 0) {
1133 /* no state file? */
1137 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1139 Gtk::TreeModel::Row row = *(recent_session_model->append());
1141 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1142 row[recent_session_columns.fullpath] = fullpath;
1144 if (state_file_names.size() > 1) {
1148 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1149 i2 != state_file_names.end(); ++i2)
1152 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1154 child_row[recent_session_columns.visible_name] = *i2;
1155 child_row[recent_session_columns.fullpath] = fullpath;
1160 recent_session_display.set_model (recent_session_model);
1164 ARDOUR_UI::build_session_selector ()
1166 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1168 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1170 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1171 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1172 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1173 recent_session_model = TreeStore::create (recent_session_columns);
1174 recent_session_display.set_model (recent_session_model);
1175 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1176 recent_session_display.set_headers_visible (false);
1177 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1178 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1180 scroller->add (recent_session_display);
1181 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1183 session_selector_window->set_name ("SessionSelectorWindow");
1184 session_selector_window->set_size_request (200, 400);
1185 session_selector_window->get_vbox()->pack_start (*scroller);
1187 recent_session_display.show();
1189 //session_selector_window->get_vbox()->show();
1193 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1195 session_selector_window->response (RESPONSE_ACCEPT);
1199 ARDOUR_UI::open_recent_session ()
1201 bool can_return = (_session != 0);
1203 if (session_selector_window == 0) {
1204 build_session_selector ();
1207 redisplay_recent_sessions ();
1211 session_selector_window->set_position (WIN_POS_MOUSE);
1213 ResponseType r = (ResponseType) session_selector_window->run ();
1216 case RESPONSE_ACCEPT:
1220 session_selector_window->hide();
1227 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1231 session_selector_window->hide();
1233 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1235 if (i == recent_session_model->children().end()) {
1239 std::string path = (*i)[recent_session_columns.fullpath];
1240 std::string state = (*i)[recent_session_columns.visible_name];
1242 _session_is_new = false;
1244 if (load_session (path, state) == 0) {
1253 ARDOUR_UI::check_audioengine ()
1256 if (!engine->connected()) {
1257 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1258 "You cannot open or close sessions in this condition"),
1271 ARDOUR_UI::open_session ()
1273 if (!check_audioengine()) {
1278 /* popup selector window */
1280 if (open_session_selector == 0) {
1282 /* ardour sessions are folders */
1284 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1285 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1286 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1287 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1289 FileFilter session_filter;
1290 session_filter.add_pattern ("*.ardour");
1291 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1292 open_session_selector->add_filter (session_filter);
1293 open_session_selector->set_filter (session_filter);
1296 int response = open_session_selector->run();
1297 open_session_selector->hide ();
1300 case RESPONSE_ACCEPT:
1303 open_session_selector->hide();
1307 open_session_selector->hide();
1308 string session_path = open_session_selector->get_filename();
1312 if (session_path.length() > 0) {
1313 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1314 _session_is_new = isnew;
1315 load_session (path, name);
1322 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1324 list<boost::shared_ptr<MidiTrack> > tracks;
1326 if (_session == 0) {
1327 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1334 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1336 if (tracks.size() != how_many) {
1337 if (how_many == 1) {
1338 error << _("could not create a new midi track") << endmsg;
1340 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1344 if ((route = _session->new_midi_route ()) == 0) {
1345 error << _("could not create new midi bus") << endmsg;
1351 MessageDialog msg (*editor,
1352 string_compose (_("There are insufficient JACK ports available\n\
1353 to create a new track or bus.\n\
1354 You should save %1, exit and\n\
1355 restart JACK with more ports."), PROGRAM_NAME));
1362 ARDOUR_UI::session_add_audio_route (bool track, bool aux, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, RouteGroup* route_group, uint32_t how_many)
1364 list<boost::shared_ptr<AudioTrack> > tracks;
1367 if (_session == 0) {
1368 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1374 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1376 if (tracks.size() != how_many) {
1377 if (how_many == 1) {
1378 error << _("could not create a new audio track") << endmsg;
1380 error << string_compose (_("could only create %1 of %2 new audio %3"),
1381 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1387 routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1389 if (routes.size() != how_many) {
1390 if (how_many == 1) {
1391 error << _("could not create a new audio track") << endmsg;
1393 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1400 MessageDialog msg (*editor,
1401 string_compose (_("There are insufficient JACK ports available\n\
1402 to create a new track or bus.\n\
1403 You should save %1, exit and\n\
1404 restart JACK with more ports."), PROGRAM_NAME));
1411 ARDOUR_UI::do_transport_locate (nframes_t new_position, bool with_roll)
1413 nframes_t _preroll = 0;
1416 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1417 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1419 if (new_position > _preroll) {
1420 new_position -= _preroll;
1425 _session->request_locate (new_position, with_roll);
1430 ARDOUR_UI::transport_goto_start ()
1433 _session->goto_start();
1435 /* force displayed area in editor to start no matter
1436 what "follow playhead" setting is.
1440 editor->center_screen (_session->current_start_frame ());
1446 ARDOUR_UI::transport_goto_zero ()
1449 _session->request_locate (0);
1451 /* force displayed area in editor to start no matter
1452 what "follow playhead" setting is.
1456 editor->reset_x_origin (0);
1462 ARDOUR_UI::transport_goto_wallclock ()
1464 if (_session && editor) {
1471 localtime_r (&now, &tmnow);
1473 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1474 frames += tmnow.tm_min * (60 * _session->frame_rate());
1475 frames += tmnow.tm_sec * _session->frame_rate();
1477 _session->request_locate (frames, _session->transport_rolling ());
1479 /* force displayed area in editor to start no matter
1480 what "follow playhead" setting is.
1484 editor->center_screen (frames);
1490 ARDOUR_UI::transport_goto_end ()
1493 nframes_t const frame = _session->current_end_frame();
1494 _session->request_locate (frame);
1496 /* force displayed area in editor to start no matter
1497 what "follow playhead" setting is.
1501 editor->center_screen (frame);
1507 ARDOUR_UI::transport_stop ()
1513 if (_session->is_auditioning()) {
1514 _session->cancel_audition ();
1518 _session->request_stop (false, true);
1522 ARDOUR_UI::transport_stop_and_forget_capture ()
1525 _session->request_stop (true, true);
1530 ARDOUR_UI::remove_last_capture()
1533 editor->remove_last_capture();
1538 ARDOUR_UI::transport_record (bool roll)
1542 switch (_session->record_status()) {
1543 case Session::Disabled:
1544 if (_session->ntracks() == 0) {
1545 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1549 _session->maybe_enable_record ();
1554 case Session::Recording:
1556 _session->request_stop();
1558 _session->disable_record (false, true);
1562 case Session::Enabled:
1563 _session->disable_record (false, true);
1566 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1570 ARDOUR_UI::transport_roll ()
1576 if (_session->is_auditioning()) {
1580 if (_session->config.get_external_sync()) {
1581 switch (_session->config.get_sync_source()) {
1585 /* transport controlled by the master */
1590 bool rolling = _session->transport_rolling();
1592 if (_session->get_play_loop()) {
1593 /* XXX it is not possible to just leave seamless loop and keep
1594 playing at present (nov 4th 2009)
1596 if (!Config->get_seamless_loop()) {
1597 _session->request_play_loop (false, true);
1599 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1600 /* stop playing a range if we currently are */
1601 _session->request_play_range (0, true);
1604 if (join_play_range_button.get_active()) {
1605 _session->request_play_range (&editor->get_selection().time, true);
1609 _session->request_transport_speed (1.0f);
1614 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1621 if (_session->is_auditioning()) {
1622 _session->cancel_audition ();
1626 if (_session->config.get_external_sync()) {
1627 switch (_session->config.get_sync_source()) {
1631 /* transport controlled by the master */
1636 bool rolling = _session->transport_rolling();
1637 bool affect_transport = true;
1639 if (rolling && roll_out_of_bounded_mode) {
1640 /* drop out of loop/range playback but leave transport rolling */
1641 if (_session->get_play_loop()) {
1642 if (Config->get_seamless_loop()) {
1643 /* the disk buffers contain copies of the loop - we can't
1644 just keep playing, so stop the transport. the user
1645 can restart as they wish.
1647 affect_transport = true;
1649 /* disk buffers are normal, so we can keep playing */
1650 affect_transport = false;
1652 _session->request_play_loop (false, true);
1653 } else if (_session->get_play_range ()) {
1654 affect_transport = false;
1655 _session->request_play_range (0, true);
1659 if (affect_transport) {
1661 _session->request_stop (with_abort, true);
1663 if (join_play_range_button.get_active()) {
1664 _session->request_play_range (&editor->get_selection().time, true);
1667 _session->request_transport_speed (1.0f);
1673 ARDOUR_UI::toggle_session_auto_loop ()
1676 if (_session->get_play_loop()) {
1677 if (_session->transport_rolling()) {
1678 Location * looploc = _session->locations()->auto_loop_location();
1680 _session->request_locate (looploc->start(), true);
1683 _session->request_play_loop (false);
1686 Location * looploc = _session->locations()->auto_loop_location();
1688 _session->request_play_loop (true);
1695 ARDOUR_UI::transport_play_selection ()
1701 editor->play_selection ();
1705 ARDOUR_UI::transport_rewind (int option)
1707 float current_transport_speed;
1710 current_transport_speed = _session->transport_speed();
1712 if (current_transport_speed >= 0.0f) {
1715 _session->request_transport_speed (-1.0f);
1718 _session->request_transport_speed (-4.0f);
1721 _session->request_transport_speed (-0.5f);
1726 _session->request_transport_speed (current_transport_speed * 1.5f);
1732 ARDOUR_UI::transport_forward (int option)
1734 float current_transport_speed;
1737 current_transport_speed = _session->transport_speed();
1739 if (current_transport_speed <= 0.0f) {
1742 _session->request_transport_speed (1.0f);
1745 _session->request_transport_speed (4.0f);
1748 _session->request_transport_speed (0.5f);
1753 _session->request_transport_speed (current_transport_speed * 1.5f);
1760 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1762 if (_session == 0) {
1766 boost::shared_ptr<Route> r;
1768 if ((r = _session->route_by_remote_id (rid)) != 0) {
1772 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1773 t->set_record_enabled (!t->record_enabled(), this);
1776 if (_session == 0) {
1782 ARDOUR_UI::map_transport_state ()
1784 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1787 auto_loop_button.set_visual_state (0);
1788 play_selection_button.set_visual_state (0);
1789 roll_button.set_visual_state (0);
1790 stop_button.set_visual_state (1);
1794 float sp = _session->transport_speed();
1797 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1798 shuttle_box.queue_draw ();
1799 } else if (sp == 0.0f) {
1801 shuttle_box.queue_draw ();
1802 update_disk_space ();
1809 if (_session->get_play_range()) {
1811 play_selection_button.set_visual_state (1);
1812 roll_button.set_visual_state (0);
1813 auto_loop_button.set_visual_state (0);
1815 } else if (_session->get_play_loop ()) {
1817 auto_loop_button.set_visual_state (1);
1818 play_selection_button.set_visual_state (0);
1819 roll_button.set_visual_state (0);
1823 roll_button.set_visual_state (1);
1824 play_selection_button.set_visual_state (0);
1825 auto_loop_button.set_visual_state (0);
1828 if (join_play_range_button.get_active()) {
1829 /* light up both roll and play-selection if they are joined */
1830 roll_button.set_visual_state (1);
1831 play_selection_button.set_visual_state (1);
1834 stop_button.set_visual_state (0);
1838 stop_button.set_visual_state (1);
1839 roll_button.set_visual_state (0);
1840 play_selection_button.set_visual_state (0);
1841 auto_loop_button.set_visual_state (0);
1846 ARDOUR_UI::engine_stopped ()
1848 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1849 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1850 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1854 ARDOUR_UI::engine_running ()
1856 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1857 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1858 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1860 Glib::RefPtr<Action> action;
1861 const char* action_name = 0;
1863 switch (engine->frames_per_cycle()) {
1865 action_name = X_("JACKLatency32");
1868 action_name = X_("JACKLatency64");
1871 action_name = X_("JACKLatency128");
1874 action_name = X_("JACKLatency512");
1877 action_name = X_("JACKLatency1024");
1880 action_name = X_("JACKLatency2048");
1883 action_name = X_("JACKLatency4096");
1886 action_name = X_("JACKLatency8192");
1889 /* XXX can we do anything useful ? */
1895 action = ActionManager::get_action (X_("JACK"), action_name);
1898 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1899 ract->set_active ();
1905 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1907 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1908 /* we can't rely on the original string continuing to exist when we are called
1909 again in the GUI thread, so make a copy and note that we need to
1912 char *copy = strdup (reason);
1913 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1917 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1918 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1920 update_sample_rate (0);
1924 /* if the reason is a non-empty string, it means that the backend was shutdown
1925 rather than just Ardour.
1928 if (strlen (reason)) {
1929 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1931 msgstr = string_compose (_("\
1932 JACK has either been shutdown or it\n\
1933 disconnected %1 because %1\n\
1934 was not fast enough. Try to restart\n\
1935 JACK, reconnect and save the session."), PROGRAM_NAME);
1938 MessageDialog msg (*editor, msgstr);
1943 free ((char*) reason);
1948 ARDOUR_UI::do_engine_start ()
1956 error << _("Unable to start the session running")
1966 ARDOUR_UI::setup_theme ()
1968 theme_manager->setup_theme();
1972 ARDOUR_UI::update_clocks ()
1974 if (!editor || !editor->dragging_playhead()) {
1975 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1980 ARDOUR_UI::start_clocking ()
1982 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1986 ARDOUR_UI::stop_clocking ()
1988 clock_signal_connection.disconnect ();
1992 ARDOUR_UI::toggle_clocking ()
1995 if (clock_button.get_active()) {
2004 ARDOUR_UI::_blink (void *arg)
2007 ((ARDOUR_UI *) arg)->blink ();
2014 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2018 ARDOUR_UI::start_blinking ()
2020 /* Start the blink signal. Everybody with a blinking widget
2021 uses Blink to drive the widget's state.
2024 if (blink_timeout_tag < 0) {
2026 blink_timeout_tag = g_timeout_add (240, _blink, this);
2031 ARDOUR_UI::stop_blinking ()
2033 if (blink_timeout_tag >= 0) {
2034 g_source_remove (blink_timeout_tag);
2035 blink_timeout_tag = -1;
2040 /** Ask the user for the name of a new shapshot and then take it.
2044 ARDOUR_UI::snapshot_session (bool switch_to_it)
2046 ArdourPrompter prompter (true);
2049 prompter.set_name ("Prompter");
2050 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2051 prompter.set_title (_("Take Snapshot"));
2052 prompter.set_title (_("Take Snapshot"));
2053 prompter.set_prompt (_("Name of new snapshot"));
2055 if (!switch_to_it) {
2058 struct tm local_time;
2061 localtime_r (&n, &local_time);
2062 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2063 prompter.set_initial_text (timebuf);
2067 switch (prompter.run()) {
2068 case RESPONSE_ACCEPT:
2070 prompter.get_result (snapname);
2072 bool do_save = (snapname.length() != 0);
2075 if (snapname.find ('/') != string::npos) {
2076 MessageDialog msg (_("To ensure compatibility with various systems\n"
2077 "snapshot names may not contain a '/' character"));
2081 if (snapname.find ('\\') != string::npos) {
2082 MessageDialog msg (_("To ensure compatibility with various systems\n"
2083 "snapshot names may not contain a '\\' character"));
2089 vector<sys::path> p;
2090 get_state_files_in_directory (_session->session_directory().root_path(), p);
2091 vector<string> n = get_file_names_no_extension (p);
2092 if (find (n.begin(), n.end(), snapname) != n.end()) {
2094 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2095 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2096 confirm.get_vbox()->pack_start (m, true, true);
2097 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2098 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2099 confirm.show_all ();
2100 switch (confirm.run()) {
2101 case RESPONSE_CANCEL:
2107 save_state (snapname, switch_to_it);
2118 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2120 XMLNode* node = new XMLNode (X_("UI"));
2122 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2123 if (!(*i)->rc_configured()) {
2124 node->add_child_nocopy (*((*i)->get_state ()));
2128 _session->add_extra_xml (*node);
2130 save_state_canfail (name, switch_to_it);
2134 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2139 if (name.length() == 0) {
2140 name = _session->snap_name();
2143 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2147 cerr << "SS canfail\n";
2148 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2153 ARDOUR_UI::primary_clock_value_changed ()
2156 _session->request_locate (primary_clock.current_time ());
2161 ARDOUR_UI::big_clock_value_changed ()
2164 _session->request_locate (big_clock.current_time ());
2169 ARDOUR_UI::secondary_clock_value_changed ()
2172 _session->request_locate (secondary_clock.current_time ());
2177 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2179 if (_session == 0) {
2183 if (_session->step_editing()) {
2187 Session::RecordState const r = _session->record_status ();
2188 bool const h = _session->have_rec_enabled_track ();
2190 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2192 rec_button.set_visual_state (2);
2194 rec_button.set_visual_state (0);
2196 } else if (r == Session::Recording && h) {
2197 rec_button.set_visual_state (1);
2199 rec_button.set_visual_state (0);
2204 ARDOUR_UI::save_template ()
2206 ArdourPrompter prompter (true);
2209 if (!check_audioengine()) {
2213 prompter.set_name (X_("Prompter"));
2214 prompter.set_title (_("Save Mix Template"));
2215 prompter.set_prompt (_("Name for mix template:"));
2216 prompter.set_initial_text(_session->name() + _("-template"));
2217 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2219 switch (prompter.run()) {
2220 case RESPONSE_ACCEPT:
2221 prompter.get_result (name);
2223 if (name.length()) {
2224 _session->save_template (name);
2234 ARDOUR_UI::edit_metadata ()
2236 SessionMetadataEditor dialog;
2237 dialog.set_session (_session);
2238 editor->ensure_float (dialog);
2243 ARDOUR_UI::import_metadata ()
2245 SessionMetadataImporter dialog;
2246 dialog.set_session (_session);
2247 editor->ensure_float (dialog);
2252 ARDOUR_UI::fontconfig_dialog ()
2255 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2256 may not and it can take a while to build it. Warn them.
2259 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2261 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2262 MessageDialog msg (*_startup,
2263 string_compose (_("Welcome to %1.\n\n"
2264 "The program will take a bit longer to start up\n"
2265 "while the system fonts are checked.\n\n"
2266 "This will only be done once, and you will\n"
2267 "not see this message again\n"), PROGRAM_NAME),
2280 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2282 existing_session = false;
2284 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2285 session_path = cmdline_path;
2286 existing_session = true;
2287 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2288 session_path = Glib::path_get_dirname (string (cmdline_path));
2289 existing_session = true;
2291 /* it doesn't exist, assume the best */
2292 session_path = Glib::path_get_dirname (string (cmdline_path));
2295 session_name = basename_nosuffix (string (cmdline_path));
2299 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2301 /* when this is called, the backend audio system must be running */
2303 /* the main idea here is to deal with the fact that a cmdline argument for the session
2304 can be interpreted in different ways - it could be a directory or a file, and before
2305 we load, we need to know both the session directory and the snapshot (statefile) within it
2306 that we are supposed to use.
2309 if (session_name.length() == 0 || session_path.length() == 0) {
2313 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2315 std::string predicted_session_file;
2317 predicted_session_file = session_path;
2318 predicted_session_file += '/';
2319 predicted_session_file += session_name;
2320 predicted_session_file += ARDOUR::statefile_suffix;
2322 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2323 existing_session = true;
2326 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2328 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2329 /* existing .ardour file */
2330 existing_session = true;
2334 existing_session = false;
2337 /* lets just try to load it */
2339 if (create_engine ()) {
2340 backend_audio_error (false, _startup);
2344 return load_session (session_path, session_name);
2348 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2350 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2352 MessageDialog msg (str,
2354 Gtk::MESSAGE_WARNING,
2355 Gtk::BUTTONS_YES_NO,
2359 msg.set_name (X_("OpenExistingDialog"));
2360 msg.set_title (_("Open Existing Session"));
2361 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2362 msg.set_position (Gtk::WIN_POS_MOUSE);
2365 switch (msg.run()) {
2374 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2376 BusProfile bus_profile;
2378 if (Profile->get_sae()) {
2380 bus_profile.master_out_channels = 2;
2381 bus_profile.input_ac = AutoConnectPhysical;
2382 bus_profile.output_ac = AutoConnectMaster;
2383 bus_profile.requested_physical_in = 0; // use all available
2384 bus_profile.requested_physical_out = 0; // use all available
2388 /* get settings from advanced section of NSD */
2390 if (_startup->create_master_bus()) {
2391 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2393 bus_profile.master_out_channels = 0;
2396 if (_startup->connect_inputs()) {
2397 bus_profile.input_ac = AutoConnectPhysical;
2399 bus_profile.input_ac = AutoConnectOption (0);
2402 /// @todo some minor tweaks.
2404 bus_profile.output_ac = AutoConnectOption (0);
2406 if (_startup->connect_outputs ()) {
2407 if (_startup->connect_outs_to_master()) {
2408 bus_profile.output_ac = AutoConnectMaster;
2409 } else if (_startup->connect_outs_to_physical()) {
2410 bus_profile.output_ac = AutoConnectPhysical;
2414 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2415 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2418 if (build_session (session_path, session_name, bus_profile)) {
2426 ARDOUR_UI::idle_load (const std::string& path)
2429 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2430 /* /path/to/foo => /path/to/foo, foo */
2431 load_session (path, basename_nosuffix (path));
2433 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2434 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2438 ARDOUR_COMMAND_LINE::session_name = path;
2441 * new_session_dialog doens't exist in A3
2442 * Try to remove all references to it to
2443 * see if it will compile. NOTE: this will
2444 * likely cause a runtime issue is my somewhat
2448 //if (new_session_dialog) {
2451 /* make it break out of Dialog::run() and
2455 //new_session_dialog->response (1);
2461 ARDOUR_UI::end_loading_messages ()
2467 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2470 // splash->message (msg);
2474 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2476 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2478 string session_name;
2479 string session_path;
2480 string template_name;
2482 bool likely_new = false;
2484 if (! load_template.empty()) {
2485 should_be_new = true;
2486 template_name = load_template;
2491 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2493 /* if they named a specific statefile, use it, otherwise they are
2494 just giving a session folder, and we want to use it as is
2495 to find the session.
2498 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2499 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2501 session_path = ARDOUR_COMMAND_LINE::session_name;
2504 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2508 bool const apply = run_startup (should_be_new, load_template);
2511 if (quit_on_cancel) {
2518 /* if we run the startup dialog again, offer more than just "new session" */
2520 should_be_new = false;
2522 session_name = _startup->session_name (likely_new);
2524 /* this shouldn't happen, but we catch it just in case it does */
2526 if (session_name.empty()) {
2530 if (_startup->use_session_template()) {
2531 template_name = _startup->session_template_name();
2532 _session_is_new = true;
2535 if (session_name[0] == G_DIR_SEPARATOR ||
2536 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2537 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2539 /* absolute path or cwd-relative path specified for session name: infer session folder
2540 from what was given.
2543 session_path = Glib::path_get_dirname (session_name);
2544 session_name = Glib::path_get_basename (session_name);
2548 session_path = _startup->session_folder();
2550 if (session_name.find ('/') != string::npos) {
2551 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2552 "session names may not contain a '/' character"));
2554 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2558 if (session_name.find ('\\') != string::npos) {
2559 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2560 "session names may not contain a '\\' character"));
2562 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2568 if (create_engine ()) {
2572 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2576 std::string existing = Glib::build_filename (session_path, session_name);
2578 if (!ask_about_loading_existing_session (existing)) {
2579 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2584 _session_is_new = false;
2589 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2591 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2595 if (session_name.find ('/') != std::string::npos) {
2596 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2597 "session names may not contain a '/' character"));
2599 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2603 if (session_name.find ('\\') != std::string::npos) {
2604 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2605 "session names may not contain a '\\' character"));
2607 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2611 _session_is_new = true;
2614 if (likely_new && template_name.empty()) {
2616 ret = build_session_from_nsd (session_path, session_name);
2620 ret = load_session (session_path, session_name, template_name);
2621 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2622 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2632 ARDOUR_UI::close_session()
2634 if (!check_audioengine()) {
2638 if (unload_session (true)) {
2642 ARDOUR_COMMAND_LINE::session_name = "";
2644 if (get_session_parameters (true, false)) {
2648 goto_editor_window ();
2652 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2654 Session *new_session;
2658 session_loaded = false;
2660 if (!check_audioengine()) {
2664 unload_status = unload_session ();
2666 if (unload_status < 0) {
2668 } else if (unload_status > 0) {
2673 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2676 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2679 /* this one is special */
2681 catch (AudioEngine::PortRegistrationFailure& err) {
2683 MessageDialog msg (err.what(),
2686 Gtk::BUTTONS_CLOSE);
2688 msg.set_title (_("Port Registration Error"));
2689 msg.set_secondary_text (_("Click the Close button to try again."));
2690 msg.set_position (Gtk::WIN_POS_CENTER);
2694 int response = msg.run ();
2699 case RESPONSE_CANCEL:
2709 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2714 msg.set_title (_("Loading Error"));
2715 msg.set_secondary_text (_("Click the Refresh button to try again."));
2716 msg.add_button (Stock::REFRESH, 1);
2717 msg.set_position (Gtk::WIN_POS_CENTER);
2721 int response = msg.run ();
2735 /* Now the session been created, add the transport controls */
2736 new_session->add_controllable(roll_controllable);
2737 new_session->add_controllable(stop_controllable);
2738 new_session->add_controllable(goto_start_controllable);
2739 new_session->add_controllable(goto_end_controllable);
2740 new_session->add_controllable(auto_loop_controllable);
2741 new_session->add_controllable(play_selection_controllable);
2742 new_session->add_controllable(rec_controllable);
2744 set_session (new_session);
2746 session_loaded = true;
2748 goto_editor_window ();
2751 _session->set_clean ();
2762 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2764 Session *new_session;
2767 if (!check_audioengine()) {
2771 session_loaded = false;
2773 x = unload_session ();
2781 _session_is_new = true;
2784 new_session = new Session (*engine, path, snap_name, &bus_profile);
2789 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2795 /* Give the new session the default GUI state, if such things exist */
2798 n = Config->instant_xml (X_("Editor"));
2800 new_session->add_instant_xml (*n, false);
2802 n = Config->instant_xml (X_("Mixer"));
2804 new_session->add_instant_xml (*n, false);
2807 set_session (new_session);
2809 session_loaded = true;
2811 new_session->save_state(new_session->name());
2817 ARDOUR_UI::launch_chat ()
2820 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2822 open_uri("http://webchat.freenode.net/?channels=ardour");
2827 ARDOUR_UI::show_about ()
2831 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2834 about->set_transient_for(*editor);
2839 ARDOUR_UI::launch_manual ()
2841 PBD::open_uri("http://ardour.org/flossmanual");
2845 ARDOUR_UI::launch_reference ()
2847 PBD::open_uri("http://ardour.org/refmanual");
2851 ARDOUR_UI::hide_about ()
2854 about->get_window()->set_cursor ();
2860 ARDOUR_UI::about_signal_response (int /*response*/)
2866 ARDOUR_UI::show_splash ()
2870 splash = new Splash;
2878 splash->queue_draw ();
2879 splash->get_window()->process_updates (true);
2884 ARDOUR_UI::hide_splash ()
2892 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2893 const string& plural_msg, const string& singular_msg)
2897 removed = rep.paths.size();
2900 MessageDialog msgd (*editor,
2901 _("No audio files were ready for cleanup"),
2904 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2905 msgd.set_secondary_text (_("If this seems suprising, \n\
2906 check for any existing snapshots.\n\
2907 These may still include regions that\n\
2908 require some unused files to continue to exist."));
2914 ArdourDialog results (_("Clean-up"), true, false);
2916 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2917 CleanupResultsModelColumns() {
2921 Gtk::TreeModelColumn<std::string> visible_name;
2922 Gtk::TreeModelColumn<std::string> fullpath;
2926 CleanupResultsModelColumns results_columns;
2927 Glib::RefPtr<Gtk::ListStore> results_model;
2928 Gtk::TreeView results_display;
2930 results_model = ListStore::create (results_columns);
2931 results_display.set_model (results_model);
2932 results_display.append_column (list_title, results_columns.visible_name);
2934 results_display.set_name ("CleanupResultsList");
2935 results_display.set_headers_visible (true);
2936 results_display.set_headers_clickable (false);
2937 results_display.set_reorderable (false);
2939 Gtk::ScrolledWindow list_scroller;
2942 Gtk::HBox dhbox; // the hbox for the image and text
2943 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2944 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2946 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2948 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2951 %1 - number of files removed
2952 %2 - location of "dead_sounds"
2953 %3 - size of files affected
2954 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2957 const char* bprefix;
2958 double space_adjusted = 0;
2960 if (rep.space < 100000.0f) {
2961 bprefix = X_("kilo");
2962 } else if (rep.space < 1000000.0f * 1000) {
2963 bprefix = X_("mega");
2964 space_adjusted = truncf((float)rep.space / 1000.0);
2966 bprefix = X_("giga");
2967 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2971 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2973 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2976 dhbox.pack_start (*dimage, true, false, 5);
2977 dhbox.pack_start (txt, true, false, 5);
2979 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2980 TreeModel::Row row = *(results_model->append());
2981 row[results_columns.visible_name] = *i;
2982 row[results_columns.fullpath] = *i;
2985 list_scroller.add (results_display);
2986 list_scroller.set_size_request (-1, 150);
2987 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2989 dvbox.pack_start (dhbox, true, false, 5);
2990 dvbox.pack_start (list_scroller, true, false, 5);
2991 ddhbox.pack_start (dvbox, true, false, 5);
2993 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2994 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2995 results.set_default_response (RESPONSE_CLOSE);
2996 results.set_position (Gtk::WIN_POS_MOUSE);
2998 results_display.show();
2999 list_scroller.show();
3006 //results.get_vbox()->show();
3007 results.set_resizable (false);
3014 ARDOUR_UI::cleanup ()
3016 if (_session == 0) {
3017 /* shouldn't happen: menu item is insensitive */
3022 MessageDialog checker (_("Are you sure you want to cleanup?"),
3024 Gtk::MESSAGE_QUESTION,
3025 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3027 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3028 ALL undo/redo information will be lost if you cleanup.\n\
3029 After cleanup, unused audio files will be moved to a \
3030 \"dead sounds\" location."));
3032 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3033 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3034 checker.set_default_response (RESPONSE_CANCEL);
3036 checker.set_name (_("CleanupDialog"));
3037 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3038 checker.set_position (Gtk::WIN_POS_MOUSE);
3040 switch (checker.run()) {
3041 case RESPONSE_ACCEPT:
3047 ARDOUR::CleanupReport rep;
3049 editor->prepare_for_cleanup ();
3051 /* do not allow flush until a session is reloaded */
3053 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3055 act->set_sensitive (false);
3058 if (_session->cleanup_sources (rep)) {
3059 editor->finish_cleanup ();
3063 editor->finish_cleanup ();
3066 display_cleanup_results (rep,
3069 The following %1 files were not in use and \n\
3070 have been moved to:\n\
3072 Flushing the wastebasket will \n\
3073 release an additional\n\
3074 %3 %4bytes of disk space.\n"),
3076 The following file was not in use and \n \
3077 has been moved to:\n \
3079 Flushing the wastebasket will \n\
3080 release an additional\n\
3081 %3 %4bytes of disk space.\n"
3087 ARDOUR_UI::flush_trash ()
3089 if (_session == 0) {
3090 /* shouldn't happen: menu item is insensitive */
3094 ARDOUR::CleanupReport rep;
3096 if (_session->cleanup_trash_sources (rep)) {
3100 display_cleanup_results (rep,
3102 _("The following %1 files were deleted from\n\
3104 releasing %3 %4bytes of disk space"),
3105 _("The following file was deleted from\n\
3107 releasing %3 %4bytes of disk space"));
3111 ARDOUR_UI::add_route (Gtk::Window* float_window)
3119 if (add_route_dialog == 0) {
3120 add_route_dialog = new AddRouteDialog (_session);
3122 add_route_dialog->set_transient_for (*float_window);
3126 if (add_route_dialog->is_visible()) {
3127 /* we're already doing this */
3131 ResponseType r = (ResponseType) add_route_dialog->run ();
3133 add_route_dialog->hide();
3136 case RESPONSE_ACCEPT:
3143 if ((count = add_route_dialog->count()) <= 0) {
3147 string template_path = add_route_dialog->track_template();
3149 if (!template_path.empty()) {
3150 _session->new_route_from_template (count, template_path);
3154 uint32_t input_chan = add_route_dialog->channels ();
3155 uint32_t output_chan;
3156 string name_template = add_route_dialog->name_template ();
3157 bool track = add_route_dialog->track ();
3158 bool aux = !track && add_route_dialog->aux();
3159 RouteGroup* route_group = add_route_dialog->route_group ();
3161 AutoConnectOption oac = Config->get_output_auto_connect();
3163 if (oac & AutoConnectMaster) {
3164 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3166 output_chan = input_chan;
3169 /* XXX do something with name template */
3171 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3173 session_add_midi_track (route_group, count);
3175 MessageDialog msg (*editor,
3176 _("Sorry, MIDI Busses are not supported at this time."));
3178 //session_add_midi_bus();
3182 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3184 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3190 ARDOUR_UI::mixer_settings () const
3195 node = _session->instant_xml(X_("Mixer"));
3197 node = Config->instant_xml(X_("Mixer"));
3201 node = new XMLNode (X_("Mixer"));
3208 ARDOUR_UI::editor_settings () const
3213 node = _session->instant_xml(X_("Editor"));
3215 node = Config->instant_xml(X_("Editor"));
3219 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3220 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3225 node = new XMLNode (X_("Editor"));
3232 ARDOUR_UI::keyboard_settings () const
3236 node = Config->extra_xml(X_("Keyboard"));
3239 node = new XMLNode (X_("Keyboard"));
3245 ARDOUR_UI::create_xrun_marker(nframes_t where)
3247 editor->mouse_add_new_marker (where, false, true);
3251 ARDOUR_UI::halt_on_xrun_message ()
3253 MessageDialog msg (*editor,
3254 _("Recording was stopped because your system could not keep up."));
3259 ARDOUR_UI::xrun_handler(nframes_t where)
3265 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3267 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3268 create_xrun_marker(where);
3271 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3272 halt_on_xrun_message ();
3277 ARDOUR_UI::disk_overrun_handler ()
3279 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3281 if (!have_disk_speed_dialog_displayed) {
3282 have_disk_speed_dialog_displayed = true;
3283 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3284 The disk system on your computer\n\
3285 was not able to keep up with %1.\n\
3287 Specifically, it failed to write data to disk\n\
3288 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3289 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3295 ARDOUR_UI::disk_underrun_handler ()
3297 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3299 if (!have_disk_speed_dialog_displayed) {
3300 have_disk_speed_dialog_displayed = true;
3301 MessageDialog* msg = new MessageDialog (*editor,
3302 string_compose (_("The disk system on your computer\n\
3303 was not able to keep up with %1.\n\
3305 Specifically, it failed to read data from disk\n\
3306 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3307 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3313 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3315 have_disk_speed_dialog_displayed = false;
3320 ARDOUR_UI::session_dialog (std::string msg)
3322 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3327 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3329 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3338 ARDOUR_UI::pending_state_dialog ()
3340 HBox* hbox = new HBox();
3341 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3342 ArdourDialog dialog (_("Crash Recovery"), true);
3344 This session appears to have been in\n\
3345 middle of recording when ardour or\n\
3346 the computer was shutdown.\n\
3348 Ardour can recover any captured audio for\n\
3349 you, or it can ignore it. Please decide\n\
3350 what you would like to do.\n"));
3351 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3352 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3353 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3354 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3355 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3356 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3357 dialog.set_default_response (RESPONSE_ACCEPT);
3358 dialog.set_position (WIN_POS_CENTER);
3363 switch (dialog.run ()) {
3364 case RESPONSE_ACCEPT:
3372 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3374 HBox* hbox = new HBox();
3375 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3376 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3377 Label message (string_compose (_("\
3378 This session was created with a sample rate of %1 Hz\n\
3380 The audioengine is currently running at %2 Hz\n"), desired, actual));
3382 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3383 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3384 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3385 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3386 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3387 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3388 dialog.set_default_response (RESPONSE_ACCEPT);
3389 dialog.set_position (WIN_POS_CENTER);
3394 switch (dialog.run ()) {
3395 case RESPONSE_ACCEPT:
3404 ARDOUR_UI::disconnect_from_jack ()
3407 if( engine->disconnect_from_jack ()) {
3408 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3412 update_sample_rate (0);
3417 ARDOUR_UI::reconnect_to_jack ()
3420 if (engine->reconnect_to_jack ()) {
3421 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3425 update_sample_rate (0);
3430 ARDOUR_UI::use_config ()
3432 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3434 set_transport_controllable_state (*node);
3439 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3441 if (Config->get_primary_clock_delta_edit_cursor()) {
3442 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3444 primary_clock.set (pos, 0, true);
3447 if (Config->get_secondary_clock_delta_edit_cursor()) {
3448 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3450 secondary_clock.set (pos);
3453 if (big_clock_window->get()) {
3454 big_clock.set (pos);
3460 ARDOUR_UI::step_edit_status_change (bool yn)
3462 // XXX should really store pre-step edit status of things
3463 // we make insensitive
3466 rec_button.set_visual_state (3);
3467 rec_button.set_sensitive (false);
3469 rec_button.set_visual_state (0);
3470 rec_button.set_sensitive (true);
3475 ARDOUR_UI::record_state_changed ()
3477 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3479 if (!_session || !big_clock_window->get()) {
3480 /* why bother - the clock isn't visible */
3484 Session::RecordState const r = _session->record_status ();
3485 bool const h = _session->have_rec_enabled_track ();
3487 if (r == Session::Recording && h) {
3488 big_clock.set_widget_name ("BigClockRecording");
3490 big_clock.set_widget_name ("BigClockNonRecording");
3495 ARDOUR_UI::first_idle ()
3498 _session->allow_auto_play (true);
3502 editor->first_idle();
3505 Keyboard::set_can_save_keybindings (true);
3510 ARDOUR_UI::store_clock_modes ()
3512 XMLNode* node = new XMLNode(X_("ClockModes"));
3514 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3515 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3518 _session->add_extra_xml (*node);
3519 _session->set_dirty ();
3524 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3525 : Controllable (name), ui (u), type(tp)
3531 ARDOUR_UI::TransportControllable::set_value (double val)
3533 if (type == ShuttleControl) {
3540 fract = -((0.5 - val)/0.5);
3542 fract = ((val - 0.5)/0.5);
3546 ui.set_shuttle_fract (fract);
3551 /* do nothing: these are radio-style actions */
3555 const char *action = 0;
3559 action = X_("Roll");
3562 action = X_("Stop");
3565 action = X_("Goto Start");
3568 action = X_("Goto End");
3571 action = X_("Loop");
3574 action = X_("Play Selection");
3577 action = X_("Record");
3587 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3595 ARDOUR_UI::TransportControllable::get_value (void) const
3614 case ShuttleControl:
3624 ARDOUR_UI::TransportControllable::set_id (const string& str)
3630 ARDOUR_UI::setup_profile ()
3632 if (gdk_screen_width() < 1200) {
3633 Profile->set_small_screen ();
3637 if (getenv ("ARDOUR_SAE")) {
3638 Profile->set_sae ();
3639 Profile->set_single_package ();
3644 ARDOUR_UI::toggle_translations ()
3646 using namespace Glib;
3648 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3650 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3653 string i18n_killer = ARDOUR::translation_kill_path();
3655 bool already_enabled = !ARDOUR::translations_are_disabled ();
3657 if (ract->get_active ()) {
3658 /* we don't care about errors */
3659 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3662 /* we don't care about errors */
3663 unlink (i18n_killer.c_str());
3666 if (already_enabled != ract->get_active()) {
3667 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3669 Gtk::MESSAGE_WARNING,
3671 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3672 win.set_position (Gtk::WIN_POS_CENTER);
3680 /** Add a window proxy to our list, so that its state will be saved.
3681 * This call also causes the window to be created and opened if its
3682 * state was saved as `visible'.
3685 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3687 _window_proxies.push_back (p);
3691 /** Remove a window proxy from our list. Must be called if a WindowProxy
3692 * is deleted, to prevent hanging pointers.
3695 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3697 _window_proxies.remove (p);
3701 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3703 MissingFileDialog dialog (s, str, type);
3708 int result = dialog.run ();
3715 return 1; // quit entire session load
3718 result = dialog.get_action ();