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%H.%M.%S", &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"));
2157 if (snapname.find (':') != string::npos) {
2158 MessageDialog msg (_("To ensure compatibility with various systems\n"
2159 "snapshot names may not contain a ':' character"));
2165 vector<sys::path> p;
2166 get_state_files_in_directory (_session->session_directory().root_path(), p);
2167 vector<string> n = get_file_names_no_extension (p);
2168 if (find (n.begin(), n.end(), snapname) != n.end()) {
2170 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2171 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2172 confirm.get_vbox()->pack_start (m, true, true);
2173 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2174 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2175 confirm.show_all ();
2176 switch (confirm.run()) {
2177 case RESPONSE_CANCEL:
2183 save_state (snapname, switch_to_it);
2193 /** Ask the user for the name of a new shapshot and then take it.
2197 ARDOUR_UI::rename_session ()
2203 ArdourPrompter prompter (true);
2206 prompter.set_name ("Prompter");
2207 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2208 prompter.set_title (_("Rename Session"));
2209 prompter.set_prompt (_("New session name"));
2212 switch (prompter.run()) {
2213 case RESPONSE_ACCEPT:
2215 prompter.get_result (name);
2217 bool do_rename = (name.length() != 0);
2220 if (name.find ('/') != string::npos) {
2221 MessageDialog msg (_("To ensure compatibility with various systems\n"
2222 "session names may not contain a '/' character"));
2226 if (name.find ('\\') != string::npos) {
2227 MessageDialog msg (_("To ensure compatibility with various systems\n"
2228 "session names may not contain a '\\' character"));
2233 switch (_session->rename (name)) {
2235 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2236 msg.set_position (WIN_POS_MOUSE);
2244 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2245 msg.set_position (WIN_POS_MOUSE);
2261 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2263 XMLNode* node = new XMLNode (X_("UI"));
2265 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2266 if (!(*i)->rc_configured()) {
2267 node->add_child_nocopy (*((*i)->get_state ()));
2271 node->add_child_nocopy (gui_object_state->get_state());
2273 _session->add_extra_xml (*node);
2275 save_state_canfail (name, switch_to_it);
2279 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2284 if (name.length() == 0) {
2285 name = _session->snap_name();
2288 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2293 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2298 ARDOUR_UI::primary_clock_value_changed ()
2301 _session->request_locate (primary_clock->current_time ());
2306 ARDOUR_UI::big_clock_value_changed ()
2309 _session->request_locate (big_clock->current_time ());
2314 ARDOUR_UI::secondary_clock_value_changed ()
2317 _session->request_locate (secondary_clock->current_time ());
2322 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2324 if (_session == 0) {
2328 if (_session->step_editing()) {
2332 Session::RecordState const r = _session->record_status ();
2333 bool const h = _session->have_rec_enabled_track ();
2335 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2337 rec_button.set_visual_state (2);
2339 rec_button.set_visual_state (0);
2341 } else if (r == Session::Recording && h) {
2342 rec_button.set_visual_state (1);
2344 rec_button.set_visual_state (0);
2349 ARDOUR_UI::save_template ()
2351 ArdourPrompter prompter (true);
2354 if (!check_audioengine()) {
2358 prompter.set_name (X_("Prompter"));
2359 prompter.set_title (_("Save Template"));
2360 prompter.set_prompt (_("Name for template:"));
2361 prompter.set_initial_text(_session->name() + _("-template"));
2362 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2364 switch (prompter.run()) {
2365 case RESPONSE_ACCEPT:
2366 prompter.get_result (name);
2368 if (name.length()) {
2369 _session->save_template (name);
2379 ARDOUR_UI::edit_metadata ()
2381 SessionMetadataEditor dialog;
2382 dialog.set_session (_session);
2383 editor->ensure_float (dialog);
2388 ARDOUR_UI::import_metadata ()
2390 SessionMetadataImporter dialog;
2391 dialog.set_session (_session);
2392 editor->ensure_float (dialog);
2397 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2399 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2401 MessageDialog msg (str,
2403 Gtk::MESSAGE_WARNING,
2404 Gtk::BUTTONS_YES_NO,
2408 msg.set_name (X_("OpenExistingDialog"));
2409 msg.set_title (_("Open Existing Session"));
2410 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2411 msg.set_position (Gtk::WIN_POS_MOUSE);
2414 switch (msg.run()) {
2423 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2425 BusProfile bus_profile;
2427 if (Profile->get_sae()) {
2429 bus_profile.master_out_channels = 2;
2430 bus_profile.input_ac = AutoConnectPhysical;
2431 bus_profile.output_ac = AutoConnectMaster;
2432 bus_profile.requested_physical_in = 0; // use all available
2433 bus_profile.requested_physical_out = 0; // use all available
2437 /* get settings from advanced section of NSD */
2439 if (_startup->create_master_bus()) {
2440 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2442 bus_profile.master_out_channels = 0;
2445 if (_startup->connect_inputs()) {
2446 bus_profile.input_ac = AutoConnectPhysical;
2448 bus_profile.input_ac = AutoConnectOption (0);
2451 /// @todo some minor tweaks.
2453 bus_profile.output_ac = AutoConnectOption (0);
2455 if (_startup->connect_outputs ()) {
2456 if (_startup->connect_outs_to_master()) {
2457 bus_profile.output_ac = AutoConnectMaster;
2458 } else if (_startup->connect_outs_to_physical()) {
2459 bus_profile.output_ac = AutoConnectPhysical;
2463 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2464 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2467 if (build_session (session_path, session_name, bus_profile)) {
2475 ARDOUR_UI::idle_load (const std::string& path)
2478 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2479 /* /path/to/foo => /path/to/foo, foo */
2480 load_session (path, basename_nosuffix (path));
2482 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2483 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2487 ARDOUR_COMMAND_LINE::session_name = path;
2490 * new_session_dialog doens't exist in A3
2491 * Try to remove all references to it to
2492 * see if it will compile. NOTE: this will
2493 * likely cause a runtime issue is my somewhat
2497 //if (new_session_dialog) {
2500 /* make it break out of Dialog::run() and
2504 //new_session_dialog->response (1);
2510 ARDOUR_UI::end_loading_messages ()
2516 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2519 // splash->message (msg);
2523 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2525 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2527 string session_name;
2528 string session_path;
2529 string template_name;
2531 bool likely_new = false;
2533 if (!load_template.empty()) {
2534 should_be_new = true;
2535 template_name = load_template;
2540 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2542 /* if they named a specific statefile, use it, otherwise they are
2543 just giving a session folder, and we want to use it as is
2544 to find the session.
2547 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2549 if (suffix != string::npos) {
2550 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2551 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2552 session_name = Glib::path_get_basename (session_name);
2554 session_path = ARDOUR_COMMAND_LINE::session_name;
2555 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2560 bool const apply = run_startup (should_be_new, load_template);
2563 if (quit_on_cancel) {
2570 /* if we run the startup dialog again, offer more than just "new session" */
2572 should_be_new = false;
2574 session_name = _startup->session_name (likely_new);
2576 string::size_type suffix = session_name.find (statefile_suffix);
2578 if (suffix != string::npos) {
2579 session_name = session_name.substr (0, suffix);
2582 /* this shouldn't happen, but we catch it just in case it does */
2584 if (session_name.empty()) {
2588 if (_startup->use_session_template()) {
2589 template_name = _startup->session_template_name();
2590 _session_is_new = true;
2593 if (session_name[0] == G_DIR_SEPARATOR ||
2594 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2595 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2597 /* absolute path or cwd-relative path specified for session name: infer session folder
2598 from what was given.
2601 session_path = Glib::path_get_dirname (session_name);
2602 session_name = Glib::path_get_basename (session_name);
2606 session_path = _startup->session_folder();
2608 if (session_name.find ('/') != string::npos) {
2609 MessageDialog msg (*_startup,
2610 _("To ensure compatibility with various systems\n"
2611 "session names may not contain a '/' character"));
2613 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2617 if (session_name.find ('\\') != string::npos) {
2618 MessageDialog msg (*_startup,
2619 _("To ensure compatibility with various systems\n"
2620 "session names may not contain a '\\' character"));
2622 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2628 if (create_engine ()) {
2632 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2636 std::string existing = Glib::build_filename (session_path, session_name);
2638 if (!ask_about_loading_existing_session (existing)) {
2639 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2644 _session_is_new = false;
2649 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2651 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2655 if (session_name.find ('/') != std::string::npos) {
2656 MessageDialog msg (*_startup,
2657 _("To ensure compatibility with various systems\n"
2658 "session names may not contain a '/' character"));
2660 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2664 if (session_name.find ('\\') != std::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 _session_is_new = true;
2676 if (likely_new && template_name.empty()) {
2678 ret = build_session_from_nsd (session_path, session_name);
2682 ret = load_session (session_path, session_name, template_name);
2685 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2689 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2690 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2700 ARDOUR_UI::close_session()
2702 if (!check_audioengine()) {
2706 if (unload_session (true)) {
2710 ARDOUR_COMMAND_LINE::session_name = "";
2712 if (get_session_parameters (true, false)) {
2716 goto_editor_window ();
2719 /** @param snap_name Snapshot name (without .ardour suffix).
2720 * @return -2 if the load failed because we are not connected to the AudioEngine.
2723 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2725 Session *new_session;
2729 session_loaded = false;
2731 if (!check_audioengine()) {
2735 unload_status = unload_session ();
2737 if (unload_status < 0) {
2739 } else if (unload_status > 0) {
2744 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2747 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2750 /* this one is special */
2752 catch (AudioEngine::PortRegistrationFailure& err) {
2754 MessageDialog msg (err.what(),
2757 Gtk::BUTTONS_CLOSE);
2759 msg.set_title (_("Port Registration Error"));
2760 msg.set_secondary_text (_("Click the Close button to try again."));
2761 msg.set_position (Gtk::WIN_POS_CENTER);
2765 int response = msg.run ();
2770 case RESPONSE_CANCEL:
2780 MessageDialog msg (string_compose(
2781 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2787 msg.set_title (_("Loading Error"));
2788 msg.set_secondary_text (_("Click the Refresh button to try again."));
2789 msg.add_button (Stock::REFRESH, 1);
2790 msg.set_position (Gtk::WIN_POS_CENTER);
2794 int response = msg.run ();
2809 list<string> const u = new_session->unknown_processors ();
2811 MissingPluginDialog d (_session, u);
2816 /* Now the session been created, add the transport controls */
2817 new_session->add_controllable(roll_controllable);
2818 new_session->add_controllable(stop_controllable);
2819 new_session->add_controllable(goto_start_controllable);
2820 new_session->add_controllable(goto_end_controllable);
2821 new_session->add_controllable(auto_loop_controllable);
2822 new_session->add_controllable(play_selection_controllable);
2823 new_session->add_controllable(rec_controllable);
2825 set_session (new_session);
2827 session_loaded = true;
2829 goto_editor_window ();
2832 _session->set_clean ();
2843 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2845 Session *new_session;
2848 if (!check_audioengine()) {
2852 session_loaded = false;
2854 x = unload_session ();
2862 _session_is_new = true;
2865 new_session = new Session (*engine, path, snap_name, &bus_profile);
2870 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2876 /* Give the new session the default GUI state, if such things exist */
2879 n = Config->instant_xml (X_("Editor"));
2881 new_session->add_instant_xml (*n, false);
2883 n = Config->instant_xml (X_("Mixer"));
2885 new_session->add_instant_xml (*n, false);
2888 /* Put the playhead at 0 and scroll fully left */
2889 n = new_session->instant_xml (X_("Editor"));
2891 n->add_property (X_("playhead"), X_("0"));
2892 n->add_property (X_("left-frame"), X_("0"));
2895 set_session (new_session);
2897 session_loaded = true;
2899 new_session->save_state(new_session->name());
2905 ARDOUR_UI::launch_chat ()
2908 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2910 open_uri("http://webchat.freenode.net/?channels=ardour");
2915 ARDOUR_UI::show_about ()
2919 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2922 about->set_transient_for(*editor);
2927 ARDOUR_UI::launch_manual ()
2929 PBD::open_uri("http://ardour.org/flossmanual");
2933 ARDOUR_UI::launch_reference ()
2935 PBD::open_uri("http://ardour.org/refmanual");
2939 ARDOUR_UI::hide_about ()
2942 about->get_window()->set_cursor ();
2948 ARDOUR_UI::about_signal_response (int /*response*/)
2954 ARDOUR_UI::show_splash ()
2958 splash = new Splash;
2966 splash->queue_draw ();
2967 splash->get_window()->process_updates (true);
2972 ARDOUR_UI::hide_splash ()
2980 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2981 const string& plural_msg, const string& singular_msg)
2985 removed = rep.paths.size();
2988 MessageDialog msgd (*editor,
2989 _("No files were ready for clean-up"),
2992 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2993 msgd.set_title (_("Clean-up"));
2994 msgd.set_secondary_text (_("If this seems suprising, \n\
2995 check for any existing snapshots.\n\
2996 These may still include regions that\n\
2997 require some unused files to continue to exist."));
3003 ArdourDialog results (_("Clean-up"), true, false);
3005 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3006 CleanupResultsModelColumns() {
3010 Gtk::TreeModelColumn<std::string> visible_name;
3011 Gtk::TreeModelColumn<std::string> fullpath;
3015 CleanupResultsModelColumns results_columns;
3016 Glib::RefPtr<Gtk::ListStore> results_model;
3017 Gtk::TreeView results_display;
3019 results_model = ListStore::create (results_columns);
3020 results_display.set_model (results_model);
3021 results_display.append_column (list_title, results_columns.visible_name);
3023 results_display.set_name ("CleanupResultsList");
3024 results_display.set_headers_visible (true);
3025 results_display.set_headers_clickable (false);
3026 results_display.set_reorderable (false);
3028 Gtk::ScrolledWindow list_scroller;
3031 Gtk::HBox dhbox; // the hbox for the image and text
3032 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3033 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3035 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3037 const string dead_directory = _session->session_directory().dead_path().to_string();
3040 %1 - number of files removed
3041 %2 - location of "dead"
3042 %3 - size of files affected
3043 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3046 const char* bprefix;
3047 double space_adjusted = 0;
3049 if (rep.space < 1000) {
3051 space_adjusted = rep.space;
3052 } else if (rep.space < 1000000) {
3053 bprefix = X_("kilo");
3054 space_adjusted = truncf((float)rep.space / 1000.0);
3055 } else if (rep.space < 1000000 * 1000) {
3056 bprefix = X_("mega");
3057 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
3059 bprefix = X_("giga");
3060 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
3064 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
3066 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
3069 dhbox.pack_start (*dimage, true, false, 5);
3070 dhbox.pack_start (txt, true, false, 5);
3072 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3073 TreeModel::Row row = *(results_model->append());
3074 row[results_columns.visible_name] = *i;
3075 row[results_columns.fullpath] = *i;
3078 list_scroller.add (results_display);
3079 list_scroller.set_size_request (-1, 150);
3080 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3082 dvbox.pack_start (dhbox, true, false, 5);
3083 dvbox.pack_start (list_scroller, true, false, 5);
3084 ddhbox.pack_start (dvbox, true, false, 5);
3086 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3087 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3088 results.set_default_response (RESPONSE_CLOSE);
3089 results.set_position (Gtk::WIN_POS_MOUSE);
3091 results_display.show();
3092 list_scroller.show();
3099 //results.get_vbox()->show();
3100 results.set_resizable (false);
3107 ARDOUR_UI::cleanup ()
3109 if (_session == 0) {
3110 /* shouldn't happen: menu item is insensitive */
3115 MessageDialog checker (_("Are you sure you want to clean-up?"),
3117 Gtk::MESSAGE_QUESTION,
3118 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3120 checker.set_title (_("Clean-up"));
3122 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3123 ALL undo/redo information will be lost if you clean-up.\n\
3124 Clean-up will move all unused files to a \"dead\" location."));
3126 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3127 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3128 checker.set_default_response (RESPONSE_CANCEL);
3130 checker.set_name (_("CleanupDialog"));
3131 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3132 checker.set_position (Gtk::WIN_POS_MOUSE);
3134 switch (checker.run()) {
3135 case RESPONSE_ACCEPT:
3141 ARDOUR::CleanupReport rep;
3143 editor->prepare_for_cleanup ();
3145 /* do not allow flush until a session is reloaded */
3147 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3149 act->set_sensitive (false);
3152 if (_session->cleanup_sources (rep)) {
3153 editor->finish_cleanup ();
3157 editor->finish_cleanup ();
3160 display_cleanup_results (rep,
3163 The following %1 files were not in use and \n\
3164 have been moved to:\n\n\
3166 After a restart of Ardour,\n\n\
3167 Session -> Clean-up -> Flush Wastebasket\n\n\
3168 will release an additional\n\
3169 %3 %4bytes of disk space.\n"),
3171 The following file was not in use and \n\
3172 has been moved to:\n \
3174 After a restart of Ardour,\n\n\
3175 Session -> Clean-up -> Flush Wastebasket\n\n\
3176 will release an additional\n\
3177 %3 %4bytes of disk space.\n"
3183 ARDOUR_UI::flush_trash ()
3185 if (_session == 0) {
3186 /* shouldn't happen: menu item is insensitive */
3190 ARDOUR::CleanupReport rep;
3192 if (_session->cleanup_trash_sources (rep)) {
3196 display_cleanup_results (rep,
3198 _("The following %1 files were deleted from\n\
3200 releasing %3 %4bytes of disk space"),
3201 _("The following file was deleted from\n\
3203 releasing %3 %4bytes of disk space"));
3207 ARDOUR_UI::add_route (Gtk::Window* float_window)
3215 if (add_route_dialog == 0) {
3216 add_route_dialog = new AddRouteDialog (_session);
3218 add_route_dialog->set_transient_for (*float_window);
3222 if (add_route_dialog->is_visible()) {
3223 /* we're already doing this */
3227 ResponseType r = (ResponseType) add_route_dialog->run ();
3229 add_route_dialog->hide();
3232 case RESPONSE_ACCEPT:
3239 if ((count = add_route_dialog->count()) <= 0) {
3243 string template_path = add_route_dialog->track_template();
3245 if (!template_path.empty()) {
3246 _session->new_route_from_template (count, template_path);
3250 uint32_t input_chan = add_route_dialog->channels ();
3251 uint32_t output_chan;
3252 string name_template = add_route_dialog->name_template ();
3253 bool track = add_route_dialog->track ();
3254 RouteGroup* route_group = add_route_dialog->route_group ();
3256 AutoConnectOption oac = Config->get_output_auto_connect();
3258 if (oac & AutoConnectMaster) {
3259 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3261 output_chan = input_chan;
3264 /* XXX do something with name template */
3266 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3268 session_add_midi_track (route_group, count, name_template);
3270 MessageDialog msg (*editor,
3271 _("Sorry, MIDI Busses are not supported at this time."));
3273 //session_add_midi_bus();
3277 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3279 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3285 ARDOUR_UI::mixer_settings () const
3290 node = _session->instant_xml(X_("Mixer"));
3292 node = Config->instant_xml(X_("Mixer"));
3296 node = new XMLNode (X_("Mixer"));
3303 ARDOUR_UI::editor_settings () const
3308 node = _session->instant_xml(X_("Editor"));
3310 node = Config->instant_xml(X_("Editor"));
3314 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3315 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3320 node = new XMLNode (X_("Editor"));
3327 ARDOUR_UI::keyboard_settings () const
3331 node = Config->extra_xml(X_("Keyboard"));
3334 node = new XMLNode (X_("Keyboard"));
3341 ARDOUR_UI::create_xrun_marker (framepos_t where)
3343 editor->mouse_add_new_marker (where, false, true);
3347 ARDOUR_UI::halt_on_xrun_message ()
3349 MessageDialog msg (*editor,
3350 _("Recording was stopped because your system could not keep up."));
3355 ARDOUR_UI::xrun_handler (framepos_t where)
3361 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3363 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3364 create_xrun_marker(where);
3367 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3368 halt_on_xrun_message ();
3373 ARDOUR_UI::disk_overrun_handler ()
3375 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3377 if (!have_disk_speed_dialog_displayed) {
3378 have_disk_speed_dialog_displayed = true;
3379 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3380 The disk system on your computer\n\
3381 was not able to keep up with %1.\n\
3383 Specifically, it failed to write data to disk\n\
3384 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3385 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3391 ARDOUR_UI::disk_underrun_handler ()
3393 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3395 if (!have_disk_speed_dialog_displayed) {
3396 have_disk_speed_dialog_displayed = true;
3397 MessageDialog* msg = new MessageDialog (
3398 *editor, string_compose (_("The disk system on your computer\n\
3399 was not able to keep up with %1.\n\
3401 Specifically, it failed to read data from disk\n\
3402 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3403 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3409 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3411 have_disk_speed_dialog_displayed = false;
3416 ARDOUR_UI::session_dialog (std::string msg)
3418 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3423 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3425 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3434 ARDOUR_UI::pending_state_dialog ()
3436 HBox* hbox = new HBox();
3437 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3438 ArdourDialog dialog (_("Crash Recovery"), true);
3440 This session appears to have been in\n\
3441 middle of recording when ardour or\n\
3442 the computer was shutdown.\n\
3444 Ardour can recover any captured audio for\n\
3445 you, or it can ignore it. Please decide\n\
3446 what you would like to do.\n"));
3447 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3448 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3449 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3450 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3451 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3452 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3453 dialog.set_default_response (RESPONSE_ACCEPT);
3454 dialog.set_position (WIN_POS_CENTER);
3459 switch (dialog.run ()) {
3460 case RESPONSE_ACCEPT:
3468 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3470 HBox* hbox = new HBox();
3471 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3472 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3473 Label message (string_compose (_("\
3474 This session was created with a sample rate of %1 Hz\n\
3476 The audioengine is currently running at %2 Hz\n"), desired, actual));
3478 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3479 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3480 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3481 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3482 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3483 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3484 dialog.set_default_response (RESPONSE_ACCEPT);
3485 dialog.set_position (WIN_POS_CENTER);
3490 switch (dialog.run ()) {
3491 case RESPONSE_ACCEPT:
3500 ARDOUR_UI::disconnect_from_jack ()
3503 if( engine->disconnect_from_jack ()) {
3504 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3508 update_sample_rate (0);
3513 ARDOUR_UI::reconnect_to_jack ()
3516 if (engine->reconnect_to_jack ()) {
3517 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3521 update_sample_rate (0);
3526 ARDOUR_UI::use_config ()
3528 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3530 set_transport_controllable_state (*node);
3535 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3537 if (Config->get_primary_clock_delta_edit_cursor()) {
3538 primary_clock->set (pos, false, editor->get_preferred_edit_position(), 1);
3540 primary_clock->set (pos, 0, true);
3543 if (Config->get_secondary_clock_delta_edit_cursor()) {
3544 secondary_clock->set (pos, false, editor->get_preferred_edit_position(), 2);
3546 secondary_clock->set (pos);
3549 if (big_clock_window->get()) {
3550 big_clock->set (pos);
3556 ARDOUR_UI::step_edit_status_change (bool yn)
3558 // XXX should really store pre-step edit status of things
3559 // we make insensitive
3562 rec_button.set_visual_state (3);
3563 rec_button.set_sensitive (false);
3565 rec_button.set_visual_state (0);
3566 rec_button.set_sensitive (true);
3571 ARDOUR_UI::record_state_changed ()
3573 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3575 if (!_session || !big_clock_window->get()) {
3576 /* why bother - the clock isn't visible */
3580 Session::RecordState const r = _session->record_status ();
3581 bool const h = _session->have_rec_enabled_track ();
3583 if (r == Session::Recording && h) {
3584 big_clock->set_widget_name ("BigClockRecording");
3586 big_clock->set_widget_name ("BigClockNonRecording");
3591 ARDOUR_UI::first_idle ()
3594 _session->allow_auto_play (true);
3598 editor->first_idle();
3601 Keyboard::set_can_save_keybindings (true);
3606 ARDOUR_UI::store_clock_modes ()
3608 XMLNode* node = new XMLNode(X_("ClockModes"));
3610 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3611 XMLNode* child = new XMLNode (X_("Clock"));
3613 child->add_property (X_("name"), (*x)->name());
3614 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
3615 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
3617 node->add_child_nocopy (*child);
3620 _session->add_extra_xml (*node);
3621 _session->set_dirty ();
3624 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3625 : Controllable (name), ui (u), type(tp)
3631 ARDOUR_UI::TransportControllable::set_value (double val)
3634 /* do nothing: these are radio-style actions */
3638 const char *action = 0;
3642 action = X_("Roll");
3645 action = X_("Stop");
3648 action = X_("Goto Start");
3651 action = X_("Goto End");
3654 action = X_("Loop");
3657 action = X_("Play Selection");
3660 action = X_("Record");
3670 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3678 ARDOUR_UI::TransportControllable::get_value (void) const
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 ();