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/gtk_ui.h"
53 #include "gtkmm2ext/utils.h"
54 #include "gtkmm2ext/click_box.h"
55 #include "gtkmm2ext/fastmeter.h"
56 #include "gtkmm2ext/popup.h"
57 #include "gtkmm2ext/window_title.h"
59 #include "midi++/manager.h"
61 #include "ardour/ardour.h"
62 #include "ardour/callback.h"
63 #include "ardour/profile.h"
64 #include "ardour/session_directory.h"
65 #include "ardour/session_route.h"
66 #include "ardour/session_state_utils.h"
67 #include "ardour/session_utils.h"
68 #include "ardour/port.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/playlist.h"
71 #include "ardour/utils.h"
72 #include "ardour/audio_diskstream.h"
73 #include "ardour/audiofilesource.h"
74 #include "ardour/recent_sessions.h"
75 #include "ardour/port.h"
76 #include "ardour/audio_track.h"
77 #include "ardour/midi_track.h"
78 #include "ardour/filesystem_paths.h"
79 #include "ardour/filename_extensions.h"
81 typedef uint64_t microseconds_t;
84 #include "ardour_ui.h"
85 #include "public_editor.h"
86 #include "audio_clock.h"
91 #include "add_route_dialog.h"
95 #include "gui_thread.h"
96 #include "theme_manager.h"
97 #include "bundle_manager.h"
98 #include "session_metadata_dialog.h"
99 #include "gain_meter.h"
100 #include "route_time_axis.h"
102 #include "engine_dialog.h"
103 #include "processor_box.h"
104 #include "time_axis_view_item.h"
105 #include "window_proxy.h"
106 #include "global_port_matrix.h"
107 #include "location_ui.h"
108 #include "missing_file_dialog.h"
109 #include "missing_plugin_dialog.h"
110 #include "ambiguous_file_dialog.h"
114 using namespace ARDOUR;
116 using namespace Gtkmm2ext;
119 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
120 UIConfiguration *ARDOUR_UI::ui_config = 0;
122 sigc::signal<void,bool> ARDOUR_UI::Blink;
123 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
124 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
125 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
127 bool could_be_a_valid_path (const string& path);
129 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
131 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
133 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
134 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
135 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
136 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
140 preroll_button (_("pre\nroll")),
141 postroll_button (_("post\nroll")),
145 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
149 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
150 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
151 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
152 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
153 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
154 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
155 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
156 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
157 shuttle_controller_binding_proxy (shuttle_controllable),
159 roll_button (roll_controllable),
160 stop_button (stop_controllable),
161 goto_start_button (goto_start_controllable),
162 goto_end_button (goto_end_controllable),
163 auto_loop_button (auto_loop_controllable),
164 play_selection_button (play_selection_controllable),
165 rec_button (rec_controllable),
167 shuttle_units_button (_("% ")),
169 punch_in_button (_("Punch In")),
170 punch_out_button (_("Punch Out")),
171 auto_return_button (_("Auto Return")),
172 auto_play_button (_("Auto Play")),
173 auto_input_button (_("Auto Input")),
174 click_button (_("Click")),
175 time_master_button (_("time\nmaster")),
177 auditioning_alert_button (_("AUDITION")),
178 solo_alert_button (_("SOLO")),
180 error_log_button (_("Errors"))
183 using namespace Gtk::Menu_Helpers;
189 // _auto_display_errors = false;
191 * This was commented out as it wasn't defined
192 * in A3 IIRC. If this is not needed it should
193 * be completely removed.
201 if (theArdourUI == 0) {
205 ui_config = new UIConfiguration();
206 theme_manager = new ThemeManager();
212 _session_is_new = false;
213 big_clock_window = 0;
214 big_clock_height = 0;
215 big_clock_resize_in_progress = false;
216 session_selector_window = 0;
217 last_key_press_time = 0;
218 _will_create_new_session_automatically = false;
219 add_route_dialog = 0;
221 rc_option_editor = 0;
222 session_option_editor = 0;
224 open_session_selector = 0;
225 have_configure_timeout = false;
226 have_disk_speed_dialog_displayed = false;
227 session_loaded = false;
228 last_speed_displayed = -1.0f;
229 ignore_dual_punch = false;
230 original_big_clock_width = -1;
231 original_big_clock_height = -1;
232 original_big_clock_font_size = 0;
234 roll_button.unset_flags (Gtk::CAN_FOCUS);
235 stop_button.unset_flags (Gtk::CAN_FOCUS);
236 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
237 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
238 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
239 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
240 rec_button.unset_flags (Gtk::CAN_FOCUS);
242 last_configure_time= 0;
244 shuttle_grabbed = false;
246 shuttle_max_speed = 8.0f;
248 shuttle_style_menu = 0;
249 shuttle_unit_menu = 0;
251 // We do not have jack linked in yet so;
253 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
255 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
256 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
258 /* handle dialog requests */
260 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
262 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
264 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
266 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
268 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
270 /* handle requests to quit (coming from JACK session) */
272 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
274 /* handle requests to deal with missing files */
276 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
278 /* and ambiguous files */
280 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2, _3));
282 /* lets get this party started */
285 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
286 throw failed_constructor ();
289 setup_gtk_ardour_enums ();
292 GainMeter::setup_slider_pix ();
293 RouteTimeAxisView::setup_slider_pix ();
294 SendProcessorEntry::setup_slider_pix ();
295 SessionEvent::create_per_thread_pool ("GUI", 512);
297 } catch (failed_constructor& err) {
298 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
303 /* we like keyboards */
305 keyboard = new ArdourKeyboard(*this);
307 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
309 keyboard->set_state (*node, Stateful::loading_state_version);
314 TimeAxisViewItem::set_constant_heights ();
316 /* The following must happen after ARDOUR::init() so that Config is set up */
318 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
319 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
321 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
322 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
323 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
324 Config->extra_xml (X_("UI")),
325 string_compose ("toggle-%1-connection-manager", (*i).to_string())
331 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
332 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
337 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
339 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
342 _startup = new ArdourStartup ();
344 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
346 if (audio_setup && _startup->engine_control()) {
347 _startup->engine_control()->set_state (*audio_setup);
350 _startup->set_new_only (should_be_new);
351 if (!load_template.empty()) {
352 _startup->set_load_template( load_template );
354 _startup->present ();
360 switch (_startup->response()) {
369 ARDOUR_UI::create_engine ()
371 // this gets called every time by new_session()
377 loading_message (_("Starting audio engine"));
380 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
387 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
388 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
389 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
391 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
393 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
401 ARDOUR_UI::post_engine ()
403 /* Things to be done once we create the AudioEngine
406 ARDOUR::init_post_engine ();
408 ActionManager::init ();
411 if (setup_windows ()) {
412 throw failed_constructor ();
415 check_memory_locking();
417 /* this is the first point at which all the keybindings are available */
419 if (ARDOUR_COMMAND_LINE::show_key_actions) {
420 vector<string> names;
421 vector<string> paths;
423 vector<AccelKey> bindings;
425 ActionManager::get_all_actions (names, paths, keys, bindings);
427 vector<string>::iterator n;
428 vector<string>::iterator k;
429 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
430 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
436 blink_timeout_tag = -1;
438 /* this being a GUI and all, we want peakfiles */
440 AudioFileSource::set_build_peakfiles (true);
441 AudioFileSource::set_build_missing_peakfiles (true);
443 /* set default clock modes */
445 if (Profile->get_sae()) {
446 primary_clock.set_mode (AudioClock::BBT);
447 secondary_clock.set_mode (AudioClock::MinSec);
449 primary_clock.set_mode (AudioClock::Timecode);
450 secondary_clock.set_mode (AudioClock::BBT);
453 /* start the time-of-day-clock */
456 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
457 update_wall_clock ();
458 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
461 update_disk_space ();
463 update_sample_rate (engine->frame_rate());
465 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
466 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
467 Config->map_parameters (pc);
469 /* now start and maybe save state */
471 if (do_engine_start () == 0) {
472 if (_session && _session_is_new) {
473 /* we need to retain initial visual
474 settings for a new session
476 _session->save_state ("");
481 ARDOUR_UI::~ARDOUR_UI ()
486 delete add_route_dialog;
490 ARDOUR_UI::pop_back_splash ()
492 if (Splash::instance()) {
493 // Splash::instance()->pop_back();
494 Splash::instance()->hide ();
499 ARDOUR_UI::configure_timeout ()
501 if (last_configure_time == 0) {
502 /* no configure events yet */
506 /* force a gap of 0.5 seconds since the last configure event
509 if (get_microseconds() - last_configure_time < 500000) {
512 have_configure_timeout = false;
513 cerr << "config event-driven save\n";
514 save_ardour_state ();
520 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
522 if (have_configure_timeout) {
523 last_configure_time = get_microseconds();
525 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
526 have_configure_timeout = true;
533 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
535 const XMLProperty* prop;
537 if ((prop = node.property ("roll")) != 0) {
538 roll_controllable->set_id (prop->value());
540 if ((prop = node.property ("stop")) != 0) {
541 stop_controllable->set_id (prop->value());
543 if ((prop = node.property ("goto-start")) != 0) {
544 goto_start_controllable->set_id (prop->value());
546 if ((prop = node.property ("goto-end")) != 0) {
547 goto_end_controllable->set_id (prop->value());
549 if ((prop = node.property ("auto-loop")) != 0) {
550 auto_loop_controllable->set_id (prop->value());
552 if ((prop = node.property ("play-selection")) != 0) {
553 play_selection_controllable->set_id (prop->value());
555 if ((prop = node.property ("rec")) != 0) {
556 rec_controllable->set_id (prop->value());
558 if ((prop = node.property ("shuttle")) != 0) {
559 shuttle_controllable->set_id (prop->value());
564 ARDOUR_UI::get_transport_controllable_state ()
566 XMLNode* node = new XMLNode(X_("TransportControllables"));
569 roll_controllable->id().print (buf, sizeof (buf));
570 node->add_property (X_("roll"), buf);
571 stop_controllable->id().print (buf, sizeof (buf));
572 node->add_property (X_("stop"), buf);
573 goto_start_controllable->id().print (buf, sizeof (buf));
574 node->add_property (X_("goto_start"), buf);
575 goto_end_controllable->id().print (buf, sizeof (buf));
576 node->add_property (X_("goto_end"), buf);
577 auto_loop_controllable->id().print (buf, sizeof (buf));
578 node->add_property (X_("auto_loop"), buf);
579 play_selection_controllable->id().print (buf, sizeof (buf));
580 node->add_property (X_("play_selection"), buf);
581 rec_controllable->id().print (buf, sizeof (buf));
582 node->add_property (X_("rec"), buf);
583 shuttle_controllable->id().print (buf, sizeof (buf));
584 node->add_property (X_("shuttle"), buf);
591 ARDOUR_UI::autosave_session ()
593 if (g_main_depth() > 1) {
594 /* inside a recursive main loop,
595 give up because we may not be able to
601 if (!Config->get_periodic_safety_backups()) {
606 _session->maybe_write_autosave();
613 ARDOUR_UI::update_autosave ()
615 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
617 if (_session && _session->dirty()) {
618 if (_autosave_connection.connected()) {
619 _autosave_connection.disconnect();
622 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
623 Config->get_periodic_safety_backup_interval() * 1000);
626 if (_autosave_connection.connected()) {
627 _autosave_connection.disconnect();
633 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
637 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
639 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
642 MessageDialog win (title,
648 win.set_secondary_text(_("There are several possible reasons:\n\
650 1) You requested audio parameters that are not supported..\n\
651 2) JACK is running as another user.\n\
653 Please consider the possibilities, and perhaps try different parameters."));
655 win.set_secondary_text(_("There are several possible reasons:\n\
657 1) JACK is not running.\n\
658 2) JACK is running as another user, perhaps root.\n\
659 3) There is already another client called \"ardour\".\n\
661 Please consider the possibilities, and perhaps (re)start JACK."));
665 win.set_transient_for (*toplevel);
669 win.add_button (Stock::OK, RESPONSE_CLOSE);
671 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
674 win.set_default_response (RESPONSE_CLOSE);
677 win.set_position (Gtk::WIN_POS_CENTER);
680 /* we just don't care about the result, but we want to block */
686 ARDOUR_UI::startup ()
688 Application* app = Application::instance ();
690 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
691 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
694 call_the_mothership (VERSIONSTRING);
699 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
705 goto_editor_window ();
707 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
708 to be opened on top of the editor window that goto_editor_window() just opened.
710 add_window_proxy (location_ui);
711 add_window_proxy (big_clock_window);
712 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
713 add_window_proxy (_global_port_matrix[*i]);
716 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
720 ARDOUR_UI::no_memory_warning ()
722 XMLNode node (X_("no-memory-warning"));
723 Config->add_instant_xml (node);
727 ARDOUR_UI::check_memory_locking ()
730 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
734 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
736 if (engine->is_realtime() && memory_warning_node == 0) {
738 struct rlimit limits;
740 long pages, page_size;
742 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
745 ram = (int64_t) pages * (int64_t) page_size;
748 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
752 if (limits.rlim_cur != RLIM_INFINITY) {
754 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
758 string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
759 "This might cause %1 to run out of memory before your system "
760 "runs out of memory. \n\n"
761 "You can view the memory limit with 'ulimit -l', "
762 "and it is normally controlled by /etc/security/limits.conf"),
763 PROGRAM_NAME).c_str());
765 VBox* vbox = msg.get_vbox();
767 CheckButton cb (_("Do not show this window again"));
769 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
771 hbox.pack_start (cb, true, false);
772 vbox->pack_start (hbox);
779 editor->ensure_float (msg);
789 ARDOUR_UI::queue_finish ()
791 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
795 ARDOUR_UI::idle_finish ()
798 return false; /* do not call again */
807 if (_session->transport_rolling() && (++tries < 8)) {
808 _session->request_stop (false, true);
812 if (_session->dirty()) {
813 switch (ask_about_saving_session(_("quit"))) {
818 /* use the default name */
819 if (save_state_canfail ("")) {
820 /* failed - don't quit */
821 MessageDialog msg (*editor,
823 Ardour was unable to save your session.\n\n\
824 If you still wish to quit, please use the\n\n\
825 \"Just quit\" option."));
836 second_connection.disconnect ();
837 point_one_second_connection.disconnect ();
838 point_oh_five_second_connection.disconnect ();
839 point_zero_one_second_connection.disconnect();
842 /* Save state before deleting the session, as that causes some
843 windows to be destroyed before their visible state can be
846 save_ardour_state ();
849 // _session->set_deletion_in_progress ();
850 _session->set_clean ();
851 _session->remove_pending_capture_state ();
856 ArdourDialog::close_all_dialogs ();
862 ARDOUR_UI::ask_about_saving_session (const string & what)
864 ArdourDialog window (_("Unsaved Session"));
865 Gtk::HBox dhbox; // the hbox for the image and text
866 Gtk::Label prompt_label;
867 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
871 msg = string_compose(_("Don't %1"), what);
872 window.add_button (msg, RESPONSE_REJECT);
873 msg = string_compose(_("Just %1"), what);
874 window.add_button (msg, RESPONSE_APPLY);
875 msg = string_compose(_("Save and %1"), what);
876 window.add_button (msg, RESPONSE_ACCEPT);
878 window.set_default_response (RESPONSE_ACCEPT);
880 Gtk::Button noquit_button (msg);
881 noquit_button.set_name ("EditorGTKButton");
886 if (_session->snap_name() == _session->name()) {
889 type = _("snapshot");
891 prompt = string_compose(_("The %1 \"%2\"\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 type, _session->snap_name());
894 prompt_label.set_text (prompt);
895 prompt_label.set_name (X_("PrompterLabel"));
896 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
898 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
899 dhbox.set_homogeneous (false);
900 dhbox.pack_start (*dimage, false, false, 5);
901 dhbox.pack_start (prompt_label, true, false, 5);
902 window.get_vbox()->pack_start (dhbox);
904 window.set_name (_("Prompter"));
905 window.set_position (Gtk::WIN_POS_MOUSE);
906 window.set_modal (true);
907 window.set_resizable (false);
913 window.set_keep_above (true);
916 ResponseType r = (ResponseType) window.run();
921 case RESPONSE_ACCEPT: // save and get out of here
923 case RESPONSE_APPLY: // get out of here
933 ARDOUR_UI::every_second ()
936 update_buffer_load ();
937 update_disk_space ();
942 ARDOUR_UI::every_point_one_seconds ()
944 update_speed_display ();
945 RapidScreenUpdate(); /* EMIT_SIGNAL */
950 ARDOUR_UI::every_point_zero_one_seconds ()
952 // august 2007: actual update frequency: 40Hz, not 100Hz
954 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
959 ARDOUR_UI::update_sample_rate (framecnt_t)
963 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
965 if (!engine->connected()) {
967 snprintf (buf, sizeof (buf), _("disconnected"));
971 framecnt_t rate = engine->frame_rate();
973 if (fmod (rate, 1000.0) != 0.0) {
974 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
975 (float) rate/1000.0f,
976 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
978 snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"),
980 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
984 sample_rate_label.set_text (buf);
988 ARDOUR_UI::update_cpu_load ()
991 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
992 cpu_load_label.set_text (buf);
996 ARDOUR_UI::update_buffer_load ()
1002 c = _session->capture_load ();
1003 p = _session->playback_load ();
1005 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
1006 _session->playback_load(), _session->capture_load());
1007 buffer_load_label.set_text (buf);
1009 buffer_load_label.set_text ("");
1014 ARDOUR_UI::count_recenabled_streams (Route& route)
1016 Track* track = dynamic_cast<Track*>(&route);
1017 if (track && track->record_enabled()) {
1018 rec_enabled_streams += track->n_inputs().n_total();
1023 ARDOUR_UI::update_disk_space()
1025 if (_session == 0) {
1029 framecnt_t frames = _session->available_capture_duration();
1031 framecnt_t fr = _session->frame_rate();
1033 if (frames == max_framecnt) {
1034 strcpy (buf, _("Disk: 24hrs+"));
1036 rec_enabled_streams = 0;
1037 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1039 if (rec_enabled_streams) {
1040 frames /= rec_enabled_streams;
1047 hrs = frames / (fr * 3600);
1048 frames -= hrs * fr * 3600;
1049 mins = frames / (fr * 60);
1050 frames -= mins * fr * 60;
1053 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1056 disk_space_label.set_text (buf);
1058 // An attempt to make the disk space label flash red when space has run out.
1060 if (frames < fr * 60 * 5) {
1061 /* disk_space_box.style ("disk_space_label_empty"); */
1063 /* disk_space_box.style ("disk_space_label"); */
1069 ARDOUR_UI::update_wall_clock ()
1076 tm_now = localtime (&now);
1078 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1079 wall_clock_label.set_text (buf);
1085 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1087 session_popup_menu->popup (0, 0);
1092 ARDOUR_UI::redisplay_recent_sessions ()
1094 std::vector<sys::path> session_directories;
1095 RecentSessionsSorter cmp;
1097 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1098 recent_session_model->clear ();
1100 ARDOUR::RecentSessions rs;
1101 ARDOUR::read_recent_sessions (rs);
1104 recent_session_display.set_model (recent_session_model);
1108 // sort them alphabetically
1109 sort (rs.begin(), rs.end(), cmp);
1111 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1112 session_directories.push_back ((*i).second);
1115 for (vector<sys::path>::const_iterator i = session_directories.begin();
1116 i != session_directories.end(); ++i)
1118 std::vector<sys::path> state_file_paths;
1120 // now get available states for this session
1122 get_state_files_in_directory (*i, state_file_paths);
1124 vector<string*>* states;
1125 vector<const gchar*> item;
1126 string fullpath = (*i).to_string();
1128 /* remove any trailing / */
1130 if (fullpath[fullpath.length()-1] == '/') {
1131 fullpath = fullpath.substr (0, fullpath.length()-1);
1134 /* check whether session still exists */
1135 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1136 /* session doesn't exist */
1137 cerr << "skipping non-existent session " << fullpath << endl;
1141 /* now get available states for this session */
1143 if ((states = Session::possible_states (fullpath)) == 0) {
1144 /* no state file? */
1148 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1150 Gtk::TreeModel::Row row = *(recent_session_model->append());
1152 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1153 row[recent_session_columns.fullpath] = fullpath;
1155 if (state_file_names.size() > 1) {
1159 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1160 i2 != state_file_names.end(); ++i2)
1163 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1165 child_row[recent_session_columns.visible_name] = *i2;
1166 child_row[recent_session_columns.fullpath] = fullpath;
1171 recent_session_display.set_model (recent_session_model);
1175 ARDOUR_UI::build_session_selector ()
1177 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1179 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1181 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1182 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1183 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1184 recent_session_model = TreeStore::create (recent_session_columns);
1185 recent_session_display.set_model (recent_session_model);
1186 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1187 recent_session_display.set_headers_visible (false);
1188 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1189 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1191 scroller->add (recent_session_display);
1192 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1194 session_selector_window->set_name ("SessionSelectorWindow");
1195 session_selector_window->set_size_request (200, 400);
1196 session_selector_window->get_vbox()->pack_start (*scroller);
1198 recent_session_display.show();
1200 //session_selector_window->get_vbox()->show();
1204 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1206 session_selector_window->response (RESPONSE_ACCEPT);
1210 ARDOUR_UI::open_recent_session ()
1212 bool can_return = (_session != 0);
1214 if (session_selector_window == 0) {
1215 build_session_selector ();
1218 redisplay_recent_sessions ();
1222 session_selector_window->set_position (WIN_POS_MOUSE);
1224 ResponseType r = (ResponseType) session_selector_window->run ();
1227 case RESPONSE_ACCEPT:
1231 session_selector_window->hide();
1238 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1242 session_selector_window->hide();
1244 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1246 if (i == recent_session_model->children().end()) {
1250 std::string path = (*i)[recent_session_columns.fullpath];
1251 std::string state = (*i)[recent_session_columns.visible_name];
1253 _session_is_new = false;
1255 if (load_session (path, state) == 0) {
1264 ARDOUR_UI::check_audioengine ()
1267 if (!engine->connected()) {
1268 MessageDialog msg (string_compose (_("%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)
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);
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 (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, RouteGroup* route_group, uint32_t how_many)
1375 list<boost::shared_ptr<AudioTrack> > tracks;
1378 if (_session == 0) {
1379 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1385 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1387 if (tracks.size() != how_many) {
1388 if (how_many == 1) {
1389 error << _("could not create a new audio track") << endmsg;
1391 error << string_compose (_("could only create %1 of %2 new audio %3"),
1392 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1398 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many);
1400 if (routes.size() != how_many) {
1401 if (how_many == 1) {
1402 error << _("could not create a new audio track") << endmsg;
1404 error << string_compose (_("could not create %1 new audio tracks"), how_many) << 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::do_transport_locate (framepos_t new_position, bool with_roll)
1424 framecnt_t _preroll = 0;
1427 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1428 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1430 if (new_position > _preroll) {
1431 new_position -= _preroll;
1436 _session->request_locate (new_position, with_roll);
1441 ARDOUR_UI::transport_goto_start ()
1444 _session->goto_start();
1446 /* force displayed area in editor to start no matter
1447 what "follow playhead" setting is.
1451 editor->center_screen (_session->current_start_frame ());
1457 ARDOUR_UI::transport_goto_zero ()
1460 _session->request_locate (0);
1462 /* force displayed area in editor to start no matter
1463 what "follow playhead" setting is.
1467 editor->reset_x_origin (0);
1473 ARDOUR_UI::transport_goto_wallclock ()
1475 if (_session && editor) {
1482 localtime_r (&now, &tmnow);
1484 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1485 frames += tmnow.tm_min * (60 * _session->frame_rate());
1486 frames += tmnow.tm_sec * _session->frame_rate();
1488 _session->request_locate (frames, _session->transport_rolling ());
1490 /* force displayed area in editor to start no matter
1491 what "follow playhead" setting is.
1495 editor->center_screen (frames);
1501 ARDOUR_UI::transport_goto_end ()
1504 framepos_t const frame = _session->current_end_frame();
1505 _session->request_locate (frame);
1507 /* force displayed area in editor to start no matter
1508 what "follow playhead" setting is.
1512 editor->center_screen (frame);
1518 ARDOUR_UI::transport_stop ()
1524 if (_session->is_auditioning()) {
1525 _session->cancel_audition ();
1529 _session->request_stop (false, true);
1533 ARDOUR_UI::transport_stop_and_forget_capture ()
1536 _session->request_stop (true, true);
1541 ARDOUR_UI::remove_last_capture()
1544 editor->remove_last_capture();
1549 ARDOUR_UI::transport_record (bool roll)
1553 switch (_session->record_status()) {
1554 case Session::Disabled:
1555 if (_session->ntracks() == 0) {
1556 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1560 _session->maybe_enable_record ();
1565 case Session::Recording:
1567 _session->request_stop();
1569 _session->disable_record (false, true);
1573 case Session::Enabled:
1574 _session->disable_record (false, true);
1577 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1581 ARDOUR_UI::transport_roll ()
1587 if (_session->is_auditioning()) {
1592 if (_session->config.get_external_sync()) {
1593 switch (_session->config.get_sync_source()) {
1597 /* transport controlled by the master */
1603 bool rolling = _session->transport_rolling();
1605 if (_session->get_play_loop()) {
1606 /* XXX it is not possible to just leave seamless loop and keep
1607 playing at present (nov 4th 2009)
1609 if (!Config->get_seamless_loop()) {
1610 _session->request_play_loop (false, true);
1612 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1613 /* stop playing a range if we currently are */
1614 _session->request_play_range (0, true);
1617 if (join_play_range_button.get_active()) {
1618 _session->request_play_range (&editor->get_selection().time, true);
1622 _session->request_transport_speed (1.0f);
1627 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1634 if (_session->is_auditioning()) {
1635 _session->cancel_audition ();
1640 if (_session->config.get_external_sync()) {
1641 switch (_session->config.get_sync_source()) {
1645 /* transport controlled by the master */
1651 bool rolling = _session->transport_rolling();
1652 bool affect_transport = true;
1654 if (rolling && roll_out_of_bounded_mode) {
1655 /* drop out of loop/range playback but leave transport rolling */
1656 if (_session->get_play_loop()) {
1657 if (Config->get_seamless_loop()) {
1658 /* the disk buffers contain copies of the loop - we can't
1659 just keep playing, so stop the transport. the user
1660 can restart as they wish.
1662 affect_transport = true;
1664 /* disk buffers are normal, so we can keep playing */
1665 affect_transport = false;
1667 _session->request_play_loop (false, true);
1668 } else if (_session->get_play_range ()) {
1669 affect_transport = false;
1670 _session->request_play_range (0, true);
1674 if (affect_transport) {
1676 _session->request_stop (with_abort, true);
1678 if (join_play_range_button.get_active()) {
1679 _session->request_play_range (&editor->get_selection().time, true);
1682 _session->request_transport_speed (1.0f);
1688 ARDOUR_UI::toggle_session_auto_loop ()
1694 if (_session->get_play_loop()) {
1696 if (_session->transport_rolling()) {
1698 Location * looploc = _session->locations()->auto_loop_location();
1701 _session->request_locate (looploc->start(), true);
1702 _session->request_play_loop (false);
1706 _session->request_play_loop (false);
1710 Location * looploc = _session->locations()->auto_loop_location();
1713 _session->request_play_loop (true);
1719 ARDOUR_UI::transport_play_selection ()
1725 editor->play_selection ();
1729 ARDOUR_UI::transport_rewind (int option)
1731 float current_transport_speed;
1734 current_transport_speed = _session->transport_speed();
1736 if (current_transport_speed >= 0.0f) {
1739 _session->request_transport_speed (-1.0f);
1742 _session->request_transport_speed (-4.0f);
1745 _session->request_transport_speed (-0.5f);
1750 _session->request_transport_speed (current_transport_speed * 1.5f);
1756 ARDOUR_UI::transport_forward (int option)
1758 float current_transport_speed;
1761 current_transport_speed = _session->transport_speed();
1763 if (current_transport_speed <= 0.0f) {
1766 _session->request_transport_speed (1.0f);
1769 _session->request_transport_speed (4.0f);
1772 _session->request_transport_speed (0.5f);
1777 _session->request_transport_speed (current_transport_speed * 1.5f);
1784 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1786 if (_session == 0) {
1790 boost::shared_ptr<Route> r;
1792 if ((r = _session->route_by_remote_id (rid)) != 0) {
1796 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1797 t->set_record_enabled (!t->record_enabled(), this);
1800 if (_session == 0) {
1806 ARDOUR_UI::map_transport_state ()
1808 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1811 auto_loop_button.set_visual_state (0);
1812 play_selection_button.set_visual_state (0);
1813 roll_button.set_visual_state (0);
1814 stop_button.set_visual_state (1);
1818 float sp = _session->transport_speed();
1821 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1822 shuttle_box.queue_draw ();
1823 } else if (sp == 0.0f) {
1825 shuttle_box.queue_draw ();
1826 update_disk_space ();
1833 if (_session->get_play_range()) {
1835 play_selection_button.set_visual_state (1);
1836 roll_button.set_visual_state (0);
1837 auto_loop_button.set_visual_state (0);
1839 } else if (_session->get_play_loop ()) {
1841 auto_loop_button.set_visual_state (1);
1842 play_selection_button.set_visual_state (0);
1843 roll_button.set_visual_state (0);
1847 roll_button.set_visual_state (1);
1848 play_selection_button.set_visual_state (0);
1849 auto_loop_button.set_visual_state (0);
1852 if (join_play_range_button.get_active()) {
1853 /* light up both roll and play-selection if they are joined */
1854 roll_button.set_visual_state (1);
1855 play_selection_button.set_visual_state (1);
1858 stop_button.set_visual_state (0);
1862 stop_button.set_visual_state (1);
1863 roll_button.set_visual_state (0);
1864 play_selection_button.set_visual_state (0);
1865 auto_loop_button.set_visual_state (0);
1870 ARDOUR_UI::engine_stopped ()
1872 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1873 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1874 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1878 ARDOUR_UI::engine_running ()
1880 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1881 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1882 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1884 Glib::RefPtr<Action> action;
1885 const char* action_name = 0;
1887 switch (engine->frames_per_cycle()) {
1889 action_name = X_("JACKLatency32");
1892 action_name = X_("JACKLatency64");
1895 action_name = X_("JACKLatency128");
1898 action_name = X_("JACKLatency512");
1901 action_name = X_("JACKLatency1024");
1904 action_name = X_("JACKLatency2048");
1907 action_name = X_("JACKLatency4096");
1910 action_name = X_("JACKLatency8192");
1913 /* XXX can we do anything useful ? */
1919 action = ActionManager::get_action (X_("JACK"), action_name);
1922 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1923 ract->set_active ();
1929 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1931 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1932 /* we can't rely on the original string continuing to exist when we are called
1933 again in the GUI thread, so make a copy and note that we need to
1936 char *copy = strdup (reason);
1937 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1941 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1942 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1944 update_sample_rate (0);
1948 /* if the reason is a non-empty string, it means that the backend was shutdown
1949 rather than just Ardour.
1952 if (strlen (reason)) {
1953 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1955 msgstr = string_compose (_("\
1956 JACK has either been shutdown or it\n\
1957 disconnected %1 because %1\n\
1958 was not fast enough. Try to restart\n\
1959 JACK, reconnect and save the session."), PROGRAM_NAME);
1962 MessageDialog msg (*editor, msgstr);
1967 free ((char*) reason);
1972 ARDOUR_UI::do_engine_start ()
1980 error << _("Unable to start the session running")
1990 ARDOUR_UI::setup_theme ()
1992 theme_manager->setup_theme();
1996 ARDOUR_UI::update_clocks ()
1998 if (!editor || !editor->dragging_playhead()) {
1999 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
2004 ARDOUR_UI::start_clocking ()
2006 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2010 ARDOUR_UI::stop_clocking ()
2012 clock_signal_connection.disconnect ();
2016 ARDOUR_UI::toggle_clocking ()
2019 if (clock_button.get_active()) {
2028 ARDOUR_UI::_blink (void *arg)
2031 ((ARDOUR_UI *) arg)->blink ();
2038 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2042 ARDOUR_UI::start_blinking ()
2044 /* Start the blink signal. Everybody with a blinking widget
2045 uses Blink to drive the widget's state.
2048 if (blink_timeout_tag < 0) {
2050 blink_timeout_tag = g_timeout_add (240, _blink, this);
2055 ARDOUR_UI::stop_blinking ()
2057 if (blink_timeout_tag >= 0) {
2058 g_source_remove (blink_timeout_tag);
2059 blink_timeout_tag = -1;
2064 /** Ask the user for the name of a new shapshot and then take it.
2068 ARDOUR_UI::snapshot_session (bool switch_to_it)
2070 ArdourPrompter prompter (true);
2073 prompter.set_name ("Prompter");
2074 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2075 prompter.set_title (_("Take Snapshot"));
2076 prompter.set_title (_("Take Snapshot"));
2077 prompter.set_prompt (_("Name of new snapshot"));
2079 if (!switch_to_it) {
2082 struct tm local_time;
2085 localtime_r (&n, &local_time);
2086 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2087 prompter.set_initial_text (timebuf);
2091 switch (prompter.run()) {
2092 case RESPONSE_ACCEPT:
2094 prompter.get_result (snapname);
2096 bool do_save = (snapname.length() != 0);
2099 if (snapname.find ('/') != string::npos) {
2100 MessageDialog msg (_("To ensure compatibility with various systems\n"
2101 "snapshot names may not contain a '/' character"));
2105 if (snapname.find ('\\') != string::npos) {
2106 MessageDialog msg (_("To ensure compatibility with various systems\n"
2107 "snapshot names may not contain a '\\' character"));
2113 vector<sys::path> p;
2114 get_state_files_in_directory (_session->session_directory().root_path(), p);
2115 vector<string> n = get_file_names_no_extension (p);
2116 if (find (n.begin(), n.end(), snapname) != n.end()) {
2118 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2119 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2120 confirm.get_vbox()->pack_start (m, true, true);
2121 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2122 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2123 confirm.show_all ();
2124 switch (confirm.run()) {
2125 case RESPONSE_CANCEL:
2131 save_state (snapname, switch_to_it);
2142 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2144 XMLNode* node = new XMLNode (X_("UI"));
2146 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2147 if (!(*i)->rc_configured()) {
2148 node->add_child_nocopy (*((*i)->get_state ()));
2152 _session->add_extra_xml (*node);
2154 save_state_canfail (name, switch_to_it);
2158 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2163 if (name.length() == 0) {
2164 name = _session->snap_name();
2167 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2171 cerr << "SS canfail\n";
2172 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2177 ARDOUR_UI::primary_clock_value_changed ()
2180 _session->request_locate (primary_clock.current_time ());
2185 ARDOUR_UI::big_clock_value_changed ()
2188 _session->request_locate (big_clock.current_time ());
2193 ARDOUR_UI::secondary_clock_value_changed ()
2196 _session->request_locate (secondary_clock.current_time ());
2201 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2203 if (_session == 0) {
2207 if (_session->step_editing()) {
2211 Session::RecordState const r = _session->record_status ();
2212 bool const h = _session->have_rec_enabled_track ();
2214 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2216 rec_button.set_visual_state (2);
2218 rec_button.set_visual_state (0);
2220 } else if (r == Session::Recording && h) {
2221 rec_button.set_visual_state (1);
2223 rec_button.set_visual_state (0);
2228 ARDOUR_UI::save_template ()
2230 ArdourPrompter prompter (true);
2233 if (!check_audioengine()) {
2237 prompter.set_name (X_("Prompter"));
2238 prompter.set_title (_("Save Mix Template"));
2239 prompter.set_prompt (_("Name for mix template:"));
2240 prompter.set_initial_text(_session->name() + _("-template"));
2241 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2243 switch (prompter.run()) {
2244 case RESPONSE_ACCEPT:
2245 prompter.get_result (name);
2247 if (name.length()) {
2248 _session->save_template (name);
2258 ARDOUR_UI::edit_metadata ()
2260 SessionMetadataEditor dialog;
2261 dialog.set_session (_session);
2262 editor->ensure_float (dialog);
2267 ARDOUR_UI::import_metadata ()
2269 SessionMetadataImporter dialog;
2270 dialog.set_session (_session);
2271 editor->ensure_float (dialog);
2276 ARDOUR_UI::fontconfig_dialog ()
2279 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2280 may not and it can take a while to build it. Warn them.
2283 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2285 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2286 MessageDialog msg (*_startup,
2287 string_compose (_("Welcome to %1.\n\n"
2288 "The program will take a bit longer to start up\n"
2289 "while the system fonts are checked.\n\n"
2290 "This will only be done once, and you will\n"
2291 "not see this message again\n"), PROGRAM_NAME),
2304 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2306 existing_session = false;
2308 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2309 session_path = cmdline_path;
2310 existing_session = true;
2311 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2312 session_path = Glib::path_get_dirname (string (cmdline_path));
2313 existing_session = true;
2315 /* it doesn't exist, assume the best */
2316 session_path = Glib::path_get_dirname (string (cmdline_path));
2319 session_name = basename_nosuffix (string (cmdline_path));
2323 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2325 /* when this is called, the backend audio system must be running */
2327 /* the main idea here is to deal with the fact that a cmdline argument for the session
2328 can be interpreted in different ways - it could be a directory or a file, and before
2329 we load, we need to know both the session directory and the snapshot (statefile) within it
2330 that we are supposed to use.
2333 if (session_name.length() == 0 || session_path.length() == 0) {
2337 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2339 std::string predicted_session_file;
2341 predicted_session_file = session_path;
2342 predicted_session_file += '/';
2343 predicted_session_file += session_name;
2344 predicted_session_file += ARDOUR::statefile_suffix;
2346 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2347 existing_session = true;
2350 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2352 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2353 /* existing .ardour file */
2354 existing_session = true;
2358 existing_session = false;
2361 /* lets just try to load it */
2363 if (create_engine ()) {
2364 backend_audio_error (false, _startup);
2368 return load_session (session_path, session_name);
2372 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2374 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2376 MessageDialog msg (str,
2378 Gtk::MESSAGE_WARNING,
2379 Gtk::BUTTONS_YES_NO,
2383 msg.set_name (X_("OpenExistingDialog"));
2384 msg.set_title (_("Open Existing Session"));
2385 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2386 msg.set_position (Gtk::WIN_POS_MOUSE);
2389 switch (msg.run()) {
2398 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2400 BusProfile bus_profile;
2402 if (Profile->get_sae()) {
2404 bus_profile.master_out_channels = 2;
2405 bus_profile.input_ac = AutoConnectPhysical;
2406 bus_profile.output_ac = AutoConnectMaster;
2407 bus_profile.requested_physical_in = 0; // use all available
2408 bus_profile.requested_physical_out = 0; // use all available
2412 /* get settings from advanced section of NSD */
2414 if (_startup->create_master_bus()) {
2415 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2417 bus_profile.master_out_channels = 0;
2420 if (_startup->connect_inputs()) {
2421 bus_profile.input_ac = AutoConnectPhysical;
2423 bus_profile.input_ac = AutoConnectOption (0);
2426 /// @todo some minor tweaks.
2428 bus_profile.output_ac = AutoConnectOption (0);
2430 if (_startup->connect_outputs ()) {
2431 if (_startup->connect_outs_to_master()) {
2432 bus_profile.output_ac = AutoConnectMaster;
2433 } else if (_startup->connect_outs_to_physical()) {
2434 bus_profile.output_ac = AutoConnectPhysical;
2438 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2439 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2442 if (build_session (session_path, session_name, bus_profile)) {
2450 ARDOUR_UI::idle_load (const std::string& path)
2453 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2454 /* /path/to/foo => /path/to/foo, foo */
2455 load_session (path, basename_nosuffix (path));
2457 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2458 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2462 ARDOUR_COMMAND_LINE::session_name = path;
2465 * new_session_dialog doens't exist in A3
2466 * Try to remove all references to it to
2467 * see if it will compile. NOTE: this will
2468 * likely cause a runtime issue is my somewhat
2472 //if (new_session_dialog) {
2475 /* make it break out of Dialog::run() and
2479 //new_session_dialog->response (1);
2485 ARDOUR_UI::end_loading_messages ()
2491 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2494 // splash->message (msg);
2498 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2500 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2502 string session_name;
2503 string session_path;
2504 string template_name;
2506 bool likely_new = false;
2508 if (! load_template.empty()) {
2509 should_be_new = true;
2510 template_name = load_template;
2515 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2517 /* if they named a specific statefile, use it, otherwise they are
2518 just giving a session folder, and we want to use it as is
2519 to find the session.
2522 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2523 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2525 session_path = ARDOUR_COMMAND_LINE::session_name;
2528 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2532 bool const apply = run_startup (should_be_new, load_template);
2535 if (quit_on_cancel) {
2542 /* if we run the startup dialog again, offer more than just "new session" */
2544 should_be_new = false;
2546 session_name = _startup->session_name (likely_new);
2548 /* this shouldn't happen, but we catch it just in case it does */
2550 if (session_name.empty()) {
2554 if (_startup->use_session_template()) {
2555 template_name = _startup->session_template_name();
2556 _session_is_new = true;
2559 if (session_name[0] == G_DIR_SEPARATOR ||
2560 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2561 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2563 /* absolute path or cwd-relative path specified for session name: infer session folder
2564 from what was given.
2567 session_path = Glib::path_get_dirname (session_name);
2568 session_name = Glib::path_get_basename (session_name);
2572 session_path = _startup->session_folder();
2574 if (session_name.find ('/') != string::npos) {
2575 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2576 "session names may not contain a '/' character"));
2578 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2582 if (session_name.find ('\\') != string::npos) {
2583 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2584 "session names may not contain a '\\' character"));
2586 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2592 if (create_engine ()) {
2596 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2600 std::string existing = Glib::build_filename (session_path, session_name);
2602 if (!ask_about_loading_existing_session (existing)) {
2603 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2608 _session_is_new = false;
2613 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2615 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2619 if (session_name.find ('/') != std::string::npos) {
2620 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2621 "session names may not contain a '/' character"));
2623 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2627 if (session_name.find ('\\') != std::string::npos) {
2628 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2629 "session names may not contain a '\\' character"));
2631 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2635 _session_is_new = true;
2638 if (likely_new && template_name.empty()) {
2640 ret = build_session_from_nsd (session_path, session_name);
2644 ret = load_session (session_path, session_name, template_name);
2645 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2646 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2656 ARDOUR_UI::close_session()
2658 if (!check_audioengine()) {
2662 if (unload_session (true)) {
2666 ARDOUR_COMMAND_LINE::session_name = "";
2668 if (get_session_parameters (true, false)) {
2672 goto_editor_window ();
2676 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2678 Session *new_session;
2682 session_loaded = false;
2684 if (!check_audioengine()) {
2688 unload_status = unload_session ();
2690 if (unload_status < 0) {
2692 } else if (unload_status > 0) {
2697 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2700 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2703 /* this one is special */
2705 catch (AudioEngine::PortRegistrationFailure& err) {
2707 MessageDialog msg (err.what(),
2710 Gtk::BUTTONS_CLOSE);
2712 msg.set_title (_("Port Registration Error"));
2713 msg.set_secondary_text (_("Click the Close button to try again."));
2714 msg.set_position (Gtk::WIN_POS_CENTER);
2718 int response = msg.run ();
2723 case RESPONSE_CANCEL:
2733 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"),path, snap_name),
2738 msg.set_title (_("Loading Error"));
2739 msg.set_secondary_text (_("Click the Refresh button to try again."));
2740 msg.add_button (Stock::REFRESH, 1);
2741 msg.set_position (Gtk::WIN_POS_CENTER);
2745 int response = msg.run ();
2760 list<string> const u = new_session->unknown_processors ();
2762 MissingPluginDialog d (_session, u);
2767 /* Now the session been created, add the transport controls */
2768 new_session->add_controllable(roll_controllable);
2769 new_session->add_controllable(stop_controllable);
2770 new_session->add_controllable(goto_start_controllable);
2771 new_session->add_controllable(goto_end_controllable);
2772 new_session->add_controllable(auto_loop_controllable);
2773 new_session->add_controllable(play_selection_controllable);
2774 new_session->add_controllable(rec_controllable);
2776 set_session (new_session);
2778 session_loaded = true;
2780 goto_editor_window ();
2783 _session->set_clean ();
2794 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2796 Session *new_session;
2799 if (!check_audioengine()) {
2803 session_loaded = false;
2805 x = unload_session ();
2813 _session_is_new = true;
2816 new_session = new Session (*engine, path, snap_name, &bus_profile);
2821 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2827 /* Give the new session the default GUI state, if such things exist */
2830 n = Config->instant_xml (X_("Editor"));
2832 new_session->add_instant_xml (*n, false);
2834 n = Config->instant_xml (X_("Mixer"));
2836 new_session->add_instant_xml (*n, false);
2839 /* Put the playhead at 0 and scroll fully left */
2840 new_session->instant_xml(X_("Editor"))->add_property (X_("playhead"), X_("0"));
2841 new_session->instant_xml(X_("Editor"))->add_property (X_("left-frame"), X_("0"));
2843 set_session (new_session);
2845 session_loaded = true;
2847 new_session->save_state(new_session->name());
2853 ARDOUR_UI::launch_chat ()
2856 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2858 open_uri("http://webchat.freenode.net/?channels=ardour");
2863 ARDOUR_UI::show_about ()
2867 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2870 about->set_transient_for(*editor);
2875 ARDOUR_UI::launch_manual ()
2877 PBD::open_uri("http://ardour.org/flossmanual");
2881 ARDOUR_UI::launch_reference ()
2883 PBD::open_uri("http://ardour.org/refmanual");
2887 ARDOUR_UI::hide_about ()
2890 about->get_window()->set_cursor ();
2896 ARDOUR_UI::about_signal_response (int /*response*/)
2902 ARDOUR_UI::show_splash ()
2906 splash = new Splash;
2914 splash->queue_draw ();
2915 splash->get_window()->process_updates (true);
2920 ARDOUR_UI::hide_splash ()
2928 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2929 const string& plural_msg, const string& singular_msg)
2933 removed = rep.paths.size();
2936 MessageDialog msgd (*editor,
2937 _("No audio files were ready for cleanup"),
2940 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2941 msgd.set_secondary_text (_("If this seems suprising, \n\
2942 check for any existing snapshots.\n\
2943 These may still include regions that\n\
2944 require some unused files to continue to exist."));
2950 ArdourDialog results (_("Clean-up"), true, false);
2952 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2953 CleanupResultsModelColumns() {
2957 Gtk::TreeModelColumn<std::string> visible_name;
2958 Gtk::TreeModelColumn<std::string> fullpath;
2962 CleanupResultsModelColumns results_columns;
2963 Glib::RefPtr<Gtk::ListStore> results_model;
2964 Gtk::TreeView results_display;
2966 results_model = ListStore::create (results_columns);
2967 results_display.set_model (results_model);
2968 results_display.append_column (list_title, results_columns.visible_name);
2970 results_display.set_name ("CleanupResultsList");
2971 results_display.set_headers_visible (true);
2972 results_display.set_headers_clickable (false);
2973 results_display.set_reorderable (false);
2975 Gtk::ScrolledWindow list_scroller;
2978 Gtk::HBox dhbox; // the hbox for the image and text
2979 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2980 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2982 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2984 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2987 %1 - number of files removed
2988 %2 - location of "dead_sounds"
2989 %3 - size of files affected
2990 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2993 const char* bprefix;
2994 double space_adjusted = 0;
2996 if (rep.space < 100000.0f) {
2997 bprefix = X_("kilo");
2998 } else if (rep.space < 1000000.0f * 1000) {
2999 bprefix = X_("mega");
3000 space_adjusted = truncf((float)rep.space / 1000.0);
3002 bprefix = X_("giga");
3003 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
3007 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
3009 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
3012 dhbox.pack_start (*dimage, true, false, 5);
3013 dhbox.pack_start (txt, true, false, 5);
3015 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3016 TreeModel::Row row = *(results_model->append());
3017 row[results_columns.visible_name] = *i;
3018 row[results_columns.fullpath] = *i;
3021 list_scroller.add (results_display);
3022 list_scroller.set_size_request (-1, 150);
3023 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3025 dvbox.pack_start (dhbox, true, false, 5);
3026 dvbox.pack_start (list_scroller, true, false, 5);
3027 ddhbox.pack_start (dvbox, true, false, 5);
3029 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3030 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3031 results.set_default_response (RESPONSE_CLOSE);
3032 results.set_position (Gtk::WIN_POS_MOUSE);
3034 results_display.show();
3035 list_scroller.show();
3042 //results.get_vbox()->show();
3043 results.set_resizable (false);
3050 ARDOUR_UI::cleanup ()
3052 if (_session == 0) {
3053 /* shouldn't happen: menu item is insensitive */
3058 MessageDialog checker (_("Are you sure you want to cleanup?"),
3060 Gtk::MESSAGE_QUESTION,
3061 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3063 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3064 ALL undo/redo information will be lost if you cleanup.\n\
3065 After cleanup, unused audio files will be moved to a \
3066 \"dead sounds\" location."));
3068 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3069 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3070 checker.set_default_response (RESPONSE_CANCEL);
3072 checker.set_name (_("CleanupDialog"));
3073 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3074 checker.set_position (Gtk::WIN_POS_MOUSE);
3076 switch (checker.run()) {
3077 case RESPONSE_ACCEPT:
3083 ARDOUR::CleanupReport rep;
3085 editor->prepare_for_cleanup ();
3087 /* do not allow flush until a session is reloaded */
3089 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3091 act->set_sensitive (false);
3094 if (_session->cleanup_sources (rep)) {
3095 editor->finish_cleanup ();
3099 editor->finish_cleanup ();
3102 display_cleanup_results (rep,
3105 The following %1 files were not in use and \n\
3106 have been moved to:\n\
3108 Flushing the wastebasket will \n\
3109 release an additional\n\
3110 %3 %4bytes of disk space.\n"),
3112 The following file was not in use and \n \
3113 has been moved to:\n \
3115 Flushing the wastebasket will \n\
3116 release an additional\n\
3117 %3 %4bytes of disk space.\n"
3123 ARDOUR_UI::flush_trash ()
3125 if (_session == 0) {
3126 /* shouldn't happen: menu item is insensitive */
3130 ARDOUR::CleanupReport rep;
3132 if (_session->cleanup_trash_sources (rep)) {
3136 display_cleanup_results (rep,
3138 _("The following %1 files were deleted from\n\
3140 releasing %3 %4bytes of disk space"),
3141 _("The following file was deleted from\n\
3143 releasing %3 %4bytes of disk space"));
3147 ARDOUR_UI::add_route (Gtk::Window* float_window)
3155 if (add_route_dialog == 0) {
3156 add_route_dialog = new AddRouteDialog (_session);
3158 add_route_dialog->set_transient_for (*float_window);
3162 if (add_route_dialog->is_visible()) {
3163 /* we're already doing this */
3167 ResponseType r = (ResponseType) add_route_dialog->run ();
3169 add_route_dialog->hide();
3172 case RESPONSE_ACCEPT:
3179 if ((count = add_route_dialog->count()) <= 0) {
3183 string template_path = add_route_dialog->track_template();
3185 if (!template_path.empty()) {
3186 _session->new_route_from_template (count, template_path);
3190 uint32_t input_chan = add_route_dialog->channels ();
3191 uint32_t output_chan;
3192 string name_template = add_route_dialog->name_template ();
3193 bool track = add_route_dialog->track ();
3194 RouteGroup* route_group = add_route_dialog->route_group ();
3196 AutoConnectOption oac = Config->get_output_auto_connect();
3198 if (oac & AutoConnectMaster) {
3199 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3201 output_chan = input_chan;
3204 /* XXX do something with name template */
3206 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3208 session_add_midi_track (route_group, count);
3210 MessageDialog msg (*editor,
3211 _("Sorry, MIDI Busses are not supported at this time."));
3213 //session_add_midi_bus();
3217 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3219 session_add_audio_bus (input_chan, output_chan, route_group, count);
3225 ARDOUR_UI::mixer_settings () const
3230 node = _session->instant_xml(X_("Mixer"));
3232 node = Config->instant_xml(X_("Mixer"));
3236 node = new XMLNode (X_("Mixer"));
3243 ARDOUR_UI::editor_settings () const
3248 node = _session->instant_xml(X_("Editor"));
3250 node = Config->instant_xml(X_("Editor"));
3254 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3255 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3260 node = new XMLNode (X_("Editor"));
3267 ARDOUR_UI::keyboard_settings () const
3271 node = Config->extra_xml(X_("Keyboard"));
3274 node = new XMLNode (X_("Keyboard"));
3280 ARDOUR_UI::create_xrun_marker (framepos_t where)
3282 editor->mouse_add_new_marker (where, false, true);
3286 ARDOUR_UI::halt_on_xrun_message ()
3288 MessageDialog msg (*editor,
3289 _("Recording was stopped because your system could not keep up."));
3294 ARDOUR_UI::xrun_handler (framepos_t where)
3300 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3302 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3303 create_xrun_marker(where);
3306 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3307 halt_on_xrun_message ();
3312 ARDOUR_UI::disk_overrun_handler ()
3314 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3316 if (!have_disk_speed_dialog_displayed) {
3317 have_disk_speed_dialog_displayed = true;
3318 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3319 The disk system on your computer\n\
3320 was not able to keep up with %1.\n\
3322 Specifically, it failed to write data to disk\n\
3323 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3324 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3330 ARDOUR_UI::disk_underrun_handler ()
3332 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3334 if (!have_disk_speed_dialog_displayed) {
3335 have_disk_speed_dialog_displayed = true;
3336 MessageDialog* msg = new MessageDialog (*editor,
3337 string_compose (_("The disk system on your computer\n\
3338 was not able to keep up with %1.\n\
3340 Specifically, it failed to read data from disk\n\
3341 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3342 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3348 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3350 have_disk_speed_dialog_displayed = false;
3355 ARDOUR_UI::session_dialog (std::string msg)
3357 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3362 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3364 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3373 ARDOUR_UI::pending_state_dialog ()
3375 HBox* hbox = new HBox();
3376 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3377 ArdourDialog dialog (_("Crash Recovery"), true);
3379 This session appears to have been in\n\
3380 middle of recording when ardour or\n\
3381 the computer was shutdown.\n\
3383 Ardour can recover any captured audio for\n\
3384 you, or it can ignore it. Please decide\n\
3385 what you would like to do.\n"));
3386 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3387 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3388 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3389 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3390 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3391 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3392 dialog.set_default_response (RESPONSE_ACCEPT);
3393 dialog.set_position (WIN_POS_CENTER);
3398 switch (dialog.run ()) {
3399 case RESPONSE_ACCEPT:
3407 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3409 HBox* hbox = new HBox();
3410 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3411 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3412 Label message (string_compose (_("\
3413 This session was created with a sample rate of %1 Hz\n\
3415 The audioengine is currently running at %2 Hz\n"), desired, actual));
3417 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3418 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3419 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3420 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3421 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3422 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3423 dialog.set_default_response (RESPONSE_ACCEPT);
3424 dialog.set_position (WIN_POS_CENTER);
3429 switch (dialog.run ()) {
3430 case RESPONSE_ACCEPT:
3439 ARDOUR_UI::disconnect_from_jack ()
3442 if( engine->disconnect_from_jack ()) {
3443 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3447 update_sample_rate (0);
3452 ARDOUR_UI::reconnect_to_jack ()
3455 if (engine->reconnect_to_jack ()) {
3456 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3460 update_sample_rate (0);
3465 ARDOUR_UI::use_config ()
3467 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3469 set_transport_controllable_state (*node);
3474 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3476 if (Config->get_primary_clock_delta_edit_cursor()) {
3477 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3479 primary_clock.set (pos, 0, true);
3482 if (Config->get_secondary_clock_delta_edit_cursor()) {
3483 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3485 secondary_clock.set (pos);
3488 if (big_clock_window->get()) {
3489 big_clock.set (pos);
3495 ARDOUR_UI::step_edit_status_change (bool yn)
3497 // XXX should really store pre-step edit status of things
3498 // we make insensitive
3501 rec_button.set_visual_state (3);
3502 rec_button.set_sensitive (false);
3504 rec_button.set_visual_state (0);
3505 rec_button.set_sensitive (true);
3510 ARDOUR_UI::record_state_changed ()
3512 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3514 if (!_session || !big_clock_window->get()) {
3515 /* why bother - the clock isn't visible */
3519 Session::RecordState const r = _session->record_status ();
3520 bool const h = _session->have_rec_enabled_track ();
3522 if (r == Session::Recording && h) {
3523 big_clock.set_widget_name ("BigClockRecording");
3525 big_clock.set_widget_name ("BigClockNonRecording");
3530 ARDOUR_UI::first_idle ()
3533 _session->allow_auto_play (true);
3537 editor->first_idle();
3540 Keyboard::set_can_save_keybindings (true);
3545 ARDOUR_UI::store_clock_modes ()
3547 XMLNode* node = new XMLNode(X_("ClockModes"));
3549 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3550 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3553 _session->add_extra_xml (*node);
3554 _session->set_dirty ();
3559 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3560 : Controllable (name), ui (u), type(tp)
3566 ARDOUR_UI::TransportControllable::set_value (double val)
3568 if (type == ShuttleControl) {
3575 fract = -((0.5 - val)/0.5);
3577 fract = ((val - 0.5)/0.5);
3581 ui.set_shuttle_fract (fract);
3586 /* do nothing: these are radio-style actions */
3590 const char *action = 0;
3594 action = X_("Roll");
3597 action = X_("Stop");
3600 action = X_("Goto Start");
3603 action = X_("Goto End");
3606 action = X_("Loop");
3609 action = X_("Play Selection");
3612 action = X_("Record");
3622 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3630 ARDOUR_UI::TransportControllable::get_value (void) const
3649 case ShuttleControl:
3659 ARDOUR_UI::TransportControllable::set_id (const string& str)
3665 ARDOUR_UI::setup_profile ()
3667 if (gdk_screen_width() < 1200) {
3668 Profile->set_small_screen ();
3672 if (getenv ("ARDOUR_SAE")) {
3673 Profile->set_sae ();
3674 Profile->set_single_package ();
3679 ARDOUR_UI::toggle_translations ()
3681 using namespace Glib;
3683 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3685 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3688 string i18n_killer = ARDOUR::translation_kill_path();
3690 bool already_enabled = !ARDOUR::translations_are_disabled ();
3692 if (ract->get_active ()) {
3693 /* we don't care about errors */
3694 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3697 /* we don't care about errors */
3698 unlink (i18n_killer.c_str());
3701 if (already_enabled != ract->get_active()) {
3702 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3704 Gtk::MESSAGE_WARNING,
3706 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3707 win.set_position (Gtk::WIN_POS_CENTER);
3715 /** Add a window proxy to our list, so that its state will be saved.
3716 * This call also causes the window to be created and opened if its
3717 * state was saved as `visible'.
3720 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3722 _window_proxies.push_back (p);
3726 /** Remove a window proxy from our list. Must be called if a WindowProxy
3727 * is deleted, to prevent hanging pointers.
3730 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3732 _window_proxies.remove (p);
3736 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3738 MissingFileDialog dialog (s, str, type);
3743 int result = dialog.run ();
3750 return 1; // quit entire session load
3753 result = dialog.get_action ();
3759 ARDOUR_UI::ambiguous_file (std::string file, std::string path, std::vector<std::string> hits)
3761 AmbiguousFileDialog dialog (file, hits);
3767 return dialog.get_which ();