2 Copyright (C) 1999-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
37 #include <sys/resource.h>
39 #include <gtkmm/messagedialog.h>
40 #include <gtkmm/accelmap.h>
42 #include "pbd/error.h"
43 #include "pbd/basename.h"
44 #include "pbd/compose.h"
45 #include "pbd/failed_constructor.h"
46 #include "pbd/enumwriter.h"
47 #include "pbd/memento_command.h"
48 #include "pbd/openuri.h"
49 #include "pbd/file_utils.h"
51 #include "gtkmm2ext/application.h"
52 #include "gtkmm2ext/gtk_ui.h"
53 #include "gtkmm2ext/utils.h"
54 #include "gtkmm2ext/click_box.h"
55 #include "gtkmm2ext/fastmeter.h"
56 #include "gtkmm2ext/popup.h"
57 #include "gtkmm2ext/window_title.h"
59 #include "midi++/manager.h"
61 #include "ardour/ardour.h"
62 #include "ardour/callback.h"
63 #include "ardour/profile.h"
64 #include "ardour/session_directory.h"
65 #include "ardour/session_route.h"
66 #include "ardour/session_state_utils.h"
67 #include "ardour/session_utils.h"
68 #include "ardour/port.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/playlist.h"
71 #include "ardour/utils.h"
72 #include "ardour/audio_diskstream.h"
73 #include "ardour/audiofilesource.h"
74 #include "ardour/recent_sessions.h"
75 #include "ardour/port.h"
76 #include "ardour/audio_track.h"
77 #include "ardour/midi_track.h"
78 #include "ardour/filesystem_paths.h"
79 #include "ardour/filename_extensions.h"
81 typedef uint64_t microseconds_t;
85 #include "add_route_dialog.h"
86 #include "ambiguous_file_dialog.h"
87 #include "ardour_ui.h"
88 #include "audio_clock.h"
89 #include "bundle_manager.h"
90 #include "engine_dialog.h"
91 #include "gain_meter.h"
92 #include "global_port_matrix.h"
93 #include "gui_thread.h"
95 #include "location_ui.h"
96 #include "missing_file_dialog.h"
97 #include "missing_plugin_dialog.h"
100 #include "processor_box.h"
101 #include "prompter.h"
102 #include "public_editor.h"
103 #include "route_time_axis.h"
104 #include "session_metadata_dialog.h"
105 #include "speaker_dialog.h"
108 #include "theme_manager.h"
109 #include "time_axis_view_item.h"
111 #include "window_proxy.h"
115 using namespace ARDOUR;
117 using namespace Gtkmm2ext;
120 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
121 UIConfiguration *ARDOUR_UI::ui_config = 0;
123 sigc::signal<void,bool> ARDOUR_UI::Blink;
124 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
125 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
126 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
128 bool could_be_a_valid_path (const string& path);
130 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
132 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
134 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
135 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
136 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
137 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
141 preroll_button (_("pre\nroll")),
142 postroll_button (_("post\nroll")),
146 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
150 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
151 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
152 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
153 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
154 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
155 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
156 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
157 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
158 shuttle_controller_binding_proxy (shuttle_controllable),
160 roll_button (roll_controllable),
161 stop_button (stop_controllable),
162 goto_start_button (goto_start_controllable),
163 goto_end_button (goto_end_controllable),
164 auto_loop_button (auto_loop_controllable),
165 play_selection_button (play_selection_controllable),
166 rec_button (rec_controllable),
168 shuttle_units_button (_("% ")),
170 punch_in_button (_("Punch In")),
171 punch_out_button (_("Punch Out")),
172 auto_return_button (_("Auto Return")),
173 auto_play_button (_("Auto Play")),
174 auto_input_button (_("Auto Input")),
175 click_button (_("Click")),
176 time_master_button (_("time\nmaster")),
178 auditioning_alert_button (_("AUDITION")),
179 solo_alert_button (_("SOLO")),
181 error_log_button (_("Errors"))
184 using namespace Gtk::Menu_Helpers;
190 // _auto_display_errors = false;
192 * This was commented out as it wasn't defined
193 * in A3 IIRC. If this is not needed it should
194 * be completely removed.
202 if (theArdourUI == 0) {
206 ui_config = new UIConfiguration();
207 theme_manager = new ThemeManager();
213 _session_is_new = false;
214 big_clock_window = 0;
215 big_clock_height = 0;
216 big_clock_resize_in_progress = false;
217 session_selector_window = 0;
218 last_key_press_time = 0;
219 _will_create_new_session_automatically = false;
220 add_route_dialog = 0;
222 rc_option_editor = 0;
223 session_option_editor = 0;
225 open_session_selector = 0;
226 have_configure_timeout = false;
227 have_disk_speed_dialog_displayed = false;
228 session_loaded = false;
229 last_speed_displayed = -1.0f;
230 ignore_dual_punch = false;
231 original_big_clock_width = -1;
232 original_big_clock_height = -1;
233 original_big_clock_font_size = 0;
235 roll_button.unset_flags (Gtk::CAN_FOCUS);
236 stop_button.unset_flags (Gtk::CAN_FOCUS);
237 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
238 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
239 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
240 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
241 rec_button.unset_flags (Gtk::CAN_FOCUS);
243 last_configure_time= 0;
245 shuttle_grabbed = false;
247 shuttle_max_speed = 8.0f;
249 shuttle_style_menu = 0;
250 shuttle_unit_menu = 0;
252 // We do not have jack linked in yet so;
254 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
256 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
257 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
259 /* handle dialog requests */
261 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
263 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
265 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
267 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
269 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
271 /* handle requests to quit (coming from JACK session) */
273 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
275 /* handle requests to deal with missing files */
277 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
279 /* and ambiguous files */
281 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
283 /* lets get this party started */
286 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
287 throw failed_constructor ();
290 setup_gtk_ardour_enums ();
293 GainMeter::setup_slider_pix ();
294 RouteTimeAxisView::setup_slider_pix ();
295 SendProcessorEntry::setup_slider_pix ();
296 SessionEvent::create_per_thread_pool ("GUI", 512);
298 } catch (failed_constructor& err) {
299 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
304 /* we like keyboards */
306 keyboard = new ArdourKeyboard(*this);
308 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
310 keyboard->set_state (*node, Stateful::loading_state_version);
315 TimeAxisViewItem::set_constant_heights ();
317 /* The following must happen after ARDOUR::init() so that Config is set up */
319 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
320 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
321 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
323 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
324 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
325 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
326 Config->extra_xml (X_("UI")),
327 string_compose ("toggle-%1-connection-manager", (*i).to_string())
332 speaker_config_window->set (new SpeakerDialog);
334 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
335 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
340 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
342 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
345 _startup = new ArdourStartup ();
347 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
349 if (audio_setup && _startup->engine_control()) {
350 _startup->engine_control()->set_state (*audio_setup);
353 _startup->set_new_only (should_be_new);
354 if (!load_template.empty()) {
355 _startup->set_load_template( load_template );
357 _startup->present ();
363 switch (_startup->response()) {
372 ARDOUR_UI::create_engine ()
374 // this gets called every time by new_session()
380 loading_message (_("Starting audio engine"));
383 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
390 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
391 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
392 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
394 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
396 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
404 ARDOUR_UI::post_engine ()
406 /* Things to be done once we create the AudioEngine
409 ARDOUR::init_post_engine ();
411 ActionManager::init ();
414 if (setup_windows ()) {
415 throw failed_constructor ();
418 check_memory_locking();
420 /* this is the first point at which all the keybindings are available */
422 if (ARDOUR_COMMAND_LINE::show_key_actions) {
423 vector<string> names;
424 vector<string> paths;
426 vector<AccelKey> bindings;
428 ActionManager::get_all_actions (names, paths, keys, bindings);
430 vector<string>::iterator n;
431 vector<string>::iterator k;
432 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
433 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
439 blink_timeout_tag = -1;
441 /* this being a GUI and all, we want peakfiles */
443 AudioFileSource::set_build_peakfiles (true);
444 AudioFileSource::set_build_missing_peakfiles (true);
446 /* set default clock modes */
448 if (Profile->get_sae()) {
449 primary_clock.set_mode (AudioClock::BBT);
450 secondary_clock.set_mode (AudioClock::MinSec);
452 primary_clock.set_mode (AudioClock::Timecode);
453 secondary_clock.set_mode (AudioClock::BBT);
456 /* start the time-of-day-clock */
459 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
460 update_wall_clock ();
461 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
464 update_disk_space ();
466 update_sample_rate (engine->frame_rate());
468 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
469 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
470 Config->map_parameters (pc);
472 /* now start and maybe save state */
474 if (do_engine_start () == 0) {
475 if (_session && _session_is_new) {
476 /* we need to retain initial visual
477 settings for a new session
479 _session->save_state ("");
484 ARDOUR_UI::~ARDOUR_UI ()
489 delete add_route_dialog;
493 ARDOUR_UI::pop_back_splash ()
495 if (Splash::instance()) {
496 // Splash::instance()->pop_back();
497 Splash::instance()->hide ();
502 ARDOUR_UI::configure_timeout ()
504 if (last_configure_time == 0) {
505 /* no configure events yet */
509 /* force a gap of 0.5 seconds since the last configure event
512 if (get_microseconds() - last_configure_time < 500000) {
515 have_configure_timeout = false;
516 cerr << "config event-driven save\n";
517 save_ardour_state ();
523 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
525 if (have_configure_timeout) {
526 last_configure_time = get_microseconds();
528 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
529 have_configure_timeout = true;
536 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
538 const XMLProperty* prop;
540 if ((prop = node.property ("roll")) != 0) {
541 roll_controllable->set_id (prop->value());
543 if ((prop = node.property ("stop")) != 0) {
544 stop_controllable->set_id (prop->value());
546 if ((prop = node.property ("goto-start")) != 0) {
547 goto_start_controllable->set_id (prop->value());
549 if ((prop = node.property ("goto-end")) != 0) {
550 goto_end_controllable->set_id (prop->value());
552 if ((prop = node.property ("auto-loop")) != 0) {
553 auto_loop_controllable->set_id (prop->value());
555 if ((prop = node.property ("play-selection")) != 0) {
556 play_selection_controllable->set_id (prop->value());
558 if ((prop = node.property ("rec")) != 0) {
559 rec_controllable->set_id (prop->value());
561 if ((prop = node.property ("shuttle")) != 0) {
562 shuttle_controllable->set_id (prop->value());
567 ARDOUR_UI::get_transport_controllable_state ()
569 XMLNode* node = new XMLNode(X_("TransportControllables"));
572 roll_controllable->id().print (buf, sizeof (buf));
573 node->add_property (X_("roll"), buf);
574 stop_controllable->id().print (buf, sizeof (buf));
575 node->add_property (X_("stop"), buf);
576 goto_start_controllable->id().print (buf, sizeof (buf));
577 node->add_property (X_("goto_start"), buf);
578 goto_end_controllable->id().print (buf, sizeof (buf));
579 node->add_property (X_("goto_end"), buf);
580 auto_loop_controllable->id().print (buf, sizeof (buf));
581 node->add_property (X_("auto_loop"), buf);
582 play_selection_controllable->id().print (buf, sizeof (buf));
583 node->add_property (X_("play_selection"), buf);
584 rec_controllable->id().print (buf, sizeof (buf));
585 node->add_property (X_("rec"), buf);
586 shuttle_controllable->id().print (buf, sizeof (buf));
587 node->add_property (X_("shuttle"), buf);
594 ARDOUR_UI::autosave_session ()
596 if (g_main_depth() > 1) {
597 /* inside a recursive main loop,
598 give up because we may not be able to
604 if (!Config->get_periodic_safety_backups()) {
609 _session->maybe_write_autosave();
616 ARDOUR_UI::update_autosave ()
618 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
620 if (_session && _session->dirty()) {
621 if (_autosave_connection.connected()) {
622 _autosave_connection.disconnect();
625 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
626 Config->get_periodic_safety_backup_interval() * 1000);
629 if (_autosave_connection.connected()) {
630 _autosave_connection.disconnect();
636 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
640 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
642 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
645 MessageDialog win (title,
651 win.set_secondary_text(_("There are several possible reasons:\n\
653 1) You requested audio parameters that are not supported..\n\
654 2) JACK is running as another user.\n\
656 Please consider the possibilities, and perhaps try different parameters."));
658 win.set_secondary_text(_("There are several possible reasons:\n\
660 1) JACK is not running.\n\
661 2) JACK is running as another user, perhaps root.\n\
662 3) There is already another client called \"ardour\".\n\
664 Please consider the possibilities, and perhaps (re)start JACK."));
668 win.set_transient_for (*toplevel);
672 win.add_button (Stock::OK, RESPONSE_CLOSE);
674 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
677 win.set_default_response (RESPONSE_CLOSE);
680 win.set_position (Gtk::WIN_POS_CENTER);
683 /* we just don't care about the result, but we want to block */
689 ARDOUR_UI::startup ()
691 Application* app = Application::instance ();
693 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
694 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
697 call_the_mothership (VERSIONSTRING);
702 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
708 goto_editor_window ();
710 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
711 to be opened on top of the editor window that goto_editor_window() just opened.
713 add_window_proxy (location_ui);
714 add_window_proxy (big_clock_window);
715 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
716 add_window_proxy (_global_port_matrix[*i]);
719 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
723 ARDOUR_UI::no_memory_warning ()
725 XMLNode node (X_("no-memory-warning"));
726 Config->add_instant_xml (node);
730 ARDOUR_UI::check_memory_locking ()
733 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
737 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
739 if (engine->is_realtime() && memory_warning_node == 0) {
741 struct rlimit limits;
743 long pages, page_size;
745 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
748 ram = (int64_t) pages * (int64_t) page_size;
751 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
755 if (limits.rlim_cur != RLIM_INFINITY) {
757 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
761 string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
762 "This might cause %1 to run out of memory before your system "
763 "runs out of memory. \n\n"
764 "You can view the memory limit with 'ulimit -l', "
765 "and it is normally controlled by /etc/security/limits.conf"),
766 PROGRAM_NAME).c_str());
768 VBox* vbox = msg.get_vbox();
770 CheckButton cb (_("Do not show this window again"));
772 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
774 hbox.pack_start (cb, true, false);
775 vbox->pack_start (hbox);
782 editor->ensure_float (msg);
792 ARDOUR_UI::queue_finish ()
794 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
798 ARDOUR_UI::idle_finish ()
801 return false; /* do not call again */
810 if (_session->transport_rolling() && (++tries < 8)) {
811 _session->request_stop (false, true);
815 if (_session->dirty()) {
816 switch (ask_about_saving_session(_("quit"))) {
821 /* use the default name */
822 if (save_state_canfail ("")) {
823 /* failed - don't quit */
824 MessageDialog msg (*editor,
826 Ardour was unable to save your session.\n\n\
827 If you still wish to quit, please use the\n\n\
828 \"Just quit\" option."));
839 second_connection.disconnect ();
840 point_one_second_connection.disconnect ();
841 point_oh_five_second_connection.disconnect ();
842 point_zero_one_second_connection.disconnect();
845 /* Save state before deleting the session, as that causes some
846 windows to be destroyed before their visible state can be
849 save_ardour_state ();
852 // _session->set_deletion_in_progress ();
853 _session->set_clean ();
854 _session->remove_pending_capture_state ();
859 ArdourDialog::close_all_dialogs ();
865 ARDOUR_UI::ask_about_saving_session (const string & what)
867 ArdourDialog window (_("Unsaved Session"));
868 Gtk::HBox dhbox; // the hbox for the image and text
869 Gtk::Label prompt_label;
870 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
874 msg = string_compose(_("Don't %1"), what);
875 window.add_button (msg, RESPONSE_REJECT);
876 msg = string_compose(_("Just %1"), what);
877 window.add_button (msg, RESPONSE_APPLY);
878 msg = string_compose(_("Save and %1"), what);
879 window.add_button (msg, RESPONSE_ACCEPT);
881 window.set_default_response (RESPONSE_ACCEPT);
883 Gtk::Button noquit_button (msg);
884 noquit_button.set_name ("EditorGTKButton");
889 if (_session->snap_name() == _session->name()) {
892 type = _("snapshot");
894 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?"),
895 type, _session->snap_name());
897 prompt_label.set_text (prompt);
898 prompt_label.set_name (X_("PrompterLabel"));
899 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
901 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
902 dhbox.set_homogeneous (false);
903 dhbox.pack_start (*dimage, false, false, 5);
904 dhbox.pack_start (prompt_label, true, false, 5);
905 window.get_vbox()->pack_start (dhbox);
907 window.set_name (_("Prompter"));
908 window.set_position (Gtk::WIN_POS_MOUSE);
909 window.set_modal (true);
910 window.set_resizable (false);
916 window.set_keep_above (true);
919 ResponseType r = (ResponseType) window.run();
924 case RESPONSE_ACCEPT: // save and get out of here
926 case RESPONSE_APPLY: // get out of here
936 ARDOUR_UI::every_second ()
939 update_buffer_load ();
940 update_disk_space ();
945 ARDOUR_UI::every_point_one_seconds ()
947 update_speed_display ();
948 RapidScreenUpdate(); /* EMIT_SIGNAL */
953 ARDOUR_UI::every_point_zero_one_seconds ()
955 // august 2007: actual update frequency: 40Hz, not 100Hz
957 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
962 ARDOUR_UI::update_sample_rate (framecnt_t)
966 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
968 if (!engine->connected()) {
970 snprintf (buf, sizeof (buf), _("disconnected"));
974 framecnt_t rate = engine->frame_rate();
976 if (fmod (rate, 1000.0) != 0.0) {
977 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
978 (float) rate/1000.0f,
979 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
981 snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"),
983 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
987 sample_rate_label.set_text (buf);
991 ARDOUR_UI::update_cpu_load ()
994 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
995 cpu_load_label.set_text (buf);
999 ARDOUR_UI::update_buffer_load ()
1005 c = _session->capture_load ();
1006 p = _session->playback_load ();
1008 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
1009 _session->playback_load(), _session->capture_load());
1010 buffer_load_label.set_text (buf);
1012 buffer_load_label.set_text ("");
1017 ARDOUR_UI::count_recenabled_streams (Route& route)
1019 Track* track = dynamic_cast<Track*>(&route);
1020 if (track && track->record_enabled()) {
1021 rec_enabled_streams += track->n_inputs().n_total();
1026 ARDOUR_UI::update_disk_space()
1028 if (_session == 0) {
1032 framecnt_t frames = _session->available_capture_duration();
1034 framecnt_t fr = _session->frame_rate();
1036 if (frames == max_framecnt) {
1037 strcpy (buf, _("Disk: 24hrs+"));
1039 rec_enabled_streams = 0;
1040 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1042 if (rec_enabled_streams) {
1043 frames /= rec_enabled_streams;
1050 hrs = frames / (fr * 3600);
1051 frames -= hrs * fr * 3600;
1052 mins = frames / (fr * 60);
1053 frames -= mins * fr * 60;
1056 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1059 disk_space_label.set_text (buf);
1061 // An attempt to make the disk space label flash red when space has run out.
1063 if (frames < fr * 60 * 5) {
1064 /* disk_space_box.style ("disk_space_label_empty"); */
1066 /* disk_space_box.style ("disk_space_label"); */
1072 ARDOUR_UI::update_wall_clock ()
1079 tm_now = localtime (&now);
1081 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1082 wall_clock_label.set_text (buf);
1088 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1090 session_popup_menu->popup (0, 0);
1095 ARDOUR_UI::redisplay_recent_sessions ()
1097 std::vector<sys::path> session_directories;
1098 RecentSessionsSorter cmp;
1100 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1101 recent_session_model->clear ();
1103 ARDOUR::RecentSessions rs;
1104 ARDOUR::read_recent_sessions (rs);
1107 recent_session_display.set_model (recent_session_model);
1111 // sort them alphabetically
1112 sort (rs.begin(), rs.end(), cmp);
1114 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1115 session_directories.push_back ((*i).second);
1118 for (vector<sys::path>::const_iterator i = session_directories.begin();
1119 i != session_directories.end(); ++i)
1121 std::vector<sys::path> state_file_paths;
1123 // now get available states for this session
1125 get_state_files_in_directory (*i, state_file_paths);
1127 vector<string*>* states;
1128 vector<const gchar*> item;
1129 string fullpath = (*i).to_string();
1131 /* remove any trailing / */
1133 if (fullpath[fullpath.length()-1] == '/') {
1134 fullpath = fullpath.substr (0, fullpath.length()-1);
1137 /* check whether session still exists */
1138 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1139 /* session doesn't exist */
1140 cerr << "skipping non-existent session " << fullpath << endl;
1144 /* now get available states for this session */
1146 if ((states = Session::possible_states (fullpath)) == 0) {
1147 /* no state file? */
1151 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1153 Gtk::TreeModel::Row row = *(recent_session_model->append());
1155 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1156 row[recent_session_columns.fullpath] = fullpath;
1158 if (state_file_names.size() > 1) {
1162 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1163 i2 != state_file_names.end(); ++i2)
1166 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1168 child_row[recent_session_columns.visible_name] = *i2;
1169 child_row[recent_session_columns.fullpath] = fullpath;
1174 recent_session_display.set_model (recent_session_model);
1178 ARDOUR_UI::build_session_selector ()
1180 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1182 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1184 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1185 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1186 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1187 recent_session_model = TreeStore::create (recent_session_columns);
1188 recent_session_display.set_model (recent_session_model);
1189 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1190 recent_session_display.set_headers_visible (false);
1191 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1192 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1194 scroller->add (recent_session_display);
1195 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1197 session_selector_window->set_name ("SessionSelectorWindow");
1198 session_selector_window->set_size_request (200, 400);
1199 session_selector_window->get_vbox()->pack_start (*scroller);
1201 recent_session_display.show();
1203 //session_selector_window->get_vbox()->show();
1207 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1209 session_selector_window->response (RESPONSE_ACCEPT);
1213 ARDOUR_UI::open_recent_session ()
1215 bool can_return = (_session != 0);
1217 if (session_selector_window == 0) {
1218 build_session_selector ();
1221 redisplay_recent_sessions ();
1225 session_selector_window->set_position (WIN_POS_MOUSE);
1227 ResponseType r = (ResponseType) session_selector_window->run ();
1230 case RESPONSE_ACCEPT:
1234 session_selector_window->hide();
1241 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1245 session_selector_window->hide();
1247 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1249 if (i == recent_session_model->children().end()) {
1253 std::string path = (*i)[recent_session_columns.fullpath];
1254 std::string state = (*i)[recent_session_columns.visible_name];
1256 _session_is_new = false;
1258 if (load_session (path, state) == 0) {
1267 ARDOUR_UI::check_audioengine ()
1270 if (!engine->connected()) {
1271 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1272 "You cannot open or close sessions in this condition"),
1285 ARDOUR_UI::open_session ()
1287 if (!check_audioengine()) {
1292 /* popup selector window */
1294 if (open_session_selector == 0) {
1296 /* ardour sessions are folders */
1298 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1299 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1300 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1301 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1303 FileFilter session_filter;
1304 session_filter.add_pattern ("*.ardour");
1305 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1306 open_session_selector->add_filter (session_filter);
1307 open_session_selector->set_filter (session_filter);
1310 int response = open_session_selector->run();
1311 open_session_selector->hide ();
1314 case RESPONSE_ACCEPT:
1317 open_session_selector->hide();
1321 open_session_selector->hide();
1322 string session_path = open_session_selector->get_filename();
1326 if (session_path.length() > 0) {
1327 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1328 _session_is_new = isnew;
1329 load_session (path, name);
1336 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1338 list<boost::shared_ptr<MidiTrack> > tracks;
1340 if (_session == 0) {
1341 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1348 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1350 if (tracks.size() != how_many) {
1351 if (how_many == 1) {
1352 error << _("could not create a new midi track") << endmsg;
1354 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1358 if ((route = _session->new_midi_route ()) == 0) {
1359 error << _("could not create new midi bus") << endmsg;
1365 MessageDialog msg (*editor,
1366 string_compose (_("There are insufficient JACK ports available\n\
1367 to create a new track or bus.\n\
1368 You should save %1, exit and\n\
1369 restart JACK with more ports."), PROGRAM_NAME));
1376 ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, RouteGroup* route_group, uint32_t how_many)
1378 list<boost::shared_ptr<AudioTrack> > tracks;
1381 if (_session == 0) {
1382 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1388 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1390 if (tracks.size() != how_many) {
1391 if (how_many == 1) {
1392 error << _("could not create a new audio track") << endmsg;
1394 error << string_compose (_("could only create %1 of %2 new audio %3"),
1395 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1401 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many);
1403 if (routes.size() != how_many) {
1404 if (how_many == 1) {
1405 error << _("could not create a new audio track") << endmsg;
1407 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1414 MessageDialog msg (*editor,
1415 string_compose (_("There are insufficient JACK ports available\n\
1416 to create a new track or bus.\n\
1417 You should save %1, exit and\n\
1418 restart JACK with more ports."), PROGRAM_NAME));
1425 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1427 framecnt_t _preroll = 0;
1430 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1431 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1433 if (new_position > _preroll) {
1434 new_position -= _preroll;
1439 _session->request_locate (new_position, with_roll);
1444 ARDOUR_UI::transport_goto_start ()
1447 _session->goto_start();
1449 /* force displayed area in editor to start no matter
1450 what "follow playhead" setting is.
1454 editor->center_screen (_session->current_start_frame ());
1460 ARDOUR_UI::transport_goto_zero ()
1463 _session->request_locate (0);
1465 /* force displayed area in editor to start no matter
1466 what "follow playhead" setting is.
1470 editor->reset_x_origin (0);
1476 ARDOUR_UI::transport_goto_wallclock ()
1478 if (_session && editor) {
1485 localtime_r (&now, &tmnow);
1487 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1488 frames += tmnow.tm_min * (60 * _session->frame_rate());
1489 frames += tmnow.tm_sec * _session->frame_rate();
1491 _session->request_locate (frames, _session->transport_rolling ());
1493 /* force displayed area in editor to start no matter
1494 what "follow playhead" setting is.
1498 editor->center_screen (frames);
1504 ARDOUR_UI::transport_goto_end ()
1507 framepos_t const frame = _session->current_end_frame();
1508 _session->request_locate (frame);
1510 /* force displayed area in editor to start no matter
1511 what "follow playhead" setting is.
1515 editor->center_screen (frame);
1521 ARDOUR_UI::transport_stop ()
1527 if (_session->is_auditioning()) {
1528 _session->cancel_audition ();
1532 _session->request_stop (false, true);
1536 ARDOUR_UI::transport_stop_and_forget_capture ()
1539 _session->request_stop (true, true);
1544 ARDOUR_UI::remove_last_capture()
1547 editor->remove_last_capture();
1552 ARDOUR_UI::transport_record (bool roll)
1556 switch (_session->record_status()) {
1557 case Session::Disabled:
1558 if (_session->ntracks() == 0) {
1559 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1563 _session->maybe_enable_record ();
1568 case Session::Recording:
1570 _session->request_stop();
1572 _session->disable_record (false, true);
1576 case Session::Enabled:
1577 _session->disable_record (false, true);
1580 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1584 ARDOUR_UI::transport_roll ()
1590 if (_session->is_auditioning()) {
1595 if (_session->config.get_external_sync()) {
1596 switch (_session->config.get_sync_source()) {
1600 /* transport controlled by the master */
1606 bool rolling = _session->transport_rolling();
1608 if (_session->get_play_loop()) {
1609 /* XXX it is not possible to just leave seamless loop and keep
1610 playing at present (nov 4th 2009)
1612 if (!Config->get_seamless_loop()) {
1613 _session->request_play_loop (false, true);
1615 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1616 /* stop playing a range if we currently are */
1617 _session->request_play_range (0, true);
1620 if (join_play_range_button.get_active()) {
1621 _session->request_play_range (&editor->get_selection().time, true);
1625 _session->request_transport_speed (1.0f);
1630 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1637 if (_session->is_auditioning()) {
1638 _session->cancel_audition ();
1643 if (_session->config.get_external_sync()) {
1644 switch (_session->config.get_sync_source()) {
1648 /* transport controlled by the master */
1654 bool rolling = _session->transport_rolling();
1655 bool affect_transport = true;
1657 if (rolling && roll_out_of_bounded_mode) {
1658 /* drop out of loop/range playback but leave transport rolling */
1659 if (_session->get_play_loop()) {
1660 if (Config->get_seamless_loop()) {
1661 /* the disk buffers contain copies of the loop - we can't
1662 just keep playing, so stop the transport. the user
1663 can restart as they wish.
1665 affect_transport = true;
1667 /* disk buffers are normal, so we can keep playing */
1668 affect_transport = false;
1670 _session->request_play_loop (false, true);
1671 } else if (_session->get_play_range ()) {
1672 affect_transport = false;
1673 _session->request_play_range (0, true);
1677 if (affect_transport) {
1679 _session->request_stop (with_abort, true);
1681 if (join_play_range_button.get_active()) {
1682 _session->request_play_range (&editor->get_selection().time, true);
1685 _session->request_transport_speed (1.0f);
1691 ARDOUR_UI::toggle_session_auto_loop ()
1697 if (_session->get_play_loop()) {
1699 if (_session->transport_rolling()) {
1701 Location * looploc = _session->locations()->auto_loop_location();
1704 _session->request_locate (looploc->start(), true);
1705 _session->request_play_loop (false);
1709 _session->request_play_loop (false);
1713 Location * looploc = _session->locations()->auto_loop_location();
1716 _session->request_play_loop (true);
1722 ARDOUR_UI::transport_play_selection ()
1728 editor->play_selection ();
1732 ARDOUR_UI::transport_rewind (int option)
1734 float current_transport_speed;
1737 current_transport_speed = _session->transport_speed();
1739 if (current_transport_speed >= 0.0f) {
1742 _session->request_transport_speed (-1.0f);
1745 _session->request_transport_speed (-4.0f);
1748 _session->request_transport_speed (-0.5f);
1753 _session->request_transport_speed (current_transport_speed * 1.5f);
1759 ARDOUR_UI::transport_forward (int option)
1761 float current_transport_speed;
1764 current_transport_speed = _session->transport_speed();
1766 if (current_transport_speed <= 0.0f) {
1769 _session->request_transport_speed (1.0f);
1772 _session->request_transport_speed (4.0f);
1775 _session->request_transport_speed (0.5f);
1780 _session->request_transport_speed (current_transport_speed * 1.5f);
1787 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1789 if (_session == 0) {
1793 boost::shared_ptr<Route> r;
1795 if ((r = _session->route_by_remote_id (rid)) != 0) {
1799 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1800 t->set_record_enabled (!t->record_enabled(), this);
1803 if (_session == 0) {
1809 ARDOUR_UI::map_transport_state ()
1811 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1814 auto_loop_button.set_visual_state (0);
1815 play_selection_button.set_visual_state (0);
1816 roll_button.set_visual_state (0);
1817 stop_button.set_visual_state (1);
1821 float sp = _session->transport_speed();
1824 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1825 shuttle_box.queue_draw ();
1826 } else if (sp == 0.0f) {
1828 shuttle_box.queue_draw ();
1829 update_disk_space ();
1836 if (_session->get_play_range()) {
1838 play_selection_button.set_visual_state (1);
1839 roll_button.set_visual_state (0);
1840 auto_loop_button.set_visual_state (0);
1842 } else if (_session->get_play_loop ()) {
1844 auto_loop_button.set_visual_state (1);
1845 play_selection_button.set_visual_state (0);
1846 roll_button.set_visual_state (0);
1850 roll_button.set_visual_state (1);
1851 play_selection_button.set_visual_state (0);
1852 auto_loop_button.set_visual_state (0);
1855 if (join_play_range_button.get_active()) {
1856 /* light up both roll and play-selection if they are joined */
1857 roll_button.set_visual_state (1);
1858 play_selection_button.set_visual_state (1);
1861 stop_button.set_visual_state (0);
1865 stop_button.set_visual_state (1);
1866 roll_button.set_visual_state (0);
1867 play_selection_button.set_visual_state (0);
1868 auto_loop_button.set_visual_state (0);
1873 ARDOUR_UI::engine_stopped ()
1875 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1876 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1877 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1881 ARDOUR_UI::engine_running ()
1883 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1884 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1885 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1887 Glib::RefPtr<Action> action;
1888 const char* action_name = 0;
1890 switch (engine->frames_per_cycle()) {
1892 action_name = X_("JACKLatency32");
1895 action_name = X_("JACKLatency64");
1898 action_name = X_("JACKLatency128");
1901 action_name = X_("JACKLatency512");
1904 action_name = X_("JACKLatency1024");
1907 action_name = X_("JACKLatency2048");
1910 action_name = X_("JACKLatency4096");
1913 action_name = X_("JACKLatency8192");
1916 /* XXX can we do anything useful ? */
1922 action = ActionManager::get_action (X_("JACK"), action_name);
1925 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1926 ract->set_active ();
1932 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1934 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1935 /* we can't rely on the original string continuing to exist when we are called
1936 again in the GUI thread, so make a copy and note that we need to
1939 char *copy = strdup (reason);
1940 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1944 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1945 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1947 update_sample_rate (0);
1951 /* if the reason is a non-empty string, it means that the backend was shutdown
1952 rather than just Ardour.
1955 if (strlen (reason)) {
1956 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1958 msgstr = string_compose (_("\
1959 JACK has either been shutdown or it\n\
1960 disconnected %1 because %1\n\
1961 was not fast enough. Try to restart\n\
1962 JACK, reconnect and save the session."), PROGRAM_NAME);
1965 MessageDialog msg (*editor, msgstr);
1970 free ((char*) reason);
1975 ARDOUR_UI::do_engine_start ()
1983 error << _("Unable to start the session running")
1993 ARDOUR_UI::setup_theme ()
1995 theme_manager->setup_theme();
1999 ARDOUR_UI::update_clocks ()
2001 if (!editor || !editor->dragging_playhead()) {
2002 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2007 ARDOUR_UI::start_clocking ()
2009 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2013 ARDOUR_UI::stop_clocking ()
2015 clock_signal_connection.disconnect ();
2019 ARDOUR_UI::toggle_clocking ()
2022 if (clock_button.get_active()) {
2031 ARDOUR_UI::_blink (void *arg)
2034 ((ARDOUR_UI *) arg)->blink ();
2041 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2045 ARDOUR_UI::start_blinking ()
2047 /* Start the blink signal. Everybody with a blinking widget
2048 uses Blink to drive the widget's state.
2051 if (blink_timeout_tag < 0) {
2053 blink_timeout_tag = g_timeout_add (240, _blink, this);
2058 ARDOUR_UI::stop_blinking ()
2060 if (blink_timeout_tag >= 0) {
2061 g_source_remove (blink_timeout_tag);
2062 blink_timeout_tag = -1;
2067 /** Ask the user for the name of a new shapshot and then take it.
2071 ARDOUR_UI::snapshot_session (bool switch_to_it)
2073 ArdourPrompter prompter (true);
2076 prompter.set_name ("Prompter");
2077 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2078 prompter.set_title (_("Take Snapshot"));
2079 prompter.set_title (_("Take Snapshot"));
2080 prompter.set_prompt (_("Name of new snapshot"));
2082 if (!switch_to_it) {
2085 struct tm local_time;
2088 localtime_r (&n, &local_time);
2089 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2090 prompter.set_initial_text (timebuf);
2094 switch (prompter.run()) {
2095 case RESPONSE_ACCEPT:
2097 prompter.get_result (snapname);
2099 bool do_save = (snapname.length() != 0);
2102 if (snapname.find ('/') != string::npos) {
2103 MessageDialog msg (_("To ensure compatibility with various systems\n"
2104 "snapshot names may not contain a '/' character"));
2108 if (snapname.find ('\\') != string::npos) {
2109 MessageDialog msg (_("To ensure compatibility with various systems\n"
2110 "snapshot names may not contain a '\\' character"));
2116 vector<sys::path> p;
2117 get_state_files_in_directory (_session->session_directory().root_path(), p);
2118 vector<string> n = get_file_names_no_extension (p);
2119 if (find (n.begin(), n.end(), snapname) != n.end()) {
2121 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2122 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2123 confirm.get_vbox()->pack_start (m, true, true);
2124 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2125 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2126 confirm.show_all ();
2127 switch (confirm.run()) {
2128 case RESPONSE_CANCEL:
2134 save_state (snapname, switch_to_it);
2145 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2147 XMLNode* node = new XMLNode (X_("UI"));
2149 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2150 if (!(*i)->rc_configured()) {
2151 node->add_child_nocopy (*((*i)->get_state ()));
2155 _session->add_extra_xml (*node);
2157 save_state_canfail (name, switch_to_it);
2161 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2166 if (name.length() == 0) {
2167 name = _session->snap_name();
2170 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2174 cerr << "SS canfail\n";
2175 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2180 ARDOUR_UI::primary_clock_value_changed ()
2183 _session->request_locate (primary_clock.current_time ());
2188 ARDOUR_UI::big_clock_value_changed ()
2191 _session->request_locate (big_clock.current_time ());
2196 ARDOUR_UI::secondary_clock_value_changed ()
2199 _session->request_locate (secondary_clock.current_time ());
2204 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2206 if (_session == 0) {
2210 if (_session->step_editing()) {
2214 Session::RecordState const r = _session->record_status ();
2215 bool const h = _session->have_rec_enabled_track ();
2217 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2219 rec_button.set_visual_state (2);
2221 rec_button.set_visual_state (0);
2223 } else if (r == Session::Recording && h) {
2224 rec_button.set_visual_state (1);
2226 rec_button.set_visual_state (0);
2231 ARDOUR_UI::save_template ()
2233 ArdourPrompter prompter (true);
2236 if (!check_audioengine()) {
2240 prompter.set_name (X_("Prompter"));
2241 prompter.set_title (_("Save Template"));
2242 prompter.set_prompt (_("Name for template:"));
2243 prompter.set_initial_text(_session->name() + _("-template"));
2244 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2246 switch (prompter.run()) {
2247 case RESPONSE_ACCEPT:
2248 prompter.get_result (name);
2250 if (name.length()) {
2251 _session->save_template (name);
2261 ARDOUR_UI::edit_metadata ()
2263 SessionMetadataEditor dialog;
2264 dialog.set_session (_session);
2265 editor->ensure_float (dialog);
2270 ARDOUR_UI::import_metadata ()
2272 SessionMetadataImporter dialog;
2273 dialog.set_session (_session);
2274 editor->ensure_float (dialog);
2279 ARDOUR_UI::fontconfig_dialog ()
2282 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2283 may not and it can take a while to build it. Warn them.
2286 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2288 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2289 MessageDialog msg (*_startup,
2290 string_compose (_("Welcome to %1.\n\n"
2291 "The program will take a bit longer to start up\n"
2292 "while the system fonts are checked.\n\n"
2293 "This will only be done once, and you will\n"
2294 "not see this message again\n"), PROGRAM_NAME),
2307 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2309 existing_session = false;
2311 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2312 session_path = cmdline_path;
2313 existing_session = true;
2314 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2315 session_path = Glib::path_get_dirname (string (cmdline_path));
2316 existing_session = true;
2318 /* it doesn't exist, assume the best */
2319 session_path = Glib::path_get_dirname (string (cmdline_path));
2322 session_name = basename_nosuffix (string (cmdline_path));
2326 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2328 /* when this is called, the backend audio system must be running */
2330 /* the main idea here is to deal with the fact that a cmdline argument for the session
2331 can be interpreted in different ways - it could be a directory or a file, and before
2332 we load, we need to know both the session directory and the snapshot (statefile) within it
2333 that we are supposed to use.
2336 if (session_name.length() == 0 || session_path.length() == 0) {
2340 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2342 std::string predicted_session_file;
2344 predicted_session_file = session_path;
2345 predicted_session_file += '/';
2346 predicted_session_file += session_name;
2347 predicted_session_file += ARDOUR::statefile_suffix;
2349 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2350 existing_session = true;
2353 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2355 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2356 /* existing .ardour file */
2357 existing_session = true;
2361 existing_session = false;
2364 /* lets just try to load it */
2366 if (create_engine ()) {
2367 backend_audio_error (false, _startup);
2371 return load_session (session_path, session_name);
2375 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2377 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2379 MessageDialog msg (str,
2381 Gtk::MESSAGE_WARNING,
2382 Gtk::BUTTONS_YES_NO,
2386 msg.set_name (X_("OpenExistingDialog"));
2387 msg.set_title (_("Open Existing Session"));
2388 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2389 msg.set_position (Gtk::WIN_POS_MOUSE);
2392 switch (msg.run()) {
2401 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2403 BusProfile bus_profile;
2405 if (Profile->get_sae()) {
2407 bus_profile.master_out_channels = 2;
2408 bus_profile.input_ac = AutoConnectPhysical;
2409 bus_profile.output_ac = AutoConnectMaster;
2410 bus_profile.requested_physical_in = 0; // use all available
2411 bus_profile.requested_physical_out = 0; // use all available
2415 /* get settings from advanced section of NSD */
2417 if (_startup->create_master_bus()) {
2418 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2420 bus_profile.master_out_channels = 0;
2423 if (_startup->connect_inputs()) {
2424 bus_profile.input_ac = AutoConnectPhysical;
2426 bus_profile.input_ac = AutoConnectOption (0);
2429 /// @todo some minor tweaks.
2431 bus_profile.output_ac = AutoConnectOption (0);
2433 if (_startup->connect_outputs ()) {
2434 if (_startup->connect_outs_to_master()) {
2435 bus_profile.output_ac = AutoConnectMaster;
2436 } else if (_startup->connect_outs_to_physical()) {
2437 bus_profile.output_ac = AutoConnectPhysical;
2441 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2442 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2445 if (build_session (session_path, session_name, bus_profile)) {
2453 ARDOUR_UI::idle_load (const std::string& path)
2456 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2457 /* /path/to/foo => /path/to/foo, foo */
2458 load_session (path, basename_nosuffix (path));
2460 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2461 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2465 ARDOUR_COMMAND_LINE::session_name = path;
2468 * new_session_dialog doens't exist in A3
2469 * Try to remove all references to it to
2470 * see if it will compile. NOTE: this will
2471 * likely cause a runtime issue is my somewhat
2475 //if (new_session_dialog) {
2478 /* make it break out of Dialog::run() and
2482 //new_session_dialog->response (1);
2488 ARDOUR_UI::end_loading_messages ()
2494 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2497 // splash->message (msg);
2501 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2503 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2505 string session_name;
2506 string session_path;
2507 string template_name;
2509 bool likely_new = false;
2511 if (! load_template.empty()) {
2512 should_be_new = true;
2513 template_name = load_template;
2518 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2520 /* if they named a specific statefile, use it, otherwise they are
2521 just giving a session folder, and we want to use it as is
2522 to find the session.
2525 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2526 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2528 session_path = ARDOUR_COMMAND_LINE::session_name;
2531 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2535 bool const apply = run_startup (should_be_new, load_template);
2538 if (quit_on_cancel) {
2545 /* if we run the startup dialog again, offer more than just "new session" */
2547 should_be_new = false;
2549 session_name = _startup->session_name (likely_new);
2551 /* this shouldn't happen, but we catch it just in case it does */
2553 if (session_name.empty()) {
2557 if (_startup->use_session_template()) {
2558 template_name = _startup->session_template_name();
2559 _session_is_new = true;
2562 if (session_name[0] == G_DIR_SEPARATOR ||
2563 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2564 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2566 /* absolute path or cwd-relative path specified for session name: infer session folder
2567 from what was given.
2570 session_path = Glib::path_get_dirname (session_name);
2571 session_name = Glib::path_get_basename (session_name);
2575 session_path = _startup->session_folder();
2577 if (session_name.find ('/') != string::npos) {
2578 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2579 "session names may not contain a '/' character"));
2581 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2585 if (session_name.find ('\\') != string::npos) {
2586 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2587 "session names may not contain a '\\' character"));
2589 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2595 if (create_engine ()) {
2599 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2603 std::string existing = Glib::build_filename (session_path, session_name);
2605 if (!ask_about_loading_existing_session (existing)) {
2606 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2611 _session_is_new = false;
2616 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2618 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2622 if (session_name.find ('/') != std::string::npos) {
2623 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2624 "session names may not contain a '/' character"));
2626 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2630 if (session_name.find ('\\') != std::string::npos) {
2631 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2632 "session names may not contain a '\\' character"));
2634 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2638 _session_is_new = true;
2641 if (likely_new && template_name.empty()) {
2643 ret = build_session_from_nsd (session_path, session_name);
2647 ret = load_session (session_path, session_name, template_name);
2650 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2654 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2655 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2665 ARDOUR_UI::close_session()
2667 if (!check_audioengine()) {
2671 if (unload_session (true)) {
2675 ARDOUR_COMMAND_LINE::session_name = "";
2677 if (get_session_parameters (true, false)) {
2681 goto_editor_window ();
2684 /** @return -2 if the load failed because we are not connected to the AudioEngine */
2686 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2688 Session *new_session;
2692 session_loaded = false;
2694 if (!check_audioengine()) {
2698 unload_status = unload_session ();
2700 if (unload_status < 0) {
2702 } else if (unload_status > 0) {
2707 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2710 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2713 /* this one is special */
2715 catch (AudioEngine::PortRegistrationFailure& err) {
2717 MessageDialog msg (err.what(),
2720 Gtk::BUTTONS_CLOSE);
2722 msg.set_title (_("Port Registration Error"));
2723 msg.set_secondary_text (_("Click the Close button to try again."));
2724 msg.set_position (Gtk::WIN_POS_CENTER);
2728 int response = msg.run ();
2733 case RESPONSE_CANCEL:
2743 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"),path, snap_name),
2748 msg.set_title (_("Loading Error"));
2749 msg.set_secondary_text (_("Click the Refresh button to try again."));
2750 msg.add_button (Stock::REFRESH, 1);
2751 msg.set_position (Gtk::WIN_POS_CENTER);
2755 int response = msg.run ();
2770 list<string> const u = new_session->unknown_processors ();
2772 MissingPluginDialog d (_session, u);
2777 /* Now the session been created, add the transport controls */
2778 new_session->add_controllable(roll_controllable);
2779 new_session->add_controllable(stop_controllable);
2780 new_session->add_controllable(goto_start_controllable);
2781 new_session->add_controllable(goto_end_controllable);
2782 new_session->add_controllable(auto_loop_controllable);
2783 new_session->add_controllable(play_selection_controllable);
2784 new_session->add_controllable(rec_controllable);
2786 set_session (new_session);
2788 session_loaded = true;
2790 goto_editor_window ();
2793 _session->set_clean ();
2804 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2806 Session *new_session;
2809 if (!check_audioengine()) {
2813 session_loaded = false;
2815 x = unload_session ();
2823 _session_is_new = true;
2826 new_session = new Session (*engine, path, snap_name, &bus_profile);
2831 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2837 /* Give the new session the default GUI state, if such things exist */
2840 n = Config->instant_xml (X_("Editor"));
2842 new_session->add_instant_xml (*n, false);
2844 n = Config->instant_xml (X_("Mixer"));
2846 new_session->add_instant_xml (*n, false);
2849 /* Put the playhead at 0 and scroll fully left */
2850 n = new_session->instant_xml (X_("Editor"));
2852 n->add_property (X_("playhead"), X_("0"));
2853 n->add_property (X_("left-frame"), X_("0"));
2856 set_session (new_session);
2858 session_loaded = true;
2860 new_session->save_state(new_session->name());
2866 ARDOUR_UI::launch_chat ()
2869 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2871 open_uri("http://webchat.freenode.net/?channels=ardour");
2876 ARDOUR_UI::show_about ()
2880 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2883 about->set_transient_for(*editor);
2888 ARDOUR_UI::launch_manual ()
2890 PBD::open_uri("http://ardour.org/flossmanual");
2894 ARDOUR_UI::launch_reference ()
2896 PBD::open_uri("http://ardour.org/refmanual");
2900 ARDOUR_UI::hide_about ()
2903 about->get_window()->set_cursor ();
2909 ARDOUR_UI::about_signal_response (int /*response*/)
2915 ARDOUR_UI::show_splash ()
2919 splash = new Splash;
2927 splash->queue_draw ();
2928 splash->get_window()->process_updates (true);
2933 ARDOUR_UI::hide_splash ()
2941 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2942 const string& plural_msg, const string& singular_msg)
2946 removed = rep.paths.size();
2949 MessageDialog msgd (*editor,
2950 _("No audio files were ready for cleanup"),
2953 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2954 msgd.set_secondary_text (_("If this seems suprising, \n\
2955 check for any existing snapshots.\n\
2956 These may still include regions that\n\
2957 require some unused files to continue to exist."));
2963 ArdourDialog results (_("Clean-up"), true, false);
2965 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2966 CleanupResultsModelColumns() {
2970 Gtk::TreeModelColumn<std::string> visible_name;
2971 Gtk::TreeModelColumn<std::string> fullpath;
2975 CleanupResultsModelColumns results_columns;
2976 Glib::RefPtr<Gtk::ListStore> results_model;
2977 Gtk::TreeView results_display;
2979 results_model = ListStore::create (results_columns);
2980 results_display.set_model (results_model);
2981 results_display.append_column (list_title, results_columns.visible_name);
2983 results_display.set_name ("CleanupResultsList");
2984 results_display.set_headers_visible (true);
2985 results_display.set_headers_clickable (false);
2986 results_display.set_reorderable (false);
2988 Gtk::ScrolledWindow list_scroller;
2991 Gtk::HBox dhbox; // the hbox for the image and text
2992 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2993 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2995 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2997 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
3000 %1 - number of files removed
3001 %2 - location of "dead_sounds"
3002 %3 - size of files affected
3003 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3006 const char* bprefix;
3007 double space_adjusted = 0;
3009 if (rep.space < 100000.0f) {
3010 bprefix = X_("kilo");
3011 } else if (rep.space < 1000000.0f * 1000) {
3012 bprefix = X_("mega");
3013 space_adjusted = truncf((float)rep.space / 1000.0);
3015 bprefix = X_("giga");
3016 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
3020 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
3022 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
3025 dhbox.pack_start (*dimage, true, false, 5);
3026 dhbox.pack_start (txt, true, false, 5);
3028 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3029 TreeModel::Row row = *(results_model->append());
3030 row[results_columns.visible_name] = *i;
3031 row[results_columns.fullpath] = *i;
3034 list_scroller.add (results_display);
3035 list_scroller.set_size_request (-1, 150);
3036 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3038 dvbox.pack_start (dhbox, true, false, 5);
3039 dvbox.pack_start (list_scroller, true, false, 5);
3040 ddhbox.pack_start (dvbox, true, false, 5);
3042 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3043 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3044 results.set_default_response (RESPONSE_CLOSE);
3045 results.set_position (Gtk::WIN_POS_MOUSE);
3047 results_display.show();
3048 list_scroller.show();
3055 //results.get_vbox()->show();
3056 results.set_resizable (false);
3063 ARDOUR_UI::cleanup ()
3065 if (_session == 0) {
3066 /* shouldn't happen: menu item is insensitive */
3071 MessageDialog checker (_("Are you sure you want to cleanup?"),
3073 Gtk::MESSAGE_QUESTION,
3074 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3076 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3077 ALL undo/redo information will be lost if you cleanup.\n\
3078 After cleanup, unused audio files will be moved to a \
3079 \"dead sounds\" location."));
3081 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3082 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3083 checker.set_default_response (RESPONSE_CANCEL);
3085 checker.set_name (_("CleanupDialog"));
3086 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3087 checker.set_position (Gtk::WIN_POS_MOUSE);
3089 switch (checker.run()) {
3090 case RESPONSE_ACCEPT:
3096 ARDOUR::CleanupReport rep;
3098 editor->prepare_for_cleanup ();
3100 /* do not allow flush until a session is reloaded */
3102 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3104 act->set_sensitive (false);
3107 if (_session->cleanup_sources (rep)) {
3108 editor->finish_cleanup ();
3112 editor->finish_cleanup ();
3115 display_cleanup_results (rep,
3118 The following %1 files were not in use and \n\
3119 have been moved to:\n\
3121 Flushing the wastebasket will \n\
3122 release an additional\n\
3123 %3 %4bytes of disk space.\n"),
3125 The following file was not in use and \n \
3126 has been moved to:\n \
3128 Flushing the wastebasket will \n\
3129 release an additional\n\
3130 %3 %4bytes of disk space.\n"
3136 ARDOUR_UI::flush_trash ()
3138 if (_session == 0) {
3139 /* shouldn't happen: menu item is insensitive */
3143 ARDOUR::CleanupReport rep;
3145 if (_session->cleanup_trash_sources (rep)) {
3149 display_cleanup_results (rep,
3151 _("The following %1 files were deleted from\n\
3153 releasing %3 %4bytes of disk space"),
3154 _("The following file was deleted from\n\
3156 releasing %3 %4bytes of disk space"));
3160 ARDOUR_UI::add_route (Gtk::Window* float_window)
3168 if (add_route_dialog == 0) {
3169 add_route_dialog = new AddRouteDialog (_session);
3171 add_route_dialog->set_transient_for (*float_window);
3175 if (add_route_dialog->is_visible()) {
3176 /* we're already doing this */
3180 ResponseType r = (ResponseType) add_route_dialog->run ();
3182 add_route_dialog->hide();
3185 case RESPONSE_ACCEPT:
3192 if ((count = add_route_dialog->count()) <= 0) {
3196 string template_path = add_route_dialog->track_template();
3198 if (!template_path.empty()) {
3199 _session->new_route_from_template (count, template_path);
3203 uint32_t input_chan = add_route_dialog->channels ();
3204 uint32_t output_chan;
3205 string name_template = add_route_dialog->name_template ();
3206 bool track = add_route_dialog->track ();
3207 RouteGroup* route_group = add_route_dialog->route_group ();
3209 AutoConnectOption oac = Config->get_output_auto_connect();
3211 if (oac & AutoConnectMaster) {
3212 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3214 output_chan = input_chan;
3217 /* XXX do something with name template */
3219 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3221 session_add_midi_track (route_group, count);
3223 MessageDialog msg (*editor,
3224 _("Sorry, MIDI Busses are not supported at this time."));
3226 //session_add_midi_bus();
3230 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3232 session_add_audio_bus (input_chan, output_chan, route_group, count);
3238 ARDOUR_UI::mixer_settings () const
3243 node = _session->instant_xml(X_("Mixer"));
3245 node = Config->instant_xml(X_("Mixer"));
3249 node = new XMLNode (X_("Mixer"));
3256 ARDOUR_UI::editor_settings () const
3261 node = _session->instant_xml(X_("Editor"));
3263 node = Config->instant_xml(X_("Editor"));
3267 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3268 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3273 node = new XMLNode (X_("Editor"));
3280 ARDOUR_UI::keyboard_settings () const
3284 node = Config->extra_xml(X_("Keyboard"));
3287 node = new XMLNode (X_("Keyboard"));
3293 ARDOUR_UI::create_xrun_marker (framepos_t where)
3295 editor->mouse_add_new_marker (where, false, true);
3299 ARDOUR_UI::halt_on_xrun_message ()
3301 MessageDialog msg (*editor,
3302 _("Recording was stopped because your system could not keep up."));
3307 ARDOUR_UI::xrun_handler (framepos_t where)
3313 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3315 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3316 create_xrun_marker(where);
3319 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3320 halt_on_xrun_message ();
3325 ARDOUR_UI::disk_overrun_handler ()
3327 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3329 if (!have_disk_speed_dialog_displayed) {
3330 have_disk_speed_dialog_displayed = true;
3331 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3332 The disk system on your computer\n\
3333 was not able to keep up with %1.\n\
3335 Specifically, it failed to write data to disk\n\
3336 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3337 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3343 ARDOUR_UI::disk_underrun_handler ()
3345 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3347 if (!have_disk_speed_dialog_displayed) {
3348 have_disk_speed_dialog_displayed = true;
3349 MessageDialog* msg = new MessageDialog (*editor,
3350 string_compose (_("The disk system on your computer\n\
3351 was not able to keep up with %1.\n\
3353 Specifically, it failed to read data from disk\n\
3354 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3355 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3361 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3363 have_disk_speed_dialog_displayed = false;
3368 ARDOUR_UI::session_dialog (std::string msg)
3370 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3375 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3377 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3386 ARDOUR_UI::pending_state_dialog ()
3388 HBox* hbox = new HBox();
3389 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3390 ArdourDialog dialog (_("Crash Recovery"), true);
3392 This session appears to have been in\n\
3393 middle of recording when ardour or\n\
3394 the computer was shutdown.\n\
3396 Ardour can recover any captured audio for\n\
3397 you, or it can ignore it. Please decide\n\
3398 what you would like to do.\n"));
3399 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3400 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3401 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3402 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3403 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3404 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3405 dialog.set_default_response (RESPONSE_ACCEPT);
3406 dialog.set_position (WIN_POS_CENTER);
3411 switch (dialog.run ()) {
3412 case RESPONSE_ACCEPT:
3420 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3422 HBox* hbox = new HBox();
3423 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3424 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3425 Label message (string_compose (_("\
3426 This session was created with a sample rate of %1 Hz\n\
3428 The audioengine is currently running at %2 Hz\n"), desired, actual));
3430 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3431 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3432 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3433 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3434 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3435 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3436 dialog.set_default_response (RESPONSE_ACCEPT);
3437 dialog.set_position (WIN_POS_CENTER);
3442 switch (dialog.run ()) {
3443 case RESPONSE_ACCEPT:
3452 ARDOUR_UI::disconnect_from_jack ()
3455 if( engine->disconnect_from_jack ()) {
3456 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3460 update_sample_rate (0);
3465 ARDOUR_UI::reconnect_to_jack ()
3468 if (engine->reconnect_to_jack ()) {
3469 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3473 update_sample_rate (0);
3478 ARDOUR_UI::use_config ()
3480 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3482 set_transport_controllable_state (*node);
3487 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3489 if (Config->get_primary_clock_delta_edit_cursor()) {
3490 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3492 primary_clock.set (pos, 0, true);
3495 if (Config->get_secondary_clock_delta_edit_cursor()) {
3496 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3498 secondary_clock.set (pos);
3501 if (big_clock_window->get()) {
3502 big_clock.set (pos);
3508 ARDOUR_UI::step_edit_status_change (bool yn)
3510 // XXX should really store pre-step edit status of things
3511 // we make insensitive
3514 rec_button.set_visual_state (3);
3515 rec_button.set_sensitive (false);
3517 rec_button.set_visual_state (0);
3518 rec_button.set_sensitive (true);
3523 ARDOUR_UI::record_state_changed ()
3525 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3527 if (!_session || !big_clock_window->get()) {
3528 /* why bother - the clock isn't visible */
3532 Session::RecordState const r = _session->record_status ();
3533 bool const h = _session->have_rec_enabled_track ();
3535 if (r == Session::Recording && h) {
3536 big_clock.set_widget_name ("BigClockRecording");
3538 big_clock.set_widget_name ("BigClockNonRecording");
3543 ARDOUR_UI::first_idle ()
3546 _session->allow_auto_play (true);
3550 editor->first_idle();
3553 Keyboard::set_can_save_keybindings (true);
3558 ARDOUR_UI::store_clock_modes ()
3560 XMLNode* node = new XMLNode(X_("ClockModes"));
3562 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3563 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3566 _session->add_extra_xml (*node);
3567 _session->set_dirty ();
3572 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3573 : Controllable (name), ui (u), type(tp)
3579 ARDOUR_UI::TransportControllable::set_value (double val)
3581 if (type == ShuttleControl) {
3588 fract = -((0.5 - val)/0.5);
3590 fract = ((val - 0.5)/0.5);
3594 ui.set_shuttle_fract (fract);
3599 /* do nothing: these are radio-style actions */
3603 const char *action = 0;
3607 action = X_("Roll");
3610 action = X_("Stop");
3613 action = X_("Goto Start");
3616 action = X_("Goto End");
3619 action = X_("Loop");
3622 action = X_("Play Selection");
3625 action = X_("Record");
3635 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3643 ARDOUR_UI::TransportControllable::get_value (void) const
3662 case ShuttleControl:
3672 ARDOUR_UI::TransportControllable::set_id (const string& str)
3678 ARDOUR_UI::setup_profile ()
3680 if (gdk_screen_width() < 1200) {
3681 Profile->set_small_screen ();
3685 if (getenv ("ARDOUR_SAE")) {
3686 Profile->set_sae ();
3687 Profile->set_single_package ();
3692 ARDOUR_UI::toggle_translations ()
3694 using namespace Glib;
3696 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3698 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3701 string i18n_killer = ARDOUR::translation_kill_path();
3703 bool already_enabled = !ARDOUR::translations_are_disabled ();
3705 if (ract->get_active ()) {
3706 /* we don't care about errors */
3707 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3710 /* we don't care about errors */
3711 unlink (i18n_killer.c_str());
3714 if (already_enabled != ract->get_active()) {
3715 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3717 Gtk::MESSAGE_WARNING,
3719 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3720 win.set_position (Gtk::WIN_POS_CENTER);
3728 /** Add a window proxy to our list, so that its state will be saved.
3729 * This call also causes the window to be created and opened if its
3730 * state was saved as `visible'.
3733 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3735 _window_proxies.push_back (p);
3739 /** Remove a window proxy from our list. Must be called if a WindowProxy
3740 * is deleted, to prevent hanging pointers.
3743 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3745 _window_proxies.remove (p);
3749 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3751 MissingFileDialog dialog (s, str, type);
3756 int result = dialog.run ();
3763 return 1; // quit entire session load
3766 result = dialog.get_action ();
3772 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3774 AmbiguousFileDialog dialog (file, hits);
3780 return dialog.get_which ();