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"
113 using namespace ARDOUR;
115 using namespace Gtkmm2ext;
118 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
119 UIConfiguration *ARDOUR_UI::ui_config = 0;
121 sigc::signal<void,bool> ARDOUR_UI::Blink;
122 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
123 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
124 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
126 bool could_be_a_valid_path (const string& path);
128 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
130 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
132 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
133 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
134 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
135 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
139 preroll_button (_("pre\nroll")),
140 postroll_button (_("post\nroll")),
144 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
148 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
149 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
150 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
151 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
152 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
153 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
154 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
155 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
156 shuttle_controller_binding_proxy (shuttle_controllable),
158 roll_button (roll_controllable),
159 stop_button (stop_controllable),
160 goto_start_button (goto_start_controllable),
161 goto_end_button (goto_end_controllable),
162 auto_loop_button (auto_loop_controllable),
163 play_selection_button (play_selection_controllable),
164 rec_button (rec_controllable),
166 shuttle_units_button (_("% ")),
168 punch_in_button (_("Punch In")),
169 punch_out_button (_("Punch Out")),
170 auto_return_button (_("Auto Return")),
171 auto_play_button (_("Auto Play")),
172 auto_input_button (_("Auto Input")),
173 click_button (_("Click")),
174 time_master_button (_("time\nmaster")),
176 auditioning_alert_button (_("AUDITION")),
177 solo_alert_button (_("SOLO")),
179 error_log_button (_("Errors"))
182 using namespace Gtk::Menu_Helpers;
188 // _auto_display_errors = false;
190 * This was commented out as it wasn't defined
191 * in A3 IIRC. If this is not needed it should
192 * be completely removed.
200 if (theArdourUI == 0) {
204 ui_config = new UIConfiguration();
205 theme_manager = new ThemeManager();
211 _session_is_new = false;
212 big_clock_window = 0;
213 big_clock_height = 0;
214 big_clock_resize_in_progress = false;
215 session_selector_window = 0;
216 last_key_press_time = 0;
217 _will_create_new_session_automatically = false;
218 add_route_dialog = 0;
220 rc_option_editor = 0;
221 session_option_editor = 0;
223 open_session_selector = 0;
224 have_configure_timeout = false;
225 have_disk_speed_dialog_displayed = false;
226 session_loaded = false;
227 last_speed_displayed = -1.0f;
228 ignore_dual_punch = false;
229 original_big_clock_width = -1;
230 original_big_clock_height = -1;
231 original_big_clock_font_size = 0;
233 roll_button.unset_flags (Gtk::CAN_FOCUS);
234 stop_button.unset_flags (Gtk::CAN_FOCUS);
235 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
236 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
237 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
238 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
239 rec_button.unset_flags (Gtk::CAN_FOCUS);
241 last_configure_time= 0;
243 shuttle_grabbed = false;
245 shuttle_max_speed = 8.0f;
247 shuttle_style_menu = 0;
248 shuttle_unit_menu = 0;
250 // We do not have jack linked in yet so;
252 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
254 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
255 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
257 /* handle dialog requests */
259 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
261 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
263 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
265 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
267 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
269 /* handle requests to quit (coming from JACK session) */
271 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::finish, this), gui_context ());
273 /* handle requests to deal with missing files */
275 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
277 /* lets get this party started */
280 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
281 throw failed_constructor ();
284 setup_gtk_ardour_enums ();
287 GainMeter::setup_slider_pix ();
288 RouteTimeAxisView::setup_slider_pix ();
289 SendProcessorEntry::setup_slider_pix ();
290 SessionEvent::create_per_thread_pool ("GUI", 512);
292 } catch (failed_constructor& err) {
293 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
298 /* we like keyboards */
300 keyboard = new ArdourKeyboard(*this);
302 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
304 keyboard->set_state (*node, Stateful::loading_state_version);
309 TimeAxisViewItem::set_constant_heights ();
311 /* The following must happen after ARDOUR::init() so that Config is set up */
313 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
314 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
316 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
317 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
318 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
319 Config->extra_xml (X_("UI")),
320 string_compose ("toggle-%1-connection-manager", (*i).to_string())
326 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
327 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
332 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
334 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
337 _startup = new ArdourStartup ();
339 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
341 if (audio_setup && _startup->engine_control()) {
342 _startup->engine_control()->set_state (*audio_setup);
345 _startup->set_new_only (should_be_new);
346 if (!load_template.empty()) {
347 _startup->set_load_template( load_template );
349 _startup->present ();
355 switch (_startup->response()) {
364 ARDOUR_UI::create_engine ()
366 // this gets called every time by new_session()
372 loading_message (_("Starting audio engine"));
375 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
382 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
383 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
384 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
386 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
388 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
396 ARDOUR_UI::post_engine ()
398 /* Things to be done once we create the AudioEngine
401 ARDOUR::init_post_engine ();
403 ActionManager::init ();
406 if (setup_windows ()) {
407 throw failed_constructor ();
410 check_memory_locking();
412 /* this is the first point at which all the keybindings are available */
414 if (ARDOUR_COMMAND_LINE::show_key_actions) {
415 vector<string> names;
416 vector<string> paths;
418 vector<AccelKey> bindings;
420 ActionManager::get_all_actions (names, paths, keys, bindings);
422 vector<string>::iterator n;
423 vector<string>::iterator k;
424 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
425 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
431 blink_timeout_tag = -1;
433 /* this being a GUI and all, we want peakfiles */
435 AudioFileSource::set_build_peakfiles (true);
436 AudioFileSource::set_build_missing_peakfiles (true);
438 /* set default clock modes */
440 if (Profile->get_sae()) {
441 primary_clock.set_mode (AudioClock::BBT);
442 secondary_clock.set_mode (AudioClock::MinSec);
444 primary_clock.set_mode (AudioClock::Timecode);
445 secondary_clock.set_mode (AudioClock::BBT);
448 /* start the time-of-day-clock */
451 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
452 update_wall_clock ();
453 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
456 update_disk_space ();
458 update_sample_rate (engine->frame_rate());
460 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
461 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
462 Config->map_parameters (pc);
464 /* now start and maybe save state */
466 if (do_engine_start () == 0) {
467 if (_session && _session_is_new) {
468 /* we need to retain initial visual
469 settings for a new session
471 _session->save_state ("");
476 ARDOUR_UI::~ARDOUR_UI ()
481 delete add_route_dialog;
485 ARDOUR_UI::pop_back_splash ()
487 if (Splash::instance()) {
488 // Splash::instance()->pop_back();
489 Splash::instance()->hide ();
494 ARDOUR_UI::configure_timeout ()
496 if (last_configure_time == 0) {
497 /* no configure events yet */
501 /* force a gap of 0.5 seconds since the last configure event
504 if (get_microseconds() - last_configure_time < 500000) {
507 have_configure_timeout = false;
508 cerr << "config event-driven save\n";
509 save_ardour_state ();
515 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
517 if (have_configure_timeout) {
518 last_configure_time = get_microseconds();
520 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
521 have_configure_timeout = true;
528 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
530 const XMLProperty* prop;
532 if ((prop = node.property ("roll")) != 0) {
533 roll_controllable->set_id (prop->value());
535 if ((prop = node.property ("stop")) != 0) {
536 stop_controllable->set_id (prop->value());
538 if ((prop = node.property ("goto-start")) != 0) {
539 goto_start_controllable->set_id (prop->value());
541 if ((prop = node.property ("goto-end")) != 0) {
542 goto_end_controllable->set_id (prop->value());
544 if ((prop = node.property ("auto-loop")) != 0) {
545 auto_loop_controllable->set_id (prop->value());
547 if ((prop = node.property ("play-selection")) != 0) {
548 play_selection_controllable->set_id (prop->value());
550 if ((prop = node.property ("rec")) != 0) {
551 rec_controllable->set_id (prop->value());
553 if ((prop = node.property ("shuttle")) != 0) {
554 shuttle_controllable->set_id (prop->value());
559 ARDOUR_UI::get_transport_controllable_state ()
561 XMLNode* node = new XMLNode(X_("TransportControllables"));
564 roll_controllable->id().print (buf, sizeof (buf));
565 node->add_property (X_("roll"), buf);
566 stop_controllable->id().print (buf, sizeof (buf));
567 node->add_property (X_("stop"), buf);
568 goto_start_controllable->id().print (buf, sizeof (buf));
569 node->add_property (X_("goto_start"), buf);
570 goto_end_controllable->id().print (buf, sizeof (buf));
571 node->add_property (X_("goto_end"), buf);
572 auto_loop_controllable->id().print (buf, sizeof (buf));
573 node->add_property (X_("auto_loop"), buf);
574 play_selection_controllable->id().print (buf, sizeof (buf));
575 node->add_property (X_("play_selection"), buf);
576 rec_controllable->id().print (buf, sizeof (buf));
577 node->add_property (X_("rec"), buf);
578 shuttle_controllable->id().print (buf, sizeof (buf));
579 node->add_property (X_("shuttle"), buf);
586 ARDOUR_UI::autosave_session ()
588 if (g_main_depth() > 1) {
589 /* inside a recursive main loop,
590 give up because we may not be able to
596 if (!Config->get_periodic_safety_backups()) {
601 _session->maybe_write_autosave();
608 ARDOUR_UI::update_autosave ()
610 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
612 if (_session && _session->dirty()) {
613 if (_autosave_connection.connected()) {
614 _autosave_connection.disconnect();
617 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
618 Config->get_periodic_safety_backup_interval() * 1000);
621 if (_autosave_connection.connected()) {
622 _autosave_connection.disconnect();
628 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
632 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
634 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
637 MessageDialog win (title,
643 win.set_secondary_text(_("There are several possible reasons:\n\
645 1) You requested audio parameters that are not supported..\n\
646 2) JACK is running as another user.\n\
648 Please consider the possibilities, and perhaps try different parameters."));
650 win.set_secondary_text(_("There are several possible reasons:\n\
652 1) JACK is not running.\n\
653 2) JACK is running as another user, perhaps root.\n\
654 3) There is already another client called \"ardour\".\n\
656 Please consider the possibilities, and perhaps (re)start JACK."));
660 win.set_transient_for (*toplevel);
664 win.add_button (Stock::OK, RESPONSE_CLOSE);
666 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
669 win.set_default_response (RESPONSE_CLOSE);
672 win.set_position (Gtk::WIN_POS_CENTER);
675 /* we just don't care about the result, but we want to block */
681 ARDOUR_UI::startup ()
683 Application* app = Application::instance ();
685 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
686 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
689 call_the_mothership (VERSIONSTRING);
694 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
700 goto_editor_window ();
702 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
703 to be opened on top of the editor window that goto_editor_window() just opened.
705 add_window_proxy (location_ui);
706 add_window_proxy (big_clock_window);
707 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
708 add_window_proxy (_global_port_matrix[*i]);
711 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
715 ARDOUR_UI::no_memory_warning ()
717 XMLNode node (X_("no-memory-warning"));
718 Config->add_instant_xml (node);
722 ARDOUR_UI::check_memory_locking ()
725 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
729 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
731 if (engine->is_realtime() && memory_warning_node == 0) {
733 struct rlimit limits;
735 long pages, page_size;
737 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
740 ram = (int64_t) pages * (int64_t) page_size;
743 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
747 if (limits.rlim_cur != RLIM_INFINITY) {
749 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
753 string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
754 "This might cause %1 to run out of memory before your system "
755 "runs out of memory. \n\n"
756 "You can view the memory limit with 'ulimit -l', "
757 "and it is normally controlled by /etc/security/limits.conf"),
758 PROGRAM_NAME).c_str());
760 VBox* vbox = msg.get_vbox();
762 CheckButton cb (_("Do not show this window again"));
764 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
766 hbox.pack_start (cb, true, false);
767 vbox->pack_start (hbox);
774 editor->ensure_float (msg);
784 ARDOUR_UI::queue_finish ()
786 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
790 ARDOUR_UI::idle_finish ()
793 return false; /* do not call again */
802 if (_session->transport_rolling() && (++tries < 8)) {
803 _session->request_stop (false, true);
807 if (_session->dirty()) {
808 switch (ask_about_saving_session(_("quit"))) {
813 /* use the default name */
814 if (save_state_canfail ("")) {
815 /* failed - don't quit */
816 MessageDialog msg (*editor,
818 Ardour was unable to save your session.\n\n\
819 If you still wish to quit, please use the\n\n\
820 \"Just quit\" option."));
831 second_connection.disconnect ();
832 point_one_second_connection.disconnect ();
833 point_oh_five_second_connection.disconnect ();
834 point_zero_one_second_connection.disconnect();
837 /* Save state before deleting the session, as that causes some
838 windows to be destroyed before their visible state can be
841 save_ardour_state ();
844 // _session->set_deletion_in_progress ();
845 _session->set_clean ();
846 _session->remove_pending_capture_state ();
851 ArdourDialog::close_all_dialogs ();
857 ARDOUR_UI::ask_about_saving_session (const string & what)
859 ArdourDialog window (_("Unsaved Session"));
860 Gtk::HBox dhbox; // the hbox for the image and text
861 Gtk::Label prompt_label;
862 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
866 msg = string_compose(_("Don't %1"), what);
867 window.add_button (msg, RESPONSE_REJECT);
868 msg = string_compose(_("Just %1"), what);
869 window.add_button (msg, RESPONSE_APPLY);
870 msg = string_compose(_("Save and %1"), what);
871 window.add_button (msg, RESPONSE_ACCEPT);
873 window.set_default_response (RESPONSE_ACCEPT);
875 Gtk::Button noquit_button (msg);
876 noquit_button.set_name ("EditorGTKButton");
881 if (_session->snap_name() == _session->name()) {
884 type = _("snapshot");
886 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?"),
887 type, _session->snap_name());
889 prompt_label.set_text (prompt);
890 prompt_label.set_name (X_("PrompterLabel"));
891 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
893 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
894 dhbox.set_homogeneous (false);
895 dhbox.pack_start (*dimage, false, false, 5);
896 dhbox.pack_start (prompt_label, true, false, 5);
897 window.get_vbox()->pack_start (dhbox);
899 window.set_name (_("Prompter"));
900 window.set_position (Gtk::WIN_POS_MOUSE);
901 window.set_modal (true);
902 window.set_resizable (false);
908 window.set_keep_above (true);
911 ResponseType r = (ResponseType) window.run();
916 case RESPONSE_ACCEPT: // save and get out of here
918 case RESPONSE_APPLY: // get out of here
928 ARDOUR_UI::every_second ()
931 update_buffer_load ();
932 update_disk_space ();
937 ARDOUR_UI::every_point_one_seconds ()
939 update_speed_display ();
940 RapidScreenUpdate(); /* EMIT_SIGNAL */
945 ARDOUR_UI::every_point_zero_one_seconds ()
947 // august 2007: actual update frequency: 40Hz, not 100Hz
949 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
954 ARDOUR_UI::update_sample_rate (framecnt_t)
958 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
960 if (!engine->connected()) {
962 snprintf (buf, sizeof (buf), _("disconnected"));
966 framecnt_t rate = engine->frame_rate();
968 if (fmod (rate, 1000.0) != 0.0) {
969 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
970 (float) rate/1000.0f,
971 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
973 snprintf (buf, sizeof (buf), _("%" PRId64 " kHz / %4.1f ms"),
975 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
979 sample_rate_label.set_text (buf);
983 ARDOUR_UI::update_cpu_load ()
986 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
987 cpu_load_label.set_text (buf);
991 ARDOUR_UI::update_buffer_load ()
997 c = _session->capture_load ();
998 p = _session->playback_load ();
1000 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
1001 _session->playback_load(), _session->capture_load());
1002 buffer_load_label.set_text (buf);
1004 buffer_load_label.set_text ("");
1009 ARDOUR_UI::count_recenabled_streams (Route& route)
1011 Track* track = dynamic_cast<Track*>(&route);
1012 if (track && track->record_enabled()) {
1013 rec_enabled_streams += track->n_inputs().n_total();
1018 ARDOUR_UI::update_disk_space()
1020 if (_session == 0) {
1024 framecnt_t frames = _session->available_capture_duration();
1026 framecnt_t fr = _session->frame_rate();
1028 if (frames == max_framecnt) {
1029 strcpy (buf, _("Disk: 24hrs+"));
1031 rec_enabled_streams = 0;
1032 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1034 if (rec_enabled_streams) {
1035 frames /= rec_enabled_streams;
1042 hrs = frames / (fr * 3600);
1043 frames -= hrs * fr * 3600;
1044 mins = frames / (fr * 60);
1045 frames -= mins * fr * 60;
1048 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1051 disk_space_label.set_text (buf);
1053 // An attempt to make the disk space label flash red when space has run out.
1055 if (frames < fr * 60 * 5) {
1056 /* disk_space_box.style ("disk_space_label_empty"); */
1058 /* disk_space_box.style ("disk_space_label"); */
1064 ARDOUR_UI::update_wall_clock ()
1071 tm_now = localtime (&now);
1073 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1074 wall_clock_label.set_text (buf);
1080 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1082 session_popup_menu->popup (0, 0);
1087 ARDOUR_UI::redisplay_recent_sessions ()
1089 std::vector<sys::path> session_directories;
1090 RecentSessionsSorter cmp;
1092 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1093 recent_session_model->clear ();
1095 ARDOUR::RecentSessions rs;
1096 ARDOUR::read_recent_sessions (rs);
1099 recent_session_display.set_model (recent_session_model);
1103 // sort them alphabetically
1104 sort (rs.begin(), rs.end(), cmp);
1106 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1107 session_directories.push_back ((*i).second);
1110 for (vector<sys::path>::const_iterator i = session_directories.begin();
1111 i != session_directories.end(); ++i)
1113 std::vector<sys::path> state_file_paths;
1115 // now get available states for this session
1117 get_state_files_in_directory (*i, state_file_paths);
1119 vector<string*>* states;
1120 vector<const gchar*> item;
1121 string fullpath = (*i).to_string();
1123 /* remove any trailing / */
1125 if (fullpath[fullpath.length()-1] == '/') {
1126 fullpath = fullpath.substr (0, fullpath.length()-1);
1129 /* check whether session still exists */
1130 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1131 /* session doesn't exist */
1132 cerr << "skipping non-existent session " << fullpath << endl;
1136 /* now get available states for this session */
1138 if ((states = Session::possible_states (fullpath)) == 0) {
1139 /* no state file? */
1143 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1145 Gtk::TreeModel::Row row = *(recent_session_model->append());
1147 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1148 row[recent_session_columns.fullpath] = fullpath;
1150 if (state_file_names.size() > 1) {
1154 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1155 i2 != state_file_names.end(); ++i2)
1158 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1160 child_row[recent_session_columns.visible_name] = *i2;
1161 child_row[recent_session_columns.fullpath] = fullpath;
1166 recent_session_display.set_model (recent_session_model);
1170 ARDOUR_UI::build_session_selector ()
1172 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1174 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1176 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1177 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1178 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1179 recent_session_model = TreeStore::create (recent_session_columns);
1180 recent_session_display.set_model (recent_session_model);
1181 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1182 recent_session_display.set_headers_visible (false);
1183 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1184 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1186 scroller->add (recent_session_display);
1187 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1189 session_selector_window->set_name ("SessionSelectorWindow");
1190 session_selector_window->set_size_request (200, 400);
1191 session_selector_window->get_vbox()->pack_start (*scroller);
1193 recent_session_display.show();
1195 //session_selector_window->get_vbox()->show();
1199 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1201 session_selector_window->response (RESPONSE_ACCEPT);
1205 ARDOUR_UI::open_recent_session ()
1207 bool can_return = (_session != 0);
1209 if (session_selector_window == 0) {
1210 build_session_selector ();
1213 redisplay_recent_sessions ();
1217 session_selector_window->set_position (WIN_POS_MOUSE);
1219 ResponseType r = (ResponseType) session_selector_window->run ();
1222 case RESPONSE_ACCEPT:
1226 session_selector_window->hide();
1233 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1237 session_selector_window->hide();
1239 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1241 if (i == recent_session_model->children().end()) {
1245 std::string path = (*i)[recent_session_columns.fullpath];
1246 std::string state = (*i)[recent_session_columns.visible_name];
1248 _session_is_new = false;
1250 if (load_session (path, state) == 0) {
1259 ARDOUR_UI::check_audioengine ()
1262 if (!engine->connected()) {
1263 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1264 "You cannot open or close sessions in this condition"),
1277 ARDOUR_UI::open_session ()
1279 if (!check_audioengine()) {
1284 /* popup selector window */
1286 if (open_session_selector == 0) {
1288 /* ardour sessions are folders */
1290 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1291 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1292 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1293 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1295 FileFilter session_filter;
1296 session_filter.add_pattern ("*.ardour");
1297 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1298 open_session_selector->add_filter (session_filter);
1299 open_session_selector->set_filter (session_filter);
1302 int response = open_session_selector->run();
1303 open_session_selector->hide ();
1306 case RESPONSE_ACCEPT:
1309 open_session_selector->hide();
1313 open_session_selector->hide();
1314 string session_path = open_session_selector->get_filename();
1318 if (session_path.length() > 0) {
1319 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1320 _session_is_new = isnew;
1321 load_session (path, name);
1328 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1330 list<boost::shared_ptr<MidiTrack> > tracks;
1332 if (_session == 0) {
1333 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1340 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1342 if (tracks.size() != how_many) {
1343 if (how_many == 1) {
1344 error << _("could not create a new midi track") << endmsg;
1346 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1350 if ((route = _session->new_midi_route ()) == 0) {
1351 error << _("could not create new midi bus") << endmsg;
1357 MessageDialog msg (*editor,
1358 string_compose (_("There are insufficient JACK ports available\n\
1359 to create a new track or bus.\n\
1360 You should save %1, exit and\n\
1361 restart JACK with more ports."), PROGRAM_NAME));
1368 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)
1370 list<boost::shared_ptr<AudioTrack> > tracks;
1373 if (_session == 0) {
1374 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1380 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1382 if (tracks.size() != how_many) {
1383 if (how_many == 1) {
1384 error << _("could not create a new audio track") << endmsg;
1386 error << string_compose (_("could only create %1 of %2 new audio %3"),
1387 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1393 routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1395 if (routes.size() != how_many) {
1396 if (how_many == 1) {
1397 error << _("could not create a new audio track") << endmsg;
1399 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1406 MessageDialog msg (*editor,
1407 string_compose (_("There are insufficient JACK ports available\n\
1408 to create a new track or bus.\n\
1409 You should save %1, exit and\n\
1410 restart JACK with more ports."), PROGRAM_NAME));
1417 ARDOUR_UI::do_transport_locate (framepos_t new_position, bool with_roll)
1419 framecnt_t _preroll = 0;
1422 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1423 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1425 if (new_position > _preroll) {
1426 new_position -= _preroll;
1431 _session->request_locate (new_position, with_roll);
1436 ARDOUR_UI::transport_goto_start ()
1439 _session->goto_start();
1441 /* force displayed area in editor to start no matter
1442 what "follow playhead" setting is.
1446 editor->center_screen (_session->current_start_frame ());
1452 ARDOUR_UI::transport_goto_zero ()
1455 _session->request_locate (0);
1457 /* force displayed area in editor to start no matter
1458 what "follow playhead" setting is.
1462 editor->reset_x_origin (0);
1468 ARDOUR_UI::transport_goto_wallclock ()
1470 if (_session && editor) {
1477 localtime_r (&now, &tmnow);
1479 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1480 frames += tmnow.tm_min * (60 * _session->frame_rate());
1481 frames += tmnow.tm_sec * _session->frame_rate();
1483 _session->request_locate (frames, _session->transport_rolling ());
1485 /* force displayed area in editor to start no matter
1486 what "follow playhead" setting is.
1490 editor->center_screen (frames);
1496 ARDOUR_UI::transport_goto_end ()
1499 framepos_t const frame = _session->current_end_frame();
1500 _session->request_locate (frame);
1502 /* force displayed area in editor to start no matter
1503 what "follow playhead" setting is.
1507 editor->center_screen (frame);
1513 ARDOUR_UI::transport_stop ()
1519 if (_session->is_auditioning()) {
1520 _session->cancel_audition ();
1524 _session->request_stop (false, true);
1528 ARDOUR_UI::transport_stop_and_forget_capture ()
1531 _session->request_stop (true, true);
1536 ARDOUR_UI::remove_last_capture()
1539 editor->remove_last_capture();
1544 ARDOUR_UI::transport_record (bool roll)
1548 switch (_session->record_status()) {
1549 case Session::Disabled:
1550 if (_session->ntracks() == 0) {
1551 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1555 _session->maybe_enable_record ();
1560 case Session::Recording:
1562 _session->request_stop();
1564 _session->disable_record (false, true);
1568 case Session::Enabled:
1569 _session->disable_record (false, true);
1572 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1576 ARDOUR_UI::transport_roll ()
1582 if (_session->is_auditioning()) {
1586 if (_session->config.get_external_sync()) {
1587 switch (_session->config.get_sync_source()) {
1591 /* transport controlled by the master */
1596 bool rolling = _session->transport_rolling();
1598 if (_session->get_play_loop()) {
1599 /* XXX it is not possible to just leave seamless loop and keep
1600 playing at present (nov 4th 2009)
1602 if (!Config->get_seamless_loop()) {
1603 _session->request_play_loop (false, true);
1605 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1606 /* stop playing a range if we currently are */
1607 _session->request_play_range (0, true);
1610 if (join_play_range_button.get_active()) {
1611 _session->request_play_range (&editor->get_selection().time, true);
1615 _session->request_transport_speed (1.0f);
1620 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1627 if (_session->is_auditioning()) {
1628 _session->cancel_audition ();
1632 if (_session->config.get_external_sync()) {
1633 switch (_session->config.get_sync_source()) {
1637 /* transport controlled by the master */
1642 bool rolling = _session->transport_rolling();
1643 bool affect_transport = true;
1645 if (rolling && roll_out_of_bounded_mode) {
1646 /* drop out of loop/range playback but leave transport rolling */
1647 if (_session->get_play_loop()) {
1648 if (Config->get_seamless_loop()) {
1649 /* the disk buffers contain copies of the loop - we can't
1650 just keep playing, so stop the transport. the user
1651 can restart as they wish.
1653 affect_transport = true;
1655 /* disk buffers are normal, so we can keep playing */
1656 affect_transport = false;
1658 _session->request_play_loop (false, true);
1659 } else if (_session->get_play_range ()) {
1660 affect_transport = false;
1661 _session->request_play_range (0, true);
1665 if (affect_transport) {
1667 _session->request_stop (with_abort, true);
1669 if (join_play_range_button.get_active()) {
1670 _session->request_play_range (&editor->get_selection().time, true);
1673 _session->request_transport_speed (1.0f);
1679 ARDOUR_UI::toggle_session_auto_loop ()
1682 if (_session->get_play_loop()) {
1683 if (_session->transport_rolling()) {
1684 Location * looploc = _session->locations()->auto_loop_location();
1686 _session->request_locate (looploc->start(), true);
1689 _session->request_play_loop (false);
1692 Location * looploc = _session->locations()->auto_loop_location();
1694 _session->request_play_loop (true);
1701 ARDOUR_UI::transport_play_selection ()
1707 editor->play_selection ();
1711 ARDOUR_UI::transport_rewind (int option)
1713 float current_transport_speed;
1716 current_transport_speed = _session->transport_speed();
1718 if (current_transport_speed >= 0.0f) {
1721 _session->request_transport_speed (-1.0f);
1724 _session->request_transport_speed (-4.0f);
1727 _session->request_transport_speed (-0.5f);
1732 _session->request_transport_speed (current_transport_speed * 1.5f);
1738 ARDOUR_UI::transport_forward (int option)
1740 float current_transport_speed;
1743 current_transport_speed = _session->transport_speed();
1745 if (current_transport_speed <= 0.0f) {
1748 _session->request_transport_speed (1.0f);
1751 _session->request_transport_speed (4.0f);
1754 _session->request_transport_speed (0.5f);
1759 _session->request_transport_speed (current_transport_speed * 1.5f);
1766 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1768 if (_session == 0) {
1772 boost::shared_ptr<Route> r;
1774 if ((r = _session->route_by_remote_id (rid)) != 0) {
1778 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1779 t->set_record_enabled (!t->record_enabled(), this);
1782 if (_session == 0) {
1788 ARDOUR_UI::map_transport_state ()
1790 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1793 auto_loop_button.set_visual_state (0);
1794 play_selection_button.set_visual_state (0);
1795 roll_button.set_visual_state (0);
1796 stop_button.set_visual_state (1);
1800 float sp = _session->transport_speed();
1803 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1804 shuttle_box.queue_draw ();
1805 } else if (sp == 0.0f) {
1807 shuttle_box.queue_draw ();
1808 update_disk_space ();
1815 if (_session->get_play_range()) {
1817 play_selection_button.set_visual_state (1);
1818 roll_button.set_visual_state (0);
1819 auto_loop_button.set_visual_state (0);
1821 } else if (_session->get_play_loop ()) {
1823 auto_loop_button.set_visual_state (1);
1824 play_selection_button.set_visual_state (0);
1825 roll_button.set_visual_state (0);
1829 roll_button.set_visual_state (1);
1830 play_selection_button.set_visual_state (0);
1831 auto_loop_button.set_visual_state (0);
1834 if (join_play_range_button.get_active()) {
1835 /* light up both roll and play-selection if they are joined */
1836 roll_button.set_visual_state (1);
1837 play_selection_button.set_visual_state (1);
1840 stop_button.set_visual_state (0);
1844 stop_button.set_visual_state (1);
1845 roll_button.set_visual_state (0);
1846 play_selection_button.set_visual_state (0);
1847 auto_loop_button.set_visual_state (0);
1852 ARDOUR_UI::engine_stopped ()
1854 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1855 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1856 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1860 ARDOUR_UI::engine_running ()
1862 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1863 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1864 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1866 Glib::RefPtr<Action> action;
1867 const char* action_name = 0;
1869 switch (engine->frames_per_cycle()) {
1871 action_name = X_("JACKLatency32");
1874 action_name = X_("JACKLatency64");
1877 action_name = X_("JACKLatency128");
1880 action_name = X_("JACKLatency512");
1883 action_name = X_("JACKLatency1024");
1886 action_name = X_("JACKLatency2048");
1889 action_name = X_("JACKLatency4096");
1892 action_name = X_("JACKLatency8192");
1895 /* XXX can we do anything useful ? */
1901 action = ActionManager::get_action (X_("JACK"), action_name);
1904 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1905 ract->set_active ();
1911 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1913 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1914 /* we can't rely on the original string continuing to exist when we are called
1915 again in the GUI thread, so make a copy and note that we need to
1918 char *copy = strdup (reason);
1919 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1923 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1924 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1926 update_sample_rate (0);
1930 /* if the reason is a non-empty string, it means that the backend was shutdown
1931 rather than just Ardour.
1934 if (strlen (reason)) {
1935 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1937 msgstr = string_compose (_("\
1938 JACK has either been shutdown or it\n\
1939 disconnected %1 because %1\n\
1940 was not fast enough. Try to restart\n\
1941 JACK, reconnect and save the session."), PROGRAM_NAME);
1944 MessageDialog msg (*editor, msgstr);
1949 free ((char*) reason);
1954 ARDOUR_UI::do_engine_start ()
1962 error << _("Unable to start the session running")
1972 ARDOUR_UI::setup_theme ()
1974 theme_manager->setup_theme();
1978 ARDOUR_UI::update_clocks ()
1980 if (!editor || !editor->dragging_playhead()) {
1981 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1986 ARDOUR_UI::start_clocking ()
1988 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1992 ARDOUR_UI::stop_clocking ()
1994 clock_signal_connection.disconnect ();
1998 ARDOUR_UI::toggle_clocking ()
2001 if (clock_button.get_active()) {
2010 ARDOUR_UI::_blink (void *arg)
2013 ((ARDOUR_UI *) arg)->blink ();
2020 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2024 ARDOUR_UI::start_blinking ()
2026 /* Start the blink signal. Everybody with a blinking widget
2027 uses Blink to drive the widget's state.
2030 if (blink_timeout_tag < 0) {
2032 blink_timeout_tag = g_timeout_add (240, _blink, this);
2037 ARDOUR_UI::stop_blinking ()
2039 if (blink_timeout_tag >= 0) {
2040 g_source_remove (blink_timeout_tag);
2041 blink_timeout_tag = -1;
2046 /** Ask the user for the name of a new shapshot and then take it.
2050 ARDOUR_UI::snapshot_session (bool switch_to_it)
2052 ArdourPrompter prompter (true);
2055 prompter.set_name ("Prompter");
2056 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2057 prompter.set_title (_("Take Snapshot"));
2058 prompter.set_title (_("Take Snapshot"));
2059 prompter.set_prompt (_("Name of new snapshot"));
2061 if (!switch_to_it) {
2064 struct tm local_time;
2067 localtime_r (&n, &local_time);
2068 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2069 prompter.set_initial_text (timebuf);
2073 switch (prompter.run()) {
2074 case RESPONSE_ACCEPT:
2076 prompter.get_result (snapname);
2078 bool do_save = (snapname.length() != 0);
2081 if (snapname.find ('/') != string::npos) {
2082 MessageDialog msg (_("To ensure compatibility with various systems\n"
2083 "snapshot names may not contain a '/' character"));
2087 if (snapname.find ('\\') != string::npos) {
2088 MessageDialog msg (_("To ensure compatibility with various systems\n"
2089 "snapshot names may not contain a '\\' character"));
2095 vector<sys::path> p;
2096 get_state_files_in_directory (_session->session_directory().root_path(), p);
2097 vector<string> n = get_file_names_no_extension (p);
2098 if (find (n.begin(), n.end(), snapname) != n.end()) {
2100 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2101 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2102 confirm.get_vbox()->pack_start (m, true, true);
2103 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2104 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2105 confirm.show_all ();
2106 switch (confirm.run()) {
2107 case RESPONSE_CANCEL:
2113 save_state (snapname, switch_to_it);
2124 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2126 XMLNode* node = new XMLNode (X_("UI"));
2128 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2129 if (!(*i)->rc_configured()) {
2130 node->add_child_nocopy (*((*i)->get_state ()));
2134 _session->add_extra_xml (*node);
2136 save_state_canfail (name, switch_to_it);
2140 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2145 if (name.length() == 0) {
2146 name = _session->snap_name();
2149 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2153 cerr << "SS canfail\n";
2154 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2159 ARDOUR_UI::primary_clock_value_changed ()
2162 _session->request_locate (primary_clock.current_time ());
2167 ARDOUR_UI::big_clock_value_changed ()
2170 _session->request_locate (big_clock.current_time ());
2175 ARDOUR_UI::secondary_clock_value_changed ()
2178 _session->request_locate (secondary_clock.current_time ());
2183 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2185 if (_session == 0) {
2189 if (_session->step_editing()) {
2193 Session::RecordState const r = _session->record_status ();
2194 bool const h = _session->have_rec_enabled_track ();
2196 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2198 rec_button.set_visual_state (2);
2200 rec_button.set_visual_state (0);
2202 } else if (r == Session::Recording && h) {
2203 rec_button.set_visual_state (1);
2205 rec_button.set_visual_state (0);
2210 ARDOUR_UI::save_template ()
2212 ArdourPrompter prompter (true);
2215 if (!check_audioengine()) {
2219 prompter.set_name (X_("Prompter"));
2220 prompter.set_title (_("Save Mix Template"));
2221 prompter.set_prompt (_("Name for mix template:"));
2222 prompter.set_initial_text(_session->name() + _("-template"));
2223 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2225 switch (prompter.run()) {
2226 case RESPONSE_ACCEPT:
2227 prompter.get_result (name);
2229 if (name.length()) {
2230 _session->save_template (name);
2240 ARDOUR_UI::edit_metadata ()
2242 SessionMetadataEditor dialog;
2243 dialog.set_session (_session);
2244 editor->ensure_float (dialog);
2249 ARDOUR_UI::import_metadata ()
2251 SessionMetadataImporter dialog;
2252 dialog.set_session (_session);
2253 editor->ensure_float (dialog);
2258 ARDOUR_UI::fontconfig_dialog ()
2261 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2262 may not and it can take a while to build it. Warn them.
2265 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2267 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2268 MessageDialog msg (*_startup,
2269 string_compose (_("Welcome to %1.\n\n"
2270 "The program will take a bit longer to start up\n"
2271 "while the system fonts are checked.\n\n"
2272 "This will only be done once, and you will\n"
2273 "not see this message again\n"), PROGRAM_NAME),
2286 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2288 existing_session = false;
2290 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2291 session_path = cmdline_path;
2292 existing_session = true;
2293 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2294 session_path = Glib::path_get_dirname (string (cmdline_path));
2295 existing_session = true;
2297 /* it doesn't exist, assume the best */
2298 session_path = Glib::path_get_dirname (string (cmdline_path));
2301 session_name = basename_nosuffix (string (cmdline_path));
2305 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2307 /* when this is called, the backend audio system must be running */
2309 /* the main idea here is to deal with the fact that a cmdline argument for the session
2310 can be interpreted in different ways - it could be a directory or a file, and before
2311 we load, we need to know both the session directory and the snapshot (statefile) within it
2312 that we are supposed to use.
2315 if (session_name.length() == 0 || session_path.length() == 0) {
2319 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2321 std::string predicted_session_file;
2323 predicted_session_file = session_path;
2324 predicted_session_file += '/';
2325 predicted_session_file += session_name;
2326 predicted_session_file += ARDOUR::statefile_suffix;
2328 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2329 existing_session = true;
2332 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2334 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2335 /* existing .ardour file */
2336 existing_session = true;
2340 existing_session = false;
2343 /* lets just try to load it */
2345 if (create_engine ()) {
2346 backend_audio_error (false, _startup);
2350 return load_session (session_path, session_name);
2354 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2356 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2358 MessageDialog msg (str,
2360 Gtk::MESSAGE_WARNING,
2361 Gtk::BUTTONS_YES_NO,
2365 msg.set_name (X_("OpenExistingDialog"));
2366 msg.set_title (_("Open Existing Session"));
2367 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2368 msg.set_position (Gtk::WIN_POS_MOUSE);
2371 switch (msg.run()) {
2380 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2382 BusProfile bus_profile;
2384 if (Profile->get_sae()) {
2386 bus_profile.master_out_channels = 2;
2387 bus_profile.input_ac = AutoConnectPhysical;
2388 bus_profile.output_ac = AutoConnectMaster;
2389 bus_profile.requested_physical_in = 0; // use all available
2390 bus_profile.requested_physical_out = 0; // use all available
2394 /* get settings from advanced section of NSD */
2396 if (_startup->create_master_bus()) {
2397 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2399 bus_profile.master_out_channels = 0;
2402 if (_startup->connect_inputs()) {
2403 bus_profile.input_ac = AutoConnectPhysical;
2405 bus_profile.input_ac = AutoConnectOption (0);
2408 /// @todo some minor tweaks.
2410 bus_profile.output_ac = AutoConnectOption (0);
2412 if (_startup->connect_outputs ()) {
2413 if (_startup->connect_outs_to_master()) {
2414 bus_profile.output_ac = AutoConnectMaster;
2415 } else if (_startup->connect_outs_to_physical()) {
2416 bus_profile.output_ac = AutoConnectPhysical;
2420 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2421 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2424 if (build_session (session_path, session_name, bus_profile)) {
2432 ARDOUR_UI::idle_load (const std::string& path)
2435 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2436 /* /path/to/foo => /path/to/foo, foo */
2437 load_session (path, basename_nosuffix (path));
2439 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2440 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2444 ARDOUR_COMMAND_LINE::session_name = path;
2447 * new_session_dialog doens't exist in A3
2448 * Try to remove all references to it to
2449 * see if it will compile. NOTE: this will
2450 * likely cause a runtime issue is my somewhat
2454 //if (new_session_dialog) {
2457 /* make it break out of Dialog::run() and
2461 //new_session_dialog->response (1);
2467 ARDOUR_UI::end_loading_messages ()
2473 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2476 // splash->message (msg);
2480 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2482 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2484 string session_name;
2485 string session_path;
2486 string template_name;
2488 bool likely_new = false;
2490 if (! load_template.empty()) {
2491 should_be_new = true;
2492 template_name = load_template;
2497 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2499 /* if they named a specific statefile, use it, otherwise they are
2500 just giving a session folder, and we want to use it as is
2501 to find the session.
2504 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2505 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2507 session_path = ARDOUR_COMMAND_LINE::session_name;
2510 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2514 bool const apply = run_startup (should_be_new, load_template);
2517 if (quit_on_cancel) {
2524 /* if we run the startup dialog again, offer more than just "new session" */
2526 should_be_new = false;
2528 session_name = _startup->session_name (likely_new);
2530 /* this shouldn't happen, but we catch it just in case it does */
2532 if (session_name.empty()) {
2536 if (_startup->use_session_template()) {
2537 template_name = _startup->session_template_name();
2538 _session_is_new = true;
2541 if (session_name[0] == G_DIR_SEPARATOR ||
2542 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2543 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2545 /* absolute path or cwd-relative path specified for session name: infer session folder
2546 from what was given.
2549 session_path = Glib::path_get_dirname (session_name);
2550 session_name = Glib::path_get_basename (session_name);
2554 session_path = _startup->session_folder();
2556 if (session_name.find ('/') != string::npos) {
2557 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2558 "session names may not contain a '/' character"));
2560 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2564 if (session_name.find ('\\') != string::npos) {
2565 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2566 "session names may not contain a '\\' character"));
2568 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2574 if (create_engine ()) {
2578 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2582 std::string existing = Glib::build_filename (session_path, session_name);
2584 if (!ask_about_loading_existing_session (existing)) {
2585 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2590 _session_is_new = false;
2595 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2597 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2601 if (session_name.find ('/') != std::string::npos) {
2602 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2603 "session names may not contain a '/' character"));
2605 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2609 if (session_name.find ('\\') != std::string::npos) {
2610 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2611 "session names may not contain a '\\' character"));
2613 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2617 _session_is_new = true;
2620 if (likely_new && template_name.empty()) {
2622 ret = build_session_from_nsd (session_path, session_name);
2626 ret = load_session (session_path, session_name, template_name);
2627 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2628 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2638 ARDOUR_UI::close_session()
2640 if (!check_audioengine()) {
2644 if (unload_session (true)) {
2648 ARDOUR_COMMAND_LINE::session_name = "";
2650 if (get_session_parameters (true, false)) {
2654 goto_editor_window ();
2658 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2660 Session *new_session;
2664 session_loaded = false;
2666 if (!check_audioengine()) {
2670 unload_status = unload_session ();
2672 if (unload_status < 0) {
2674 } else if (unload_status > 0) {
2679 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2682 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2685 /* this one is special */
2687 catch (AudioEngine::PortRegistrationFailure& err) {
2689 MessageDialog msg (err.what(),
2692 Gtk::BUTTONS_CLOSE);
2694 msg.set_title (_("Port Registration Error"));
2695 msg.set_secondary_text (_("Click the Close button to try again."));
2696 msg.set_position (Gtk::WIN_POS_CENTER);
2700 int response = msg.run ();
2705 case RESPONSE_CANCEL:
2715 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"),path, snap_name),
2720 msg.set_title (_("Loading Error"));
2721 msg.set_secondary_text (_("Click the Refresh button to try again."));
2722 msg.add_button (Stock::REFRESH, 1);
2723 msg.set_position (Gtk::WIN_POS_CENTER);
2727 int response = msg.run ();
2742 list<string> const u = new_session->unknown_processors ();
2744 MissingPluginDialog d (_session, u);
2749 /* Now the session been created, add the transport controls */
2750 new_session->add_controllable(roll_controllable);
2751 new_session->add_controllable(stop_controllable);
2752 new_session->add_controllable(goto_start_controllable);
2753 new_session->add_controllable(goto_end_controllable);
2754 new_session->add_controllable(auto_loop_controllable);
2755 new_session->add_controllable(play_selection_controllable);
2756 new_session->add_controllable(rec_controllable);
2758 set_session (new_session);
2760 session_loaded = true;
2762 goto_editor_window ();
2765 _session->set_clean ();
2776 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2778 Session *new_session;
2781 if (!check_audioengine()) {
2785 session_loaded = false;
2787 x = unload_session ();
2795 _session_is_new = true;
2798 new_session = new Session (*engine, path, snap_name, &bus_profile);
2803 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2809 /* Give the new session the default GUI state, if such things exist */
2812 n = Config->instant_xml (X_("Editor"));
2814 new_session->add_instant_xml (*n, false);
2816 n = Config->instant_xml (X_("Mixer"));
2818 new_session->add_instant_xml (*n, false);
2821 set_session (new_session);
2823 session_loaded = true;
2825 new_session->save_state(new_session->name());
2831 ARDOUR_UI::launch_chat ()
2834 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2836 open_uri("http://webchat.freenode.net/?channels=ardour");
2841 ARDOUR_UI::show_about ()
2845 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2848 about->set_transient_for(*editor);
2853 ARDOUR_UI::launch_manual ()
2855 PBD::open_uri("http://ardour.org/flossmanual");
2859 ARDOUR_UI::launch_reference ()
2861 PBD::open_uri("http://ardour.org/refmanual");
2865 ARDOUR_UI::hide_about ()
2868 about->get_window()->set_cursor ();
2874 ARDOUR_UI::about_signal_response (int /*response*/)
2880 ARDOUR_UI::show_splash ()
2884 splash = new Splash;
2892 splash->queue_draw ();
2893 splash->get_window()->process_updates (true);
2898 ARDOUR_UI::hide_splash ()
2906 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2907 const string& plural_msg, const string& singular_msg)
2911 removed = rep.paths.size();
2914 MessageDialog msgd (*editor,
2915 _("No audio files were ready for cleanup"),
2918 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2919 msgd.set_secondary_text (_("If this seems suprising, \n\
2920 check for any existing snapshots.\n\
2921 These may still include regions that\n\
2922 require some unused files to continue to exist."));
2928 ArdourDialog results (_("Clean-up"), true, false);
2930 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2931 CleanupResultsModelColumns() {
2935 Gtk::TreeModelColumn<std::string> visible_name;
2936 Gtk::TreeModelColumn<std::string> fullpath;
2940 CleanupResultsModelColumns results_columns;
2941 Glib::RefPtr<Gtk::ListStore> results_model;
2942 Gtk::TreeView results_display;
2944 results_model = ListStore::create (results_columns);
2945 results_display.set_model (results_model);
2946 results_display.append_column (list_title, results_columns.visible_name);
2948 results_display.set_name ("CleanupResultsList");
2949 results_display.set_headers_visible (true);
2950 results_display.set_headers_clickable (false);
2951 results_display.set_reorderable (false);
2953 Gtk::ScrolledWindow list_scroller;
2956 Gtk::HBox dhbox; // the hbox for the image and text
2957 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2958 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2960 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2962 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2965 %1 - number of files removed
2966 %2 - location of "dead_sounds"
2967 %3 - size of files affected
2968 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2971 const char* bprefix;
2972 double space_adjusted = 0;
2974 if (rep.space < 100000.0f) {
2975 bprefix = X_("kilo");
2976 } else if (rep.space < 1000000.0f * 1000) {
2977 bprefix = X_("mega");
2978 space_adjusted = truncf((float)rep.space / 1000.0);
2980 bprefix = X_("giga");
2981 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2985 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2987 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2990 dhbox.pack_start (*dimage, true, false, 5);
2991 dhbox.pack_start (txt, true, false, 5);
2993 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2994 TreeModel::Row row = *(results_model->append());
2995 row[results_columns.visible_name] = *i;
2996 row[results_columns.fullpath] = *i;
2999 list_scroller.add (results_display);
3000 list_scroller.set_size_request (-1, 150);
3001 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3003 dvbox.pack_start (dhbox, true, false, 5);
3004 dvbox.pack_start (list_scroller, true, false, 5);
3005 ddhbox.pack_start (dvbox, true, false, 5);
3007 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3008 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3009 results.set_default_response (RESPONSE_CLOSE);
3010 results.set_position (Gtk::WIN_POS_MOUSE);
3012 results_display.show();
3013 list_scroller.show();
3020 //results.get_vbox()->show();
3021 results.set_resizable (false);
3028 ARDOUR_UI::cleanup ()
3030 if (_session == 0) {
3031 /* shouldn't happen: menu item is insensitive */
3036 MessageDialog checker (_("Are you sure you want to cleanup?"),
3038 Gtk::MESSAGE_QUESTION,
3039 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3041 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3042 ALL undo/redo information will be lost if you cleanup.\n\
3043 After cleanup, unused audio files will be moved to a \
3044 \"dead sounds\" location."));
3046 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3047 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3048 checker.set_default_response (RESPONSE_CANCEL);
3050 checker.set_name (_("CleanupDialog"));
3051 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3052 checker.set_position (Gtk::WIN_POS_MOUSE);
3054 switch (checker.run()) {
3055 case RESPONSE_ACCEPT:
3061 ARDOUR::CleanupReport rep;
3063 editor->prepare_for_cleanup ();
3065 /* do not allow flush until a session is reloaded */
3067 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3069 act->set_sensitive (false);
3072 if (_session->cleanup_sources (rep)) {
3073 editor->finish_cleanup ();
3077 editor->finish_cleanup ();
3080 display_cleanup_results (rep,
3083 The following %1 files were not in use and \n\
3084 have been moved to:\n\
3086 Flushing the wastebasket will \n\
3087 release an additional\n\
3088 %3 %4bytes of disk space.\n"),
3090 The following file was not in use and \n \
3091 has been moved to:\n \
3093 Flushing the wastebasket will \n\
3094 release an additional\n\
3095 %3 %4bytes of disk space.\n"
3101 ARDOUR_UI::flush_trash ()
3103 if (_session == 0) {
3104 /* shouldn't happen: menu item is insensitive */
3108 ARDOUR::CleanupReport rep;
3110 if (_session->cleanup_trash_sources (rep)) {
3114 display_cleanup_results (rep,
3116 _("The following %1 files were deleted from\n\
3118 releasing %3 %4bytes of disk space"),
3119 _("The following file was deleted from\n\
3121 releasing %3 %4bytes of disk space"));
3125 ARDOUR_UI::add_route (Gtk::Window* float_window)
3133 if (add_route_dialog == 0) {
3134 add_route_dialog = new AddRouteDialog (_session);
3136 add_route_dialog->set_transient_for (*float_window);
3140 if (add_route_dialog->is_visible()) {
3141 /* we're already doing this */
3145 ResponseType r = (ResponseType) add_route_dialog->run ();
3147 add_route_dialog->hide();
3150 case RESPONSE_ACCEPT:
3157 if ((count = add_route_dialog->count()) <= 0) {
3161 string template_path = add_route_dialog->track_template();
3163 if (!template_path.empty()) {
3164 _session->new_route_from_template (count, template_path);
3168 uint32_t input_chan = add_route_dialog->channels ();
3169 uint32_t output_chan;
3170 string name_template = add_route_dialog->name_template ();
3171 bool track = add_route_dialog->track ();
3172 bool aux = !track && add_route_dialog->aux();
3173 RouteGroup* route_group = add_route_dialog->route_group ();
3175 AutoConnectOption oac = Config->get_output_auto_connect();
3177 if (oac & AutoConnectMaster) {
3178 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3180 output_chan = input_chan;
3183 /* XXX do something with name template */
3185 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3187 session_add_midi_track (route_group, count);
3189 MessageDialog msg (*editor,
3190 _("Sorry, MIDI Busses are not supported at this time."));
3192 //session_add_midi_bus();
3196 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3198 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3204 ARDOUR_UI::mixer_settings () const
3209 node = _session->instant_xml(X_("Mixer"));
3211 node = Config->instant_xml(X_("Mixer"));
3215 node = new XMLNode (X_("Mixer"));
3222 ARDOUR_UI::editor_settings () const
3227 node = _session->instant_xml(X_("Editor"));
3229 node = Config->instant_xml(X_("Editor"));
3233 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3234 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3239 node = new XMLNode (X_("Editor"));
3246 ARDOUR_UI::keyboard_settings () const
3250 node = Config->extra_xml(X_("Keyboard"));
3253 node = new XMLNode (X_("Keyboard"));
3259 ARDOUR_UI::create_xrun_marker (framepos_t where)
3261 editor->mouse_add_new_marker (where, false, true);
3265 ARDOUR_UI::halt_on_xrun_message ()
3267 MessageDialog msg (*editor,
3268 _("Recording was stopped because your system could not keep up."));
3273 ARDOUR_UI::xrun_handler (framepos_t where)
3279 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3281 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3282 create_xrun_marker(where);
3285 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3286 halt_on_xrun_message ();
3291 ARDOUR_UI::disk_overrun_handler ()
3293 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3295 if (!have_disk_speed_dialog_displayed) {
3296 have_disk_speed_dialog_displayed = true;
3297 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3298 The disk system on your computer\n\
3299 was not able to keep up with %1.\n\
3301 Specifically, it failed to write data to disk\n\
3302 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3303 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3309 ARDOUR_UI::disk_underrun_handler ()
3311 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3313 if (!have_disk_speed_dialog_displayed) {
3314 have_disk_speed_dialog_displayed = true;
3315 MessageDialog* msg = new MessageDialog (*editor,
3316 string_compose (_("The disk system on your computer\n\
3317 was not able to keep up with %1.\n\
3319 Specifically, it failed to read data from disk\n\
3320 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3321 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3327 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3329 have_disk_speed_dialog_displayed = false;
3334 ARDOUR_UI::session_dialog (std::string msg)
3336 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3341 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3343 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3352 ARDOUR_UI::pending_state_dialog ()
3354 HBox* hbox = new HBox();
3355 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3356 ArdourDialog dialog (_("Crash Recovery"), true);
3358 This session appears to have been in\n\
3359 middle of recording when ardour or\n\
3360 the computer was shutdown.\n\
3362 Ardour can recover any captured audio for\n\
3363 you, or it can ignore it. Please decide\n\
3364 what you would like to do.\n"));
3365 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3366 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3367 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3368 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3369 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3370 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3371 dialog.set_default_response (RESPONSE_ACCEPT);
3372 dialog.set_position (WIN_POS_CENTER);
3377 switch (dialog.run ()) {
3378 case RESPONSE_ACCEPT:
3386 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
3388 HBox* hbox = new HBox();
3389 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3390 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3391 Label message (string_compose (_("\
3392 This session was created with a sample rate of %1 Hz\n\
3394 The audioengine is currently running at %2 Hz\n"), desired, actual));
3396 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3397 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3398 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3399 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3400 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3401 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3402 dialog.set_default_response (RESPONSE_ACCEPT);
3403 dialog.set_position (WIN_POS_CENTER);
3408 switch (dialog.run ()) {
3409 case RESPONSE_ACCEPT:
3418 ARDOUR_UI::disconnect_from_jack ()
3421 if( engine->disconnect_from_jack ()) {
3422 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3426 update_sample_rate (0);
3431 ARDOUR_UI::reconnect_to_jack ()
3434 if (engine->reconnect_to_jack ()) {
3435 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3439 update_sample_rate (0);
3444 ARDOUR_UI::use_config ()
3446 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3448 set_transport_controllable_state (*node);
3453 ARDOUR_UI::update_transport_clocks (framepos_t pos)
3455 if (Config->get_primary_clock_delta_edit_cursor()) {
3456 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3458 primary_clock.set (pos, 0, true);
3461 if (Config->get_secondary_clock_delta_edit_cursor()) {
3462 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3464 secondary_clock.set (pos);
3467 if (big_clock_window->get()) {
3468 big_clock.set (pos);
3474 ARDOUR_UI::step_edit_status_change (bool yn)
3476 // XXX should really store pre-step edit status of things
3477 // we make insensitive
3480 rec_button.set_visual_state (3);
3481 rec_button.set_sensitive (false);
3483 rec_button.set_visual_state (0);
3484 rec_button.set_sensitive (true);
3489 ARDOUR_UI::record_state_changed ()
3491 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3493 if (!_session || !big_clock_window->get()) {
3494 /* why bother - the clock isn't visible */
3498 Session::RecordState const r = _session->record_status ();
3499 bool const h = _session->have_rec_enabled_track ();
3501 if (r == Session::Recording && h) {
3502 big_clock.set_widget_name ("BigClockRecording");
3504 big_clock.set_widget_name ("BigClockNonRecording");
3509 ARDOUR_UI::first_idle ()
3512 _session->allow_auto_play (true);
3516 editor->first_idle();
3519 Keyboard::set_can_save_keybindings (true);
3524 ARDOUR_UI::store_clock_modes ()
3526 XMLNode* node = new XMLNode(X_("ClockModes"));
3528 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3529 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3532 _session->add_extra_xml (*node);
3533 _session->set_dirty ();
3538 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3539 : Controllable (name), ui (u), type(tp)
3545 ARDOUR_UI::TransportControllable::set_value (double val)
3547 if (type == ShuttleControl) {
3554 fract = -((0.5 - val)/0.5);
3556 fract = ((val - 0.5)/0.5);
3560 ui.set_shuttle_fract (fract);
3565 /* do nothing: these are radio-style actions */
3569 const char *action = 0;
3573 action = X_("Roll");
3576 action = X_("Stop");
3579 action = X_("Goto Start");
3582 action = X_("Goto End");
3585 action = X_("Loop");
3588 action = X_("Play Selection");
3591 action = X_("Record");
3601 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3609 ARDOUR_UI::TransportControllable::get_value (void) const
3628 case ShuttleControl:
3638 ARDOUR_UI::TransportControllable::set_id (const string& str)
3644 ARDOUR_UI::setup_profile ()
3646 if (gdk_screen_width() < 1200) {
3647 Profile->set_small_screen ();
3651 if (getenv ("ARDOUR_SAE")) {
3652 Profile->set_sae ();
3653 Profile->set_single_package ();
3658 ARDOUR_UI::toggle_translations ()
3660 using namespace Glib;
3662 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3664 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3667 string i18n_killer = ARDOUR::translation_kill_path();
3669 bool already_enabled = !ARDOUR::translations_are_disabled ();
3671 if (ract->get_active ()) {
3672 /* we don't care about errors */
3673 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3676 /* we don't care about errors */
3677 unlink (i18n_killer.c_str());
3680 if (already_enabled != ract->get_active()) {
3681 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3683 Gtk::MESSAGE_WARNING,
3685 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3686 win.set_position (Gtk::WIN_POS_CENTER);
3694 /** Add a window proxy to our list, so that its state will be saved.
3695 * This call also causes the window to be created and opened if its
3696 * state was saved as `visible'.
3699 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3701 _window_proxies.push_back (p);
3705 /** Remove a window proxy from our list. Must be called if a WindowProxy
3706 * is deleted, to prevent hanging pointers.
3709 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3711 _window_proxies.remove (p);
3715 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
3717 MissingFileDialog dialog (s, str, type);
3722 int result = dialog.run ();
3729 return 1; // quit entire session load
3732 result = dialog.get_action ();