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;
84 #include "ardour_ui.h"
85 #include "public_editor.h"
86 #include "audio_clock.h"
91 #include "add_route_dialog.h"
95 #include "gui_thread.h"
96 #include "theme_manager.h"
97 #include "bundle_manager.h"
98 #include "session_metadata_dialog.h"
99 #include "gain_meter.h"
100 #include "route_time_axis.h"
102 #include "engine_dialog.h"
103 #include "processor_box.h"
104 #include "time_axis_view_item.h"
105 #include "window_proxy.h"
106 #include "global_port_matrix.h"
107 #include "location_ui.h"
108 #include "missing_file_dialog.h"
112 using namespace ARDOUR;
114 using namespace Gtkmm2ext;
117 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
118 UIConfiguration *ARDOUR_UI::ui_config = 0;
120 sigc::signal<void,bool> ARDOUR_UI::Blink;
121 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
122 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
123 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
125 bool could_be_a_valid_path (const string& path);
127 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
129 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
131 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
132 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
133 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
134 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
138 preroll_button (_("pre\nroll")),
139 postroll_button (_("post\nroll")),
143 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
147 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
148 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
149 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
150 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
151 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
152 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
153 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
154 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
155 shuttle_controller_binding_proxy (shuttle_controllable),
157 roll_button (roll_controllable),
158 stop_button (stop_controllable),
159 goto_start_button (goto_start_controllable),
160 goto_end_button (goto_end_controllable),
161 auto_loop_button (auto_loop_controllable),
162 play_selection_button (play_selection_controllable),
163 rec_button (rec_controllable),
165 shuttle_units_button (_("% ")),
167 punch_in_button (_("Punch In")),
168 punch_out_button (_("Punch Out")),
169 auto_return_button (_("Auto Return")),
170 auto_play_button (_("Auto Play")),
171 auto_input_button (_("Auto Input")),
172 click_button (_("Click")),
173 time_master_button (_("time\nmaster")),
175 auditioning_alert_button (_("AUDITION")),
176 solo_alert_button (_("SOLO")),
177 error_log_button (_("Errors"))
180 using namespace Gtk::Menu_Helpers;
186 // _auto_display_errors = false;
188 * This was commented out as it wasn't defined
189 * in A3 IIRC. If this is not needed it should
190 * be completely removed.
198 if (theArdourUI == 0) {
202 ui_config = new UIConfiguration();
203 theme_manager = new ThemeManager();
209 _session_is_new = false;
210 big_clock_window = 0;
211 big_clock_height = 0;
212 big_clock_resize_in_progress = false;
213 session_selector_window = 0;
214 last_key_press_time = 0;
215 _will_create_new_session_automatically = false;
216 add_route_dialog = 0;
218 rc_option_editor = 0;
219 session_option_editor = 0;
221 open_session_selector = 0;
222 have_configure_timeout = false;
223 have_disk_speed_dialog_displayed = false;
224 session_loaded = false;
225 last_speed_displayed = -1.0f;
226 ignore_dual_punch = false;
227 original_big_clock_width = -1;
228 original_big_clock_height = -1;
229 original_big_clock_font_size = 0;
231 roll_button.unset_flags (Gtk::CAN_FOCUS);
232 stop_button.unset_flags (Gtk::CAN_FOCUS);
233 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
234 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
235 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
236 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
237 rec_button.unset_flags (Gtk::CAN_FOCUS);
239 last_configure_time= 0;
241 shuttle_grabbed = false;
243 shuttle_max_speed = 8.0f;
245 shuttle_style_menu = 0;
246 shuttle_unit_menu = 0;
248 // We do not have jack linked in yet so;
250 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
252 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
253 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
255 /* handle dialog requests */
257 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
259 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
261 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
263 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
265 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
267 /* handle requests to quit (coming from JACK session) */
269 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
271 /* handle requests to deal with missing files */
273 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
275 /* lets get this party started */
278 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
279 throw failed_constructor ();
282 setup_gtk_ardour_enums ();
285 GainMeter::setup_slider_pix ();
286 RouteTimeAxisView::setup_slider_pix ();
287 SendProcessorEntry::setup_slider_pix ();
288 SessionEvent::create_per_thread_pool ("GUI", 512);
290 } catch (failed_constructor& err) {
291 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
296 /* we like keyboards */
298 keyboard = new ArdourKeyboard(*this);
300 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
302 keyboard->set_state (*node, Stateful::loading_state_version);
307 TimeAxisViewItem::set_constant_heights ();
309 /* The following must happen after ARDOUR::init() so that Config is set up */
311 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
312 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
314 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
315 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
316 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
317 Config->extra_xml (X_("UI")),
318 string_compose ("toggle-%1-connection-manager", (*i).to_string())
324 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
325 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
330 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
332 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
335 _startup = new ArdourStartup ();
337 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
339 if (audio_setup && _startup->engine_control()) {
340 _startup->engine_control()->set_state (*audio_setup);
343 _startup->set_new_only (should_be_new);
344 if (!load_template.empty()) {
345 _startup->set_load_template( load_template );
347 _startup->present ();
353 switch (_startup->response()) {
362 ARDOUR_UI::create_engine ()
364 // this gets called every time by new_session()
370 loading_message (_("Starting audio engine"));
373 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
380 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
381 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
382 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
384 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
386 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
394 ARDOUR_UI::post_engine ()
396 /* Things to be done once we create the AudioEngine
399 ARDOUR::init_post_engine ();
401 ActionManager::init ();
404 if (setup_windows ()) {
405 throw failed_constructor ();
408 check_memory_locking();
410 /* this is the first point at which all the keybindings are available */
412 if (ARDOUR_COMMAND_LINE::show_key_actions) {
413 vector<string> names;
414 vector<string> paths;
416 vector<AccelKey> bindings;
418 ActionManager::get_all_actions (names, paths, keys, bindings);
420 vector<string>::iterator n;
421 vector<string>::iterator k;
422 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
423 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
429 blink_timeout_tag = -1;
431 /* this being a GUI and all, we want peakfiles */
433 AudioFileSource::set_build_peakfiles (true);
434 AudioFileSource::set_build_missing_peakfiles (true);
436 /* set default clock modes */
438 if (Profile->get_sae()) {
439 primary_clock.set_mode (AudioClock::BBT);
440 secondary_clock.set_mode (AudioClock::MinSec);
442 primary_clock.set_mode (AudioClock::Timecode);
443 secondary_clock.set_mode (AudioClock::BBT);
446 /* start the time-of-day-clock */
449 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
450 update_wall_clock ();
451 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
454 update_disk_space ();
456 update_sample_rate (engine->frame_rate());
458 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
459 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
460 Config->map_parameters (pc);
462 /* now start and maybe save state */
464 if (do_engine_start () == 0) {
465 if (_session && _session_is_new) {
466 /* we need to retain initial visual
467 settings for a new session
469 _session->save_state ("");
474 ARDOUR_UI::~ARDOUR_UI ()
479 delete add_route_dialog;
483 ARDOUR_UI::pop_back_splash ()
485 if (Splash::instance()) {
486 // Splash::instance()->pop_back();
487 Splash::instance()->hide ();
492 ARDOUR_UI::configure_timeout ()
494 if (last_configure_time == 0) {
495 /* no configure events yet */
499 /* force a gap of 0.5 seconds since the last configure event
502 if (get_microseconds() - last_configure_time < 500000) {
505 have_configure_timeout = false;
506 cerr << "config event-driven save\n";
507 save_ardour_state ();
513 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
515 if (have_configure_timeout) {
516 last_configure_time = get_microseconds();
518 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
519 have_configure_timeout = true;
526 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
528 const XMLProperty* prop;
530 if ((prop = node.property ("roll")) != 0) {
531 roll_controllable->set_id (prop->value());
533 if ((prop = node.property ("stop")) != 0) {
534 stop_controllable->set_id (prop->value());
536 if ((prop = node.property ("goto-start")) != 0) {
537 goto_start_controllable->set_id (prop->value());
539 if ((prop = node.property ("goto-end")) != 0) {
540 goto_end_controllable->set_id (prop->value());
542 if ((prop = node.property ("auto-loop")) != 0) {
543 auto_loop_controllable->set_id (prop->value());
545 if ((prop = node.property ("play-selection")) != 0) {
546 play_selection_controllable->set_id (prop->value());
548 if ((prop = node.property ("rec")) != 0) {
549 rec_controllable->set_id (prop->value());
551 if ((prop = node.property ("shuttle")) != 0) {
552 shuttle_controllable->set_id (prop->value());
557 ARDOUR_UI::get_transport_controllable_state ()
559 XMLNode* node = new XMLNode(X_("TransportControllables"));
562 roll_controllable->id().print (buf, sizeof (buf));
563 node->add_property (X_("roll"), buf);
564 stop_controllable->id().print (buf, sizeof (buf));
565 node->add_property (X_("stop"), buf);
566 goto_start_controllable->id().print (buf, sizeof (buf));
567 node->add_property (X_("goto_start"), buf);
568 goto_end_controllable->id().print (buf, sizeof (buf));
569 node->add_property (X_("goto_end"), buf);
570 auto_loop_controllable->id().print (buf, sizeof (buf));
571 node->add_property (X_("auto_loop"), buf);
572 play_selection_controllable->id().print (buf, sizeof (buf));
573 node->add_property (X_("play_selection"), buf);
574 rec_controllable->id().print (buf, sizeof (buf));
575 node->add_property (X_("rec"), buf);
576 shuttle_controllable->id().print (buf, sizeof (buf));
577 node->add_property (X_("shuttle"), buf);
584 ARDOUR_UI::autosave_session ()
586 if (g_main_depth() > 1) {
587 /* inside a recursive main loop,
588 give up because we may not be able to
594 if (!Config->get_periodic_safety_backups()) {
599 _session->maybe_write_autosave();
606 ARDOUR_UI::update_autosave ()
608 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
610 if (_session && _session->dirty()) {
611 if (_autosave_connection.connected()) {
612 _autosave_connection.disconnect();
615 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
616 Config->get_periodic_safety_backup_interval() * 1000);
619 if (_autosave_connection.connected()) {
620 _autosave_connection.disconnect();
626 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
630 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
632 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
635 MessageDialog win (title,
641 win.set_secondary_text(_("There are several possible reasons:\n\
643 1) You requested audio parameters that are not supported..\n\
644 2) JACK is running as another user.\n\
646 Please consider the possibilities, and perhaps try different parameters."));
648 win.set_secondary_text(_("There are several possible reasons:\n\
650 1) JACK is not running.\n\
651 2) JACK is running as another user, perhaps root.\n\
652 3) There is already another client called \"ardour\".\n\
654 Please consider the possibilities, and perhaps (re)start JACK."));
658 win.set_transient_for (*toplevel);
662 win.add_button (Stock::OK, RESPONSE_CLOSE);
664 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
667 win.set_default_response (RESPONSE_CLOSE);
670 win.set_position (Gtk::WIN_POS_CENTER);
673 /* we just don't care about the result, but we want to block */
679 ARDOUR_UI::startup ()
681 Application* app = Application::instance ();
683 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
684 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
687 call_the_mothership (VERSIONSTRING);
692 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
698 goto_editor_window ();
700 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
701 to be opened on top of the editor window that goto_editor_window() just opened.
703 add_window_proxy (location_ui);
704 add_window_proxy (big_clock_window);
705 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
706 add_window_proxy (_global_port_matrix[*i]);
709 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
713 ARDOUR_UI::no_memory_warning ()
715 XMLNode node (X_("no-memory-warning"));
716 Config->add_instant_xml (node);
720 ARDOUR_UI::check_memory_locking ()
723 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
727 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
729 if (engine->is_realtime() && memory_warning_node == 0) {
731 struct rlimit limits;
733 long pages, page_size;
735 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
738 ram = (int64_t) pages * (int64_t) page_size;
741 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
745 if (limits.rlim_cur != RLIM_INFINITY) {
747 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
750 MessageDialog msg (string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
751 "This might cause %1 to run out of memory before your system "
752 "runs out of memory. \n\n"
753 "You can view the memory limit with 'ulimit -l', "
754 "and it is normally controlled by /etc/security/limits.conf"),
755 PROGRAM_NAME).c_str());
757 VBox* vbox = msg.get_vbox();
759 CheckButton cb (_("Do not show this window again"));
761 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
763 hbox.pack_start (cb, true, false);
764 vbox->pack_start (hbox);
771 editor->ensure_float (msg);
781 ARDOUR_UI::queue_finish ()
783 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
787 ARDOUR_UI::idle_finish ()
790 return false; /* do not call again */
799 if (_session->transport_rolling() && (++tries < 8)) {
800 _session->request_stop (false, true);
804 if (_session->dirty()) {
805 switch (ask_about_saving_session(_("quit"))) {
810 /* use the default name */
811 if (save_state_canfail ("")) {
812 /* failed - don't quit */
813 MessageDialog msg (*editor,
815 Ardour was unable to save your session.\n\n\
816 If you still wish to quit, please use the\n\n\
817 \"Just quit\" option."));
828 second_connection.disconnect ();
829 point_one_second_connection.disconnect ();
830 point_oh_five_second_connection.disconnect ();
831 point_zero_one_second_connection.disconnect();
834 /* Save state before deleting the session, as that causes some
835 windows to be destroyed before their visible state can be
838 save_ardour_state ();
841 // _session->set_deletion_in_progress ();
842 _session->set_clean ();
843 _session->remove_pending_capture_state ();
848 ArdourDialog::close_all_dialogs ();
854 ARDOUR_UI::ask_about_saving_session (const string & what)
856 ArdourDialog window (_("Unsaved Session"));
857 Gtk::HBox dhbox; // the hbox for the image and text
858 Gtk::Label prompt_label;
859 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
863 msg = string_compose(_("Don't %1"), what);
864 window.add_button (msg, RESPONSE_REJECT);
865 msg = string_compose(_("Just %1"), what);
866 window.add_button (msg, RESPONSE_APPLY);
867 msg = string_compose(_("Save and %1"), what);
868 window.add_button (msg, RESPONSE_ACCEPT);
870 window.set_default_response (RESPONSE_ACCEPT);
872 Gtk::Button noquit_button (msg);
873 noquit_button.set_name ("EditorGTKButton");
878 if (_session->snap_name() == _session->name()) {
881 type = _("snapshot");
883 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?"),
884 type, _session->snap_name());
886 prompt_label.set_text (prompt);
887 prompt_label.set_name (X_("PrompterLabel"));
888 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
890 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
891 dhbox.set_homogeneous (false);
892 dhbox.pack_start (*dimage, false, false, 5);
893 dhbox.pack_start (prompt_label, true, false, 5);
894 window.get_vbox()->pack_start (dhbox);
896 window.set_name (_("Prompter"));
897 window.set_position (Gtk::WIN_POS_MOUSE);
898 window.set_modal (true);
899 window.set_resizable (false);
905 window.set_keep_above (true);
908 ResponseType r = (ResponseType) window.run();
913 case RESPONSE_ACCEPT: // save and get out of here
915 case RESPONSE_APPLY: // get out of here
925 ARDOUR_UI::every_second ()
928 update_buffer_load ();
929 update_disk_space ();
934 ARDOUR_UI::every_point_one_seconds ()
936 update_speed_display ();
937 RapidScreenUpdate(); /* EMIT_SIGNAL */
942 ARDOUR_UI::every_point_zero_one_seconds ()
944 // august 2007: actual update frequency: 40Hz, not 100Hz
946 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
951 ARDOUR_UI::update_sample_rate (nframes_t)
955 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
957 if (!engine->connected()) {
959 snprintf (buf, sizeof (buf), _("disconnected"));
963 nframes_t rate = engine->frame_rate();
965 if (fmod (rate, 1000.0) != 0.0) {
966 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
967 (float) rate/1000.0f,
968 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
970 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
972 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
976 sample_rate_label.set_text (buf);
980 ARDOUR_UI::update_cpu_load ()
983 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
984 cpu_load_label.set_text (buf);
988 ARDOUR_UI::update_buffer_load ()
994 c = _session->capture_load ();
995 p = _session->playback_load ();
997 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
998 _session->playback_load(), _session->capture_load());
999 buffer_load_label.set_text (buf);
1001 buffer_load_label.set_text ("");
1006 ARDOUR_UI::count_recenabled_streams (Route& route)
1008 Track* track = dynamic_cast<Track*>(&route);
1009 if (track && track->record_enabled()) {
1010 rec_enabled_streams += track->n_inputs().n_total();
1015 ARDOUR_UI::update_disk_space()
1017 if (_session == 0) {
1021 framecnt_t frames = _session->available_capture_duration();
1023 nframes_t fr = _session->frame_rate();
1025 if (frames == max_framecnt) {
1026 strcpy (buf, _("Disk: 24hrs+"));
1028 rec_enabled_streams = 0;
1029 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1031 if (rec_enabled_streams) {
1032 frames /= rec_enabled_streams;
1039 hrs = frames / (fr * 3600);
1040 frames -= hrs * fr * 3600;
1041 mins = frames / (fr * 60);
1042 frames -= mins * fr * 60;
1045 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1048 disk_space_label.set_text (buf);
1050 // An attempt to make the disk space label flash red when space has run out.
1052 if (frames < fr * 60 * 5) {
1053 /* disk_space_box.style ("disk_space_label_empty"); */
1055 /* disk_space_box.style ("disk_space_label"); */
1061 ARDOUR_UI::update_wall_clock ()
1068 tm_now = localtime (&now);
1070 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1071 wall_clock_label.set_text (buf);
1077 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1079 session_popup_menu->popup (0, 0);
1084 ARDOUR_UI::redisplay_recent_sessions ()
1086 std::vector<sys::path> session_directories;
1087 RecentSessionsSorter cmp;
1089 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1090 recent_session_model->clear ();
1092 ARDOUR::RecentSessions rs;
1093 ARDOUR::read_recent_sessions (rs);
1096 recent_session_display.set_model (recent_session_model);
1100 // sort them alphabetically
1101 sort (rs.begin(), rs.end(), cmp);
1103 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1104 session_directories.push_back ((*i).second);
1107 for (vector<sys::path>::const_iterator i = session_directories.begin();
1108 i != session_directories.end(); ++i)
1110 std::vector<sys::path> state_file_paths;
1112 // now get available states for this session
1114 get_state_files_in_directory (*i, state_file_paths);
1116 vector<string*>* states;
1117 vector<const gchar*> item;
1118 string fullpath = (*i).to_string();
1120 /* remove any trailing / */
1122 if (fullpath[fullpath.length()-1] == '/') {
1123 fullpath = fullpath.substr (0, fullpath.length()-1);
1126 /* check whether session still exists */
1127 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1128 /* session doesn't exist */
1129 cerr << "skipping non-existent session " << fullpath << endl;
1133 /* now get available states for this session */
1135 if ((states = Session::possible_states (fullpath)) == 0) {
1136 /* no state file? */
1140 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1142 Gtk::TreeModel::Row row = *(recent_session_model->append());
1144 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1145 row[recent_session_columns.fullpath] = fullpath;
1147 if (state_file_names.size() > 1) {
1151 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1152 i2 != state_file_names.end(); ++i2)
1155 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1157 child_row[recent_session_columns.visible_name] = *i2;
1158 child_row[recent_session_columns.fullpath] = fullpath;
1163 recent_session_display.set_model (recent_session_model);
1167 ARDOUR_UI::build_session_selector ()
1169 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1171 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1173 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1174 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1175 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1176 recent_session_model = TreeStore::create (recent_session_columns);
1177 recent_session_display.set_model (recent_session_model);
1178 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1179 recent_session_display.set_headers_visible (false);
1180 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1181 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1183 scroller->add (recent_session_display);
1184 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1186 session_selector_window->set_name ("SessionSelectorWindow");
1187 session_selector_window->set_size_request (200, 400);
1188 session_selector_window->get_vbox()->pack_start (*scroller);
1190 recent_session_display.show();
1192 //session_selector_window->get_vbox()->show();
1196 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1198 session_selector_window->response (RESPONSE_ACCEPT);
1202 ARDOUR_UI::open_recent_session ()
1204 bool can_return = (_session != 0);
1206 if (session_selector_window == 0) {
1207 build_session_selector ();
1210 redisplay_recent_sessions ();
1214 session_selector_window->set_position (WIN_POS_MOUSE);
1216 ResponseType r = (ResponseType) session_selector_window->run ();
1219 case RESPONSE_ACCEPT:
1223 session_selector_window->hide();
1230 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1234 session_selector_window->hide();
1236 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1238 if (i == recent_session_model->children().end()) {
1242 std::string path = (*i)[recent_session_columns.fullpath];
1243 std::string state = (*i)[recent_session_columns.visible_name];
1245 _session_is_new = false;
1247 if (load_session (path, state) == 0) {
1256 ARDOUR_UI::check_audioengine ()
1259 if (!engine->connected()) {
1260 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1261 "You cannot open or close sessions in this condition"),
1274 ARDOUR_UI::open_session ()
1276 if (!check_audioengine()) {
1281 /* popup selector window */
1283 if (open_session_selector == 0) {
1285 /* ardour sessions are folders */
1287 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1288 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1289 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1290 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1292 FileFilter session_filter;
1293 session_filter.add_pattern ("*.ardour");
1294 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1295 open_session_selector->add_filter (session_filter);
1296 open_session_selector->set_filter (session_filter);
1299 int response = open_session_selector->run();
1300 open_session_selector->hide ();
1303 case RESPONSE_ACCEPT:
1306 open_session_selector->hide();
1310 open_session_selector->hide();
1311 string session_path = open_session_selector->get_filename();
1315 if (session_path.length() > 0) {
1316 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1317 _session_is_new = isnew;
1318 load_session (path, name);
1325 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1327 list<boost::shared_ptr<MidiTrack> > tracks;
1329 if (_session == 0) {
1330 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1337 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1339 if (tracks.size() != how_many) {
1340 if (how_many == 1) {
1341 error << _("could not create a new midi track") << endmsg;
1343 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1347 if ((route = _session->new_midi_route ()) == 0) {
1348 error << _("could not create new midi bus") << endmsg;
1354 MessageDialog msg (*editor,
1355 string_compose (_("There are insufficient JACK ports available\n\
1356 to create a new track or bus.\n\
1357 You should save %1, exit and\n\
1358 restart JACK with more ports."), PROGRAM_NAME));
1365 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)
1367 list<boost::shared_ptr<AudioTrack> > tracks;
1370 if (_session == 0) {
1371 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1377 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1379 if (tracks.size() != how_many) {
1380 if (how_many == 1) {
1381 error << _("could not create a new audio track") << endmsg;
1383 error << string_compose (_("could only create %1 of %2 new audio %3"),
1384 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1390 routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1392 if (routes.size() != how_many) {
1393 if (how_many == 1) {
1394 error << _("could not create a new audio track") << endmsg;
1396 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1403 MessageDialog msg (*editor,
1404 string_compose (_("There are insufficient JACK ports available\n\
1405 to create a new track or bus.\n\
1406 You should save %1, exit and\n\
1407 restart JACK with more ports."), PROGRAM_NAME));
1414 ARDOUR_UI::do_transport_locate (nframes_t new_position, bool with_roll)
1416 nframes_t _preroll = 0;
1419 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1420 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1422 if (new_position > _preroll) {
1423 new_position -= _preroll;
1428 _session->request_locate (new_position, with_roll);
1433 ARDOUR_UI::transport_goto_start ()
1436 _session->goto_start();
1438 /* force displayed area in editor to start no matter
1439 what "follow playhead" setting is.
1443 editor->center_screen (_session->current_start_frame ());
1449 ARDOUR_UI::transport_goto_zero ()
1452 _session->request_locate (0);
1454 /* force displayed area in editor to start no matter
1455 what "follow playhead" setting is.
1459 editor->reset_x_origin (0);
1465 ARDOUR_UI::transport_goto_wallclock ()
1467 if (_session && editor) {
1474 localtime_r (&now, &tmnow);
1476 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1477 frames += tmnow.tm_min * (60 * _session->frame_rate());
1478 frames += tmnow.tm_sec * _session->frame_rate();
1480 _session->request_locate (frames, _session->transport_rolling ());
1482 /* force displayed area in editor to start no matter
1483 what "follow playhead" setting is.
1487 editor->center_screen (frames);
1493 ARDOUR_UI::transport_goto_end ()
1496 nframes_t const frame = _session->current_end_frame();
1497 _session->request_locate (frame);
1499 /* force displayed area in editor to start no matter
1500 what "follow playhead" setting is.
1504 editor->center_screen (frame);
1510 ARDOUR_UI::transport_stop ()
1516 if (_session->is_auditioning()) {
1517 _session->cancel_audition ();
1521 _session->request_stop (false, true);
1525 ARDOUR_UI::transport_stop_and_forget_capture ()
1528 _session->request_stop (true, true);
1533 ARDOUR_UI::remove_last_capture()
1536 editor->remove_last_capture();
1541 ARDOUR_UI::transport_record (bool roll)
1545 switch (_session->record_status()) {
1546 case Session::Disabled:
1547 if (_session->ntracks() == 0) {
1548 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1552 _session->maybe_enable_record ();
1557 case Session::Recording:
1559 _session->request_stop();
1561 _session->disable_record (false, true);
1565 case Session::Enabled:
1566 _session->disable_record (false, true);
1569 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1573 ARDOUR_UI::transport_roll ()
1579 if (_session->is_auditioning()) {
1583 if (_session->config.get_external_sync()) {
1584 switch (_session->config.get_sync_source()) {
1588 /* transport controlled by the master */
1593 bool rolling = _session->transport_rolling();
1595 if (_session->get_play_loop()) {
1596 /* XXX it is not possible to just leave seamless loop and keep
1597 playing at present (nov 4th 2009)
1599 if (!Config->get_seamless_loop()) {
1600 _session->request_play_loop (false, true);
1602 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1603 /* stop playing a range if we currently are */
1604 _session->request_play_range (0, true);
1607 if (join_play_range_button.get_active()) {
1608 _session->request_play_range (&editor->get_selection().time, true);
1612 _session->request_transport_speed (1.0f);
1617 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1624 if (_session->is_auditioning()) {
1625 _session->cancel_audition ();
1629 if (_session->config.get_external_sync()) {
1630 switch (_session->config.get_sync_source()) {
1634 /* transport controlled by the master */
1639 bool rolling = _session->transport_rolling();
1640 bool affect_transport = true;
1642 if (rolling && roll_out_of_bounded_mode) {
1643 /* drop out of loop/range playback but leave transport rolling */
1644 if (_session->get_play_loop()) {
1645 if (Config->get_seamless_loop()) {
1646 /* the disk buffers contain copies of the loop - we can't
1647 just keep playing, so stop the transport. the user
1648 can restart as they wish.
1650 affect_transport = true;
1652 /* disk buffers are normal, so we can keep playing */
1653 affect_transport = false;
1655 _session->request_play_loop (false, true);
1656 } else if (_session->get_play_range ()) {
1657 affect_transport = false;
1658 _session->request_play_range (0, true);
1662 if (affect_transport) {
1664 _session->request_stop (with_abort, true);
1666 if (join_play_range_button.get_active()) {
1667 _session->request_play_range (&editor->get_selection().time, true);
1670 _session->request_transport_speed (1.0f);
1676 ARDOUR_UI::toggle_session_auto_loop ()
1679 if (_session->get_play_loop()) {
1680 if (_session->transport_rolling()) {
1681 Location * looploc = _session->locations()->auto_loop_location();
1683 _session->request_locate (looploc->start(), true);
1686 _session->request_play_loop (false);
1689 Location * looploc = _session->locations()->auto_loop_location();
1691 _session->request_play_loop (true);
1698 ARDOUR_UI::transport_play_selection ()
1704 editor->play_selection ();
1708 ARDOUR_UI::transport_rewind (int option)
1710 float current_transport_speed;
1713 current_transport_speed = _session->transport_speed();
1715 if (current_transport_speed >= 0.0f) {
1718 _session->request_transport_speed (-1.0f);
1721 _session->request_transport_speed (-4.0f);
1724 _session->request_transport_speed (-0.5f);
1729 _session->request_transport_speed (current_transport_speed * 1.5f);
1735 ARDOUR_UI::transport_forward (int option)
1737 float current_transport_speed;
1740 current_transport_speed = _session->transport_speed();
1742 if (current_transport_speed <= 0.0f) {
1745 _session->request_transport_speed (1.0f);
1748 _session->request_transport_speed (4.0f);
1751 _session->request_transport_speed (0.5f);
1756 _session->request_transport_speed (current_transport_speed * 1.5f);
1763 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1765 if (_session == 0) {
1769 boost::shared_ptr<Route> r;
1771 if ((r = _session->route_by_remote_id (rid)) != 0) {
1775 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1776 t->set_record_enabled (!t->record_enabled(), this);
1779 if (_session == 0) {
1785 ARDOUR_UI::map_transport_state ()
1787 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1790 auto_loop_button.set_visual_state (0);
1791 play_selection_button.set_visual_state (0);
1792 roll_button.set_visual_state (0);
1793 stop_button.set_visual_state (1);
1797 float sp = _session->transport_speed();
1800 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1801 shuttle_box.queue_draw ();
1802 } else if (sp == 0.0f) {
1804 shuttle_box.queue_draw ();
1805 update_disk_space ();
1812 if (_session->get_play_range()) {
1814 play_selection_button.set_visual_state (1);
1815 roll_button.set_visual_state (0);
1816 auto_loop_button.set_visual_state (0);
1818 } else if (_session->get_play_loop ()) {
1820 auto_loop_button.set_visual_state (1);
1821 play_selection_button.set_visual_state (0);
1822 roll_button.set_visual_state (0);
1826 roll_button.set_visual_state (1);
1827 play_selection_button.set_visual_state (0);
1828 auto_loop_button.set_visual_state (0);
1831 if (join_play_range_button.get_active()) {
1832 /* light up both roll and play-selection if they are joined */
1833 roll_button.set_visual_state (1);
1834 play_selection_button.set_visual_state (1);
1837 stop_button.set_visual_state (0);
1841 stop_button.set_visual_state (1);
1842 roll_button.set_visual_state (0);
1843 play_selection_button.set_visual_state (0);
1844 auto_loop_button.set_visual_state (0);
1849 ARDOUR_UI::engine_stopped ()
1851 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1852 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1853 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1857 ARDOUR_UI::engine_running ()
1859 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1860 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1861 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1863 Glib::RefPtr<Action> action;
1864 const char* action_name = 0;
1866 switch (engine->frames_per_cycle()) {
1868 action_name = X_("JACKLatency32");
1871 action_name = X_("JACKLatency64");
1874 action_name = X_("JACKLatency128");
1877 action_name = X_("JACKLatency512");
1880 action_name = X_("JACKLatency1024");
1883 action_name = X_("JACKLatency2048");
1886 action_name = X_("JACKLatency4096");
1889 action_name = X_("JACKLatency8192");
1892 /* XXX can we do anything useful ? */
1898 action = ActionManager::get_action (X_("JACK"), action_name);
1901 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1902 ract->set_active ();
1908 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1910 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1911 /* we can't rely on the original string continuing to exist when we are called
1912 again in the GUI thread, so make a copy and note that we need to
1915 char *copy = strdup (reason);
1916 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1920 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1921 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1923 update_sample_rate (0);
1927 /* if the reason is a non-empty string, it means that the backend was shutdown
1928 rather than just Ardour.
1931 if (strlen (reason)) {
1932 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1934 msgstr = string_compose (_("\
1935 JACK has either been shutdown or it\n\
1936 disconnected %1 because %1\n\
1937 was not fast enough. Try to restart\n\
1938 JACK, reconnect and save the session."), PROGRAM_NAME);
1941 MessageDialog msg (*editor, msgstr);
1946 free ((char*) reason);
1951 ARDOUR_UI::do_engine_start ()
1959 error << _("Unable to start the session running")
1969 ARDOUR_UI::setup_theme ()
1971 theme_manager->setup_theme();
1975 ARDOUR_UI::update_clocks ()
1977 if (!editor || !editor->dragging_playhead()) {
1978 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1983 ARDOUR_UI::start_clocking ()
1985 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1989 ARDOUR_UI::stop_clocking ()
1991 clock_signal_connection.disconnect ();
1995 ARDOUR_UI::toggle_clocking ()
1998 if (clock_button.get_active()) {
2007 ARDOUR_UI::_blink (void *arg)
2010 ((ARDOUR_UI *) arg)->blink ();
2017 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2021 ARDOUR_UI::start_blinking ()
2023 /* Start the blink signal. Everybody with a blinking widget
2024 uses Blink to drive the widget's state.
2027 if (blink_timeout_tag < 0) {
2029 blink_timeout_tag = g_timeout_add (240, _blink, this);
2034 ARDOUR_UI::stop_blinking ()
2036 if (blink_timeout_tag >= 0) {
2037 g_source_remove (blink_timeout_tag);
2038 blink_timeout_tag = -1;
2043 /** Ask the user for the name of a new shapshot and then take it.
2047 ARDOUR_UI::snapshot_session (bool switch_to_it)
2049 ArdourPrompter prompter (true);
2052 prompter.set_name ("Prompter");
2053 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2054 prompter.set_title (_("Take Snapshot"));
2055 prompter.set_title (_("Take Snapshot"));
2056 prompter.set_prompt (_("Name of new snapshot"));
2058 if (!switch_to_it) {
2061 struct tm local_time;
2064 localtime_r (&n, &local_time);
2065 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2066 prompter.set_initial_text (timebuf);
2070 switch (prompter.run()) {
2071 case RESPONSE_ACCEPT:
2073 prompter.get_result (snapname);
2075 bool do_save = (snapname.length() != 0);
2078 if (snapname.find ('/') != string::npos) {
2079 MessageDialog msg (_("To ensure compatibility with various systems\n"
2080 "snapshot names may not contain a '/' character"));
2084 if (snapname.find ('\\') != string::npos) {
2085 MessageDialog msg (_("To ensure compatibility with various systems\n"
2086 "snapshot names may not contain a '\\' character"));
2092 vector<sys::path> p;
2093 get_state_files_in_directory (_session->session_directory().root_path(), p);
2094 vector<string> n = get_file_names_no_extension (p);
2095 if (find (n.begin(), n.end(), snapname) != n.end()) {
2097 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2098 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2099 confirm.get_vbox()->pack_start (m, true, true);
2100 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2101 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2102 confirm.show_all ();
2103 switch (confirm.run()) {
2104 case RESPONSE_CANCEL:
2110 save_state (snapname, switch_to_it);
2121 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2123 XMLNode* node = new XMLNode (X_("UI"));
2125 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2126 if (!(*i)->rc_configured()) {
2127 node->add_child_nocopy (*((*i)->get_state ()));
2131 _session->add_extra_xml (*node);
2133 save_state_canfail (name, switch_to_it);
2137 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2142 if (name.length() == 0) {
2143 name = _session->snap_name();
2146 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2150 cerr << "SS canfail\n";
2151 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2156 ARDOUR_UI::primary_clock_value_changed ()
2159 _session->request_locate (primary_clock.current_time ());
2164 ARDOUR_UI::big_clock_value_changed ()
2167 _session->request_locate (big_clock.current_time ());
2172 ARDOUR_UI::secondary_clock_value_changed ()
2175 _session->request_locate (secondary_clock.current_time ());
2180 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2182 if (_session == 0) {
2186 if (_session->step_editing()) {
2190 Session::RecordState const r = _session->record_status ();
2191 bool const h = _session->have_rec_enabled_track ();
2193 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2195 rec_button.set_visual_state (2);
2197 rec_button.set_visual_state (0);
2199 } else if (r == Session::Recording && h) {
2200 rec_button.set_visual_state (1);
2202 rec_button.set_visual_state (0);
2207 ARDOUR_UI::save_template ()
2209 ArdourPrompter prompter (true);
2212 if (!check_audioengine()) {
2216 prompter.set_name (X_("Prompter"));
2217 prompter.set_title (_("Save Mix Template"));
2218 prompter.set_prompt (_("Name for mix template:"));
2219 prompter.set_initial_text(_session->name() + _("-template"));
2220 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2222 switch (prompter.run()) {
2223 case RESPONSE_ACCEPT:
2224 prompter.get_result (name);
2226 if (name.length()) {
2227 _session->save_template (name);
2237 ARDOUR_UI::edit_metadata ()
2239 SessionMetadataEditor dialog;
2240 dialog.set_session (_session);
2241 editor->ensure_float (dialog);
2246 ARDOUR_UI::import_metadata ()
2248 SessionMetadataImporter dialog;
2249 dialog.set_session (_session);
2250 editor->ensure_float (dialog);
2255 ARDOUR_UI::fontconfig_dialog ()
2258 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2259 may not and it can take a while to build it. Warn them.
2262 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2264 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2265 MessageDialog msg (*_startup,
2266 string_compose (_("Welcome to %1.\n\n"
2267 "The program will take a bit longer to start up\n"
2268 "while the system fonts are checked.\n\n"
2269 "This will only be done once, and you will\n"
2270 "not see this message again\n"), PROGRAM_NAME),
2283 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2285 existing_session = false;
2287 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2288 session_path = cmdline_path;
2289 existing_session = true;
2290 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2291 session_path = Glib::path_get_dirname (string (cmdline_path));
2292 existing_session = true;
2294 /* it doesn't exist, assume the best */
2295 session_path = Glib::path_get_dirname (string (cmdline_path));
2298 session_name = basename_nosuffix (string (cmdline_path));
2302 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2304 /* when this is called, the backend audio system must be running */
2306 /* the main idea here is to deal with the fact that a cmdline argument for the session
2307 can be interpreted in different ways - it could be a directory or a file, and before
2308 we load, we need to know both the session directory and the snapshot (statefile) within it
2309 that we are supposed to use.
2312 if (session_name.length() == 0 || session_path.length() == 0) {
2316 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2318 std::string predicted_session_file;
2320 predicted_session_file = session_path;
2321 predicted_session_file += '/';
2322 predicted_session_file += session_name;
2323 predicted_session_file += ARDOUR::statefile_suffix;
2325 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2326 existing_session = true;
2329 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2331 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2332 /* existing .ardour file */
2333 existing_session = true;
2337 existing_session = false;
2340 /* lets just try to load it */
2342 if (create_engine ()) {
2343 backend_audio_error (false, _startup);
2347 return load_session (session_path, session_name);
2351 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2353 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2355 MessageDialog msg (str,
2357 Gtk::MESSAGE_WARNING,
2358 Gtk::BUTTONS_YES_NO,
2362 msg.set_name (X_("OpenExistingDialog"));
2363 msg.set_title (_("Open Existing Session"));
2364 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2365 msg.set_position (Gtk::WIN_POS_MOUSE);
2368 switch (msg.run()) {
2377 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2379 BusProfile bus_profile;
2381 if (Profile->get_sae()) {
2383 bus_profile.master_out_channels = 2;
2384 bus_profile.input_ac = AutoConnectPhysical;
2385 bus_profile.output_ac = AutoConnectMaster;
2386 bus_profile.requested_physical_in = 0; // use all available
2387 bus_profile.requested_physical_out = 0; // use all available
2391 /* get settings from advanced section of NSD */
2393 if (_startup->create_master_bus()) {
2394 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2396 bus_profile.master_out_channels = 0;
2399 if (_startup->connect_inputs()) {
2400 bus_profile.input_ac = AutoConnectPhysical;
2402 bus_profile.input_ac = AutoConnectOption (0);
2405 /// @todo some minor tweaks.
2407 bus_profile.output_ac = AutoConnectOption (0);
2409 if (_startup->connect_outputs ()) {
2410 if (_startup->connect_outs_to_master()) {
2411 bus_profile.output_ac = AutoConnectMaster;
2412 } else if (_startup->connect_outs_to_physical()) {
2413 bus_profile.output_ac = AutoConnectPhysical;
2417 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2418 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2421 if (build_session (session_path, session_name, bus_profile)) {
2429 ARDOUR_UI::idle_load (const std::string& path)
2432 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2433 /* /path/to/foo => /path/to/foo, foo */
2434 load_session (path, basename_nosuffix (path));
2436 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2437 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2441 ARDOUR_COMMAND_LINE::session_name = path;
2444 * new_session_dialog doens't exist in A3
2445 * Try to remove all references to it to
2446 * see if it will compile. NOTE: this will
2447 * likely cause a runtime issue is my somewhat
2451 //if (new_session_dialog) {
2454 /* make it break out of Dialog::run() and
2458 //new_session_dialog->response (1);
2464 ARDOUR_UI::end_loading_messages ()
2470 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2473 // splash->message (msg);
2477 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2479 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2481 string session_name;
2482 string session_path;
2483 string template_name;
2485 bool likely_new = false;
2487 if (! load_template.empty()) {
2488 should_be_new = true;
2489 template_name = load_template;
2494 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2496 /* if they named a specific statefile, use it, otherwise they are
2497 just giving a session folder, and we want to use it as is
2498 to find the session.
2501 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2502 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2504 session_path = ARDOUR_COMMAND_LINE::session_name;
2507 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2511 bool const apply = run_startup (should_be_new, load_template);
2514 if (quit_on_cancel) {
2521 /* if we run the startup dialog again, offer more than just "new session" */
2523 should_be_new = false;
2525 session_name = _startup->session_name (likely_new);
2527 /* this shouldn't happen, but we catch it just in case it does */
2529 if (session_name.empty()) {
2533 if (_startup->use_session_template()) {
2534 template_name = _startup->session_template_name();
2535 _session_is_new = true;
2538 if (session_name[0] == G_DIR_SEPARATOR ||
2539 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2540 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2542 /* absolute path or cwd-relative path specified for session name: infer session folder
2543 from what was given.
2546 session_path = Glib::path_get_dirname (session_name);
2547 session_name = Glib::path_get_basename (session_name);
2551 session_path = _startup->session_folder();
2553 if (session_name.find ('/') != string::npos) {
2554 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2555 "session names may not contain a '/' character"));
2557 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2561 if (session_name.find ('\\') != string::npos) {
2562 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2563 "session names may not contain a '\\' character"));
2565 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2571 if (create_engine ()) {
2575 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2579 std::string existing = Glib::build_filename (session_path, session_name);
2581 if (!ask_about_loading_existing_session (existing)) {
2582 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2587 _session_is_new = false;
2592 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2594 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2598 if (session_name.find ('/') != std::string::npos) {
2599 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2600 "session names may not contain a '/' character"));
2602 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2606 if (session_name.find ('\\') != std::string::npos) {
2607 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2608 "session names may not contain a '\\' character"));
2610 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2614 _session_is_new = true;
2617 if (likely_new && template_name.empty()) {
2619 ret = build_session_from_nsd (session_path, session_name);
2623 ret = load_session (session_path, session_name, template_name);
2624 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2625 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2635 ARDOUR_UI::close_session()
2637 if (!check_audioengine()) {
2641 if (unload_session (true)) {
2645 ARDOUR_COMMAND_LINE::session_name = "";
2647 if (get_session_parameters (true, false)) {
2651 goto_editor_window ();
2655 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2657 Session *new_session;
2661 session_loaded = false;
2663 if (!check_audioengine()) {
2667 unload_status = unload_session ();
2669 if (unload_status < 0) {
2671 } else if (unload_status > 0) {
2676 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2679 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2682 /* this one is special */
2684 catch (AudioEngine::PortRegistrationFailure& err) {
2686 MessageDialog msg (err.what(),
2689 Gtk::BUTTONS_CLOSE);
2691 msg.set_title (_("Port Registration Error"));
2692 msg.set_secondary_text (_("Click the Close button to try again."));
2693 msg.set_position (Gtk::WIN_POS_CENTER);
2697 int response = msg.run ();
2702 case RESPONSE_CANCEL:
2712 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2717 msg.set_title (_("Loading Error"));
2718 msg.set_secondary_text (_("Click the Refresh button to try again."));
2719 msg.add_button (Stock::REFRESH, 1);
2720 msg.set_position (Gtk::WIN_POS_CENTER);
2724 int response = msg.run ();
2738 /* Now the session been created, add the transport controls */
2739 new_session->add_controllable(roll_controllable);
2740 new_session->add_controllable(stop_controllable);
2741 new_session->add_controllable(goto_start_controllable);
2742 new_session->add_controllable(goto_end_controllable);
2743 new_session->add_controllable(auto_loop_controllable);
2744 new_session->add_controllable(play_selection_controllable);
2745 new_session->add_controllable(rec_controllable);
2747 set_session (new_session);
2749 session_loaded = true;
2751 goto_editor_window ();
2754 _session->set_clean ();
2765 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2767 Session *new_session;
2770 if (!check_audioengine()) {
2774 session_loaded = false;
2776 x = unload_session ();
2784 _session_is_new = true;
2787 new_session = new Session (*engine, path, snap_name, &bus_profile);
2792 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2798 /* Give the new session the default GUI state, if such things exist */
2801 n = Config->instant_xml (X_("Editor"));
2803 new_session->add_instant_xml (*n, false);
2805 n = Config->instant_xml (X_("Mixer"));
2807 new_session->add_instant_xml (*n, false);
2810 set_session (new_session);
2812 session_loaded = true;
2814 new_session->save_state(new_session->name());
2820 ARDOUR_UI::launch_chat ()
2823 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2825 open_uri("http://webchat.freenode.net/?channels=ardour");
2830 ARDOUR_UI::show_about ()
2834 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2837 about->set_transient_for(*editor);
2842 ARDOUR_UI::launch_manual ()
2844 PBD::open_uri("http://ardour.org/flossmanual");
2848 ARDOUR_UI::launch_reference ()
2850 PBD::open_uri("http://ardour.org/refmanual");
2854 ARDOUR_UI::hide_about ()
2857 about->get_window()->set_cursor ();
2863 ARDOUR_UI::about_signal_response (int /*response*/)
2869 ARDOUR_UI::show_splash ()
2873 splash = new Splash;
2881 splash->queue_draw ();
2882 splash->get_window()->process_updates (true);
2887 ARDOUR_UI::hide_splash ()
2895 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2896 const string& plural_msg, const string& singular_msg)
2900 removed = rep.paths.size();
2903 MessageDialog msgd (*editor,
2904 _("No audio files were ready for cleanup"),
2907 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2908 msgd.set_secondary_text (_("If this seems suprising, \n\
2909 check for any existing snapshots.\n\
2910 These may still include regions that\n\
2911 require some unused files to continue to exist."));
2917 ArdourDialog results (_("Clean-up"), true, false);
2919 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2920 CleanupResultsModelColumns() {
2924 Gtk::TreeModelColumn<std::string> visible_name;
2925 Gtk::TreeModelColumn<std::string> fullpath;
2929 CleanupResultsModelColumns results_columns;
2930 Glib::RefPtr<Gtk::ListStore> results_model;
2931 Gtk::TreeView results_display;
2933 results_model = ListStore::create (results_columns);
2934 results_display.set_model (results_model);
2935 results_display.append_column (list_title, results_columns.visible_name);
2937 results_display.set_name ("CleanupResultsList");
2938 results_display.set_headers_visible (true);
2939 results_display.set_headers_clickable (false);
2940 results_display.set_reorderable (false);
2942 Gtk::ScrolledWindow list_scroller;
2945 Gtk::HBox dhbox; // the hbox for the image and text
2946 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2947 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2949 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2951 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2954 %1 - number of files removed
2955 %2 - location of "dead_sounds"
2956 %3 - size of files affected
2957 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2960 const char* bprefix;
2961 double space_adjusted = 0;
2963 if (rep.space < 100000.0f) {
2964 bprefix = X_("kilo");
2965 } else if (rep.space < 1000000.0f * 1000) {
2966 bprefix = X_("mega");
2967 space_adjusted = truncf((float)rep.space / 1000.0);
2969 bprefix = X_("giga");
2970 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2974 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2976 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2979 dhbox.pack_start (*dimage, true, false, 5);
2980 dhbox.pack_start (txt, true, false, 5);
2982 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2983 TreeModel::Row row = *(results_model->append());
2984 row[results_columns.visible_name] = *i;
2985 row[results_columns.fullpath] = *i;
2988 list_scroller.add (results_display);
2989 list_scroller.set_size_request (-1, 150);
2990 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2992 dvbox.pack_start (dhbox, true, false, 5);
2993 dvbox.pack_start (list_scroller, true, false, 5);
2994 ddhbox.pack_start (dvbox, true, false, 5);
2996 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2997 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2998 results.set_default_response (RESPONSE_CLOSE);
2999 results.set_position (Gtk::WIN_POS_MOUSE);
3001 results_display.show();
3002 list_scroller.show();
3009 //results.get_vbox()->show();
3010 results.set_resizable (false);
3017 ARDOUR_UI::cleanup ()
3019 if (_session == 0) {
3020 /* shouldn't happen: menu item is insensitive */
3025 MessageDialog checker (_("Are you sure you want to cleanup?"),
3027 Gtk::MESSAGE_QUESTION,
3028 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3030 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3031 ALL undo/redo information will be lost if you cleanup.\n\
3032 After cleanup, unused audio files will be moved to a \
3033 \"dead sounds\" location."));
3035 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3036 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3037 checker.set_default_response (RESPONSE_CANCEL);
3039 checker.set_name (_("CleanupDialog"));
3040 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3041 checker.set_position (Gtk::WIN_POS_MOUSE);
3043 switch (checker.run()) {
3044 case RESPONSE_ACCEPT:
3050 ARDOUR::CleanupReport rep;
3052 editor->prepare_for_cleanup ();
3054 /* do not allow flush until a session is reloaded */
3056 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3058 act->set_sensitive (false);
3061 if (_session->cleanup_sources (rep)) {
3062 editor->finish_cleanup ();
3066 editor->finish_cleanup ();
3069 display_cleanup_results (rep,
3072 The following %1 files were not in use and \n\
3073 have been moved to:\n\
3075 Flushing the wastebasket will \n\
3076 release an additional\n\
3077 %3 %4bytes of disk space.\n"),
3079 The following file was not in use and \n \
3080 has been moved to:\n \
3082 Flushing the wastebasket will \n\
3083 release an additional\n\
3084 %3 %4bytes of disk space.\n"
3090 ARDOUR_UI::flush_trash ()
3092 if (_session == 0) {
3093 /* shouldn't happen: menu item is insensitive */
3097 ARDOUR::CleanupReport rep;
3099 if (_session->cleanup_trash_sources (rep)) {
3103 display_cleanup_results (rep,
3105 _("The following %1 files were deleted from\n\
3107 releasing %3 %4bytes of disk space"),
3108 _("The following file was deleted from\n\
3110 releasing %3 %4bytes of disk space"));
3114 ARDOUR_UI::add_route (Gtk::Window* float_window)
3122 if (add_route_dialog == 0) {
3123 add_route_dialog = new AddRouteDialog (_session);
3125 add_route_dialog->set_transient_for (*float_window);
3129 if (add_route_dialog->is_visible()) {
3130 /* we're already doing this */
3134 ResponseType r = (ResponseType) add_route_dialog->run ();
3136 add_route_dialog->hide();
3139 case RESPONSE_ACCEPT:
3146 if ((count = add_route_dialog->count()) <= 0) {
3150 string template_path = add_route_dialog->track_template();
3152 if (!template_path.empty()) {
3153 _session->new_route_from_template (count, template_path);
3157 uint32_t input_chan = add_route_dialog->channels ();
3158 uint32_t output_chan;
3159 string name_template = add_route_dialog->name_template ();
3160 bool track = add_route_dialog->track ();
3161 bool aux = !track && add_route_dialog->aux();
3162 RouteGroup* route_group = add_route_dialog->route_group ();
3164 AutoConnectOption oac = Config->get_output_auto_connect();
3166 if (oac & AutoConnectMaster) {
3167 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3169 output_chan = input_chan;
3172 /* XXX do something with name template */
3174 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3176 session_add_midi_track (route_group, count);
3178 MessageDialog msg (*editor,
3179 _("Sorry, MIDI Busses are not supported at this time."));
3181 //session_add_midi_bus();
3185 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3187 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3193 ARDOUR_UI::mixer_settings () const
3198 node = _session->instant_xml(X_("Mixer"));
3200 node = Config->instant_xml(X_("Mixer"));
3204 node = new XMLNode (X_("Mixer"));
3211 ARDOUR_UI::editor_settings () const
3216 node = _session->instant_xml(X_("Editor"));
3218 node = Config->instant_xml(X_("Editor"));
3222 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3223 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3228 node = new XMLNode (X_("Editor"));
3235 ARDOUR_UI::keyboard_settings () const
3239 node = Config->extra_xml(X_("Keyboard"));
3242 node = new XMLNode (X_("Keyboard"));
3248 ARDOUR_UI::create_xrun_marker(nframes_t where)
3250 editor->mouse_add_new_marker (where, false, true);
3254 ARDOUR_UI::halt_on_xrun_message ()
3256 MessageDialog msg (*editor,
3257 _("Recording was stopped because your system could not keep up."));
3262 ARDOUR_UI::xrun_handler(nframes_t where)
3268 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3270 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3271 create_xrun_marker(where);
3274 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3275 halt_on_xrun_message ();
3280 ARDOUR_UI::disk_overrun_handler ()
3282 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3284 if (!have_disk_speed_dialog_displayed) {
3285 have_disk_speed_dialog_displayed = true;
3286 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3287 The disk system on your computer\n\
3288 was not able to keep up with %1.\n\
3290 Specifically, it failed to write data to disk\n\
3291 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3292 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3298 ARDOUR_UI::disk_underrun_handler ()
3300 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3302 if (!have_disk_speed_dialog_displayed) {
3303 have_disk_speed_dialog_displayed = true;
3304 MessageDialog* msg = new MessageDialog (*editor,
3305 string_compose (_("The disk system on your computer\n\
3306 was not able to keep up with %1.\n\
3308 Specifically, it failed to read data from disk\n\
3309 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3310 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3316 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3318 have_disk_speed_dialog_displayed = false;
3323 ARDOUR_UI::session_dialog (std::string msg)
3325 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3330 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3332 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3341 ARDOUR_UI::pending_state_dialog ()
3343 HBox* hbox = new HBox();
3344 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3345 ArdourDialog dialog (_("Crash Recovery"), true);
3347 This session appears to have been in\n\
3348 middle of recording when ardour or\n\
3349 the computer was shutdown.\n\
3351 Ardour can recover any captured audio for\n\
3352 you, or it can ignore it. Please decide\n\
3353 what you would like to do.\n"));
3354 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3355 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3356 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3357 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3358 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3359 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3360 dialog.set_default_response (RESPONSE_ACCEPT);
3361 dialog.set_position (WIN_POS_CENTER);
3366 switch (dialog.run ()) {
3367 case RESPONSE_ACCEPT:
3375 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3377 HBox* hbox = new HBox();
3378 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3379 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3380 Label message (string_compose (_("\
3381 This session was created with a sample rate of %1 Hz\n\
3383 The audioengine is currently running at %2 Hz\n"), desired, actual));
3385 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3386 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3387 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3388 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3389 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3390 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3391 dialog.set_default_response (RESPONSE_ACCEPT);
3392 dialog.set_position (WIN_POS_CENTER);
3397 switch (dialog.run ()) {
3398 case RESPONSE_ACCEPT:
3407 ARDOUR_UI::disconnect_from_jack ()
3410 if( engine->disconnect_from_jack ()) {
3411 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3415 update_sample_rate (0);
3420 ARDOUR_UI::reconnect_to_jack ()
3423 if (engine->reconnect_to_jack ()) {
3424 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3428 update_sample_rate (0);
3433 ARDOUR_UI::use_config ()
3435 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3437 set_transport_controllable_state (*node);
3442 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3444 if (Config->get_primary_clock_delta_edit_cursor()) {
3445 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3447 primary_clock.set (pos, 0, true);
3450 if (Config->get_secondary_clock_delta_edit_cursor()) {
3451 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3453 secondary_clock.set (pos);
3456 if (big_clock_window->get()) {
3457 big_clock.set (pos);
3463 ARDOUR_UI::step_edit_status_change (bool yn)
3465 // XXX should really store pre-step edit status of things
3466 // we make insensitive
3469 rec_button.set_visual_state (3);
3470 rec_button.set_sensitive (false);
3472 rec_button.set_visual_state (0);
3473 rec_button.set_sensitive (true);
3478 ARDOUR_UI::record_state_changed ()
3480 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3482 if (!_session || !big_clock_window->get()) {
3483 /* why bother - the clock isn't visible */
3487 Session::RecordState const r = _session->record_status ();
3488 bool const h = _session->have_rec_enabled_track ();
3490 if (r == Session::Recording && h) {
3491 big_clock.set_widget_name ("BigClockRecording");
3493 big_clock.set_widget_name ("BigClockNonRecording");
3498 ARDOUR_UI::first_idle ()
3501 _session->allow_auto_play (true);
3505 editor->first_idle();
3508 Keyboard::set_can_save_keybindings (true);
3513 ARDOUR_UI::store_clock_modes ()
3515 XMLNode* node = new XMLNode(X_("ClockModes"));
3517 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3518 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3521 _session->add_extra_xml (*node);
3522 _session->set_dirty ();
3527 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3528 : Controllable (name), ui (u), type(tp)
3534 ARDOUR_UI::TransportControllable::set_value (double val)
3536 if (type == ShuttleControl) {
3543 fract = -((0.5 - val)/0.5);
3545 fract = ((val - 0.5)/0.5);
3549 ui.set_shuttle_fract (fract);
3554 /* do nothing: these are radio-style actions */
3558 const char *action = 0;
3562 action = X_("Roll");
3565 action = X_("Stop");
3568 action = X_("Goto Start");
3571 action = X_("Goto End");
3574 action = X_("Loop");
3577 action = X_("Play Selection");
3580 action = X_("Record");
3590 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3598 ARDOUR_UI::TransportControllable::get_value (void) const
3617 case ShuttleControl:
3627 ARDOUR_UI::TransportControllable::set_id (const string& str)
3633 ARDOUR_UI::setup_profile ()
3635 if (gdk_screen_width() < 1200) {
3636 Profile->set_small_screen ();
3640 if (getenv ("ARDOUR_SAE")) {
3641 Profile->set_sae ();
3642 Profile->set_single_package ();
3647 ARDOUR_UI::toggle_translations ()
3649 using namespace Glib;
3651 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3653 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3656 string i18n_killer = ARDOUR::translation_kill_path();
3658 bool already_enabled = !ARDOUR::translations_are_disabled ();
3660 if (ract->get_active ()) {
3661 /* we don't care about errors */
3662 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3665 /* we don't care about errors */
3666 unlink (i18n_killer.c_str());
3669 if (already_enabled != ract->get_active()) {
3670 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3672 Gtk::MESSAGE_WARNING,
3674 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3675 win.set_position (Gtk::WIN_POS_CENTER);
3683 /** Add a window proxy to our list, so that its state will be saved.
3684 * This call also causes the window to be created and opened if its
3685 * state was saved as `visible'.
3688 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3690 _window_proxies.push_back (p);
3694 /** Remove a window proxy from our list. Must be called if a WindowProxy
3695 * is deleted, to prevent hanging pointers.
3698 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3700 _window_proxies.remove (p);
3704 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3706 MissingFileDialog dialog (s, str, type);
3711 int result = dialog.run ();
3718 return 1; // quit entire session load
3721 result = dialog.get_action ();