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 (ArdourButton::led_default_elements)
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");
239 midi_panic_button.set_name ("transport button");
241 goto_start_button.set_tweaks (ArdourButton::ShowClick);
242 goto_end_button.set_tweaks (ArdourButton::ShowClick);
243 midi_panic_button.set_tweaks (ArdourButton::ShowClick);
245 last_configure_time= 0;
248 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
249 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
251 /* handle dialog requests */
253 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
255 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
257 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
259 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
261 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
263 /* handle requests to quit (coming from JACK session) */
265 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
267 /* tell the user about feedback */
269 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
271 /* handle requests to deal with missing files */
273 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
275 /* and ambiguous files */
277 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
279 /* lets get this party started */
282 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
283 throw failed_constructor ();
286 setup_gtk_ardour_enums ();
289 GainMeter::setup_slider_pix ();
290 RouteTimeAxisView::setup_slider_pix ();
291 SendProcessorEntry::setup_slider_pix ();
292 SessionEvent::create_per_thread_pool ("GUI", 512);
294 } catch (failed_constructor& err) {
295 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
300 /* we like keyboards */
302 keyboard = new ArdourKeyboard(*this);
304 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
306 keyboard->set_state (*node, Stateful::loading_state_version);
309 /* we don't like certain modifiers */
310 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
314 TimeAxisViewItem::set_constant_heights ();
316 /* The following must happen after ARDOUR::init() so that Config is set up */
318 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
319 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
320 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
322 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
323 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
324 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
325 Config->extra_xml (X_("UI")),
326 string_compose ("toggle-%1-connection-manager", (*i).to_string())
332 SpeakerDialog* s = new SpeakerDialog ();
333 s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
334 speaker_config_window->set (s);
336 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
337 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
339 _process_thread = new ProcessThread ();
340 _process_thread->init ();
343 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
345 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
348 _startup = new ArdourStartup ();
350 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
352 if (audio_setup && _startup->engine_control()) {
353 _startup->engine_control()->set_state (*audio_setup);
356 _startup->set_new_only (should_be_new);
357 if (!load_template.empty()) {
358 _startup->set_load_template( load_template );
360 _startup->present ();
366 switch (_startup->response()) {
375 ARDOUR_UI::create_engine ()
377 // this gets called every time by new_session()
383 loading_message (_("Starting audio engine"));
386 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
393 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
394 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
395 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
397 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
399 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
407 ARDOUR_UI::post_engine ()
409 /* Things to be done once we create the AudioEngine
412 ARDOUR::init_post_engine ();
414 ActionManager::init ();
417 if (setup_windows ()) {
418 throw failed_constructor ();
421 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
422 XMLNode* n = Config->extra_xml (X_("UI"));
424 _status_bar_visibility.set_state (*n);
427 check_memory_locking();
429 /* this is the first point at which all the keybindings are available */
431 if (ARDOUR_COMMAND_LINE::show_key_actions) {
432 vector<string> names;
433 vector<string> paths;
434 vector<string> tooltips;
436 vector<AccelKey> bindings;
438 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
440 vector<string>::iterator n;
441 vector<string>::iterator k;
442 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
443 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
449 blink_timeout_tag = -1;
451 /* this being a GUI and all, we want peakfiles */
453 AudioFileSource::set_build_peakfiles (true);
454 AudioFileSource::set_build_missing_peakfiles (true);
456 /* set default clock modes */
458 if (Profile->get_sae()) {
459 primary_clock->set_mode (AudioClock::BBT);
460 secondary_clock->set_mode (AudioClock::MinSec);
462 primary_clock->set_mode (AudioClock::Timecode);
463 secondary_clock->set_mode (AudioClock::BBT);
466 /* start the time-of-day-clock */
469 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
470 update_wall_clock ();
471 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
474 update_disk_space ();
476 update_sample_rate (engine->frame_rate());
478 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
479 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
480 Config->map_parameters (pc);
482 /* now start and maybe save state */
484 if (do_engine_start () == 0) {
485 if (_session && _session_is_new) {
486 /* we need to retain initial visual
487 settings for a new session
489 _session->save_state ("");
494 ARDOUR_UI::~ARDOUR_UI ()
499 delete add_route_dialog;
503 ARDOUR_UI::pop_back_splash ()
505 if (Splash::instance()) {
506 // Splash::instance()->pop_back();
507 Splash::instance()->hide ();
512 ARDOUR_UI::configure_timeout ()
514 if (last_configure_time == 0) {
515 /* no configure events yet */
519 /* force a gap of 0.5 seconds since the last configure event
522 if (get_microseconds() - last_configure_time < 500000) {
525 have_configure_timeout = false;
526 cerr << "config event-driven save\n";
527 save_ardour_state ();
533 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
535 if (have_configure_timeout) {
536 last_configure_time = get_microseconds();
538 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
539 have_configure_timeout = true;
546 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
548 const XMLProperty* prop;
550 if ((prop = node.property ("roll")) != 0) {
551 roll_controllable->set_id (prop->value());
553 if ((prop = node.property ("stop")) != 0) {
554 stop_controllable->set_id (prop->value());
556 if ((prop = node.property ("goto-start")) != 0) {
557 goto_start_controllable->set_id (prop->value());
559 if ((prop = node.property ("goto-end")) != 0) {
560 goto_end_controllable->set_id (prop->value());
562 if ((prop = node.property ("auto-loop")) != 0) {
563 auto_loop_controllable->set_id (prop->value());
565 if ((prop = node.property ("play-selection")) != 0) {
566 play_selection_controllable->set_id (prop->value());
568 if ((prop = node.property ("rec")) != 0) {
569 rec_controllable->set_id (prop->value());
571 if ((prop = node.property ("shuttle")) != 0) {
572 shuttle_box->controllable()->set_id (prop->value());
578 ARDOUR_UI::get_transport_controllable_state ()
580 XMLNode* node = new XMLNode(X_("TransportControllables"));
583 roll_controllable->id().print (buf, sizeof (buf));
584 node->add_property (X_("roll"), buf);
585 stop_controllable->id().print (buf, sizeof (buf));
586 node->add_property (X_("stop"), buf);
587 goto_start_controllable->id().print (buf, sizeof (buf));
588 node->add_property (X_("goto_start"), buf);
589 goto_end_controllable->id().print (buf, sizeof (buf));
590 node->add_property (X_("goto_end"), buf);
591 auto_loop_controllable->id().print (buf, sizeof (buf));
592 node->add_property (X_("auto_loop"), buf);
593 play_selection_controllable->id().print (buf, sizeof (buf));
594 node->add_property (X_("play_selection"), buf);
595 rec_controllable->id().print (buf, sizeof (buf));
596 node->add_property (X_("rec"), buf);
597 shuttle_box->controllable()->id().print (buf, sizeof (buf));
598 node->add_property (X_("shuttle"), buf);
605 ARDOUR_UI::autosave_session ()
607 if (g_main_depth() > 1) {
608 /* inside a recursive main loop,
609 give up because we may not be able to
615 if (!Config->get_periodic_safety_backups()) {
620 _session->maybe_write_autosave();
627 ARDOUR_UI::update_autosave ()
629 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
631 if (_session && _session->dirty()) {
632 if (_autosave_connection.connected()) {
633 _autosave_connection.disconnect();
636 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
637 Config->get_periodic_safety_backup_interval() * 1000);
640 if (_autosave_connection.connected()) {
641 _autosave_connection.disconnect();
647 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
651 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
653 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
656 MessageDialog win (title,
662 win.set_secondary_text(_("There are several possible reasons:\n\
664 1) You requested audio parameters that are not supported..\n\
665 2) JACK is running as another user.\n\
667 Please consider the possibilities, and perhaps try different parameters."));
669 win.set_secondary_text(_("There are several possible reasons:\n\
671 1) JACK is not running.\n\
672 2) JACK is running as another user, perhaps root.\n\
673 3) There is already another client called \"ardour\".\n\
675 Please consider the possibilities, and perhaps (re)start JACK."));
679 win.set_transient_for (*toplevel);
683 win.add_button (Stock::OK, RESPONSE_CLOSE);
685 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
688 win.set_default_response (RESPONSE_CLOSE);
691 win.set_position (Gtk::WIN_POS_CENTER);
694 /* we just don't care about the result, but we want to block */
700 ARDOUR_UI::startup ()
702 Application* app = Application::instance ();
704 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
705 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
708 call_the_mothership (VERSIONSTRING);
713 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
719 goto_editor_window ();
721 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
722 to be opened on top of the editor window that goto_editor_window() just opened.
724 add_window_proxy (location_ui);
725 add_window_proxy (big_clock_window);
726 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
727 add_window_proxy (_global_port_matrix[*i]);
730 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
731 * editor window, and we may want stuff to be hidden.
733 _status_bar_visibility.update ();
735 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
739 ARDOUR_UI::no_memory_warning ()
741 XMLNode node (X_("no-memory-warning"));
742 Config->add_instant_xml (node);
746 ARDOUR_UI::check_memory_locking ()
749 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
753 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
755 if (engine->is_realtime() && memory_warning_node == 0) {
757 struct rlimit limits;
759 long pages, page_size;
761 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
764 ram = (int64_t) pages * (int64_t) page_size;
767 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
771 if (limits.rlim_cur != RLIM_INFINITY) {
773 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
777 _("WARNING: Your system has a limit for maximum amount of locked memory. "
778 "This might cause %1 to run out of memory before your system "
779 "runs out of memory. \n\n"
780 "You can view the memory limit with 'ulimit -l', "
781 "and it is normally controlled by /etc/security/limits.conf"),
782 PROGRAM_NAME).c_str());
784 VBox* vbox = msg.get_vbox();
786 CheckButton cb (_("Do not show this window again"));
788 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
790 hbox.pack_start (cb, true, false);
791 vbox->pack_start (hbox);
798 editor->ensure_float (msg);
808 ARDOUR_UI::queue_finish ()
810 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
814 ARDOUR_UI::idle_finish ()
817 return false; /* do not call again */
826 if (_session->transport_rolling() && (++tries < 8)) {
827 _session->request_stop (false, true);
831 if (_session->dirty()) {
832 vector<string> actions;
833 actions.push_back (_("Don't quit"));
834 actions.push_back (_("Just quit"));
835 actions.push_back (_("Save and quit"));
836 switch (ask_about_saving_session(actions)) {
841 /* use the default name */
842 if (save_state_canfail ("")) {
843 /* failed - don't quit */
844 MessageDialog msg (*editor,
846 Ardour was unable to save your session.\n\n\
847 If you still wish to quit, please use the\n\n\
848 \"Just quit\" option."));
859 second_connection.disconnect ();
860 point_one_second_connection.disconnect ();
861 point_oh_five_second_connection.disconnect ();
862 point_zero_one_second_connection.disconnect();
865 /* Save state before deleting the session, as that causes some
866 windows to be destroyed before their visible state can be
869 save_ardour_state ();
872 // _session->set_deletion_in_progress ();
873 _session->set_clean ();
874 _session->remove_pending_capture_state ();
879 ArdourDialog::close_all_dialogs ();
885 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
887 ArdourDialog window (_("Unsaved Session"));
888 Gtk::HBox dhbox; // the hbox for the image and text
889 Gtk::Label prompt_label;
890 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
894 assert (actions.size() >= 3);
896 window.add_button (actions[0], RESPONSE_REJECT);
897 window.add_button (actions[1], RESPONSE_APPLY);
898 window.add_button (actions[2], RESPONSE_ACCEPT);
900 window.set_default_response (RESPONSE_ACCEPT);
902 Gtk::Button noquit_button (msg);
903 noquit_button.set_name ("EditorGTKButton");
907 if (_session->snap_name() == _session->name()) {
908 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?"),
909 _session->snap_name());
911 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?"),
912 _session->snap_name());
915 prompt_label.set_text (prompt);
916 prompt_label.set_name (X_("PrompterLabel"));
917 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
919 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
920 dhbox.set_homogeneous (false);
921 dhbox.pack_start (*dimage, false, false, 5);
922 dhbox.pack_start (prompt_label, true, false, 5);
923 window.get_vbox()->pack_start (dhbox);
925 window.set_name (_("Prompter"));
926 window.set_position (Gtk::WIN_POS_MOUSE);
927 window.set_modal (true);
928 window.set_resizable (false);
934 window.set_keep_above (true);
937 ResponseType r = (ResponseType) window.run();
942 case RESPONSE_ACCEPT: // save and get out of here
944 case RESPONSE_APPLY: // get out of here
954 ARDOUR_UI::every_second ()
957 update_buffer_load ();
958 update_disk_space ();
963 ARDOUR_UI::every_point_one_seconds ()
965 shuttle_box->update_speed_display ();
966 RapidScreenUpdate(); /* EMIT_SIGNAL */
971 ARDOUR_UI::every_point_zero_one_seconds ()
973 // august 2007: actual update frequency: 40Hz, not 100Hz
975 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
980 ARDOUR_UI::update_sample_rate (framecnt_t)
984 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
986 if (!engine->connected()) {
988 snprintf (buf, sizeof (buf), _("disconnected"));
992 framecnt_t rate = engine->frame_rate();
994 if (fmod (rate, 1000.0) != 0.0) {
995 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
996 (float) rate/1000.0f,
997 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
999 snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1001 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1005 sample_rate_label.set_markup (buf);
1009 ARDOUR_UI::update_format ()
1012 format_label.set_text ("");
1017 s << "File: <span foreground=\"green\">";
1019 switch (_session->config.get_native_file_header_format ()) {
1045 switch (_session->config.get_native_file_data_format ()) {
1059 format_label.set_markup (s.str ());
1063 ARDOUR_UI::update_cpu_load ()
1067 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::build_menu_bar
1068 should also be changed.
1071 float const c = engine->get_cpu_load ();
1072 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1073 cpu_load_label.set_markup (buf);
1077 ARDOUR_UI::update_buffer_load ()
1081 uint32_t const playback = _session ? _session->playback_load () : 100;
1082 uint32_t const capture = _session ? _session->capture_load () : 100;
1084 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::build_menu_bar
1085 should also be changed.
1091 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1092 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1093 playback <= 5 ? X_("red") : X_("green"),
1095 capture <= 5 ? X_("red") : X_("green"),
1099 buffer_load_label.set_markup (buf);
1101 buffer_load_label.set_text ("");
1106 ARDOUR_UI::count_recenabled_streams (Route& route)
1108 Track* track = dynamic_cast<Track*>(&route);
1109 if (track && track->record_enabled()) {
1110 rec_enabled_streams += track->n_inputs().n_total();
1115 ARDOUR_UI::update_disk_space()
1117 if (_session == 0) {
1121 framecnt_t frames = _session->available_capture_duration();
1123 framecnt_t fr = _session->frame_rate();
1125 if (frames == max_framecnt) {
1126 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">24hrs+</span>"));
1128 rec_enabled_streams = 0;
1129 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1131 if (rec_enabled_streams) {
1132 frames /= rec_enabled_streams;
1139 hrs = frames / (fr * 3600);
1142 snprintf (buf, sizeof (buf), _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1144 frames -= hrs * fr * 3600;
1145 mins = frames / (fr * 60);
1146 frames -= mins * fr * 60;
1149 bool const low = (hrs == 0 && mins <= 30);
1153 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1154 low ? X_("red") : X_("green"),
1160 disk_space_label.set_markup (buf);
1162 // An attempt to make the disk space label flash red when space has run out.
1164 if (frames < fr * 60 * 5) {
1165 /* disk_space_box.style ("disk_space_label_empty"); */
1167 /* disk_space_box.style ("disk_space_label"); */
1173 ARDOUR_UI::update_wall_clock ()
1180 tm_now = localtime (&now);
1182 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1183 wall_clock_label.set_text (buf);
1189 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1191 session_popup_menu->popup (0, 0);
1196 ARDOUR_UI::redisplay_recent_sessions ()
1198 std::vector<sys::path> session_directories;
1199 RecentSessionsSorter cmp;
1201 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1202 recent_session_model->clear ();
1204 ARDOUR::RecentSessions rs;
1205 ARDOUR::read_recent_sessions (rs);
1208 recent_session_display.set_model (recent_session_model);
1212 // sort them alphabetically
1213 sort (rs.begin(), rs.end(), cmp);
1215 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1216 session_directories.push_back ((*i).second);
1219 for (vector<sys::path>::const_iterator i = session_directories.begin();
1220 i != session_directories.end(); ++i)
1222 std::vector<sys::path> state_file_paths;
1224 // now get available states for this session
1226 get_state_files_in_directory (*i, state_file_paths);
1228 vector<string*>* states;
1229 vector<const gchar*> item;
1230 string fullpath = (*i).to_string();
1232 /* remove any trailing / */
1234 if (fullpath[fullpath.length()-1] == '/') {
1235 fullpath = fullpath.substr (0, fullpath.length()-1);
1238 /* check whether session still exists */
1239 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1240 /* session doesn't exist */
1241 cerr << "skipping non-existent session " << fullpath << endl;
1245 /* now get available states for this session */
1247 if ((states = Session::possible_states (fullpath)) == 0) {
1248 /* no state file? */
1252 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1254 Gtk::TreeModel::Row row = *(recent_session_model->append());
1256 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1257 row[recent_session_columns.fullpath] = fullpath;
1259 if (state_file_names.size() > 1) {
1263 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1264 i2 != state_file_names.end(); ++i2)
1267 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1269 child_row[recent_session_columns.visible_name] = *i2;
1270 child_row[recent_session_columns.fullpath] = fullpath;
1275 recent_session_display.set_model (recent_session_model);
1279 ARDOUR_UI::build_session_selector ()
1281 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1283 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1285 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1286 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1287 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1288 recent_session_model = TreeStore::create (recent_session_columns);
1289 recent_session_display.set_model (recent_session_model);
1290 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1291 recent_session_display.set_headers_visible (false);
1292 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1293 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1295 scroller->add (recent_session_display);
1296 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1298 session_selector_window->set_name ("SessionSelectorWindow");
1299 session_selector_window->set_size_request (200, 400);
1300 session_selector_window->get_vbox()->pack_start (*scroller);
1302 recent_session_display.show();
1304 //session_selector_window->get_vbox()->show();
1308 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1310 session_selector_window->response (RESPONSE_ACCEPT);
1314 ARDOUR_UI::open_recent_session ()
1316 bool can_return = (_session != 0);
1318 if (session_selector_window == 0) {
1319 build_session_selector ();
1322 redisplay_recent_sessions ();
1326 session_selector_window->set_position (WIN_POS_MOUSE);
1328 ResponseType r = (ResponseType) session_selector_window->run ();
1331 case RESPONSE_ACCEPT:
1335 session_selector_window->hide();
1342 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1346 session_selector_window->hide();
1348 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1350 if (i == recent_session_model->children().end()) {
1354 std::string path = (*i)[recent_session_columns.fullpath];
1355 std::string state = (*i)[recent_session_columns.visible_name];
1357 _session_is_new = false;
1359 if (load_session (path, state) == 0) {
1368 ARDOUR_UI::check_audioengine ()
1371 if (!engine->connected()) {
1372 MessageDialog msg (string_compose (
1373 _("%1 is not connected to JACK\n"
1374 "You cannot open or close sessions in this condition"),
1387 ARDOUR_UI::open_session ()
1389 if (!check_audioengine()) {
1394 /* popup selector window */
1396 if (open_session_selector == 0) {
1398 /* ardour sessions are folders */
1400 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1401 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1402 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1403 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1405 FileFilter session_filter;
1406 session_filter.add_pattern ("*.ardour");
1407 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1408 open_session_selector->add_filter (session_filter);
1409 open_session_selector->set_filter (session_filter);
1412 int response = open_session_selector->run();
1413 open_session_selector->hide ();
1416 case RESPONSE_ACCEPT:
1419 open_session_selector->hide();
1423 open_session_selector->hide();
1424 string session_path = open_session_selector->get_filename();
1428 if (session_path.length() > 0) {
1429 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1430 _session_is_new = isnew;
1431 load_session (path, name);
1438 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1440 list<boost::shared_ptr<MidiTrack> > tracks;
1442 if (_session == 0) {
1443 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1450 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1452 if (tracks.size() != how_many) {
1453 if (how_many == 1) {
1454 error << _("could not create a new midi track") << endmsg;
1456 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1460 if ((route = _session->new_midi_route ()) == 0) {
1461 error << _("could not create new midi bus") << endmsg;
1467 MessageDialog msg (*editor,
1468 string_compose (_("There are insufficient JACK ports available\n\
1469 to create a new track or bus.\n\
1470 You should save %1, exit and\n\
1471 restart JACK with more ports."), PROGRAM_NAME));
1478 ARDOUR_UI::session_add_audio_route (
1480 int32_t input_channels,
1481 int32_t output_channels,
1482 ARDOUR::TrackMode mode,
1483 RouteGroup* route_group,
1485 string const & name_template
1488 list<boost::shared_ptr<AudioTrack> > tracks;
1491 if (_session == 0) {
1492 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1498 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1500 if (tracks.size() != how_many) {
1501 if (how_many == 1) {
1502 error << _("could not create a new audio track") << endmsg;
1504 error << string_compose (_("could only create %1 of %2 new audio %3"),
1505 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1511 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1513 if (routes.size() != how_many) {
1514 if (how_many == 1) {
1515 error << _("could not create a new audio bus") << endmsg;
1517 error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg;
1524 MessageDialog msg (*editor,
1525 string_compose (_("There are insufficient JACK ports available\n\
1526 to create a new track or bus.\n\
1527 You should save %1, exit and\n\
1528 restart JACK with more ports."), PROGRAM_NAME));
1535 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1537 framecnt_t _preroll = 0;
1540 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1541 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1543 if (new_position > _preroll) {
1544 new_position -= _preroll;
1549 _session->request_locate (new_position, with_roll);
1554 ARDOUR_UI::transport_goto_start ()
1557 _session->goto_start();
1559 /* force displayed area in editor to start no matter
1560 what "follow playhead" setting is.
1564 editor->center_screen (_session->current_start_frame ());
1570 ARDOUR_UI::transport_goto_zero ()
1573 _session->request_locate (0);
1575 /* force displayed area in editor to start no matter
1576 what "follow playhead" setting is.
1580 editor->reset_x_origin (0);
1586 ARDOUR_UI::transport_goto_wallclock ()
1588 if (_session && editor) {
1595 localtime_r (&now, &tmnow);
1597 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1598 frames += tmnow.tm_min * (60 * _session->frame_rate());
1599 frames += tmnow.tm_sec * _session->frame_rate();
1601 _session->request_locate (frames, _session->transport_rolling ());
1603 /* force displayed area in editor to start no matter
1604 what "follow playhead" setting is.
1608 editor->center_screen (frames);
1614 ARDOUR_UI::transport_goto_end ()
1617 framepos_t const frame = _session->current_end_frame();
1618 _session->request_locate (frame);
1620 /* force displayed area in editor to start no matter
1621 what "follow playhead" setting is.
1625 editor->center_screen (frame);
1631 ARDOUR_UI::transport_stop ()
1637 if (_session->is_auditioning()) {
1638 _session->cancel_audition ();
1642 _session->request_stop (false, true);
1646 ARDOUR_UI::transport_stop_and_forget_capture ()
1649 _session->request_stop (true, true);
1654 ARDOUR_UI::remove_last_capture()
1657 editor->remove_last_capture();
1662 ARDOUR_UI::transport_record (bool roll)
1666 switch (_session->record_status()) {
1667 case Session::Disabled:
1668 if (_session->ntracks() == 0) {
1669 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1673 _session->maybe_enable_record ();
1678 case Session::Recording:
1680 _session->request_stop();
1682 _session->disable_record (false, true);
1686 case Session::Enabled:
1687 _session->disable_record (false, true);
1690 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1694 ARDOUR_UI::transport_roll ()
1700 if (_session->is_auditioning()) {
1705 if (_session->config.get_external_sync()) {
1706 switch (_session->config.get_sync_source()) {
1710 /* transport controlled by the master */
1716 bool rolling = _session->transport_rolling();
1718 if (_session->get_play_loop()) {
1719 /* XXX it is not possible to just leave seamless loop and keep
1720 playing at present (nov 4th 2009)
1722 if (!Config->get_seamless_loop()) {
1723 _session->request_play_loop (false, true);
1725 } else if (_session->get_play_range () && !join_play_range_button.active_state()) {
1726 /* stop playing a range if we currently are */
1727 _session->request_play_range (0, true);
1730 if (join_play_range_button.active_state()) {
1731 _session->request_play_range (&editor->get_selection().time, true);
1735 _session->request_transport_speed (1.0f);
1740 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1747 if (_session->is_auditioning()) {
1748 _session->cancel_audition ();
1752 if (_session->config.get_external_sync()) {
1753 switch (_session->config.get_sync_source()) {
1757 /* transport controlled by the master */
1762 bool rolling = _session->transport_rolling();
1763 bool affect_transport = true;
1765 if (rolling && roll_out_of_bounded_mode) {
1766 /* drop out of loop/range playback but leave transport rolling */
1767 if (_session->get_play_loop()) {
1768 if (Config->get_seamless_loop()) {
1769 /* the disk buffers contain copies of the loop - we can't
1770 just keep playing, so stop the transport. the user
1771 can restart as they wish.
1773 affect_transport = true;
1775 /* disk buffers are normal, so we can keep playing */
1776 affect_transport = false;
1778 _session->request_play_loop (false, true);
1779 } else if (_session->get_play_range ()) {
1780 affect_transport = false;
1781 _session->request_play_range (0, true);
1785 if (affect_transport) {
1787 _session->request_stop (with_abort, true);
1789 if (join_play_range_button.active_state()) {
1790 _session->request_play_range (&editor->get_selection().time, true);
1793 _session->request_transport_speed (1.0f);
1799 ARDOUR_UI::toggle_session_auto_loop ()
1805 if (_session->get_play_loop()) {
1807 if (_session->transport_rolling()) {
1809 Location * looploc = _session->locations()->auto_loop_location();
1812 _session->request_locate (looploc->start(), true);
1813 _session->request_play_loop (false);
1817 _session->request_play_loop (false);
1821 Location * looploc = _session->locations()->auto_loop_location();
1824 _session->request_play_loop (true);
1830 ARDOUR_UI::transport_play_selection ()
1836 editor->play_selection ();
1840 ARDOUR_UI::transport_rewind (int option)
1842 float current_transport_speed;
1845 current_transport_speed = _session->transport_speed();
1847 if (current_transport_speed >= 0.0f) {
1850 _session->request_transport_speed (-1.0f);
1853 _session->request_transport_speed (-4.0f);
1856 _session->request_transport_speed (-0.5f);
1861 _session->request_transport_speed (current_transport_speed * 1.5f);
1867 ARDOUR_UI::transport_forward (int option)
1869 float current_transport_speed;
1872 current_transport_speed = _session->transport_speed();
1874 if (current_transport_speed <= 0.0f) {
1877 _session->request_transport_speed (1.0f);
1880 _session->request_transport_speed (4.0f);
1883 _session->request_transport_speed (0.5f);
1888 _session->request_transport_speed (current_transport_speed * 1.5f);
1895 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1897 if (_session == 0) {
1901 boost::shared_ptr<Route> r;
1903 if ((r = _session->route_by_remote_id (rid)) != 0) {
1907 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1908 t->set_record_enabled (!t->record_enabled(), this);
1911 if (_session == 0) {
1917 ARDOUR_UI::map_transport_state ()
1920 auto_loop_button.unset_active_state ();
1921 play_selection_button.unset_active_state ();
1922 roll_button.unset_active_state ();
1923 stop_button.set_active_state (Gtkmm2ext::Active);
1927 shuttle_box->map_transport_state ();
1929 float sp = _session->transport_speed();
1935 if (_session->get_play_range()) {
1937 play_selection_button.set_active_state (Gtkmm2ext::Active);
1938 roll_button.unset_active_state ();
1939 auto_loop_button.unset_active_state ();
1941 } else if (_session->get_play_loop ()) {
1943 auto_loop_button.set_active_state (Gtkmm2ext::Active);
1944 play_selection_button.unset_active_state ();
1945 roll_button.unset_active_state ();
1949 roll_button.set_active_state (Gtkmm2ext::Active);
1950 play_selection_button.unset_active_state ();
1951 auto_loop_button.unset_active_state ();
1954 if (join_play_range_button.active_state()) {
1955 /* light up both roll and play-selection if they are joined */
1956 roll_button.set_active_state (Gtkmm2ext::Active);
1957 play_selection_button.set_active_state (Gtkmm2ext::Active);
1960 stop_button.unset_active_state ();
1964 stop_button.set_active_state (Gtkmm2ext::Active);
1965 roll_button.unset_active_state ();
1966 play_selection_button.unset_active_state ();
1967 auto_loop_button.unset_active_state ();
1968 update_disk_space ();
1973 ARDOUR_UI::engine_stopped ()
1975 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1976 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1977 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1981 ARDOUR_UI::engine_running ()
1983 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1984 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1985 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1987 Glib::RefPtr<Action> action;
1988 const char* action_name = 0;
1990 switch (engine->frames_per_cycle()) {
1992 action_name = X_("JACKLatency32");
1995 action_name = X_("JACKLatency64");
1998 action_name = X_("JACKLatency128");
2001 action_name = X_("JACKLatency512");
2004 action_name = X_("JACKLatency1024");
2007 action_name = X_("JACKLatency2048");
2010 action_name = X_("JACKLatency4096");
2013 action_name = X_("JACKLatency8192");
2016 /* XXX can we do anything useful ? */
2022 action = ActionManager::get_action (X_("JACK"), action_name);
2025 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
2026 ract->set_active ();
2032 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
2034 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
2035 /* we can't rely on the original string continuing to exist when we are called
2036 again in the GUI thread, so make a copy and note that we need to
2039 char *copy = strdup (reason);
2040 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
2044 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
2045 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
2047 update_sample_rate (0);
2051 /* if the reason is a non-empty string, it means that the backend was shutdown
2052 rather than just Ardour.
2055 if (strlen (reason)) {
2056 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
2058 msgstr = string_compose (_("\
2059 JACK has either been shutdown or it\n\
2060 disconnected %1 because %1\n\
2061 was not fast enough. Try to restart\n\
2062 JACK, reconnect and save the session."), PROGRAM_NAME);
2065 MessageDialog msg (*editor, msgstr);
2070 free ((char*) reason);
2075 ARDOUR_UI::do_engine_start ()
2083 error << _("Unable to start the session running")
2093 ARDOUR_UI::setup_theme ()
2095 theme_manager->setup_theme();
2099 ARDOUR_UI::update_clocks ()
2101 if (!editor || !editor->dragging_playhead()) {
2102 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2107 ARDOUR_UI::start_clocking ()
2109 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2113 ARDOUR_UI::stop_clocking ()
2115 clock_signal_connection.disconnect ();
2119 ARDOUR_UI::toggle_clocking ()
2122 if (clock_button.get_active()) {
2131 ARDOUR_UI::_blink (void *arg)
2134 ((ARDOUR_UI *) arg)->blink ();
2141 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2145 ARDOUR_UI::start_blinking ()
2147 /* Start the blink signal. Everybody with a blinking widget
2148 uses Blink to drive the widget's state.
2151 if (blink_timeout_tag < 0) {
2153 blink_timeout_tag = g_timeout_add (240, _blink, this);
2158 ARDOUR_UI::stop_blinking ()
2160 if (blink_timeout_tag >= 0) {
2161 g_source_remove (blink_timeout_tag);
2162 blink_timeout_tag = -1;
2167 /** Ask the user for the name of a new shapshot and then take it.
2171 ARDOUR_UI::snapshot_session (bool switch_to_it)
2173 ArdourPrompter prompter (true);
2176 prompter.set_name ("Prompter");
2177 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2178 prompter.set_title (_("Take Snapshot"));
2179 prompter.set_prompt (_("Name of new snapshot"));
2181 if (!switch_to_it) {
2184 struct tm local_time;
2187 localtime_r (&n, &local_time);
2188 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2189 prompter.set_initial_text (timebuf);
2193 switch (prompter.run()) {
2194 case RESPONSE_ACCEPT:
2196 prompter.get_result (snapname);
2198 bool do_save = (snapname.length() != 0);
2201 if (snapname.find ('/') != string::npos) {
2202 MessageDialog msg (_("To ensure compatibility with various systems\n"
2203 "snapshot names may not contain a '/' character"));
2207 if (snapname.find ('\\') != string::npos) {
2208 MessageDialog msg (_("To ensure compatibility with various systems\n"
2209 "snapshot names may not contain a '\\' character"));
2213 if (snapname.find (':') != string::npos) {
2214 MessageDialog msg (_("To ensure compatibility with various systems\n"
2215 "snapshot names may not contain a ':' character"));
2221 vector<sys::path> p;
2222 get_state_files_in_directory (_session->session_directory().root_path(), p);
2223 vector<string> n = get_file_names_no_extension (p);
2224 if (find (n.begin(), n.end(), snapname) != n.end()) {
2226 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2227 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2228 confirm.get_vbox()->pack_start (m, true, true);
2229 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2230 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2231 confirm.show_all ();
2232 switch (confirm.run()) {
2233 case RESPONSE_CANCEL:
2239 save_state (snapname, switch_to_it);
2249 /** Ask the user for the name of a new shapshot and then take it.
2253 ARDOUR_UI::rename_session ()
2259 ArdourPrompter prompter (true);
2262 prompter.set_name ("Prompter");
2263 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2264 prompter.set_title (_("Rename Session"));
2265 prompter.set_prompt (_("New session name"));
2268 switch (prompter.run()) {
2269 case RESPONSE_ACCEPT:
2271 prompter.get_result (name);
2273 bool do_rename = (name.length() != 0);
2276 if (name.find ('/') != string::npos) {
2277 MessageDialog msg (_("To ensure compatibility with various systems\n"
2278 "session names may not contain a '/' character"));
2282 if (name.find ('\\') != string::npos) {
2283 MessageDialog msg (_("To ensure compatibility with various systems\n"
2284 "session names may not contain a '\\' character"));
2289 switch (_session->rename (name)) {
2291 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2292 msg.set_position (WIN_POS_MOUSE);
2300 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2301 msg.set_position (WIN_POS_MOUSE);
2317 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2319 XMLNode* node = new XMLNode (X_("UI"));
2321 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2322 if (!(*i)->rc_configured()) {
2323 node->add_child_nocopy (*((*i)->get_state ()));
2327 node->add_child_nocopy (gui_object_state->get_state());
2329 _session->add_extra_xml (*node);
2331 save_state_canfail (name, switch_to_it);
2335 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2340 if (name.length() == 0) {
2341 name = _session->snap_name();
2344 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2349 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2354 ARDOUR_UI::primary_clock_value_changed ()
2357 _session->request_locate (primary_clock->current_time ());
2362 ARDOUR_UI::big_clock_value_changed ()
2365 _session->request_locate (big_clock->current_time ());
2370 ARDOUR_UI::secondary_clock_value_changed ()
2373 _session->request_locate (secondary_clock->current_time ());
2378 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2380 if (_session == 0) {
2384 if (_session->step_editing()) {
2388 Session::RecordState const r = _session->record_status ();
2389 bool const h = _session->have_rec_enabled_track ();
2391 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2393 rec_button.set_active_state (Active);
2395 rec_button.set_active_state (Mid);
2397 } else if (r == Session::Recording && h) {
2398 rec_button.set_active_state (Mid);
2400 rec_button.unset_active_state ();
2405 ARDOUR_UI::save_template ()
2407 ArdourPrompter prompter (true);
2410 if (!check_audioengine()) {
2414 prompter.set_name (X_("Prompter"));
2415 prompter.set_title (_("Save Template"));
2416 prompter.set_prompt (_("Name for template:"));
2417 prompter.set_initial_text(_session->name() + _("-template"));
2418 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2420 switch (prompter.run()) {
2421 case RESPONSE_ACCEPT:
2422 prompter.get_result (name);
2424 if (name.length()) {
2425 _session->save_template (name);
2435 ARDOUR_UI::edit_metadata ()
2437 SessionMetadataEditor dialog;
2438 dialog.set_session (_session);
2439 editor->ensure_float (dialog);
2444 ARDOUR_UI::import_metadata ()
2446 SessionMetadataImporter dialog;
2447 dialog.set_session (_session);
2448 editor->ensure_float (dialog);
2453 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2455 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2457 MessageDialog msg (str,
2459 Gtk::MESSAGE_WARNING,
2460 Gtk::BUTTONS_YES_NO,
2464 msg.set_name (X_("OpenExistingDialog"));
2465 msg.set_title (_("Open Existing Session"));
2466 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2467 msg.set_position (Gtk::WIN_POS_MOUSE);
2470 switch (msg.run()) {
2479 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2481 BusProfile bus_profile;
2483 if (Profile->get_sae()) {
2485 bus_profile.master_out_channels = 2;
2486 bus_profile.input_ac = AutoConnectPhysical;
2487 bus_profile.output_ac = AutoConnectMaster;
2488 bus_profile.requested_physical_in = 0; // use all available
2489 bus_profile.requested_physical_out = 0; // use all available
2493 /* get settings from advanced section of NSD */
2495 if (_startup->create_master_bus()) {
2496 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2498 bus_profile.master_out_channels = 0;
2501 if (_startup->connect_inputs()) {
2502 bus_profile.input_ac = AutoConnectPhysical;
2504 bus_profile.input_ac = AutoConnectOption (0);
2507 /// @todo some minor tweaks.
2509 bus_profile.output_ac = AutoConnectOption (0);
2511 if (_startup->connect_outputs ()) {
2512 if (_startup->connect_outs_to_master()) {
2513 bus_profile.output_ac = AutoConnectMaster;
2514 } else if (_startup->connect_outs_to_physical()) {
2515 bus_profile.output_ac = AutoConnectPhysical;
2519 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2520 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2523 if (build_session (session_path, session_name, bus_profile)) {
2531 ARDOUR_UI::idle_load (const std::string& path)
2534 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2535 /* /path/to/foo => /path/to/foo, foo */
2536 load_session (path, basename_nosuffix (path));
2538 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2539 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2543 ARDOUR_COMMAND_LINE::session_name = path;
2546 * new_session_dialog doens't exist in A3
2547 * Try to remove all references to it to
2548 * see if it will compile. NOTE: this will
2549 * likely cause a runtime issue is my somewhat
2553 //if (new_session_dialog) {
2556 /* make it break out of Dialog::run() and
2560 //new_session_dialog->response (1);
2566 ARDOUR_UI::end_loading_messages ()
2572 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2575 // splash->message (msg);
2579 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2581 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2583 string session_name;
2584 string session_path;
2585 string template_name;
2587 bool likely_new = false;
2589 if (!load_template.empty()) {
2590 should_be_new = true;
2591 template_name = load_template;
2596 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2598 /* if they named a specific statefile, use it, otherwise they are
2599 just giving a session folder, and we want to use it as is
2600 to find the session.
2603 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2605 if (suffix != string::npos) {
2606 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2607 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2608 session_name = Glib::path_get_basename (session_name);
2610 session_path = ARDOUR_COMMAND_LINE::session_name;
2611 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2616 bool const apply = run_startup (should_be_new, load_template);
2619 if (quit_on_cancel) {
2626 /* if we run the startup dialog again, offer more than just "new session" */
2628 should_be_new = false;
2630 session_name = _startup->session_name (likely_new);
2632 string::size_type suffix = session_name.find (statefile_suffix);
2634 if (suffix != string::npos) {
2635 session_name = session_name.substr (0, suffix);
2638 /* this shouldn't happen, but we catch it just in case it does */
2640 if (session_name.empty()) {
2644 if (_startup->use_session_template()) {
2645 template_name = _startup->session_template_name();
2646 _session_is_new = true;
2649 if (session_name[0] == G_DIR_SEPARATOR ||
2650 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2651 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2653 /* absolute path or cwd-relative path specified for session name: infer session folder
2654 from what was given.
2657 session_path = Glib::path_get_dirname (session_name);
2658 session_name = Glib::path_get_basename (session_name);
2662 session_path = _startup->session_folder();
2664 if (session_name.find ('/') != string::npos) {
2665 MessageDialog msg (*_startup,
2666 _("To ensure compatibility with various systems\n"
2667 "session names may not contain a '/' character"));
2669 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2673 if (session_name.find ('\\') != string::npos) {
2674 MessageDialog msg (*_startup,
2675 _("To ensure compatibility with various systems\n"
2676 "session names may not contain a '\\' character"));
2678 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2684 if (create_engine ()) {
2688 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2692 std::string existing = Glib::build_filename (session_path, session_name);
2694 if (!ask_about_loading_existing_session (existing)) {
2695 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2700 _session_is_new = false;
2705 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2707 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2711 if (session_name.find ('/') != std::string::npos) {
2712 MessageDialog msg (*_startup,
2713 _("To ensure compatibility with various systems\n"
2714 "session names may not contain a '/' character"));
2716 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2720 if (session_name.find ('\\') != std::string::npos) {
2721 MessageDialog msg (*_startup,
2722 _("To ensure compatibility with various systems\n"
2723 "session names may not contain a '\\' character"));
2725 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2729 _session_is_new = true;
2732 if (likely_new && template_name.empty()) {
2734 ret = build_session_from_nsd (session_path, session_name);
2738 ret = load_session (session_path, session_name, template_name);
2741 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2745 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2746 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2756 ARDOUR_UI::close_session()
2758 if (!check_audioengine()) {
2762 if (unload_session (true)) {
2766 ARDOUR_COMMAND_LINE::session_name = "";
2768 if (get_session_parameters (true, false)) {
2772 goto_editor_window ();
2775 /** @param snap_name Snapshot name (without .ardour suffix).
2776 * @return -2 if the load failed because we are not connected to the AudioEngine.
2779 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2781 Session *new_session;
2785 session_loaded = false;
2787 if (!check_audioengine()) {
2791 unload_status = unload_session ();
2793 if (unload_status < 0) {
2795 } else if (unload_status > 0) {
2800 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2803 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2806 /* this one is special */
2808 catch (AudioEngine::PortRegistrationFailure& err) {
2810 MessageDialog msg (err.what(),
2813 Gtk::BUTTONS_CLOSE);
2815 msg.set_title (_("Port Registration Error"));
2816 msg.set_secondary_text (_("Click the Close button to try again."));
2817 msg.set_position (Gtk::WIN_POS_CENTER);
2821 int response = msg.run ();
2826 case RESPONSE_CANCEL:
2836 MessageDialog msg (string_compose(
2837 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2843 msg.set_title (_("Loading Error"));
2844 msg.set_secondary_text (_("Click the Refresh button to try again."));
2845 msg.add_button (Stock::REFRESH, 1);
2846 msg.set_position (Gtk::WIN_POS_CENTER);
2850 int response = msg.run ();
2865 list<string> const u = new_session->unknown_processors ();
2867 MissingPluginDialog d (_session, u);
2872 /* Now the session been created, add the transport controls */
2873 new_session->add_controllable(roll_controllable);
2874 new_session->add_controllable(stop_controllable);
2875 new_session->add_controllable(goto_start_controllable);
2876 new_session->add_controllable(goto_end_controllable);
2877 new_session->add_controllable(auto_loop_controllable);
2878 new_session->add_controllable(play_selection_controllable);
2879 new_session->add_controllable(rec_controllable);
2881 set_session (new_session);
2883 session_loaded = true;
2885 goto_editor_window ();
2888 _session->set_clean ();
2899 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2901 Session *new_session;
2904 if (!check_audioengine()) {
2908 session_loaded = false;
2910 x = unload_session ();
2918 _session_is_new = true;
2921 new_session = new Session (*engine, path, snap_name, &bus_profile);
2926 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2932 /* Give the new session the default GUI state, if such things exist */
2935 n = Config->instant_xml (X_("Editor"));
2937 new_session->add_instant_xml (*n, false);
2939 n = Config->instant_xml (X_("Mixer"));
2941 new_session->add_instant_xml (*n, false);
2944 /* Put the playhead at 0 and scroll fully left */
2945 n = new_session->instant_xml (X_("Editor"));
2947 n->add_property (X_("playhead"), X_("0"));
2948 n->add_property (X_("left-frame"), X_("0"));
2951 set_session (new_session);
2953 session_loaded = true;
2955 new_session->save_state(new_session->name());
2961 ARDOUR_UI::launch_chat ()
2964 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2966 open_uri("http://webchat.freenode.net/?channels=ardour");
2971 ARDOUR_UI::show_about ()
2975 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2978 about->set_transient_for(*editor);
2983 ARDOUR_UI::launch_manual ()
2985 PBD::open_uri("http://ardour.org/flossmanual");
2989 ARDOUR_UI::launch_reference ()
2991 PBD::open_uri("http://ardour.org/refmanual");
2995 ARDOUR_UI::hide_about ()
2998 about->get_window()->set_cursor ();
3004 ARDOUR_UI::about_signal_response (int /*response*/)
3010 ARDOUR_UI::show_splash ()
3014 splash = new Splash;
3022 splash->queue_draw ();
3023 splash->get_window()->process_updates (true);
3028 ARDOUR_UI::hide_splash ()
3036 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
3037 const string& plural_msg, const string& singular_msg)
3041 removed = rep.paths.size();
3044 MessageDialog msgd (*editor,
3045 _("No files were ready for clean-up"),
3048 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
3049 msgd.set_title (_("Clean-up"));
3050 msgd.set_secondary_text (_("If this seems suprising, \n\
3051 check for any existing snapshots.\n\
3052 These may still include regions that\n\
3053 require some unused files to continue to exist."));
3059 ArdourDialog results (_("Clean-up"), true, false);
3061 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3062 CleanupResultsModelColumns() {
3066 Gtk::TreeModelColumn<std::string> visible_name;
3067 Gtk::TreeModelColumn<std::string> fullpath;
3071 CleanupResultsModelColumns results_columns;
3072 Glib::RefPtr<Gtk::ListStore> results_model;
3073 Gtk::TreeView results_display;
3075 results_model = ListStore::create (results_columns);
3076 results_display.set_model (results_model);
3077 results_display.append_column (list_title, results_columns.visible_name);
3079 results_display.set_name ("CleanupResultsList");
3080 results_display.set_headers_visible (true);
3081 results_display.set_headers_clickable (false);
3082 results_display.set_reorderable (false);
3084 Gtk::ScrolledWindow list_scroller;
3087 Gtk::HBox dhbox; // the hbox for the image and text
3088 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3089 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3091 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3093 const string dead_directory = _session->session_directory().dead_path().to_string();
3096 %1 - number of files removed
3097 %2 - location of "dead"
3098 %3 - size of files affected
3099 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3102 const char* bprefix;
3103 double space_adjusted = 0;
3105 if (rep.space < 1000) {
3107 space_adjusted = rep.space;
3108 } else if (rep.space < 1000000) {
3109 bprefix = X_("kilo");
3110 space_adjusted = truncf((float)rep.space / 1000.0);
3111 } else if (rep.space < 1000000 * 1000) {
3112 bprefix = X_("mega");
3113 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3115 bprefix = X_("giga");
3116 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3120 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3122 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3125 dhbox.pack_start (*dimage, true, false, 5);
3126 dhbox.pack_start (txt, true, false, 5);
3128 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3129 TreeModel::Row row = *(results_model->append());
3130 row[results_columns.visible_name] = *i;
3131 row[results_columns.fullpath] = *i;
3134 list_scroller.add (results_display);
3135 list_scroller.set_size_request (-1, 150);
3136 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3138 dvbox.pack_start (dhbox, true, false, 5);
3139 dvbox.pack_start (list_scroller, true, false, 5);
3140 ddhbox.pack_start (dvbox, true, false, 5);
3142 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3143 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3144 results.set_default_response (RESPONSE_CLOSE);
3145 results.set_position (Gtk::WIN_POS_MOUSE);
3147 results_display.show();
3148 list_scroller.show();
3155 //results.get_vbox()->show();
3156 results.set_resizable (false);
3163 ARDOUR_UI::cleanup ()
3165 if (_session == 0) {
3166 /* shouldn't happen: menu item is insensitive */
3171 MessageDialog checker (_("Are you sure you want to clean-up?"),
3173 Gtk::MESSAGE_QUESTION,
3174 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3176 checker.set_title (_("Clean-up"));
3178 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3179 ALL undo/redo information will be lost if you clean-up.\n\
3180 Clean-up will move all unused files to a \"dead\" location."));
3182 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3183 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3184 checker.set_default_response (RESPONSE_CANCEL);
3186 checker.set_name (_("CleanupDialog"));
3187 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3188 checker.set_position (Gtk::WIN_POS_MOUSE);
3190 switch (checker.run()) {
3191 case RESPONSE_ACCEPT:
3197 ARDOUR::CleanupReport rep;
3199 editor->prepare_for_cleanup ();
3201 /* do not allow flush until a session is reloaded */
3203 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3205 act->set_sensitive (false);
3208 if (_session->cleanup_sources (rep)) {
3209 editor->finish_cleanup ();
3213 editor->finish_cleanup ();
3216 display_cleanup_results (rep,
3219 The following %1 files were not in use and \n\
3220 have been moved to:\n\n\
3222 After a restart of Ardour,\n\n\
3223 Session -> Clean-up -> Flush Wastebasket\n\n\
3224 will release an additional\n\
3225 %3 %4bytes of disk space.\n"),
3227 The following file was not in use and \n\
3228 has been moved to:\n \
3230 After a restart of Ardour,\n\n\
3231 Session -> Clean-up -> Flush Wastebasket\n\n\
3232 will release an additional\n\
3233 %3 %4bytes of disk space.\n"
3239 ARDOUR_UI::flush_trash ()
3241 if (_session == 0) {
3242 /* shouldn't happen: menu item is insensitive */
3246 ARDOUR::CleanupReport rep;
3248 if (_session->cleanup_trash_sources (rep)) {
3252 display_cleanup_results (rep,
3254 _("The following %1 files were deleted from\n\
3256 releasing %3 %4bytes of disk space"),
3257 _("The following file was deleted from\n\
3259 releasing %3 %4bytes of disk space"));
3263 ARDOUR_UI::add_route (Gtk::Window* float_window)
3271 if (add_route_dialog == 0) {
3272 add_route_dialog = new AddRouteDialog (_session);
3274 add_route_dialog->set_transient_for (*float_window);
3278 if (add_route_dialog->is_visible()) {
3279 /* we're already doing this */
3283 ResponseType r = (ResponseType) add_route_dialog->run ();
3285 add_route_dialog->hide();
3288 case RESPONSE_ACCEPT:
3295 if ((count = add_route_dialog->count()) <= 0) {
3299 string template_path = add_route_dialog->track_template();
3301 if (!template_path.empty()) {
3302 _session->new_route_from_template (count, template_path);
3306 uint32_t input_chan = add_route_dialog->channels ();
3307 uint32_t output_chan;
3308 string name_template = add_route_dialog->name_template ();
3309 bool track = add_route_dialog->track ();
3310 RouteGroup* route_group = add_route_dialog->route_group ();
3312 AutoConnectOption oac = Config->get_output_auto_connect();
3314 if (oac & AutoConnectMaster) {
3315 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3317 output_chan = input_chan;
3320 /* XXX do something with name template */
3322 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3324 session_add_midi_track (route_group, count, name_template);
3326 MessageDialog msg (*editor,
3327 _("Sorry, MIDI Busses are not supported at this time."));
3329 //session_add_midi_bus();
3333 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3335 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3341 ARDOUR_UI::mixer_settings () const
3346 node = _session->instant_xml(X_("Mixer"));
3348 node = Config->instant_xml(X_("Mixer"));
3352 node = new XMLNode (X_("Mixer"));
3359 ARDOUR_UI::editor_settings () const
3364 node = _session->instant_xml(X_("Editor"));
3366 node = Config->instant_xml(X_("Editor"));
3370 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3371 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3376 node = new XMLNode (X_("Editor"));
3383 ARDOUR_UI::keyboard_settings () const
3387 node = Config->extra_xml(X_("Keyboard"));
3390 node = new XMLNode (X_("Keyboard"));
3397 ARDOUR_UI::create_xrun_marker (framepos_t where)
3399 editor->mouse_add_new_marker (where, false, true);
3403 ARDOUR_UI::halt_on_xrun_message ()
3405 MessageDialog msg (*editor,
3406 _("Recording was stopped because your system could not keep up."));
3411 ARDOUR_UI::xrun_handler (framepos_t where)
3417 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3419 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3420 create_xrun_marker(where);
3423 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3424 halt_on_xrun_message ();
3429 ARDOUR_UI::disk_overrun_handler ()
3431 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3433 if (!have_disk_speed_dialog_displayed) {
3434 have_disk_speed_dialog_displayed = true;
3435 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3436 The disk system on your computer\n\
3437 was not able to keep up with %1.\n\
3439 Specifically, it failed to write data to disk\n\
3440 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3441 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3447 ARDOUR_UI::disk_underrun_handler ()
3449 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3451 if (!have_disk_speed_dialog_displayed) {
3452 have_disk_speed_dialog_displayed = true;
3453 MessageDialog* msg = new MessageDialog (
3454 *editor, string_compose (_("The disk system on your computer\n\
3455 was not able to keep up with %1.\n\
3457 Specifically, it failed to read data from disk\n\
3458 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3459 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3465 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3467 have_disk_speed_dialog_displayed = false;
3472 ARDOUR_UI::session_dialog (std::string msg)
3474 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3479 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3481 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3490 ARDOUR_UI::pending_state_dialog ()
3492 HBox* hbox = new HBox();
3493 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3494 ArdourDialog dialog (_("Crash Recovery"), true);
3496 This session appears to have been in\n\
3497 middle of recording when ardour or\n\
3498 the computer was shutdown.\n\
3500 Ardour can recover any captured audio for\n\
3501 you, or it can ignore it. Please decide\n\
3502 what you would like to do.\n"));
3503 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3504 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3505 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3506 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3507 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3508 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3509 dialog.set_default_response (RESPONSE_ACCEPT);
3510 dialog.set_position (WIN_POS_CENTER);
3515 switch (dialog.run ()) {
3516 case RESPONSE_ACCEPT:
3524 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3526 HBox* hbox = new HBox();
3527 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3528 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3529 Label message (string_compose (_("\
3530 This session was created with a sample rate of %1 Hz\n\
3532 The audioengine is currently running at %2 Hz\n"), desired, actual));
3534 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3535 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3536 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3537 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3538 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3539 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3540 dialog.set_default_response (RESPONSE_ACCEPT);
3541 dialog.set_position (WIN_POS_CENTER);
3546 switch (dialog.run ()) {
3547 case RESPONSE_ACCEPT:
3556 ARDOUR_UI::disconnect_from_jack ()
3559 if( engine->disconnect_from_jack ()) {
3560 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3564 update_sample_rate (0);
3569 ARDOUR_UI::reconnect_to_jack ()
3572 if (engine->reconnect_to_jack ()) {
3573 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3577 update_sample_rate (0);
3582 ARDOUR_UI::use_config ()
3584 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3586 set_transport_controllable_state (*node);
3591 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3593 if (Config->get_primary_clock_delta_edit_cursor()) {
3594 primary_clock->set (pos, false, editor->get_preferred_edit_position(), 1);
3596 primary_clock->set (pos, 0, true);
3599 if (Config->get_secondary_clock_delta_edit_cursor()) {
3600 secondary_clock->set (pos, false, editor->get_preferred_edit_position(), 2);
3602 secondary_clock->set (pos);
3605 if (big_clock_window->get()) {
3606 big_clock->set (pos);
3612 ARDOUR_UI::step_edit_status_change (bool yn)
3614 // XXX should really store pre-step edit status of things
3615 // we make insensitive
3618 rec_button.set_active_state (Mid);
3619 rec_button.set_sensitive (false);
3621 rec_button.unset_active_state ();;
3622 rec_button.set_sensitive (true);
3627 ARDOUR_UI::record_state_changed ()
3629 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3631 if (!_session || !big_clock_window->get()) {
3632 /* why bother - the clock isn't visible */
3636 Session::RecordState const r = _session->record_status ();
3637 bool const h = _session->have_rec_enabled_track ();
3639 if (r == Session::Recording && h) {
3640 big_clock->set_widget_name ("BigClockRecording");
3642 big_clock->set_widget_name ("BigClockNonRecording");
3647 ARDOUR_UI::first_idle ()
3650 _session->allow_auto_play (true);
3654 editor->first_idle();
3657 Keyboard::set_can_save_keybindings (true);
3662 ARDOUR_UI::store_clock_modes ()
3664 XMLNode* node = new XMLNode(X_("ClockModes"));
3666 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3667 XMLNode* child = new XMLNode (X_("Clock"));
3669 child->add_property (X_("name"), (*x)->name());
3670 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3671 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3673 node->add_child_nocopy (*child);
3676 _session->add_extra_xml (*node);
3677 _session->set_dirty ();
3680 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3681 : Controllable (name), ui (u), type(tp)
3687 ARDOUR_UI::TransportControllable::set_value (double val)
3690 /* do nothing: these are radio-style actions */
3694 const char *action = 0;
3698 action = X_("Roll");
3701 action = X_("Stop");
3704 action = X_("Goto Start");
3707 action = X_("Goto End");
3710 action = X_("Loop");
3713 action = X_("Play Selection");
3716 action = X_("Record");
3726 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3734 ARDOUR_UI::TransportControllable::get_value (void) const
3761 ARDOUR_UI::setup_profile ()
3763 if (gdk_screen_width() < 1200) {
3764 Profile->set_small_screen ();
3768 if (getenv ("ARDOUR_SAE")) {
3769 Profile->set_sae ();
3770 Profile->set_single_package ();
3775 ARDOUR_UI::toggle_translations ()
3777 using namespace Glib;
3779 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3781 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3784 string i18n_killer = ARDOUR::translation_kill_path();
3786 bool already_enabled = !ARDOUR::translations_are_disabled ();
3788 if (ract->get_active ()) {
3789 /* we don't care about errors */
3790 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3793 /* we don't care about errors */
3794 unlink (i18n_killer.c_str());
3797 if (already_enabled != ract->get_active()) {
3798 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3800 Gtk::MESSAGE_WARNING,
3802 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3803 win.set_position (Gtk::WIN_POS_CENTER);
3811 /** Add a window proxy to our list, so that its state will be saved.
3812 * This call also causes the window to be created and opened if its
3813 * state was saved as `visible'.
3816 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3818 _window_proxies.push_back (p);
3822 /** Remove a window proxy from our list. Must be called if a WindowProxy
3823 * is deleted, to prevent hanging pointers.
3826 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3828 _window_proxies.remove (p);
3832 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3834 MissingFileDialog dialog (s, str, type);
3839 int result = dialog.run ();
3846 return 1; // quit entire session load
3849 result = dialog.get_action ();
3855 ARDOUR_UI::ambiguous_file (std::string file, std::string /*path*/, std::vector<std::string> hits)
3857 AmbiguousFileDialog dialog (file, hits);
3863 return dialog.get_which ();
3866 /** Allocate our thread-local buffers */
3868 ARDOUR_UI::get_process_buffers ()
3870 _process_thread->get_buffers ();
3873 /** Drop our thread-local buffers */
3875 ARDOUR_UI::drop_process_buffers ()
3877 _process_thread->drop_buffers ();
3881 ARDOUR_UI::feedback_detected ()
3884 _("Something you have just done has generated a feedback path within Ardour's "
3885 "routing. Until this feedback is removed, Ardour's output will be as it was "
3886 "before you made the feedback-generating connection.")
3893 ARDOUR_UI::midi_panic ()
3896 _session->midi_panic();