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"
82 typedef uint64_t microseconds_t;
86 #include "add_route_dialog.h"
87 #include "ambiguous_file_dialog.h"
88 #include "ardour_ui.h"
89 #include "audio_clock.h"
90 #include "bundle_manager.h"
91 #include "engine_dialog.h"
92 #include "gain_meter.h"
93 #include "global_port_matrix.h"
94 #include "gui_object.h"
95 #include "gui_thread.h"
97 #include "location_ui.h"
98 #include "missing_file_dialog.h"
99 #include "missing_plugin_dialog.h"
100 #include "mixer_ui.h"
102 #include "processor_box.h"
103 #include "prompter.h"
104 #include "public_editor.h"
105 #include "route_time_axis.h"
106 #include "session_metadata_dialog.h"
107 #include "shuttle_control.h"
108 #include "speaker_dialog.h"
111 #include "theme_manager.h"
112 #include "time_axis_view_item.h"
114 #include "window_proxy.h"
118 using namespace ARDOUR;
120 using namespace Gtkmm2ext;
123 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
124 UIConfiguration *ARDOUR_UI::ui_config = 0;
126 sigc::signal<void,bool> ARDOUR_UI::Blink;
127 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
128 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
129 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
131 bool could_be_a_valid_path (const string& path);
133 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
135 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
137 , gui_object_state (new GUIObjectState)
138 , primary_clock (new AudioClock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true))
139 , secondary_clock (new AudioClock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true))
140 , preroll_clock (new AudioClock (X_("preroll"), false, X_("PreRollClock"), true, false, true))
141 , postroll_clock (new AudioClock (X_("postroll"), false, X_("PostRollClock"), true, false, true))
145 , preroll_button (_("pre\nroll"))
146 , postroll_button (_("post\nroll"))
150 , big_clock (new AudioClock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false))
154 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
155 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
156 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
157 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
158 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
159 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
160 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
162 , roll_button (roll_controllable)
163 , stop_button (stop_controllable)
164 , goto_start_button (goto_start_controllable)
165 , goto_end_button (goto_end_controllable)
166 , auto_loop_button (auto_loop_controllable)
167 , play_selection_button (play_selection_controllable)
168 , rec_button (rec_controllable)
170 , auto_return_button (_("Auto Return"))
171 , auto_play_button (_("Auto Play"))
172 , auto_input_button (_("Auto Input"))
173 // , click_button (_("Click"))
174 , time_master_button (_("time\nmaster"))
176 , auditioning_alert_button (_("AUDITION"))
177 , solo_alert_button (_("SOLO"))
179 , error_log_button (_("Errors"))
182 using namespace Gtk::Menu_Helpers;
188 // _auto_display_errors = false;
190 * This was commented out as it wasn't defined
191 * in A3 IIRC. If this is not needed it should
192 * be completely removed.
200 if (theArdourUI == 0) {
204 ui_config = new UIConfiguration();
205 theme_manager = new ThemeManager();
213 _session_is_new = false;
214 big_clock_window = 0;
215 big_clock_height = 0;
216 big_clock_resize_in_progress = false;
217 session_selector_window = 0;
218 last_key_press_time = 0;
219 _will_create_new_session_automatically = false;
220 add_route_dialog = 0;
223 rc_option_editor = 0;
224 session_option_editor = 0;
226 open_session_selector = 0;
227 have_configure_timeout = false;
228 have_disk_speed_dialog_displayed = false;
229 session_loaded = false;
230 ignore_dual_punch = false;
231 original_big_clock_width = -1;
232 original_big_clock_height = -1;
233 original_big_clock_font_size = 0;
235 roll_button.unset_flags (Gtk::CAN_FOCUS);
236 stop_button.unset_flags (Gtk::CAN_FOCUS);
237 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
238 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
239 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
240 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
241 rec_button.unset_flags (Gtk::CAN_FOCUS);
242 join_play_range_button.unset_flags (Gtk::CAN_FOCUS);
243 last_configure_time= 0;
246 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
247 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
249 /* handle dialog requests */
251 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
253 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
255 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
257 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
259 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
261 /* handle requests to quit (coming from JACK session) */
263 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
265 /* handle requests to deal with missing files */
267 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
269 /* and ambiguous files */
271 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
273 /* lets get this party started */
276 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
277 throw failed_constructor ();
280 setup_gtk_ardour_enums ();
283 GainMeter::setup_slider_pix ();
284 RouteTimeAxisView::setup_slider_pix ();
285 SendProcessorEntry::setup_slider_pix ();
286 SessionEvent::create_per_thread_pool ("GUI", 512);
288 } catch (failed_constructor& err) {
289 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
294 /* we like keyboards */
296 keyboard = new ArdourKeyboard(*this);
298 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
300 keyboard->set_state (*node, Stateful::loading_state_version);
303 /* we don't like certain modifiers */
304 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
308 TimeAxisViewItem::set_constant_heights ();
310 /* The following must happen after ARDOUR::init() so that Config is set up */
312 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
313 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
314 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
316 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
317 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
318 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
319 Config->extra_xml (X_("UI")),
320 string_compose ("toggle-%1-connection-manager", (*i).to_string())
326 SpeakerDialog* s = new SpeakerDialog ();
327 s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
328 speaker_config_window->set (s);
330 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
331 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
334 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
336 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
339 _startup = new ArdourStartup ();
341 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
343 if (audio_setup && _startup->engine_control()) {
344 _startup->engine_control()->set_state (*audio_setup);
347 _startup->set_new_only (should_be_new);
348 if (!load_template.empty()) {
349 _startup->set_load_template( load_template );
351 _startup->present ();
357 switch (_startup->response()) {
366 ARDOUR_UI::create_engine ()
368 // this gets called every time by new_session()
374 loading_message (_("Starting audio engine"));
377 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
384 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
385 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
386 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
388 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
390 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
398 ARDOUR_UI::post_engine ()
400 /* Things to be done once we create the AudioEngine
403 ARDOUR::init_post_engine ();
405 ActionManager::init ();
408 if (setup_windows ()) {
409 throw failed_constructor ();
412 check_memory_locking();
414 /* this is the first point at which all the keybindings are available */
416 if (ARDOUR_COMMAND_LINE::show_key_actions) {
417 vector<string> names;
418 vector<string> paths;
419 vector<string> tooltips;
421 vector<AccelKey> bindings;
423 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
425 vector<string>::iterator n;
426 vector<string>::iterator k;
427 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
428 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
434 blink_timeout_tag = -1;
436 /* this being a GUI and all, we want peakfiles */
438 AudioFileSource::set_build_peakfiles (true);
439 AudioFileSource::set_build_missing_peakfiles (true);
441 /* set default clock modes */
443 if (Profile->get_sae()) {
444 primary_clock->set_mode (AudioClock::BBT);
445 secondary_clock->set_mode (AudioClock::MinSec);
447 primary_clock->set_mode (AudioClock::Timecode);
448 secondary_clock->set_mode (AudioClock::BBT);
451 /* start the time-of-day-clock */
454 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
455 update_wall_clock ();
456 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
459 update_disk_space ();
461 update_sample_rate (engine->frame_rate());
463 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
464 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
465 Config->map_parameters (pc);
467 /* now start and maybe save state */
469 if (do_engine_start () == 0) {
470 if (_session && _session_is_new) {
471 /* we need to retain initial visual
472 settings for a new session
474 _session->save_state ("");
479 ARDOUR_UI::~ARDOUR_UI ()
484 delete add_route_dialog;
488 ARDOUR_UI::pop_back_splash ()
490 if (Splash::instance()) {
491 // Splash::instance()->pop_back();
492 Splash::instance()->hide ();
497 ARDOUR_UI::configure_timeout ()
499 if (last_configure_time == 0) {
500 /* no configure events yet */
504 /* force a gap of 0.5 seconds since the last configure event
507 if (get_microseconds() - last_configure_time < 500000) {
510 have_configure_timeout = false;
511 cerr << "config event-driven save\n";
512 save_ardour_state ();
518 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
520 if (have_configure_timeout) {
521 last_configure_time = get_microseconds();
523 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
524 have_configure_timeout = true;
531 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
533 const XMLProperty* prop;
535 if ((prop = node.property ("roll")) != 0) {
536 roll_controllable->set_id (prop->value());
538 if ((prop = node.property ("stop")) != 0) {
539 stop_controllable->set_id (prop->value());
541 if ((prop = node.property ("goto-start")) != 0) {
542 goto_start_controllable->set_id (prop->value());
544 if ((prop = node.property ("goto-end")) != 0) {
545 goto_end_controllable->set_id (prop->value());
547 if ((prop = node.property ("auto-loop")) != 0) {
548 auto_loop_controllable->set_id (prop->value());
550 if ((prop = node.property ("play-selection")) != 0) {
551 play_selection_controllable->set_id (prop->value());
553 if ((prop = node.property ("rec")) != 0) {
554 rec_controllable->set_id (prop->value());
556 if ((prop = node.property ("shuttle")) != 0) {
557 shuttle_box->controllable()->set_id (prop->value());
563 ARDOUR_UI::get_transport_controllable_state ()
565 XMLNode* node = new XMLNode(X_("TransportControllables"));
568 roll_controllable->id().print (buf, sizeof (buf));
569 node->add_property (X_("roll"), buf);
570 stop_controllable->id().print (buf, sizeof (buf));
571 node->add_property (X_("stop"), buf);
572 goto_start_controllable->id().print (buf, sizeof (buf));
573 node->add_property (X_("goto_start"), buf);
574 goto_end_controllable->id().print (buf, sizeof (buf));
575 node->add_property (X_("goto_end"), buf);
576 auto_loop_controllable->id().print (buf, sizeof (buf));
577 node->add_property (X_("auto_loop"), buf);
578 play_selection_controllable->id().print (buf, sizeof (buf));
579 node->add_property (X_("play_selection"), buf);
580 rec_controllable->id().print (buf, sizeof (buf));
581 node->add_property (X_("rec"), buf);
582 shuttle_box->controllable()->id().print (buf, sizeof (buf));
583 node->add_property (X_("shuttle"), buf);
590 ARDOUR_UI::autosave_session ()
592 if (g_main_depth() > 1) {
593 /* inside a recursive main loop,
594 give up because we may not be able to
600 if (!Config->get_periodic_safety_backups()) {
605 _session->maybe_write_autosave();
612 ARDOUR_UI::update_autosave ()
614 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
616 if (_session && _session->dirty()) {
617 if (_autosave_connection.connected()) {
618 _autosave_connection.disconnect();
621 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
622 Config->get_periodic_safety_backup_interval() * 1000);
625 if (_autosave_connection.connected()) {
626 _autosave_connection.disconnect();
632 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
636 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
638 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
641 MessageDialog win (title,
647 win.set_secondary_text(_("There are several possible reasons:\n\
649 1) You requested audio parameters that are not supported..\n\
650 2) JACK is running as another user.\n\
652 Please consider the possibilities, and perhaps try different parameters."));
654 win.set_secondary_text(_("There are several possible reasons:\n\
656 1) JACK is not running.\n\
657 2) JACK is running as another user, perhaps root.\n\
658 3) There is already another client called \"ardour\".\n\
660 Please consider the possibilities, and perhaps (re)start JACK."));
664 win.set_transient_for (*toplevel);
668 win.add_button (Stock::OK, RESPONSE_CLOSE);
670 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
673 win.set_default_response (RESPONSE_CLOSE);
676 win.set_position (Gtk::WIN_POS_CENTER);
679 /* we just don't care about the result, but we want to block */
685 ARDOUR_UI::startup ()
687 Application* app = Application::instance ();
689 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
690 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
693 call_the_mothership (VERSIONSTRING);
698 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
704 goto_editor_window ();
706 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
707 to be opened on top of the editor window that goto_editor_window() just opened.
709 add_window_proxy (location_ui);
710 add_window_proxy (big_clock_window);
711 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
712 add_window_proxy (_global_port_matrix[*i]);
715 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
719 ARDOUR_UI::no_memory_warning ()
721 XMLNode node (X_("no-memory-warning"));
722 Config->add_instant_xml (node);
726 ARDOUR_UI::check_memory_locking ()
729 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
733 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
735 if (engine->is_realtime() && memory_warning_node == 0) {
737 struct rlimit limits;
739 long pages, page_size;
741 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
744 ram = (int64_t) pages * (int64_t) page_size;
747 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
751 if (limits.rlim_cur != RLIM_INFINITY) {
753 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
757 _("WARNING: Your system has a limit for maximum amount of locked memory. "
758 "This might cause %1 to run out of memory before your system "
759 "runs out of memory. \n\n"
760 "You can view the memory limit with 'ulimit -l', "
761 "and it is normally controlled by /etc/security/limits.conf"),
762 PROGRAM_NAME).c_str());
764 VBox* vbox = msg.get_vbox();
766 CheckButton cb (_("Do not show this window again"));
768 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
770 hbox.pack_start (cb, true, false);
771 vbox->pack_start (hbox);
778 editor->ensure_float (msg);
788 ARDOUR_UI::queue_finish ()
790 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
794 ARDOUR_UI::idle_finish ()
797 return false; /* do not call again */
806 if (_session->transport_rolling() && (++tries < 8)) {
807 _session->request_stop (false, true);
811 if (_session->dirty()) {
812 vector<string> actions;
813 actions.push_back (_("Don't quit"));
814 actions.push_back (_("Just quit"));
815 actions.push_back (_("Save and quit"));
816 switch (ask_about_saving_session(actions)) {
821 /* use the default name */
822 if (save_state_canfail ("")) {
823 /* failed - don't quit */
824 MessageDialog msg (*editor,
826 Ardour was unable to save your session.\n\n\
827 If you still wish to quit, please use the\n\n\
828 \"Just quit\" option."));
839 second_connection.disconnect ();
840 point_one_second_connection.disconnect ();
841 point_oh_five_second_connection.disconnect ();
842 point_zero_one_second_connection.disconnect();
845 /* Save state before deleting the session, as that causes some
846 windows to be destroyed before their visible state can be
849 save_ardour_state ();
852 // _session->set_deletion_in_progress ();
853 _session->set_clean ();
854 _session->remove_pending_capture_state ();
859 ArdourDialog::close_all_dialogs ();
865 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
867 ArdourDialog window (_("Unsaved Session"));
868 Gtk::HBox dhbox; // the hbox for the image and text
869 Gtk::Label prompt_label;
870 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
874 assert (actions.size() >= 3);
876 window.add_button (actions[0], RESPONSE_REJECT);
877 window.add_button (actions[1], RESPONSE_APPLY);
878 window.add_button (actions[2], RESPONSE_ACCEPT);
880 window.set_default_response (RESPONSE_ACCEPT);
882 Gtk::Button noquit_button (msg);
883 noquit_button.set_name ("EditorGTKButton");
887 if (_session->snap_name() == _session->name()) {
888 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?"),
889 _session->snap_name());
891 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?"),
892 _session->snap_name());
895 prompt_label.set_text (prompt);
896 prompt_label.set_name (X_("PrompterLabel"));
897 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
899 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
900 dhbox.set_homogeneous (false);
901 dhbox.pack_start (*dimage, false, false, 5);
902 dhbox.pack_start (prompt_label, true, false, 5);
903 window.get_vbox()->pack_start (dhbox);
905 window.set_name (_("Prompter"));
906 window.set_position (Gtk::WIN_POS_MOUSE);
907 window.set_modal (true);
908 window.set_resizable (false);
914 window.set_keep_above (true);
917 ResponseType r = (ResponseType) window.run();
922 case RESPONSE_ACCEPT: // save and get out of here
924 case RESPONSE_APPLY: // get out of here
934 ARDOUR_UI::every_second ()
937 update_buffer_load ();
938 update_disk_space ();
943 ARDOUR_UI::every_point_one_seconds ()
945 shuttle_box->update_speed_display ();
946 RapidScreenUpdate(); /* EMIT_SIGNAL */
951 ARDOUR_UI::every_point_zero_one_seconds ()
953 // august 2007: actual update frequency: 40Hz, not 100Hz
955 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
960 ARDOUR_UI::update_sample_rate (framecnt_t)
964 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
966 if (!engine->connected()) {
968 snprintf (buf, sizeof (buf), _("disconnected"));
972 framecnt_t rate = engine->frame_rate();
974 if (fmod (rate, 1000.0) != 0.0) {
975 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
976 (float) rate/1000.0f,
977 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
979 snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"),
981 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
985 sample_rate_label.set_text (buf);
989 ARDOUR_UI::update_format ()
992 format_label.set_text ("");
998 switch (_session->config.get_native_file_header_format ()) {
1024 switch (_session->config.get_native_file_data_format ()) {
1036 format_label.set_text (s.str ());
1040 ARDOUR_UI::update_cpu_load ()
1043 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
1044 cpu_load_label.set_text (buf);
1048 ARDOUR_UI::update_buffer_load ()
1053 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
1054 _session->playback_load(), _session->capture_load());
1055 buffer_load_label.set_text (buf);
1057 buffer_load_label.set_text ("");
1062 ARDOUR_UI::count_recenabled_streams (Route& route)
1064 Track* track = dynamic_cast<Track*>(&route);
1065 if (track && track->record_enabled()) {
1066 rec_enabled_streams += track->n_inputs().n_total();
1071 ARDOUR_UI::update_disk_space()
1073 if (_session == 0) {
1077 framecnt_t frames = _session->available_capture_duration();
1079 framecnt_t fr = _session->frame_rate();
1081 if (frames == max_framecnt) {
1082 strcpy (buf, _("Disk: 24hrs+"));
1084 rec_enabled_streams = 0;
1085 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1087 if (rec_enabled_streams) {
1088 frames /= rec_enabled_streams;
1095 hrs = frames / (fr * 3600);
1096 frames -= hrs * fr * 3600;
1097 mins = frames / (fr * 60);
1098 frames -= mins * fr * 60;
1101 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1104 disk_space_label.set_text (buf);
1106 // An attempt to make the disk space label flash red when space has run out.
1108 if (frames < fr * 60 * 5) {
1109 /* disk_space_box.style ("disk_space_label_empty"); */
1111 /* disk_space_box.style ("disk_space_label"); */
1117 ARDOUR_UI::update_wall_clock ()
1124 tm_now = localtime (&now);
1126 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1127 wall_clock_label.set_text (buf);
1133 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1135 session_popup_menu->popup (0, 0);
1140 ARDOUR_UI::redisplay_recent_sessions ()
1142 std::vector<sys::path> session_directories;
1143 RecentSessionsSorter cmp;
1145 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1146 recent_session_model->clear ();
1148 ARDOUR::RecentSessions rs;
1149 ARDOUR::read_recent_sessions (rs);
1152 recent_session_display.set_model (recent_session_model);
1156 // sort them alphabetically
1157 sort (rs.begin(), rs.end(), cmp);
1159 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1160 session_directories.push_back ((*i).second);
1163 for (vector<sys::path>::const_iterator i = session_directories.begin();
1164 i != session_directories.end(); ++i)
1166 std::vector<sys::path> state_file_paths;
1168 // now get available states for this session
1170 get_state_files_in_directory (*i, state_file_paths);
1172 vector<string*>* states;
1173 vector<const gchar*> item;
1174 string fullpath = (*i).to_string();
1176 /* remove any trailing / */
1178 if (fullpath[fullpath.length()-1] == '/') {
1179 fullpath = fullpath.substr (0, fullpath.length()-1);
1182 /* check whether session still exists */
1183 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1184 /* session doesn't exist */
1185 cerr << "skipping non-existent session " << fullpath << endl;
1189 /* now get available states for this session */
1191 if ((states = Session::possible_states (fullpath)) == 0) {
1192 /* no state file? */
1196 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1198 Gtk::TreeModel::Row row = *(recent_session_model->append());
1200 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1201 row[recent_session_columns.fullpath] = fullpath;
1203 if (state_file_names.size() > 1) {
1207 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1208 i2 != state_file_names.end(); ++i2)
1211 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1213 child_row[recent_session_columns.visible_name] = *i2;
1214 child_row[recent_session_columns.fullpath] = fullpath;
1219 recent_session_display.set_model (recent_session_model);
1223 ARDOUR_UI::build_session_selector ()
1225 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1227 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1229 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1230 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1231 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1232 recent_session_model = TreeStore::create (recent_session_columns);
1233 recent_session_display.set_model (recent_session_model);
1234 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1235 recent_session_display.set_headers_visible (false);
1236 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1237 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1239 scroller->add (recent_session_display);
1240 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1242 session_selector_window->set_name ("SessionSelectorWindow");
1243 session_selector_window->set_size_request (200, 400);
1244 session_selector_window->get_vbox()->pack_start (*scroller);
1246 recent_session_display.show();
1248 //session_selector_window->get_vbox()->show();
1252 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1254 session_selector_window->response (RESPONSE_ACCEPT);
1258 ARDOUR_UI::open_recent_session ()
1260 bool can_return = (_session != 0);
1262 if (session_selector_window == 0) {
1263 build_session_selector ();
1266 redisplay_recent_sessions ();
1270 session_selector_window->set_position (WIN_POS_MOUSE);
1272 ResponseType r = (ResponseType) session_selector_window->run ();
1275 case RESPONSE_ACCEPT:
1279 session_selector_window->hide();
1286 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1290 session_selector_window->hide();
1292 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1294 if (i == recent_session_model->children().end()) {
1298 std::string path = (*i)[recent_session_columns.fullpath];
1299 std::string state = (*i)[recent_session_columns.visible_name];
1301 _session_is_new = false;
1303 if (load_session (path, state) == 0) {
1312 ARDOUR_UI::check_audioengine ()
1315 if (!engine->connected()) {
1316 MessageDialog msg (string_compose (
1317 _("%1 is not connected to JACK\n"
1318 "You cannot open or close sessions in this condition"),
1331 ARDOUR_UI::open_session ()
1333 if (!check_audioengine()) {
1338 /* popup selector window */
1340 if (open_session_selector == 0) {
1342 /* ardour sessions are folders */
1344 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1345 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1346 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1347 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1349 FileFilter session_filter;
1350 session_filter.add_pattern ("*.ardour");
1351 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1352 open_session_selector->add_filter (session_filter);
1353 open_session_selector->set_filter (session_filter);
1356 int response = open_session_selector->run();
1357 open_session_selector->hide ();
1360 case RESPONSE_ACCEPT:
1363 open_session_selector->hide();
1367 open_session_selector->hide();
1368 string session_path = open_session_selector->get_filename();
1372 if (session_path.length() > 0) {
1373 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1374 _session_is_new = isnew;
1375 load_session (path, name);
1382 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1384 list<boost::shared_ptr<MidiTrack> > tracks;
1386 if (_session == 0) {
1387 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1394 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1396 if (tracks.size() != how_many) {
1397 if (how_many == 1) {
1398 error << _("could not create a new midi track") << endmsg;
1400 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1404 if ((route = _session->new_midi_route ()) == 0) {
1405 error << _("could not create new midi bus") << endmsg;
1411 MessageDialog msg (*editor,
1412 string_compose (_("There are insufficient JACK ports available\n\
1413 to create a new track or bus.\n\
1414 You should save %1, exit and\n\
1415 restart JACK with more ports."), PROGRAM_NAME));
1422 ARDOUR_UI::session_add_audio_route (
1424 int32_t input_channels,
1425 int32_t output_channels,
1426 ARDOUR::TrackMode mode,
1427 RouteGroup* route_group,
1429 string const & name_template
1432 list<boost::shared_ptr<AudioTrack> > tracks;
1435 if (_session == 0) {
1436 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1442 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1444 if (tracks.size() != how_many) {
1445 if (how_many == 1) {
1446 error << _("could not create a new audio track") << endmsg;
1448 error << string_compose (_("could only create %1 of %2 new audio %3"),
1449 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1455 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1457 if (routes.size() != how_many) {
1458 if (how_many == 1) {
1459 error << _("could not create a new audio bus") << endmsg;
1461 error << string_compose (_("could not create %1 new audio busses"), how_many) << endmsg;
1468 MessageDialog msg (*editor,
1469 string_compose (_("There are insufficient JACK ports available\n\
1470 to create a new track or bus.\n\
1471 You should save %1, exit and\n\
1472 restart JACK with more ports."), PROGRAM_NAME));
1479 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1481 framecnt_t _preroll = 0;
1484 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1485 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1487 if (new_position > _preroll) {
1488 new_position -= _preroll;
1493 _session->request_locate (new_position, with_roll);
1498 ARDOUR_UI::transport_goto_start ()
1501 _session->goto_start();
1503 /* force displayed area in editor to start no matter
1504 what "follow playhead" setting is.
1508 editor->center_screen (_session->current_start_frame ());
1514 ARDOUR_UI::transport_goto_zero ()
1517 _session->request_locate (0);
1519 /* force displayed area in editor to start no matter
1520 what "follow playhead" setting is.
1524 editor->reset_x_origin (0);
1530 ARDOUR_UI::transport_goto_wallclock ()
1532 if (_session && editor) {
1539 localtime_r (&now, &tmnow);
1541 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1542 frames += tmnow.tm_min * (60 * _session->frame_rate());
1543 frames += tmnow.tm_sec * _session->frame_rate();
1545 _session->request_locate (frames, _session->transport_rolling ());
1547 /* force displayed area in editor to start no matter
1548 what "follow playhead" setting is.
1552 editor->center_screen (frames);
1558 ARDOUR_UI::transport_goto_end ()
1561 framepos_t const frame = _session->current_end_frame();
1562 _session->request_locate (frame);
1564 /* force displayed area in editor to start no matter
1565 what "follow playhead" setting is.
1569 editor->center_screen (frame);
1575 ARDOUR_UI::transport_stop ()
1581 if (_session->is_auditioning()) {
1582 _session->cancel_audition ();
1586 _session->request_stop (false, true);
1590 ARDOUR_UI::transport_stop_and_forget_capture ()
1593 _session->request_stop (true, true);
1598 ARDOUR_UI::remove_last_capture()
1601 editor->remove_last_capture();
1606 ARDOUR_UI::transport_record (bool roll)
1610 switch (_session->record_status()) {
1611 case Session::Disabled:
1612 if (_session->ntracks() == 0) {
1613 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1617 _session->maybe_enable_record ();
1622 case Session::Recording:
1624 _session->request_stop();
1626 _session->disable_record (false, true);
1630 case Session::Enabled:
1631 _session->disable_record (false, true);
1634 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1638 ARDOUR_UI::transport_roll ()
1644 if (_session->is_auditioning()) {
1649 if (_session->config.get_external_sync()) {
1650 switch (_session->config.get_sync_source()) {
1654 /* transport controlled by the master */
1660 bool rolling = _session->transport_rolling();
1662 if (_session->get_play_loop()) {
1663 /* XXX it is not possible to just leave seamless loop and keep
1664 playing at present (nov 4th 2009)
1666 if (!Config->get_seamless_loop()) {
1667 _session->request_play_loop (false, true);
1669 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1670 /* stop playing a range if we currently are */
1671 _session->request_play_range (0, true);
1674 if (join_play_range_button.get_active()) {
1675 _session->request_play_range (&editor->get_selection().time, true);
1679 _session->request_transport_speed (1.0f);
1684 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1691 if (_session->is_auditioning()) {
1692 _session->cancel_audition ();
1696 if (_session->config.get_external_sync()) {
1697 switch (_session->config.get_sync_source()) {
1701 /* transport controlled by the master */
1706 bool rolling = _session->transport_rolling();
1707 bool affect_transport = true;
1709 if (rolling && roll_out_of_bounded_mode) {
1710 /* drop out of loop/range playback but leave transport rolling */
1711 if (_session->get_play_loop()) {
1712 if (Config->get_seamless_loop()) {
1713 /* the disk buffers contain copies of the loop - we can't
1714 just keep playing, so stop the transport. the user
1715 can restart as they wish.
1717 affect_transport = true;
1719 /* disk buffers are normal, so we can keep playing */
1720 affect_transport = false;
1722 _session->request_play_loop (false, true);
1723 } else if (_session->get_play_range ()) {
1724 affect_transport = false;
1725 _session->request_play_range (0, true);
1729 if (affect_transport) {
1731 _session->request_stop (with_abort, true);
1733 if (join_play_range_button.get_active()) {
1734 _session->request_play_range (&editor->get_selection().time, true);
1737 _session->request_transport_speed (1.0f);
1743 ARDOUR_UI::toggle_session_auto_loop ()
1749 if (_session->get_play_loop()) {
1751 if (_session->transport_rolling()) {
1753 Location * looploc = _session->locations()->auto_loop_location();
1756 _session->request_locate (looploc->start(), true);
1757 _session->request_play_loop (false);
1761 _session->request_play_loop (false);
1765 Location * looploc = _session->locations()->auto_loop_location();
1768 _session->request_play_loop (true);
1774 ARDOUR_UI::transport_play_selection ()
1780 editor->play_selection ();
1784 ARDOUR_UI::transport_rewind (int option)
1786 float current_transport_speed;
1789 current_transport_speed = _session->transport_speed();
1791 if (current_transport_speed >= 0.0f) {
1794 _session->request_transport_speed (-1.0f);
1797 _session->request_transport_speed (-4.0f);
1800 _session->request_transport_speed (-0.5f);
1805 _session->request_transport_speed (current_transport_speed * 1.5f);
1811 ARDOUR_UI::transport_forward (int option)
1813 float current_transport_speed;
1816 current_transport_speed = _session->transport_speed();
1818 if (current_transport_speed <= 0.0f) {
1821 _session->request_transport_speed (1.0f);
1824 _session->request_transport_speed (4.0f);
1827 _session->request_transport_speed (0.5f);
1832 _session->request_transport_speed (current_transport_speed * 1.5f);
1839 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1841 if (_session == 0) {
1845 boost::shared_ptr<Route> r;
1847 if ((r = _session->route_by_remote_id (rid)) != 0) {
1851 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1852 t->set_record_enabled (!t->record_enabled(), this);
1855 if (_session == 0) {
1861 ARDOUR_UI::map_transport_state ()
1864 auto_loop_button.set_visual_state (0);
1865 play_selection_button.set_visual_state (0);
1866 roll_button.set_visual_state (0);
1867 stop_button.set_visual_state (1);
1871 shuttle_box->map_transport_state ();
1873 float sp = _session->transport_speed();
1879 if (_session->get_play_range()) {
1881 play_selection_button.set_visual_state (1);
1882 roll_button.set_visual_state (0);
1883 auto_loop_button.set_visual_state (0);
1885 } else if (_session->get_play_loop ()) {
1887 auto_loop_button.set_visual_state (1);
1888 play_selection_button.set_visual_state (0);
1889 roll_button.set_visual_state (0);
1893 roll_button.set_visual_state (1);
1894 play_selection_button.set_visual_state (0);
1895 auto_loop_button.set_visual_state (0);
1898 if (join_play_range_button.get_active()) {
1899 /* light up both roll and play-selection if they are joined */
1900 roll_button.set_visual_state (1);
1901 play_selection_button.set_visual_state (1);
1904 stop_button.set_visual_state (0);
1908 stop_button.set_visual_state (1);
1909 roll_button.set_visual_state (0);
1910 play_selection_button.set_visual_state (0);
1911 auto_loop_button.set_visual_state (0);
1912 update_disk_space ();
1917 ARDOUR_UI::engine_stopped ()
1919 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1920 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1921 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1925 ARDOUR_UI::engine_running ()
1927 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1928 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1929 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1931 Glib::RefPtr<Action> action;
1932 const char* action_name = 0;
1934 switch (engine->frames_per_cycle()) {
1936 action_name = X_("JACKLatency32");
1939 action_name = X_("JACKLatency64");
1942 action_name = X_("JACKLatency128");
1945 action_name = X_("JACKLatency512");
1948 action_name = X_("JACKLatency1024");
1951 action_name = X_("JACKLatency2048");
1954 action_name = X_("JACKLatency4096");
1957 action_name = X_("JACKLatency8192");
1960 /* XXX can we do anything useful ? */
1966 action = ActionManager::get_action (X_("JACK"), action_name);
1969 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1970 ract->set_active ();
1976 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1978 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1979 /* we can't rely on the original string continuing to exist when we are called
1980 again in the GUI thread, so make a copy and note that we need to
1983 char *copy = strdup (reason);
1984 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1988 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1989 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1991 update_sample_rate (0);
1995 /* if the reason is a non-empty string, it means that the backend was shutdown
1996 rather than just Ardour.
1999 if (strlen (reason)) {
2000 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
2002 msgstr = string_compose (_("\
2003 JACK has either been shutdown or it\n\
2004 disconnected %1 because %1\n\
2005 was not fast enough. Try to restart\n\
2006 JACK, reconnect and save the session."), PROGRAM_NAME);
2009 MessageDialog msg (*editor, msgstr);
2014 free ((char*) reason);
2019 ARDOUR_UI::do_engine_start ()
2027 error << _("Unable to start the session running")
2037 ARDOUR_UI::setup_theme ()
2039 theme_manager->setup_theme();
2043 ARDOUR_UI::update_clocks ()
2045 if (!editor || !editor->dragging_playhead()) {
2046 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2051 ARDOUR_UI::start_clocking ()
2053 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2057 ARDOUR_UI::stop_clocking ()
2059 clock_signal_connection.disconnect ();
2063 ARDOUR_UI::toggle_clocking ()
2066 if (clock_button.get_active()) {
2075 ARDOUR_UI::_blink (void *arg)
2078 ((ARDOUR_UI *) arg)->blink ();
2085 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2089 ARDOUR_UI::start_blinking ()
2091 /* Start the blink signal. Everybody with a blinking widget
2092 uses Blink to drive the widget's state.
2095 if (blink_timeout_tag < 0) {
2097 blink_timeout_tag = g_timeout_add (240, _blink, this);
2102 ARDOUR_UI::stop_blinking ()
2104 if (blink_timeout_tag >= 0) {
2105 g_source_remove (blink_timeout_tag);
2106 blink_timeout_tag = -1;
2111 /** Ask the user for the name of a new shapshot and then take it.
2115 ARDOUR_UI::snapshot_session (bool switch_to_it)
2117 ArdourPrompter prompter (true);
2120 prompter.set_name ("Prompter");
2121 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2122 prompter.set_title (_("Take Snapshot"));
2123 prompter.set_prompt (_("Name of new snapshot"));
2125 if (!switch_to_it) {
2128 struct tm local_time;
2131 localtime_r (&n, &local_time);
2132 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2133 prompter.set_initial_text (timebuf);
2137 switch (prompter.run()) {
2138 case RESPONSE_ACCEPT:
2140 prompter.get_result (snapname);
2142 bool do_save = (snapname.length() != 0);
2145 if (snapname.find ('/') != string::npos) {
2146 MessageDialog msg (_("To ensure compatibility with various systems\n"
2147 "snapshot names may not contain a '/' character"));
2151 if (snapname.find ('\\') != string::npos) {
2152 MessageDialog msg (_("To ensure compatibility with various systems\n"
2153 "snapshot names may not contain a '\\' character"));
2159 vector<sys::path> p;
2160 get_state_files_in_directory (_session->session_directory().root_path(), p);
2161 vector<string> n = get_file_names_no_extension (p);
2162 if (find (n.begin(), n.end(), snapname) != n.end()) {
2164 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2165 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2166 confirm.get_vbox()->pack_start (m, true, true);
2167 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2168 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2169 confirm.show_all ();
2170 switch (confirm.run()) {
2171 case RESPONSE_CANCEL:
2177 save_state (snapname, switch_to_it);
2187 /** Ask the user for the name of a new shapshot and then take it.
2191 ARDOUR_UI::rename_session ()
2197 ArdourPrompter prompter (true);
2200 prompter.set_name ("Prompter");
2201 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2202 prompter.set_title (_("Rename Session"));
2203 prompter.set_prompt (_("New session name"));
2206 switch (prompter.run()) {
2207 case RESPONSE_ACCEPT:
2209 prompter.get_result (name);
2211 bool do_rename = (name.length() != 0);
2214 if (name.find ('/') != string::npos) {
2215 MessageDialog msg (_("To ensure compatibility with various systems\n"
2216 "session names may not contain a '/' character"));
2220 if (name.find ('\\') != string::npos) {
2221 MessageDialog msg (_("To ensure compatibility with various systems\n"
2222 "session names may not contain a '\\' character"));
2227 switch (_session->rename (name)) {
2229 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2230 msg.set_position (WIN_POS_MOUSE);
2238 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2239 msg.set_position (WIN_POS_MOUSE);
2255 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2257 XMLNode* node = new XMLNode (X_("UI"));
2259 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2260 if (!(*i)->rc_configured()) {
2261 node->add_child_nocopy (*((*i)->get_state ()));
2265 node->add_child_nocopy (gui_object_state->get_state());
2267 _session->add_extra_xml (*node);
2269 save_state_canfail (name, switch_to_it);
2273 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2278 if (name.length() == 0) {
2279 name = _session->snap_name();
2282 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2287 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2292 ARDOUR_UI::primary_clock_value_changed ()
2295 _session->request_locate (primary_clock->current_time ());
2300 ARDOUR_UI::big_clock_value_changed ()
2303 _session->request_locate (big_clock->current_time ());
2308 ARDOUR_UI::secondary_clock_value_changed ()
2311 _session->request_locate (secondary_clock->current_time ());
2316 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2318 if (_session == 0) {
2322 if (_session->step_editing()) {
2326 Session::RecordState const r = _session->record_status ();
2327 bool const h = _session->have_rec_enabled_track ();
2329 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2331 rec_button.set_visual_state (2);
2333 rec_button.set_visual_state (0);
2335 } else if (r == Session::Recording && h) {
2336 rec_button.set_visual_state (1);
2338 rec_button.set_visual_state (0);
2343 ARDOUR_UI::save_template ()
2345 ArdourPrompter prompter (true);
2348 if (!check_audioengine()) {
2352 prompter.set_name (X_("Prompter"));
2353 prompter.set_title (_("Save Template"));
2354 prompter.set_prompt (_("Name for template:"));
2355 prompter.set_initial_text(_session->name() + _("-template"));
2356 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2358 switch (prompter.run()) {
2359 case RESPONSE_ACCEPT:
2360 prompter.get_result (name);
2362 if (name.length()) {
2363 _session->save_template (name);
2373 ARDOUR_UI::edit_metadata ()
2375 SessionMetadataEditor dialog;
2376 dialog.set_session (_session);
2377 editor->ensure_float (dialog);
2382 ARDOUR_UI::import_metadata ()
2384 SessionMetadataImporter dialog;
2385 dialog.set_session (_session);
2386 editor->ensure_float (dialog);
2391 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2393 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2395 MessageDialog msg (str,
2397 Gtk::MESSAGE_WARNING,
2398 Gtk::BUTTONS_YES_NO,
2402 msg.set_name (X_("OpenExistingDialog"));
2403 msg.set_title (_("Open Existing Session"));
2404 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2405 msg.set_position (Gtk::WIN_POS_MOUSE);
2408 switch (msg.run()) {
2417 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2419 BusProfile bus_profile;
2421 if (Profile->get_sae()) {
2423 bus_profile.master_out_channels = 2;
2424 bus_profile.input_ac = AutoConnectPhysical;
2425 bus_profile.output_ac = AutoConnectMaster;
2426 bus_profile.requested_physical_in = 0; // use all available
2427 bus_profile.requested_physical_out = 0; // use all available
2431 /* get settings from advanced section of NSD */
2433 if (_startup->create_master_bus()) {
2434 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2436 bus_profile.master_out_channels = 0;
2439 if (_startup->connect_inputs()) {
2440 bus_profile.input_ac = AutoConnectPhysical;
2442 bus_profile.input_ac = AutoConnectOption (0);
2445 /// @todo some minor tweaks.
2447 bus_profile.output_ac = AutoConnectOption (0);
2449 if (_startup->connect_outputs ()) {
2450 if (_startup->connect_outs_to_master()) {
2451 bus_profile.output_ac = AutoConnectMaster;
2452 } else if (_startup->connect_outs_to_physical()) {
2453 bus_profile.output_ac = AutoConnectPhysical;
2457 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2458 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2461 if (build_session (session_path, session_name, bus_profile)) {
2469 ARDOUR_UI::idle_load (const std::string& path)
2472 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2473 /* /path/to/foo => /path/to/foo, foo */
2474 load_session (path, basename_nosuffix (path));
2476 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2477 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2481 ARDOUR_COMMAND_LINE::session_name = path;
2484 * new_session_dialog doens't exist in A3
2485 * Try to remove all references to it to
2486 * see if it will compile. NOTE: this will
2487 * likely cause a runtime issue is my somewhat
2491 //if (new_session_dialog) {
2494 /* make it break out of Dialog::run() and
2498 //new_session_dialog->response (1);
2504 ARDOUR_UI::end_loading_messages ()
2510 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2513 // splash->message (msg);
2517 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2519 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2521 string session_name;
2522 string session_path;
2523 string template_name;
2525 bool likely_new = false;
2527 if (!load_template.empty()) {
2528 should_be_new = true;
2529 template_name = load_template;
2534 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2536 /* if they named a specific statefile, use it, otherwise they are
2537 just giving a session folder, and we want to use it as is
2538 to find the session.
2541 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2543 if (suffix != string::npos) {
2544 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2545 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2546 session_name = Glib::path_get_basename (session_name);
2548 session_path = ARDOUR_COMMAND_LINE::session_name;
2549 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2554 bool const apply = run_startup (should_be_new, load_template);
2557 if (quit_on_cancel) {
2564 /* if we run the startup dialog again, offer more than just "new session" */
2566 should_be_new = false;
2568 session_name = _startup->session_name (likely_new);
2570 string::size_type suffix = session_name.find (statefile_suffix);
2572 if (suffix != string::npos) {
2573 session_name = session_name.substr (0, suffix);
2576 /* this shouldn't happen, but we catch it just in case it does */
2578 if (session_name.empty()) {
2582 if (_startup->use_session_template()) {
2583 template_name = _startup->session_template_name();
2584 _session_is_new = true;
2587 if (session_name[0] == G_DIR_SEPARATOR ||
2588 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2589 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2591 /* absolute path or cwd-relative path specified for session name: infer session folder
2592 from what was given.
2595 session_path = Glib::path_get_dirname (session_name);
2596 session_name = Glib::path_get_basename (session_name);
2600 session_path = _startup->session_folder();
2602 if (session_name.find ('/') != string::npos) {
2603 MessageDialog msg (*_startup,
2604 _("To ensure compatibility with various systems\n"
2605 "session names may not contain a '/' character"));
2607 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2611 if (session_name.find ('\\') != string::npos) {
2612 MessageDialog msg (*_startup,
2613 _("To ensure compatibility with various systems\n"
2614 "session names may not contain a '\\' character"));
2616 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2622 if (create_engine ()) {
2626 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2630 std::string existing = Glib::build_filename (session_path, session_name);
2632 if (!ask_about_loading_existing_session (existing)) {
2633 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2638 _session_is_new = false;
2643 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2645 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2649 if (session_name.find ('/') != std::string::npos) {
2650 MessageDialog msg (*_startup,
2651 _("To ensure compatibility with various systems\n"
2652 "session names may not contain a '/' character"));
2654 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2658 if (session_name.find ('\\') != std::string::npos) {
2659 MessageDialog msg (*_startup,
2660 _("To ensure compatibility with various systems\n"
2661 "session names may not contain a '\\' character"));
2663 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2667 _session_is_new = true;
2670 if (likely_new && template_name.empty()) {
2672 ret = build_session_from_nsd (session_path, session_name);
2676 ret = load_session (session_path, session_name, template_name);
2679 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2683 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2684 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2694 ARDOUR_UI::close_session()
2696 if (!check_audioengine()) {
2700 if (unload_session (true)) {
2704 ARDOUR_COMMAND_LINE::session_name = "";
2706 if (get_session_parameters (true, false)) {
2710 goto_editor_window ();
2713 /** @param snap_name Snapshot name (without .ardour suffix).
2714 * @return -2 if the load failed because we are not connected to the AudioEngine.
2717 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2719 Session *new_session;
2723 session_loaded = false;
2725 if (!check_audioengine()) {
2729 unload_status = unload_session ();
2731 if (unload_status < 0) {
2733 } else if (unload_status > 0) {
2738 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2741 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2744 /* this one is special */
2746 catch (AudioEngine::PortRegistrationFailure& err) {
2748 MessageDialog msg (err.what(),
2751 Gtk::BUTTONS_CLOSE);
2753 msg.set_title (_("Port Registration Error"));
2754 msg.set_secondary_text (_("Click the Close button to try again."));
2755 msg.set_position (Gtk::WIN_POS_CENTER);
2759 int response = msg.run ();
2764 case RESPONSE_CANCEL:
2774 MessageDialog msg (string_compose(
2775 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2781 msg.set_title (_("Loading Error"));
2782 msg.set_secondary_text (_("Click the Refresh button to try again."));
2783 msg.add_button (Stock::REFRESH, 1);
2784 msg.set_position (Gtk::WIN_POS_CENTER);
2788 int response = msg.run ();
2803 list<string> const u = new_session->unknown_processors ();
2805 MissingPluginDialog d (_session, u);
2810 /* Now the session been created, add the transport controls */
2811 new_session->add_controllable(roll_controllable);
2812 new_session->add_controllable(stop_controllable);
2813 new_session->add_controllable(goto_start_controllable);
2814 new_session->add_controllable(goto_end_controllable);
2815 new_session->add_controllable(auto_loop_controllable);
2816 new_session->add_controllable(play_selection_controllable);
2817 new_session->add_controllable(rec_controllable);
2819 set_session (new_session);
2821 session_loaded = true;
2823 goto_editor_window ();
2826 _session->set_clean ();
2837 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2839 Session *new_session;
2842 if (!check_audioengine()) {
2846 session_loaded = false;
2848 x = unload_session ();
2856 _session_is_new = true;
2859 new_session = new Session (*engine, path, snap_name, &bus_profile);
2864 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2870 /* Give the new session the default GUI state, if such things exist */
2873 n = Config->instant_xml (X_("Editor"));
2875 new_session->add_instant_xml (*n, false);
2877 n = Config->instant_xml (X_("Mixer"));
2879 new_session->add_instant_xml (*n, false);
2882 /* Put the playhead at 0 and scroll fully left */
2883 n = new_session->instant_xml (X_("Editor"));
2885 n->add_property (X_("playhead"), X_("0"));
2886 n->add_property (X_("left-frame"), X_("0"));
2889 set_session (new_session);
2891 session_loaded = true;
2893 new_session->save_state(new_session->name());
2899 ARDOUR_UI::launch_chat ()
2902 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2904 open_uri("http://webchat.freenode.net/?channels=ardour");
2909 ARDOUR_UI::show_about ()
2913 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2916 about->set_transient_for(*editor);
2921 ARDOUR_UI::launch_manual ()
2923 PBD::open_uri("http://ardour.org/flossmanual");
2927 ARDOUR_UI::launch_reference ()
2929 PBD::open_uri("http://ardour.org/refmanual");
2933 ARDOUR_UI::hide_about ()
2936 about->get_window()->set_cursor ();
2942 ARDOUR_UI::about_signal_response (int /*response*/)
2948 ARDOUR_UI::show_splash ()
2952 splash = new Splash;
2960 splash->queue_draw ();
2961 splash->get_window()->process_updates (true);
2966 ARDOUR_UI::hide_splash ()
2974 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2975 const string& plural_msg, const string& singular_msg)
2979 removed = rep.paths.size();
2982 MessageDialog msgd (*editor,
2983 _("No files were ready for clean-up"),
2986 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2987 msgd.set_title (_("Clean-up"));
2988 msgd.set_secondary_text (_("If this seems suprising, \n\
2989 check for any existing snapshots.\n\
2990 These may still include regions that\n\
2991 require some unused files to continue to exist."));
2997 ArdourDialog results (_("Clean-up"), true, false);
2999 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3000 CleanupResultsModelColumns() {
3004 Gtk::TreeModelColumn<std::string> visible_name;
3005 Gtk::TreeModelColumn<std::string> fullpath;
3009 CleanupResultsModelColumns results_columns;
3010 Glib::RefPtr<Gtk::ListStore> results_model;
3011 Gtk::TreeView results_display;
3013 results_model = ListStore::create (results_columns);
3014 results_display.set_model (results_model);
3015 results_display.append_column (list_title, results_columns.visible_name);
3017 results_display.set_name ("CleanupResultsList");
3018 results_display.set_headers_visible (true);
3019 results_display.set_headers_clickable (false);
3020 results_display.set_reorderable (false);
3022 Gtk::ScrolledWindow list_scroller;
3025 Gtk::HBox dhbox; // the hbox for the image and text
3026 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3027 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3029 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3031 const string dead_directory = _session->session_directory().dead_path().to_string();
3034 %1 - number of files removed
3035 %2 - location of "dead"
3036 %3 - size of files affected
3037 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3040 const char* bprefix;
3041 double space_adjusted = 0;
3043 if (rep.space < 1000) {
3045 space_adjusted = rep.space;
3046 } else if (rep.space < 1000000) {
3047 bprefix = X_("kilo");
3048 space_adjusted = truncf((float)rep.space / 1000.0);
3049 } else if (rep.space < 1000000 * 1000) {
3050 bprefix = X_("mega");
3051 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3053 bprefix = X_("giga");
3054 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3058 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3060 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3063 dhbox.pack_start (*dimage, true, false, 5);
3064 dhbox.pack_start (txt, true, false, 5);
3066 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3067 TreeModel::Row row = *(results_model->append());
3068 row[results_columns.visible_name] = *i;
3069 row[results_columns.fullpath] = *i;
3072 list_scroller.add (results_display);
3073 list_scroller.set_size_request (-1, 150);
3074 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3076 dvbox.pack_start (dhbox, true, false, 5);
3077 dvbox.pack_start (list_scroller, true, false, 5);
3078 ddhbox.pack_start (dvbox, true, false, 5);
3080 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3081 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3082 results.set_default_response (RESPONSE_CLOSE);
3083 results.set_position (Gtk::WIN_POS_MOUSE);
3085 results_display.show();
3086 list_scroller.show();
3093 //results.get_vbox()->show();
3094 results.set_resizable (false);
3101 ARDOUR_UI::cleanup ()
3103 if (_session == 0) {
3104 /* shouldn't happen: menu item is insensitive */
3109 MessageDialog checker (_("Are you sure you want to clean-up?"),
3111 Gtk::MESSAGE_QUESTION,
3112 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3114 checker.set_title (_("Clean-up"));
3116 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3117 ALL undo/redo information will be lost if you clean-up.\n\
3118 Clean-up will move all unused files to a \"dead\" location."));
3120 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3121 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3122 checker.set_default_response (RESPONSE_CANCEL);
3124 checker.set_name (_("CleanupDialog"));
3125 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3126 checker.set_position (Gtk::WIN_POS_MOUSE);
3128 switch (checker.run()) {
3129 case RESPONSE_ACCEPT:
3135 ARDOUR::CleanupReport rep;
3137 editor->prepare_for_cleanup ();
3139 /* do not allow flush until a session is reloaded */
3141 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3143 act->set_sensitive (false);
3146 if (_session->cleanup_sources (rep)) {
3147 editor->finish_cleanup ();
3151 editor->finish_cleanup ();
3154 display_cleanup_results (rep,
3157 The following %1 files were not in use and \n\
3158 have been moved to:\n\n\
3160 After a restart of Ardour,\n\n\
3161 Session -> Clean-up -> Flush Wastebasket\n\n\
3162 will release an additional\n\
3163 %3 %4bytes of disk space.\n"),
3165 The following file was not in use and \n\
3166 has been moved to:\n \
3168 After a restart of Ardour,\n\n\
3169 Session -> Clean-up -> Flush Wastebasket\n\n\
3170 will release an additional\n\
3171 %3 %4bytes of disk space.\n"
3177 ARDOUR_UI::flush_trash ()
3179 if (_session == 0) {
3180 /* shouldn't happen: menu item is insensitive */
3184 ARDOUR::CleanupReport rep;
3186 if (_session->cleanup_trash_sources (rep)) {
3190 display_cleanup_results (rep,
3192 _("The following %1 files were deleted from\n\
3194 releasing %3 %4bytes of disk space"),
3195 _("The following file was deleted from\n\
3197 releasing %3 %4bytes of disk space"));
3201 ARDOUR_UI::add_route (Gtk::Window* float_window)
3209 if (add_route_dialog == 0) {
3210 add_route_dialog = new AddRouteDialog (_session);
3212 add_route_dialog->set_transient_for (*float_window);
3216 if (add_route_dialog->is_visible()) {
3217 /* we're already doing this */
3221 ResponseType r = (ResponseType) add_route_dialog->run ();
3223 add_route_dialog->hide();
3226 case RESPONSE_ACCEPT:
3233 if ((count = add_route_dialog->count()) <= 0) {
3237 string template_path = add_route_dialog->track_template();
3239 if (!template_path.empty()) {
3240 _session->new_route_from_template (count, template_path);
3244 uint32_t input_chan = add_route_dialog->channels ();
3245 uint32_t output_chan;
3246 string name_template = add_route_dialog->name_template ();
3247 bool track = add_route_dialog->track ();
3248 RouteGroup* route_group = add_route_dialog->route_group ();
3250 AutoConnectOption oac = Config->get_output_auto_connect();
3252 if (oac & AutoConnectMaster) {
3253 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3255 output_chan = input_chan;
3258 /* XXX do something with name template */
3260 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3262 session_add_midi_track (route_group, count, name_template);
3264 MessageDialog msg (*editor,
3265 _("Sorry, MIDI Busses are not supported at this time."));
3267 //session_add_midi_bus();
3271 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3273 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3279 ARDOUR_UI::mixer_settings () const
3284 node = _session->instant_xml(X_("Mixer"));
3286 node = Config->instant_xml(X_("Mixer"));
3290 node = new XMLNode (X_("Mixer"));
3297 ARDOUR_UI::editor_settings () const
3302 node = _session->instant_xml(X_("Editor"));
3304 node = Config->instant_xml(X_("Editor"));
3308 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3309 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3314 node = new XMLNode (X_("Editor"));
3321 ARDOUR_UI::keyboard_settings () const
3325 node = Config->extra_xml(X_("Keyboard"));
3328 node = new XMLNode (X_("Keyboard"));
3335 ARDOUR_UI::create_xrun_marker (framepos_t where)
3337 editor->mouse_add_new_marker (where, false, true);
3341 ARDOUR_UI::halt_on_xrun_message ()
3343 MessageDialog msg (*editor,
3344 _("Recording was stopped because your system could not keep up."));
3349 ARDOUR_UI::xrun_handler (framepos_t where)
3355 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3357 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3358 create_xrun_marker(where);
3361 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3362 halt_on_xrun_message ();
3367 ARDOUR_UI::disk_overrun_handler ()
3369 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3371 if (!have_disk_speed_dialog_displayed) {
3372 have_disk_speed_dialog_displayed = true;
3373 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3374 The disk system on your computer\n\
3375 was not able to keep up with %1.\n\
3377 Specifically, it failed to write data to disk\n\
3378 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3379 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3385 ARDOUR_UI::disk_underrun_handler ()
3387 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3389 if (!have_disk_speed_dialog_displayed) {
3390 have_disk_speed_dialog_displayed = true;
3391 MessageDialog* msg = new MessageDialog (
3392 *editor, string_compose (_("The disk system on your computer\n\
3393 was not able to keep up with %1.\n\
3395 Specifically, it failed to read data from disk\n\
3396 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3397 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3403 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3405 have_disk_speed_dialog_displayed = false;
3410 ARDOUR_UI::session_dialog (std::string msg)
3412 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3417 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3419 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3428 ARDOUR_UI::pending_state_dialog ()
3430 HBox* hbox = new HBox();
3431 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3432 ArdourDialog dialog (_("Crash Recovery"), true);
3434 This session appears to have been in\n\
3435 middle of recording when ardour or\n\
3436 the computer was shutdown.\n\
3438 Ardour can recover any captured audio for\n\
3439 you, or it can ignore it. Please decide\n\
3440 what you would like to do.\n"));
3441 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3442 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3443 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3444 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3445 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3446 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3447 dialog.set_default_response (RESPONSE_ACCEPT);
3448 dialog.set_position (WIN_POS_CENTER);
3453 switch (dialog.run ()) {
3454 case RESPONSE_ACCEPT:
3462 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3464 HBox* hbox = new HBox();
3465 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3466 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3467 Label message (string_compose (_("\
3468 This session was created with a sample rate of %1 Hz\n\
3470 The audioengine is currently running at %2 Hz\n"), desired, actual));
3472 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3473 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3474 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3475 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3476 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3477 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3478 dialog.set_default_response (RESPONSE_ACCEPT);
3479 dialog.set_position (WIN_POS_CENTER);
3484 switch (dialog.run ()) {
3485 case RESPONSE_ACCEPT:
3494 ARDOUR_UI::disconnect_from_jack ()
3497 if( engine->disconnect_from_jack ()) {
3498 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3502 update_sample_rate (0);
3507 ARDOUR_UI::reconnect_to_jack ()
3510 if (engine->reconnect_to_jack ()) {
3511 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3515 update_sample_rate (0);
3520 ARDOUR_UI::use_config ()
3522 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3524 set_transport_controllable_state (*node);
3529 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3531 if (Config->get_primary_clock_delta_edit_cursor()) {
3532 primary_clock->set (pos, false, editor->get_preferred_edit_position(), 1);
3534 primary_clock->set (pos, 0, true);
3537 if (Config->get_secondary_clock_delta_edit_cursor()) {
3538 secondary_clock->set (pos, false, editor->get_preferred_edit_position(), 2);
3540 secondary_clock->set (pos);
3543 if (big_clock_window->get()) {
3544 big_clock->set (pos);
3550 ARDOUR_UI::step_edit_status_change (bool yn)
3552 // XXX should really store pre-step edit status of things
3553 // we make insensitive
3556 rec_button.set_visual_state (3);
3557 rec_button.set_sensitive (false);
3559 rec_button.set_visual_state (0);
3560 rec_button.set_sensitive (true);
3565 ARDOUR_UI::record_state_changed ()
3567 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3569 if (!_session || !big_clock_window->get()) {
3570 /* why bother - the clock isn't visible */
3574 Session::RecordState const r = _session->record_status ();
3575 bool const h = _session->have_rec_enabled_track ();
3577 if (r == Session::Recording && h) {
3578 big_clock->set_widget_name ("BigClockRecording");
3580 big_clock->set_widget_name ("BigClockNonRecording");
3585 ARDOUR_UI::first_idle ()
3588 _session->allow_auto_play (true);
3592 editor->first_idle();
3595 Keyboard::set_can_save_keybindings (true);
3600 ARDOUR_UI::store_clock_modes ()
3602 XMLNode* node = new XMLNode(X_("ClockModes"));
3604 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3605 XMLNode* child = new XMLNode (X_("Clock"));
3607 child->add_property (X_("name"), (*x)->name());
3608 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3609 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3611 node->add_child_nocopy (*child);
3614 _session->add_extra_xml (*node);
3615 _session->set_dirty ();
3618 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3619 : Controllable (name), ui (u), type(tp)
3625 ARDOUR_UI::TransportControllable::set_value (double val)
3628 /* do nothing: these are radio-style actions */
3632 const char *action = 0;
3636 action = X_("Roll");
3639 action = X_("Stop");
3642 action = X_("Goto Start");
3645 action = X_("Goto End");
3648 action = X_("Loop");
3651 action = X_("Play Selection");
3654 action = X_("Record");
3664 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3672 ARDOUR_UI::TransportControllable::get_value (void) const
3699 ARDOUR_UI::TransportControllable::set_id (const string& str)
3705 ARDOUR_UI::setup_profile ()
3707 if (gdk_screen_width() < 1200) {
3708 Profile->set_small_screen ();
3712 if (getenv ("ARDOUR_SAE")) {
3713 Profile->set_sae ();
3714 Profile->set_single_package ();
3719 ARDOUR_UI::toggle_translations ()
3721 using namespace Glib;
3723 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3725 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3728 string i18n_killer = ARDOUR::translation_kill_path();
3730 bool already_enabled = !ARDOUR::translations_are_disabled ();
3732 if (ract->get_active ()) {
3733 /* we don't care about errors */
3734 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3737 /* we don't care about errors */
3738 unlink (i18n_killer.c_str());
3741 if (already_enabled != ract->get_active()) {
3742 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3744 Gtk::MESSAGE_WARNING,
3746 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3747 win.set_position (Gtk::WIN_POS_CENTER);
3755 /** Add a window proxy to our list, so that its state will be saved.
3756 * This call also causes the window to be created and opened if its
3757 * state was saved as `visible'.
3760 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3762 _window_proxies.push_back (p);
3766 /** Remove a window proxy from our list. Must be called if a WindowProxy
3767 * is deleted, to prevent hanging pointers.
3770 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3772 _window_proxies.remove (p);
3776 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3778 MissingFileDialog dialog (s, str, type);
3783 int result = dialog.run ();
3790 return 1; // quit entire session load
3793 result = dialog.get_action ();
3799 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3801 AmbiguousFileDialog dialog (file, hits);
3807 return dialog.get_which ();