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"
109 #include "missing_plugin_dialog.h"
113 using namespace ARDOUR;
115 using namespace Gtkmm2ext;
118 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
119 UIConfiguration *ARDOUR_UI::ui_config = 0;
121 sigc::signal<void,bool> ARDOUR_UI::Blink;
122 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
123 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
124 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
126 bool could_be_a_valid_path (const string& path);
128 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
130 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
132 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
133 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
134 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
135 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
139 preroll_button (_("pre\nroll")),
140 postroll_button (_("post\nroll")),
144 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
148 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
149 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
150 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
151 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
152 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
153 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
154 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
155 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
156 shuttle_controller_binding_proxy (shuttle_controllable),
158 roll_button (roll_controllable),
159 stop_button (stop_controllable),
160 goto_start_button (goto_start_controllable),
161 goto_end_button (goto_end_controllable),
162 auto_loop_button (auto_loop_controllable),
163 play_selection_button (play_selection_controllable),
164 rec_button (rec_controllable),
166 shuttle_units_button (_("% ")),
168 punch_in_button (_("Punch In")),
169 punch_out_button (_("Punch Out")),
170 auto_return_button (_("Auto Return")),
171 auto_play_button (_("Auto Play")),
172 auto_input_button (_("Auto Input")),
173 click_button (_("Click")),
174 time_master_button (_("time\nmaster")),
176 auditioning_alert_button (_("AUDITION")),
177 solo_alert_button (_("SOLO")),
178 _menu_bar_clock (X_("menu_bar"), false, X_("MenuBarClock"), true, true, false, false),
180 error_log_button (_("Errors"))
183 using namespace Gtk::Menu_Helpers;
189 // _auto_display_errors = false;
191 * This was commented out as it wasn't defined
192 * in A3 IIRC. If this is not needed it should
193 * be completely removed.
201 if (theArdourUI == 0) {
205 ui_config = new UIConfiguration();
206 theme_manager = new ThemeManager();
212 _session_is_new = false;
213 big_clock_window = 0;
214 big_clock_height = 0;
215 big_clock_resize_in_progress = false;
216 session_selector_window = 0;
217 last_key_press_time = 0;
218 _will_create_new_session_automatically = false;
219 add_route_dialog = 0;
221 rc_option_editor = 0;
222 session_option_editor = 0;
224 open_session_selector = 0;
225 have_configure_timeout = false;
226 have_disk_speed_dialog_displayed = false;
227 session_loaded = false;
228 last_speed_displayed = -1.0f;
229 ignore_dual_punch = false;
230 original_big_clock_width = -1;
231 original_big_clock_height = -1;
232 original_big_clock_font_size = 0;
234 roll_button.unset_flags (Gtk::CAN_FOCUS);
235 stop_button.unset_flags (Gtk::CAN_FOCUS);
236 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
237 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
238 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
239 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
240 rec_button.unset_flags (Gtk::CAN_FOCUS);
242 last_configure_time= 0;
244 shuttle_grabbed = false;
246 shuttle_max_speed = 8.0f;
248 shuttle_style_menu = 0;
249 shuttle_unit_menu = 0;
251 // We do not have jack linked in yet so;
253 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
255 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
256 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
258 /* handle dialog requests */
260 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
262 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
264 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
266 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
268 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
270 /* handle requests to quit (coming from JACK session) */
272 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
274 /* handle requests to deal with missing files */
276 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
278 /* lets get this party started */
281 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
282 throw failed_constructor ();
285 setup_gtk_ardour_enums ();
288 GainMeter::setup_slider_pix ();
289 RouteTimeAxisView::setup_slider_pix ();
290 SendProcessorEntry::setup_slider_pix ();
291 SessionEvent::create_per_thread_pool ("GUI", 512);
293 } catch (failed_constructor& err) {
294 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
299 /* we like keyboards */
301 keyboard = new ArdourKeyboard(*this);
303 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
305 keyboard->set_state (*node, Stateful::loading_state_version);
310 TimeAxisViewItem::set_constant_heights ();
312 /* The following must happen after ARDOUR::init() so that Config is set up */
314 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
315 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
317 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
318 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
319 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
320 Config->extra_xml (X_("UI")),
321 string_compose ("toggle-%1-connection-manager", (*i).to_string())
327 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
328 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
333 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
335 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
338 _startup = new ArdourStartup ();
340 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
342 if (audio_setup && _startup->engine_control()) {
343 _startup->engine_control()->set_state (*audio_setup);
346 _startup->set_new_only (should_be_new);
347 if (!load_template.empty()) {
348 _startup->set_load_template( load_template );
350 _startup->present ();
356 switch (_startup->response()) {
365 ARDOUR_UI::create_engine ()
367 // this gets called every time by new_session()
373 loading_message (_("Starting audio engine"));
376 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
383 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
384 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
385 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
387 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
389 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
397 ARDOUR_UI::post_engine ()
399 /* Things to be done once we create the AudioEngine
402 ARDOUR::init_post_engine ();
404 ActionManager::init ();
407 if (setup_windows ()) {
408 throw failed_constructor ();
411 check_memory_locking();
413 /* this is the first point at which all the keybindings are available */
415 if (ARDOUR_COMMAND_LINE::show_key_actions) {
416 vector<string> names;
417 vector<string> paths;
419 vector<AccelKey> bindings;
421 ActionManager::get_all_actions (names, paths, keys, bindings);
423 vector<string>::iterator n;
424 vector<string>::iterator k;
425 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
426 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
432 blink_timeout_tag = -1;
434 /* this being a GUI and all, we want peakfiles */
436 AudioFileSource::set_build_peakfiles (true);
437 AudioFileSource::set_build_missing_peakfiles (true);
439 /* set default clock modes */
441 if (Profile->get_sae()) {
442 primary_clock.set_mode (AudioClock::BBT);
443 secondary_clock.set_mode (AudioClock::MinSec);
445 primary_clock.set_mode (AudioClock::Timecode);
446 secondary_clock.set_mode (AudioClock::BBT);
449 /* start the time-of-day-clock */
452 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
453 update_wall_clock ();
454 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
457 update_disk_space ();
459 update_sample_rate (engine->frame_rate());
461 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
462 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
463 Config->map_parameters (pc);
465 /* now start and maybe save state */
467 if (do_engine_start () == 0) {
468 if (_session && _session_is_new) {
469 /* we need to retain initial visual
470 settings for a new session
472 _session->save_state ("");
477 ARDOUR_UI::~ARDOUR_UI ()
482 delete add_route_dialog;
486 ARDOUR_UI::pop_back_splash ()
488 if (Splash::instance()) {
489 // Splash::instance()->pop_back();
490 Splash::instance()->hide ();
495 ARDOUR_UI::configure_timeout ()
497 if (last_configure_time == 0) {
498 /* no configure events yet */
502 /* force a gap of 0.5 seconds since the last configure event
505 if (get_microseconds() - last_configure_time < 500000) {
508 have_configure_timeout = false;
509 cerr << "config event-driven save\n";
510 save_ardour_state ();
516 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
518 if (have_configure_timeout) {
519 last_configure_time = get_microseconds();
521 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
522 have_configure_timeout = true;
529 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
531 const XMLProperty* prop;
533 if ((prop = node.property ("roll")) != 0) {
534 roll_controllable->set_id (prop->value());
536 if ((prop = node.property ("stop")) != 0) {
537 stop_controllable->set_id (prop->value());
539 if ((prop = node.property ("goto-start")) != 0) {
540 goto_start_controllable->set_id (prop->value());
542 if ((prop = node.property ("goto-end")) != 0) {
543 goto_end_controllable->set_id (prop->value());
545 if ((prop = node.property ("auto-loop")) != 0) {
546 auto_loop_controllable->set_id (prop->value());
548 if ((prop = node.property ("play-selection")) != 0) {
549 play_selection_controllable->set_id (prop->value());
551 if ((prop = node.property ("rec")) != 0) {
552 rec_controllable->set_id (prop->value());
554 if ((prop = node.property ("shuttle")) != 0) {
555 shuttle_controllable->set_id (prop->value());
560 ARDOUR_UI::get_transport_controllable_state ()
562 XMLNode* node = new XMLNode(X_("TransportControllables"));
565 roll_controllable->id().print (buf, sizeof (buf));
566 node->add_property (X_("roll"), buf);
567 stop_controllable->id().print (buf, sizeof (buf));
568 node->add_property (X_("stop"), buf);
569 goto_start_controllable->id().print (buf, sizeof (buf));
570 node->add_property (X_("goto_start"), buf);
571 goto_end_controllable->id().print (buf, sizeof (buf));
572 node->add_property (X_("goto_end"), buf);
573 auto_loop_controllable->id().print (buf, sizeof (buf));
574 node->add_property (X_("auto_loop"), buf);
575 play_selection_controllable->id().print (buf, sizeof (buf));
576 node->add_property (X_("play_selection"), buf);
577 rec_controllable->id().print (buf, sizeof (buf));
578 node->add_property (X_("rec"), buf);
579 shuttle_controllable->id().print (buf, sizeof (buf));
580 node->add_property (X_("shuttle"), buf);
587 ARDOUR_UI::autosave_session ()
589 if (g_main_depth() > 1) {
590 /* inside a recursive main loop,
591 give up because we may not be able to
597 if (!Config->get_periodic_safety_backups()) {
602 _session->maybe_write_autosave();
609 ARDOUR_UI::update_autosave ()
611 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
613 if (_session && _session->dirty()) {
614 if (_autosave_connection.connected()) {
615 _autosave_connection.disconnect();
618 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
619 Config->get_periodic_safety_backup_interval() * 1000);
622 if (_autosave_connection.connected()) {
623 _autosave_connection.disconnect();
629 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
633 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
635 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
638 MessageDialog win (title,
644 win.set_secondary_text(_("There are several possible reasons:\n\
646 1) You requested audio parameters that are not supported..\n\
647 2) JACK is running as another user.\n\
649 Please consider the possibilities, and perhaps try different parameters."));
651 win.set_secondary_text(_("There are several possible reasons:\n\
653 1) JACK is not running.\n\
654 2) JACK is running as another user, perhaps root.\n\
655 3) There is already another client called \"ardour\".\n\
657 Please consider the possibilities, and perhaps (re)start JACK."));
661 win.set_transient_for (*toplevel);
665 win.add_button (Stock::OK, RESPONSE_CLOSE);
667 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
670 win.set_default_response (RESPONSE_CLOSE);
673 win.set_position (Gtk::WIN_POS_CENTER);
676 /* we just don't care about the result, but we want to block */
682 ARDOUR_UI::startup ()
684 Application* app = Application::instance ();
686 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
687 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
690 call_the_mothership (VERSIONSTRING);
695 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
701 goto_editor_window ();
703 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
704 to be opened on top of the editor window that goto_editor_window() just opened.
706 add_window_proxy (location_ui);
707 add_window_proxy (big_clock_window);
708 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
709 add_window_proxy (_global_port_matrix[*i]);
712 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
716 ARDOUR_UI::no_memory_warning ()
718 XMLNode node (X_("no-memory-warning"));
719 Config->add_instant_xml (node);
723 ARDOUR_UI::check_memory_locking ()
726 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
730 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
732 if (engine->is_realtime() && memory_warning_node == 0) {
734 struct rlimit limits;
736 long pages, page_size;
738 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
741 ram = (int64_t) pages * (int64_t) page_size;
744 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
748 if (limits.rlim_cur != RLIM_INFINITY) {
750 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
754 string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
755 "This might cause %1 to run out of memory before your system "
756 "runs out of memory. \n\n"
757 "You can view the memory limit with 'ulimit -l', "
758 "and it is normally controlled by /etc/security/limits.conf"),
759 PROGRAM_NAME).c_str());
761 VBox* vbox = msg.get_vbox();
763 CheckButton cb (_("Do not show this window again"));
765 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
767 hbox.pack_start (cb, true, false);
768 vbox->pack_start (hbox);
775 editor->ensure_float (msg);
785 ARDOUR_UI::queue_finish ()
787 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
791 ARDOUR_UI::idle_finish ()
794 return false; /* do not call again */
803 if (_session->transport_rolling() && (++tries < 8)) {
804 _session->request_stop (false, true);
808 if (_session->dirty()) {
809 switch (ask_about_saving_session(_("quit"))) {
814 /* use the default name */
815 if (save_state_canfail ("")) {
816 /* failed - don't quit */
817 MessageDialog msg (*editor,
819 Ardour was unable to save your session.\n\n\
820 If you still wish to quit, please use the\n\n\
821 \"Just quit\" option."));
832 second_connection.disconnect ();
833 point_one_second_connection.disconnect ();
834 point_oh_five_second_connection.disconnect ();
835 point_zero_one_second_connection.disconnect();
838 /* Save state before deleting the session, as that causes some
839 windows to be destroyed before their visible state can be
842 save_ardour_state ();
845 // _session->set_deletion_in_progress ();
846 _session->set_clean ();
847 _session->remove_pending_capture_state ();
852 ArdourDialog::close_all_dialogs ();
858 ARDOUR_UI::ask_about_saving_session (const string & what)
860 ArdourDialog window (_("Unsaved Session"));
861 Gtk::HBox dhbox; // the hbox for the image and text
862 Gtk::Label prompt_label;
863 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
867 msg = string_compose(_("Don't %1"), what);
868 window.add_button (msg, RESPONSE_REJECT);
869 msg = string_compose(_("Just %1"), what);
870 window.add_button (msg, RESPONSE_APPLY);
871 msg = string_compose(_("Save and %1"), what);
872 window.add_button (msg, RESPONSE_ACCEPT);
874 window.set_default_response (RESPONSE_ACCEPT);
876 Gtk::Button noquit_button (msg);
877 noquit_button.set_name ("EditorGTKButton");
882 if (_session->snap_name() == _session->name()) {
885 type = _("snapshot");
887 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?"),
888 type, _session->snap_name());
890 prompt_label.set_text (prompt);
891 prompt_label.set_name (X_("PrompterLabel"));
892 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
894 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
895 dhbox.set_homogeneous (false);
896 dhbox.pack_start (*dimage, false, false, 5);
897 dhbox.pack_start (prompt_label, true, false, 5);
898 window.get_vbox()->pack_start (dhbox);
900 window.set_name (_("Prompter"));
901 window.set_position (Gtk::WIN_POS_MOUSE);
902 window.set_modal (true);
903 window.set_resizable (false);
909 window.set_keep_above (true);
912 ResponseType r = (ResponseType) window.run();
917 case RESPONSE_ACCEPT: // save and get out of here
919 case RESPONSE_APPLY: // get out of here
929 ARDOUR_UI::every_second ()
932 update_buffer_load ();
933 update_disk_space ();
938 ARDOUR_UI::every_point_one_seconds ()
940 update_speed_display ();
941 RapidScreenUpdate(); /* EMIT_SIGNAL */
946 ARDOUR_UI::every_point_zero_one_seconds ()
948 // august 2007: actual update frequency: 40Hz, not 100Hz
950 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
955 ARDOUR_UI::update_sample_rate (nframes_t)
959 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
961 if (!engine->connected()) {
963 snprintf (buf, sizeof (buf), _("disconnected"));
967 nframes_t rate = engine->frame_rate();
969 if (fmod (rate, 1000.0) != 0.0) {
970 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
971 (float) rate/1000.0f,
972 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
974 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
976 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
980 sample_rate_label.set_text (buf);
984 ARDOUR_UI::update_cpu_load ()
987 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
988 cpu_load_label.set_text (buf);
992 ARDOUR_UI::update_buffer_load ()
998 c = _session->capture_load ();
999 p = _session->playback_load ();
1001 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
1002 _session->playback_load(), _session->capture_load());
1003 buffer_load_label.set_text (buf);
1005 buffer_load_label.set_text ("");
1010 ARDOUR_UI::count_recenabled_streams (Route& route)
1012 Track* track = dynamic_cast<Track*>(&route);
1013 if (track && track->record_enabled()) {
1014 rec_enabled_streams += track->n_inputs().n_total();
1019 ARDOUR_UI::update_disk_space()
1021 if (_session == 0) {
1025 framecnt_t frames = _session->available_capture_duration();
1027 nframes_t fr = _session->frame_rate();
1029 if (frames == max_framecnt) {
1030 strcpy (buf, _("Disk: 24hrs+"));
1032 rec_enabled_streams = 0;
1033 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1035 if (rec_enabled_streams) {
1036 frames /= rec_enabled_streams;
1043 hrs = frames / (fr * 3600);
1044 frames -= hrs * fr * 3600;
1045 mins = frames / (fr * 60);
1046 frames -= mins * fr * 60;
1049 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1052 disk_space_label.set_text (buf);
1054 // An attempt to make the disk space label flash red when space has run out.
1056 if (frames < fr * 60 * 5) {
1057 /* disk_space_box.style ("disk_space_label_empty"); */
1059 /* disk_space_box.style ("disk_space_label"); */
1065 ARDOUR_UI::update_wall_clock ()
1072 tm_now = localtime (&now);
1074 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1075 wall_clock_label.set_text (buf);
1081 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1083 session_popup_menu->popup (0, 0);
1088 ARDOUR_UI::redisplay_recent_sessions ()
1090 std::vector<sys::path> session_directories;
1091 RecentSessionsSorter cmp;
1093 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1094 recent_session_model->clear ();
1096 ARDOUR::RecentSessions rs;
1097 ARDOUR::read_recent_sessions (rs);
1100 recent_session_display.set_model (recent_session_model);
1104 // sort them alphabetically
1105 sort (rs.begin(), rs.end(), cmp);
1107 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1108 session_directories.push_back ((*i).second);
1111 for (vector<sys::path>::const_iterator i = session_directories.begin();
1112 i != session_directories.end(); ++i)
1114 std::vector<sys::path> state_file_paths;
1116 // now get available states for this session
1118 get_state_files_in_directory (*i, state_file_paths);
1120 vector<string*>* states;
1121 vector<const gchar*> item;
1122 string fullpath = (*i).to_string();
1124 /* remove any trailing / */
1126 if (fullpath[fullpath.length()-1] == '/') {
1127 fullpath = fullpath.substr (0, fullpath.length()-1);
1130 /* check whether session still exists */
1131 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1132 /* session doesn't exist */
1133 cerr << "skipping non-existent session " << fullpath << endl;
1137 /* now get available states for this session */
1139 if ((states = Session::possible_states (fullpath)) == 0) {
1140 /* no state file? */
1144 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1146 Gtk::TreeModel::Row row = *(recent_session_model->append());
1148 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1149 row[recent_session_columns.fullpath] = fullpath;
1151 if (state_file_names.size() > 1) {
1155 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1156 i2 != state_file_names.end(); ++i2)
1159 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1161 child_row[recent_session_columns.visible_name] = *i2;
1162 child_row[recent_session_columns.fullpath] = fullpath;
1167 recent_session_display.set_model (recent_session_model);
1171 ARDOUR_UI::build_session_selector ()
1173 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1175 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1177 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1178 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1179 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1180 recent_session_model = TreeStore::create (recent_session_columns);
1181 recent_session_display.set_model (recent_session_model);
1182 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1183 recent_session_display.set_headers_visible (false);
1184 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1185 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1187 scroller->add (recent_session_display);
1188 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1190 session_selector_window->set_name ("SessionSelectorWindow");
1191 session_selector_window->set_size_request (200, 400);
1192 session_selector_window->get_vbox()->pack_start (*scroller);
1194 recent_session_display.show();
1196 //session_selector_window->get_vbox()->show();
1200 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1202 session_selector_window->response (RESPONSE_ACCEPT);
1206 ARDOUR_UI::open_recent_session ()
1208 bool can_return = (_session != 0);
1210 if (session_selector_window == 0) {
1211 build_session_selector ();
1214 redisplay_recent_sessions ();
1218 session_selector_window->set_position (WIN_POS_MOUSE);
1220 ResponseType r = (ResponseType) session_selector_window->run ();
1223 case RESPONSE_ACCEPT:
1227 session_selector_window->hide();
1234 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1238 session_selector_window->hide();
1240 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1242 if (i == recent_session_model->children().end()) {
1246 std::string path = (*i)[recent_session_columns.fullpath];
1247 std::string state = (*i)[recent_session_columns.visible_name];
1249 _session_is_new = false;
1251 if (load_session (path, state) == 0) {
1260 ARDOUR_UI::check_audioengine ()
1263 if (!engine->connected()) {
1264 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1265 "You cannot open or close sessions in this condition"),
1278 ARDOUR_UI::open_session ()
1280 if (!check_audioengine()) {
1285 /* popup selector window */
1287 if (open_session_selector == 0) {
1289 /* ardour sessions are folders */
1291 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1292 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1293 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1294 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1296 FileFilter session_filter;
1297 session_filter.add_pattern ("*.ardour");
1298 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1299 open_session_selector->add_filter (session_filter);
1300 open_session_selector->set_filter (session_filter);
1303 int response = open_session_selector->run();
1304 open_session_selector->hide ();
1307 case RESPONSE_ACCEPT:
1310 open_session_selector->hide();
1314 open_session_selector->hide();
1315 string session_path = open_session_selector->get_filename();
1319 if (session_path.length() > 0) {
1320 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1321 _session_is_new = isnew;
1322 load_session (path, name);
1329 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1331 list<boost::shared_ptr<MidiTrack> > tracks;
1333 if (_session == 0) {
1334 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1341 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1343 if (tracks.size() != how_many) {
1344 if (how_many == 1) {
1345 error << _("could not create a new midi track") << endmsg;
1347 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1351 if ((route = _session->new_midi_route ()) == 0) {
1352 error << _("could not create new midi bus") << endmsg;
1358 MessageDialog msg (*editor,
1359 string_compose (_("There are insufficient JACK ports available\n\
1360 to create a new track or bus.\n\
1361 You should save %1, exit and\n\
1362 restart JACK with more ports."), PROGRAM_NAME));
1369 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)
1371 list<boost::shared_ptr<AudioTrack> > tracks;
1374 if (_session == 0) {
1375 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1381 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1383 if (tracks.size() != how_many) {
1384 if (how_many == 1) {
1385 error << _("could not create a new audio track") << endmsg;
1387 error << string_compose (_("could only create %1 of %2 new audio %3"),
1388 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1394 routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1396 if (routes.size() != how_many) {
1397 if (how_many == 1) {
1398 error << _("could not create a new audio track") << endmsg;
1400 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1407 MessageDialog msg (*editor,
1408 string_compose (_("There are insufficient JACK ports available\n\
1409 to create a new track or bus.\n\
1410 You should save %1, exit and\n\
1411 restart JACK with more ports."), PROGRAM_NAME));
1418 ARDOUR_UI::do_transport_locate (nframes_t new_position, bool with_roll)
1420 nframes_t _preroll = 0;
1423 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1424 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1426 if (new_position > _preroll) {
1427 new_position -= _preroll;
1432 _session->request_locate (new_position, with_roll);
1437 ARDOUR_UI::transport_goto_start ()
1440 _session->goto_start();
1442 /* force displayed area in editor to start no matter
1443 what "follow playhead" setting is.
1447 editor->center_screen (_session->current_start_frame ());
1453 ARDOUR_UI::transport_goto_zero ()
1456 _session->request_locate (0);
1458 /* force displayed area in editor to start no matter
1459 what "follow playhead" setting is.
1463 editor->reset_x_origin (0);
1469 ARDOUR_UI::transport_goto_wallclock ()
1471 if (_session && editor) {
1478 localtime_r (&now, &tmnow);
1480 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1481 frames += tmnow.tm_min * (60 * _session->frame_rate());
1482 frames += tmnow.tm_sec * _session->frame_rate();
1484 _session->request_locate (frames, _session->transport_rolling ());
1486 /* force displayed area in editor to start no matter
1487 what "follow playhead" setting is.
1491 editor->center_screen (frames);
1497 ARDOUR_UI::transport_goto_end ()
1500 nframes_t const frame = _session->current_end_frame();
1501 _session->request_locate (frame);
1503 /* force displayed area in editor to start no matter
1504 what "follow playhead" setting is.
1508 editor->center_screen (frame);
1514 ARDOUR_UI::transport_stop ()
1520 if (_session->is_auditioning()) {
1521 _session->cancel_audition ();
1525 _session->request_stop (false, true);
1529 ARDOUR_UI::transport_stop_and_forget_capture ()
1532 _session->request_stop (true, true);
1537 ARDOUR_UI::remove_last_capture()
1540 editor->remove_last_capture();
1545 ARDOUR_UI::transport_record (bool roll)
1549 switch (_session->record_status()) {
1550 case Session::Disabled:
1551 if (_session->ntracks() == 0) {
1552 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1556 _session->maybe_enable_record ();
1561 case Session::Recording:
1563 _session->request_stop();
1565 _session->disable_record (false, true);
1569 case Session::Enabled:
1570 _session->disable_record (false, true);
1573 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1577 ARDOUR_UI::transport_roll ()
1583 if (_session->is_auditioning()) {
1587 if (_session->config.get_external_sync()) {
1588 switch (_session->config.get_sync_source()) {
1592 /* transport controlled by the master */
1597 bool rolling = _session->transport_rolling();
1599 if (_session->get_play_loop()) {
1600 /* XXX it is not possible to just leave seamless loop and keep
1601 playing at present (nov 4th 2009)
1603 if (!Config->get_seamless_loop()) {
1604 _session->request_play_loop (false, true);
1606 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1607 /* stop playing a range if we currently are */
1608 _session->request_play_range (0, true);
1611 if (join_play_range_button.get_active()) {
1612 _session->request_play_range (&editor->get_selection().time, true);
1616 _session->request_transport_speed (1.0f);
1621 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1628 if (_session->is_auditioning()) {
1629 _session->cancel_audition ();
1633 if (_session->config.get_external_sync()) {
1634 switch (_session->config.get_sync_source()) {
1638 /* transport controlled by the master */
1643 bool rolling = _session->transport_rolling();
1644 bool affect_transport = true;
1646 if (rolling && roll_out_of_bounded_mode) {
1647 /* drop out of loop/range playback but leave transport rolling */
1648 if (_session->get_play_loop()) {
1649 if (Config->get_seamless_loop()) {
1650 /* the disk buffers contain copies of the loop - we can't
1651 just keep playing, so stop the transport. the user
1652 can restart as they wish.
1654 affect_transport = true;
1656 /* disk buffers are normal, so we can keep playing */
1657 affect_transport = false;
1659 _session->request_play_loop (false, true);
1660 } else if (_session->get_play_range ()) {
1661 affect_transport = false;
1662 _session->request_play_range (0, true);
1666 if (affect_transport) {
1668 _session->request_stop (with_abort, true);
1670 if (join_play_range_button.get_active()) {
1671 _session->request_play_range (&editor->get_selection().time, true);
1674 _session->request_transport_speed (1.0f);
1680 ARDOUR_UI::toggle_session_auto_loop ()
1683 if (_session->get_play_loop()) {
1684 if (_session->transport_rolling()) {
1685 Location * looploc = _session->locations()->auto_loop_location();
1687 _session->request_locate (looploc->start(), true);
1690 _session->request_play_loop (false);
1693 Location * looploc = _session->locations()->auto_loop_location();
1695 _session->request_play_loop (true);
1702 ARDOUR_UI::transport_play_selection ()
1708 editor->play_selection ();
1712 ARDOUR_UI::transport_rewind (int option)
1714 float current_transport_speed;
1717 current_transport_speed = _session->transport_speed();
1719 if (current_transport_speed >= 0.0f) {
1722 _session->request_transport_speed (-1.0f);
1725 _session->request_transport_speed (-4.0f);
1728 _session->request_transport_speed (-0.5f);
1733 _session->request_transport_speed (current_transport_speed * 1.5f);
1739 ARDOUR_UI::transport_forward (int option)
1741 float current_transport_speed;
1744 current_transport_speed = _session->transport_speed();
1746 if (current_transport_speed <= 0.0f) {
1749 _session->request_transport_speed (1.0f);
1752 _session->request_transport_speed (4.0f);
1755 _session->request_transport_speed (0.5f);
1760 _session->request_transport_speed (current_transport_speed * 1.5f);
1767 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1769 if (_session == 0) {
1773 boost::shared_ptr<Route> r;
1775 if ((r = _session->route_by_remote_id (rid)) != 0) {
1779 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1780 t->set_record_enabled (!t->record_enabled(), this);
1783 if (_session == 0) {
1789 ARDOUR_UI::map_transport_state ()
1791 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1794 auto_loop_button.set_visual_state (0);
1795 play_selection_button.set_visual_state (0);
1796 roll_button.set_visual_state (0);
1797 stop_button.set_visual_state (1);
1801 float sp = _session->transport_speed();
1804 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1805 shuttle_box.queue_draw ();
1806 } else if (sp == 0.0f) {
1808 shuttle_box.queue_draw ();
1809 update_disk_space ();
1816 if (_session->get_play_range()) {
1818 play_selection_button.set_visual_state (1);
1819 roll_button.set_visual_state (0);
1820 auto_loop_button.set_visual_state (0);
1822 } else if (_session->get_play_loop ()) {
1824 auto_loop_button.set_visual_state (1);
1825 play_selection_button.set_visual_state (0);
1826 roll_button.set_visual_state (0);
1830 roll_button.set_visual_state (1);
1831 play_selection_button.set_visual_state (0);
1832 auto_loop_button.set_visual_state (0);
1835 if (join_play_range_button.get_active()) {
1836 /* light up both roll and play-selection if they are joined */
1837 roll_button.set_visual_state (1);
1838 play_selection_button.set_visual_state (1);
1841 stop_button.set_visual_state (0);
1845 stop_button.set_visual_state (1);
1846 roll_button.set_visual_state (0);
1847 play_selection_button.set_visual_state (0);
1848 auto_loop_button.set_visual_state (0);
1853 ARDOUR_UI::engine_stopped ()
1855 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1856 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1857 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1861 ARDOUR_UI::engine_running ()
1863 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1864 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1865 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1867 Glib::RefPtr<Action> action;
1868 const char* action_name = 0;
1870 switch (engine->frames_per_cycle()) {
1872 action_name = X_("JACKLatency32");
1875 action_name = X_("JACKLatency64");
1878 action_name = X_("JACKLatency128");
1881 action_name = X_("JACKLatency512");
1884 action_name = X_("JACKLatency1024");
1887 action_name = X_("JACKLatency2048");
1890 action_name = X_("JACKLatency4096");
1893 action_name = X_("JACKLatency8192");
1896 /* XXX can we do anything useful ? */
1902 action = ActionManager::get_action (X_("JACK"), action_name);
1905 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1906 ract->set_active ();
1912 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1914 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1915 /* we can't rely on the original string continuing to exist when we are called
1916 again in the GUI thread, so make a copy and note that we need to
1919 char *copy = strdup (reason);
1920 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1924 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1925 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1927 update_sample_rate (0);
1931 /* if the reason is a non-empty string, it means that the backend was shutdown
1932 rather than just Ardour.
1935 if (strlen (reason)) {
1936 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1938 msgstr = string_compose (_("\
1939 JACK has either been shutdown or it\n\
1940 disconnected %1 because %1\n\
1941 was not fast enough. Try to restart\n\
1942 JACK, reconnect and save the session."), PROGRAM_NAME);
1945 MessageDialog msg (*editor, msgstr);
1950 free ((char*) reason);
1955 ARDOUR_UI::do_engine_start ()
1963 error << _("Unable to start the session running")
1973 ARDOUR_UI::setup_theme ()
1975 theme_manager->setup_theme();
1979 ARDOUR_UI::update_clocks ()
1981 if (!editor || !editor->dragging_playhead()) {
1982 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1987 ARDOUR_UI::start_clocking ()
1989 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1993 ARDOUR_UI::stop_clocking ()
1995 clock_signal_connection.disconnect ();
1999 ARDOUR_UI::toggle_clocking ()
2002 if (clock_button.get_active()) {
2011 ARDOUR_UI::_blink (void *arg)
2014 ((ARDOUR_UI *) arg)->blink ();
2021 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2025 ARDOUR_UI::start_blinking ()
2027 /* Start the blink signal. Everybody with a blinking widget
2028 uses Blink to drive the widget's state.
2031 if (blink_timeout_tag < 0) {
2033 blink_timeout_tag = g_timeout_add (240, _blink, this);
2038 ARDOUR_UI::stop_blinking ()
2040 if (blink_timeout_tag >= 0) {
2041 g_source_remove (blink_timeout_tag);
2042 blink_timeout_tag = -1;
2047 /** Ask the user for the name of a new shapshot and then take it.
2051 ARDOUR_UI::snapshot_session (bool switch_to_it)
2053 ArdourPrompter prompter (true);
2056 prompter.set_name ("Prompter");
2057 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2058 prompter.set_title (_("Take Snapshot"));
2059 prompter.set_title (_("Take Snapshot"));
2060 prompter.set_prompt (_("Name of new snapshot"));
2062 if (!switch_to_it) {
2065 struct tm local_time;
2068 localtime_r (&n, &local_time);
2069 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2070 prompter.set_initial_text (timebuf);
2074 switch (prompter.run()) {
2075 case RESPONSE_ACCEPT:
2077 prompter.get_result (snapname);
2079 bool do_save = (snapname.length() != 0);
2082 if (snapname.find ('/') != string::npos) {
2083 MessageDialog msg (_("To ensure compatibility with various systems\n"
2084 "snapshot names may not contain a '/' character"));
2088 if (snapname.find ('\\') != string::npos) {
2089 MessageDialog msg (_("To ensure compatibility with various systems\n"
2090 "snapshot names may not contain a '\\' character"));
2096 vector<sys::path> p;
2097 get_state_files_in_directory (_session->session_directory().root_path(), p);
2098 vector<string> n = get_file_names_no_extension (p);
2099 if (find (n.begin(), n.end(), snapname) != n.end()) {
2101 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2102 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2103 confirm.get_vbox()->pack_start (m, true, true);
2104 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2105 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2106 confirm.show_all ();
2107 switch (confirm.run()) {
2108 case RESPONSE_CANCEL:
2114 save_state (snapname, switch_to_it);
2125 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2127 XMLNode* node = new XMLNode (X_("UI"));
2129 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2130 if (!(*i)->rc_configured()) {
2131 node->add_child_nocopy (*((*i)->get_state ()));
2135 _session->add_extra_xml (*node);
2137 save_state_canfail (name, switch_to_it);
2141 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2146 if (name.length() == 0) {
2147 name = _session->snap_name();
2150 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2154 cerr << "SS canfail\n";
2155 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2160 ARDOUR_UI::primary_clock_value_changed ()
2163 _session->request_locate (primary_clock.current_time ());
2168 ARDOUR_UI::big_clock_value_changed ()
2171 _session->request_locate (big_clock.current_time ());
2176 ARDOUR_UI::secondary_clock_value_changed ()
2179 _session->request_locate (secondary_clock.current_time ());
2184 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2186 if (_session == 0) {
2190 if (_session->step_editing()) {
2194 Session::RecordState const r = _session->record_status ();
2195 bool const h = _session->have_rec_enabled_track ();
2197 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2199 rec_button.set_visual_state (2);
2201 rec_button.set_visual_state (0);
2203 } else if (r == Session::Recording && h) {
2204 rec_button.set_visual_state (1);
2206 rec_button.set_visual_state (0);
2211 ARDOUR_UI::save_template ()
2213 ArdourPrompter prompter (true);
2216 if (!check_audioengine()) {
2220 prompter.set_name (X_("Prompter"));
2221 prompter.set_title (_("Save Mix Template"));
2222 prompter.set_prompt (_("Name for mix template:"));
2223 prompter.set_initial_text(_session->name() + _("-template"));
2224 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2226 switch (prompter.run()) {
2227 case RESPONSE_ACCEPT:
2228 prompter.get_result (name);
2230 if (name.length()) {
2231 _session->save_template (name);
2241 ARDOUR_UI::edit_metadata ()
2243 SessionMetadataEditor dialog;
2244 dialog.set_session (_session);
2245 editor->ensure_float (dialog);
2250 ARDOUR_UI::import_metadata ()
2252 SessionMetadataImporter dialog;
2253 dialog.set_session (_session);
2254 editor->ensure_float (dialog);
2259 ARDOUR_UI::fontconfig_dialog ()
2262 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2263 may not and it can take a while to build it. Warn them.
2266 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2268 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2269 MessageDialog msg (*_startup,
2270 string_compose (_("Welcome to %1.\n\n"
2271 "The program will take a bit longer to start up\n"
2272 "while the system fonts are checked.\n\n"
2273 "This will only be done once, and you will\n"
2274 "not see this message again\n"), PROGRAM_NAME),
2287 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2289 existing_session = false;
2291 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2292 session_path = cmdline_path;
2293 existing_session = true;
2294 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2295 session_path = Glib::path_get_dirname (string (cmdline_path));
2296 existing_session = true;
2298 /* it doesn't exist, assume the best */
2299 session_path = Glib::path_get_dirname (string (cmdline_path));
2302 session_name = basename_nosuffix (string (cmdline_path));
2306 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2308 /* when this is called, the backend audio system must be running */
2310 /* the main idea here is to deal with the fact that a cmdline argument for the session
2311 can be interpreted in different ways - it could be a directory or a file, and before
2312 we load, we need to know both the session directory and the snapshot (statefile) within it
2313 that we are supposed to use.
2316 if (session_name.length() == 0 || session_path.length() == 0) {
2320 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2322 std::string predicted_session_file;
2324 predicted_session_file = session_path;
2325 predicted_session_file += '/';
2326 predicted_session_file += session_name;
2327 predicted_session_file += ARDOUR::statefile_suffix;
2329 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2330 existing_session = true;
2333 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2335 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2336 /* existing .ardour file */
2337 existing_session = true;
2341 existing_session = false;
2344 /* lets just try to load it */
2346 if (create_engine ()) {
2347 backend_audio_error (false, _startup);
2351 return load_session (session_path, session_name);
2355 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2357 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2359 MessageDialog msg (str,
2361 Gtk::MESSAGE_WARNING,
2362 Gtk::BUTTONS_YES_NO,
2366 msg.set_name (X_("OpenExistingDialog"));
2367 msg.set_title (_("Open Existing Session"));
2368 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2369 msg.set_position (Gtk::WIN_POS_MOUSE);
2372 switch (msg.run()) {
2381 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2383 BusProfile bus_profile;
2385 if (Profile->get_sae()) {
2387 bus_profile.master_out_channels = 2;
2388 bus_profile.input_ac = AutoConnectPhysical;
2389 bus_profile.output_ac = AutoConnectMaster;
2390 bus_profile.requested_physical_in = 0; // use all available
2391 bus_profile.requested_physical_out = 0; // use all available
2395 /* get settings from advanced section of NSD */
2397 if (_startup->create_master_bus()) {
2398 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2400 bus_profile.master_out_channels = 0;
2403 if (_startup->connect_inputs()) {
2404 bus_profile.input_ac = AutoConnectPhysical;
2406 bus_profile.input_ac = AutoConnectOption (0);
2409 /// @todo some minor tweaks.
2411 bus_profile.output_ac = AutoConnectOption (0);
2413 if (_startup->connect_outputs ()) {
2414 if (_startup->connect_outs_to_master()) {
2415 bus_profile.output_ac = AutoConnectMaster;
2416 } else if (_startup->connect_outs_to_physical()) {
2417 bus_profile.output_ac = AutoConnectPhysical;
2421 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2422 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2425 if (build_session (session_path, session_name, bus_profile)) {
2433 ARDOUR_UI::idle_load (const std::string& path)
2436 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2437 /* /path/to/foo => /path/to/foo, foo */
2438 load_session (path, basename_nosuffix (path));
2440 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2441 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2445 ARDOUR_COMMAND_LINE::session_name = path;
2448 * new_session_dialog doens't exist in A3
2449 * Try to remove all references to it to
2450 * see if it will compile. NOTE: this will
2451 * likely cause a runtime issue is my somewhat
2455 //if (new_session_dialog) {
2458 /* make it break out of Dialog::run() and
2462 //new_session_dialog->response (1);
2468 ARDOUR_UI::end_loading_messages ()
2474 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2477 // splash->message (msg);
2481 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2483 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2485 string session_name;
2486 string session_path;
2487 string template_name;
2489 bool likely_new = false;
2491 if (! load_template.empty()) {
2492 should_be_new = true;
2493 template_name = load_template;
2498 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2500 /* if they named a specific statefile, use it, otherwise they are
2501 just giving a session folder, and we want to use it as is
2502 to find the session.
2505 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2506 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2508 session_path = ARDOUR_COMMAND_LINE::session_name;
2511 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2515 bool const apply = run_startup (should_be_new, load_template);
2518 if (quit_on_cancel) {
2525 /* if we run the startup dialog again, offer more than just "new session" */
2527 should_be_new = false;
2529 session_name = _startup->session_name (likely_new);
2531 /* this shouldn't happen, but we catch it just in case it does */
2533 if (session_name.empty()) {
2537 if (_startup->use_session_template()) {
2538 template_name = _startup->session_template_name();
2539 _session_is_new = true;
2542 if (session_name[0] == G_DIR_SEPARATOR ||
2543 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2544 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2546 /* absolute path or cwd-relative path specified for session name: infer session folder
2547 from what was given.
2550 session_path = Glib::path_get_dirname (session_name);
2551 session_name = Glib::path_get_basename (session_name);
2555 session_path = _startup->session_folder();
2557 if (session_name.find ('/') != string::npos) {
2558 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2559 "session names may not contain a '/' character"));
2561 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2565 if (session_name.find ('\\') != string::npos) {
2566 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2567 "session names may not contain a '\\' character"));
2569 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2575 if (create_engine ()) {
2579 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2583 std::string existing = Glib::build_filename (session_path, session_name);
2585 if (!ask_about_loading_existing_session (existing)) {
2586 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2591 _session_is_new = false;
2596 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2598 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2602 if (session_name.find ('/') != std::string::npos) {
2603 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2604 "session names may not contain a '/' character"));
2606 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2610 if (session_name.find ('\\') != std::string::npos) {
2611 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2612 "session names may not contain a '\\' character"));
2614 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2618 _session_is_new = true;
2621 if (likely_new && template_name.empty()) {
2623 ret = build_session_from_nsd (session_path, session_name);
2627 ret = load_session (session_path, session_name, template_name);
2628 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2629 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2639 ARDOUR_UI::close_session()
2641 if (!check_audioengine()) {
2645 if (unload_session (true)) {
2649 ARDOUR_COMMAND_LINE::session_name = "";
2651 if (get_session_parameters (true, false)) {
2655 goto_editor_window ();
2659 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2661 Session *new_session;
2665 session_loaded = false;
2667 if (!check_audioengine()) {
2671 unload_status = unload_session ();
2673 if (unload_status < 0) {
2675 } else if (unload_status > 0) {
2680 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2683 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2686 /* this one is special */
2688 catch (AudioEngine::PortRegistrationFailure& err) {
2690 MessageDialog msg (err.what(),
2693 Gtk::BUTTONS_CLOSE);
2695 msg.set_title (_("Port Registration Error"));
2696 msg.set_secondary_text (_("Click the Close button to try again."));
2697 msg.set_position (Gtk::WIN_POS_CENTER);
2701 int response = msg.run ();
2706 case RESPONSE_CANCEL:
2716 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"),path, snap_name),
2721 msg.set_title (_("Loading Error"));
2722 msg.set_secondary_text (_("Click the Refresh button to try again."));
2723 msg.add_button (Stock::REFRESH, 1);
2724 msg.set_position (Gtk::WIN_POS_CENTER);
2728 int response = msg.run ();
2743 list<string> const u = new_session->unknown_processors ();
2745 MissingPluginDialog d (_session, u);
2750 /* Now the session been created, add the transport controls */
2751 new_session->add_controllable(roll_controllable);
2752 new_session->add_controllable(stop_controllable);
2753 new_session->add_controllable(goto_start_controllable);
2754 new_session->add_controllable(goto_end_controllable);
2755 new_session->add_controllable(auto_loop_controllable);
2756 new_session->add_controllable(play_selection_controllable);
2757 new_session->add_controllable(rec_controllable);
2759 set_session (new_session);
2761 session_loaded = true;
2763 goto_editor_window ();
2766 _session->set_clean ();
2777 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2779 Session *new_session;
2782 if (!check_audioengine()) {
2786 session_loaded = false;
2788 x = unload_session ();
2796 _session_is_new = true;
2799 new_session = new Session (*engine, path, snap_name, &bus_profile);
2804 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2810 /* Give the new session the default GUI state, if such things exist */
2813 n = Config->instant_xml (X_("Editor"));
2815 new_session->add_instant_xml (*n, false);
2817 n = Config->instant_xml (X_("Mixer"));
2819 new_session->add_instant_xml (*n, false);
2822 set_session (new_session);
2824 session_loaded = true;
2826 new_session->save_state(new_session->name());
2832 ARDOUR_UI::launch_chat ()
2835 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2837 open_uri("http://webchat.freenode.net/?channels=ardour");
2842 ARDOUR_UI::show_about ()
2846 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2849 about->set_transient_for(*editor);
2854 ARDOUR_UI::launch_manual ()
2856 PBD::open_uri("http://ardour.org/flossmanual");
2860 ARDOUR_UI::launch_reference ()
2862 PBD::open_uri("http://ardour.org/refmanual");
2866 ARDOUR_UI::hide_about ()
2869 about->get_window()->set_cursor ();
2875 ARDOUR_UI::about_signal_response (int /*response*/)
2881 ARDOUR_UI::show_splash ()
2885 splash = new Splash;
2893 splash->queue_draw ();
2894 splash->get_window()->process_updates (true);
2899 ARDOUR_UI::hide_splash ()
2907 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2908 const string& plural_msg, const string& singular_msg)
2912 removed = rep.paths.size();
2915 MessageDialog msgd (*editor,
2916 _("No audio files were ready for cleanup"),
2919 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2920 msgd.set_secondary_text (_("If this seems suprising, \n\
2921 check for any existing snapshots.\n\
2922 These may still include regions that\n\
2923 require some unused files to continue to exist."));
2929 ArdourDialog results (_("Clean-up"), true, false);
2931 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2932 CleanupResultsModelColumns() {
2936 Gtk::TreeModelColumn<std::string> visible_name;
2937 Gtk::TreeModelColumn<std::string> fullpath;
2941 CleanupResultsModelColumns results_columns;
2942 Glib::RefPtr<Gtk::ListStore> results_model;
2943 Gtk::TreeView results_display;
2945 results_model = ListStore::create (results_columns);
2946 results_display.set_model (results_model);
2947 results_display.append_column (list_title, results_columns.visible_name);
2949 results_display.set_name ("CleanupResultsList");
2950 results_display.set_headers_visible (true);
2951 results_display.set_headers_clickable (false);
2952 results_display.set_reorderable (false);
2954 Gtk::ScrolledWindow list_scroller;
2957 Gtk::HBox dhbox; // the hbox for the image and text
2958 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2959 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2961 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2963 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2966 %1 - number of files removed
2967 %2 - location of "dead_sounds"
2968 %3 - size of files affected
2969 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2972 const char* bprefix;
2973 double space_adjusted = 0;
2975 if (rep.space < 100000.0f) {
2976 bprefix = X_("kilo");
2977 } else if (rep.space < 1000000.0f * 1000) {
2978 bprefix = X_("mega");
2979 space_adjusted = truncf((float)rep.space / 1000.0);
2981 bprefix = X_("giga");
2982 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2986 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2988 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2991 dhbox.pack_start (*dimage, true, false, 5);
2992 dhbox.pack_start (txt, true, false, 5);
2994 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2995 TreeModel::Row row = *(results_model->append());
2996 row[results_columns.visible_name] = *i;
2997 row[results_columns.fullpath] = *i;
3000 list_scroller.add (results_display);
3001 list_scroller.set_size_request (-1, 150);
3002 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3004 dvbox.pack_start (dhbox, true, false, 5);
3005 dvbox.pack_start (list_scroller, true, false, 5);
3006 ddhbox.pack_start (dvbox, true, false, 5);
3008 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3009 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3010 results.set_default_response (RESPONSE_CLOSE);
3011 results.set_position (Gtk::WIN_POS_MOUSE);
3013 results_display.show();
3014 list_scroller.show();
3021 //results.get_vbox()->show();
3022 results.set_resizable (false);
3029 ARDOUR_UI::cleanup ()
3031 if (_session == 0) {
3032 /* shouldn't happen: menu item is insensitive */
3037 MessageDialog checker (_("Are you sure you want to cleanup?"),
3039 Gtk::MESSAGE_QUESTION,
3040 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3042 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3043 ALL undo/redo information will be lost if you cleanup.\n\
3044 After cleanup, unused audio files will be moved to a \
3045 \"dead sounds\" location."));
3047 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3048 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3049 checker.set_default_response (RESPONSE_CANCEL);
3051 checker.set_name (_("CleanupDialog"));
3052 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3053 checker.set_position (Gtk::WIN_POS_MOUSE);
3055 switch (checker.run()) {
3056 case RESPONSE_ACCEPT:
3062 ARDOUR::CleanupReport rep;
3064 editor->prepare_for_cleanup ();
3066 /* do not allow flush until a session is reloaded */
3068 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3070 act->set_sensitive (false);
3073 if (_session->cleanup_sources (rep)) {
3074 editor->finish_cleanup ();
3078 editor->finish_cleanup ();
3081 display_cleanup_results (rep,
3084 The following %1 files were not in use and \n\
3085 have been moved to:\n\
3087 Flushing the wastebasket will \n\
3088 release an additional\n\
3089 %3 %4bytes of disk space.\n"),
3091 The following file was not in use and \n \
3092 has been moved to:\n \
3094 Flushing the wastebasket will \n\
3095 release an additional\n\
3096 %3 %4bytes of disk space.\n"
3102 ARDOUR_UI::flush_trash ()
3104 if (_session == 0) {
3105 /* shouldn't happen: menu item is insensitive */
3109 ARDOUR::CleanupReport rep;
3111 if (_session->cleanup_trash_sources (rep)) {
3115 display_cleanup_results (rep,
3117 _("The following %1 files were deleted from\n\
3119 releasing %3 %4bytes of disk space"),
3120 _("The following file was deleted from\n\
3122 releasing %3 %4bytes of disk space"));
3126 ARDOUR_UI::add_route (Gtk::Window* float_window)
3134 if (add_route_dialog == 0) {
3135 add_route_dialog = new AddRouteDialog (_session);
3137 add_route_dialog->set_transient_for (*float_window);
3141 if (add_route_dialog->is_visible()) {
3142 /* we're already doing this */
3146 ResponseType r = (ResponseType) add_route_dialog->run ();
3148 add_route_dialog->hide();
3151 case RESPONSE_ACCEPT:
3158 if ((count = add_route_dialog->count()) <= 0) {
3162 string template_path = add_route_dialog->track_template();
3164 if (!template_path.empty()) {
3165 _session->new_route_from_template (count, template_path);
3169 uint32_t input_chan = add_route_dialog->channels ();
3170 uint32_t output_chan;
3171 string name_template = add_route_dialog->name_template ();
3172 bool track = add_route_dialog->track ();
3173 bool aux = !track && add_route_dialog->aux();
3174 RouteGroup* route_group = add_route_dialog->route_group ();
3176 AutoConnectOption oac = Config->get_output_auto_connect();
3178 if (oac & AutoConnectMaster) {
3179 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3181 output_chan = input_chan;
3184 /* XXX do something with name template */
3186 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3188 session_add_midi_track (route_group, count);
3190 MessageDialog msg (*editor,
3191 _("Sorry, MIDI Busses are not supported at this time."));
3193 //session_add_midi_bus();
3197 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3199 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3205 ARDOUR_UI::mixer_settings () const
3210 node = _session->instant_xml(X_("Mixer"));
3212 node = Config->instant_xml(X_("Mixer"));
3216 node = new XMLNode (X_("Mixer"));
3223 ARDOUR_UI::editor_settings () const
3228 node = _session->instant_xml(X_("Editor"));
3230 node = Config->instant_xml(X_("Editor"));
3234 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3235 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3240 node = new XMLNode (X_("Editor"));
3247 ARDOUR_UI::keyboard_settings () const
3251 node = Config->extra_xml(X_("Keyboard"));
3254 node = new XMLNode (X_("Keyboard"));
3260 ARDOUR_UI::create_xrun_marker(nframes_t where)
3262 editor->mouse_add_new_marker (where, false, true);
3266 ARDOUR_UI::halt_on_xrun_message ()
3268 MessageDialog msg (*editor,
3269 _("Recording was stopped because your system could not keep up."));
3274 ARDOUR_UI::xrun_handler(nframes_t where)
3280 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3282 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3283 create_xrun_marker(where);
3286 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3287 halt_on_xrun_message ();
3292 ARDOUR_UI::disk_overrun_handler ()
3294 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3296 if (!have_disk_speed_dialog_displayed) {
3297 have_disk_speed_dialog_displayed = true;
3298 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3299 The disk system on your computer\n\
3300 was not able to keep up with %1.\n\
3302 Specifically, it failed to write data to disk\n\
3303 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3304 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3310 ARDOUR_UI::disk_underrun_handler ()
3312 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3314 if (!have_disk_speed_dialog_displayed) {
3315 have_disk_speed_dialog_displayed = true;
3316 MessageDialog* msg = new MessageDialog (*editor,
3317 string_compose (_("The disk system on your computer\n\
3318 was not able to keep up with %1.\n\
3320 Specifically, it failed to read data from disk\n\
3321 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3322 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3328 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3330 have_disk_speed_dialog_displayed = false;
3335 ARDOUR_UI::session_dialog (std::string msg)
3337 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3342 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3344 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3353 ARDOUR_UI::pending_state_dialog ()
3355 HBox* hbox = new HBox();
3356 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3357 ArdourDialog dialog (_("Crash Recovery"), true);
3359 This session appears to have been in\n\
3360 middle of recording when ardour or\n\
3361 the computer was shutdown.\n\
3363 Ardour can recover any captured audio for\n\
3364 you, or it can ignore it. Please decide\n\
3365 what you would like to do.\n"));
3366 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3367 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3368 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3369 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3370 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3371 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3372 dialog.set_default_response (RESPONSE_ACCEPT);
3373 dialog.set_position (WIN_POS_CENTER);
3378 switch (dialog.run ()) {
3379 case RESPONSE_ACCEPT:
3387 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3389 HBox* hbox = new HBox();
3390 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3391 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3392 Label message (string_compose (_("\
3393 This session was created with a sample rate of %1 Hz\n\
3395 The audioengine is currently running at %2 Hz\n"), desired, actual));
3397 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3398 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3399 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3400 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3401 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3402 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3403 dialog.set_default_response (RESPONSE_ACCEPT);
3404 dialog.set_position (WIN_POS_CENTER);
3409 switch (dialog.run ()) {
3410 case RESPONSE_ACCEPT:
3419 ARDOUR_UI::disconnect_from_jack ()
3422 if( engine->disconnect_from_jack ()) {
3423 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3427 update_sample_rate (0);
3432 ARDOUR_UI::reconnect_to_jack ()
3435 if (engine->reconnect_to_jack ()) {
3436 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3440 update_sample_rate (0);
3445 ARDOUR_UI::use_config ()
3447 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3449 set_transport_controllable_state (*node);
3454 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3456 if (Config->get_primary_clock_delta_edit_cursor()) {
3457 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3459 primary_clock.set (pos, 0, true);
3462 if (Config->get_secondary_clock_delta_edit_cursor()) {
3463 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3465 secondary_clock.set (pos);
3468 if (big_clock_window->get()) {
3469 big_clock.set (pos);
3475 ARDOUR_UI::step_edit_status_change (bool yn)
3477 // XXX should really store pre-step edit status of things
3478 // we make insensitive
3481 rec_button.set_visual_state (3);
3482 rec_button.set_sensitive (false);
3484 rec_button.set_visual_state (0);
3485 rec_button.set_sensitive (true);
3490 ARDOUR_UI::record_state_changed ()
3492 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3494 if (!_session || !big_clock_window->get()) {
3495 /* why bother - the clock isn't visible */
3499 Session::RecordState const r = _session->record_status ();
3500 bool const h = _session->have_rec_enabled_track ();
3502 if (r == Session::Recording && h) {
3503 big_clock.set_widget_name ("BigClockRecording");
3505 big_clock.set_widget_name ("BigClockNonRecording");
3510 ARDOUR_UI::first_idle ()
3513 _session->allow_auto_play (true);
3517 editor->first_idle();
3520 Keyboard::set_can_save_keybindings (true);
3525 ARDOUR_UI::store_clock_modes ()
3527 XMLNode* node = new XMLNode(X_("ClockModes"));
3529 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3530 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3533 _session->add_extra_xml (*node);
3534 _session->set_dirty ();
3539 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3540 : Controllable (name), ui (u), type(tp)
3546 ARDOUR_UI::TransportControllable::set_value (double val)
3548 if (type == ShuttleControl) {
3555 fract = -((0.5 - val)/0.5);
3557 fract = ((val - 0.5)/0.5);
3561 ui.set_shuttle_fract (fract);
3566 /* do nothing: these are radio-style actions */
3570 const char *action = 0;
3574 action = X_("Roll");
3577 action = X_("Stop");
3580 action = X_("Goto Start");
3583 action = X_("Goto End");
3586 action = X_("Loop");
3589 action = X_("Play Selection");
3592 action = X_("Record");
3602 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3610 ARDOUR_UI::TransportControllable::get_value (void) const
3629 case ShuttleControl:
3639 ARDOUR_UI::TransportControllable::set_id (const string& str)
3645 ARDOUR_UI::setup_profile ()
3647 if (gdk_screen_width() < 1200) {
3648 Profile->set_small_screen ();
3652 if (getenv ("ARDOUR_SAE")) {
3653 Profile->set_sae ();
3654 Profile->set_single_package ();
3659 ARDOUR_UI::toggle_translations ()
3661 using namespace Glib;
3663 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3665 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3668 string i18n_killer = ARDOUR::translation_kill_path();
3670 bool already_enabled = !ARDOUR::translations_are_disabled ();
3672 if (ract->get_active ()) {
3673 /* we don't care about errors */
3674 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3677 /* we don't care about errors */
3678 unlink (i18n_killer.c_str());
3681 if (already_enabled != ract->get_active()) {
3682 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3684 Gtk::MESSAGE_WARNING,
3686 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3687 win.set_position (Gtk::WIN_POS_CENTER);
3695 /** Add a window proxy to our list, so that its state will be saved.
3696 * This call also causes the window to be created and opened if its
3697 * state was saved as `visible'.
3700 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3702 _window_proxies.push_back (p);
3706 /** Remove a window proxy from our list. Must be called if a WindowProxy
3707 * is deleted, to prevent hanging pointers.
3710 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3712 _window_proxies.remove (p);
3716 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3718 MissingFileDialog dialog (s, str, type);
3723 int result = dialog.run ();
3730 return 1; // quit entire session load
3733 result = dialog.get_action ();