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.
20 #define __STDC_FORMAT_MACROS 1
34 #include <sys/resource.h>
36 #include <gtkmm/messagedialog.h>
37 #include <gtkmm/accelmap.h>
39 #include "pbd/error.h"
40 #include "pbd/basename.h"
41 #include "pbd/compose.h"
42 #include "pbd/failed_constructor.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/openuri.h"
46 #include "pbd/file_utils.h"
48 #include "gtkmm2ext/application.h"
49 #include "gtkmm2ext/gtk_ui.h"
50 #include "gtkmm2ext/utils.h"
51 #include "gtkmm2ext/click_box.h"
52 #include "gtkmm2ext/fastmeter.h"
53 #include "gtkmm2ext/popup.h"
54 #include "gtkmm2ext/window_title.h"
56 #include "midi++/manager.h"
58 #include "ardour/ardour.h"
59 #include "ardour/callback.h"
60 #include "ardour/profile.h"
61 #include "ardour/session_directory.h"
62 #include "ardour/session_route.h"
63 #include "ardour/session_state_utils.h"
64 #include "ardour/session_utils.h"
65 #include "ardour/port.h"
66 #include "ardour/audioengine.h"
67 #include "ardour/playlist.h"
68 #include "ardour/utils.h"
69 #include "ardour/audio_diskstream.h"
70 #include "ardour/audiofilesource.h"
71 #include "ardour/recent_sessions.h"
72 #include "ardour/port.h"
73 #include "ardour/audio_track.h"
74 #include "ardour/midi_track.h"
75 #include "ardour/filesystem_paths.h"
76 #include "ardour/filename_extensions.h"
78 typedef uint64_t microseconds_t;
81 #include "ardour_ui.h"
82 #include "public_editor.h"
83 #include "audio_clock.h"
88 #include "add_route_dialog.h"
92 #include "gui_thread.h"
93 #include "theme_manager.h"
94 #include "bundle_manager.h"
95 #include "session_metadata_dialog.h"
96 #include "gain_meter.h"
97 #include "route_time_axis.h"
99 #include "engine_dialog.h"
100 #include "processor_box.h"
101 #include "time_axis_view_item.h"
102 #include "window_proxy.h"
103 #include "global_port_matrix.h"
104 #include "location_ui.h"
108 using namespace ARDOUR;
110 using namespace Gtkmm2ext;
113 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
114 UIConfiguration *ARDOUR_UI::ui_config = 0;
116 sigc::signal<void,bool> ARDOUR_UI::Blink;
117 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
118 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
119 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
121 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
123 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
125 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
126 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
127 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
128 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
132 preroll_button (_("pre\nroll")),
133 postroll_button (_("post\nroll")),
137 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
141 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
142 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
143 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
144 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
145 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
146 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
147 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
148 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
149 shuttle_controller_binding_proxy (shuttle_controllable),
151 roll_button (roll_controllable),
152 stop_button (stop_controllable),
153 goto_start_button (goto_start_controllable),
154 goto_end_button (goto_end_controllable),
155 auto_loop_button (auto_loop_controllable),
156 play_selection_button (play_selection_controllable),
157 rec_button (rec_controllable),
159 shuttle_units_button (_("% ")),
161 punch_in_button (_("Punch In")),
162 punch_out_button (_("Punch Out")),
163 auto_return_button (_("Auto Return")),
164 auto_play_button (_("Auto Play")),
165 auto_input_button (_("Auto Input")),
166 click_button (_("Click")),
167 time_master_button (_("time\nmaster")),
169 auditioning_alert_button (_("AUDITION")),
170 solo_alert_button (_("SOLO")),
171 error_log_button (_("Errors"))
174 using namespace Gtk::Menu_Helpers;
180 // _auto_display_errors = false;
182 * This was commented out as it wasn't defined
183 * in A3 IIRC. If this is not needed it should
184 * be completely removed.
192 if (theArdourUI == 0) {
196 ui_config = new UIConfiguration();
197 theme_manager = new ThemeManager();
203 _session_is_new = false;
204 big_clock_window = 0;
205 big_clock_height = 0;
206 big_clock_resize_in_progress = false;
207 session_selector_window = 0;
208 last_key_press_time = 0;
209 _will_create_new_session_automatically = false;
210 add_route_dialog = 0;
212 rc_option_editor = 0;
213 session_option_editor = 0;
215 open_session_selector = 0;
216 have_configure_timeout = false;
217 have_disk_speed_dialog_displayed = false;
218 session_loaded = false;
219 last_speed_displayed = -1.0f;
220 ignore_dual_punch = false;
221 _mixer_on_top = false;
222 original_big_clock_width = -1;
223 original_big_clock_height = -1;
224 original_big_clock_font_size = 0;
226 roll_button.unset_flags (Gtk::CAN_FOCUS);
227 stop_button.unset_flags (Gtk::CAN_FOCUS);
228 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
229 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
230 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
231 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
232 rec_button.unset_flags (Gtk::CAN_FOCUS);
234 last_configure_time= 0;
236 shuttle_grabbed = false;
238 shuttle_max_speed = 8.0f;
240 shuttle_style_menu = 0;
241 shuttle_unit_menu = 0;
243 // We do not have jack linked in yet so;
245 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
247 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
248 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
250 /* handle dialog requests */
252 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
254 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
256 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
258 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
260 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
262 /* lets get this party started */
265 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
266 throw failed_constructor ();
269 setup_gtk_ardour_enums ();
272 GainMeter::setup_slider_pix ();
273 RouteTimeAxisView::setup_slider_pix ();
274 SendProcessorEntry::setup_slider_pix ();
275 SessionEvent::create_per_thread_pool ("GUI", 512);
277 } catch (failed_constructor& err) {
278 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
283 /* we like keyboards */
285 keyboard = new ArdourKeyboard(*this);
287 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
289 keyboard->set_state (*node, Stateful::loading_state_version);
294 TimeAxisViewItem::set_constant_heights ();
296 /* The following must happen after ARDOUR::init() so that Config is set up */
298 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
299 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
301 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
302 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
303 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
304 Config->extra_xml (X_("UI")),
305 string_compose ("toggle-%1-connection-manager", (*i).to_string())
311 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
312 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
317 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
319 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
322 _startup = new ArdourStartup ();
324 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
326 if (audio_setup && _startup->engine_control()) {
327 _startup->engine_control()->set_state (*audio_setup);
330 _startup->set_new_only (should_be_new);
331 if (!load_template.empty()) {
332 _startup->set_load_template( load_template );
334 _startup->present ();
340 switch (_startup->response()) {
349 ARDOUR_UI::create_engine ()
351 // this gets called every time by new_session()
357 loading_message (_("Starting audio engine"));
360 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
367 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
368 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
369 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
371 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
373 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
381 ARDOUR_UI::post_engine ()
383 /* Things to be done once we create the AudioEngine
386 ARDOUR::init_post_engine ();
388 ActionManager::init ();
391 if (setup_windows ()) {
392 throw failed_constructor ();
395 check_memory_locking();
397 /* this is the first point at which all the keybindings are available */
399 if (ARDOUR_COMMAND_LINE::show_key_actions) {
400 vector<string> names;
401 vector<string> paths;
403 vector<AccelKey> bindings;
405 ActionManager::get_all_actions (names, paths, keys, bindings);
407 vector<string>::iterator n;
408 vector<string>::iterator k;
409 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
410 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
416 blink_timeout_tag = -1;
418 /* this being a GUI and all, we want peakfiles */
420 AudioFileSource::set_build_peakfiles (true);
421 AudioFileSource::set_build_missing_peakfiles (true);
423 /* set default clock modes */
425 if (Profile->get_sae()) {
426 primary_clock.set_mode (AudioClock::BBT);
427 secondary_clock.set_mode (AudioClock::MinSec);
429 primary_clock.set_mode (AudioClock::Timecode);
430 secondary_clock.set_mode (AudioClock::BBT);
433 /* start the time-of-day-clock */
436 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
437 update_wall_clock ();
438 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
441 update_disk_space ();
443 update_sample_rate (engine->frame_rate());
445 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
446 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
447 Config->map_parameters (pc);
449 /* now start and maybe save state */
451 if (do_engine_start () == 0) {
452 if (_session && _session_is_new) {
453 /* we need to retain initial visual
454 settings for a new session
456 _session->save_state ("");
461 ARDOUR_UI::~ARDOUR_UI ()
466 delete add_route_dialog;
470 ARDOUR_UI::pop_back_splash ()
472 if (Splash::instance()) {
473 // Splash::instance()->pop_back();
474 Splash::instance()->hide ();
479 ARDOUR_UI::configure_timeout ()
481 if (last_configure_time == 0) {
482 /* no configure events yet */
486 /* force a gap of 0.5 seconds since the last configure event
489 if (get_microseconds() - last_configure_time < 500000) {
492 have_configure_timeout = false;
493 cerr << "config event-driven save\n";
494 save_ardour_state ();
500 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
502 if (have_configure_timeout) {
503 last_configure_time = get_microseconds();
505 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
506 have_configure_timeout = true;
513 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
515 const XMLProperty* prop;
517 if ((prop = node.property ("roll")) != 0) {
518 roll_controllable->set_id (prop->value());
520 if ((prop = node.property ("stop")) != 0) {
521 stop_controllable->set_id (prop->value());
523 if ((prop = node.property ("goto-start")) != 0) {
524 goto_start_controllable->set_id (prop->value());
526 if ((prop = node.property ("goto-end")) != 0) {
527 goto_end_controllable->set_id (prop->value());
529 if ((prop = node.property ("auto-loop")) != 0) {
530 auto_loop_controllable->set_id (prop->value());
532 if ((prop = node.property ("play-selection")) != 0) {
533 play_selection_controllable->set_id (prop->value());
535 if ((prop = node.property ("rec")) != 0) {
536 rec_controllable->set_id (prop->value());
538 if ((prop = node.property ("shuttle")) != 0) {
539 shuttle_controllable->set_id (prop->value());
544 ARDOUR_UI::get_transport_controllable_state ()
546 XMLNode* node = new XMLNode(X_("TransportControllables"));
549 roll_controllable->id().print (buf, sizeof (buf));
550 node->add_property (X_("roll"), buf);
551 stop_controllable->id().print (buf, sizeof (buf));
552 node->add_property (X_("stop"), buf);
553 goto_start_controllable->id().print (buf, sizeof (buf));
554 node->add_property (X_("goto_start"), buf);
555 goto_end_controllable->id().print (buf, sizeof (buf));
556 node->add_property (X_("goto_end"), buf);
557 auto_loop_controllable->id().print (buf, sizeof (buf));
558 node->add_property (X_("auto_loop"), buf);
559 play_selection_controllable->id().print (buf, sizeof (buf));
560 node->add_property (X_("play_selection"), buf);
561 rec_controllable->id().print (buf, sizeof (buf));
562 node->add_property (X_("rec"), buf);
563 shuttle_controllable->id().print (buf, sizeof (buf));
564 node->add_property (X_("shuttle"), buf);
571 ARDOUR_UI::autosave_session ()
573 if (g_main_depth() > 1) {
574 /* inside a recursive main loop,
575 give up because we may not be able to
581 if (!Config->get_periodic_safety_backups()) {
586 _session->maybe_write_autosave();
593 ARDOUR_UI::update_autosave ()
595 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
597 if (_session && _session->dirty()) {
598 if (_autosave_connection.connected()) {
599 _autosave_connection.disconnect();
602 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
603 Config->get_periodic_safety_backup_interval() * 1000);
606 if (_autosave_connection.connected()) {
607 _autosave_connection.disconnect();
613 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
617 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
619 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
622 MessageDialog win (title,
628 win.set_secondary_text(_("There are several possible reasons:\n\
630 1) You requested audio parameters that are not supported..\n\
631 2) JACK is running as another user.\n\
633 Please consider the possibilities, and perhaps try different parameters."));
635 win.set_secondary_text(_("There are several possible reasons:\n\
637 1) JACK is not running.\n\
638 2) JACK is running as another user, perhaps root.\n\
639 3) There is already another client called \"ardour\".\n\
641 Please consider the possibilities, and perhaps (re)start JACK."));
645 win.set_transient_for (*toplevel);
649 win.add_button (Stock::OK, RESPONSE_CLOSE);
651 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
654 win.set_default_response (RESPONSE_CLOSE);
657 win.set_position (Gtk::WIN_POS_CENTER);
660 /* we just don't care about the result, but we want to block */
666 ARDOUR_UI::startup ()
668 Application* app = Application::instance ();
670 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
671 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
674 call_the_mothership (VERSIONSTRING);
679 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
685 goto_editor_window ();
687 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
688 to be opened on top of the editor window that goto_editor_window() just opened.
690 add_window_proxy (location_ui);
691 add_window_proxy (big_clock_window);
692 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
693 add_window_proxy (_global_port_matrix[*i]);
696 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
700 ARDOUR_UI::no_memory_warning ()
702 XMLNode node (X_("no-memory-warning"));
703 Config->add_instant_xml (node);
707 ARDOUR_UI::check_memory_locking ()
710 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
714 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
716 if (engine->is_realtime() && memory_warning_node == 0) {
718 struct rlimit limits;
720 long pages, page_size;
722 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
725 ram = (int64_t) pages * (int64_t) page_size;
728 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
732 if (limits.rlim_cur != RLIM_INFINITY) {
734 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
737 MessageDialog msg (string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
738 "This might cause %1 to run out of memory before your system "
739 "runs out of memory. \n\n"
740 "You can view the memory limit with 'ulimit -l', "
741 "and it is normally controlled by /etc/security/limits.conf"),
742 PROGRAM_NAME).c_str());
744 VBox* vbox = msg.get_vbox();
746 CheckButton cb (_("Do not show this window again"));
748 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
750 hbox.pack_start (cb, true, false);
751 vbox->pack_start (hbox);
758 editor->ensure_float (msg);
768 ARDOUR_UI::queue_finish ()
770 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
774 ARDOUR_UI::idle_finish ()
777 return false; /* do not call again */
786 if (_session->transport_rolling() && (++tries < 8)) {
787 _session->request_stop (false, true);
791 if (_session->dirty()) {
792 switch (ask_about_saving_session(_("quit"))) {
797 /* use the default name */
798 if (save_state_canfail ("")) {
799 /* failed - don't quit */
800 MessageDialog msg (*editor,
802 Ardour was unable to save your session.\n\n\
803 If you still wish to quit, please use the\n\n\
804 \"Just quit\" option."));
815 second_connection.disconnect ();
816 point_one_second_connection.disconnect ();
817 point_oh_five_second_connection.disconnect ();
818 point_zero_one_second_connection.disconnect();
821 /* Save state before deleting the session, as that causes some
822 windows to be destroyed before their visible state can be
825 save_ardour_state ();
828 // _session->set_deletion_in_progress ();
829 _session->set_clean ();
830 _session->remove_pending_capture_state ();
835 ArdourDialog::close_all_dialogs ();
841 ARDOUR_UI::ask_about_saving_session (const string & what)
843 ArdourDialog window (_("Unsaved Session"));
844 Gtk::HBox dhbox; // the hbox for the image and text
845 Gtk::Label prompt_label;
846 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
850 msg = string_compose(_("Don't %1"), what);
851 window.add_button (msg, RESPONSE_REJECT);
852 msg = string_compose(_("Just %1"), what);
853 window.add_button (msg, RESPONSE_APPLY);
854 msg = string_compose(_("Save and %1"), what);
855 window.add_button (msg, RESPONSE_ACCEPT);
857 window.set_default_response (RESPONSE_ACCEPT);
859 Gtk::Button noquit_button (msg);
860 noquit_button.set_name ("EditorGTKButton");
865 if (_session->snap_name() == _session->name()) {
868 type = _("snapshot");
870 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?"),
871 type, _session->snap_name());
873 prompt_label.set_text (prompt);
874 prompt_label.set_name (X_("PrompterLabel"));
875 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
877 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
878 dhbox.set_homogeneous (false);
879 dhbox.pack_start (*dimage, false, false, 5);
880 dhbox.pack_start (prompt_label, true, false, 5);
881 window.get_vbox()->pack_start (dhbox);
883 window.set_name (_("Prompter"));
884 window.set_position (Gtk::WIN_POS_MOUSE);
885 window.set_modal (true);
886 window.set_resizable (false);
892 window.set_keep_above (true);
895 ResponseType r = (ResponseType) window.run();
900 case RESPONSE_ACCEPT: // save and get out of here
902 case RESPONSE_APPLY: // get out of here
912 ARDOUR_UI::every_second ()
915 update_buffer_load ();
916 update_disk_space ();
921 ARDOUR_UI::every_point_one_seconds ()
923 update_speed_display ();
924 RapidScreenUpdate(); /* EMIT_SIGNAL */
929 ARDOUR_UI::every_point_zero_one_seconds ()
931 // august 2007: actual update frequency: 40Hz, not 100Hz
933 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
938 ARDOUR_UI::update_sample_rate (nframes_t)
942 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
944 if (!engine->connected()) {
946 snprintf (buf, sizeof (buf), _("disconnected"));
950 nframes_t rate = engine->frame_rate();
952 if (fmod (rate, 1000.0) != 0.0) {
953 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
954 (float) rate/1000.0f,
955 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
957 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
959 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
963 sample_rate_label.set_text (buf);
967 ARDOUR_UI::update_cpu_load ()
970 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
971 cpu_load_label.set_text (buf);
975 ARDOUR_UI::update_buffer_load ()
981 c = _session->capture_load ();
982 p = _session->playback_load ();
984 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
985 _session->playback_load(), _session->capture_load());
986 buffer_load_label.set_text (buf);
988 buffer_load_label.set_text ("");
993 ARDOUR_UI::count_recenabled_streams (Route& route)
995 Track* track = dynamic_cast<Track*>(&route);
996 if (track && track->record_enabled()) {
997 rec_enabled_streams += track->n_inputs().n_total();
1002 ARDOUR_UI::update_disk_space()
1004 if (_session == 0) {
1008 nframes_t frames = _session->available_capture_duration();
1010 nframes_t fr = _session->frame_rate();
1012 if (frames == max_frames) {
1013 strcpy (buf, _("Disk: 24hrs+"));
1015 rec_enabled_streams = 0;
1016 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1018 if (rec_enabled_streams) {
1019 frames /= rec_enabled_streams;
1026 hrs = frames / (fr * 3600);
1027 frames -= hrs * fr * 3600;
1028 mins = frames / (fr * 60);
1029 frames -= mins * fr * 60;
1032 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1035 disk_space_label.set_text (buf);
1037 // An attempt to make the disk space label flash red when space has run out.
1039 if (frames < fr * 60 * 5) {
1040 /* disk_space_box.style ("disk_space_label_empty"); */
1042 /* disk_space_box.style ("disk_space_label"); */
1048 ARDOUR_UI::update_wall_clock ()
1055 tm_now = localtime (&now);
1057 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1058 wall_clock_label.set_text (buf);
1064 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1066 session_popup_menu->popup (0, 0);
1071 ARDOUR_UI::redisplay_recent_sessions ()
1073 std::vector<sys::path> session_directories;
1074 RecentSessionsSorter cmp;
1076 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1077 recent_session_model->clear ();
1079 ARDOUR::RecentSessions rs;
1080 ARDOUR::read_recent_sessions (rs);
1083 recent_session_display.set_model (recent_session_model);
1087 // sort them alphabetically
1088 sort (rs.begin(), rs.end(), cmp);
1090 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1091 session_directories.push_back ((*i).second);
1094 for (vector<sys::path>::const_iterator i = session_directories.begin();
1095 i != session_directories.end(); ++i)
1097 std::vector<sys::path> state_file_paths;
1099 // now get available states for this session
1101 get_state_files_in_directory (*i, state_file_paths);
1103 vector<string*>* states;
1104 vector<const gchar*> item;
1105 string fullpath = (*i).to_string();
1107 /* remove any trailing / */
1109 if (fullpath[fullpath.length()-1] == '/') {
1110 fullpath = fullpath.substr (0, fullpath.length()-1);
1113 /* check whether session still exists */
1114 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1115 /* session doesn't exist */
1116 cerr << "skipping non-existent session " << fullpath << endl;
1120 /* now get available states for this session */
1122 if ((states = Session::possible_states (fullpath)) == 0) {
1123 /* no state file? */
1127 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1129 Gtk::TreeModel::Row row = *(recent_session_model->append());
1131 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1132 row[recent_session_columns.fullpath] = fullpath;
1134 if (state_file_names.size() > 1) {
1138 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1139 i2 != state_file_names.end(); ++i2)
1142 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1144 child_row[recent_session_columns.visible_name] = *i2;
1145 child_row[recent_session_columns.fullpath] = fullpath;
1150 recent_session_display.set_model (recent_session_model);
1154 ARDOUR_UI::build_session_selector ()
1156 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1158 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1160 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1161 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1162 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1163 recent_session_model = TreeStore::create (recent_session_columns);
1164 recent_session_display.set_model (recent_session_model);
1165 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1166 recent_session_display.set_headers_visible (false);
1167 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1168 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1170 scroller->add (recent_session_display);
1171 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1173 session_selector_window->set_name ("SessionSelectorWindow");
1174 session_selector_window->set_size_request (200, 400);
1175 session_selector_window->get_vbox()->pack_start (*scroller);
1177 recent_session_display.show();
1179 //session_selector_window->get_vbox()->show();
1183 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1185 session_selector_window->response (RESPONSE_ACCEPT);
1189 ARDOUR_UI::open_recent_session ()
1191 bool can_return = (_session != 0);
1193 if (session_selector_window == 0) {
1194 build_session_selector ();
1197 redisplay_recent_sessions ();
1201 session_selector_window->set_position (WIN_POS_MOUSE);
1203 ResponseType r = (ResponseType) session_selector_window->run ();
1206 case RESPONSE_ACCEPT:
1210 session_selector_window->hide();
1217 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1221 session_selector_window->hide();
1223 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1225 if (i == recent_session_model->children().end()) {
1229 Glib::ustring path = (*i)[recent_session_columns.fullpath];
1230 Glib::ustring state = (*i)[recent_session_columns.visible_name];
1232 _session_is_new = false;
1234 if (load_session (path, state) == 0) {
1243 ARDOUR_UI::check_audioengine ()
1246 if (!engine->connected()) {
1247 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1248 "You cannot open or close sessions in this condition"),
1261 ARDOUR_UI::open_session ()
1263 if (!check_audioengine()) {
1268 /* popup selector window */
1270 if (open_session_selector == 0) {
1272 /* ardour sessions are folders */
1274 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1275 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1276 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1277 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1279 FileFilter session_filter;
1280 session_filter.add_pattern ("*.ardour");
1281 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1282 open_session_selector->add_filter (session_filter);
1283 open_session_selector->set_filter (session_filter);
1286 int response = open_session_selector->run();
1287 open_session_selector->hide ();
1290 case RESPONSE_ACCEPT:
1293 open_session_selector->hide();
1297 open_session_selector->hide();
1298 string session_path = open_session_selector->get_filename();
1302 if (session_path.length() > 0) {
1303 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1304 _session_is_new = isnew;
1305 load_session (path, name);
1312 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1314 list<boost::shared_ptr<MidiTrack> > tracks;
1316 if (_session == 0) {
1317 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1324 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1326 if (tracks.size() != how_many) {
1327 if (how_many == 1) {
1328 error << _("could not create a new midi track") << endmsg;
1330 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1334 if ((route = _session->new_midi_route ()) == 0) {
1335 error << _("could not create new midi bus") << endmsg;
1341 MessageDialog msg (*editor,
1342 string_compose (_("There are insufficient JACK ports available\n\
1343 to create a new track or bus.\n\
1344 You should save %1, exit and\n\
1345 restart JACK with more ports."), PROGRAM_NAME));
1352 ARDOUR_UI::session_add_audio_route (bool track, bool aux, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, RouteGroup* route_group, uint32_t how_many)
1354 list<boost::shared_ptr<AudioTrack> > tracks;
1357 if (_session == 0) {
1358 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1364 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1366 if (tracks.size() != how_many) {
1367 if (how_many == 1) {
1368 error << _("could not create a new audio track") << endmsg;
1370 error << string_compose (_("could only create %1 of %2 new audio %3"),
1371 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1377 routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1379 if (routes.size() != how_many) {
1380 if (how_many == 1) {
1381 error << _("could not create a new audio track") << endmsg;
1383 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1390 MessageDialog msg (*editor,
1391 string_compose (_("There are insufficient JACK ports available\n\
1392 to create a new track or bus.\n\
1393 You should save %1, exit and\n\
1394 restart JACK with more ports."), PROGRAM_NAME));
1401 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1403 nframes_t _preroll = 0;
1406 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1407 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1409 if (new_position > _preroll) {
1410 new_position -= _preroll;
1415 _session->request_locate (new_position);
1420 ARDOUR_UI::transport_goto_start ()
1423 _session->goto_start();
1425 /* force displayed area in editor to start no matter
1426 what "follow playhead" setting is.
1430 editor->center_screen (_session->current_start_frame ());
1436 ARDOUR_UI::transport_goto_zero ()
1439 _session->request_locate (0);
1441 /* force displayed area in editor to start no matter
1442 what "follow playhead" setting is.
1446 editor->reset_x_origin (0);
1452 ARDOUR_UI::transport_goto_wallclock ()
1454 if (_session && editor) {
1461 localtime_r (&now, &tmnow);
1463 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1464 frames += tmnow.tm_min * (60 * _session->frame_rate());
1465 frames += tmnow.tm_sec * _session->frame_rate();
1467 _session->request_locate (frames, _session->transport_rolling ());
1469 /* force displayed area in editor to start no matter
1470 what "follow playhead" setting is.
1474 editor->center_screen (frames);
1480 ARDOUR_UI::transport_goto_end ()
1483 nframes_t const frame = _session->current_end_frame();
1484 _session->request_locate (frame);
1486 /* force displayed area in editor to start no matter
1487 what "follow playhead" setting is.
1491 editor->center_screen (frame);
1497 ARDOUR_UI::transport_stop ()
1503 if (_session->is_auditioning()) {
1504 _session->cancel_audition ();
1508 _session->request_stop (false, true);
1512 ARDOUR_UI::transport_stop_and_forget_capture ()
1515 _session->request_stop (true, true);
1520 ARDOUR_UI::remove_last_capture()
1523 editor->remove_last_capture();
1528 ARDOUR_UI::transport_record (bool roll)
1532 switch (_session->record_status()) {
1533 case Session::Disabled:
1534 if (_session->ntracks() == 0) {
1535 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1539 _session->maybe_enable_record ();
1544 case Session::Recording:
1546 _session->request_stop();
1548 _session->disable_record (false, true);
1552 case Session::Enabled:
1553 _session->disable_record (false, true);
1556 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1560 ARDOUR_UI::transport_roll ()
1566 if (_session->is_auditioning()) {
1570 if (_session->config.get_external_sync()) {
1571 switch (_session->config.get_sync_source()) {
1575 /* transport controlled by the master */
1580 bool rolling = _session->transport_rolling();
1582 if (_session->get_play_loop()) {
1583 /* XXX it is not possible to just leave seamless loop and keep
1584 playing at present (nov 4th 2009)
1586 if (!Config->get_seamless_loop()) {
1587 _session->request_play_loop (false, true);
1589 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1590 /* stop playing a range if we currently are */
1591 _session->request_play_range (0, true);
1594 if (join_play_range_button.get_active()) {
1595 _session->request_play_range (&editor->get_selection().time, true);
1599 _session->request_transport_speed (1.0f);
1604 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1611 if (_session->is_auditioning()) {
1612 _session->cancel_audition ();
1616 if (_session->config.get_external_sync()) {
1617 switch (_session->config.get_sync_source()) {
1621 /* transport controlled by the master */
1626 bool rolling = _session->transport_rolling();
1627 bool affect_transport = true;
1629 if (rolling && roll_out_of_bounded_mode) {
1630 /* drop out of loop/range playback but leave transport rolling */
1631 if (_session->get_play_loop()) {
1632 if (Config->get_seamless_loop()) {
1633 /* the disk buffers contain copies of the loop - we can't
1634 just keep playing, so stop the transport. the user
1635 can restart as they wish.
1637 affect_transport = true;
1639 /* disk buffers are normal, so we can keep playing */
1640 affect_transport = false;
1642 _session->request_play_loop (false, true);
1643 } else if (_session->get_play_range ()) {
1644 affect_transport = false;
1645 _session->request_play_range (0, true);
1649 if (affect_transport) {
1651 _session->request_stop (with_abort, true);
1653 if (join_play_range_button.get_active()) {
1654 _session->request_play_range (&editor->get_selection().time, true);
1657 _session->request_transport_speed (1.0f);
1663 ARDOUR_UI::toggle_session_auto_loop ()
1666 if (_session->get_play_loop()) {
1667 if (_session->transport_rolling()) {
1668 Location * looploc = _session->locations()->auto_loop_location();
1670 _session->request_locate (looploc->start(), true);
1673 _session->request_play_loop (false);
1676 Location * looploc = _session->locations()->auto_loop_location();
1678 _session->request_play_loop (true);
1685 ARDOUR_UI::transport_play_selection ()
1691 editor->play_selection ();
1695 ARDOUR_UI::transport_rewind (int option)
1697 float current_transport_speed;
1700 current_transport_speed = _session->transport_speed();
1702 if (current_transport_speed >= 0.0f) {
1705 _session->request_transport_speed (-1.0f);
1708 _session->request_transport_speed (-4.0f);
1711 _session->request_transport_speed (-0.5f);
1716 _session->request_transport_speed (current_transport_speed * 1.5f);
1722 ARDOUR_UI::transport_forward (int option)
1724 float current_transport_speed;
1727 current_transport_speed = _session->transport_speed();
1729 if (current_transport_speed <= 0.0f) {
1732 _session->request_transport_speed (1.0f);
1735 _session->request_transport_speed (4.0f);
1738 _session->request_transport_speed (0.5f);
1743 _session->request_transport_speed (current_transport_speed * 1.5f);
1750 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1752 if (_session == 0) {
1756 boost::shared_ptr<Route> r;
1758 if ((r = _session->route_by_remote_id (rid)) != 0) {
1762 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1763 t->set_record_enabled (!t->record_enabled(), this);
1766 if (_session == 0) {
1772 ARDOUR_UI::map_transport_state ()
1774 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1777 auto_loop_button.set_visual_state (0);
1778 play_selection_button.set_visual_state (0);
1779 roll_button.set_visual_state (0);
1780 stop_button.set_visual_state (1);
1784 float sp = _session->transport_speed();
1787 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1788 shuttle_box.queue_draw ();
1789 } else if (sp == 0.0f) {
1791 shuttle_box.queue_draw ();
1792 update_disk_space ();
1799 if (_session->get_play_range()) {
1801 play_selection_button.set_visual_state (1);
1802 roll_button.set_visual_state (0);
1803 auto_loop_button.set_visual_state (0);
1805 } else if (_session->get_play_loop ()) {
1807 auto_loop_button.set_visual_state (1);
1808 play_selection_button.set_visual_state (0);
1809 roll_button.set_visual_state (0);
1813 roll_button.set_visual_state (1);
1814 play_selection_button.set_visual_state (0);
1815 auto_loop_button.set_visual_state (0);
1818 if (join_play_range_button.get_active()) {
1819 /* light up both roll and play-selection if they are joined */
1820 roll_button.set_visual_state (1);
1821 play_selection_button.set_visual_state (1);
1824 stop_button.set_visual_state (0);
1828 stop_button.set_visual_state (1);
1829 roll_button.set_visual_state (0);
1830 play_selection_button.set_visual_state (0);
1831 auto_loop_button.set_visual_state (0);
1836 ARDOUR_UI::engine_stopped ()
1838 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1839 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1840 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1844 ARDOUR_UI::engine_running ()
1846 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1847 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1848 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1850 Glib::RefPtr<Action> action;
1851 const char* action_name = 0;
1853 switch (engine->frames_per_cycle()) {
1855 action_name = X_("JACKLatency32");
1858 action_name = X_("JACKLatency64");
1861 action_name = X_("JACKLatency128");
1864 action_name = X_("JACKLatency512");
1867 action_name = X_("JACKLatency1024");
1870 action_name = X_("JACKLatency2048");
1873 action_name = X_("JACKLatency4096");
1876 action_name = X_("JACKLatency8192");
1879 /* XXX can we do anything useful ? */
1885 action = ActionManager::get_action (X_("JACK"), action_name);
1888 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1889 ract->set_active ();
1895 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1897 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1898 /* we can't rely on the original string continuing to exist when we are called
1899 again in the GUI thread, so make a copy and note that we need to
1902 char *copy = strdup (reason);
1903 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1907 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1908 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1910 update_sample_rate (0);
1914 /* if the reason is a non-empty string, it means that the backend was shutdown
1915 rather than just Ardour.
1918 if (strlen (reason)) {
1919 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1921 msgstr = string_compose (_("\
1922 JACK has either been shutdown or it\n\
1923 disconnected %1 because %1\n\
1924 was not fast enough. Try to restart\n\
1925 JACK, reconnect and save the session."), PROGRAM_NAME);
1928 MessageDialog msg (*editor, msgstr);
1933 free ((char*) reason);
1938 ARDOUR_UI::do_engine_start ()
1946 error << _("Unable to start the session running")
1956 ARDOUR_UI::setup_theme ()
1958 theme_manager->setup_theme();
1962 ARDOUR_UI::update_clocks ()
1964 if (!editor || !editor->dragging_playhead()) {
1965 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1970 ARDOUR_UI::start_clocking ()
1972 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1976 ARDOUR_UI::stop_clocking ()
1978 clock_signal_connection.disconnect ();
1982 ARDOUR_UI::toggle_clocking ()
1985 if (clock_button.get_active()) {
1994 ARDOUR_UI::_blink (void *arg)
1997 ((ARDOUR_UI *) arg)->blink ();
2004 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2008 ARDOUR_UI::start_blinking ()
2010 /* Start the blink signal. Everybody with a blinking widget
2011 uses Blink to drive the widget's state.
2014 if (blink_timeout_tag < 0) {
2016 blink_timeout_tag = g_timeout_add (240, _blink, this);
2021 ARDOUR_UI::stop_blinking ()
2023 if (blink_timeout_tag >= 0) {
2024 g_source_remove (blink_timeout_tag);
2025 blink_timeout_tag = -1;
2030 /** Ask the user for the name of a new shapshot and then take it.
2034 ARDOUR_UI::snapshot_session (bool switch_to_it)
2036 ArdourPrompter prompter (true);
2039 prompter.set_name ("Prompter");
2040 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2041 prompter.set_title (_("Take Snapshot"));
2042 prompter.set_title (_("Take Snapshot"));
2043 prompter.set_prompt (_("Name of new snapshot"));
2045 if (!switch_to_it) {
2048 struct tm local_time;
2051 localtime_r (&n, &local_time);
2052 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2053 prompter.set_initial_text (timebuf);
2057 switch (prompter.run()) {
2058 case RESPONSE_ACCEPT:
2060 prompter.get_result (snapname);
2062 bool do_save = (snapname.length() != 0);
2065 if (snapname.find ('/') != string::npos) {
2066 MessageDialog msg (_("To ensure compatibility with various systems\n"
2067 "snapshot names may not contain a '/' character"));
2071 if (snapname.find ('\\') != string::npos) {
2072 MessageDialog msg (_("To ensure compatibility with various systems\n"
2073 "snapshot names may not contain a '\\' character"));
2079 vector<sys::path> p;
2080 get_state_files_in_directory (_session->session_directory().root_path(), p);
2081 vector<string> n = get_file_names_no_extension (p);
2082 if (find (n.begin(), n.end(), snapname) != n.end()) {
2084 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2085 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2086 confirm.get_vbox()->pack_start (m, true, true);
2087 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2088 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2089 confirm.show_all ();
2090 switch (confirm.run()) {
2091 case RESPONSE_CANCEL:
2097 save_state (snapname, switch_to_it);
2108 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2110 XMLNode* node = new XMLNode (X_("UI"));
2112 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2113 if (!(*i)->rc_configured()) {
2114 node->add_child_nocopy (*((*i)->get_state ()));
2118 _session->add_extra_xml (*node);
2120 save_state_canfail (name, switch_to_it);
2124 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2129 if (name.length() == 0) {
2130 name = _session->snap_name();
2133 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2137 cerr << "SS canfail\n";
2138 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2143 ARDOUR_UI::primary_clock_value_changed ()
2146 _session->request_locate (primary_clock.current_time ());
2151 ARDOUR_UI::big_clock_value_changed ()
2154 _session->request_locate (big_clock.current_time ());
2159 ARDOUR_UI::secondary_clock_value_changed ()
2162 _session->request_locate (secondary_clock.current_time ());
2167 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2169 if (_session == 0) {
2173 if (_session->step_editing()) {
2177 Session::RecordState const r = _session->record_status ();
2178 bool const h = _session->have_rec_enabled_track ();
2180 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2182 rec_button.set_visual_state (2);
2184 rec_button.set_visual_state (0);
2186 } else if (r == Session::Recording && h) {
2187 rec_button.set_visual_state (1);
2189 rec_button.set_visual_state (0);
2194 ARDOUR_UI::save_template ()
2196 ArdourPrompter prompter (true);
2199 if (!check_audioengine()) {
2203 prompter.set_name (X_("Prompter"));
2204 prompter.set_title (_("Save Mix Template"));
2205 prompter.set_prompt (_("Name for mix template:"));
2206 prompter.set_initial_text(_session->name() + _("-template"));
2207 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2209 switch (prompter.run()) {
2210 case RESPONSE_ACCEPT:
2211 prompter.get_result (name);
2213 if (name.length()) {
2214 _session->save_template (name);
2224 ARDOUR_UI::edit_metadata ()
2226 SessionMetadataEditor dialog;
2227 dialog.set_session (_session);
2228 editor->ensure_float (dialog);
2233 ARDOUR_UI::import_metadata ()
2235 SessionMetadataImporter dialog;
2236 dialog.set_session (_session);
2237 editor->ensure_float (dialog);
2242 ARDOUR_UI::fontconfig_dialog ()
2245 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2246 may not and it can take a while to build it. Warn them.
2249 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2251 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2252 MessageDialog msg (*_startup,
2253 string_compose (_("Welcome to %1.\n\n"
2254 "The program will take a bit longer to start up\n"
2255 "while the system fonts are checked.\n\n"
2256 "This will only be done once, and you will\n"
2257 "not see this message again\n"), PROGRAM_NAME),
2270 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
2272 existing_session = false;
2274 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2275 session_path = cmdline_path;
2276 existing_session = true;
2277 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2278 session_path = Glib::path_get_dirname (string (cmdline_path));
2279 existing_session = true;
2281 /* it doesn't exist, assume the best */
2282 session_path = Glib::path_get_dirname (string (cmdline_path));
2285 session_name = basename_nosuffix (string (cmdline_path));
2289 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2291 /* when this is called, the backend audio system must be running */
2293 /* the main idea here is to deal with the fact that a cmdline argument for the session
2294 can be interpreted in different ways - it could be a directory or a file, and before
2295 we load, we need to know both the session directory and the snapshot (statefile) within it
2296 that we are supposed to use.
2299 if (session_name.length() == 0 || session_path.length() == 0) {
2303 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2305 Glib::ustring predicted_session_file;
2307 predicted_session_file = session_path;
2308 predicted_session_file += '/';
2309 predicted_session_file += session_name;
2310 predicted_session_file += ARDOUR::statefile_suffix;
2312 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2313 existing_session = true;
2316 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2318 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2319 /* existing .ardour file */
2320 existing_session = true;
2324 existing_session = false;
2327 /* lets just try to load it */
2329 if (create_engine ()) {
2330 backend_audio_error (false, _startup);
2334 return load_session (session_path, session_name);
2338 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2340 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2342 MessageDialog msg (str,
2344 Gtk::MESSAGE_WARNING,
2345 Gtk::BUTTONS_YES_NO,
2349 msg.set_name (X_("OpenExistingDialog"));
2350 msg.set_title (_("Open Existing Session"));
2351 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2352 msg.set_position (Gtk::WIN_POS_MOUSE);
2355 switch (msg.run()) {
2364 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2366 BusProfile bus_profile;
2368 if (Profile->get_sae()) {
2370 bus_profile.master_out_channels = 2;
2371 bus_profile.input_ac = AutoConnectPhysical;
2372 bus_profile.output_ac = AutoConnectMaster;
2373 bus_profile.requested_physical_in = 0; // use all available
2374 bus_profile.requested_physical_out = 0; // use all available
2378 /* get settings from advanced section of NSD */
2380 if (_startup->create_master_bus()) {
2381 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2383 bus_profile.master_out_channels = 0;
2386 if (_startup->connect_inputs()) {
2387 bus_profile.input_ac = AutoConnectPhysical;
2389 bus_profile.input_ac = AutoConnectOption (0);
2392 /// @todo some minor tweaks.
2394 bus_profile.output_ac = AutoConnectOption (0);
2396 if (_startup->connect_outputs ()) {
2397 if (_startup->connect_outs_to_master()) {
2398 bus_profile.output_ac = AutoConnectMaster;
2399 } else if (_startup->connect_outs_to_physical()) {
2400 bus_profile.output_ac = AutoConnectPhysical;
2404 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2405 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2408 if (build_session (session_path, session_name, bus_profile)) {
2416 ARDOUR_UI::idle_load (const Glib::ustring& path)
2419 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2420 /* /path/to/foo => /path/to/foo, foo */
2421 load_session (path, basename_nosuffix (path));
2423 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2424 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2428 ARDOUR_COMMAND_LINE::session_name = path;
2431 * new_session_dialog doens't exist in A3
2432 * Try to remove all references to it to
2433 * see if it will compile. NOTE: this will
2434 * likely cause a runtime issue is my somewhat
2438 //if (new_session_dialog) {
2441 /* make it break out of Dialog::run() and
2445 //new_session_dialog->response (1);
2451 ARDOUR_UI::end_loading_messages ()
2457 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2460 // splash->message (msg);
2464 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2466 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2468 Glib::ustring session_name;
2469 Glib::ustring session_path;
2470 Glib::ustring template_name;
2472 bool likely_new = false;
2474 if (! load_template.empty()) {
2475 should_be_new = true;
2476 template_name = load_template;
2481 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2483 /* if they named a specific statefile, use it, otherwise they are
2484 just giving a session folder, and we want to use it as is
2485 to find the session.
2488 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2489 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2491 session_path = ARDOUR_COMMAND_LINE::session_name;
2494 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2498 bool const apply = run_startup (should_be_new, load_template);
2500 if (quit_on_cancel) {
2507 /* if we run the startup dialog again, offer more than just "new session" */
2509 should_be_new = false;
2511 session_name = _startup->session_name (likely_new);
2513 /* this shouldn't happen, but we catch it just in case it does */
2515 if (session_name.empty()) {
2518 if (_startup->use_session_template()) {
2519 template_name = _startup->session_template_name();
2520 _session_is_new = true;
2523 if (session_name[0] == '/' ||
2524 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2525 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2527 /* absolute path or cwd-relative path specified for session name: infer session folder
2528 from what was given.
2531 session_path = Glib::path_get_dirname (session_name);
2532 session_name = Glib::path_get_basename (session_name);
2536 session_path = _startup->session_folder();
2540 if (create_engine ()) {
2544 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2548 Glib::ustring existing = Glib::build_filename (session_path, session_name);
2550 if (!ask_about_loading_existing_session (existing)) {
2551 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2556 _session_is_new = false;
2561 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2563 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2567 if (session_name.find ('/') != Glib::ustring::npos) {
2568 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2569 "session names may not contain a '/' character"));
2571 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2575 if (session_name.find ('\\') != Glib::ustring::npos) {
2576 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2577 "session names may not contain a '\\' character"));
2579 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2583 _session_is_new = true;
2586 if (likely_new && template_name.empty()) {
2588 ret = build_session_from_nsd (session_path, session_name);
2592 ret = load_session (session_path, session_name, template_name);
2593 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2594 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2604 ARDOUR_UI::close_session()
2606 if (!check_audioengine()) {
2610 if (unload_session (true)) {
2614 ARDOUR_COMMAND_LINE::session_name = "";
2616 if (get_session_parameters (true, false)) {
2620 goto_editor_window ();
2624 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2626 Session *new_session;
2630 session_loaded = false;
2632 if (!check_audioengine()) {
2636 unload_status = unload_session ();
2638 if (unload_status < 0) {
2640 } else if (unload_status > 0) {
2645 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2648 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2651 /* this one is special */
2653 catch (AudioEngine::PortRegistrationFailure& err) {
2655 MessageDialog msg (err.what(),
2658 Gtk::BUTTONS_CLOSE);
2660 msg.set_title (_("Port Registration Error"));
2661 msg.set_secondary_text (_("Click the Close button to try again."));
2662 msg.set_position (Gtk::WIN_POS_CENTER);
2666 int response = msg.run ();
2671 case RESPONSE_CANCEL:
2681 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2684 Gtk::BUTTONS_CLOSE);
2686 msg.set_title (_("Loading Error"));
2687 msg.set_secondary_text (_("Click the Close button to try again."));
2688 msg.set_position (Gtk::WIN_POS_CENTER);
2692 int response = msg.run ();
2697 case RESPONSE_CANCEL:
2705 /* Now the session been created, add the transport controls */
2706 new_session->add_controllable(roll_controllable);
2707 new_session->add_controllable(stop_controllable);
2708 new_session->add_controllable(goto_start_controllable);
2709 new_session->add_controllable(goto_end_controllable);
2710 new_session->add_controllable(auto_loop_controllable);
2711 new_session->add_controllable(play_selection_controllable);
2712 new_session->add_controllable(rec_controllable);
2714 set_session (new_session);
2716 session_loaded = true;
2718 goto_editor_window ();
2721 _session->set_clean ();
2732 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name, BusProfile& bus_profile)
2734 Session *new_session;
2737 if (!check_audioengine()) {
2741 session_loaded = false;
2743 x = unload_session ();
2751 _session_is_new = true;
2754 new_session = new Session (*engine, path, snap_name, &bus_profile);
2759 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2765 /* Give the new session the default GUI state */
2766 new_session->add_instant_xml (*Config->instant_xml (X_("Editor")), false);
2767 new_session->add_instant_xml (*Config->instant_xml (X_("Mixer")), false);
2769 set_session (new_session);
2771 session_loaded = true;
2773 new_session->save_state(new_session->name());
2779 ARDOUR_UI::launch_chat ()
2782 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2784 open_uri("http://webchat.freenode.net/?channels=ardour");
2789 ARDOUR_UI::show_about ()
2793 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2796 about->set_transient_for(*editor);
2801 ARDOUR_UI::launch_manual ()
2803 PBD::open_uri("http://ardour.org/flossmanual");
2807 ARDOUR_UI::launch_reference ()
2809 PBD::open_uri("http://ardour.org/refmanual");
2813 ARDOUR_UI::hide_about ()
2816 about->get_window()->set_cursor ();
2822 ARDOUR_UI::about_signal_response (int /*response*/)
2828 ARDOUR_UI::show_splash ()
2832 splash = new Splash;
2840 splash->queue_draw ();
2841 splash->get_window()->process_updates (true);
2846 ARDOUR_UI::hide_splash ()
2854 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2855 const string& plural_msg, const string& singular_msg)
2859 removed = rep.paths.size();
2862 MessageDialog msgd (*editor,
2863 _("No audio files were ready for cleanup"),
2866 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2867 msgd.set_secondary_text (_("If this seems suprising, \n\
2868 check for any existing snapshots.\n\
2869 These may still include regions that\n\
2870 require some unused files to continue to exist."));
2876 ArdourDialog results (_("Clean-up"), true, false);
2878 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2879 CleanupResultsModelColumns() {
2883 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2884 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2888 CleanupResultsModelColumns results_columns;
2889 Glib::RefPtr<Gtk::ListStore> results_model;
2890 Gtk::TreeView results_display;
2892 results_model = ListStore::create (results_columns);
2893 results_display.set_model (results_model);
2894 results_display.append_column (list_title, results_columns.visible_name);
2896 results_display.set_name ("CleanupResultsList");
2897 results_display.set_headers_visible (true);
2898 results_display.set_headers_clickable (false);
2899 results_display.set_reorderable (false);
2901 Gtk::ScrolledWindow list_scroller;
2904 Gtk::HBox dhbox; // the hbox for the image and text
2905 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2906 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2908 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2910 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2913 %1 - number of files removed
2914 %2 - location of "dead_sounds"
2915 %3 - size of files affected
2916 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2919 const char* bprefix;
2920 double space_adjusted = 0;
2922 if (rep.space < 100000.0f) {
2923 bprefix = X_("kilo");
2924 } else if (rep.space < 1000000.0f * 1000) {
2925 bprefix = X_("mega");
2926 space_adjusted = truncf((float)rep.space / 1000.0);
2928 bprefix = X_("giga");
2929 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2933 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2935 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2938 dhbox.pack_start (*dimage, true, false, 5);
2939 dhbox.pack_start (txt, true, false, 5);
2941 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2942 TreeModel::Row row = *(results_model->append());
2943 row[results_columns.visible_name] = *i;
2944 row[results_columns.fullpath] = *i;
2947 list_scroller.add (results_display);
2948 list_scroller.set_size_request (-1, 150);
2949 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2951 dvbox.pack_start (dhbox, true, false, 5);
2952 dvbox.pack_start (list_scroller, true, false, 5);
2953 ddhbox.pack_start (dvbox, true, false, 5);
2955 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2956 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2957 results.set_default_response (RESPONSE_CLOSE);
2958 results.set_position (Gtk::WIN_POS_MOUSE);
2960 results_display.show();
2961 list_scroller.show();
2968 //results.get_vbox()->show();
2969 results.set_resizable (false);
2976 ARDOUR_UI::cleanup ()
2978 if (_session == 0) {
2979 /* shouldn't happen: menu item is insensitive */
2984 MessageDialog checker (_("Are you sure you want to cleanup?"),
2986 Gtk::MESSAGE_QUESTION,
2987 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2989 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2990 ALL undo/redo information will be lost if you cleanup.\n\
2991 After cleanup, unused audio files will be moved to a \
2992 \"dead sounds\" location."));
2994 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2995 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2996 checker.set_default_response (RESPONSE_CANCEL);
2998 checker.set_name (_("CleanupDialog"));
2999 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3000 checker.set_position (Gtk::WIN_POS_MOUSE);
3002 switch (checker.run()) {
3003 case RESPONSE_ACCEPT:
3009 ARDOUR::CleanupReport rep;
3011 editor->prepare_for_cleanup ();
3013 /* do not allow flush until a session is reloaded */
3015 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3017 act->set_sensitive (false);
3020 if (_session->cleanup_sources (rep)) {
3021 editor->finish_cleanup ();
3025 editor->finish_cleanup ();
3028 display_cleanup_results (rep,
3031 The following %1 files were not in use and \n\
3032 have been moved to:\n\
3034 Flushing the wastebasket will \n\
3035 release an additional\n\
3036 %3 %4bytes of disk space.\n"),
3038 The following file was not in use and \n \
3039 has been moved to:\n \
3041 Flushing the wastebasket will \n\
3042 release an additional\n\
3043 %3 %4bytes of disk space.\n"
3049 ARDOUR_UI::flush_trash ()
3051 if (_session == 0) {
3052 /* shouldn't happen: menu item is insensitive */
3056 ARDOUR::CleanupReport rep;
3058 if (_session->cleanup_trash_sources (rep)) {
3062 display_cleanup_results (rep,
3064 _("The following %1 files were deleted from\n\
3066 releasing %3 %4bytes of disk space"),
3067 _("The following file was deleted from\n\
3069 releasing %3 %4bytes of disk space"));
3073 ARDOUR_UI::add_route (Gtk::Window* float_window)
3081 if (add_route_dialog == 0) {
3082 add_route_dialog = new AddRouteDialog (_session);
3084 add_route_dialog->set_transient_for (*float_window);
3088 if (add_route_dialog->is_visible()) {
3089 /* we're already doing this */
3093 ResponseType r = (ResponseType) add_route_dialog->run ();
3095 add_route_dialog->hide();
3098 case RESPONSE_ACCEPT:
3105 if ((count = add_route_dialog->count()) <= 0) {
3109 string template_path = add_route_dialog->track_template();
3111 if (!template_path.empty()) {
3112 _session->new_route_from_template (count, template_path);
3116 uint32_t input_chan = add_route_dialog->channels ();
3117 uint32_t output_chan;
3118 string name_template = add_route_dialog->name_template ();
3119 bool track = add_route_dialog->track ();
3120 bool aux = !track && add_route_dialog->aux();
3121 RouteGroup* route_group = add_route_dialog->route_group ();
3123 AutoConnectOption oac = Config->get_output_auto_connect();
3125 if (oac & AutoConnectMaster) {
3126 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3128 output_chan = input_chan;
3131 /* XXX do something with name template */
3133 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3135 session_add_midi_track (route_group, count);
3137 MessageDialog msg (*editor,
3138 _("Sorry, MIDI Busses are not supported at this time."));
3140 //session_add_midi_bus();
3144 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3146 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3152 ARDOUR_UI::mixer_settings () const
3157 node = _session->instant_xml(X_("Mixer"));
3159 node = Config->instant_xml(X_("Mixer"));
3163 node = new XMLNode (X_("Mixer"));
3170 ARDOUR_UI::editor_settings () const
3175 node = _session->instant_xml(X_("Editor"));
3177 node = Config->instant_xml(X_("Editor"));
3181 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3182 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3187 node = new XMLNode (X_("Editor"));
3194 ARDOUR_UI::keyboard_settings () const
3198 node = Config->extra_xml(X_("Keyboard"));
3201 node = new XMLNode (X_("Keyboard"));
3207 ARDOUR_UI::create_xrun_marker(nframes_t where)
3209 editor->mouse_add_new_marker (where, false, true);
3213 ARDOUR_UI::halt_on_xrun_message ()
3215 MessageDialog msg (*editor,
3216 _("Recording was stopped because your system could not keep up."));
3221 ARDOUR_UI::xrun_handler(nframes_t where)
3227 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3229 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3230 create_xrun_marker(where);
3233 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3234 halt_on_xrun_message ();
3239 ARDOUR_UI::disk_overrun_handler ()
3241 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3243 if (!have_disk_speed_dialog_displayed) {
3244 have_disk_speed_dialog_displayed = true;
3245 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3246 The disk system on your computer\n\
3247 was not able to keep up with %1.\n\
3249 Specifically, it failed to write data to disk\n\
3250 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3251 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3257 ARDOUR_UI::disk_underrun_handler ()
3259 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3261 if (!have_disk_speed_dialog_displayed) {
3262 have_disk_speed_dialog_displayed = true;
3263 MessageDialog* msg = new MessageDialog (*editor,
3264 string_compose (_("The disk system on your computer\n\
3265 was not able to keep up with %1.\n\
3267 Specifically, it failed to read data from disk\n\
3268 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3269 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3275 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3277 have_disk_speed_dialog_displayed = false;
3282 ARDOUR_UI::session_dialog (std::string msg)
3284 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3289 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3291 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3300 ARDOUR_UI::pending_state_dialog ()
3302 HBox* hbox = new HBox();
3303 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3304 ArdourDialog dialog (_("Crash Recovery"), true);
3306 This session appears to have been in\n\
3307 middle of recording when ardour or\n\
3308 the computer was shutdown.\n\
3310 Ardour can recover any captured audio for\n\
3311 you, or it can ignore it. Please decide\n\
3312 what you would like to do.\n"));
3313 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3314 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3315 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3316 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3317 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3318 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3319 dialog.set_default_response (RESPONSE_ACCEPT);
3320 dialog.set_position (WIN_POS_CENTER);
3325 switch (dialog.run ()) {
3326 case RESPONSE_ACCEPT:
3334 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3336 HBox* hbox = new HBox();
3337 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3338 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3339 Label message (string_compose (_("\
3340 This session was created with a sample rate of %1 Hz\n\
3342 The audioengine is currently running at %2 Hz\n"), desired, actual));
3344 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3345 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3346 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3347 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3348 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3349 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3350 dialog.set_default_response (RESPONSE_ACCEPT);
3351 dialog.set_position (WIN_POS_CENTER);
3356 switch (dialog.run ()) {
3357 case RESPONSE_ACCEPT:
3366 ARDOUR_UI::disconnect_from_jack ()
3369 if( engine->disconnect_from_jack ()) {
3370 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3374 update_sample_rate (0);
3379 ARDOUR_UI::reconnect_to_jack ()
3382 if (engine->reconnect_to_jack ()) {
3383 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3387 update_sample_rate (0);
3392 ARDOUR_UI::use_config ()
3394 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3396 set_transport_controllable_state (*node);
3401 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3403 if (Config->get_primary_clock_delta_edit_cursor()) {
3404 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3406 primary_clock.set (pos, 0, true);
3409 if (Config->get_secondary_clock_delta_edit_cursor()) {
3410 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3412 secondary_clock.set (pos);
3415 if (big_clock_window->get()) {
3416 big_clock.set (pos);
3422 ARDOUR_UI::step_edit_status_change (bool yn)
3424 // XXX should really store pre-step edit status of things
3425 // we make insensitive
3428 rec_button.set_visual_state (3);
3429 rec_button.set_sensitive (false);
3431 rec_button.set_visual_state (0);
3432 rec_button.set_sensitive (true);
3437 ARDOUR_UI::record_state_changed ()
3439 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3441 if (!_session || !big_clock_window->get()) {
3442 /* why bother - the clock isn't visible */
3446 Session::RecordState const r = _session->record_status ();
3447 bool const h = _session->have_rec_enabled_track ();
3449 if (r == Session::Recording && h) {
3450 big_clock.set_widget_name ("BigClockRecording");
3452 big_clock.set_widget_name ("BigClockNonRecording");
3457 ARDOUR_UI::first_idle ()
3460 _session->allow_auto_play (true);
3464 editor->first_idle();
3467 Keyboard::set_can_save_keybindings (true);
3472 ARDOUR_UI::store_clock_modes ()
3474 XMLNode* node = new XMLNode(X_("ClockModes"));
3476 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3477 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3480 _session->add_extra_xml (*node);
3481 _session->set_dirty ();
3486 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3487 : Controllable (name), ui (u), type(tp)
3493 ARDOUR_UI::TransportControllable::set_value (double val)
3495 if (type == ShuttleControl) {
3502 fract = -((0.5 - val)/0.5);
3504 fract = ((val - 0.5)/0.5);
3508 ui.set_shuttle_fract (fract);
3513 /* do nothing: these are radio-style actions */
3517 const char *action = 0;
3521 action = X_("Roll");
3524 action = X_("Stop");
3527 action = X_("Goto Start");
3530 action = X_("Goto End");
3533 action = X_("Loop");
3536 action = X_("Play Selection");
3539 action = X_("Record");
3549 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3557 ARDOUR_UI::TransportControllable::get_value (void) const
3576 case ShuttleControl:
3586 ARDOUR_UI::TransportControllable::set_id (const string& str)
3592 ARDOUR_UI::setup_profile ()
3594 if (gdk_screen_width() < 1200) {
3595 Profile->set_small_screen ();
3599 if (getenv ("ARDOUR_SAE")) {
3600 Profile->set_sae ();
3601 Profile->set_single_package ();
3606 ARDOUR_UI::toggle_translations ()
3608 using namespace Glib;
3610 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3612 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3615 string i18n_killer = ARDOUR::translation_kill_path();
3617 bool already_enabled = !ARDOUR::translations_are_disabled ();
3619 if (ract->get_active ()) {
3620 /* we don't care about errors */
3621 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3624 /* we don't care about errors */
3625 unlink (i18n_killer.c_str());
3628 if (already_enabled != ract->get_active()) {
3629 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3631 Gtk::MESSAGE_WARNING,
3633 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3634 win.set_position (Gtk::WIN_POS_CENTER);
3642 /** Add a window proxy to our list, so that its state will be saved.
3643 * This call also causes the window to be created and opened if its
3644 * state was saved as `visible'.
3647 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3649 _window_proxies.push_back (p);
3653 /** Remove a window proxy from our list. Must be called if a WindowProxy
3654 * is deleted, to prevent hanging pointers.
3657 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3659 _window_proxies.remove (p);