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_thread.h"
96 #include "location_ui.h"
97 #include "missing_file_dialog.h"
98 #include "missing_plugin_dialog.h"
101 #include "processor_box.h"
102 #include "prompter.h"
103 #include "public_editor.h"
104 #include "route_time_axis.h"
105 #include "session_metadata_dialog.h"
106 #include "shuttle_control.h"
107 #include "speaker_dialog.h"
110 #include "theme_manager.h"
111 #include "time_axis_view_item.h"
113 #include "window_proxy.h"
117 using namespace ARDOUR;
119 using namespace Gtkmm2ext;
122 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
123 UIConfiguration *ARDOUR_UI::ui_config = 0;
125 sigc::signal<void,bool> ARDOUR_UI::Blink;
126 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
127 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
128 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
130 bool could_be_a_valid_path (const string& path);
132 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
134 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
136 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
137 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
138 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
139 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
143 preroll_button (_("pre\nroll")),
144 postroll_button (_("post\nroll")),
148 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
152 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
153 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
154 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
155 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
156 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
157 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
158 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
160 roll_button (roll_controllable),
161 stop_button (stop_controllable),
162 goto_start_button (goto_start_controllable),
163 goto_end_button (goto_end_controllable),
164 auto_loop_button (auto_loop_controllable),
165 play_selection_button (play_selection_controllable),
166 rec_button (rec_controllable),
168 punch_in_button (_("Punch In")),
169 punch_out_button (_("Punch Out")),
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();
211 _session_is_new = false;
212 big_clock_window = 0;
213 big_clock_height = 0;
214 big_clock_resize_in_progress = false;
215 session_selector_window = 0;
216 last_key_press_time = 0;
217 _will_create_new_session_automatically = false;
218 add_route_dialog = 0;
220 rc_option_editor = 0;
221 session_option_editor = 0;
223 open_session_selector = 0;
224 have_configure_timeout = false;
225 have_disk_speed_dialog_displayed = false;
226 session_loaded = false;
227 ignore_dual_punch = false;
228 original_big_clock_width = -1;
229 original_big_clock_height = -1;
230 original_big_clock_font_size = 0;
232 roll_button.unset_flags (Gtk::CAN_FOCUS);
233 stop_button.unset_flags (Gtk::CAN_FOCUS);
234 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
235 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
236 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
237 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
238 rec_button.unset_flags (Gtk::CAN_FOCUS);
239 join_play_range_button.unset_flags (Gtk::CAN_FOCUS);
240 last_configure_time= 0;
243 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
244 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
246 /* handle dialog requests */
248 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
250 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
252 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
254 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
256 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
258 /* handle requests to quit (coming from JACK session) */
260 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
262 /* handle requests to deal with missing files */
264 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
266 /* and ambiguous files */
268 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
270 /* lets get this party started */
273 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
274 throw failed_constructor ();
277 setup_gtk_ardour_enums ();
280 GainMeter::setup_slider_pix ();
281 RouteTimeAxisView::setup_slider_pix ();
282 SendProcessorEntry::setup_slider_pix ();
283 SessionEvent::create_per_thread_pool ("GUI", 512);
285 } catch (failed_constructor& err) {
286 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
291 /* we like keyboards */
293 keyboard = new ArdourKeyboard(*this);
296 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
298 keyboard->set_state (*node, Stateful::loading_state_version);
301 /* we don't like certain modifiers */
302 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
306 TimeAxisViewItem::set_constant_heights ();
308 /* The following must happen after ARDOUR::init() so that Config is set up */
310 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
311 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
312 speaker_config_window = new ActionWindowProxy<SpeakerDialog> (X_("speakerconf"), Config->extra_xml (X_("UI")), X_("toggle-speaker-config"));
314 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
315 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
316 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
317 Config->extra_xml (X_("UI")),
318 string_compose ("toggle-%1-connection-manager", (*i).to_string())
324 SpeakerDialog* s = new SpeakerDialog ();
325 s->signal_unmap().connect (sigc::bind (sigc::ptr_fun (&ActionManager::uncheck_toggleaction), X_("<Actions>/Common/toggle-speaker-config")));
326 speaker_config_window->set (s);
328 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
329 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
332 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
334 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
337 _startup = new ArdourStartup ();
339 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
341 if (audio_setup && _startup->engine_control()) {
342 _startup->engine_control()->set_state (*audio_setup);
345 _startup->set_new_only (should_be_new);
346 if (!load_template.empty()) {
347 _startup->set_load_template( load_template );
349 _startup->present ();
355 switch (_startup->response()) {
364 ARDOUR_UI::create_engine ()
366 // this gets called every time by new_session()
372 loading_message (_("Starting audio engine"));
375 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
382 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
383 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
384 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
386 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
388 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
396 ARDOUR_UI::post_engine ()
398 /* Things to be done once we create the AudioEngine
401 ARDOUR::init_post_engine ();
403 ActionManager::init ();
406 if (setup_windows ()) {
407 throw failed_constructor ();
410 check_memory_locking();
412 /* this is the first point at which all the keybindings are available */
414 if (ARDOUR_COMMAND_LINE::show_key_actions) {
415 vector<string> names;
416 vector<string> paths;
417 vector<string> tooltips;
419 vector<AccelKey> bindings;
421 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
423 vector<string>::iterator n;
424 vector<string>::iterator k;
425 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
426 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
432 blink_timeout_tag = -1;
434 /* this being a GUI and all, we want peakfiles */
436 AudioFileSource::set_build_peakfiles (true);
437 AudioFileSource::set_build_missing_peakfiles (true);
439 /* set default clock modes */
441 if (Profile->get_sae()) {
442 primary_clock.set_mode (AudioClock::BBT);
443 secondary_clock.set_mode (AudioClock::MinSec);
445 primary_clock.set_mode (AudioClock::Timecode);
446 secondary_clock.set_mode (AudioClock::BBT);
449 /* start the time-of-day-clock */
452 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
453 update_wall_clock ();
454 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
457 update_disk_space ();
459 update_sample_rate (engine->frame_rate());
461 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
462 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
463 Config->map_parameters (pc);
465 /* now start and maybe save state */
467 if (do_engine_start () == 0) {
468 if (_session && _session_is_new) {
469 /* we need to retain initial visual
470 settings for a new session
472 _session->save_state ("");
477 ARDOUR_UI::~ARDOUR_UI ()
482 delete add_route_dialog;
486 ARDOUR_UI::pop_back_splash ()
488 if (Splash::instance()) {
489 // Splash::instance()->pop_back();
490 Splash::instance()->hide ();
495 ARDOUR_UI::configure_timeout ()
497 if (last_configure_time == 0) {
498 /* no configure events yet */
502 /* force a gap of 0.5 seconds since the last configure event
505 if (get_microseconds() - last_configure_time < 500000) {
508 have_configure_timeout = false;
509 cerr << "config event-driven save\n";
510 save_ardour_state ();
516 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
518 if (have_configure_timeout) {
519 last_configure_time = get_microseconds();
521 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
522 have_configure_timeout = true;
529 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
531 const XMLProperty* prop;
533 if ((prop = node.property ("roll")) != 0) {
534 roll_controllable->set_id (prop->value());
536 if ((prop = node.property ("stop")) != 0) {
537 stop_controllable->set_id (prop->value());
539 if ((prop = node.property ("goto-start")) != 0) {
540 goto_start_controllable->set_id (prop->value());
542 if ((prop = node.property ("goto-end")) != 0) {
543 goto_end_controllable->set_id (prop->value());
545 if ((prop = node.property ("auto-loop")) != 0) {
546 auto_loop_controllable->set_id (prop->value());
548 if ((prop = node.property ("play-selection")) != 0) {
549 play_selection_controllable->set_id (prop->value());
551 if ((prop = node.property ("rec")) != 0) {
552 rec_controllable->set_id (prop->value());
554 if ((prop = node.property ("shuttle")) != 0) {
555 shuttle_box->controllable()->set_id (prop->value());
561 ARDOUR_UI::get_transport_controllable_state ()
563 XMLNode* node = new XMLNode(X_("TransportControllables"));
566 roll_controllable->id().print (buf, sizeof (buf));
567 node->add_property (X_("roll"), buf);
568 stop_controllable->id().print (buf, sizeof (buf));
569 node->add_property (X_("stop"), buf);
570 goto_start_controllable->id().print (buf, sizeof (buf));
571 node->add_property (X_("goto_start"), buf);
572 goto_end_controllable->id().print (buf, sizeof (buf));
573 node->add_property (X_("goto_end"), buf);
574 auto_loop_controllable->id().print (buf, sizeof (buf));
575 node->add_property (X_("auto_loop"), buf);
576 play_selection_controllable->id().print (buf, sizeof (buf));
577 node->add_property (X_("play_selection"), buf);
578 rec_controllable->id().print (buf, sizeof (buf));
579 node->add_property (X_("rec"), buf);
580 shuttle_box->controllable()->id().print (buf, sizeof (buf));
581 node->add_property (X_("shuttle"), buf);
588 ARDOUR_UI::autosave_session ()
590 if (g_main_depth() > 1) {
591 /* inside a recursive main loop,
592 give up because we may not be able to
598 if (!Config->get_periodic_safety_backups()) {
603 _session->maybe_write_autosave();
610 ARDOUR_UI::update_autosave ()
612 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
614 if (_session && _session->dirty()) {
615 if (_autosave_connection.connected()) {
616 _autosave_connection.disconnect();
619 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
620 Config->get_periodic_safety_backup_interval() * 1000);
623 if (_autosave_connection.connected()) {
624 _autosave_connection.disconnect();
630 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
634 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
636 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
639 MessageDialog win (title,
645 win.set_secondary_text(_("There are several possible reasons:\n\
647 1) You requested audio parameters that are not supported..\n\
648 2) JACK is running as another user.\n\
650 Please consider the possibilities, and perhaps try different parameters."));
652 win.set_secondary_text(_("There are several possible reasons:\n\
654 1) JACK is not running.\n\
655 2) JACK is running as another user, perhaps root.\n\
656 3) There is already another client called \"ardour\".\n\
658 Please consider the possibilities, and perhaps (re)start JACK."));
662 win.set_transient_for (*toplevel);
666 win.add_button (Stock::OK, RESPONSE_CLOSE);
668 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
671 win.set_default_response (RESPONSE_CLOSE);
674 win.set_position (Gtk::WIN_POS_CENTER);
677 /* we just don't care about the result, but we want to block */
683 ARDOUR_UI::startup ()
685 Application* app = Application::instance ();
687 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
688 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
691 call_the_mothership (VERSIONSTRING);
696 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
702 goto_editor_window ();
704 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
705 to be opened on top of the editor window that goto_editor_window() just opened.
707 add_window_proxy (location_ui);
708 add_window_proxy (big_clock_window);
709 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
710 add_window_proxy (_global_port_matrix[*i]);
713 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
717 ARDOUR_UI::no_memory_warning ()
719 XMLNode node (X_("no-memory-warning"));
720 Config->add_instant_xml (node);
724 ARDOUR_UI::check_memory_locking ()
727 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
731 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
733 if (engine->is_realtime() && memory_warning_node == 0) {
735 struct rlimit limits;
737 long pages, page_size;
739 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
742 ram = (int64_t) pages * (int64_t) page_size;
745 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
749 if (limits.rlim_cur != RLIM_INFINITY) {
751 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
755 _("WARNING: Your system has a limit for maximum amount of locked memory. "
756 "This might cause %1 to run out of memory before your system "
757 "runs out of memory. \n\n"
758 "You can view the memory limit with 'ulimit -l', "
759 "and it is normally controlled by /etc/security/limits.conf"),
760 PROGRAM_NAME).c_str());
762 VBox* vbox = msg.get_vbox();
764 CheckButton cb (_("Do not show this window again"));
766 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
768 hbox.pack_start (cb, true, false);
769 vbox->pack_start (hbox);
776 editor->ensure_float (msg);
786 ARDOUR_UI::queue_finish ()
788 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
792 ARDOUR_UI::idle_finish ()
795 return false; /* do not call again */
804 if (_session->transport_rolling() && (++tries < 8)) {
805 _session->request_stop (false, true);
809 if (_session->dirty()) {
810 vector<string> actions;
811 actions.push_back (_("Don't quit"));
812 actions.push_back (_("Just quit"));
813 actions.push_back (_("Save and quit"));
814 switch (ask_about_saving_session(actions)) {
819 /* use the default name */
820 if (save_state_canfail ("")) {
821 /* failed - don't quit */
822 MessageDialog msg (*editor,
824 Ardour was unable to save your session.\n\n\
825 If you still wish to quit, please use the\n\n\
826 \"Just quit\" option."));
837 second_connection.disconnect ();
838 point_one_second_connection.disconnect ();
839 point_oh_five_second_connection.disconnect ();
840 point_zero_one_second_connection.disconnect();
843 /* Save state before deleting the session, as that causes some
844 windows to be destroyed before their visible state can be
847 save_ardour_state ();
850 // _session->set_deletion_in_progress ();
851 _session->set_clean ();
852 _session->remove_pending_capture_state ();
857 ArdourDialog::close_all_dialogs ();
863 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
865 ArdourDialog window (_("Unsaved Session"));
866 Gtk::HBox dhbox; // the hbox for the image and text
867 Gtk::Label prompt_label;
868 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
872 assert (actions.size() >= 3);
874 window.add_button (actions[0], RESPONSE_REJECT);
875 window.add_button (actions[1], RESPONSE_APPLY);
876 window.add_button (actions[2], RESPONSE_ACCEPT);
878 window.set_default_response (RESPONSE_ACCEPT);
880 Gtk::Button noquit_button (msg);
881 noquit_button.set_name ("EditorGTKButton");
885 if (_session->snap_name() == _session->name()) {
886 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?"),
887 _session->snap_name());
889 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?"),
890 _session->snap_name());
893 prompt_label.set_text (prompt);
894 prompt_label.set_name (X_("PrompterLabel"));
895 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
897 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
898 dhbox.set_homogeneous (false);
899 dhbox.pack_start (*dimage, false, false, 5);
900 dhbox.pack_start (prompt_label, true, false, 5);
901 window.get_vbox()->pack_start (dhbox);
903 window.set_name (_("Prompter"));
904 window.set_position (Gtk::WIN_POS_MOUSE);
905 window.set_modal (true);
906 window.set_resizable (false);
912 window.set_keep_above (true);
915 ResponseType r = (ResponseType) window.run();
920 case RESPONSE_ACCEPT: // save and get out of here
922 case RESPONSE_APPLY: // get out of here
932 ARDOUR_UI::every_second ()
935 update_buffer_load ();
936 update_disk_space ();
941 ARDOUR_UI::every_point_one_seconds ()
943 shuttle_box->update_speed_display ();
944 RapidScreenUpdate(); /* EMIT_SIGNAL */
949 ARDOUR_UI::every_point_zero_one_seconds ()
951 // august 2007: actual update frequency: 40Hz, not 100Hz
953 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
958 ARDOUR_UI::update_sample_rate (framecnt_t)
962 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
964 if (!engine->connected()) {
966 snprintf (buf, sizeof (buf), _("disconnected"));
970 framecnt_t rate = engine->frame_rate();
972 if (fmod (rate, 1000.0) != 0.0) {
973 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
974 (float) rate/1000.0f,
975 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
977 snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"),
979 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
983 sample_rate_label.set_text (buf);
987 ARDOUR_UI::update_cpu_load ()
990 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
991 cpu_load_label.set_text (buf);
995 ARDOUR_UI::update_buffer_load ()
1001 c = _session->capture_load ();
1002 p = _session->playback_load ();
1004 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
1005 _session->playback_load(), _session->capture_load());
1006 buffer_load_label.set_text (buf);
1008 buffer_load_label.set_text ("");
1013 ARDOUR_UI::count_recenabled_streams (Route& route)
1015 Track* track = dynamic_cast<Track*>(&route);
1016 if (track && track->record_enabled()) {
1017 rec_enabled_streams += track->n_inputs().n_total();
1022 ARDOUR_UI::update_disk_space()
1024 if (_session == 0) {
1028 framecnt_t frames = _session->available_capture_duration();
1030 framecnt_t fr = _session->frame_rate();
1032 if (frames == max_framecnt) {
1033 strcpy (buf, _("Disk: 24hrs+"));
1035 rec_enabled_streams = 0;
1036 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1038 if (rec_enabled_streams) {
1039 frames /= rec_enabled_streams;
1046 hrs = frames / (fr * 3600);
1047 frames -= hrs * fr * 3600;
1048 mins = frames / (fr * 60);
1049 frames -= mins * fr * 60;
1052 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1055 disk_space_label.set_text (buf);
1057 // An attempt to make the disk space label flash red when space has run out.
1059 if (frames < fr * 60 * 5) {
1060 /* disk_space_box.style ("disk_space_label_empty"); */
1062 /* disk_space_box.style ("disk_space_label"); */
1068 ARDOUR_UI::update_wall_clock ()
1075 tm_now = localtime (&now);
1077 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1078 wall_clock_label.set_text (buf);
1084 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1086 session_popup_menu->popup (0, 0);
1091 ARDOUR_UI::redisplay_recent_sessions ()
1093 std::vector<sys::path> session_directories;
1094 RecentSessionsSorter cmp;
1096 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1097 recent_session_model->clear ();
1099 ARDOUR::RecentSessions rs;
1100 ARDOUR::read_recent_sessions (rs);
1103 recent_session_display.set_model (recent_session_model);
1107 // sort them alphabetically
1108 sort (rs.begin(), rs.end(), cmp);
1110 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1111 session_directories.push_back ((*i).second);
1114 for (vector<sys::path>::const_iterator i = session_directories.begin();
1115 i != session_directories.end(); ++i)
1117 std::vector<sys::path> state_file_paths;
1119 // now get available states for this session
1121 get_state_files_in_directory (*i, state_file_paths);
1123 vector<string*>* states;
1124 vector<const gchar*> item;
1125 string fullpath = (*i).to_string();
1127 /* remove any trailing / */
1129 if (fullpath[fullpath.length()-1] == '/') {
1130 fullpath = fullpath.substr (0, fullpath.length()-1);
1133 /* check whether session still exists */
1134 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1135 /* session doesn't exist */
1136 cerr << "skipping non-existent session " << fullpath << endl;
1140 /* now get available states for this session */
1142 if ((states = Session::possible_states (fullpath)) == 0) {
1143 /* no state file? */
1147 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1149 Gtk::TreeModel::Row row = *(recent_session_model->append());
1151 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1152 row[recent_session_columns.fullpath] = fullpath;
1154 if (state_file_names.size() > 1) {
1158 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1159 i2 != state_file_names.end(); ++i2)
1162 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1164 child_row[recent_session_columns.visible_name] = *i2;
1165 child_row[recent_session_columns.fullpath] = fullpath;
1170 recent_session_display.set_model (recent_session_model);
1174 ARDOUR_UI::build_session_selector ()
1176 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1178 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1180 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1181 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1182 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1183 recent_session_model = TreeStore::create (recent_session_columns);
1184 recent_session_display.set_model (recent_session_model);
1185 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1186 recent_session_display.set_headers_visible (false);
1187 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1188 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1190 scroller->add (recent_session_display);
1191 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1193 session_selector_window->set_name ("SessionSelectorWindow");
1194 session_selector_window->set_size_request (200, 400);
1195 session_selector_window->get_vbox()->pack_start (*scroller);
1197 recent_session_display.show();
1199 //session_selector_window->get_vbox()->show();
1203 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1205 session_selector_window->response (RESPONSE_ACCEPT);
1209 ARDOUR_UI::open_recent_session ()
1211 bool can_return = (_session != 0);
1213 if (session_selector_window == 0) {
1214 build_session_selector ();
1217 redisplay_recent_sessions ();
1221 session_selector_window->set_position (WIN_POS_MOUSE);
1223 ResponseType r = (ResponseType) session_selector_window->run ();
1226 case RESPONSE_ACCEPT:
1230 session_selector_window->hide();
1237 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1241 session_selector_window->hide();
1243 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1245 if (i == recent_session_model->children().end()) {
1249 std::string path = (*i)[recent_session_columns.fullpath];
1250 std::string state = (*i)[recent_session_columns.visible_name];
1252 _session_is_new = false;
1254 if (load_session (path, state) == 0) {
1263 ARDOUR_UI::check_audioengine ()
1266 if (!engine->connected()) {
1267 MessageDialog msg (string_compose (
1268 _("%1 is not connected to JACK\n"
1269 "You cannot open or close sessions in this condition"),
1282 ARDOUR_UI::open_session ()
1284 if (!check_audioengine()) {
1289 /* popup selector window */
1291 if (open_session_selector == 0) {
1293 /* ardour sessions are folders */
1295 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1296 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1297 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1298 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1300 FileFilter session_filter;
1301 session_filter.add_pattern ("*.ardour");
1302 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1303 open_session_selector->add_filter (session_filter);
1304 open_session_selector->set_filter (session_filter);
1307 int response = open_session_selector->run();
1308 open_session_selector->hide ();
1311 case RESPONSE_ACCEPT:
1314 open_session_selector->hide();
1318 open_session_selector->hide();
1319 string session_path = open_session_selector->get_filename();
1323 if (session_path.length() > 0) {
1324 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1325 _session_is_new = isnew;
1326 load_session (path, name);
1333 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, string const & name_template)
1335 list<boost::shared_ptr<MidiTrack> > tracks;
1337 if (_session == 0) {
1338 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1345 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many, name_template);
1347 if (tracks.size() != how_many) {
1348 if (how_many == 1) {
1349 error << _("could not create a new midi track") << endmsg;
1351 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1355 if ((route = _session->new_midi_route ()) == 0) {
1356 error << _("could not create new midi bus") << endmsg;
1362 MessageDialog msg (*editor,
1363 string_compose (_("There are insufficient JACK ports available\n\
1364 to create a new track or bus.\n\
1365 You should save %1, exit and\n\
1366 restart JACK with more ports."), PROGRAM_NAME));
1373 ARDOUR_UI::session_add_audio_route (
1375 int32_t input_channels,
1376 int32_t output_channels,
1377 ARDOUR::TrackMode mode,
1378 RouteGroup* route_group,
1380 string const & name_template
1383 list<boost::shared_ptr<AudioTrack> > tracks;
1386 if (_session == 0) {
1387 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1393 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1395 if (tracks.size() != how_many) {
1396 if (how_many == 1) {
1397 error << _("could not create a new audio track") << endmsg;
1399 error << string_compose (_("could only create %1 of %2 new audio %3"),
1400 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1406 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1408 if (routes.size() != how_many) {
1409 if (how_many == 1) {
1410 error << _("could not create a new audio track") << endmsg;
1412 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1419 MessageDialog msg (*editor,
1420 string_compose (_("There are insufficient JACK ports available\n\
1421 to create a new track or bus.\n\
1422 You should save %1, exit and\n\
1423 restart JACK with more ports."), PROGRAM_NAME));
1430 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1432 framecnt_t _preroll = 0;
1435 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1436 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1438 if (new_position > _preroll) {
1439 new_position -= _preroll;
1444 _session->request_locate (new_position, with_roll);
1449 ARDOUR_UI::transport_goto_start ()
1452 _session->goto_start();
1454 /* force displayed area in editor to start no matter
1455 what "follow playhead" setting is.
1459 editor->center_screen (_session->current_start_frame ());
1465 ARDOUR_UI::transport_goto_zero ()
1468 _session->request_locate (0);
1470 /* force displayed area in editor to start no matter
1471 what "follow playhead" setting is.
1475 editor->reset_x_origin (0);
1481 ARDOUR_UI::transport_goto_wallclock ()
1483 if (_session && editor) {
1490 localtime_r (&now, &tmnow);
1492 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1493 frames += tmnow.tm_min * (60 * _session->frame_rate());
1494 frames += tmnow.tm_sec * _session->frame_rate();
1496 _session->request_locate (frames, _session->transport_rolling ());
1498 /* force displayed area in editor to start no matter
1499 what "follow playhead" setting is.
1503 editor->center_screen (frames);
1509 ARDOUR_UI::transport_goto_end ()
1512 framepos_t const frame = _session->current_end_frame();
1513 _session->request_locate (frame);
1515 /* force displayed area in editor to start no matter
1516 what "follow playhead" setting is.
1520 editor->center_screen (frame);
1526 ARDOUR_UI::transport_stop ()
1532 if (_session->is_auditioning()) {
1533 _session->cancel_audition ();
1537 _session->request_stop (false, true);
1541 ARDOUR_UI::transport_stop_and_forget_capture ()
1544 _session->request_stop (true, true);
1549 ARDOUR_UI::remove_last_capture()
1552 editor->remove_last_capture();
1557 ARDOUR_UI::transport_record (bool roll)
1561 switch (_session->record_status()) {
1562 case Session::Disabled:
1563 if (_session->ntracks() == 0) {
1564 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1568 _session->maybe_enable_record ();
1573 case Session::Recording:
1575 _session->request_stop();
1577 _session->disable_record (false, true);
1581 case Session::Enabled:
1582 _session->disable_record (false, true);
1585 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1589 ARDOUR_UI::transport_roll ()
1595 if (_session->is_auditioning()) {
1600 if (_session->config.get_external_sync()) {
1601 switch (_session->config.get_sync_source()) {
1605 /* transport controlled by the master */
1611 bool rolling = _session->transport_rolling();
1613 if (_session->get_play_loop()) {
1614 /* XXX it is not possible to just leave seamless loop and keep
1615 playing at present (nov 4th 2009)
1617 if (!Config->get_seamless_loop()) {
1618 _session->request_play_loop (false, true);
1620 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1621 /* stop playing a range if we currently are */
1622 _session->request_play_range (0, true);
1625 if (join_play_range_button.get_active()) {
1626 _session->request_play_range (&editor->get_selection().time, true);
1630 _session->request_transport_speed (1.0f);
1635 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1642 if (_session->is_auditioning()) {
1643 _session->cancel_audition ();
1647 if (_session->config.get_external_sync()) {
1648 switch (_session->config.get_sync_source()) {
1652 /* transport controlled by the master */
1657 bool rolling = _session->transport_rolling();
1658 bool affect_transport = true;
1660 if (rolling && roll_out_of_bounded_mode) {
1661 /* drop out of loop/range playback but leave transport rolling */
1662 if (_session->get_play_loop()) {
1663 if (Config->get_seamless_loop()) {
1664 /* the disk buffers contain copies of the loop - we can't
1665 just keep playing, so stop the transport. the user
1666 can restart as they wish.
1668 affect_transport = true;
1670 /* disk buffers are normal, so we can keep playing */
1671 affect_transport = false;
1673 _session->request_play_loop (false, true);
1674 } else if (_session->get_play_range ()) {
1675 affect_transport = false;
1676 _session->request_play_range (0, true);
1680 if (affect_transport) {
1682 _session->request_stop (with_abort, true);
1684 if (join_play_range_button.get_active()) {
1685 _session->request_play_range (&editor->get_selection().time, true);
1688 _session->request_transport_speed (1.0f);
1694 ARDOUR_UI::toggle_session_auto_loop ()
1700 if (_session->get_play_loop()) {
1702 if (_session->transport_rolling()) {
1704 Location * looploc = _session->locations()->auto_loop_location();
1707 _session->request_locate (looploc->start(), true);
1708 _session->request_play_loop (false);
1712 _session->request_play_loop (false);
1716 Location * looploc = _session->locations()->auto_loop_location();
1719 _session->request_play_loop (true);
1725 ARDOUR_UI::transport_play_selection ()
1731 editor->play_selection ();
1735 ARDOUR_UI::transport_rewind (int option)
1737 float current_transport_speed;
1740 current_transport_speed = _session->transport_speed();
1742 if (current_transport_speed >= 0.0f) {
1745 _session->request_transport_speed (-1.0f);
1748 _session->request_transport_speed (-4.0f);
1751 _session->request_transport_speed (-0.5f);
1756 _session->request_transport_speed (current_transport_speed * 1.5f);
1762 ARDOUR_UI::transport_forward (int option)
1764 float current_transport_speed;
1767 current_transport_speed = _session->transport_speed();
1769 if (current_transport_speed <= 0.0f) {
1772 _session->request_transport_speed (1.0f);
1775 _session->request_transport_speed (4.0f);
1778 _session->request_transport_speed (0.5f);
1783 _session->request_transport_speed (current_transport_speed * 1.5f);
1790 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1792 if (_session == 0) {
1796 boost::shared_ptr<Route> r;
1798 if ((r = _session->route_by_remote_id (rid)) != 0) {
1802 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1803 t->set_record_enabled (!t->record_enabled(), this);
1806 if (_session == 0) {
1812 ARDOUR_UI::map_transport_state ()
1815 auto_loop_button.set_visual_state (0);
1816 play_selection_button.set_visual_state (0);
1817 roll_button.set_visual_state (0);
1818 stop_button.set_visual_state (1);
1822 shuttle_box->map_transport_state ();
1824 float sp = _session->transport_speed();
1830 if (_session->get_play_range()) {
1832 play_selection_button.set_visual_state (1);
1833 roll_button.set_visual_state (0);
1834 auto_loop_button.set_visual_state (0);
1836 } else if (_session->get_play_loop ()) {
1838 auto_loop_button.set_visual_state (1);
1839 play_selection_button.set_visual_state (0);
1840 roll_button.set_visual_state (0);
1844 roll_button.set_visual_state (1);
1845 play_selection_button.set_visual_state (0);
1846 auto_loop_button.set_visual_state (0);
1849 if (join_play_range_button.get_active()) {
1850 /* light up both roll and play-selection if they are joined */
1851 roll_button.set_visual_state (1);
1852 play_selection_button.set_visual_state (1);
1855 stop_button.set_visual_state (0);
1859 stop_button.set_visual_state (1);
1860 roll_button.set_visual_state (0);
1861 play_selection_button.set_visual_state (0);
1862 auto_loop_button.set_visual_state (0);
1863 update_disk_space ();
1868 ARDOUR_UI::engine_stopped ()
1870 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1871 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1872 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1876 ARDOUR_UI::engine_running ()
1878 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1879 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1880 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1882 Glib::RefPtr<Action> action;
1883 const char* action_name = 0;
1885 switch (engine->frames_per_cycle()) {
1887 action_name = X_("JACKLatency32");
1890 action_name = X_("JACKLatency64");
1893 action_name = X_("JACKLatency128");
1896 action_name = X_("JACKLatency512");
1899 action_name = X_("JACKLatency1024");
1902 action_name = X_("JACKLatency2048");
1905 action_name = X_("JACKLatency4096");
1908 action_name = X_("JACKLatency8192");
1911 /* XXX can we do anything useful ? */
1917 action = ActionManager::get_action (X_("JACK"), action_name);
1920 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1921 ract->set_active ();
1927 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1929 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1930 /* we can't rely on the original string continuing to exist when we are called
1931 again in the GUI thread, so make a copy and note that we need to
1934 char *copy = strdup (reason);
1935 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1939 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1940 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1942 update_sample_rate (0);
1946 /* if the reason is a non-empty string, it means that the backend was shutdown
1947 rather than just Ardour.
1950 if (strlen (reason)) {
1951 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1953 msgstr = string_compose (_("\
1954 JACK has either been shutdown or it\n\
1955 disconnected %1 because %1\n\
1956 was not fast enough. Try to restart\n\
1957 JACK, reconnect and save the session."), PROGRAM_NAME);
1960 MessageDialog msg (*editor, msgstr);
1965 free ((char*) reason);
1970 ARDOUR_UI::do_engine_start ()
1978 error << _("Unable to start the session running")
1988 ARDOUR_UI::setup_theme ()
1990 theme_manager->setup_theme();
1994 ARDOUR_UI::update_clocks ()
1996 if (!editor || !editor->dragging_playhead()) {
1997 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2002 ARDOUR_UI::start_clocking ()
2004 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2008 ARDOUR_UI::stop_clocking ()
2010 clock_signal_connection.disconnect ();
2014 ARDOUR_UI::toggle_clocking ()
2017 if (clock_button.get_active()) {
2026 ARDOUR_UI::_blink (void *arg)
2029 ((ARDOUR_UI *) arg)->blink ();
2036 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2040 ARDOUR_UI::start_blinking ()
2042 /* Start the blink signal. Everybody with a blinking widget
2043 uses Blink to drive the widget's state.
2046 if (blink_timeout_tag < 0) {
2048 blink_timeout_tag = g_timeout_add (240, _blink, this);
2053 ARDOUR_UI::stop_blinking ()
2055 if (blink_timeout_tag >= 0) {
2056 g_source_remove (blink_timeout_tag);
2057 blink_timeout_tag = -1;
2062 /** Ask the user for the name of a new shapshot and then take it.
2066 ARDOUR_UI::snapshot_session (bool switch_to_it)
2068 ArdourPrompter prompter (true);
2071 prompter.set_name ("Prompter");
2072 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2073 prompter.set_title (_("Take Snapshot"));
2074 prompter.set_title (_("Take Snapshot"));
2075 prompter.set_prompt (_("Name of new snapshot"));
2077 if (!switch_to_it) {
2080 struct tm local_time;
2083 localtime_r (&n, &local_time);
2084 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2085 prompter.set_initial_text (timebuf);
2089 switch (prompter.run()) {
2090 case RESPONSE_ACCEPT:
2092 prompter.get_result (snapname);
2094 bool do_save = (snapname.length() != 0);
2097 if (snapname.find ('/') != string::npos) {
2098 MessageDialog msg (_("To ensure compatibility with various systems\n"
2099 "snapshot names may not contain a '/' character"));
2103 if (snapname.find ('\\') != string::npos) {
2104 MessageDialog msg (_("To ensure compatibility with various systems\n"
2105 "snapshot names may not contain a '\\' character"));
2111 vector<sys::path> p;
2112 get_state_files_in_directory (_session->session_directory().root_path(), p);
2113 vector<string> n = get_file_names_no_extension (p);
2114 if (find (n.begin(), n.end(), snapname) != n.end()) {
2116 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2117 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2118 confirm.get_vbox()->pack_start (m, true, true);
2119 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2120 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2121 confirm.show_all ();
2122 switch (confirm.run()) {
2123 case RESPONSE_CANCEL:
2129 save_state (snapname, switch_to_it);
2140 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2142 XMLNode* node = new XMLNode (X_("UI"));
2144 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2145 if (!(*i)->rc_configured()) {
2146 node->add_child_nocopy (*((*i)->get_state ()));
2150 _session->add_extra_xml (*node);
2152 save_state_canfail (name, switch_to_it);
2156 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2161 if (name.length() == 0) {
2162 name = _session->snap_name();
2165 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2170 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2175 ARDOUR_UI::primary_clock_value_changed ()
2178 _session->request_locate (primary_clock.current_time ());
2183 ARDOUR_UI::big_clock_value_changed ()
2186 _session->request_locate (big_clock.current_time ());
2191 ARDOUR_UI::secondary_clock_value_changed ()
2194 _session->request_locate (secondary_clock.current_time ());
2199 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2201 if (_session == 0) {
2205 if (_session->step_editing()) {
2209 Session::RecordState const r = _session->record_status ();
2210 bool const h = _session->have_rec_enabled_track ();
2212 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2214 rec_button.set_visual_state (2);
2216 rec_button.set_visual_state (0);
2218 } else if (r == Session::Recording && h) {
2219 rec_button.set_visual_state (1);
2221 rec_button.set_visual_state (0);
2226 ARDOUR_UI::save_template ()
2228 ArdourPrompter prompter (true);
2231 if (!check_audioengine()) {
2235 prompter.set_name (X_("Prompter"));
2236 prompter.set_title (_("Save Template"));
2237 prompter.set_prompt (_("Name for template:"));
2238 prompter.set_initial_text(_session->name() + _("-template"));
2239 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2241 switch (prompter.run()) {
2242 case RESPONSE_ACCEPT:
2243 prompter.get_result (name);
2245 if (name.length()) {
2246 _session->save_template (name);
2256 ARDOUR_UI::edit_metadata ()
2258 SessionMetadataEditor dialog;
2259 dialog.set_session (_session);
2260 editor->ensure_float (dialog);
2265 ARDOUR_UI::import_metadata ()
2267 SessionMetadataImporter dialog;
2268 dialog.set_session (_session);
2269 editor->ensure_float (dialog);
2274 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2276 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2278 MessageDialog msg (str,
2280 Gtk::MESSAGE_WARNING,
2281 Gtk::BUTTONS_YES_NO,
2285 msg.set_name (X_("OpenExistingDialog"));
2286 msg.set_title (_("Open Existing Session"));
2287 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2288 msg.set_position (Gtk::WIN_POS_MOUSE);
2291 switch (msg.run()) {
2300 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2302 BusProfile bus_profile;
2304 if (Profile->get_sae()) {
2306 bus_profile.master_out_channels = 2;
2307 bus_profile.input_ac = AutoConnectPhysical;
2308 bus_profile.output_ac = AutoConnectMaster;
2309 bus_profile.requested_physical_in = 0; // use all available
2310 bus_profile.requested_physical_out = 0; // use all available
2314 /* get settings from advanced section of NSD */
2316 if (_startup->create_master_bus()) {
2317 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2319 bus_profile.master_out_channels = 0;
2322 if (_startup->connect_inputs()) {
2323 bus_profile.input_ac = AutoConnectPhysical;
2325 bus_profile.input_ac = AutoConnectOption (0);
2328 /// @todo some minor tweaks.
2330 bus_profile.output_ac = AutoConnectOption (0);
2332 if (_startup->connect_outputs ()) {
2333 if (_startup->connect_outs_to_master()) {
2334 bus_profile.output_ac = AutoConnectMaster;
2335 } else if (_startup->connect_outs_to_physical()) {
2336 bus_profile.output_ac = AutoConnectPhysical;
2340 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2341 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2344 if (build_session (session_path, session_name, bus_profile)) {
2352 ARDOUR_UI::idle_load (const std::string& path)
2355 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2356 /* /path/to/foo => /path/to/foo, foo */
2357 load_session (path, basename_nosuffix (path));
2359 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2360 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2364 ARDOUR_COMMAND_LINE::session_name = path;
2367 * new_session_dialog doens't exist in A3
2368 * Try to remove all references to it to
2369 * see if it will compile. NOTE: this will
2370 * likely cause a runtime issue is my somewhat
2374 //if (new_session_dialog) {
2377 /* make it break out of Dialog::run() and
2381 //new_session_dialog->response (1);
2387 ARDOUR_UI::end_loading_messages ()
2393 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2396 // splash->message (msg);
2400 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2402 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2404 string session_name;
2405 string session_path;
2406 string template_name;
2408 bool likely_new = false;
2410 if (!load_template.empty()) {
2411 should_be_new = true;
2412 template_name = load_template;
2417 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2419 /* if they named a specific statefile, use it, otherwise they are
2420 just giving a session folder, and we want to use it as is
2421 to find the session.
2424 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2426 if (suffix != string::npos) {
2427 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2428 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2429 session_name = Glib::path_get_basename (session_name);
2431 session_path = ARDOUR_COMMAND_LINE::session_name;
2432 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2437 bool const apply = run_startup (should_be_new, load_template);
2440 if (quit_on_cancel) {
2447 /* if we run the startup dialog again, offer more than just "new session" */
2449 should_be_new = false;
2451 session_name = _startup->session_name (likely_new);
2453 /* this shouldn't happen, but we catch it just in case it does */
2455 if (session_name.empty()) {
2459 if (_startup->use_session_template()) {
2460 template_name = _startup->session_template_name();
2461 _session_is_new = true;
2464 if (session_name[0] == G_DIR_SEPARATOR ||
2465 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2466 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2468 /* absolute path or cwd-relative path specified for session name: infer session folder
2469 from what was given.
2472 session_path = Glib::path_get_dirname (session_name);
2473 session_name = Glib::path_get_basename (session_name);
2477 session_path = _startup->session_folder();
2479 if (session_name.find ('/') != string::npos) {
2480 MessageDialog msg (*_startup,
2481 _("To ensure compatibility with various systems\n"
2482 "session names may not contain a '/' character"));
2484 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2488 if (session_name.find ('\\') != string::npos) {
2489 MessageDialog msg (*_startup,
2490 _("To ensure compatibility with various systems\n"
2491 "session names may not contain a '\\' character"));
2493 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2499 if (create_engine ()) {
2503 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2507 std::string existing = Glib::build_filename (session_path, session_name);
2509 if (!ask_about_loading_existing_session (existing)) {
2510 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2515 _session_is_new = false;
2520 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2522 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2526 if (session_name.find ('/') != std::string::npos) {
2527 MessageDialog msg (*_startup,
2528 _("To ensure compatibility with various systems\n"
2529 "session names may not contain a '/' character"));
2531 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2535 if (session_name.find ('\\') != std::string::npos) {
2536 MessageDialog msg (*_startup,
2537 _("To ensure compatibility with various systems\n"
2538 "session names may not contain a '\\' character"));
2540 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2544 _session_is_new = true;
2547 if (likely_new && template_name.empty()) {
2549 ret = build_session_from_nsd (session_path, session_name);
2553 ret = load_session (session_path, session_name, template_name);
2556 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
2560 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2561 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2571 ARDOUR_UI::close_session()
2573 if (!check_audioengine()) {
2577 if (unload_session (true)) {
2581 ARDOUR_COMMAND_LINE::session_name = "";
2583 if (get_session_parameters (true, false)) {
2587 goto_editor_window ();
2590 /** @param snap_name Snapshot name (without .ardour suffix).
2591 * @return -2 if the load failed because we are not connected to the AudioEngine.
2594 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2596 Session *new_session;
2600 session_loaded = false;
2602 if (!check_audioengine()) {
2606 unload_status = unload_session ();
2608 if (unload_status < 0) {
2610 } else if (unload_status > 0) {
2615 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
2618 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2621 /* this one is special */
2623 catch (AudioEngine::PortRegistrationFailure& err) {
2625 MessageDialog msg (err.what(),
2628 Gtk::BUTTONS_CLOSE);
2630 msg.set_title (_("Port Registration Error"));
2631 msg.set_secondary_text (_("Click the Close button to try again."));
2632 msg.set_position (Gtk::WIN_POS_CENTER);
2636 int response = msg.run ();
2641 case RESPONSE_CANCEL:
2651 MessageDialog msg (string_compose(
2652 _("Session \"%1 (snapshot %2)\" did not load successfully"),
2658 msg.set_title (_("Loading Error"));
2659 msg.set_secondary_text (_("Click the Refresh button to try again."));
2660 msg.add_button (Stock::REFRESH, 1);
2661 msg.set_position (Gtk::WIN_POS_CENTER);
2665 int response = msg.run ();
2680 list<string> const u = new_session->unknown_processors ();
2682 MissingPluginDialog d (_session, u);
2687 /* Now the session been created, add the transport controls */
2688 new_session->add_controllable(roll_controllable);
2689 new_session->add_controllable(stop_controllable);
2690 new_session->add_controllable(goto_start_controllable);
2691 new_session->add_controllable(goto_end_controllable);
2692 new_session->add_controllable(auto_loop_controllable);
2693 new_session->add_controllable(play_selection_controllable);
2694 new_session->add_controllable(rec_controllable);
2696 set_session (new_session);
2698 session_loaded = true;
2700 goto_editor_window ();
2703 _session->set_clean ();
2714 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2716 Session *new_session;
2719 if (!check_audioengine()) {
2723 session_loaded = false;
2725 x = unload_session ();
2733 _session_is_new = true;
2736 new_session = new Session (*engine, path, snap_name, &bus_profile);
2741 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2747 /* Give the new session the default GUI state, if such things exist */
2750 n = Config->instant_xml (X_("Editor"));
2752 new_session->add_instant_xml (*n, false);
2754 n = Config->instant_xml (X_("Mixer"));
2756 new_session->add_instant_xml (*n, false);
2759 /* Put the playhead at 0 and scroll fully left */
2760 n = new_session->instant_xml (X_("Editor"));
2762 n->add_property (X_("playhead"), X_("0"));
2763 n->add_property (X_("left-frame"), X_("0"));
2766 set_session (new_session);
2768 session_loaded = true;
2770 new_session->save_state(new_session->name());
2776 ARDOUR_UI::launch_chat ()
2779 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2781 open_uri("http://webchat.freenode.net/?channels=ardour");
2786 ARDOUR_UI::show_about ()
2790 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2793 about->set_transient_for(*editor);
2798 ARDOUR_UI::launch_manual ()
2800 PBD::open_uri("http://ardour.org/flossmanual");
2804 ARDOUR_UI::launch_reference ()
2806 PBD::open_uri("http://ardour.org/refmanual");
2810 ARDOUR_UI::hide_about ()
2813 about->get_window()->set_cursor ();
2819 ARDOUR_UI::about_signal_response (int /*response*/)
2825 ARDOUR_UI::show_splash ()
2829 splash = new Splash;
2837 splash->queue_draw ();
2838 splash->get_window()->process_updates (true);
2843 ARDOUR_UI::hide_splash ()
2851 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2852 const string& plural_msg, const string& singular_msg)
2856 removed = rep.paths.size();
2859 MessageDialog msgd (*editor,
2860 _("No files were ready for clean-up"),
2863 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2864 msgd.set_title (_("Clean-up"));
2865 msgd.set_secondary_text (_("If this seems suprising, \n\
2866 check for any existing snapshots.\n\
2867 These may still include regions that\n\
2868 require some unused files to continue to exist."));
2874 ArdourDialog results (_("Clean-up"), true, false);
2876 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2877 CleanupResultsModelColumns() {
2881 Gtk::TreeModelColumn<std::string> visible_name;
2882 Gtk::TreeModelColumn<std::string> fullpath;
2886 CleanupResultsModelColumns results_columns;
2887 Glib::RefPtr<Gtk::ListStore> results_model;
2888 Gtk::TreeView results_display;
2890 results_model = ListStore::create (results_columns);
2891 results_display.set_model (results_model);
2892 results_display.append_column (list_title, results_columns.visible_name);
2894 results_display.set_name ("CleanupResultsList");
2895 results_display.set_headers_visible (true);
2896 results_display.set_headers_clickable (false);
2897 results_display.set_reorderable (false);
2899 Gtk::ScrolledWindow list_scroller;
2902 Gtk::HBox dhbox; // the hbox for the image and text
2903 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2904 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2906 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2908 const string dead_directory = _session->session_directory().dead_path().to_string();
2911 %1 - number of files removed
2912 %2 - location of "dead"
2913 %3 - size of files affected
2914 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2917 const char* bprefix;
2918 double space_adjusted = 0;
2920 if (rep.space < 1000) {
2922 space_adjusted = rep.space;
2923 } else if (rep.space < 1000000) {
2924 bprefix = X_("kilo");
2925 space_adjusted = truncf((float)rep.space / 1000.0);
2926 } else if (rep.space < 1000000 * 1000) {
2927 bprefix = X_("mega");
2928 space_adjusted = truncf((float)rep.space / (1000.0 * 1000.0));
2930 bprefix = X_("giga");
2931 space_adjusted = truncf((float)rep.space / (1000.0 * 1000 * 1000.0));
2935 txt.set_text (string_compose (plural_msg, removed, dead_directory, space_adjusted, bprefix));
2937 txt.set_text (string_compose (singular_msg, removed, dead_directory, space_adjusted, bprefix));
2940 dhbox.pack_start (*dimage, true, false, 5);
2941 dhbox.pack_start (txt, true, false, 5);
2943 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2944 TreeModel::Row row = *(results_model->append());
2945 row[results_columns.visible_name] = *i;
2946 row[results_columns.fullpath] = *i;
2949 list_scroller.add (results_display);
2950 list_scroller.set_size_request (-1, 150);
2951 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2953 dvbox.pack_start (dhbox, true, false, 5);
2954 dvbox.pack_start (list_scroller, true, false, 5);
2955 ddhbox.pack_start (dvbox, true, false, 5);
2957 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2958 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2959 results.set_default_response (RESPONSE_CLOSE);
2960 results.set_position (Gtk::WIN_POS_MOUSE);
2962 results_display.show();
2963 list_scroller.show();
2970 //results.get_vbox()->show();
2971 results.set_resizable (false);
2978 ARDOUR_UI::cleanup ()
2980 if (_session == 0) {
2981 /* shouldn't happen: menu item is insensitive */
2986 MessageDialog checker (_("Are you sure you want to clean-up?"),
2988 Gtk::MESSAGE_QUESTION,
2989 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2991 checker.set_title (_("Clean-up"));
2993 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
2994 ALL undo/redo information will be lost if you clean-up.\n\
2995 Clean-up will move all unused files to a \"dead\" location."));
2997 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2998 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
2999 checker.set_default_response (RESPONSE_CANCEL);
3001 checker.set_name (_("CleanupDialog"));
3002 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3003 checker.set_position (Gtk::WIN_POS_MOUSE);
3005 switch (checker.run()) {
3006 case RESPONSE_ACCEPT:
3012 ARDOUR::CleanupReport rep;
3014 editor->prepare_for_cleanup ();
3016 /* do not allow flush until a session is reloaded */
3018 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3020 act->set_sensitive (false);
3023 if (_session->cleanup_sources (rep)) {
3024 editor->finish_cleanup ();
3028 editor->finish_cleanup ();
3031 display_cleanup_results (rep,
3034 The following %1 files were not in use and \n\
3035 have been moved to:\n\n\
3037 After a restart of Ardour,\n\n\
3038 Session -> Clean-up -> Flush Wastebasket\n\n\
3039 will release an additional\n\
3040 %3 %4bytes of disk space.\n"),
3042 The following file was not in use and \n\
3043 has been moved to:\n \
3045 After a restart of Ardour,\n\n\
3046 Session -> Clean-up -> Flush Wastebasket\n\n\
3047 will release an additional\n\
3048 %3 %4bytes of disk space.\n"
3054 ARDOUR_UI::flush_trash ()
3056 if (_session == 0) {
3057 /* shouldn't happen: menu item is insensitive */
3061 ARDOUR::CleanupReport rep;
3063 if (_session->cleanup_trash_sources (rep)) {
3067 display_cleanup_results (rep,
3069 _("The following %1 files were deleted from\n\
3071 releasing %3 %4bytes of disk space"),
3072 _("The following file was deleted from\n\
3074 releasing %3 %4bytes of disk space"));
3078 ARDOUR_UI::add_route (Gtk::Window* float_window)
3086 if (add_route_dialog == 0) {
3087 add_route_dialog = new AddRouteDialog (_session);
3089 add_route_dialog->set_transient_for (*float_window);
3093 if (add_route_dialog->is_visible()) {
3094 /* we're already doing this */
3098 ResponseType r = (ResponseType) add_route_dialog->run ();
3100 add_route_dialog->hide();
3103 case RESPONSE_ACCEPT:
3110 if ((count = add_route_dialog->count()) <= 0) {
3114 string template_path = add_route_dialog->track_template();
3116 if (!template_path.empty()) {
3117 _session->new_route_from_template (count, template_path);
3121 uint32_t input_chan = add_route_dialog->channels ();
3122 uint32_t output_chan;
3123 string name_template = add_route_dialog->name_template ();
3124 bool track = add_route_dialog->track ();
3125 RouteGroup* route_group = add_route_dialog->route_group ();
3127 AutoConnectOption oac = Config->get_output_auto_connect();
3129 if (oac & AutoConnectMaster) {
3130 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3132 output_chan = input_chan;
3135 /* XXX do something with name template */
3137 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3139 session_add_midi_track (route_group, count, name_template);
3141 MessageDialog msg (*editor,
3142 _("Sorry, MIDI Busses are not supported at this time."));
3144 //session_add_midi_bus();
3148 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count, name_template);
3150 session_add_audio_bus (input_chan, output_chan, route_group, count, name_template);
3156 ARDOUR_UI::mixer_settings () const
3161 node = _session->instant_xml(X_("Mixer"));
3163 node = Config->instant_xml(X_("Mixer"));
3167 node = new XMLNode (X_("Mixer"));
3174 ARDOUR_UI::editor_settings () const
3179 node = _session->instant_xml(X_("Editor"));
3181 node = Config->instant_xml(X_("Editor"));
3185 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3186 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3191 node = new XMLNode (X_("Editor"));
3198 ARDOUR_UI::keyboard_settings () const
3202 node = Config->extra_xml(X_("Keyboard"));
3205 node = new XMLNode (X_("Keyboard"));
3212 ARDOUR_UI::create_xrun_marker (framepos_t where)
3214 editor->mouse_add_new_marker (where, false, true);
3218 ARDOUR_UI::halt_on_xrun_message ()
3220 MessageDialog msg (*editor,
3221 _("Recording was stopped because your system could not keep up."));
3226 ARDOUR_UI::xrun_handler (framepos_t where)
3232 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3234 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3235 create_xrun_marker(where);
3238 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3239 halt_on_xrun_message ();
3244 ARDOUR_UI::disk_overrun_handler ()
3246 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3248 if (!have_disk_speed_dialog_displayed) {
3249 have_disk_speed_dialog_displayed = true;
3250 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3251 The disk system on your computer\n\
3252 was not able to keep up with %1.\n\
3254 Specifically, it failed to write data to disk\n\
3255 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3256 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3262 ARDOUR_UI::disk_underrun_handler ()
3264 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3266 if (!have_disk_speed_dialog_displayed) {
3267 have_disk_speed_dialog_displayed = true;
3268 MessageDialog* msg = new MessageDialog (
3269 *editor, string_compose (_("The disk system on your computer\n\
3270 was not able to keep up with %1.\n\
3272 Specifically, it failed to read data from disk\n\
3273 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3274 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3280 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3282 have_disk_speed_dialog_displayed = false;
3287 ARDOUR_UI::session_dialog (std::string msg)
3289 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3294 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3296 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3305 ARDOUR_UI::pending_state_dialog ()
3307 HBox* hbox = new HBox();
3308 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3309 ArdourDialog dialog (_("Crash Recovery"), true);
3311 This session appears to have been in\n\
3312 middle of recording when ardour or\n\
3313 the computer was shutdown.\n\
3315 Ardour can recover any captured audio for\n\
3316 you, or it can ignore it. Please decide\n\
3317 what you would like to do.\n"));
3318 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3319 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3320 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3321 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3322 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3323 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3324 dialog.set_default_response (RESPONSE_ACCEPT);
3325 dialog.set_position (WIN_POS_CENTER);
3330 switch (dialog.run ()) {
3331 case RESPONSE_ACCEPT:
3339 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3341 HBox* hbox = new HBox();
3342 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3343 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3344 Label message (string_compose (_("\
3345 This session was created with a sample rate of %1 Hz\n\
3347 The audioengine is currently running at %2 Hz\n"), desired, actual));
3349 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3350 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3351 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3352 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3353 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3354 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3355 dialog.set_default_response (RESPONSE_ACCEPT);
3356 dialog.set_position (WIN_POS_CENTER);
3361 switch (dialog.run ()) {
3362 case RESPONSE_ACCEPT:
3371 ARDOUR_UI::disconnect_from_jack ()
3374 if( engine->disconnect_from_jack ()) {
3375 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3379 update_sample_rate (0);
3384 ARDOUR_UI::reconnect_to_jack ()
3387 if (engine->reconnect_to_jack ()) {
3388 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3392 update_sample_rate (0);
3397 ARDOUR_UI::use_config ()
3399 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3401 set_transport_controllable_state (*node);
3406 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3408 if (Config->get_primary_clock_delta_edit_cursor()) {
3409 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3411 primary_clock.set (pos, 0, true);
3414 if (Config->get_secondary_clock_delta_edit_cursor()) {
3415 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3417 secondary_clock.set (pos);
3420 if (big_clock_window->get()) {
3421 big_clock.set (pos);
3427 ARDOUR_UI::step_edit_status_change (bool yn)
3429 // XXX should really store pre-step edit status of things
3430 // we make insensitive
3433 rec_button.set_visual_state (3);
3434 rec_button.set_sensitive (false);
3436 rec_button.set_visual_state (0);
3437 rec_button.set_sensitive (true);
3442 ARDOUR_UI::record_state_changed ()
3444 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3446 if (!_session || !big_clock_window->get()) {
3447 /* why bother - the clock isn't visible */
3451 Session::RecordState const r = _session->record_status ();
3452 bool const h = _session->have_rec_enabled_track ();
3454 if (r == Session::Recording && h) {
3455 big_clock.set_widget_name ("BigClockRecording");
3457 big_clock.set_widget_name ("BigClockNonRecording");
3462 ARDOUR_UI::first_idle ()
3465 _session->allow_auto_play (true);
3469 editor->first_idle();
3472 Keyboard::set_can_save_keybindings (true);
3477 ARDOUR_UI::store_clock_modes ()
3479 XMLNode* node = new XMLNode(X_("ClockModes"));
3481 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3482 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3485 _session->add_extra_xml (*node);
3486 _session->set_dirty ();
3491 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3492 : Controllable (name), ui (u), type(tp)
3498 ARDOUR_UI::TransportControllable::set_value (double val)
3501 /* do nothing: these are radio-style actions */
3505 const char *action = 0;
3509 action = X_("Roll");
3512 action = X_("Stop");
3515 action = X_("Goto Start");
3518 action = X_("Goto End");
3521 action = X_("Loop");
3524 action = X_("Play Selection");
3527 action = X_("Record");
3537 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3545 ARDOUR_UI::TransportControllable::get_value (void) const
3572 ARDOUR_UI::TransportControllable::set_id (const string& str)
3578 ARDOUR_UI::setup_profile ()
3580 if (gdk_screen_width() < 1200) {
3581 Profile->set_small_screen ();
3585 if (getenv ("ARDOUR_SAE")) {
3586 Profile->set_sae ();
3587 Profile->set_single_package ();
3592 ARDOUR_UI::toggle_translations ()
3594 using namespace Glib;
3596 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3598 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3601 string i18n_killer = ARDOUR::translation_kill_path();
3603 bool already_enabled = !ARDOUR::translations_are_disabled ();
3605 if (ract->get_active ()) {
3606 /* we don't care about errors */
3607 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3610 /* we don't care about errors */
3611 unlink (i18n_killer.c_str());
3614 if (already_enabled != ract->get_active()) {
3615 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3617 Gtk::MESSAGE_WARNING,
3619 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3620 win.set_position (Gtk::WIN_POS_CENTER);
3628 /** Add a window proxy to our list, so that its state will be saved.
3629 * This call also causes the window to be created and opened if its
3630 * state was saved as `visible'.
3633 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3635 _window_proxies.push_back (p);
3639 /** Remove a window proxy from our list. Must be called if a WindowProxy
3640 * is deleted, to prevent hanging pointers.
3643 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3645 _window_proxies.remove (p);
3649 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3651 MissingFileDialog dialog (s, str, type);
3656 int result = dialog.run ();
3663 return 1; // quit entire session load
3666 result = dialog.get_action ();
3672 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3674 AmbiguousFileDialog dialog (file, hits);
3680 return dialog.get_which ();