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/bindings.h"
53 #include "gtkmm2ext/gtk_ui.h"
54 #include "gtkmm2ext/utils.h"
55 #include "gtkmm2ext/click_box.h"
56 #include "gtkmm2ext/fastmeter.h"
57 #include "gtkmm2ext/popup.h"
58 #include "gtkmm2ext/window_title.h"
60 #include "midi++/manager.h"
62 #include "ardour/ardour.h"
63 #include "ardour/callback.h"
64 #include "ardour/profile.h"
65 #include "ardour/session_directory.h"
66 #include "ardour/session_route.h"
67 #include "ardour/session_state_utils.h"
68 #include "ardour/session_utils.h"
69 #include "ardour/port.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/playlist.h"
72 #include "ardour/utils.h"
73 #include "ardour/audio_diskstream.h"
74 #include "ardour/audiofilesource.h"
75 #include "ardour/recent_sessions.h"
76 #include "ardour/port.h"
77 #include "ardour/audio_track.h"
78 #include "ardour/midi_track.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/filename_extensions.h"
81 #include "ardour/process_thread.h"
83 typedef uint64_t microseconds_t;
87 #include "add_route_dialog.h"
88 #include "ambiguous_file_dialog.h"
89 #include "ardour_ui.h"
90 #include "audio_clock.h"
91 #include "bundle_manager.h"
92 #include "engine_dialog.h"
93 #include "gain_meter.h"
94 #include "global_port_matrix.h"
95 #include "gui_object.h"
96 #include "gui_thread.h"
98 #include "location_ui.h"
99 #include "missing_file_dialog.h"
100 #include "missing_plugin_dialog.h"
101 #include "mixer_ui.h"
103 #include "processor_box.h"
104 #include "prompter.h"
105 #include "public_editor.h"
106 #include "route_time_axis.h"
107 #include "session_metadata_dialog.h"
108 #include "shuttle_control.h"
109 #include "speaker_dialog.h"
112 #include "theme_manager.h"
113 #include "time_axis_view_item.h"
115 #include "window_proxy.h"
119 using namespace ARDOUR;
121 using namespace Gtkmm2ext;
124 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
125 UIConfiguration *ARDOUR_UI::ui_config = 0;
127 sigc::signal<void,bool> ARDOUR_UI::Blink;
128 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
129 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
130 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
132 bool could_be_a_valid_path (const string& path);
134 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
136 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
138 , gui_object_state (new GUIObjectState)
139 , primary_clock (new AudioClock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true))
140 , secondary_clock (new AudioClock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true))
144 , big_clock (new AudioClock (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))
156 , auto_return_button (ArdourButton::led_default_elements)
157 , auto_play_button (ArdourButton::led_default_elements)
158 , auto_input_button (ArdourButton::led_default_elements)
160 , time_master_button (_("time\nmaster"))
162 , auditioning_alert_button (_("AUDITION"))
163 , solo_alert_button (_("SOLO"))
165 , error_log_button (_("Errors"))
167 , _status_bar_visibility (X_("status-bar"))
170 using namespace Gtk::Menu_Helpers;
176 // _auto_display_errors = false;
178 * This was commented out as it wasn't defined
179 * in A3 IIRC. If this is not needed it should
180 * be completely removed.
188 if (theArdourUI == 0) {
192 ui_config = new UIConfiguration();
193 theme_manager = new ThemeManager();
201 _session_is_new = false;
202 big_clock_window = 0;
203 big_clock_height = 0;
204 big_clock_resize_in_progress = false;
205 session_selector_window = 0;
206 last_key_press_time = 0;
207 _will_create_new_session_automatically = false;
208 add_route_dialog = 0;
211 rc_option_editor = 0;
212 session_option_editor = 0;
214 open_session_selector = 0;
215 have_configure_timeout = false;
216 have_disk_speed_dialog_displayed = false;
217 session_loaded = false;
218 ignore_dual_punch = false;
219 original_big_clock_width = -1;
220 original_big_clock_height = -1;
221 original_big_clock_font_size = 0;
223 roll_button.set_controllable (roll_controllable);
224 stop_button.set_controllable (stop_controllable);
225 goto_start_button.set_controllable (goto_start_controllable);
226 goto_end_button.set_controllable (goto_end_controllable);
227 auto_loop_button.set_controllable (auto_loop_controllable);
228 play_selection_button.set_controllable (play_selection_controllable);
229 rec_button.set_controllable (rec_controllable);
231 roll_button.set_name ("transport button");
232 stop_button.set_name ("transport button");
233 goto_start_button.set_name ("transport button");
234 goto_end_button.set_name ("transport button");
235 auto_loop_button.set_name ("transport button");
236 play_selection_button.set_name ("transport button");
237 rec_button.set_name ("transport recenable button");
238 join_play_range_button.set_name ("transport button");
240 roll_button.set_tweaks (ArdourButton::ShowHover);
241 stop_button.set_tweaks (ArdourButton::ShowHover);
242 auto_loop_button.set_tweaks (ArdourButton::ShowHover);
243 play_selection_button.set_tweaks (ArdourButton::ShowHover);
244 rec_button.set_tweaks (ArdourButton::ShowHover);
245 join_play_range_button.set_tweaks (ArdourButton::ShowHover);
247 goto_start_button.set_tweaks (ArdourButton::Tweaks(ArdourButton::ShowClick|ArdourButton::ShowHover));
248 goto_end_button.set_tweaks (ArdourButton::Tweaks(ArdourButton::ShowClick|ArdourButton::ShowHover));
250 last_configure_time= 0;
253 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
254 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
256 /* handle dialog requests */
258 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
260 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
262 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
264 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
266 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
268 /* handle requests to quit (coming from JACK session) */
270 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
272 /* tell the user about feedback */
274 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
276 /* handle requests to deal with missing files */
278 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
280 /* and ambiguous files */
282 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
284 /* lets get this party started */
287 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
288 throw failed_constructor ();
291 setup_gtk_ardour_enums ();
294 GainMeter::setup_slider_pix ();
295 RouteTimeAxisView::setup_slider_pix ();
296 SendProcessorEntry::setup_slider_pix ();
297 SessionEvent::create_per_thread_pool ("GUI", 512);
299 } catch (failed_constructor& err) {
300 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
305 /* we like keyboards */
307 keyboard = new ArdourKeyboard(*this);
309 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
311 keyboard->set_state (*node, Stateful::loading_state_version);
314 /* we don't like certain modifiers */
315 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
319 TimeAxisViewItem::set_constant_heights ();
321 /* The following must happen after ARDOUR::init() so that Config is set up */
323 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
324 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
325 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
327 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
328 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
329 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
330 Config->extra_xml (X_("UI")),
331 string_compose ("toggle-%1-connection-manager", (*i).to_string())
337 SpeakerDialog* s = new SpeakerDialog ();
338 s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
339 speaker_config_window->set (s);
341 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
342 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
344 _process_thread = new ProcessThread ();
345 _process_thread->init ();
348 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
350 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
353 _startup = new ArdourStartup ();
355 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
357 if (audio_setup && _startup->engine_control()) {
358 _startup->engine_control()->set_state (*audio_setup);
361 _startup->set_new_only (should_be_new);
362 if (!load_template.empty()) {
363 _startup->set_load_template( load_template );
365 _startup->present ();
371 switch (_startup->response()) {
380 ARDOUR_UI::create_engine ()
382 // this gets called every time by new_session()
388 loading_message (_("Starting audio engine"));
391 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
398 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
399 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
400 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
402 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
404 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
412 ARDOUR_UI::post_engine ()
414 /* Things to be done once we create the AudioEngine
417 ARDOUR::init_post_engine ();
419 ActionManager::init ();
422 if (setup_windows ()) {
423 throw failed_constructor ();
426 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
427 XMLNode* n = Config->extra_xml (X_("UI"));
429 _status_bar_visibility.set_state (*n);
432 check_memory_locking();
434 /* this is the first point at which all the keybindings are available */
436 if (ARDOUR_COMMAND_LINE::show_key_actions) {
437 vector<string> names;
438 vector<string> paths;
439 vector<string> tooltips;
441 vector<AccelKey> bindings;
443 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
445 vector<string>::iterator n;
446 vector<string>::iterator k;
447 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
448 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
454 blink_timeout_tag = -1;
456 /* this being a GUI and all, we want peakfiles */
458 AudioFileSource::set_build_peakfiles (true);
459 AudioFileSource::set_build_missing_peakfiles (true);
461 /* set default clock modes */
463 if (Profile->get_sae()) {
464 primary_clock->set_mode (AudioClock::BBT);
465 secondary_clock->set_mode (AudioClock::MinSec);
467 primary_clock->set_mode (AudioClock::Timecode);
468 secondary_clock->set_mode (AudioClock::BBT);
471 /* start the time-of-day-clock */
474 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
475 update_wall_clock ();
476 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
479 update_disk_space ();
481 update_sample_rate (engine->frame_rate());
483 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
484 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
485 Config->map_parameters (pc);
487 /* now start and maybe save state */
489 if (do_engine_start () == 0) {
490 if (_session && _session_is_new) {
491 /* we need to retain initial visual
492 settings for a new session
494 _session->save_state ("");
499 ARDOUR_UI::~ARDOUR_UI ()
504 delete add_route_dialog;
508 ARDOUR_UI::pop_back_splash ()
510 if (Splash::instance()) {
511 // Splash::instance()->pop_back();
512 Splash::instance()->hide ();
517 ARDOUR_UI::configure_timeout ()
519 if (last_configure_time == 0) {
520 /* no configure events yet */
524 /* force a gap of 0.5 seconds since the last configure event
527 if (get_microseconds() - last_configure_time < 500000) {
530 have_configure_timeout = false;
531 cerr << "config event-driven save\n";
532 save_ardour_state ();
538 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
540 if (have_configure_timeout) {
541 last_configure_time = get_microseconds();
543 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
544 have_configure_timeout = true;
551 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
553 const XMLProperty* prop;
555 if ((prop = node.property ("roll")) != 0) {
556 roll_controllable->set_id (prop->value());
558 if ((prop = node.property ("stop")) != 0) {
559 stop_controllable->set_id (prop->value());
561 if ((prop = node.property ("goto-start")) != 0) {
562 goto_start_controllable->set_id (prop->value());
564 if ((prop = node.property ("goto-end")) != 0) {
565 goto_end_controllable->set_id (prop->value());
567 if ((prop = node.property ("auto-loop")) != 0) {
568 auto_loop_controllable->set_id (prop->value());
570 if ((prop = node.property ("play-selection")) != 0) {
571 play_selection_controllable->set_id (prop->value());
573 if ((prop = node.property ("rec")) != 0) {
574 rec_controllable->set_id (prop->value());
576 if ((prop = node.property ("shuttle")) != 0) {
577 shuttle_box->controllable()->set_id (prop->value());
583 ARDOUR_UI::get_transport_controllable_state ()
585 XMLNode* node = new XMLNode(X_("TransportControllables"));
588 roll_controllable->id().print (buf, sizeof (buf));
589 node->add_property (X_("roll"), buf);
590 stop_controllable->id().print (buf, sizeof (buf));
591 node->add_property (X_("stop"), buf);
592 goto_start_controllable->id().print (buf, sizeof (buf));
593 node->add_property (X_("goto_start"), buf);
594 goto_end_controllable->id().print (buf, sizeof (buf));
595 node->add_property (X_("goto_end"), buf);
596 auto_loop_controllable->id().print (buf, sizeof (buf));
597 node->add_property (X_("auto_loop"), buf);
598 play_selection_controllable->id().print (buf, sizeof (buf));
599 node->add_property (X_("play_selection"), buf);
600 rec_controllable->id().print (buf, sizeof (buf));
601 node->add_property (X_("rec"), buf);
602 shuttle_box->controllable()->id().print (buf, sizeof (buf));
603 node->add_property (X_("shuttle"), buf);
610 ARDOUR_UI::autosave_session ()
612 if (g_main_depth() > 1) {
613 /* inside a recursive main loop,
614 give up because we may not be able to
620 if (!Config->get_periodic_safety_backups()) {
625 _session->maybe_write_autosave();
632 ARDOUR_UI::update_autosave ()
634 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
636 if (_session && _session->dirty()) {
637 if (_autosave_connection.connected()) {
638 _autosave_connection.disconnect();
641 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
642 Config->get_periodic_safety_backup_interval() * 1000);
645 if (_autosave_connection.connected()) {
646 _autosave_connection.disconnect();
652 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
656 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
658 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
661 MessageDialog win (title,
667 win.set_secondary_text(_("There are several possible reasons:\n\
669 1) You requested audio parameters that are not supported..\n\
670 2) JACK is running as another user.\n\
672 Please consider the possibilities, and perhaps try different parameters."));
674 win.set_secondary_text(_("There are several possible reasons:\n\
676 1) JACK is not running.\n\
677 2) JACK is running as another user, perhaps root.\n\
678 3) There is already another client called \"ardour\".\n\
680 Please consider the possibilities, and perhaps (re)start JACK."));
684 win.set_transient_for (*toplevel);
688 win.add_button (Stock::OK, RESPONSE_CLOSE);
690 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
693 win.set_default_response (RESPONSE_CLOSE);
696 win.set_position (Gtk::WIN_POS_CENTER);
699 /* we just don't care about the result, but we want to block */
705 ARDOUR_UI::startup ()
707 Application* app = Application::instance ();
709 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
710 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
713 call_the_mothership (VERSIONSTRING);
718 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
724 goto_editor_window ();
726 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
727 to be opened on top of the editor window that goto_editor_window() just opened.
729 add_window_proxy (location_ui);
730 add_window_proxy (big_clock_window);
731 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
732 add_window_proxy (_global_port_matrix[*i]);
735 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
736 * editor window, and we may want stuff to be hidden.
738 _status_bar_visibility.update ();
740 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
744 ARDOUR_UI::no_memory_warning ()
746 XMLNode node (X_("no-memory-warning"));
747 Config->add_instant_xml (node);
751 ARDOUR_UI::check_memory_locking ()
754 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
758 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
760 if (engine->is_realtime() && memory_warning_node == 0) {
762 struct rlimit limits;
764 long pages, page_size;
766 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
769 ram = (int64_t) pages * (int64_t) page_size;
772 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
776 if (limits.rlim_cur != RLIM_INFINITY) {
778 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
782 _("WARNING: Your system has a limit for maximum amount of locked memory. "
783 "This might cause %1 to run out of memory before your system "
784 "runs out of memory. \n\n"
785 "You can view the memory limit with 'ulimit -l', "
786 "and it is normally controlled by /etc/security/limits.conf"),
787 PROGRAM_NAME).c_str());
789 VBox* vbox = msg.get_vbox();
791 CheckButton cb (_("Do not show this window again"));
793 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
795 hbox.pack_start (cb, true, false);
796 vbox->pack_start (hbox);
803 editor->ensure_float (msg);
813 ARDOUR_UI::queue_finish ()
815 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
819 ARDOUR_UI::idle_finish ()
822 return false; /* do not call again */
831 if (_session->transport_rolling() && (++tries < 8)) {
832 _session->request_stop (false, true);
836 if (_session->dirty()) {
837 vector<string> actions;
838 actions.push_back (_("Don't quit"));
839 actions.push_back (_("Just quit"));
840 actions.push_back (_("Save and quit"));
841 switch (ask_about_saving_session(actions)) {
846 /* use the default name */
847 if (save_state_canfail ("")) {
848 /* failed - don't quit */
849 MessageDialog msg (*editor,
851 Ardour was unable to save your session.\n\n\
852 If you still wish to quit, please use the\n\n\
853 \"Just quit\" option."));
864 second_connection.disconnect ();
865 point_one_second_connection.disconnect ();
866 point_oh_five_second_connection.disconnect ();
867 point_zero_one_second_connection.disconnect();
870 /* Save state before deleting the session, as that causes some
871 windows to be destroyed before their visible state can be
874 save_ardour_state ();
877 // _session->set_deletion_in_progress ();
878 _session->set_clean ();
879 _session->remove_pending_capture_state ();
884 ArdourDialog::close_all_dialogs ();
890 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
892 ArdourDialog window (_("Unsaved Session"));
893 Gtk::HBox dhbox; // the hbox for the image and text
894 Gtk::Label prompt_label;
895 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
899 assert (actions.size() >= 3);
901 window.add_button (actions[0], RESPONSE_REJECT);
902 window.add_button (actions[1], RESPONSE_APPLY);
903 window.add_button (actions[2], RESPONSE_ACCEPT);
905 window.set_default_response (RESPONSE_ACCEPT);
907 Gtk::Button noquit_button (msg);
908 noquit_button.set_name ("EditorGTKButton");
912 if (_session->snap_name() == _session->name()) {
913 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
914 _session->snap_name());
916 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
917 _session->snap_name());
920 prompt_label.set_text (prompt);
921 prompt_label.set_name (X_("PrompterLabel"));
922 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
924 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
925 dhbox.set_homogeneous (false);
926 dhbox.pack_start (*dimage, false, false, 5);
927 dhbox.pack_start (prompt_label, true, false, 5);
928 window.get_vbox()->pack_start (dhbox);
930 window.set_name (_("Prompter"));
931 window.set_position (Gtk::WIN_POS_MOUSE);
932 window.set_modal (true);
933 window.set_resizable (false);
939 window.set_keep_above (true);
942 ResponseType r = (ResponseType) window.run();
947 case RESPONSE_ACCEPT: // save and get out of here
949 case RESPONSE_APPLY: // get out of here
959 ARDOUR_UI::every_second ()
962 update_buffer_load ();
963 update_disk_space ();
968 ARDOUR_UI::every_point_one_seconds ()
970 shuttle_box->update_speed_display ();
971 RapidScreenUpdate(); /* EMIT_SIGNAL */
976 ARDOUR_UI::every_point_zero_one_seconds ()
978 // august 2007: actual update frequency: 40Hz, not 100Hz
980 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
985 ARDOUR_UI::update_sample_rate (framecnt_t)
989 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
991 if (!engine->connected()) {
993 snprintf (buf, sizeof (buf), _("disconnected"));
997 framecnt_t rate = engine->frame_rate();
999 if (fmod (rate, 1000.0) != 0.0) {
1000 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1001 (float) rate/1000.0f,
1002 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1004 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1006 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1010 sample_rate_label.set_markup (buf);
1014 ARDOUR_UI::update_format ()
1017 format_label.set_text ("");
1022 s << "File: <span foreground=\"green\">";
1024 switch (_session->config.get_native_file_header_format ()) {
1050 switch (_session->config.get_native_file_data_format ()) {
1064 format_label.set_markup (s.str ());
1068 ARDOUR_UI::update_cpu_load ()
1072 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::build_menu_bar
1073 should also be changed.
1076 float const c = engine->get_cpu_load ();
1077 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1078 cpu_load_label.set_markup (buf);
1082 ARDOUR_UI::update_buffer_load ()
1086 uint32_t const playback = _session ? _session->playback_load () : 100;
1087 uint32_t const capture = _session ? _session->capture_load () : 100;
1089 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::build_menu_bar
1090 should also be changed.
1096 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1097 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1098 playback <= 5 ? X_("red") : X_("green"),
1100 capture <= 5 ? X_("red") : X_("green"),
1104 buffer_load_label.set_markup (buf);
1106 buffer_load_label.set_text ("");
1111 ARDOUR_UI::count_recenabled_streams (Route& route)
1113 Track* track = dynamic_cast<Track*>(&route);
1114 if (track && track->record_enabled()) {
1115 rec_enabled_streams += track->n_inputs().n_total();
1120 ARDOUR_UI::update_disk_space()
1122 if (_session == 0) {
1126 framecnt_t frames = _session->available_capture_duration();
1128 framecnt_t fr = _session->frame_rate();
1130 if (frames == max_framecnt) {
1131 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">24hrs+</span>"));
1133 rec_enabled_streams = 0;
1134 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1136 if (rec_enabled_streams) {
1137 frames /= rec_enabled_streams;
1144 hrs = frames / (fr * 3600);
1147 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1149 frames -= hrs * fr * 3600;
1150 mins = frames / (fr * 60);
1151 frames -= mins * fr * 60;
1154 bool const low = (hrs == 0 && mins <= 30);
1158 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1159 low ? X_("red") : X_("green"),
1165 disk_space_label.set_markup (buf);
1167 // An attempt to make the disk space label flash red when space has run out.
1169 if (frames < fr * 60 * 5) {
1170 /* disk_space_box.style ("disk_space_label_empty"); */
1172 /* disk_space_box.style ("disk_space_label"); */
1178 ARDOUR_UI::update_wall_clock ()
1185 tm_now = localtime (&now);
1187 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1188 wall_clock_label.set_text (buf);
1194 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1196 session_popup_menu->popup (0, 0);
1201 ARDOUR_UI::redisplay_recent_sessions ()
1203 std::vector<sys::path> session_directories;
1204 RecentSessionsSorter cmp;
1206 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1207 recent_session_model->clear ();
1209 ARDOUR::RecentSessions rs;
1210 ARDOUR::read_recent_sessions (rs);
1213 recent_session_display.set_model (recent_session_model);
1217 // sort them alphabetically
1218 sort (rs.begin(), rs.end(), cmp);
1220 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1221 session_directories.push_back ((*i).second);
1224 for (vector<sys::path>::const_iterator i = session_directories.begin();
1225 i != session_directories.end(); ++i)
1227 std::vector<sys::path> state_file_paths;
1229 // now get available states for this session
1231 get_state_files_in_directory (*i, state_file_paths);
1233 vector<string*>* states;
1234 vector<const gchar*> item;
1235 string fullpath = (*i).to_string();
1237 /* remove any trailing / */
1239 if (fullpath[fullpath.length()-1] == '/') {
1240 fullpath = fullpath.substr (0, fullpath.length()-1);
1243 /* check whether session still exists */
1244 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1245 /* session doesn't exist */
1246 cerr << "skipping non-existent session " << fullpath << endl;
1250 /* now get available states for this session */
1252 if ((states = Session::possible_states (fullpath)) == 0) {
1253 /* no state file? */
1257 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1259 Gtk::TreeModel::Row row = *(recent_session_model->append());
1261 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1262 row[recent_session_columns.fullpath] = fullpath;
1264 if (state_file_names.size() > 1) {
1268 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1269 i2 != state_file_names.end(); ++i2)
1272 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1274 child_row[recent_session_columns.visible_name] = *i2;
1275 child_row[recent_session_columns.fullpath] = fullpath;
1280 recent_session_display.set_model (recent_session_model);
1284 ARDOUR_UI::build_session_selector ()
1286 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1288 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1290 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1291 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1292 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1293 recent_session_model = TreeStore::create (recent_session_columns);
1294 recent_session_display.set_model (recent_session_model);
1295 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1296 recent_session_display.set_headers_visible (false);
1297 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1298 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1300 scroller->add (recent_session_display);
1301 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1303 session_selector_window->set_name ("SessionSelectorWindow");
1304 session_selector_window->set_size_request (200, 400);
1305 session_selector_window->get_vbox()->pack_start (*scroller);
1307 recent_session_display.show();
1309 //session_selector_window->get_vbox()->show();
1313 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1315 session_selector_window->response (RESPONSE_ACCEPT);
1319 ARDOUR_UI::open_recent_session ()
1321 bool can_return = (_session != 0);
1323 if (session_selector_window == 0) {
1324 build_session_selector ();
1327 redisplay_recent_sessions ();
1331 session_selector_window->set_position (WIN_POS_MOUSE);
1333 ResponseType r = (ResponseType) session_selector_window->run ();
1336 case RESPONSE_ACCEPT:
1340 session_selector_window->hide();
1347 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1351 session_selector_window->hide();
1353 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1355 if (i == recent_session_model->children().end()) {
1359 std::string path = (*i)[recent_session_columns.fullpath];
1360 std::string state = (*i)[recent_session_columns.visible_name];
1362 _session_is_new = false;
1364 if (load_session (path, state) == 0) {
1373 ARDOUR_UI::check_audioengine ()
1376 if (!engine->connected()) {
1377 MessageDialog msg (string_compose (
1378 _("%1 is not connected to JACK\n"
1379 "You cannot open or close sessions in this condition"),
1392 ARDOUR_UI::open_session ()
1394 if (!check_audioengine()) {
1399 /* popup selector window */
1401 if (open_session_selector == 0) {
1403 /* ardour sessions are folders */
1405 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1406 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1407 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1408 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1410 FileFilter session_filter;
1411 session_filter.add_pattern ("*.ardour");
1412 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1413 open_session_selector->add_filter (session_filter);
1414 open_session_selector->set_filter (session_filter);
1417 int response = open_session_selector->run();
1418 open_session_selector->hide ();
1421 case RESPONSE_ACCEPT:
1424 open_session_selector->hide();
1428 open_session_selector->hide();
1429 string session_path = open_session_selector->get_filename();
1433 if (session_path.length() > 0) {
1434 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1435 _session_is_new = isnew;
1436 load_session (path, name);
1443 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1445 list<boost::shared_ptr<MidiTrack> > tracks;
1447 if (_session == 0) {
1448 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1455 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1457 if (tracks.size() != how_many) {
1458 if (how_many == 1) {
1459 error << _("could not create a new midi track") << endmsg;
1461 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1465 if ((route = _session->new_midi_route ()) == 0) {
1466 error << _("could not create new midi bus") << endmsg;
1472 MessageDialog msg (*editor,
1473 string_compose (_("There are insufficient JACK ports available\n\
1474 to create a new track or bus.\n\
1475 You should save %1, exit and\n\
1476 restart JACK with more ports."), PROGRAM_NAME));
1483 ARDOUR_UI::session_add_audio_route (
1485 int32_t input_channels,
1486 int32_t output_channels,
1487 ARDOUR::TrackMode mode,
1488 RouteGroup* route_group,
1490 string const & name_template
1493 list<boost::shared_ptr<AudioTrack> > tracks;
1496 if (_session == 0) {
1497 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1503 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1505 if (tracks.size() != how_many) {
1506 if (how_many == 1) {
1507 error << _("could not create a new audio track") << endmsg;
1509 error << string_compose (_("could only create %1 of %2 new audio %3"),
1510 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1516 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1518 if (routes.size() != how_many) {
1519 if (how_many == 1) {
1520 error << _("could not create a new audio bus") << endmsg;
1522 error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg;
1529 MessageDialog msg (*editor,
1530 string_compose (_("There are insufficient JACK ports available\n\
1531 to create a new track or bus.\n\
1532 You should save %1, exit and\n\
1533 restart JACK with more ports."), PROGRAM_NAME));
1540 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1542 framecnt_t _preroll = 0;
1545 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1546 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1548 if (new_position > _preroll) {
1549 new_position -= _preroll;
1554 _session->request_locate (new_position, with_roll);
1559 ARDOUR_UI::transport_goto_start ()
1562 _session->goto_start();
1564 /* force displayed area in editor to start no matter
1565 what "follow playhead" setting is.
1569 editor->center_screen (_session->current_start_frame ());
1575 ARDOUR_UI::transport_goto_zero ()
1578 _session->request_locate (0);
1580 /* force displayed area in editor to start no matter
1581 what "follow playhead" setting is.
1585 editor->reset_x_origin (0);
1591 ARDOUR_UI::transport_goto_wallclock ()
1593 if (_session && editor) {
1600 localtime_r (&now, &tmnow);
1602 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1603 frames += tmnow.tm_min * (60 * _session->frame_rate());
1604 frames += tmnow.tm_sec * _session->frame_rate();
1606 _session->request_locate (frames, _session->transport_rolling ());
1608 /* force displayed area in editor to start no matter
1609 what "follow playhead" setting is.
1613 editor->center_screen (frames);
1619 ARDOUR_UI::transport_goto_end ()
1622 framepos_t const frame = _session->current_end_frame();
1623 _session->request_locate (frame);
1625 /* force displayed area in editor to start no matter
1626 what "follow playhead" setting is.
1630 editor->center_screen (frame);
1636 ARDOUR_UI::transport_stop ()
1642 if (_session->is_auditioning()) {
1643 _session->cancel_audition ();
1647 _session->request_stop (false, true);
1651 ARDOUR_UI::transport_stop_and_forget_capture ()
1654 _session->request_stop (true, true);
1659 ARDOUR_UI::remove_last_capture()
1662 editor->remove_last_capture();
1667 ARDOUR_UI::transport_record (bool roll)
1671 switch (_session->record_status()) {
1672 case Session::Disabled:
1673 if (_session->ntracks() == 0) {
1674 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1678 _session->maybe_enable_record ();
1683 case Session::Recording:
1685 _session->request_stop();
1687 _session->disable_record (false, true);
1691 case Session::Enabled:
1692 _session->disable_record (false, true);
1695 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1699 ARDOUR_UI::transport_roll ()
1705 if (_session->is_auditioning()) {
1710 if (_session->config.get_external_sync()) {
1711 switch (_session->config.get_sync_source()) {
1715 /* transport controlled by the master */
1721 bool rolling = _session->transport_rolling();
1723 if (_session->get_play_loop()) {
1724 /* XXX it is not possible to just leave seamless loop and keep
1725 playing at present (nov 4th 2009)
1727 if (!Config->get_seamless_loop()) {
1728 _session->request_play_loop (false, true);
1730 } else if (_session->get_play_range () && !join_play_range_button.active_state()) {
1731 /* stop playing a range if we currently are */
1732 _session->request_play_range (0, true);
1735 if (join_play_range_button.active_state()) {
1736 _session->request_play_range (&editor->get_selection().time, true);
1740 _session->request_transport_speed (1.0f);
1745 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1752 if (_session->is_auditioning()) {
1753 _session->cancel_audition ();
1757 if (_session->config.get_external_sync()) {
1758 switch (_session->config.get_sync_source()) {
1762 /* transport controlled by the master */
1767 bool rolling = _session->transport_rolling();
1768 bool affect_transport = true;
1770 if (rolling && roll_out_of_bounded_mode) {
1771 /* drop out of loop/range playback but leave transport rolling */
1772 if (_session->get_play_loop()) {
1773 if (Config->get_seamless_loop()) {
1774 /* the disk buffers contain copies of the loop - we can't
1775 just keep playing, so stop the transport. the user
1776 can restart as they wish.
1778 affect_transport = true;
1780 /* disk buffers are normal, so we can keep playing */
1781 affect_transport = false;
1783 _session->request_play_loop (false, true);
1784 } else if (_session->get_play_range ()) {
1785 affect_transport = false;
1786 _session->request_play_range (0, true);
1790 if (affect_transport) {
1792 _session->request_stop (with_abort, true);
1794 if (join_play_range_button.active_state()) {
1795 _session->request_play_range (&editor->get_selection().time, true);
1798 _session->request_transport_speed (1.0f);
1804 ARDOUR_UI::toggle_session_auto_loop ()
1810 if (_session->get_play_loop()) {
1812 if (_session->transport_rolling()) {
1814 Location * looploc = _session->locations()->auto_loop_location();
1817 _session->request_locate (looploc->start(), true);
1818 _session->request_play_loop (false);
1822 _session->request_play_loop (false);
1826 Location * looploc = _session->locations()->auto_loop_location();
1829 _session->request_play_loop (true);
1835 ARDOUR_UI::transport_play_selection ()
1841 editor->play_selection ();
1845 ARDOUR_UI::transport_rewind (int option)
1847 float current_transport_speed;
1850 current_transport_speed = _session->transport_speed();
1852 if (current_transport_speed >= 0.0f) {
1855 _session->request_transport_speed (-1.0f);
1858 _session->request_transport_speed (-4.0f);
1861 _session->request_transport_speed (-0.5f);
1866 _session->request_transport_speed (current_transport_speed * 1.5f);
1872 ARDOUR_UI::transport_forward (int option)
1874 float current_transport_speed;
1877 current_transport_speed = _session->transport_speed();
1879 if (current_transport_speed <= 0.0f) {
1882 _session->request_transport_speed (1.0f);
1885 _session->request_transport_speed (4.0f);
1888 _session->request_transport_speed (0.5f);
1893 _session->request_transport_speed (current_transport_speed * 1.5f);
1900 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1902 if (_session == 0) {
1906 boost::shared_ptr<Route> r;
1908 if ((r = _session->route_by_remote_id (rid)) != 0) {
1912 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1913 t->set_record_enabled (!t->record_enabled(), this);
1916 if (_session == 0) {
1922 ARDOUR_UI::map_transport_state ()
1925 auto_loop_button.unset_active_state ();
1926 play_selection_button.unset_active_state ();
1927 roll_button.unset_active_state ();
1928 stop_button.set_active_state (Gtkmm2ext::Active);
1932 shuttle_box->map_transport_state ();
1934 float sp = _session->transport_speed();
1940 if (_session->get_play_range()) {
1942 play_selection_button.set_active_state (Gtkmm2ext::Active);
1943 roll_button.unset_active_state ();
1944 auto_loop_button.unset_active_state ();
1946 } else if (_session->get_play_loop ()) {
1948 auto_loop_button.set_active_state (Gtkmm2ext::Active);
1949 play_selection_button.unset_active_state ();
1950 roll_button.unset_active_state ();
1954 roll_button.set_active_state (Gtkmm2ext::Active);
1955 play_selection_button.unset_active_state ();
1956 auto_loop_button.unset_active_state ();
1959 if (join_play_range_button.active_state()) {
1960 /* light up both roll and play-selection if they are joined */
1961 roll_button.set_active_state (Gtkmm2ext::Active);
1962 play_selection_button.set_active_state (Gtkmm2ext::Active);
1965 stop_button.unset_active_state ();
1969 stop_button.set_active_state (Gtkmm2ext::Active);
1970 roll_button.unset_active_state ();
1971 play_selection_button.unset_active_state ();
1972 auto_loop_button.unset_active_state ();
1973 update_disk_space ();
1978 ARDOUR_UI::engine_stopped ()
1980 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1981 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1982 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1986 ARDOUR_UI::engine_running ()
1988 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1989 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1990 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1992 Glib::RefPtr<Action> action;
1993 const char* action_name = 0;
1995 switch (engine->frames_per_cycle()) {
1997 action_name = X_("JACKLatency32");
2000 action_name = X_("JACKLatency64");
2003 action_name = X_("JACKLatency128");
2006 action_name = X_("JACKLatency512");
2009 action_name = X_("JACKLatency1024");
2012 action_name = X_("JACKLatency2048");
2015 action_name = X_("JACKLatency4096");
2018 action_name = X_("JACKLatency8192");
2021 /* XXX can we do anything useful ? */
2027 action = ActionManager::get_action (X_("JACK"), action_name);
2030 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
2031 ract->set_active ();
2037 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
2039 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
2040 /* we can't rely on the original string continuing to exist when we are called
2041 again in the GUI thread, so make a copy and note that we need to
2044 char *copy = strdup (reason);
2045 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
2049 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
2050 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
2052 update_sample_rate (0);
2056 /* if the reason is a non-empty string, it means that the backend was shutdown
2057 rather than just Ardour.
2060 if (strlen (reason)) {
2061 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
2063 msgstr = string_compose (_("\
2064 JACK has either been shutdown or it\n\
2065 disconnected %1 because %1\n\
2066 was not fast enough. Try to restart\n\
2067 JACK, reconnect and save the session."), PROGRAM_NAME);
2070 MessageDialog msg (*editor, msgstr);
2075 free ((char*) reason);
2080 ARDOUR_UI::do_engine_start ()
2088 error << _("Unable to start the session running")
2098 ARDOUR_UI::setup_theme ()
2100 theme_manager->setup_theme();
2104 ARDOUR_UI::update_clocks ()
2106 if (!editor || !editor->dragging_playhead()) {
2107 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2112 ARDOUR_UI::start_clocking ()
2114 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2118 ARDOUR_UI::stop_clocking ()
2120 clock_signal_connection.disconnect ();
2124 ARDOUR_UI::toggle_clocking ()
2127 if (clock_button.get_active()) {
2136 ARDOUR_UI::_blink (void *arg)
2139 ((ARDOUR_UI *) arg)->blink ();
2146 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2150 ARDOUR_UI::start_blinking ()
2152 /* Start the blink signal. Everybody with a blinking widget
2153 uses Blink to drive the widget's state.
2156 if (blink_timeout_tag < 0) {
2158 blink_timeout_tag = g_timeout_add (240, _blink, this);
2163 ARDOUR_UI::stop_blinking ()
2165 if (blink_timeout_tag >= 0) {
2166 g_source_remove (blink_timeout_tag);
2167 blink_timeout_tag = -1;
2172 /** Ask the user for the name of a new shapshot and then take it.
2176 ARDOUR_UI::snapshot_session (bool switch_to_it)
2178 ArdourPrompter prompter (true);
2181 prompter.set_name ("Prompter");
2182 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2183 prompter.set_title (_("Take Snapshot"));
2184 prompter.set_prompt (_("Name of new snapshot"));
2186 if (!switch_to_it) {
2189 struct tm local_time;
2192 localtime_r (&n, &local_time);
2193 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2194 prompter.set_initial_text (timebuf);
2198 switch (prompter.run()) {
2199 case RESPONSE_ACCEPT:
2201 prompter.get_result (snapname);
2203 bool do_save = (snapname.length() != 0);
2206 if (snapname.find ('/') != string::npos) {
2207 MessageDialog msg (_("To ensure compatibility with various systems\n"
2208 "snapshot names may not contain a '/' character"));
2212 if (snapname.find ('\\') != string::npos) {
2213 MessageDialog msg (_("To ensure compatibility with various systems\n"
2214 "snapshot names may not contain a '\\' character"));
2218 if (snapname.find (':') != string::npos) {
2219 MessageDialog msg (_("To ensure compatibility with various systems\n"
2220 "snapshot names may not contain a ':' character"));
2226 vector<sys::path> p;
2227 get_state_files_in_directory (_session->session_directory().root_path(), p);
2228 vector<string> n = get_file_names_no_extension (p);
2229 if (find (n.begin(), n.end(), snapname) != n.end()) {
2231 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2232 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2233 confirm.get_vbox()->pack_start (m, true, true);
2234 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2235 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2236 confirm.show_all ();
2237 switch (confirm.run()) {
2238 case RESPONSE_CANCEL:
2244 save_state (snapname, switch_to_it);
2254 /** Ask the user for the name of a new shapshot and then take it.
2258 ARDOUR_UI::rename_session ()
2264 ArdourPrompter prompter (true);
2267 prompter.set_name ("Prompter");
2268 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2269 prompter.set_title (_("Rename Session"));
2270 prompter.set_prompt (_("New session name"));
2273 switch (prompter.run()) {
2274 case RESPONSE_ACCEPT:
2276 prompter.get_result (name);
2278 bool do_rename = (name.length() != 0);
2281 if (name.find ('/') != string::npos) {
2282 MessageDialog msg (_("To ensure compatibility with various systems\n"
2283 "session names may not contain a '/' character"));
2287 if (name.find ('\\') != string::npos) {
2288 MessageDialog msg (_("To ensure compatibility with various systems\n"
2289 "session names may not contain a '\\' character"));
2294 switch (_session->rename (name)) {
2296 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2297 msg.set_position (WIN_POS_MOUSE);
2305 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2306 msg.set_position (WIN_POS_MOUSE);
2322 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2324 XMLNode* node = new XMLNode (X_("UI"));
2326 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2327 if (!(*i)->rc_configured()) {
2328 node->add_child_nocopy (*((*i)->get_state ()));
2332 node->add_child_nocopy (gui_object_state->get_state());
2334 _session->add_extra_xml (*node);
2336 save_state_canfail (name, switch_to_it);
2340 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2345 if (name.length() == 0) {
2346 name = _session->snap_name();
2349 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2354 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2359 ARDOUR_UI::primary_clock_value_changed ()
2362 _session->request_locate (primary_clock->current_time ());
2367 ARDOUR_UI::big_clock_value_changed ()
2370 _session->request_locate (big_clock->current_time ());
2375 ARDOUR_UI::secondary_clock_value_changed ()
2378 _session->request_locate (secondary_clock->current_time ());
2383 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2385 if (_session == 0) {
2389 if (_session->step_editing()) {
2393 Session::RecordState const r = _session->record_status ();
2394 bool const h = _session->have_rec_enabled_track ();
2396 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2398 rec_button.set_active_state (Active);
2400 rec_button.set_active_state (Mid);
2402 } else if (r == Session::Recording && h) {
2403 rec_button.set_active_state (Mid);
2405 rec_button.unset_active_state ();
2410 ARDOUR_UI::save_template ()
2412 ArdourPrompter prompter (true);
2415 if (!check_audioengine()) {
2419 prompter.set_name (X_("Prompter"));
2420 prompter.set_title (_("Save Template"));
2421 prompter.set_prompt (_("Name for template:"));
2422 prompter.set_initial_text(_session->name() + _("-template"));
2423 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2425 switch (prompter.run()) {
2426 case RESPONSE_ACCEPT:
2427 prompter.get_result (name);
2429 if (name.length()) {
2430 _session->save_template (name);
2440 ARDOUR_UI::edit_metadata ()
2442 SessionMetadataEditor dialog;
2443 dialog.set_session (_session);
2444 editor->ensure_float (dialog);
2449 ARDOUR_UI::import_metadata ()
2451 SessionMetadataImporter dialog;
2452 dialog.set_session (_session);
2453 editor->ensure_float (dialog);
2458 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2460 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2462 MessageDialog msg (str,
2464 Gtk::MESSAGE_WARNING,
2465 Gtk::BUTTONS_YES_NO,
2469 msg.set_name (X_("OpenExistingDialog"));
2470 msg.set_title (_("Open Existing Session"));
2471 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2472 msg.set_position (Gtk::WIN_POS_MOUSE);
2475 switch (msg.run()) {
2484 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2486 BusProfile bus_profile;
2488 if (Profile->get_sae()) {
2490 bus_profile.master_out_channels = 2;
2491 bus_profile.input_ac = AutoConnectPhysical;
2492 bus_profile.output_ac = AutoConnectMaster;
2493 bus_profile.requested_physical_in = 0; // use all available
2494 bus_profile.requested_physical_out = 0; // use all available
2498 /* get settings from advanced section of NSD */
2500 if (_startup->create_master_bus()) {
2501 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2503 bus_profile.master_out_channels = 0;
2506 if (_startup->connect_inputs()) {
2507 bus_profile.input_ac = AutoConnectPhysical;
2509 bus_profile.input_ac = AutoConnectOption (0);
2512 /// @todo some minor tweaks.
2514 bus_profile.output_ac = AutoConnectOption (0);
2516 if (_startup->connect_outputs ()) {
2517 if (_startup->connect_outs_to_master()) {
2518 bus_profile.output_ac = AutoConnectMaster;
2519 } else if (_startup->connect_outs_to_physical()) {
2520 bus_profile.output_ac = AutoConnectPhysical;
2524 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2525 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2528 if (build_session (session_path, session_name, bus_profile)) {
2536 ARDOUR_UI::idle_load (const std::string& path)
2539 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2540 /* /path/to/foo => /path/to/foo, foo */
2541 load_session (path, basename_nosuffix (path));
2543 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2544 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2548 ARDOUR_COMMAND_LINE::session_name = path;
2551 * new_session_dialog doens't exist in A3
2552 * Try to remove all references to it to
2553 * see if it will compile. NOTE: this will
2554 * likely cause a runtime issue is my somewhat
2558 //if (new_session_dialog) {
2561 /* make it break out of Dialog::run() and
2565 //new_session_dialog->response (1);
2571 ARDOUR_UI::end_loading_messages ()
2577 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2580 // splash->message (msg);
2584 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2586 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2588 string session_name;
2589 string session_path;
2590 string template_name;
2592 bool likely_new = false;
2594 if (!load_template.empty()) {
2595 should_be_new = true;
2596 template_name = load_template;
2601 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2603 /* if they named a specific statefile, use it, otherwise they are
2604 just giving a session folder, and we want to use it as is
2605 to find the session.
2608 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2610 if (suffix != string::npos) {
2611 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2612 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2613 session_name = Glib::path_get_basename (session_name);
2615 session_path = ARDOUR_COMMAND_LINE::session_name;
2616 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2621 bool const apply = run_startup (should_be_new, load_template);
2624 if (quit_on_cancel) {
2631 /* if we run the startup dialog again, offer more than just "new session" */
2633 should_be_new = false;
2635 session_name = _startup->session_name (likely_new);
2637 string::size_type suffix = session_name.find (statefile_suffix);
2639 if (suffix != string::npos) {
2640 session_name = session_name.substr (0, suffix);
2643 /* this shouldn't happen, but we catch it just in case it does */
2645 if (session_name.empty()) {
2649 if (_startup->use_session_template()) {
2650 template_name = _startup->session_template_name();
2651 _session_is_new = true;
2654 if (session_name[0] == G_DIR_SEPARATOR ||
2655 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2656 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2658 /* absolute path or cwd-relative path specified for session name: infer session folder
2659 from what was given.
2662 session_path = Glib::path_get_dirname (session_name);
2663 session_name = Glib::path_get_basename (session_name);
2667 session_path = _startup->session_folder();
2669 if (session_name.find ('/') != string::npos) {
2670 MessageDialog msg (*_startup,
2671 _("To ensure compatibility with various systems\n"
2672 "session names may not contain a '/' character"));
2674 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2678 if (session_name.find ('\\') != string::npos) {
2679 MessageDialog msg (*_startup,
2680 _("To ensure compatibility with various systems\n"
2681 "session names may not contain a '\\' character"));
2683 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2689 if (create_engine ()) {
2693 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2697 std::string existing = Glib::build_filename (session_path, session_name);
2699 if (!ask_about_loading_existing_session (existing)) {
2700 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2705 _session_is_new = false;
2710 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2712 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2716 if (session_name.find ('/') != std::string::npos) {
2717 MessageDialog msg (*_startup,
2718 _("To ensure compatibility with various systems\n"
2719 "session names may not contain a '/' character"));
2721 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2725 if (session_name.find ('\\') != std::string::npos) {
2726 MessageDialog msg (*_startup,
2727 _("To ensure compatibility with various systems\n"
2728 "session names may not contain a '\\' character"));
2730 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2734 _session_is_new = true;
2737 if (likely_new && template_name.empty()) {
2739 ret = build_session_from_nsd (session_path, session_name);
2743 ret = load_session (session_path, session_name, template_name);
2746 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2750 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2751 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2761 ARDOUR_UI::close_session()
2763 if (!check_audioengine()) {
2767 if (unload_session (true)) {
2771 ARDOUR_COMMAND_LINE::session_name = "";
2773 if (get_session_parameters (true, false)) {
2777 goto_editor_window ();
2780 /** @param snap_name Snapshot name (without .ardour suffix).
2781 * @return -2 if the load failed because we are not connected to the AudioEngine.
2784 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2786 Session *new_session;
2790 session_loaded = false;
2792 if (!check_audioengine()) {
2796 unload_status = unload_session ();
2798 if (unload_status < 0) {
2800 } else if (unload_status > 0) {
2805 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2808 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2811 /* this one is special */
2813 catch (AudioEngine::PortRegistrationFailure& err) {
2815 MessageDialog msg (err.what(),
2818 Gtk::BUTTONS_CLOSE);
2820 msg.set_title (_("Port Registration Error"));
2821 msg.set_secondary_text (_("Click the Close button to try again."));
2822 msg.set_position (Gtk::WIN_POS_CENTER);
2826 int response = msg.run ();
2831 case RESPONSE_CANCEL:
2841 MessageDialog msg (string_compose(
2842 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2848 msg.set_title (_("Loading Error"));
2849 msg.set_secondary_text (_("Click the Refresh button to try again."));
2850 msg.add_button (Stock::REFRESH, 1);
2851 msg.set_position (Gtk::WIN_POS_CENTER);
2855 int response = msg.run ();
2870 list<string> const u = new_session->unknown_processors ();
2872 MissingPluginDialog d (_session, u);
2877 /* Now the session been created, add the transport controls */
2878 new_session->add_controllable(roll_controllable);
2879 new_session->add_controllable(stop_controllable);
2880 new_session->add_controllable(goto_start_controllable);
2881 new_session->add_controllable(goto_end_controllable);
2882 new_session->add_controllable(auto_loop_controllable);
2883 new_session->add_controllable(play_selection_controllable);
2884 new_session->add_controllable(rec_controllable);
2886 set_session (new_session);
2888 session_loaded = true;
2890 goto_editor_window ();
2893 _session->set_clean ();
2904 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2906 Session *new_session;
2909 if (!check_audioengine()) {
2913 session_loaded = false;
2915 x = unload_session ();
2923 _session_is_new = true;
2926 new_session = new Session (*engine, path, snap_name, &bus_profile);
2931 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2937 /* Give the new session the default GUI state, if such things exist */
2940 n = Config->instant_xml (X_("Editor"));
2942 new_session->add_instant_xml (*n, false);
2944 n = Config->instant_xml (X_("Mixer"));
2946 new_session->add_instant_xml (*n, false);
2949 /* Put the playhead at 0 and scroll fully left */
2950 n = new_session->instant_xml (X_("Editor"));
2952 n->add_property (X_("playhead"), X_("0"));
2953 n->add_property (X_("left-frame"), X_("0"));
2956 set_session (new_session);
2958 session_loaded = true;
2960 new_session->save_state(new_session->name());
2966 ARDOUR_UI::launch_chat ()
2969 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2971 open_uri("http://webchat.freenode.net/?channels=ardour");
2976 ARDOUR_UI::show_about ()
2980 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2983 about->set_transient_for(*editor);
2988 ARDOUR_UI::launch_manual ()
2990 PBD::open_uri("http://ardour.org/flossmanual");
2994 ARDOUR_UI::launch_reference ()
2996 PBD::open_uri("http://ardour.org/refmanual");
3000 ARDOUR_UI::hide_about ()
3003 about->get_window()->set_cursor ();
3009 ARDOUR_UI::about_signal_response (int /*response*/)
3015 ARDOUR_UI::show_splash ()
3019 splash = new Splash;
3027 splash->queue_draw ();
3028 splash->get_window()->process_updates (true);
3033 ARDOUR_UI::hide_splash ()
3041 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
3042 const string& plural_msg, const string& singular_msg)
3046 removed = rep.paths.size();
3049 MessageDialog msgd (*editor,
3050 _("No files were ready for clean-up"),
3053 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
3054 msgd.set_title (_("Clean-up"));
3055 msgd.set_secondary_text (_("If this seems suprising, \n\
3056 check for any existing snapshots.\n\
3057 These may still include regions that\n\
3058 require some unused files to continue to exist."));
3064 ArdourDialog results (_("Clean-up"), true, false);
3066 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3067 CleanupResultsModelColumns() {
3071 Gtk::TreeModelColumn<std::string> visible_name;
3072 Gtk::TreeModelColumn<std::string> fullpath;
3076 CleanupResultsModelColumns results_columns;
3077 Glib::RefPtr<Gtk::ListStore> results_model;
3078 Gtk::TreeView results_display;
3080 results_model = ListStore::create (results_columns);
3081 results_display.set_model (results_model);
3082 results_display.append_column (list_title, results_columns.visible_name);
3084 results_display.set_name ("CleanupResultsList");
3085 results_display.set_headers_visible (true);
3086 results_display.set_headers_clickable (false);
3087 results_display.set_reorderable (false);
3089 Gtk::ScrolledWindow list_scroller;
3092 Gtk::HBox dhbox; // the hbox for the image and text
3093 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3094 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3096 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3098 const string dead_directory = _session->session_directory().dead_path().to_string();
3101 %1 - number of files removed
3102 %2 - location of "dead"
3103 %3 - size of files affected
3104 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3107 const char* bprefix;
3108 double space_adjusted = 0;
3110 if (rep.space < 1000) {
3112 space_adjusted = rep.space;
3113 } else if (rep.space < 1000000) {
3114 bprefix = X_("kilo");
3115 space_adjusted = truncf((float)rep.space / 1000.0);
3116 } else if (rep.space < 1000000 * 1000) {
3117 bprefix = X_("mega");
3118 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3120 bprefix = X_("giga");
3121 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3125 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3127 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3130 dhbox.pack_start (*dimage, true, false, 5);
3131 dhbox.pack_start (txt, true, false, 5);
3133 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3134 TreeModel::Row row = *(results_model->append());
3135 row[results_columns.visible_name] = *i;
3136 row[results_columns.fullpath] = *i;
3139 list_scroller.add (results_display);
3140 list_scroller.set_size_request (-1, 150);
3141 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3143 dvbox.pack_start (dhbox, true, false, 5);
3144 dvbox.pack_start (list_scroller, true, false, 5);
3145 ddhbox.pack_start (dvbox, true, false, 5);
3147 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3148 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3149 results.set_default_response (RESPONSE_CLOSE);
3150 results.set_position (Gtk::WIN_POS_MOUSE);
3152 results_display.show();
3153 list_scroller.show();
3160 //results.get_vbox()->show();
3161 results.set_resizable (false);
3168 ARDOUR_UI::cleanup ()
3170 if (_session == 0) {
3171 /* shouldn't happen: menu item is insensitive */
3176 MessageDialog checker (_("Are you sure you want to clean-up?"),
3178 Gtk::MESSAGE_QUESTION,
3179 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3181 checker.set_title (_("Clean-up"));
3183 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3184 ALL undo/redo information will be lost if you clean-up.\n\
3185 Clean-up will move all unused files to a \"dead\" location."));
3187 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3188 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3189 checker.set_default_response (RESPONSE_CANCEL);
3191 checker.set_name (_("CleanupDialog"));
3192 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3193 checker.set_position (Gtk::WIN_POS_MOUSE);
3195 switch (checker.run()) {
3196 case RESPONSE_ACCEPT:
3202 ARDOUR::CleanupReport rep;
3204 editor->prepare_for_cleanup ();
3206 /* do not allow flush until a session is reloaded */
3208 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3210 act->set_sensitive (false);
3213 if (_session->cleanup_sources (rep)) {
3214 editor->finish_cleanup ();
3218 editor->finish_cleanup ();
3221 display_cleanup_results (rep,
3224 The following %1 files were not in use and \n\
3225 have been moved to:\n\n\
3227 After a restart of Ardour,\n\n\
3228 Session -> Clean-up -> Flush Wastebasket\n\n\
3229 will release an additional\n\
3230 %3 %4bytes of disk space.\n"),
3232 The following file was not in use and \n\
3233 has been moved to:\n \
3235 After a restart of Ardour,\n\n\
3236 Session -> Clean-up -> Flush Wastebasket\n\n\
3237 will release an additional\n\
3238 %3 %4bytes of disk space.\n"
3244 ARDOUR_UI::flush_trash ()
3246 if (_session == 0) {
3247 /* shouldn't happen: menu item is insensitive */
3251 ARDOUR::CleanupReport rep;
3253 if (_session->cleanup_trash_sources (rep)) {
3257 display_cleanup_results (rep,
3259 _("The following %1 files were deleted from\n\
3261 releasing %3 %4bytes of disk space"),
3262 _("The following file was deleted from\n\
3264 releasing %3 %4bytes of disk space"));
3268 ARDOUR_UI::add_route (Gtk::Window* float_window)
3276 if (add_route_dialog == 0) {
3277 add_route_dialog = new AddRouteDialog (_session);
3279 add_route_dialog->set_transient_for (*float_window);
3283 if (add_route_dialog->is_visible()) {
3284 /* we're already doing this */
3288 ResponseType r = (ResponseType) add_route_dialog->run ();
3290 add_route_dialog->hide();
3293 case RESPONSE_ACCEPT:
3300 if ((count = add_route_dialog->count()) <= 0) {
3304 string template_path = add_route_dialog->track_template();
3306 if (!template_path.empty()) {
3307 _session->new_route_from_template (count, template_path);
3311 uint32_t input_chan = add_route_dialog->channels ();
3312 uint32_t output_chan;
3313 string name_template = add_route_dialog->name_template ();
3314 bool track = add_route_dialog->track ();
3315 RouteGroup* route_group = add_route_dialog->route_group ();
3317 AutoConnectOption oac = Config->get_output_auto_connect();
3319 if (oac & AutoConnectMaster) {
3320 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3322 output_chan = input_chan;
3325 /* XXX do something with name template */
3327 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3329 session_add_midi_track (route_group, count, name_template);
3331 MessageDialog msg (*editor,
3332 _("Sorry, MIDI Busses are not supported at this time."));
3334 //session_add_midi_bus();
3338 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3340 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3346 ARDOUR_UI::mixer_settings () const
3351 node = _session->instant_xml(X_("Mixer"));
3353 node = Config->instant_xml(X_("Mixer"));
3357 node = new XMLNode (X_("Mixer"));
3364 ARDOUR_UI::editor_settings () const
3369 node = _session->instant_xml(X_("Editor"));
3371 node = Config->instant_xml(X_("Editor"));
3375 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3376 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3381 node = new XMLNode (X_("Editor"));
3388 ARDOUR_UI::keyboard_settings () const
3392 node = Config->extra_xml(X_("Keyboard"));
3395 node = new XMLNode (X_("Keyboard"));
3402 ARDOUR_UI::create_xrun_marker (framepos_t where)
3404 editor->mouse_add_new_marker (where, false, true);
3408 ARDOUR_UI::halt_on_xrun_message ()
3410 MessageDialog msg (*editor,
3411 _("Recording was stopped because your system could not keep up."));
3416 ARDOUR_UI::xrun_handler (framepos_t where)
3422 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3424 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3425 create_xrun_marker(where);
3428 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3429 halt_on_xrun_message ();
3434 ARDOUR_UI::disk_overrun_handler ()
3436 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3438 if (!have_disk_speed_dialog_displayed) {
3439 have_disk_speed_dialog_displayed = true;
3440 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3441 The disk system on your computer\n\
3442 was not able to keep up with %1.\n\
3444 Specifically, it failed to write data to disk\n\
3445 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3446 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3452 ARDOUR_UI::disk_underrun_handler ()
3454 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3456 if (!have_disk_speed_dialog_displayed) {
3457 have_disk_speed_dialog_displayed = true;
3458 MessageDialog* msg = new MessageDialog (
3459 *editor, string_compose (_("The disk system on your computer\n\
3460 was not able to keep up with %1.\n\
3462 Specifically, it failed to read data from disk\n\
3463 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3464 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3470 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3472 have_disk_speed_dialog_displayed = false;
3477 ARDOUR_UI::session_dialog (std::string msg)
3479 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3484 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3486 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3495 ARDOUR_UI::pending_state_dialog ()
3497 HBox* hbox = new HBox();
3498 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3499 ArdourDialog dialog (_("Crash Recovery"), true);
3501 This session appears to have been in\n\
3502 middle of recording when ardour or\n\
3503 the computer was shutdown.\n\
3505 Ardour can recover any captured audio for\n\
3506 you, or it can ignore it. Please decide\n\
3507 what you would like to do.\n"));
3508 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3509 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3510 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3511 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3512 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3513 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3514 dialog.set_default_response (RESPONSE_ACCEPT);
3515 dialog.set_position (WIN_POS_CENTER);
3520 switch (dialog.run ()) {
3521 case RESPONSE_ACCEPT:
3529 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3531 HBox* hbox = new HBox();
3532 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3533 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3534 Label message (string_compose (_("\
3535 This session was created with a sample rate of %1 Hz\n\
3537 The audioengine is currently running at %2 Hz\n"), desired, actual));
3539 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3540 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3541 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3542 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3543 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3544 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3545 dialog.set_default_response (RESPONSE_ACCEPT);
3546 dialog.set_position (WIN_POS_CENTER);
3551 switch (dialog.run ()) {
3552 case RESPONSE_ACCEPT:
3561 ARDOUR_UI::disconnect_from_jack ()
3564 if( engine->disconnect_from_jack ()) {
3565 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3569 update_sample_rate (0);
3574 ARDOUR_UI::reconnect_to_jack ()
3577 if (engine->reconnect_to_jack ()) {
3578 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3582 update_sample_rate (0);
3587 ARDOUR_UI::use_config ()
3589 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3591 set_transport_controllable_state (*node);
3596 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3598 if (Config->get_primary_clock_delta_edit_cursor()) {
3599 primary_clock->set (pos, false, editor->get_preferred_edit_position(), 1);
3601 primary_clock->set (pos, 0, true);
3604 if (Config->get_secondary_clock_delta_edit_cursor()) {
3605 secondary_clock->set (pos, false, editor->get_preferred_edit_position(), 2);
3607 secondary_clock->set (pos);
3610 if (big_clock_window->get()) {
3611 big_clock->set (pos);
3617 ARDOUR_UI::step_edit_status_change (bool yn)
3619 // XXX should really store pre-step edit status of things
3620 // we make insensitive
3623 rec_button.set_active_state (Mid);
3624 rec_button.set_sensitive (false);
3626 rec_button.unset_active_state ();;
3627 rec_button.set_sensitive (true);
3632 ARDOUR_UI::record_state_changed ()
3634 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3636 if (!_session || !big_clock_window->get()) {
3637 /* why bother - the clock isn't visible */
3641 Session::RecordState const r = _session->record_status ();
3642 bool const h = _session->have_rec_enabled_track ();
3644 if (r == Session::Recording && h) {
3645 big_clock->set_widget_name ("BigClockRecording");
3647 big_clock->set_widget_name ("BigClockNonRecording");
3652 ARDOUR_UI::first_idle ()
3655 _session->allow_auto_play (true);
3659 editor->first_idle();
3662 Keyboard::set_can_save_keybindings (true);
3667 ARDOUR_UI::store_clock_modes ()
3669 XMLNode* node = new XMLNode(X_("ClockModes"));
3671 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3672 XMLNode* child = new XMLNode (X_("Clock"));
3674 child->add_property (X_("name"), (*x)->name());
3675 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3676 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3678 node->add_child_nocopy (*child);
3681 _session->add_extra_xml (*node);
3682 _session->set_dirty ();
3685 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3686 : Controllable (name), ui (u), type(tp)
3692 ARDOUR_UI::TransportControllable::set_value (double val)
3695 /* do nothing: these are radio-style actions */
3699 const char *action = 0;
3703 action = X_("Roll");
3706 action = X_("Stop");
3709 action = X_("Goto Start");
3712 action = X_("Goto End");
3715 action = X_("Loop");
3718 action = X_("Play Selection");
3721 action = X_("Record");
3731 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3739 ARDOUR_UI::TransportControllable::get_value (void) const
3766 ARDOUR_UI::setup_profile ()
3768 if (gdk_screen_width() < 1200) {
3769 Profile->set_small_screen ();
3773 if (getenv ("ARDOUR_SAE")) {
3774 Profile->set_sae ();
3775 Profile->set_single_package ();
3780 ARDOUR_UI::toggle_translations ()
3782 using namespace Glib;
3784 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3786 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3789 string i18n_killer = ARDOUR::translation_kill_path();
3791 bool already_enabled = !ARDOUR::translations_are_disabled ();
3793 if (ract->get_active ()) {
3794 /* we don't care about errors */
3795 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3798 /* we don't care about errors */
3799 unlink (i18n_killer.c_str());
3802 if (already_enabled != ract->get_active()) {
3803 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3805 Gtk::MESSAGE_WARNING,
3807 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3808 win.set_position (Gtk::WIN_POS_CENTER);
3816 /** Add a window proxy to our list, so that its state will be saved.
3817 * This call also causes the window to be created and opened if its
3818 * state was saved as `visible'.
3821 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3823 _window_proxies.push_back (p);
3827 /** Remove a window proxy from our list. Must be called if a WindowProxy
3828 * is deleted, to prevent hanging pointers.
3831 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3833 _window_proxies.remove (p);
3837 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3839 MissingFileDialog dialog (s, str, type);
3844 int result = dialog.run ();
3851 return 1; // quit entire session load
3854 result = dialog.get_action ();
3860 ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
3862 AmbiguousFileDialog dialog (file, hits);
3868 return dialog.get_which ();
3871 /** Allocate our thread-local buffers */
3873 ARDOUR_UI::get_process_buffers ()
3875 _process_thread->get_buffers ();
3878 /** Drop our thread-local buffers */
3880 ARDOUR_UI::drop_process_buffers ()
3882 _process_thread->drop_buffers ();
3886 ARDOUR_UI::feedback_detected ()
3889 _("Something you have just done has generated a feedback path within Ardour's "
3890 "routing. Until this feedback is removed, Ardour's output will be as it was "
3891 "before you made the feedback-generating connection.")