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 bool could_be_a_valid_path (const string& path);
123 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
125 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp),
127 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, true, false, true),
128 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, true, false, true),
129 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, false, true),
130 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, false, true),
134 preroll_button (_("pre\nroll")),
135 postroll_button (_("post\nroll")),
139 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, true, false, false),
143 roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll)),
144 stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop)),
145 goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart)),
146 goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd)),
147 auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop)),
148 play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection)),
149 rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable)),
150 shuttle_controllable (new TransportControllable ("shuttle", *this, TransportControllable::ShuttleControl)),
151 shuttle_controller_binding_proxy (shuttle_controllable),
153 roll_button (roll_controllable),
154 stop_button (stop_controllable),
155 goto_start_button (goto_start_controllable),
156 goto_end_button (goto_end_controllable),
157 auto_loop_button (auto_loop_controllable),
158 play_selection_button (play_selection_controllable),
159 rec_button (rec_controllable),
161 shuttle_units_button (_("% ")),
163 punch_in_button (_("Punch In")),
164 punch_out_button (_("Punch Out")),
165 auto_return_button (_("Auto Return")),
166 auto_play_button (_("Auto Play")),
167 auto_input_button (_("Auto Input")),
168 click_button (_("Click")),
169 time_master_button (_("time\nmaster")),
171 auditioning_alert_button (_("AUDITION")),
172 solo_alert_button (_("SOLO")),
173 error_log_button (_("Errors"))
176 using namespace Gtk::Menu_Helpers;
182 // _auto_display_errors = false;
184 * This was commented out as it wasn't defined
185 * in A3 IIRC. If this is not needed it should
186 * be completely removed.
194 if (theArdourUI == 0) {
198 ui_config = new UIConfiguration();
199 theme_manager = new ThemeManager();
205 _session_is_new = false;
206 big_clock_window = 0;
207 big_clock_height = 0;
208 big_clock_resize_in_progress = false;
209 session_selector_window = 0;
210 last_key_press_time = 0;
211 _will_create_new_session_automatically = false;
212 add_route_dialog = 0;
214 rc_option_editor = 0;
215 session_option_editor = 0;
217 open_session_selector = 0;
218 have_configure_timeout = false;
219 have_disk_speed_dialog_displayed = false;
220 session_loaded = false;
221 last_speed_displayed = -1.0f;
222 ignore_dual_punch = false;
223 original_big_clock_width = -1;
224 original_big_clock_height = -1;
225 original_big_clock_font_size = 0;
227 roll_button.unset_flags (Gtk::CAN_FOCUS);
228 stop_button.unset_flags (Gtk::CAN_FOCUS);
229 goto_start_button.unset_flags (Gtk::CAN_FOCUS);
230 goto_end_button.unset_flags (Gtk::CAN_FOCUS);
231 auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
232 play_selection_button.unset_flags (Gtk::CAN_FOCUS);
233 rec_button.unset_flags (Gtk::CAN_FOCUS);
235 last_configure_time= 0;
237 shuttle_grabbed = false;
239 shuttle_max_speed = 8.0f;
241 shuttle_style_menu = 0;
242 shuttle_unit_menu = 0;
244 // We do not have jack linked in yet so;
246 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
248 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
249 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
251 /* handle dialog requests */
253 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
255 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
257 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
259 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
261 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
263 /* lets get this party started */
266 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
267 throw failed_constructor ();
270 setup_gtk_ardour_enums ();
273 GainMeter::setup_slider_pix ();
274 RouteTimeAxisView::setup_slider_pix ();
275 SendProcessorEntry::setup_slider_pix ();
276 SessionEvent::create_per_thread_pool ("GUI", 512);
278 } catch (failed_constructor& err) {
279 error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg;
284 /* we like keyboards */
286 keyboard = new ArdourKeyboard(*this);
288 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
290 keyboard->set_state (*node, Stateful::loading_state_version);
295 TimeAxisViewItem::set_constant_heights ();
297 /* The following must happen after ARDOUR::init() so that Config is set up */
299 location_ui = new ActionWindowProxy<LocationUIWindow> (X_("locations"), Config->extra_xml (X_("UI")), X_("ToggleLocations"));
300 big_clock_window = new ActionWindowProxy<Gtk::Window> (X_("bigclock"), Config->extra_xml (X_("UI")), X_("ToggleBigClock"));
302 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
303 _global_port_matrix[*i] = new ActionWindowProxy<GlobalPortMatrixWindow> (
304 string_compose ("GlobalPortMatrix-%1", (*i).to_string()),
305 Config->extra_xml (X_("UI")),
306 string_compose ("toggle-%1-connection-manager", (*i).to_string())
312 starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
313 stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown));
318 /** @return true if a session was chosen and `apply' clicked, otherwise false if `cancel' was clicked */
320 ARDOUR_UI::run_startup (bool should_be_new, string load_template)
323 _startup = new ArdourStartup ();
325 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
327 if (audio_setup && _startup->engine_control()) {
328 _startup->engine_control()->set_state (*audio_setup);
331 _startup->set_new_only (should_be_new);
332 if (!load_template.empty()) {
333 _startup->set_load_template( load_template );
335 _startup->present ();
341 switch (_startup->response()) {
350 ARDOUR_UI::create_engine ()
352 // this gets called every time by new_session()
358 loading_message (_("Starting audio engine"));
361 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
368 engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
369 engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
370 engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
372 engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
374 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
382 ARDOUR_UI::post_engine ()
384 /* Things to be done once we create the AudioEngine
387 ARDOUR::init_post_engine ();
389 ActionManager::init ();
392 if (setup_windows ()) {
393 throw failed_constructor ();
396 check_memory_locking();
398 /* this is the first point at which all the keybindings are available */
400 if (ARDOUR_COMMAND_LINE::show_key_actions) {
401 vector<string> names;
402 vector<string> paths;
404 vector<AccelKey> bindings;
406 ActionManager::get_all_actions (names, paths, keys, bindings);
408 vector<string>::iterator n;
409 vector<string>::iterator k;
410 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
411 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
417 blink_timeout_tag = -1;
419 /* this being a GUI and all, we want peakfiles */
421 AudioFileSource::set_build_peakfiles (true);
422 AudioFileSource::set_build_missing_peakfiles (true);
424 /* set default clock modes */
426 if (Profile->get_sae()) {
427 primary_clock.set_mode (AudioClock::BBT);
428 secondary_clock.set_mode (AudioClock::MinSec);
430 primary_clock.set_mode (AudioClock::Timecode);
431 secondary_clock.set_mode (AudioClock::BBT);
434 /* start the time-of-day-clock */
437 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
438 update_wall_clock ();
439 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
442 update_disk_space ();
444 update_sample_rate (engine->frame_rate());
446 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
447 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
448 Config->map_parameters (pc);
450 /* now start and maybe save state */
452 if (do_engine_start () == 0) {
453 if (_session && _session_is_new) {
454 /* we need to retain initial visual
455 settings for a new session
457 _session->save_state ("");
462 ARDOUR_UI::~ARDOUR_UI ()
467 delete add_route_dialog;
471 ARDOUR_UI::pop_back_splash ()
473 if (Splash::instance()) {
474 // Splash::instance()->pop_back();
475 Splash::instance()->hide ();
480 ARDOUR_UI::configure_timeout ()
482 if (last_configure_time == 0) {
483 /* no configure events yet */
487 /* force a gap of 0.5 seconds since the last configure event
490 if (get_microseconds() - last_configure_time < 500000) {
493 have_configure_timeout = false;
494 cerr << "config event-driven save\n";
495 save_ardour_state ();
501 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
503 if (have_configure_timeout) {
504 last_configure_time = get_microseconds();
506 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
507 have_configure_timeout = true;
514 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
516 const XMLProperty* prop;
518 if ((prop = node.property ("roll")) != 0) {
519 roll_controllable->set_id (prop->value());
521 if ((prop = node.property ("stop")) != 0) {
522 stop_controllable->set_id (prop->value());
524 if ((prop = node.property ("goto-start")) != 0) {
525 goto_start_controllable->set_id (prop->value());
527 if ((prop = node.property ("goto-end")) != 0) {
528 goto_end_controllable->set_id (prop->value());
530 if ((prop = node.property ("auto-loop")) != 0) {
531 auto_loop_controllable->set_id (prop->value());
533 if ((prop = node.property ("play-selection")) != 0) {
534 play_selection_controllable->set_id (prop->value());
536 if ((prop = node.property ("rec")) != 0) {
537 rec_controllable->set_id (prop->value());
539 if ((prop = node.property ("shuttle")) != 0) {
540 shuttle_controllable->set_id (prop->value());
545 ARDOUR_UI::get_transport_controllable_state ()
547 XMLNode* node = new XMLNode(X_("TransportControllables"));
550 roll_controllable->id().print (buf, sizeof (buf));
551 node->add_property (X_("roll"), buf);
552 stop_controllable->id().print (buf, sizeof (buf));
553 node->add_property (X_("stop"), buf);
554 goto_start_controllable->id().print (buf, sizeof (buf));
555 node->add_property (X_("goto_start"), buf);
556 goto_end_controllable->id().print (buf, sizeof (buf));
557 node->add_property (X_("goto_end"), buf);
558 auto_loop_controllable->id().print (buf, sizeof (buf));
559 node->add_property (X_("auto_loop"), buf);
560 play_selection_controllable->id().print (buf, sizeof (buf));
561 node->add_property (X_("play_selection"), buf);
562 rec_controllable->id().print (buf, sizeof (buf));
563 node->add_property (X_("rec"), buf);
564 shuttle_controllable->id().print (buf, sizeof (buf));
565 node->add_property (X_("shuttle"), buf);
572 ARDOUR_UI::autosave_session ()
574 if (g_main_depth() > 1) {
575 /* inside a recursive main loop,
576 give up because we may not be able to
582 if (!Config->get_periodic_safety_backups()) {
587 _session->maybe_write_autosave();
594 ARDOUR_UI::update_autosave ()
596 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
598 if (_session && _session->dirty()) {
599 if (_autosave_connection.connected()) {
600 _autosave_connection.disconnect();
603 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
604 Config->get_periodic_safety_backup_interval() * 1000);
607 if (_autosave_connection.connected()) {
608 _autosave_connection.disconnect();
614 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
618 title = string_compose (_("%1 could not start JACK"), PROGRAM_NAME);
620 title = string_compose (_("%1 could not connect to JACK."), PROGRAM_NAME);
623 MessageDialog win (title,
629 win.set_secondary_text(_("There are several possible reasons:\n\
631 1) You requested audio parameters that are not supported..\n\
632 2) JACK is running as another user.\n\
634 Please consider the possibilities, and perhaps try different parameters."));
636 win.set_secondary_text(_("There are several possible reasons:\n\
638 1) JACK is not running.\n\
639 2) JACK is running as another user, perhaps root.\n\
640 3) There is already another client called \"ardour\".\n\
642 Please consider the possibilities, and perhaps (re)start JACK."));
646 win.set_transient_for (*toplevel);
650 win.add_button (Stock::OK, RESPONSE_CLOSE);
652 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
655 win.set_default_response (RESPONSE_CLOSE);
658 win.set_position (Gtk::WIN_POS_CENTER);
661 /* we just don't care about the result, but we want to block */
667 ARDOUR_UI::startup ()
669 Application* app = Application::instance ();
671 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
672 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load));
675 call_the_mothership (VERSIONSTRING);
680 if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) {
686 goto_editor_window ();
688 /* Add the window proxies here; their addition may cause windows to be opened, and we want them
689 to be opened on top of the editor window that goto_editor_window() just opened.
691 add_window_proxy (location_ui);
692 add_window_proxy (big_clock_window);
693 for (ARDOUR::DataType::iterator i = ARDOUR::DataType::begin(); i != ARDOUR::DataType::end(); ++i) {
694 add_window_proxy (_global_port_matrix[*i]);
697 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
701 ARDOUR_UI::no_memory_warning ()
703 XMLNode node (X_("no-memory-warning"));
704 Config->add_instant_xml (node);
708 ARDOUR_UI::check_memory_locking ()
711 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
715 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
717 if (engine->is_realtime() && memory_warning_node == 0) {
719 struct rlimit limits;
721 long pages, page_size;
723 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
726 ram = (int64_t) pages * (int64_t) page_size;
729 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
733 if (limits.rlim_cur != RLIM_INFINITY) {
735 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
738 MessageDialog msg (string_compose (_("WARNING: Your system has a limit for maximum amount of locked memory. "
739 "This might cause %1 to run out of memory before your system "
740 "runs out of memory. \n\n"
741 "You can view the memory limit with 'ulimit -l', "
742 "and it is normally controlled by /etc/security/limits.conf"),
743 PROGRAM_NAME).c_str());
745 VBox* vbox = msg.get_vbox();
747 CheckButton cb (_("Do not show this window again"));
749 cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning));
751 hbox.pack_start (cb, true, false);
752 vbox->pack_start (hbox);
759 editor->ensure_float (msg);
769 ARDOUR_UI::queue_finish ()
771 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
775 ARDOUR_UI::idle_finish ()
778 return false; /* do not call again */
787 if (_session->transport_rolling() && (++tries < 8)) {
788 _session->request_stop (false, true);
792 if (_session->dirty()) {
793 switch (ask_about_saving_session(_("quit"))) {
798 /* use the default name */
799 if (save_state_canfail ("")) {
800 /* failed - don't quit */
801 MessageDialog msg (*editor,
803 Ardour was unable to save your session.\n\n\
804 If you still wish to quit, please use the\n\n\
805 \"Just quit\" option."));
816 second_connection.disconnect ();
817 point_one_second_connection.disconnect ();
818 point_oh_five_second_connection.disconnect ();
819 point_zero_one_second_connection.disconnect();
822 /* Save state before deleting the session, as that causes some
823 windows to be destroyed before their visible state can be
826 save_ardour_state ();
829 // _session->set_deletion_in_progress ();
830 _session->set_clean ();
831 _session->remove_pending_capture_state ();
836 ArdourDialog::close_all_dialogs ();
842 ARDOUR_UI::ask_about_saving_session (const string & what)
844 ArdourDialog window (_("Unsaved Session"));
845 Gtk::HBox dhbox; // the hbox for the image and text
846 Gtk::Label prompt_label;
847 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
851 msg = string_compose(_("Don't %1"), what);
852 window.add_button (msg, RESPONSE_REJECT);
853 msg = string_compose(_("Just %1"), what);
854 window.add_button (msg, RESPONSE_APPLY);
855 msg = string_compose(_("Save and %1"), what);
856 window.add_button (msg, RESPONSE_ACCEPT);
858 window.set_default_response (RESPONSE_ACCEPT);
860 Gtk::Button noquit_button (msg);
861 noquit_button.set_name ("EditorGTKButton");
866 if (_session->snap_name() == _session->name()) {
869 type = _("snapshot");
871 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?"),
872 type, _session->snap_name());
874 prompt_label.set_text (prompt);
875 prompt_label.set_name (X_("PrompterLabel"));
876 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
878 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
879 dhbox.set_homogeneous (false);
880 dhbox.pack_start (*dimage, false, false, 5);
881 dhbox.pack_start (prompt_label, true, false, 5);
882 window.get_vbox()->pack_start (dhbox);
884 window.set_name (_("Prompter"));
885 window.set_position (Gtk::WIN_POS_MOUSE);
886 window.set_modal (true);
887 window.set_resizable (false);
893 window.set_keep_above (true);
896 ResponseType r = (ResponseType) window.run();
901 case RESPONSE_ACCEPT: // save and get out of here
903 case RESPONSE_APPLY: // get out of here
913 ARDOUR_UI::every_second ()
916 update_buffer_load ();
917 update_disk_space ();
922 ARDOUR_UI::every_point_one_seconds ()
924 update_speed_display ();
925 RapidScreenUpdate(); /* EMIT_SIGNAL */
930 ARDOUR_UI::every_point_zero_one_seconds ()
932 // august 2007: actual update frequency: 40Hz, not 100Hz
934 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
939 ARDOUR_UI::update_sample_rate (nframes_t)
943 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
945 if (!engine->connected()) {
947 snprintf (buf, sizeof (buf), _("disconnected"));
951 nframes_t rate = engine->frame_rate();
953 if (fmod (rate, 1000.0) != 0.0) {
954 snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"),
955 (float) rate/1000.0f,
956 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
958 snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"),
960 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
964 sample_rate_label.set_text (buf);
968 ARDOUR_UI::update_cpu_load ()
971 snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load());
972 cpu_load_label.set_text (buf);
976 ARDOUR_UI::update_buffer_load ()
982 c = _session->capture_load ();
983 p = _session->playback_load ();
985 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
986 _session->playback_load(), _session->capture_load());
987 buffer_load_label.set_text (buf);
989 buffer_load_label.set_text ("");
994 ARDOUR_UI::count_recenabled_streams (Route& route)
996 Track* track = dynamic_cast<Track*>(&route);
997 if (track && track->record_enabled()) {
998 rec_enabled_streams += track->n_inputs().n_total();
1003 ARDOUR_UI::update_disk_space()
1005 if (_session == 0) {
1009 framecnt_t frames = _session->available_capture_duration();
1011 nframes_t fr = _session->frame_rate();
1013 if (frames == max_framecnt) {
1014 strcpy (buf, _("Disk: 24hrs+"));
1016 rec_enabled_streams = 0;
1017 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
1019 if (rec_enabled_streams) {
1020 frames /= rec_enabled_streams;
1027 hrs = frames / (fr * 3600);
1028 frames -= hrs * fr * 3600;
1029 mins = frames / (fr * 60);
1030 frames -= mins * fr * 60;
1033 snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs);
1036 disk_space_label.set_text (buf);
1038 // An attempt to make the disk space label flash red when space has run out.
1040 if (frames < fr * 60 * 5) {
1041 /* disk_space_box.style ("disk_space_label_empty"); */
1043 /* disk_space_box.style ("disk_space_label"); */
1049 ARDOUR_UI::update_wall_clock ()
1056 tm_now = localtime (&now);
1058 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1059 wall_clock_label.set_text (buf);
1065 ARDOUR_UI::session_menu (GdkEventButton */*ev*/)
1067 session_popup_menu->popup (0, 0);
1072 ARDOUR_UI::redisplay_recent_sessions ()
1074 std::vector<sys::path> session_directories;
1075 RecentSessionsSorter cmp;
1077 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1078 recent_session_model->clear ();
1080 ARDOUR::RecentSessions rs;
1081 ARDOUR::read_recent_sessions (rs);
1084 recent_session_display.set_model (recent_session_model);
1088 // sort them alphabetically
1089 sort (rs.begin(), rs.end(), cmp);
1091 for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1092 session_directories.push_back ((*i).second);
1095 for (vector<sys::path>::const_iterator i = session_directories.begin();
1096 i != session_directories.end(); ++i)
1098 std::vector<sys::path> state_file_paths;
1100 // now get available states for this session
1102 get_state_files_in_directory (*i, state_file_paths);
1104 vector<string*>* states;
1105 vector<const gchar*> item;
1106 string fullpath = (*i).to_string();
1108 /* remove any trailing / */
1110 if (fullpath[fullpath.length()-1] == '/') {
1111 fullpath = fullpath.substr (0, fullpath.length()-1);
1114 /* check whether session still exists */
1115 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
1116 /* session doesn't exist */
1117 cerr << "skipping non-existent session " << fullpath << endl;
1121 /* now get available states for this session */
1123 if ((states = Session::possible_states (fullpath)) == 0) {
1124 /* no state file? */
1128 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
1130 Gtk::TreeModel::Row row = *(recent_session_model->append());
1132 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
1133 row[recent_session_columns.fullpath] = fullpath;
1135 if (state_file_names.size() > 1) {
1139 for (std::vector<std::string>::iterator i2 = state_file_names.begin();
1140 i2 != state_file_names.end(); ++i2)
1143 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1145 child_row[recent_session_columns.visible_name] = *i2;
1146 child_row[recent_session_columns.fullpath] = fullpath;
1151 recent_session_display.set_model (recent_session_model);
1155 ARDOUR_UI::build_session_selector ()
1157 session_selector_window = new ArdourDialog (_("Recent Sessions"));
1159 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1161 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
1162 session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT);
1163 session_selector_window->set_default_response (RESPONSE_ACCEPT);
1164 recent_session_model = TreeStore::create (recent_session_columns);
1165 recent_session_display.set_model (recent_session_model);
1166 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1167 recent_session_display.set_headers_visible (false);
1168 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
1169 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ARDOUR_UI::recent_session_row_activated));
1171 scroller->add (recent_session_display);
1172 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1174 session_selector_window->set_name ("SessionSelectorWindow");
1175 session_selector_window->set_size_request (200, 400);
1176 session_selector_window->get_vbox()->pack_start (*scroller);
1178 recent_session_display.show();
1180 //session_selector_window->get_vbox()->show();
1184 ARDOUR_UI::recent_session_row_activated (const TreePath& /*path*/, TreeViewColumn* /*col*/)
1186 session_selector_window->response (RESPONSE_ACCEPT);
1190 ARDOUR_UI::open_recent_session ()
1192 bool can_return = (_session != 0);
1194 if (session_selector_window == 0) {
1195 build_session_selector ();
1198 redisplay_recent_sessions ();
1202 session_selector_window->set_position (WIN_POS_MOUSE);
1204 ResponseType r = (ResponseType) session_selector_window->run ();
1207 case RESPONSE_ACCEPT:
1211 session_selector_window->hide();
1218 if (recent_session_display.get_selection()->count_selected_rows() == 0) {
1222 session_selector_window->hide();
1224 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1226 if (i == recent_session_model->children().end()) {
1230 std::string path = (*i)[recent_session_columns.fullpath];
1231 std::string state = (*i)[recent_session_columns.visible_name];
1233 _session_is_new = false;
1235 if (load_session (path, state) == 0) {
1244 ARDOUR_UI::check_audioengine ()
1247 if (!engine->connected()) {
1248 MessageDialog msg (string_compose (_("%1 is not connected to JACK\n"
1249 "You cannot open or close sessions in this condition"),
1262 ARDOUR_UI::open_session ()
1264 if (!check_audioengine()) {
1269 /* popup selector window */
1271 if (open_session_selector == 0) {
1273 /* ardour sessions are folders */
1275 open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1276 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1277 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1278 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1280 FileFilter session_filter;
1281 session_filter.add_pattern ("*.ardour");
1282 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1283 open_session_selector->add_filter (session_filter);
1284 open_session_selector->set_filter (session_filter);
1287 int response = open_session_selector->run();
1288 open_session_selector->hide ();
1291 case RESPONSE_ACCEPT:
1294 open_session_selector->hide();
1298 open_session_selector->hide();
1299 string session_path = open_session_selector->get_filename();
1303 if (session_path.length() > 0) {
1304 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1305 _session_is_new = isnew;
1306 load_session (path, name);
1313 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many)
1315 list<boost::shared_ptr<MidiTrack> > tracks;
1317 if (_session == 0) {
1318 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1325 tracks = _session->new_midi_track (ARDOUR::Normal, route_group, how_many);
1327 if (tracks.size() != how_many) {
1328 if (how_many == 1) {
1329 error << _("could not create a new midi track") << endmsg;
1331 error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg;
1335 if ((route = _session->new_midi_route ()) == 0) {
1336 error << _("could not create new midi bus") << endmsg;
1342 MessageDialog msg (*editor,
1343 string_compose (_("There are insufficient JACK ports available\n\
1344 to create a new track or bus.\n\
1345 You should save %1, exit and\n\
1346 restart JACK with more ports."), PROGRAM_NAME));
1353 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)
1355 list<boost::shared_ptr<AudioTrack> > tracks;
1358 if (_session == 0) {
1359 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1365 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many);
1367 if (tracks.size() != how_many) {
1368 if (how_many == 1) {
1369 error << _("could not create a new audio track") << endmsg;
1371 error << string_compose (_("could only create %1 of %2 new audio %3"),
1372 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1378 routes = _session->new_audio_route (aux, input_channels, output_channels, route_group, how_many);
1380 if (routes.size() != how_many) {
1381 if (how_many == 1) {
1382 error << _("could not create a new audio track") << endmsg;
1384 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1391 MessageDialog msg (*editor,
1392 string_compose (_("There are insufficient JACK ports available\n\
1393 to create a new track or bus.\n\
1394 You should save %1, exit and\n\
1395 restart JACK with more ports."), PROGRAM_NAME));
1402 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1404 nframes_t _preroll = 0;
1407 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1408 // _preroll = _session->convert_to_frames_at (new_position, Config->get_preroll());
1410 if (new_position > _preroll) {
1411 new_position -= _preroll;
1416 _session->request_locate (new_position);
1421 ARDOUR_UI::transport_goto_start ()
1424 _session->goto_start();
1426 /* force displayed area in editor to start no matter
1427 what "follow playhead" setting is.
1431 editor->center_screen (_session->current_start_frame ());
1437 ARDOUR_UI::transport_goto_zero ()
1440 _session->request_locate (0);
1442 /* force displayed area in editor to start no matter
1443 what "follow playhead" setting is.
1447 editor->reset_x_origin (0);
1453 ARDOUR_UI::transport_goto_wallclock ()
1455 if (_session && editor) {
1462 localtime_r (&now, &tmnow);
1464 frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate());
1465 frames += tmnow.tm_min * (60 * _session->frame_rate());
1466 frames += tmnow.tm_sec * _session->frame_rate();
1468 _session->request_locate (frames, _session->transport_rolling ());
1470 /* force displayed area in editor to start no matter
1471 what "follow playhead" setting is.
1475 editor->center_screen (frames);
1481 ARDOUR_UI::transport_goto_end ()
1484 nframes_t const frame = _session->current_end_frame();
1485 _session->request_locate (frame);
1487 /* force displayed area in editor to start no matter
1488 what "follow playhead" setting is.
1492 editor->center_screen (frame);
1498 ARDOUR_UI::transport_stop ()
1504 if (_session->is_auditioning()) {
1505 _session->cancel_audition ();
1509 _session->request_stop (false, true);
1513 ARDOUR_UI::transport_stop_and_forget_capture ()
1516 _session->request_stop (true, true);
1521 ARDOUR_UI::remove_last_capture()
1524 editor->remove_last_capture();
1529 ARDOUR_UI::transport_record (bool roll)
1533 switch (_session->record_status()) {
1534 case Session::Disabled:
1535 if (_session->ntracks() == 0) {
1536 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1540 _session->maybe_enable_record ();
1545 case Session::Recording:
1547 _session->request_stop();
1549 _session->disable_record (false, true);
1553 case Session::Enabled:
1554 _session->disable_record (false, true);
1557 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " _session->record_status() = " << _session->record_status() << endl;
1561 ARDOUR_UI::transport_roll ()
1567 if (_session->is_auditioning()) {
1571 if (_session->config.get_external_sync()) {
1572 switch (_session->config.get_sync_source()) {
1576 /* transport controlled by the master */
1581 bool rolling = _session->transport_rolling();
1583 if (_session->get_play_loop()) {
1584 /* XXX it is not possible to just leave seamless loop and keep
1585 playing at present (nov 4th 2009)
1587 if (!Config->get_seamless_loop()) {
1588 _session->request_play_loop (false, true);
1590 } else if (_session->get_play_range () && !join_play_range_button.get_active()) {
1591 /* stop playing a range if we currently are */
1592 _session->request_play_range (0, true);
1595 if (join_play_range_button.get_active()) {
1596 _session->request_play_range (&editor->get_selection().time, true);
1600 _session->request_transport_speed (1.0f);
1605 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
1612 if (_session->is_auditioning()) {
1613 _session->cancel_audition ();
1617 if (_session->config.get_external_sync()) {
1618 switch (_session->config.get_sync_source()) {
1622 /* transport controlled by the master */
1627 bool rolling = _session->transport_rolling();
1628 bool affect_transport = true;
1630 if (rolling && roll_out_of_bounded_mode) {
1631 /* drop out of loop/range playback but leave transport rolling */
1632 if (_session->get_play_loop()) {
1633 if (Config->get_seamless_loop()) {
1634 /* the disk buffers contain copies of the loop - we can't
1635 just keep playing, so stop the transport. the user
1636 can restart as they wish.
1638 affect_transport = true;
1640 /* disk buffers are normal, so we can keep playing */
1641 affect_transport = false;
1643 _session->request_play_loop (false, true);
1644 } else if (_session->get_play_range ()) {
1645 affect_transport = false;
1646 _session->request_play_range (0, true);
1650 if (affect_transport) {
1652 _session->request_stop (with_abort, true);
1654 if (join_play_range_button.get_active()) {
1655 _session->request_play_range (&editor->get_selection().time, true);
1658 _session->request_transport_speed (1.0f);
1664 ARDOUR_UI::toggle_session_auto_loop ()
1667 if (_session->get_play_loop()) {
1668 if (_session->transport_rolling()) {
1669 Location * looploc = _session->locations()->auto_loop_location();
1671 _session->request_locate (looploc->start(), true);
1674 _session->request_play_loop (false);
1677 Location * looploc = _session->locations()->auto_loop_location();
1679 _session->request_play_loop (true);
1686 ARDOUR_UI::transport_play_selection ()
1692 editor->play_selection ();
1696 ARDOUR_UI::transport_rewind (int option)
1698 float current_transport_speed;
1701 current_transport_speed = _session->transport_speed();
1703 if (current_transport_speed >= 0.0f) {
1706 _session->request_transport_speed (-1.0f);
1709 _session->request_transport_speed (-4.0f);
1712 _session->request_transport_speed (-0.5f);
1717 _session->request_transport_speed (current_transport_speed * 1.5f);
1723 ARDOUR_UI::transport_forward (int option)
1725 float current_transport_speed;
1728 current_transport_speed = _session->transport_speed();
1730 if (current_transport_speed <= 0.0f) {
1733 _session->request_transport_speed (1.0f);
1736 _session->request_transport_speed (4.0f);
1739 _session->request_transport_speed (0.5f);
1744 _session->request_transport_speed (current_transport_speed * 1.5f);
1751 ARDOUR_UI::toggle_record_enable (uint32_t rid)
1753 if (_session == 0) {
1757 boost::shared_ptr<Route> r;
1759 if ((r = _session->route_by_remote_id (rid)) != 0) {
1763 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1764 t->set_record_enabled (!t->record_enabled(), this);
1767 if (_session == 0) {
1773 ARDOUR_UI::map_transport_state ()
1775 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::map_transport_state)
1778 auto_loop_button.set_visual_state (0);
1779 play_selection_button.set_visual_state (0);
1780 roll_button.set_visual_state (0);
1781 stop_button.set_visual_state (1);
1785 float sp = _session->transport_speed();
1788 shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
1789 shuttle_box.queue_draw ();
1790 } else if (sp == 0.0f) {
1792 shuttle_box.queue_draw ();
1793 update_disk_space ();
1800 if (_session->get_play_range()) {
1802 play_selection_button.set_visual_state (1);
1803 roll_button.set_visual_state (0);
1804 auto_loop_button.set_visual_state (0);
1806 } else if (_session->get_play_loop ()) {
1808 auto_loop_button.set_visual_state (1);
1809 play_selection_button.set_visual_state (0);
1810 roll_button.set_visual_state (0);
1814 roll_button.set_visual_state (1);
1815 play_selection_button.set_visual_state (0);
1816 auto_loop_button.set_visual_state (0);
1819 if (join_play_range_button.get_active()) {
1820 /* light up both roll and play-selection if they are joined */
1821 roll_button.set_visual_state (1);
1822 play_selection_button.set_visual_state (1);
1825 stop_button.set_visual_state (0);
1829 stop_button.set_visual_state (1);
1830 roll_button.set_visual_state (0);
1831 play_selection_button.set_visual_state (0);
1832 auto_loop_button.set_visual_state (0);
1837 ARDOUR_UI::engine_stopped ()
1839 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
1840 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1841 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1845 ARDOUR_UI::engine_running ()
1847 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
1848 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1849 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1851 Glib::RefPtr<Action> action;
1852 const char* action_name = 0;
1854 switch (engine->frames_per_cycle()) {
1856 action_name = X_("JACKLatency32");
1859 action_name = X_("JACKLatency64");
1862 action_name = X_("JACKLatency128");
1865 action_name = X_("JACKLatency512");
1868 action_name = X_("JACKLatency1024");
1871 action_name = X_("JACKLatency2048");
1874 action_name = X_("JACKLatency4096");
1877 action_name = X_("JACKLatency8192");
1880 /* XXX can we do anything useful ? */
1886 action = ActionManager::get_action (X_("JACK"), action_name);
1889 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1890 ract->set_active ();
1896 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
1898 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
1899 /* we can't rely on the original string continuing to exist when we are called
1900 again in the GUI thread, so make a copy and note that we need to
1903 char *copy = strdup (reason);
1904 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
1908 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1909 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1911 update_sample_rate (0);
1915 /* if the reason is a non-empty string, it means that the backend was shutdown
1916 rather than just Ardour.
1919 if (strlen (reason)) {
1920 msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
1922 msgstr = string_compose (_("\
1923 JACK has either been shutdown or it\n\
1924 disconnected %1 because %1\n\
1925 was not fast enough. Try to restart\n\
1926 JACK, reconnect and save the session."), PROGRAM_NAME);
1929 MessageDialog msg (*editor, msgstr);
1934 free ((char*) reason);
1939 ARDOUR_UI::do_engine_start ()
1947 error << _("Unable to start the session running")
1957 ARDOUR_UI::setup_theme ()
1959 theme_manager->setup_theme();
1963 ARDOUR_UI::update_clocks ()
1965 if (!editor || !editor->dragging_playhead()) {
1966 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1971 ARDOUR_UI::start_clocking ()
1973 clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
1977 ARDOUR_UI::stop_clocking ()
1979 clock_signal_connection.disconnect ();
1983 ARDOUR_UI::toggle_clocking ()
1986 if (clock_button.get_active()) {
1995 ARDOUR_UI::_blink (void *arg)
1998 ((ARDOUR_UI *) arg)->blink ();
2005 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2009 ARDOUR_UI::start_blinking ()
2011 /* Start the blink signal. Everybody with a blinking widget
2012 uses Blink to drive the widget's state.
2015 if (blink_timeout_tag < 0) {
2017 blink_timeout_tag = g_timeout_add (240, _blink, this);
2022 ARDOUR_UI::stop_blinking ()
2024 if (blink_timeout_tag >= 0) {
2025 g_source_remove (blink_timeout_tag);
2026 blink_timeout_tag = -1;
2031 /** Ask the user for the name of a new shapshot and then take it.
2035 ARDOUR_UI::snapshot_session (bool switch_to_it)
2037 ArdourPrompter prompter (true);
2040 prompter.set_name ("Prompter");
2041 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2042 prompter.set_title (_("Take Snapshot"));
2043 prompter.set_title (_("Take Snapshot"));
2044 prompter.set_prompt (_("Name of new snapshot"));
2046 if (!switch_to_it) {
2049 struct tm local_time;
2052 localtime_r (&n, &local_time);
2053 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
2054 prompter.set_initial_text (timebuf);
2058 switch (prompter.run()) {
2059 case RESPONSE_ACCEPT:
2061 prompter.get_result (snapname);
2063 bool do_save = (snapname.length() != 0);
2066 if (snapname.find ('/') != string::npos) {
2067 MessageDialog msg (_("To ensure compatibility with various systems\n"
2068 "snapshot names may not contain a '/' character"));
2072 if (snapname.find ('\\') != string::npos) {
2073 MessageDialog msg (_("To ensure compatibility with various systems\n"
2074 "snapshot names may not contain a '\\' character"));
2080 vector<sys::path> p;
2081 get_state_files_in_directory (_session->session_directory().root_path(), p);
2082 vector<string> n = get_file_names_no_extension (p);
2083 if (find (n.begin(), n.end(), snapname) != n.end()) {
2085 ArdourDialog confirm (_("Confirm Snapshot Overwrite"), true);
2086 Label m (_("A snapshot already exists with that name. Do you want to overwrite it?"));
2087 confirm.get_vbox()->pack_start (m, true, true);
2088 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2089 confirm.add_button (_("Overwrite"), Gtk::RESPONSE_ACCEPT);
2090 confirm.show_all ();
2091 switch (confirm.run()) {
2092 case RESPONSE_CANCEL:
2098 save_state (snapname, switch_to_it);
2109 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2111 XMLNode* node = new XMLNode (X_("UI"));
2113 for (list<WindowProxyBase*>::iterator i = _window_proxies.begin(); i != _window_proxies.end(); ++i) {
2114 if (!(*i)->rc_configured()) {
2115 node->add_child_nocopy (*((*i)->get_state ()));
2119 _session->add_extra_xml (*node);
2121 save_state_canfail (name, switch_to_it);
2125 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2130 if (name.length() == 0) {
2131 name = _session->snap_name();
2134 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2138 cerr << "SS canfail\n";
2139 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2144 ARDOUR_UI::primary_clock_value_changed ()
2147 _session->request_locate (primary_clock.current_time ());
2152 ARDOUR_UI::big_clock_value_changed ()
2155 _session->request_locate (big_clock.current_time ());
2160 ARDOUR_UI::secondary_clock_value_changed ()
2163 _session->request_locate (secondary_clock.current_time ());
2168 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2170 if (_session == 0) {
2174 if (_session->step_editing()) {
2178 Session::RecordState const r = _session->record_status ();
2179 bool const h = _session->have_rec_enabled_track ();
2181 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2183 rec_button.set_visual_state (2);
2185 rec_button.set_visual_state (0);
2187 } else if (r == Session::Recording && h) {
2188 rec_button.set_visual_state (1);
2190 rec_button.set_visual_state (0);
2195 ARDOUR_UI::save_template ()
2197 ArdourPrompter prompter (true);
2200 if (!check_audioengine()) {
2204 prompter.set_name (X_("Prompter"));
2205 prompter.set_title (_("Save Mix Template"));
2206 prompter.set_prompt (_("Name for mix template:"));
2207 prompter.set_initial_text(_session->name() + _("-template"));
2208 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2210 switch (prompter.run()) {
2211 case RESPONSE_ACCEPT:
2212 prompter.get_result (name);
2214 if (name.length()) {
2215 _session->save_template (name);
2225 ARDOUR_UI::edit_metadata ()
2227 SessionMetadataEditor dialog;
2228 dialog.set_session (_session);
2229 editor->ensure_float (dialog);
2234 ARDOUR_UI::import_metadata ()
2236 SessionMetadataImporter dialog;
2237 dialog.set_session (_session);
2238 editor->ensure_float (dialog);
2243 ARDOUR_UI::fontconfig_dialog ()
2246 /* X11 users will always have fontconfig info around, but new GTK-OSX users
2247 may not and it can take a while to build it. Warn them.
2250 std::string fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
2252 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
2253 MessageDialog msg (*_startup,
2254 string_compose (_("Welcome to %1.\n\n"
2255 "The program will take a bit longer to start up\n"
2256 "while the system fonts are checked.\n\n"
2257 "This will only be done once, and you will\n"
2258 "not see this message again\n"), PROGRAM_NAME),
2271 ARDOUR_UI::parse_cmdline_path (const std::string& cmdline_path, std::string& session_name, std::string& session_path, bool& existing_session)
2273 existing_session = false;
2275 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
2276 session_path = cmdline_path;
2277 existing_session = true;
2278 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
2279 session_path = Glib::path_get_dirname (string (cmdline_path));
2280 existing_session = true;
2282 /* it doesn't exist, assume the best */
2283 session_path = Glib::path_get_dirname (string (cmdline_path));
2286 session_name = basename_nosuffix (string (cmdline_path));
2290 ARDOUR_UI::load_cmdline_session (const std::string& session_name, const std::string& session_path, bool& existing_session)
2292 /* when this is called, the backend audio system must be running */
2294 /* the main idea here is to deal with the fact that a cmdline argument for the session
2295 can be interpreted in different ways - it could be a directory or a file, and before
2296 we load, we need to know both the session directory and the snapshot (statefile) within it
2297 that we are supposed to use.
2300 if (session_name.length() == 0 || session_path.length() == 0) {
2304 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2306 std::string predicted_session_file;
2308 predicted_session_file = session_path;
2309 predicted_session_file += '/';
2310 predicted_session_file += session_name;
2311 predicted_session_file += ARDOUR::statefile_suffix;
2313 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2314 existing_session = true;
2317 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2319 if (session_path.find (ARDOUR::statefile_suffix) == session_path.length() - 7) {
2320 /* existing .ardour file */
2321 existing_session = true;
2325 existing_session = false;
2328 /* lets just try to load it */
2330 if (create_engine ()) {
2331 backend_audio_error (false, _startup);
2335 return load_session (session_path, session_name);
2339 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2341 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2343 MessageDialog msg (str,
2345 Gtk::MESSAGE_WARNING,
2346 Gtk::BUTTONS_YES_NO,
2350 msg.set_name (X_("OpenExistingDialog"));
2351 msg.set_title (_("Open Existing Session"));
2352 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2353 msg.set_position (Gtk::WIN_POS_MOUSE);
2356 switch (msg.run()) {
2365 ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name)
2367 BusProfile bus_profile;
2369 if (Profile->get_sae()) {
2371 bus_profile.master_out_channels = 2;
2372 bus_profile.input_ac = AutoConnectPhysical;
2373 bus_profile.output_ac = AutoConnectMaster;
2374 bus_profile.requested_physical_in = 0; // use all available
2375 bus_profile.requested_physical_out = 0; // use all available
2379 /* get settings from advanced section of NSD */
2381 if (_startup->create_master_bus()) {
2382 bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count();
2384 bus_profile.master_out_channels = 0;
2387 if (_startup->connect_inputs()) {
2388 bus_profile.input_ac = AutoConnectPhysical;
2390 bus_profile.input_ac = AutoConnectOption (0);
2393 /// @todo some minor tweaks.
2395 bus_profile.output_ac = AutoConnectOption (0);
2397 if (_startup->connect_outputs ()) {
2398 if (_startup->connect_outs_to_master()) {
2399 bus_profile.output_ac = AutoConnectMaster;
2400 } else if (_startup->connect_outs_to_physical()) {
2401 bus_profile.output_ac = AutoConnectPhysical;
2405 bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count();
2406 bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count();
2409 if (build_session (session_path, session_name, bus_profile)) {
2417 ARDOUR_UI::idle_load (const std::string& path)
2420 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2421 /* /path/to/foo => /path/to/foo, foo */
2422 load_session (path, basename_nosuffix (path));
2424 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2425 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2429 ARDOUR_COMMAND_LINE::session_name = path;
2432 * new_session_dialog doens't exist in A3
2433 * Try to remove all references to it to
2434 * see if it will compile. NOTE: this will
2435 * likely cause a runtime issue is my somewhat
2439 //if (new_session_dialog) {
2442 /* make it break out of Dialog::run() and
2446 //new_session_dialog->response (1);
2452 ARDOUR_UI::end_loading_messages ()
2458 ARDOUR_UI::loading_message (const std::string& /*msg*/)
2461 // splash->message (msg);
2465 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2467 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2469 string session_name;
2470 string session_path;
2471 string template_name;
2473 bool likely_new = false;
2475 if (! load_template.empty()) {
2476 should_be_new = true;
2477 template_name = load_template;
2482 if (!should_be_new && !ARDOUR_COMMAND_LINE::session_name.empty()) {
2484 /* if they named a specific statefile, use it, otherwise they are
2485 just giving a session folder, and we want to use it as is
2486 to find the session.
2489 if (ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix) != string::npos) {
2490 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2492 session_path = ARDOUR_COMMAND_LINE::session_name;
2495 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2499 bool const apply = run_startup (should_be_new, load_template);
2502 if (quit_on_cancel) {
2509 /* if we run the startup dialog again, offer more than just "new session" */
2511 should_be_new = false;
2513 session_name = _startup->session_name (likely_new);
2515 /* this shouldn't happen, but we catch it just in case it does */
2517 if (session_name.empty()) {
2521 if (_startup->use_session_template()) {
2522 template_name = _startup->session_template_name();
2523 _session_is_new = true;
2526 if (session_name[0] == G_DIR_SEPARATOR ||
2527 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
2528 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)) {
2530 /* absolute path or cwd-relative path specified for session name: infer session folder
2531 from what was given.
2534 session_path = Glib::path_get_dirname (session_name);
2535 session_name = Glib::path_get_basename (session_name);
2539 session_path = _startup->session_folder();
2541 if (session_name.find ('/') != string::npos) {
2542 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2543 "session names may not contain a '/' character"));
2545 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2549 if (session_name.find ('\\') != string::npos) {
2550 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2551 "session names may not contain a '\\' character"));
2553 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2559 if (create_engine ()) {
2563 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2567 std::string existing = Glib::build_filename (session_path, session_name);
2569 if (!ask_about_loading_existing_session (existing)) {
2570 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2575 _session_is_new = false;
2580 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
2582 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2586 if (session_name.find ('/') != std::string::npos) {
2587 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2588 "session names may not contain a '/' character"));
2590 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2594 if (session_name.find ('\\') != std::string::npos) {
2595 MessageDialog msg (*_startup, _("To ensure compatibility with various systems\n"
2596 "session names may not contain a '\\' character"));
2598 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
2602 _session_is_new = true;
2605 if (likely_new && template_name.empty()) {
2607 ret = build_session_from_nsd (session_path, session_name);
2611 ret = load_session (session_path, session_name, template_name);
2612 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
2613 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
2623 ARDOUR_UI::close_session()
2625 if (!check_audioengine()) {
2629 if (unload_session (true)) {
2633 ARDOUR_COMMAND_LINE::session_name = "";
2635 if (get_session_parameters (true, false)) {
2639 goto_editor_window ();
2643 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
2645 Session *new_session;
2649 session_loaded = false;
2651 if (!check_audioengine()) {
2655 unload_status = unload_session ();
2657 if (unload_status < 0) {
2659 } else if (unload_status > 0) {
2664 loading_message (string_compose (_("Please wait while %1loads your session"), PROGRAM_NAME));
2667 new_session = new Session (*engine, path, snap_name, 0, mix_template);
2670 /* this one is special */
2672 catch (AudioEngine::PortRegistrationFailure& err) {
2674 MessageDialog msg (err.what(),
2677 Gtk::BUTTONS_CLOSE);
2679 msg.set_title (_("Port Registration Error"));
2680 msg.set_secondary_text (_("Click the Close button to try again."));
2681 msg.set_position (Gtk::WIN_POS_CENTER);
2685 int response = msg.run ();
2690 case RESPONSE_CANCEL:
2700 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2703 Gtk::BUTTONS_CLOSE);
2705 msg.set_title (_("Loading Error"));
2706 msg.set_secondary_text (_("Click the Close button to try again."));
2707 msg.set_position (Gtk::WIN_POS_CENTER);
2711 int response = msg.run ();
2716 case RESPONSE_CANCEL:
2724 /* Now the session been created, add the transport controls */
2725 new_session->add_controllable(roll_controllable);
2726 new_session->add_controllable(stop_controllable);
2727 new_session->add_controllable(goto_start_controllable);
2728 new_session->add_controllable(goto_end_controllable);
2729 new_session->add_controllable(auto_loop_controllable);
2730 new_session->add_controllable(play_selection_controllable);
2731 new_session->add_controllable(rec_controllable);
2733 set_session (new_session);
2735 session_loaded = true;
2737 goto_editor_window ();
2740 _session->set_clean ();
2751 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
2753 Session *new_session;
2756 if (!check_audioengine()) {
2760 session_loaded = false;
2762 x = unload_session ();
2770 _session_is_new = true;
2773 new_session = new Session (*engine, path, snap_name, &bus_profile);
2778 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2784 /* Give the new session the default GUI state, if such things exist */
2787 n = Config->instant_xml (X_("Editor"));
2789 new_session->add_instant_xml (*n, false);
2791 n = Config->instant_xml (X_("Mixer"));
2793 new_session->add_instant_xml (*n, false);
2796 set_session (new_session);
2798 session_loaded = true;
2800 new_session->save_state(new_session->name());
2806 ARDOUR_UI::launch_chat ()
2809 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
2811 open_uri("http://webchat.freenode.net/?channels=ardour");
2816 ARDOUR_UI::show_about ()
2820 about->signal_response().connect(sigc::mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2823 about->set_transient_for(*editor);
2828 ARDOUR_UI::launch_manual ()
2830 PBD::open_uri("http://ardour.org/flossmanual");
2834 ARDOUR_UI::launch_reference ()
2836 PBD::open_uri("http://ardour.org/refmanual");
2840 ARDOUR_UI::hide_about ()
2843 about->get_window()->set_cursor ();
2849 ARDOUR_UI::about_signal_response (int /*response*/)
2855 ARDOUR_UI::show_splash ()
2859 splash = new Splash;
2867 splash->queue_draw ();
2868 splash->get_window()->process_updates (true);
2873 ARDOUR_UI::hide_splash ()
2881 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title,
2882 const string& plural_msg, const string& singular_msg)
2886 removed = rep.paths.size();
2889 MessageDialog msgd (*editor,
2890 _("No audio files were ready for cleanup"),
2893 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2894 msgd.set_secondary_text (_("If this seems suprising, \n\
2895 check for any existing snapshots.\n\
2896 These may still include regions that\n\
2897 require some unused files to continue to exist."));
2903 ArdourDialog results (_("Clean-up"), true, false);
2905 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2906 CleanupResultsModelColumns() {
2910 Gtk::TreeModelColumn<std::string> visible_name;
2911 Gtk::TreeModelColumn<std::string> fullpath;
2915 CleanupResultsModelColumns results_columns;
2916 Glib::RefPtr<Gtk::ListStore> results_model;
2917 Gtk::TreeView results_display;
2919 results_model = ListStore::create (results_columns);
2920 results_display.set_model (results_model);
2921 results_display.append_column (list_title, results_columns.visible_name);
2923 results_display.set_name ("CleanupResultsList");
2924 results_display.set_headers_visible (true);
2925 results_display.set_headers_clickable (false);
2926 results_display.set_reorderable (false);
2928 Gtk::ScrolledWindow list_scroller;
2931 Gtk::HBox dhbox; // the hbox for the image and text
2932 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2933 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2935 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2937 const string dead_sound_directory = _session->session_directory().dead_sound_path().to_string();
2940 %1 - number of files removed
2941 %2 - location of "dead_sounds"
2942 %3 - size of files affected
2943 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
2946 const char* bprefix;
2947 double space_adjusted = 0;
2949 if (rep.space < 100000.0f) {
2950 bprefix = X_("kilo");
2951 } else if (rep.space < 1000000.0f * 1000) {
2952 bprefix = X_("mega");
2953 space_adjusted = truncf((float)rep.space / 1000.0);
2955 bprefix = X_("giga");
2956 space_adjusted = truncf((float)rep.space / (1000000.0 * 1000));
2960 txt.set_text (string_compose (plural_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2962 txt.set_text (string_compose (singular_msg, removed, _session->path() + "dead_sounds", space_adjusted, bprefix));
2965 dhbox.pack_start (*dimage, true, false, 5);
2966 dhbox.pack_start (txt, true, false, 5);
2968 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2969 TreeModel::Row row = *(results_model->append());
2970 row[results_columns.visible_name] = *i;
2971 row[results_columns.fullpath] = *i;
2974 list_scroller.add (results_display);
2975 list_scroller.set_size_request (-1, 150);
2976 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2978 dvbox.pack_start (dhbox, true, false, 5);
2979 dvbox.pack_start (list_scroller, true, false, 5);
2980 ddhbox.pack_start (dvbox, true, false, 5);
2982 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2983 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2984 results.set_default_response (RESPONSE_CLOSE);
2985 results.set_position (Gtk::WIN_POS_MOUSE);
2987 results_display.show();
2988 list_scroller.show();
2995 //results.get_vbox()->show();
2996 results.set_resizable (false);
3003 ARDOUR_UI::cleanup ()
3005 if (_session == 0) {
3006 /* shouldn't happen: menu item is insensitive */
3011 MessageDialog checker (_("Are you sure you want to cleanup?"),
3013 Gtk::MESSAGE_QUESTION,
3014 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
3016 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
3017 ALL undo/redo information will be lost if you cleanup.\n\
3018 After cleanup, unused audio files will be moved to a \
3019 \"dead sounds\" location."));
3021 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3022 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
3023 checker.set_default_response (RESPONSE_CANCEL);
3025 checker.set_name (_("CleanupDialog"));
3026 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3027 checker.set_position (Gtk::WIN_POS_MOUSE);
3029 switch (checker.run()) {
3030 case RESPONSE_ACCEPT:
3036 ARDOUR::CleanupReport rep;
3038 editor->prepare_for_cleanup ();
3040 /* do not allow flush until a session is reloaded */
3042 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3044 act->set_sensitive (false);
3047 if (_session->cleanup_sources (rep)) {
3048 editor->finish_cleanup ();
3052 editor->finish_cleanup ();
3055 display_cleanup_results (rep,
3058 The following %1 files were not in use and \n\
3059 have been moved to:\n\
3061 Flushing the wastebasket will \n\
3062 release an additional\n\
3063 %3 %4bytes of disk space.\n"),
3065 The following file was not in use and \n \
3066 has been moved to:\n \
3068 Flushing the wastebasket will \n\
3069 release an additional\n\
3070 %3 %4bytes of disk space.\n"
3076 ARDOUR_UI::flush_trash ()
3078 if (_session == 0) {
3079 /* shouldn't happen: menu item is insensitive */
3083 ARDOUR::CleanupReport rep;
3085 if (_session->cleanup_trash_sources (rep)) {
3089 display_cleanup_results (rep,
3091 _("The following %1 files were deleted from\n\
3093 releasing %3 %4bytes of disk space"),
3094 _("The following file was deleted from\n\
3096 releasing %3 %4bytes of disk space"));
3100 ARDOUR_UI::add_route (Gtk::Window* float_window)
3108 if (add_route_dialog == 0) {
3109 add_route_dialog = new AddRouteDialog (_session);
3111 add_route_dialog->set_transient_for (*float_window);
3115 if (add_route_dialog->is_visible()) {
3116 /* we're already doing this */
3120 ResponseType r = (ResponseType) add_route_dialog->run ();
3122 add_route_dialog->hide();
3125 case RESPONSE_ACCEPT:
3132 if ((count = add_route_dialog->count()) <= 0) {
3136 string template_path = add_route_dialog->track_template();
3138 if (!template_path.empty()) {
3139 _session->new_route_from_template (count, template_path);
3143 uint32_t input_chan = add_route_dialog->channels ();
3144 uint32_t output_chan;
3145 string name_template = add_route_dialog->name_template ();
3146 bool track = add_route_dialog->track ();
3147 bool aux = !track && add_route_dialog->aux();
3148 RouteGroup* route_group = add_route_dialog->route_group ();
3150 AutoConnectOption oac = Config->get_output_auto_connect();
3152 if (oac & AutoConnectMaster) {
3153 output_chan = (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan);
3155 output_chan = input_chan;
3158 /* XXX do something with name template */
3160 if (add_route_dialog->type() == ARDOUR::DataType::MIDI) {
3162 session_add_midi_track (route_group, count);
3164 MessageDialog msg (*editor,
3165 _("Sorry, MIDI Busses are not supported at this time."));
3167 //session_add_midi_bus();
3171 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), route_group, count);
3173 session_add_audio_bus (aux, input_chan, output_chan, route_group, count);
3179 ARDOUR_UI::mixer_settings () const
3184 node = _session->instant_xml(X_("Mixer"));
3186 node = Config->instant_xml(X_("Mixer"));
3190 node = new XMLNode (X_("Mixer"));
3197 ARDOUR_UI::editor_settings () const
3202 node = _session->instant_xml(X_("Editor"));
3204 node = Config->instant_xml(X_("Editor"));
3208 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
3209 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
3214 node = new XMLNode (X_("Editor"));
3221 ARDOUR_UI::keyboard_settings () const
3225 node = Config->extra_xml(X_("Keyboard"));
3228 node = new XMLNode (X_("Keyboard"));
3234 ARDOUR_UI::create_xrun_marker(nframes_t where)
3236 editor->mouse_add_new_marker (where, false, true);
3240 ARDOUR_UI::halt_on_xrun_message ()
3242 MessageDialog msg (*editor,
3243 _("Recording was stopped because your system could not keep up."));
3248 ARDOUR_UI::xrun_handler(nframes_t where)
3254 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
3256 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
3257 create_xrun_marker(where);
3260 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
3261 halt_on_xrun_message ();
3266 ARDOUR_UI::disk_overrun_handler ()
3268 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
3270 if (!have_disk_speed_dialog_displayed) {
3271 have_disk_speed_dialog_displayed = true;
3272 MessageDialog* msg = new MessageDialog (*editor, string_compose (_("\
3273 The disk system on your computer\n\
3274 was not able to keep up with %1.\n\
3276 Specifically, it failed to write data to disk\n\
3277 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
3278 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3284 ARDOUR_UI::disk_underrun_handler ()
3286 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
3288 if (!have_disk_speed_dialog_displayed) {
3289 have_disk_speed_dialog_displayed = true;
3290 MessageDialog* msg = new MessageDialog (*editor,
3291 string_compose (_("The disk system on your computer\n\
3292 was not able to keep up with %1.\n\
3294 Specifically, it failed to read data from disk\n\
3295 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
3296 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
3302 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
3304 have_disk_speed_dialog_displayed = false;
3309 ARDOUR_UI::session_dialog (std::string msg)
3311 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
3316 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3318 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
3327 ARDOUR_UI::pending_state_dialog ()
3329 HBox* hbox = new HBox();
3330 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3331 ArdourDialog dialog (_("Crash Recovery"), true);
3333 This session appears to have been in\n\
3334 middle of recording when ardour or\n\
3335 the computer was shutdown.\n\
3337 Ardour can recover any captured audio for\n\
3338 you, or it can ignore it. Please decide\n\
3339 what you would like to do.\n"));
3340 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3341 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3342 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3343 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3344 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3345 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3346 dialog.set_default_response (RESPONSE_ACCEPT);
3347 dialog.set_position (WIN_POS_CENTER);
3352 switch (dialog.run ()) {
3353 case RESPONSE_ACCEPT:
3361 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3363 HBox* hbox = new HBox();
3364 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3365 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3366 Label message (string_compose (_("\
3367 This session was created with a sample rate of %1 Hz\n\
3369 The audioengine is currently running at %2 Hz\n"), desired, actual));
3371 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3372 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3373 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3374 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3375 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3376 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3377 dialog.set_default_response (RESPONSE_ACCEPT);
3378 dialog.set_position (WIN_POS_CENTER);
3383 switch (dialog.run ()) {
3384 case RESPONSE_ACCEPT:
3393 ARDOUR_UI::disconnect_from_jack ()
3396 if( engine->disconnect_from_jack ()) {
3397 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3401 update_sample_rate (0);
3406 ARDOUR_UI::reconnect_to_jack ()
3409 if (engine->reconnect_to_jack ()) {
3410 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3414 update_sample_rate (0);
3419 ARDOUR_UI::use_config ()
3421 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3423 set_transport_controllable_state (*node);
3428 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3430 if (Config->get_primary_clock_delta_edit_cursor()) {
3431 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3433 primary_clock.set (pos, 0, true);
3436 if (Config->get_secondary_clock_delta_edit_cursor()) {
3437 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3439 secondary_clock.set (pos);
3442 if (big_clock_window->get()) {
3443 big_clock.set (pos);
3449 ARDOUR_UI::step_edit_status_change (bool yn)
3451 // XXX should really store pre-step edit status of things
3452 // we make insensitive
3455 rec_button.set_visual_state (3);
3456 rec_button.set_sensitive (false);
3458 rec_button.set_visual_state (0);
3459 rec_button.set_sensitive (true);
3464 ARDOUR_UI::record_state_changed ()
3466 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
3468 if (!_session || !big_clock_window->get()) {
3469 /* why bother - the clock isn't visible */
3473 Session::RecordState const r = _session->record_status ();
3474 bool const h = _session->have_rec_enabled_track ();
3476 if (r == Session::Recording && h) {
3477 big_clock.set_widget_name ("BigClockRecording");
3479 big_clock.set_widget_name ("BigClockNonRecording");
3484 ARDOUR_UI::first_idle ()
3487 _session->allow_auto_play (true);
3491 editor->first_idle();
3494 Keyboard::set_can_save_keybindings (true);
3499 ARDOUR_UI::store_clock_modes ()
3501 XMLNode* node = new XMLNode(X_("ClockModes"));
3503 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3504 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3507 _session->add_extra_xml (*node);
3508 _session->set_dirty ();
3513 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3514 : Controllable (name), ui (u), type(tp)
3520 ARDOUR_UI::TransportControllable::set_value (double val)
3522 if (type == ShuttleControl) {
3529 fract = -((0.5 - val)/0.5);
3531 fract = ((val - 0.5)/0.5);
3535 ui.set_shuttle_fract (fract);
3540 /* do nothing: these are radio-style actions */
3544 const char *action = 0;
3548 action = X_("Roll");
3551 action = X_("Stop");
3554 action = X_("Goto Start");
3557 action = X_("Goto End");
3560 action = X_("Loop");
3563 action = X_("Play Selection");
3566 action = X_("Record");
3576 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3584 ARDOUR_UI::TransportControllable::get_value (void) const
3603 case ShuttleControl:
3613 ARDOUR_UI::TransportControllable::set_id (const string& str)
3619 ARDOUR_UI::setup_profile ()
3621 if (gdk_screen_width() < 1200) {
3622 Profile->set_small_screen ();
3626 if (getenv ("ARDOUR_SAE")) {
3627 Profile->set_sae ();
3628 Profile->set_single_package ();
3633 ARDOUR_UI::toggle_translations ()
3635 using namespace Glib;
3637 RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("EnableTranslation"));
3639 RefPtr<ToggleAction> ract = RefPtr<ToggleAction>::cast_dynamic (act);
3642 string i18n_killer = ARDOUR::translation_kill_path();
3644 bool already_enabled = !ARDOUR::translations_are_disabled ();
3646 if (ract->get_active ()) {
3647 /* we don't care about errors */
3648 int fd = ::open (i18n_killer.c_str(), O_RDONLY|O_CREAT, 0644);
3651 /* we don't care about errors */
3652 unlink (i18n_killer.c_str());
3655 if (already_enabled != ract->get_active()) {
3656 MessageDialog win (already_enabled ? _("Translations disabled") : _("Translations enabled"),
3658 Gtk::MESSAGE_WARNING,
3660 win.set_secondary_text (string_compose (_("You must restart %1 for this to take effect."), PROGRAM_NAME));
3661 win.set_position (Gtk::WIN_POS_CENTER);
3669 /** Add a window proxy to our list, so that its state will be saved.
3670 * This call also causes the window to be created and opened if its
3671 * state was saved as `visible'.
3674 ARDOUR_UI::add_window_proxy (WindowProxyBase* p)
3676 _window_proxies.push_back (p);
3680 /** Remove a window proxy from our list. Must be called if a WindowProxy
3681 * is deleted, to prevent hanging pointers.
3684 ARDOUR_UI::remove_window_proxy (WindowProxyBase* p)
3686 _window_proxies.remove (p);